@@ -50,6 +50,15 @@ function getFavIconSize() {
5050 return Math . min ( icon_size , MAX_FAV_ICON_SIZE ) ;
5151}
5252
53+ const RefreshFlags = Object . freeze ( {
54+ APP : 0b00001 ,
55+ FAV : 0b00010 ,
56+ PLACE : 0b00100 ,
57+ RECENT : 0b01000 ,
58+ SYSTEM : 0b10000
59+ } ) ;
60+ const REFRESH_ALL_MASK = 0b11111 ;
61+
5362/* VisibleChildIterator takes a container (boxlayout, etc.)
5463 * and creates an array of its visible children and their index
5564 * positions. We can then work through that list without
@@ -979,7 +988,7 @@ class CinnamonMenuApplet extends Applet.TextIconApplet {
979988
980989 this . settings = new Settings . AppletSettings ( this , "menu@cinnamon.org" , instance_id ) ;
981990
982- this . settings . bind ( "show-places" , "showPlaces" , this . _refreshBelowApps ) ;
991+ this . settings . bind ( "show-places" , "showPlaces" , ( ) => this . queueRefresh ( RefreshFlags . PLACE ) ) ;
983992
984993 this . _appletEnterEventId = 0 ;
985994 this . _appletLeaveEventId = 0 ;
@@ -1038,26 +1047,25 @@ class CinnamonMenuApplet extends Applet.TextIconApplet {
10381047 this . _activeContextMenuParent = null ;
10391048 this . _activeContextMenuItem = null ;
10401049 this . _display ( ) ;
1041- appsys . connect ( 'installed-changed' , Lang . bind ( this , this . onAppSysChanged ) ) ;
1042- AppFavorites . getAppFavorites ( ) . connect ( 'changed' , Lang . bind ( this , this . _refreshFavs ) ) ;
1043- Main . placesManager . connect ( 'places-updated' , Lang . bind ( this , this . _refreshBelowApps ) ) ;
1044- this . RecentManager . connect ( 'changed' , Lang . bind ( this , this . _refreshRecent ) ) ;
1045- this . privacy_settings . connect ( "changed::" + REMEMBER_RECENT_KEY , Lang . bind ( this , this . _refreshRecent ) ) ;
1050+ appsys . connect ( 'installed-changed' , ( ) => this . queueRefresh ( RefreshFlags . APP | RefreshFlags . FAV ) ) ;
1051+ AppFavorites . getAppFavorites ( ) . connect ( 'changed' , ( ) => this . queueRefresh ( RefreshFlags . FAV ) ) ;
1052+ Main . placesManager . connect ( 'places-updated' , ( ) => this . queueRefresh ( RefreshFlags . PLACE ) ) ;
1053+ this . RecentManager . connect ( 'changed' , ( ) => this . queueRefresh ( RefreshFlags . RECENT ) ) ;
1054+ this . privacy_settings . connect ( "changed::" + REMEMBER_RECENT_KEY , ( ) => this . queueRefresh ( RefreshFlags . RECENT ) ) ;
10461055 this . _fileFolderAccessActive = false ;
10471056 this . _pathCompleter = new Gio . FilenameCompleter ( ) ;
10481057 this . _pathCompleter . set_dirs_only ( false ) ;
10491058 this . lastAcResults = [ ] ;
10501059 this . settings . bind ( "search-filesystem" , "searchFilesystem" ) ;
1051- this . refreshing = false ; // used as a flag to know if we're currently refreshing (so we don't do it more than once concurrently)
1052-
10531060 this . contextMenu = null ;
1054-
10551061 this . lastSelectedCategory = null ;
10561062
10571063 // We shouldn't need to call refreshAll() here... since we get a "icon-theme-changed" signal when CSD starts.
10581064 // The reason we do is in case the Cinnamon icon theme is the same as the one specificed in GTK itself (in .config)
10591065 // In that particular case we get no signal at all.
1060- this . _refreshAll ( ) ;
1066+ this . refreshId = 0 ;
1067+ this . refreshMask = REFRESH_ALL_MASK ;
1068+ this . _doRefresh ( ) ;
10611069
10621070 this . set_show_label_in_vertical_panels ( false ) ;
10631071 }
@@ -1079,32 +1087,44 @@ class CinnamonMenuApplet extends Applet.TextIconApplet {
10791087 } ) ) ;
10801088 }
10811089
1082- onAppSysChanged ( ) {
1083- if ( this . refreshing == false ) {
1084- this . refreshing = true ;
1085- Mainloop . timeout_add_seconds ( 1 , ( ) => this . _refreshAll ( ) ) ;
1086- }
1090+ queueRefresh ( refreshFlags ) {
1091+ if ( ! refreshFlags )
1092+ return ;
1093+ this . refreshMask |= refreshFlags ;
1094+ if ( ! this . refreshId )
1095+ this . refreshId = Mainloop . timeout_add_seconds ( 1 , ( ) => this . _doRefresh ( ) , Mainloop . PRIORITY_LOW ) ;
10871096 }
10881097
1089- _refreshAll ( ) {
1090- try {
1098+ _doRefresh ( ) {
1099+ this . refreshId = 0 ;
1100+ if ( this . refreshMask === 0 )
1101+ return ;
1102+
1103+ let m = this . refreshMask ;
1104+ if ( ( m & RefreshFlags . APP ) === RefreshFlags . APP )
10911105 this . _refreshApps ( ) ;
1106+ if ( ( m & RefreshFlags . FAV ) === RefreshFlags . FAV )
10921107 this . _refreshFavs ( ) ;
1108+ if ( ( m & RefreshFlags . SYSTEM ) === RefreshFlags . SYSTEM )
10931109 this . _refreshSystemButtons ( ) ;
1110+ if ( ( m & RefreshFlags . PLACE ) === RefreshFlags . PLACE )
10941111 this . _refreshPlaces ( ) ;
1112+ if ( ( m & RefreshFlags . RECENT ) === RefreshFlags . RECENT )
10951113 this . _refreshRecent ( ) ;
10961114
1097- this . _resizeApplicationsBox ( ) ;
1098- }
1099- catch ( exception ) {
1100- global . log ( exception ) ;
1101- }
1102- this . refreshing = false ;
1103- }
1115+ this . refreshMask = 0 ;
11041116
1105- _refreshBelowApps ( ) {
1106- this . _refreshPlaces ( ) ;
1107- this . _refreshRecent ( ) ;
1117+ // recent category is always last
1118+ if ( this . recentButton )
1119+ this . categoriesBox . set_child_at_index ( this . recentButton . actor , - 1 ) ;
1120+
1121+ // places is before recents, or last in list if recents is disabled/not generated
1122+ if ( this . placesButton ) {
1123+ if ( this . recentButton )
1124+ this . categoriesBox . set_child_below_sibling ( this . placesButton . actor , this . recentButton . actor ) ;
1125+ else
1126+ this . categoriesBox . set_child_at_index ( this . placesButton . actor , - 1 ) ;
1127+ }
11081128
11091129 this . _resizeApplicationsBox ( ) ;
11101130 }
@@ -2089,14 +2109,14 @@ class CinnamonMenuApplet extends Applet.TextIconApplet {
20892109 this . categoriesBox . add_actor ( this . placesButton . actor ) ;
20902110 }
20912111
2092- // places is before recents, or last in list if recents is disabled
2093- let sibling = this . recentButton ? this . recentButton . actor : null ;
2094- this . categoriesBox . set_child_above_sibling ( this . placesButton . actor , sibling ) ;
2095-
2112+ // places go after the last applicationbutton
2113+ let sibling = this . _applicationsButtons [ this . _applicationsButtons . length - 1 ] . actor ;
20962114 Util . each ( Main . placesManager . getAllPlaces ( ) , place => {
20972115 let button = new PlaceButton ( this , place ) ;
20982116 this . _placesButtons . push ( button ) ;
2099- this . applicationsBox . add_actor ( button . actor ) ;
2117+ this . applicationsBox . insert_child_below ( button . actor , sibling ) ;
2118+ button . actor . visible = false ;
2119+ sibling = button . actor ;
21002120 } ) ;
21012121
21022122 this . _resizeApplicationsBox ( ) ;
@@ -2127,16 +2147,15 @@ class CinnamonMenuApplet extends Applet.TextIconApplet {
21272147 this . categoriesBox . add_actor ( this . recentButton . actor ) ;
21282148 }
21292149
2130- // recent is always last
2131- this . categoriesBox . set_child_at_index ( this . recentButton . actor , - 1 ) ;
2132-
21332150 if ( this . RecentManager . _infosByTimestamp . length > 0 ) {
21342151 this . noRecentDocuments = false ;
21352152 Util . each ( this . RecentManager . _infosByTimestamp , ( info ) => {
21362153 let button = new RecentButton ( this , info ) ;
21372154 this . _recentButtons . push ( button ) ;
21382155 this . applicationsBox . add_actor ( button . actor ) ;
2156+ button . actor . visible = false ;
21392157 } ) ;
2158+
21402159 let button = new SimpleMenuItem ( this , { name : _ ( "Clear list" ) ,
21412160 description : ( "Clear all recent documents" ) ,
21422161 type : 'recent-clear' ,
@@ -2154,6 +2173,7 @@ class CinnamonMenuApplet extends Applet.TextIconApplet {
21542173
21552174 this . _recentButtons . push ( button ) ;
21562175 this . applicationsBox . add_actor ( button . actor ) ;
2176+ button . actor . visible = false ;
21572177 } else {
21582178 this . noRecentDocuments = true ;
21592179 let button = new SimpleMenuItem ( this , { name : _ ( "No recent documents" ) ,
@@ -2164,6 +2184,7 @@ class CinnamonMenuApplet extends Applet.TextIconApplet {
21642184 button . addLabel ( button . name , 'menu-application-button-label' ) ;
21652185 this . _recentButtons . push ( button ) ;
21662186 this . applicationsBox . add_actor ( button . actor ) ;
2187+ button . actor . visible = false ;
21672188 }
21682189
21692190 this . _resizeApplicationsBox ( ) ;
@@ -2173,19 +2194,22 @@ class CinnamonMenuApplet extends Applet.TextIconApplet {
21732194 /* iterate in reverse, so multiple splices will not upset
21742195 * the remaining elements */
21752196 for ( let i = this . _categoryButtons . length - 1 ; i > - 1 ; i -- ) {
2176- if ( this . _categoryButtons [ i ] . categoryId != 'place' &&
2177- this . _categoryButtons [ i ] . categoryId != 'recent' ) {
2178- this . _categoryButtons [ i ] . destroy ( ) ;
2179- this . _categoryButtons . splice ( i , 1 ) ;
2180- }
2197+ let b = this . _categoryButtons [ i ] ;
2198+ if ( b === this . _allAppsCategoryButton ||
2199+ [ 'place' , 'recent' ] . includes ( b . categoryId ) )
2200+ continue ;
2201+ this . _categoryButtons [ i ] . destroy ( ) ;
2202+ this . _categoryButtons . splice ( i , 1 ) ;
21812203 }
21822204
21832205 this . _applicationsButtons . forEach ( button => button . destroy ( ) ) ;
21842206 this . _applicationsButtons = [ ] ;
21852207
2186- this . _allAppsCategoryButton = new CategoryButton ( this ) ;
2187- this . categoriesBox . add_actor ( this . _allAppsCategoryButton . actor ) ;
2188- this . _categoryButtons . push ( this . _allAppsCategoryButton ) ;
2208+ if ( ! this . _allAppsCategoryButton ) {
2209+ this . _allAppsCategoryButton = new CategoryButton ( this ) ;
2210+ this . categoriesBox . add_actor ( this . _allAppsCategoryButton . actor ) ;
2211+ this . _categoryButtons . push ( this . _allAppsCategoryButton ) ;
2212+ }
21892213
21902214 // grab top level directories and all apps in them
21912215 let [ apps , dirs ] = AppUtils . getApps ( ) ;
@@ -2197,11 +2221,12 @@ class CinnamonMenuApplet extends Applet.TextIconApplet {
21972221 this . categoriesBox . add_actor ( categoryButton . actor ) ;
21982222 } ) ;
21992223
2200- // generate all app buttons and associate all categories
2201- Util . each ( apps , ( a ) => {
2202- let app = a [ 0 ] ;
2224+ /* we add them in reverse at index 0 so they are always above places and
2225+ * recent buttons, and below */
2226+ for ( let i = apps . length - 1 ; i > - 1 ; i -- ) {
2227+ let app = apps [ i ] [ 0 ] ;
22032228 let button = new ApplicationButton ( this , app ) ;
2204- button . category = a [ 1 ] ;
2229+ button . category = apps [ i ] [ 1 ] ;
22052230 let appKey = app . get_id ( ) || `${ app . get_name ( ) } :${ app . get_description ( ) } ` ;
22062231
22072232 // appsWereRefreshed if this is not initial load. on initial load every
@@ -2212,9 +2237,12 @@ class CinnamonMenuApplet extends Applet.TextIconApplet {
22122237 this . _knownApps . add ( appKey ) ;
22132238
22142239 this . _applicationsButtons . push ( button ) ;
2215- this . applicationsBox . add_actor ( button . actor ) ;
2216- } ) ;
2240+ this . applicationsBox . insert_child_at_index ( button . actor , 0 ) ;
2241+ button . actor . visible = false ;
2242+ }
22172243
2244+ // we expect this array to be in the same order as the child list
2245+ this . _applicationsButtons . reverse ( ) ;
22182246 this . _appsWereRefreshed = true ;
22192247 }
22202248
0 commit comments