Skip to content

Commit eb099fe

Browse files
committed
menu: Add context menu actions for favorites/recents
Add `Remove from favorites` and `Open containing folder` action for favorites/recents.
1 parent 979d0ea commit eb099fe

File tree

1 file changed

+119
-23
lines changed
  • files/usr/share/cinnamon/applets/menu@cinnamon.org

1 file changed

+119
-23
lines changed

files/usr/share/cinnamon/applets/menu@cinnamon.org/applet.js

Lines changed: 119 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -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

431434
class 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+
760800
class 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

801891
class 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

Comments
 (0)