@@ -99,6 +99,106 @@ class VisibleChildIterator {
9999 }
100100}
101101
102+ class Rect {
103+ constructor ( x , y , width , height ) {
104+ this . x1 = x ;
105+ this . y1 = y ;
106+ this . x2 = x + width ;
107+ this . y2 = y + height ;
108+ }
109+ containsPoint ( x , y ) {
110+ if ( ( x < this . x1 || x > this . x2 ) || ( y < this . y1 || y > this . y2 ) )
111+ return false ;
112+ return true ;
113+ }
114+ }
115+
116+ class SelectionInhibitor {
117+ constructor ( ) {
118+ this . _timeoutId = 0 ;
119+ this . _container = null ;
120+ this . _bounds = null ;
121+ this . _lastPos = null ;
122+ this . _inhibited = false ;
123+ this . _averageSlope = 0 ;
124+ }
125+
126+ get inhibited ( ) {
127+ return this . _inhibited ;
128+ }
129+
130+ inhibit ( ) {
131+ if ( ! this . _container )
132+ return ;
133+
134+ if ( ! this . _timeoutId ) {
135+ let [ cx , cy ] = this . _container . get_transformed_position ( ) ;
136+ let [ cw , ch ] = this . _container . get_transformed_size ( ) ;
137+ this . _bounds = new Rect ( cx , cy , cw , ch ) ;
138+ this . _timeoutId = Mainloop . timeout_add ( 50 , this . _trackMouse . bind ( this ) ) ;
139+ }
140+
141+ this . _setInhibited ( true ) ;
142+ }
143+
144+ stop ( ) {
145+ if ( this . _timeoutId )
146+ Mainloop . source_remove ( this . _timeoutId ) ;
147+
148+ this . _setInhibited ( false ) ;
149+ this . _timeoutId = 0 ;
150+ this . _bounds = null ;
151+ this . _inhibited = false ;
152+ this . _averageSlope = 0 ;
153+ }
154+
155+ setContainer ( container ) {
156+ this . stop ( ) ;
157+ this . _container = container ;
158+ }
159+
160+ _setInhibited ( state ) {
161+ if ( state == this . _inhibited || ! this . _container )
162+ return ;
163+
164+ let [ mx , my , ] = global . get_pointer ( ) ;
165+ this . _lastPos = [ mx , my ] ;
166+ this . _averageSlope = 0 ;
167+ this . _inhibited = state ;
168+
169+ for ( let actor of this . _container . get_children ( ) )
170+ actor . set_reactive ( ! state ) ;
171+ }
172+
173+ _trackMouse ( ) {
174+ if ( ! this . _timeoutId )
175+ return ;
176+
177+ let [ x , y , mask ] = global . get_pointer ( ) ;
178+ if ( ! this . _bounds . containsPoint ( x , y ) ) {
179+ this . stop ( ) ;
180+ return false ;
181+ }
182+
183+ if ( this . _inhibited ) {
184+ let dx = x - this . _lastPos [ 0 ] ;
185+ let dy = Math . abs ( y - this . _lastPos [ 1 ] ) ;
186+
187+ if ( dx > 0 && dy > 0 ) {
188+ this . _averageSlope += dy / dx ;
189+ this . _averageSlope /= 2 ;
190+ }
191+ //log(`averageSlope = ${this._averageSlope}; dx = ${dx}; dy = ${dy}`);
192+ if ( this . _averageSlope > 4 || dx < 0 || ( dx == 0 && dy > 0 ) ) {
193+ this . _setInhibited ( false )
194+ }
195+
196+ }
197+ this . _lastPos = [ x , y ] ;
198+ return true ;
199+ }
200+ }
201+
102202class ApplicationContextMenuItem extends PopupMenu . PopupBaseMenuItem {
103203 constructor ( appButton , label , action , iconName ) {
104204 super ( { focusOnHover : false } ) ;
@@ -1149,6 +1249,7 @@ class CinnamonMenuApplet extends Applet.TextIconApplet {
11491249 this . noRecentDocuments = true ;
11501250 this . _activeContextMenuParent = null ;
11511251 this . _activeContextMenuItem = null ;
1252+ this . selectionInhibitor = new SelectionInhibitor ( ) ;
11521253 this . _display ( ) ;
11531254 appsys . connect ( 'installed-changed' , Lang . bind ( this , this . onAppSysChanged ) ) ;
11541255 AppFavorites . getAppFavorites ( ) . connect ( 'changed' , Lang . bind ( this , this . _refreshFavs ) ) ;
@@ -1352,7 +1453,7 @@ class CinnamonMenuApplet extends Applet.TextIconApplet {
13521453 this . closeContextMenus ( null , false ) ;
13531454
13541455 this . _clearAllSelections ( true ) ;
1355- this . destroyVectorBox ( ) ;
1456+ this . selectionInhibitor . stop ( ) ;
13561457 }
13571458 }
13581459
@@ -2037,101 +2138,6 @@ class CinnamonMenuApplet extends Applet.TextIconApplet {
20372138 }
20382139 }
20392140
2040- /*
2041- * The vectorBox overlays the the categoriesBox to aid in navigation from categories to apps
2042- * by preventing misselections. It is set to the same size as the categoriesOverlayBox and
2043- * categoriesBox.
2044- *
2045- * The actor is a quadrilateral that we turn into a triangle by setting the A and B vertices to
2046- * the same position. The size and origin of the vectorBox are calculated in _getVectorInfo().
2047- * Using those properties, the bounding box is sized as (w, h) and the triangle is defined as
2048- * follows:
2049- * _____
2050- * | /|D
2051- * | / | AB: (mx, my)
2052- * | A/ | C: (w, h)
2053- * | B\ | D: (w, 0)
2054- * | \ |
2055- * |____\|C
2056- */
2057-
2058- _getVectorInfo ( ) {
2059- let [ mx , my , mask ] = global . get_pointer ( ) ;
2060- let [ bx , by ] = this . categoriesOverlayBox . get_transformed_position ( ) ;
2061- let [ bw , bh ] = this . categoriesOverlayBox . get_transformed_size ( ) ;
2062-
2063- let xformed_mx = mx - bx ;
2064- let xformed_my = my - by ;
2065-
2066- if ( xformed_mx < 0 || xformed_mx > bw || xformed_my < 0 || xformed_my > bh ) {
2067- return null ;
2068- }
2069-
2070- return { mx : xformed_mx ,
2071- my : xformed_my ,
2072- w : bw ,
2073- h : bh } ;
2074- }
2075-
2076- makeVectorBox ( actor ) {
2077- this . destroyVectorBox ( actor ) ;
2078- let vi = this . _getVectorInfo ( ) ;
2079- if ( ! vi ) {
2080- return ;
2081- }
2082-
2083- this . vectorBox = new St . Polygon ( { debug : false , width : vi . w - 1 , height : vi . h ,
2084- ulc_x : vi . mx , ulc_y : vi . my ,
2085- llc_x : vi . mx , llc_y : vi . my ,
2086- urc_x : vi . w , urc_y : 0 ,
2087- lrc_x : vi . w , lrc_y : vi . h } ) ;
2088-
2089- this . categoriesOverlayBox . add_actor ( this . vectorBox ) ;
2090-
2091- this . vectorBox . show ( ) ;
2092- this . vectorBox . set_reactive ( true ) ;
2093-
2094- this . vectorBox . connect ( "leave-event" , Lang . bind ( this , this . destroyVectorBox ) ) ;
2095- this . vectorBox . connect ( "motion-event" , Lang . bind ( this , this . maybeUpdateVectorBox ) ) ;
2096- this . actor_motion_id = actor . connect ( "motion-event" , Lang . bind ( this , this . maybeUpdateVectorBox ) ) ;
2097- this . current_motion_actor = actor ;
2098- }
2099-
2100- maybeUpdateVectorBox ( ) {
2101- if ( this . vector_update_loop ) {
2102- Mainloop . source_remove ( this . vector_update_loop ) ;
2103- this . vector_update_loop = 0 ;
2104- }
2105- this . vector_update_loop = Mainloop . timeout_add ( 50 , Lang . bind ( this , this . updateVectorBox ) ) ;
2106- }
2107-
2108- updateVectorBox ( actor ) {
2109- if ( this . vectorBox ) {
2110- let vi = this . _getVectorInfo ( ) ;
2111- if ( vi ) {
2112- this . vectorBox . ulc_x = vi . mx ;
2113- this . vectorBox . llc_x = vi . mx ;
2114- this . vectorBox . queue_repaint ( ) ;
2115- } else {
2116- this . destroyVectorBox ( actor ) ;
2117- }
2118- }
2119- this . vector_update_loop = 0 ;
2120- return false ;
2121- }
2122-
2123- destroyVectorBox ( actor ) {
2124- if ( this . vectorBox != null ) {
2125- this . vectorBox . destroy ( ) ;
2126- this . vectorBox = null ;
2127- }
2128- if ( this . actor_motion_id > 0 && this . current_motion_actor != null ) {
2129- this . current_motion_actor . disconnect ( this . actor_motion_id ) ;
2130- this . actor_motion_id = 0 ;
2131- this . current_motion_actor = null ;
2132- }
2133- }
2134-
21352141 _refreshPlaces ( ) {
21362142 for ( let i = 0 ; i < this . _placesButtons . length ; i ++ ) {
21372143 this . _placesButtons [ i ] . actor . destroy ( ) ;
@@ -2160,7 +2166,7 @@ class CinnamonMenuApplet extends Applet.TextIconApplet {
21602166 this . closeContextMenus ( null , false ) ;
21612167 this . _select_category ( "places" ) ;
21622168
2163- this . makeVectorBox ( this . placesButton . actor ) ;
2169+ this . selectionInhibitor . inhibit ( ) ;
21642170 }
21652171 } ) ) ;
21662172 this . placesButton . actor . connect ( 'leave-event' , Lang . bind ( this , function ( ) {
@@ -2234,7 +2240,7 @@ class CinnamonMenuApplet extends Applet.TextIconApplet {
22342240 this . closeContextMenus ( null , false ) ;
22352241 this . _select_category ( "recent" ) ;
22362242
2237- this . makeVectorBox ( this . recentButton . actor ) ;
2243+ this . selectionInhibitor . inhibit ( ) ;
22382244 }
22392245 } ) ) ;
22402246 this . recentButton . actor . connect ( 'leave-event' , Lang . bind ( this , function ( ) {
@@ -2473,7 +2479,7 @@ class CinnamonMenuApplet extends Applet.TextIconApplet {
24732479 this . _allAppsCategoryButton . actor . style_class = "menu-category-button-selected" ;
24742480 this . _select_category ( null ) ;
24752481
2476- this . makeVectorBox ( this . _allAppsCategoryButton . actor ) ;
2482+ this . selectionInhibitor . inhibit ( ) ;
24772483 }
24782484 } ) ) ;
24792485 this . _allAppsCategoryButton . actor . connect ( 'leave-event' , Lang . bind ( this , function ( ) {
@@ -2538,7 +2544,7 @@ class CinnamonMenuApplet extends Applet.TextIconApplet {
25382544 categoryButton . actor . style_class = "menu-category-button-selected" ;
25392545 this . _select_category ( dir . get_menu_id ( ) ) ;
25402546
2541- this . makeVectorBox ( categoryButton . actor ) ;
2547+ this . selectionInhibitor . inhibit ( ) ;
25422548 }
25432549 } ) ;
25442550 } ;
@@ -2827,10 +2833,6 @@ class CinnamonMenuApplet extends Applet.TextIconApplet {
28272833 _display ( ) {
28282834 this . _activeContainer = null ;
28292835 this . _activeActor = null ;
2830- this . vectorBox = null ;
2831- this . actor_motion_id = 0 ;
2832- this . vector_update_loop = null ;
2833- this . current_motion_actor = null ;
28342836 let section = new PopupMenu . PopupMenuSection ( ) ;
28352837 this . menu . addMenuItem ( section ) ;
28362838
@@ -2866,11 +2868,10 @@ class CinnamonMenuApplet extends Applet.TextIconApplet {
28662868 rightPane . add_actor ( topRow ) ;
28672869 rightPane . add_actor ( this . categoriesApplicationsBox . actor ) ;
28682870
2869- this . categoriesOverlayBox = new Clutter . Actor ( ) ;
28702871 this . categoriesBox = new St . BoxLayout ( { style_class : 'menu-categories-box' ,
28712872 vertical : true ,
28722873 accessible_role : Atk . Role . LIST } ) ;
2873- this . categoriesOverlayBox . add_actor ( this . categoriesBox ) ;
2874+ this . selectionInhibitor . setContainer ( this . categoriesBox ) ;
28742875
28752876 this . applicationsScrollBox = new St . ScrollView ( { x_fill : true , y_fill : false , y_align : St . Align . START , style_class : 'vfade menu-applications-scrollbox' } ) ;
28762877
@@ -2898,7 +2899,7 @@ class CinnamonMenuApplet extends Applet.TextIconApplet {
28982899 this . applicationsBox . add_style_class_name ( 'menu-applications-box' ) ; //this is to support old themes
28992900 this . applicationsScrollBox . add_actor ( this . applicationsBox ) ;
29002901 this . applicationsScrollBox . set_policy ( Gtk . PolicyType . NEVER , Gtk . PolicyType . AUTOMATIC ) ;
2901- this . categoriesApplicationsBox . actor . add_actor ( this . categoriesOverlayBox ) ;
2902+ this . categoriesApplicationsBox . actor . add_actor ( this . categoriesBox ) ;
29022903 this . categoriesApplicationsBox . actor . add_actor ( this . applicationsScrollBox ) ;
29032904
29042905 this . favoritesScrollBox = new St . ScrollView ( {
0 commit comments