@@ -99,6 +99,93 @@ class VisibleChildIterator {
9999 }
100100}
101101
102+ // blocks child reactivity on a container while the mouse is moving
103+ // more rightwards than up/down. any left movement uninhibits.
104+ class SelectionInhibitor {
105+ constructor ( ) {
106+ this . _timeoutId = 0 ;
107+ this . _averageSlope = 0 ;
108+ this . _inhibited = false ;
109+ this . _container = null ;
110+ this . _bounds = null ;
111+ this . _lastPos = null ;
112+ }
113+
114+ start ( ) {
115+ if ( ! this . _container )
116+ return ;
117+
118+ if ( ! this . _timeoutId ) {
119+ this . _bounds = Cinnamon . util_get_transformed_allocation ( this . _container ) ;
120+ this . _timeoutId = Mainloop . timeout_add ( 50 , this . _trackMouse . bind ( this ) ) ;
121+ }
122+
123+ this . _setInhibited ( true ) ;
124+ }
125+
126+ stop ( ) {
127+ if ( this . _timeoutId )
128+ Mainloop . source_remove ( this . _timeoutId ) ;
129+
130+ this . _timeoutId = 0 ;
131+ this . _bounds = null ;
132+ this . _setInhibited ( false ) ;
133+ }
134+
135+ setContainer ( container ) {
136+ this . stop ( ) ;
137+ this . _container = container ;
138+ }
139+
140+ _setInhibited ( state ) {
141+ if ( state == this . _inhibited || ! this . _container )
142+ return ;
143+
144+ this . _inhibited = state ;
145+ this . _container . get_children ( ) . forEach ( c => c . set_reactive ( ! state ) ) ;
146+
147+ if ( state ) {
148+ let [ mx , my , ] = global . get_pointer ( ) ;
149+ this . _lastPos = [ mx , my ] ;
150+ this . _averageSlope = 0 ;
151+ }
152+ }
153+
154+ _trackMouse ( ) {
155+ if ( ! this . _timeoutId )
156+ return false ;
157+
158+ let [ x , y , ] = global . get_pointer ( ) ;
159+ if ( ! this . _bounds . contains ( x , y ) ) {
160+ this . stop ( ) ;
161+ return false ;
162+ }
163+
164+ if ( this . _inhibited ) {
165+ let dx = x - this . _lastPos [ 0 ] ;
166+ let dy = Math . abs ( y - this . _lastPos [ 1 ] ) ;
167+
168+ if ( dx > 0 && dy > 0 ) {
169+ this . _averageSlope += dy / dx ;
170+ this . _averageSlope /= 2 ;
171+ } else if ( dy > 0 && dx >= 0 ) {
172+ this . _averageSlope += dy ;
173+ } else {
174+ // x < 0 (moving left) or not moving at all
175+ this . _averageSlope = 0 ;
176+ this . _setInhibited ( false )
177+ }
178+
179+ // approx 4 pixels straight up or down, or moving up/down 3.5 pixels per one right on average
180+ // basically it's what "feels right" with my weird algorithm.
181+ if ( this . _averageSlope > 3.5 )
182+ this . _setInhibited ( false )
183+ }
184+ this . _lastPos = [ x , y ] ;
185+ return true ;
186+ }
187+ }
188+
102189class ApplicationContextMenuItem extends PopupMenu . PopupBaseMenuItem {
103190 constructor ( appButton , label , action , iconName ) {
104191 super ( { focusOnHover : false } ) ;
@@ -1154,6 +1241,7 @@ class CinnamonMenuApplet extends Applet.TextIconApplet {
11541241 this . noRecentDocuments = true ;
11551242 this . _activeContextMenuParent = null ;
11561243 this . _activeContextMenuItem = null ;
1244+ this . selectionInhibitor = new SelectionInhibitor ( ) ;
11571245 this . _display ( ) ;
11581246 appsys . connect ( 'installed-changed' , Lang . bind ( this , this . onAppSysChanged ) ) ;
11591247 AppFavorites . getAppFavorites ( ) . connect ( 'changed' , Lang . bind ( this , this . _refreshFavs ) ) ;
@@ -1361,7 +1449,7 @@ class CinnamonMenuApplet extends Applet.TextIconApplet {
13611449
13621450 this . _clearAllSelections ( true ) ;
13631451 this . _scrollToButton ( this . favBoxIter . getFirstVisible ( ) . _delegate , this . favoritesScrollBox ) ;
1364- this . destroyVectorBox ( ) ;
1452+ this . selectionInhibitor . stop ( ) ;
13651453 }
13661454 }
13671455
@@ -2061,101 +2149,6 @@ class CinnamonMenuApplet extends Applet.TextIconApplet {
20612149 }
20622150 }
20632151
2064- /*
2065- * The vectorBox overlays the the categoriesBox to aid in navigation from categories to apps
2066- * by preventing misselections. It is set to the same size as the categoriesOverlayBox and
2067- * categoriesBox.
2068- *
2069- * The actor is a quadrilateral that we turn into a triangle by setting the A and B vertices to
2070- * the same position. The size and origin of the vectorBox are calculated in _getVectorInfo().
2071- * Using those properties, the bounding box is sized as (w, h) and the triangle is defined as
2072- * follows:
2073- * _____
2074- * | /|D
2075- * | / | AB: (mx, my)
2076- * | A/ | C: (w, h)
2077- * | B\ | D: (w, 0)
2078- * | \ |
2079- * |____\|C
2080- */
2081-
2082- _getVectorInfo ( ) {
2083- let [ mx , my , mask ] = global . get_pointer ( ) ;
2084- let [ bx , by ] = this . categoriesOverlayBox . get_transformed_position ( ) ;
2085- let [ bw , bh ] = this . categoriesOverlayBox . get_transformed_size ( ) ;
2086-
2087- let xformed_mx = mx - bx ;
2088- let xformed_my = my - by ;
2089-
2090- if ( xformed_mx < 0 || xformed_mx > bw || xformed_my < 0 || xformed_my > bh ) {
2091- return null ;
2092- }
2093-
2094- return { mx : xformed_mx ,
2095- my : xformed_my ,
2096- w : bw ,
2097- h : bh } ;
2098- }
2099-
2100- makeVectorBox ( actor ) {
2101- this . destroyVectorBox ( actor ) ;
2102- let vi = this . _getVectorInfo ( ) ;
2103- if ( ! vi ) {
2104- return ;
2105- }
2106-
2107- this . vectorBox = new St . Polygon ( { debug : false , width : vi . w - 1 , height : vi . h ,
2108- ulc_x : vi . mx , ulc_y : vi . my ,
2109- llc_x : vi . mx , llc_y : vi . my ,
2110- urc_x : vi . w , urc_y : 0 ,
2111- lrc_x : vi . w , lrc_y : vi . h } ) ;
2112-
2113- this . categoriesOverlayBox . add_actor ( this . vectorBox ) ;
2114-
2115- this . vectorBox . show ( ) ;
2116- this . vectorBox . set_reactive ( true ) ;
2117-
2118- this . vectorBox . connect ( "leave-event" , Lang . bind ( this , this . destroyVectorBox ) ) ;
2119- this . vectorBox . connect ( "motion-event" , Lang . bind ( this , this . maybeUpdateVectorBox ) ) ;
2120- this . actor_motion_id = actor . connect ( "motion-event" , Lang . bind ( this , this . maybeUpdateVectorBox ) ) ;
2121- this . current_motion_actor = actor ;
2122- }
2123-
2124- maybeUpdateVectorBox ( ) {
2125- if ( this . vector_update_loop ) {
2126- Mainloop . source_remove ( this . vector_update_loop ) ;
2127- this . vector_update_loop = 0 ;
2128- }
2129- this . vector_update_loop = Mainloop . timeout_add ( 50 , Lang . bind ( this , this . updateVectorBox ) ) ;
2130- }
2131-
2132- updateVectorBox ( actor ) {
2133- if ( this . vectorBox ) {
2134- let vi = this . _getVectorInfo ( ) ;
2135- if ( vi ) {
2136- this . vectorBox . ulc_x = vi . mx ;
2137- this . vectorBox . llc_x = vi . mx ;
2138- this . vectorBox . queue_repaint ( ) ;
2139- } else {
2140- this . destroyVectorBox ( actor ) ;
2141- }
2142- }
2143- this . vector_update_loop = 0 ;
2144- return false ;
2145- }
2146-
2147- destroyVectorBox ( actor ) {
2148- if ( this . vectorBox != null ) {
2149- this . vectorBox . destroy ( ) ;
2150- this . vectorBox = null ;
2151- }
2152- if ( this . actor_motion_id > 0 && this . current_motion_actor != null ) {
2153- this . current_motion_actor . disconnect ( this . actor_motion_id ) ;
2154- this . actor_motion_id = 0 ;
2155- this . current_motion_actor = null ;
2156- }
2157- }
2158-
21592152 _refreshPlaces ( ) {
21602153 for ( let i = 0 ; i < this . _placesButtons . length ; i ++ ) {
21612154 this . _placesButtons [ i ] . actor . destroy ( ) ;
@@ -2184,7 +2177,7 @@ class CinnamonMenuApplet extends Applet.TextIconApplet {
21842177 this . closeContextMenus ( null , false ) ;
21852178 this . _select_category ( "places" ) ;
21862179
2187- this . makeVectorBox ( this . placesButton . actor ) ;
2180+ this . selectionInhibitor . start ( ) ;
21882181 }
21892182 } ) ) ;
21902183 this . placesButton . actor . connect ( 'leave-event' , Lang . bind ( this , function ( ) {
@@ -2258,7 +2251,7 @@ class CinnamonMenuApplet extends Applet.TextIconApplet {
22582251 this . closeContextMenus ( null , false ) ;
22592252 this . _select_category ( "recent" ) ;
22602253
2261- this . makeVectorBox ( this . recentButton . actor ) ;
2254+ this . selectionInhibitor . start ( ) ;
22622255 }
22632256 } ) ) ;
22642257 this . recentButton . actor . connect ( 'leave-event' , Lang . bind ( this , function ( ) {
@@ -2495,7 +2488,7 @@ class CinnamonMenuApplet extends Applet.TextIconApplet {
24952488 this . _allAppsCategoryButton . actor . style_class = "menu-category-button-selected" ;
24962489 this . _select_category ( null ) ;
24972490
2498- this . makeVectorBox ( this . _allAppsCategoryButton . actor ) ;
2491+ this . selectionInhibitor . start ( ) ;
24992492 }
25002493 } ) ) ;
25012494 this . _allAppsCategoryButton . actor . connect ( 'leave-event' , Lang . bind ( this , function ( ) {
@@ -2560,7 +2553,7 @@ class CinnamonMenuApplet extends Applet.TextIconApplet {
25602553 categoryButton . actor . style_class = "menu-category-button-selected" ;
25612554 this . _select_category ( dir . get_menu_id ( ) ) ;
25622555
2563- this . makeVectorBox ( categoryButton . actor ) ;
2556+ this . selectionInhibitor . start ( ) ;
25642557 }
25652558 } ) ;
25662559 } ;
@@ -2862,10 +2855,6 @@ class CinnamonMenuApplet extends Applet.TextIconApplet {
28622855 _display ( ) {
28632856 this . _activeContainer = null ;
28642857 this . _activeActor = null ;
2865- this . vectorBox = null ;
2866- this . actor_motion_id = 0 ;
2867- this . vector_update_loop = null ;
2868- this . current_motion_actor = null ;
28692858 let section = new PopupMenu . PopupMenuSection ( ) ;
28702859 this . menu . addMenuItem ( section ) ;
28712860
@@ -2899,11 +2888,10 @@ class CinnamonMenuApplet extends Applet.TextIconApplet {
28992888 rightPane . add_actor ( this . searchBox ) ;
29002889 rightPane . add_actor ( this . categoriesApplicationsBox . actor ) ;
29012890
2902- this . categoriesOverlayBox = new Clutter . Actor ( ) ;
29032891 this . categoriesBox = new St . BoxLayout ( { style_class : 'menu-categories-box' ,
29042892 vertical : true ,
29052893 accessible_role : Atk . Role . LIST } ) ;
2906- this . categoriesOverlayBox . add_actor ( this . categoriesBox ) ;
2894+ this . selectionInhibitor . setContainer ( this . categoriesBox ) ;
29072895
29082896 this . applicationsScrollBox = new St . ScrollView ( { x_fill : true , y_fill : false , y_align : St . Align . START , style_class : 'vfade menu-applications-scrollbox' } ) ;
29092897 this . favoritesScrollBox = new St . ScrollView ( {
@@ -2937,7 +2925,7 @@ class CinnamonMenuApplet extends Applet.TextIconApplet {
29372925 this . applicationsBox . add_style_class_name ( 'menu-applications-box' ) ; //this is to support old themes
29382926 this . applicationsScrollBox . add_actor ( this . applicationsBox ) ;
29392927 this . applicationsScrollBox . set_policy ( Gtk . PolicyType . NEVER , Gtk . PolicyType . AUTOMATIC ) ;
2940- this . categoriesApplicationsBox . actor . add_actor ( this . categoriesOverlayBox ) ;
2928+ this . categoriesApplicationsBox . actor . add_actor ( this . categoriesBox ) ;
29412929 this . categoriesApplicationsBox . actor . add_actor ( this . applicationsScrollBox ) ;
29422930
29432931 this . favoritesBox = new FavoritesBox ( ) . actor ;
0 commit comments