@@ -135,7 +135,7 @@ class VisibleChildIterator {
135135 * no-favorites "No favorite documents" button
136136 * none Default type
137137 * place PlaceButton
138- * favorite PathButton
138+ * favorite FavoriteDocumentButton
139139 * recent PathButton
140140 * recent-clear "Clear recent documents" button
141141 * search-provider SearchProviderResultButton
@@ -331,11 +331,11 @@ class SimpleMenuItem {
331331 }
332332}
333333
334- class ApplicationContextMenuItem extends PopupMenu . PopupBaseMenuItem {
335- constructor ( appButton , label , action , iconName ) {
334+ class ContextMenuItem extends PopupMenu . PopupBaseMenuItem {
335+ constructor ( button , label , action , iconName ) {
336336 super ( { focusOnHover : false } ) ;
337337
338- this . _appButton = appButton ;
338+ this . _button = button ;
339339 this . _action = action ;
340340 this . label = new St . Label ( { text : label } ) ;
341341
@@ -351,6 +351,12 @@ class ApplicationContextMenuItem extends PopupMenu.PopupBaseMenuItem {
351351
352352 this . addActor ( this . label ) ;
353353 }
354+ }
355+
356+ class ApplicationContextMenuItem extends ContextMenuItem {
357+ constructor ( appButton , label , action , iconName ) {
358+ super ( appButton , label , action , iconName ) ;
359+ }
354360
355361 activate ( event ) {
356362 let closeMenu = true ;
@@ -371,13 +377,13 @@ class ApplicationContextMenuItem extends PopupMenu.PopupBaseMenuItem {
371377 let launcherApplet = Main . AppletManager . get_role_provider ( Main . AppletManager . Roles . PANEL_LAUNCHER ) ;
372378 if ( ! launcherApplet )
373379 return true ;
374- launcherApplet . acceptNewLauncher ( this . _appButton . app . get_id ( ) ) ;
380+ launcherApplet . acceptNewLauncher ( this . _button . app . get_id ( ) ) ;
375381 }
376382 return false ;
377383 } ) ;
378384 break ;
379385 case "add_to_desktop" :
380- let file = Gio . file_new_for_path ( this . _appButton . app . get_app_info ( ) . get_filename ( ) ) ;
386+ let file = Gio . file_new_for_path ( this . _button . app . get_app_info ( ) . get_filename ( ) ) ;
381387 let destFile = Gio . file_new_for_path ( USER_DESKTOP_PATH + "/" + file . get_basename ( ) ) ;
382388 try {
383389 file . copy ( destFile , 0 , null , function ( ) { } ) ;
@@ -387,45 +393,42 @@ class ApplicationContextMenuItem extends PopupMenu.PopupBaseMenuItem {
387393 }
388394 break ;
389395 case "add_to_favorites" :
390- AppFavorites . getAppFavorites ( ) . addFavorite ( this . _appButton . app . get_id ( ) ) ;
396+ AppFavorites . getAppFavorites ( ) . addFavorite ( this . _button . app . get_id ( ) ) ;
391397 this . label . set_text ( _ ( "Remove from favorites" ) ) ;
392398 this . icon . icon_name = "xsi-starred" ;
393399 this . _action = "remove_from_favorites" ;
394400 closeMenu = false ;
395401 break ;
396402 case "remove_from_favorites" :
397- AppFavorites . getAppFavorites ( ) . removeFavorite ( this . _appButton . app . get_id ( ) ) ;
403+ AppFavorites . getAppFavorites ( ) . removeFavorite ( this . _button . app . get_id ( ) ) ;
398404 this . label . set_text ( _ ( "Add to favorites" ) ) ;
399405 this . icon . icon_name = "xsi-non-starred" ;
400406 this . _action = "add_to_favorites" ;
401407 closeMenu = false ;
402408 break ;
403409 case "app_properties" :
404- Util . spawnCommandLine ( "cinnamon-desktop-editor -mlauncher -o" + GLib . shell_quote ( this . _appButton . app . get_app_info ( ) . get_filename ( ) ) ) ;
410+ Util . spawnCommandLine ( "cinnamon-desktop-editor -mlauncher -o" + GLib . shell_quote ( this . _button . app . get_app_info ( ) . get_filename ( ) ) ) ;
405411 break ;
406412 case "uninstall" :
407- Util . spawnCommandLine ( "/usr/bin/cinnamon-remove-application '" + this . _appButton . app . get_app_info ( ) . get_filename ( ) + "'" ) ;
413+ Util . spawnCommandLine ( "/usr/bin/cinnamon-remove-application '" + this . _button . app . get_app_info ( ) . get_filename ( ) + "'" ) ;
408414 break ;
409415 case "offload_launch" :
410416 try {
411- this . _appButton . app . launch_offloaded ( 0 , [ ] , - 1 ) ;
417+ this . _button . app . launch_offloaded ( 0 , [ ] , - 1 ) ;
412418 } catch ( e ) {
413419 logError ( e , "Could not launch app with dedicated gpu: " ) ;
414420 }
415421 break ;
416422 default :
417423 if ( this . _action . startsWith ( "action_" ) ) {
418424 let action = this . _action . substring ( 7 ) ;
419- this . _appButton . app . get_app_info ( ) . launch_action ( action , global . create_app_launch_context ( ) ) ;
425+ this . _button . app . get_app_info ( ) . launch_action ( action , global . create_app_launch_context ( ) ) ;
420426 } else return true ;
421427 }
422- if ( closeMenu ) {
423- this . _appButton . applet . toggleContextMenu ( this . _appButton ) ;
424- this . _appButton . applet . menu . close ( ) ;
425- }
428+ if ( closeMenu )
429+ this . _button . applet . menu . close ( ) ;
426430 return false ;
427431 }
428-
429432}
430433
431434class GenericApplicationButton extends SimpleMenuItem {
@@ -757,15 +760,53 @@ class RecentButton extends SimpleMenuItem {
757760 }
758761}
759762
763+ class PathContextMenuItem extends ContextMenuItem {
764+ constructor ( pathButton , label , action , iconName ) {
765+ super ( pathButton , label , action , iconName ) ;
766+ }
767+
768+ activate ( event ) {
769+ switch ( this . _action ) {
770+ case "open_containing_folder" :
771+ this . _openContainingFolder ( ) ;
772+ this . _button . applet . menu . close ( ) ;
773+ return false ;
774+ }
775+ return true ;
776+ }
777+
778+ _openContainingFolder ( ) {
779+ try {
780+ Gio . DBus . session . call_sync (
781+ "org.freedesktop.FileManager1" ,
782+ "/org/freedesktop/FileManager1" ,
783+ "org.freedesktop.FileManager1" ,
784+ "ShowItems" ,
785+ new GLib . Variant ( "(ass)" , [
786+ [ this . _button . uri ] ,
787+ global . get_pid ( ) . toString ( )
788+ ] ) ,
789+ null ,
790+ Gio . DBusCallFlags . NONE ,
791+ 1000 ,
792+ null
793+ ) ;
794+ } catch ( e ) {
795+ global . logError ( `Could not open containing folder: ${ e } ` ) ;
796+ }
797+ }
798+ }
799+
760800class PathButton extends SimpleMenuItem {
761- constructor ( applet , type , name , uri , icon ) {
801+ constructor ( applet , type , name , uri , mimeType , icon ) {
762802 super ( applet , {
763803 name : name ,
764804 description : shorten_path ( uri , name ) ,
765805 type : type ,
766806 styleClass : 'appmenu-application-button' ,
767- withMenu : false ,
807+ withMenu : true ,
768808 uri : uri ,
809+ mimeType : mimeType
769810 } ) ;
770811
771812 this . icon = icon ;
@@ -796,6 +837,55 @@ class PathButton extends SimpleMenuItem {
796837 source . notify ( notification ) ;
797838 }
798839 }
840+
841+ populateMenu ( menu ) {
842+ if ( this . mimeType !== "inode/directory" ) {
843+ let menuItem = new PathContextMenuItem ( this , _ ( "Open containing folder" ) , "open_containing_folder" , "xsi-go-jump-symbolic" ) ;
844+ menu . addMenuItem ( menuItem ) ;
845+ }
846+ }
847+ }
848+
849+ class FavoriteDocumentContextMenuItem extends ContextMenuItem {
850+ constructor ( favDocButton , label , action , iconName ) {
851+ super ( favDocButton , label , action , iconName ) ;
852+ }
853+
854+ activate ( event ) {
855+ switch ( this . _action ) {
856+ case "remove_from_favorite_documents" :
857+ this . _button . _unfavorited = true ;
858+ // Do not refresh the favdoc menu during interaction, as it will destroy every menu item.
859+ this . _button . applet . deferRefreshMask |= RefreshFlags . FAV_DOC ;
860+ this . _button . applet . closeContextMenu ( true ) ;
861+ this . _button . actor . hide ( ) ;
862+ XApp . Favorites . get_default ( ) . remove ( this . _button . uri ) ;
863+ return false ;
864+ }
865+ return true ;
866+ }
867+ }
868+
869+ class FavoriteDocumentButton extends PathButton {
870+ constructor ( applet , type , name , uri , mimeType , icon ) {
871+ super ( applet , type , name , uri , mimeType , icon ) ;
872+
873+ this . _unfavorited = false ;
874+ this . _signals . connect ( this . actor , "show" , ( ) => {
875+ if ( this . _unfavorited ) {
876+ this . actor . hide ( ) ;
877+ return Clutter . EVENT_STOP ;
878+ }
879+ return Clutter . EVENT_PROPAGATE ;
880+ } ) ;
881+ }
882+
883+ populateMenu ( menu ) {
884+ let menuItem = new FavoriteDocumentContextMenuItem ( this , _ ( "Remove from favorites" ) , "remove_from_favorite_documents" , "xsi-unfavorite-symbolic" ) ;
885+ menu . addMenuItem ( menuItem ) ;
886+
887+ super . populateMenu ( menu ) ;
888+ }
799889}
800890
801891class CategoryButton extends SimpleMenuItem {
@@ -1222,6 +1312,7 @@ class CinnamonMenuApplet extends Applet.TextIconApplet {
12221312 // In that particular case we get no signal at all.
12231313 this . refreshId = 0 ;
12241314 this . refreshMask = REFRESH_ALL_MASK ;
1315+ this . deferRefreshMask = 0 ;
12251316 this . _doRefresh ( ) ;
12261317
12271318 this . set_show_label_in_vertical_panels ( false ) ;
@@ -1275,7 +1366,7 @@ class CinnamonMenuApplet extends Applet.TextIconApplet {
12751366
12761367 _doRefresh ( ) {
12771368 this . refreshId = 0 ;
1278- if ( this . refreshMask === 0 )
1369+ if ( ( this . refreshMask &= ~ this . deferRefreshMask ) === 0 )
12791370 return ;
12801371
12811372 let m = this . refreshMask ;
@@ -1414,6 +1505,10 @@ class CinnamonMenuApplet extends Applet.TextIconApplet {
14141505 if ( this . searchActive ) {
14151506 this . resetSearch ( ) ;
14161507 }
1508+ if ( this . deferRefreshMask !== 0 ) {
1509+ this . queueRefresh ( this . deferRefreshMask ) ;
1510+ this . deferRefreshMask = 0 ;
1511+ }
14171512
14181513 this . hoveredCategory = null ;
14191514 this . hoveredApp = null ;
@@ -1578,7 +1673,8 @@ class CinnamonMenuApplet extends Applet.TextIconApplet {
15781673 button . populateMenu ( this . contextMenu ) ;
15791674 }
15801675
1581- this . contextMenu . toggle ( ) ;
1676+ if ( this . contextMenu . numMenuItems !== 0 )
1677+ this . contextMenu . toggle ( ) ;
15821678 }
15831679
15841680 _navigateContextMenu ( button , symbol , ctrlKey ) {
@@ -2179,7 +2275,7 @@ class CinnamonMenuApplet extends Applet.TextIconApplet {
21792275 this . noRecentDocuments = false ;
21802276 recents . forEach ( info => {
21812277 let icon = info . createIcon ( this . applicationIconSize ) ;
2182- let button = new PathButton ( this , 'recent' , info . name , info . uri , icon ) ;
2278+ let button = new PathButton ( this , 'recent' , info . name , info . uri , info . mimeType , icon ) ;
21832279 this . _recentButtons . push ( button ) ;
21842280 this . applicationsBox . add_actor ( button . actor ) ;
21852281 button . actor . visible = this . menu . isOpen && this . lastSelectedCategory === "recent" ;
@@ -2243,7 +2339,7 @@ class CinnamonMenuApplet extends Applet.TextIconApplet {
22432339 gicon : Gio . content_type_get_icon ( info . cached_mimetype ) ,
22442340 icon_size : this . applicationIconSize
22452341 } ) ;
2246- let button = new PathButton ( this , 'favorite' , info . display_name , info . uri , icon ) ;
2342+ let button = new FavoriteDocumentButton ( this , 'favorite' , info . display_name , info . uri , info . cached_mimetype , icon ) ;
22472343 this . _favoriteDocButtons . push ( button ) ;
22482344 this . applicationsBox . add_actor ( button . actor ) ;
22492345 button . actor . visible = this . menu . isOpen && this . lastSelectedCategory === "favorite" ;
0 commit comments