diff --git a/data/theme/cinnamon-sass/_widgets.scss b/data/theme/cinnamon-sass/_widgets.scss index 787e2b7159..4995d66338 100644 --- a/data/theme/cinnamon-sass/_widgets.scss +++ b/data/theme/cinnamon-sass/_widgets.scss @@ -15,3 +15,4 @@ @import 'widgets/startmenu'; @import 'widgets/switch-check'; @import 'widgets/windowlist'; +@import 'widgets/deprecated'; diff --git a/data/theme/cinnamon-sass/widgets/_deprecated.scss b/data/theme/cinnamon-sass/widgets/_deprecated.scss new file mode 100644 index 0000000000..c79a776bd9 --- /dev/null +++ b/data/theme/cinnamon-sass/widgets/_deprecated.scss @@ -0,0 +1,98 @@ +// OLD MENU - Used by some of the menu spices + +$menu_outer_padding: 9px; +$menu_outer_border_radius: $base_border_radius * 1.25; + +%start_menu_button { + padding: $base_padding; + spacing: $base_margin; + border-radius: $base_border_radius; +} + +.menu { + + // this can be used to color the entire menu background but we aren't using it here + &-background {} + + &-favorites-box { + padding: $base_padding * 1.5; + background-color: $light_bg_color; + border: 1px solid transparentize(black, 0.9); + border-radius: $base_border_radius; + } + + &-favorites-button { + padding: $base_padding * 1.5; + border-radius: $base_border_radius; + + &:hover { background-color: $lightest_bg_color; } + } + + &-categories-box { padding: $menu_outer_padding $base_padding * 4; } + &-applications-box { padding: $menu_outer_padding; } + &-applications-inner-box { + &:ltr { padding-left: $base_padding * 4; } + &:rtl { padding-right: $base_padding * 4; } + } + + &-application-button { + @extend %start_menu_button; + + &-label { padding: 0; } + + &:highlighted { font-weight: bold; } + + &-selected { + @extend %start_menu_button; + + background-color: $light_bg_color; + + &:highlighted { font-weight: bold; } + } + } + + &-category-button { + @extend %start_menu_button; + + &-label { padding: 0; } + + &:hover { background-color: $lighter_bg_color; } + + &-selected { + @extend %start_menu_button; + + background-color: $light_bg_color; + } + + &-greyed { + @extend %start_menu_button; + color: $insensitive_fg_color; + font-style: italic; + + StIcon { opacity: 0.5; } + } + } + + &-context-menu {} + + &-selected-app-box { + padding-right: $base_padding * 4; + padding-left: $base_padding * 4; + text-align: right; + } + + &-selected-app-title { @extend %heading; } + &-selected-app-description { color: $insensitive_fg_color; } + + &-search-box { + padding: 0 0 $base_padding $menu_outer_padding; + } +} + +#menu-search-entry { + @extend %entry; +} + +.menu-search-entry-icon { + icon-size: $scalable_icon_size; +} diff --git a/data/theme/cinnamon-sass/widgets/_startmenu.scss b/data/theme/cinnamon-sass/widgets/_startmenu.scss index c2e3cc5a44..1cfeaeea54 100644 --- a/data/theme/cinnamon-sass/widgets/_startmenu.scss +++ b/data/theme/cinnamon-sass/widgets/_startmenu.scss @@ -1,48 +1,81 @@ -$menu_outer_padding: 9px; -$menu_outer_border_radius: $base_border_radius * 1.25; +$appmenu_outer_padding: 9px; +$appmenu_outer_border_radius: $base_border_radius * 1.25; -%start_menu_button { +%appmenu_button { padding: $base_padding; spacing: $base_margin; border-radius: $base_border_radius; } -.menu { +.appmenu { // this can be used to color the entire menu background but we aren't using it here - &-background {} - - &-favorites-box { - padding: $base_padding * 1.5; - background-color: $light_bg_color; - border: 1px solid transparentize(black, 0.9); - border-radius: $base_border_radius; + &-background { + // using this to override the default padding on menus so widgets can span edge + // to edge. The side effect is that some of our internal container widgets + // will need to have a border-radius added to them or the corners will poke out + // the edges of the menu. + .popup-menu-content { padding: 0; } } - &-favorites-button { - padding: $base_padding * 1.5; - border-radius: $base_border_radius; + &-sidebar { + background-color: $base_color; + border-radius: $appmenu_outer_border_radius 0 0 $appmenu_outer_border_radius; + border-right-width: 1px; + border-color: $borders_color; + + .sidebar-user-box { + padding-top: $appmenu_outer_padding; + padding-bottom: $appmenu_outer_padding / 2; + } + + .appmenu-favorites-button { + @extend %appmenu_button; + + padding: 3px $base_padding 3px $base_padding; + margin: 0 $appmenu_outer_padding 0 $appmenu_outer_padding; - &:hover { background-color: $lightest_bg_color; } + &:hover { + background-color: $lighter_bg_color; + border-color: $borders_color; + } + } } - &-categories-box { padding: $menu_outer_padding $base_padding * 4; } - &-applications-box { padding: $menu_outer_padding; } - &-applications-inner-box { - &:ltr { padding-left: $base_padding * 4; } - &:rtl { padding-right: $base_padding * 4; } + &-system-buttons-box { + spacing: 6px; + padding-left: 6px; + padding-right: 6px; + + .system-button { + padding: $base_padding * 1.4; + border: 1px solid $borders_color; + border-radius: 9999px; + background-color: lighten($bg_color, 10%); + + &:hover { background-color: $accent_color; } + } } + &-categories-box { padding: $appmenu_outer_padding $base_padding * 3; } + &-applications-box { padding: $appmenu_outer_padding; } + // This small amount of padding is needed to be able + // to resize the menu with the mouse + &-applications-scrollbox { padding-right: 3px; } + &-application-button { - @extend %start_menu_button; + @extend %appmenu_button; &-label { padding: 0; } + &-description { + @extend %caption; + color: $light_text_color; + } &:highlighted { font-weight: bold; } &-selected { - @extend %start_menu_button; - + @extend %appmenu_button; background-color: $light_bg_color; &:highlighted { font-weight: bold; } @@ -50,20 +83,20 @@ $menu_outer_border_radius: $base_border_radius * 1.25; } &-category-button { - @extend %start_menu_button; + @extend %appmenu_button; &-label { padding: 0; } &:hover { background-color: $lighter_bg_color; } &-selected { - @extend %start_menu_button; + @extend %appmenu_button; background-color: $light_bg_color; } &-greyed { - @extend %start_menu_button; + @extend %appmenu_button; color: $insensitive_fg_color; font-style: italic; @@ -73,24 +106,18 @@ $menu_outer_border_radius: $base_border_radius * 1.25; &-context-menu {} - &-selected-app-box { - padding-right: $base_padding * 4; - padding-left: $base_padding * 4; - text-align: right; + &-search-box { + padding: $base_padding $base_padding $base_padding $appmenu_outer_padding; + border-bottom-width: 1px; + border-color: $borders_color; } - &-selected-app-title { @extend %heading; } - &-selected-app-description { color: $insensitive_fg_color; } - - &-search-box { - padding: 0 0 $base_padding $menu_outer_padding; + &-search-entry-icon { + icon-size: $scalable_icon_size; } } -#menu-search-entry { +#appmenu-search-entry { @extend %entry; -} - -.menu-search-entry-icon { - icon-size: $scalable_icon_size; + margin: $appmenu_outer_padding; } diff --git a/files/usr/share/cinnamon/applets/menu@cinnamon.org/applet.js b/files/usr/share/cinnamon/applets/menu@cinnamon.org/applet.js index 0afcbaf73e..421e921f23 100644 --- a/files/usr/share/cinnamon/applets/menu@cinnamon.org/applet.js +++ b/files/usr/share/cinnamon/applets/menu@cinnamon.org/applet.js @@ -1,17 +1,18 @@ const Applet = imports.ui.applet; const Mainloop = imports.mainloop; -const Lang = imports.lang; const Cinnamon = imports.gi.Cinnamon; const St = imports.gi.St; const Clutter = imports.gi.Clutter; const Main = imports.ui.main; const MessageTray = imports.ui.messageTray; const PopupMenu = imports.ui.popupMenu; +const UserWidget = imports.ui.userWidget; const AppFavorites = imports.ui.appFavorites; const Gtk = imports.gi.Gtk; const Atk = imports.gi.Atk; const Gio = imports.gi.Gio; const XApp = imports.gi.XApp; +const AccountsService = imports.gi.AccountsService; const GnomeSession = imports.misc.gnomeSession; const ScreenSaver = imports.misc.screenSaver; const FileUtils = imports.misc.fileUtils; @@ -60,6 +61,22 @@ const MATCH_ADDERS = [ 3000 // id ]; +function calc_angle(x, y) { + if (x === 0) { x = .001 } + if (y === 0) { y = .001 } + + let r = Math.atan2(y, x) * (180 / Math.PI); + return r; +} + +function shorten_path(path, filename) { + let str = path.replace("file://", ""); + str = str.replace(GLib.get_home_dir(), "~"); + str = str.replace("/" + filename, ""); + return str; +} + + /* VisibleChildIterator takes a container (boxlayout, etc.) * and creates an array of its visible children and their index * positions. We can then work through that list without @@ -73,15 +90,6 @@ const MATCH_ADDERS = [ * navigating, so increase speed, we reload only when we * want to use it. */ - -function calc_angle(x, y) { - if (x === 0) { x = .001 } - if (y === 0) { y = .001 } - - let r = Math.atan2(y, x) * (180 / Math.PI); - return r; -} - class VisibleChildIterator { constructor(container) { this.container = container; @@ -90,42 +98,31 @@ class VisibleChildIterator { reloadVisible() { this.array = this.container.get_focus_chain() - .filter(x => !(x._delegate instanceof PopupMenu.PopupSeparatorMenuItem)); + .filter(x => !(x._delegate instanceof PopupMenu.PopupSeparatorMenuItem)); } - getNextVisible(curChild) { + next(curChild) { return this.getVisibleItem(this.array.indexOf(curChild) + 1); } - getPrevVisible(curChild) { + prev(curChild) { return this.getVisibleItem(this.array.indexOf(curChild) - 1); } - getFirstVisible() { + first() { return this.array[0]; } - getLastVisible() { + last() { return this.array[this.array.length - 1]; } - getVisibleIndex(curChild) { - return this.array.indexOf(curChild); - } - getVisibleItem(index) { let len = this.array.length; index = ((index % len) + len) % len; return this.array[index]; } - getNumVisibleChildren() { - return this.array.length; - } - - getAbsoluteIndexOfChild(child) { - return this.container.get_children().indexOf(child); - } } /** @@ -137,7 +134,8 @@ class VisibleChildIterator { * no-recent "No recent documents" button * none Default type * place PlaceButton - * recent RecentsButton + * favorite PathButton + * recent PathButton * recent-clear "Clear recent documents" button * search-provider SearchProviderResultButton * system SystemButton @@ -177,15 +175,23 @@ class SimpleMenuItem { params = Params.parse(params, SMI_DEFAULT_PARAMS, true); this._signals = new SignalManager.SignalManager(); - this.actor = new St.BoxLayout({ style_class: params.styleClass, - reactive: params.reactive, - accessible_role: Atk.Role.MENU_ITEM }); + this.actor = new St.BoxLayout({ + style_class: params.styleClass, + reactive: params.reactive, + accessible_role: Atk.Role.MENU_ITEM, + }); this._signals.connect(this.actor, 'destroy', () => this.destroy(true)); this.actor._delegate = this; this.applet = applet; + this.labelContainer = new St.BoxLayout({ + vertical: true, + y_expand: true, + y_align: Clutter.ActorAlign.CENTER, + }); this.label = null; + this.descriptionLabel = null; this.icon = null; this.matchIndex = NO_MATCH; @@ -197,8 +203,8 @@ class SimpleMenuItem { this._signals.connect(this.actor, 'enter-event', () => applet._buttonEnterEvent(this)); this._signals.connect(this.actor, 'leave-event', () => applet._buttonLeaveEvent(this)); if (params.activatable || params.withMenu) { - this._signals.connect(this.actor, 'button-release-event', Lang.bind(this, this._onButtonReleaseEvent)); - this._signals.connect(this.actor, 'key-press-event', Lang.bind(this, this._onKeyPressEvent)); + this._signals.connect(this.actor, 'button-release-event', this._onButtonReleaseEvent.bind(this)); + this._signals.connect(this.actor, 'key-press-event', this._onKeyPressEvent.bind(this)); } } } @@ -255,16 +261,6 @@ class SimpleMenuItem { this.actor.add_actor(this.icon); } - /** - * Removes the icon previously added with addIcon() - */ - removeIcon() { - if (!this.icon) - return; - this.icon.destroy(); - this.icon = null; - } - /** * Adds an StLabel as the next child, accessible as `this.label`. * @@ -278,21 +274,31 @@ class SimpleMenuItem { if (this.label) return; - this.label = new St.Label({ text: label, y_expand: true, y_align: Clutter.ActorAlign.CENTER }); + this.label = new St.Label({ text: label }); if (styleClass) this.label.set_style_class_name(styleClass); this.label.clutter_text.ellipsize = Pango.EllipsizeMode.END; - this.actor.add_actor(this.label); + this.actor.add_actor(this.labelContainer); + this.labelContainer.add_actor(this.label); } - /** - * Removes the label previously added with addLabel() - */ - removeLabel() { - if (!this.label) + addDescription(label='', styleClass=null) { + if (this.descriptionLabel) return; - this.label.destroy(); - this.label = null; + + if (label === '') + return; + + this.descriptionLabel = new St.Label({ + text: label, + y_expand: true, + y_align: Clutter.ActorAlign.CENTER + }); + + if (styleClass) + this.descriptionLabel.set_style_class_name(styleClass); + this.descriptionLabel.clutter_text.ellipsize = Pango.EllipsizeMode.END; + this.labelContainer.add_actor(this.descriptionLabel); } /** @@ -304,20 +310,13 @@ class SimpleMenuItem { this.actor.add_actor(child); } - /** - * Removes a ClutterActor. - * - * @param {ClutterActor} child - */ - removeActor(child) { - this.actor.remove_actor(child); - } - destroy(actorDestroySignal=false) { this._signals.disconnectAllSignals(); if (this.label) this.label.destroy(); + if (this.descriptionLabel) + this.descriptionLabel.destroy(); if (this.icon) this.icon.destroy(); if (!actorDestroySignal) @@ -326,6 +325,7 @@ class SimpleMenuItem { delete this.actor._delegate; delete this.actor; delete this.label; + delete this.descriptionLabel; delete this.icon; } } @@ -339,7 +339,11 @@ class ApplicationContextMenuItem extends PopupMenu.PopupBaseMenuItem { this.label = new St.Label({ text: label }); if (iconName != null) { - this.icon = new St.Icon({ icon_name: iconName, icon_size: 12, icon_type: St.IconType.SYMBOLIC }); + this.icon = new St.Icon({ + icon_name: iconName, + icon_size: 12, + icon_type: St.IconType.SYMBOLIC, + }); if (this.icon) this.addActor(this.icon); } @@ -415,12 +419,14 @@ class ApplicationContextMenuItem extends PopupMenu.PopupBaseMenuItem { class GenericApplicationButton extends SimpleMenuItem { constructor(applet, app, type, withMenu=false, styleClass="") { let desc = app.get_description() || ""; - super(applet, { name: app.get_name(), - description: desc.split("\n")[0], - type: type, - withMenu: withMenu, - styleClass: styleClass, - app: app }); + super(applet, { + name: app.get_name(), + description: desc.split("\n")[0], + type: type, + withMenu: withMenu, + styleClass: styleClass, + app: app, + }); } highlight() { @@ -479,24 +485,24 @@ class GenericApplicationButton extends SimpleMenuItem { menuItem = new ApplicationContextMenuItem(this, _("Uninstall"), "uninstall", "edit-delete"); menu.addMenuItem(menuItem); } - - let actions = appinfo.list_actions(); - if (actions) { - for (let i = 0; i < actions.length; i++) { - let icon = Util.getDesktopActionIcon(actions[i]); - let label = appinfo.get_action_name(actions[i]); - menuItem = new ApplicationContextMenuItem(this, label, "action_" + actions[i], icon); - menu.addMenuItem(menuItem); - } + + for (const action of appinfo.list_actions()) { + let icon = Util.getDesktopActionIcon(action); + let label = appinfo.get_action_name(action); + menuItem = new ApplicationContextMenuItem(this, label, "action_" + action, icon); + menu.addMenuItem(menuItem); } } } class TransientButton extends SimpleMenuItem { constructor(applet, pathOrCommand) { - super(applet, { description: pathOrCommand, - type: 'transient', - styleClass: 'menu-application-button' }); + super(applet, { + description: pathOrCommand, + type: 'transient', + styleClass: 'appmenu-application-button', + }); + if (pathOrCommand.startsWith('~')) { pathOrCommand = pathOrCommand.slice(1); pathOrCommand = GLib.get_home_dir() + pathOrCommand; @@ -516,23 +522,29 @@ class TransientButton extends SimpleMenuItem { this.file = Gio.file_new_for_path(this.pathOrCommand); - if (applet.showApplicationIcons) { - try { - this.handler = this.file.query_default_handler(null); - let contentType = Gio.content_type_guess(this.pathOrCommand, null); - let themedIcon = Gio.content_type_get_icon(contentType[0]); - this.icon = new St.Icon({gicon: themedIcon, icon_size: applet.applicationIconSize, icon_type: St.IconType.FULLCOLOR }); - } catch (e) { - this.handler = null; - let iconName = this.isPath ? 'folder' : 'unknown'; - this.icon = new St.Icon({icon_name: iconName, icon_size: applet.applicationIconSize, icon_type: St.IconType.FULLCOLOR}); - // @todo Would be nice to indicate we don't have a handler for this file. - } - - this.addActor(this.icon); + try { + this.handler = this.file.query_default_handler(null); + let contentType = Gio.content_type_guess(this.pathOrCommand, null); + let themedIcon = Gio.content_type_get_icon(contentType[0]); + this.icon = new St.Icon({ + gicon: themedIcon, + icon_size: applet.applicationIconSize, + icon_type: St.IconType.FULLCOLOR, + }); + } catch (e) { + this.handler = null; + let iconName = this.isPath ? 'folder' : 'unknown'; + this.icon = new St.Icon({ + icon_name: iconName, + icon_size: applet.applicationIconSize, + icon_type: St.IconType.FULLCOLOR, + }); + // @todo Would be nice to indicate we don't have a handler for this file. } - this.addLabel(this.description, 'menu-application-button-label'); + this.addActor(this.icon); + + this.addLabel(this.description, 'appmenu-application-button-label'); this.isDraggableApp = false; } @@ -555,18 +567,30 @@ class TransientButton extends SimpleMenuItem { class ApplicationButton extends GenericApplicationButton { constructor(applet, app) { - super(applet, app, 'app', true, 'menu-application-button'); + super(applet, app, 'app', true, 'appmenu-application-button'); this.category = []; - this.icon = this.app.create_icon_texture(applet.applicationIconSize); + let gicon = this.icon.get_gicon(); + if (gicon?.get_names) { + let iconNames = gicon.get_names(); + let iconTheme = Gtk.IconTheme.get_default(); + let hasAnyIcon = gicon.get_names().some(name => iconTheme.has_icon(name)); + if (!hasAnyIcon) { + this.icon = new St.Icon({ + icon_name: 'application-x-executable', + icon_size: applet.applicationIconSize, + icon_type: St.IconType.FULLCOLOR + }); + } + } this.addActor(this.icon); - if (!applet.showApplicationIcons) - this.icon.visible = false; - this.addLabel(this.name, 'menu-application-button-label'); + this.addLabel(this.name, 'appmenu-application-button-label'); + if (applet.showDescription) + this.addDescription(this.description, 'appmenu-application-button-description'); this._draggable = DND.makeDraggable(this.actor); - this._signals.connect(this._draggable, 'drag-end', Lang.bind(this, this._onDragEnd)); + this._signals.connect(this._draggable, 'drag-end', this._onDragEnd.bind(this)); this.isDraggableApp = true; this.searchStrings = [ @@ -582,7 +606,7 @@ class ApplicationButton extends GenericApplicationButton { } getDragActor() { - return this.app.create_icon_texture(this.applet.favIconSize); + return this.app.create_icon_texture(this.applet.sidebarIconSize); } // Returns the original actor that should align with the actor @@ -592,8 +616,9 @@ class ApplicationButton extends GenericApplicationButton { } _onDragEnd() { - this.applet.favoritesBox._delegate._clearDragPlaceholder(); + this.applet.favoriteAppsBox._delegate._clearDragPlaceholder(); } + destroy() { delete this._draggable; super.destroy(); @@ -602,27 +627,30 @@ class ApplicationButton extends GenericApplicationButton { class SearchProviderResultButton extends SimpleMenuItem { constructor(applet, provider, result) { - super(applet, { name:result.label, - description: result.description, - type: 'search-provider', - styleClass: 'menu-application-button', - provider: provider, - result: result }); - - if (applet.showApplicationIcons) { - if (result.icon) { - this.icon = result.icon; - } else if (result.icon_app) { - this.icon = result.icon_app.create_icon_texture(applet.applicationIconSize); - } else if (result.icon_filename) { - this.icon = new St.Icon({gicon: new Gio.FileIcon({file: Gio.file_new_for_path(result.icon_filename)}), icon_size: applet.applicationIconSize}); - } + super(applet, { + name:result.label, + description: result.description, + type: 'search-provider', + styleClass: 'appmenu-application-button', + provider: provider, + result: result, + }); - if (this.icon) - this.addActor(this.icon); + if (result.icon) { + this.icon = result.icon; + } else if (result.icon_app) { + this.icon = result.icon_app.create_icon_texture(applet.applicationIconSize); + } else if (result.icon_filename) { + this.icon = new St.Icon({ + gicon: new Gio.FileIcon({ file: Gio.file_new_for_path(result.icon_filename) }), + icon_size: applet.applicationIconSize, + }); } - this.addLabel(result.label, 'menu-application-button-label'); + if (this.icon) + this.addActor(this.icon); + + this.addLabel(result.label, 'appmenu-application-button-label'); } activate() { @@ -652,26 +680,20 @@ class PlaceButton extends SimpleMenuItem { selectedAppId = place.name } - super(applet, { name: place.name, - description: selectedAppId, - type: 'place', - styleClass: 'menu-application-button', - place: place }); + super(applet, { + name: place.name, + type: 'place', + styleClass: 'appmenu-favorites-button', + place: place, + }); - this.icon = place.iconFactory(applet.applicationIconSize); + this.icon = place.iconFactory(applet.sidebarIconSize); if (this.icon) this.addActor(this.icon); else this.addIcon(applet.applicationIconSize, 'folder'); - if (!applet.showApplicationIcons) - this.icon.visible = false; - - this.addLabel(this.name, 'menu-application-button-label'); - - this.searchStrings = [ - AppUtils.decomp_string(place.name).replace(/\s/g, '') - ]; + this.addLabel(this.name, 'appmenu-application-button-label'); } activate() { @@ -680,46 +702,26 @@ class PlaceButton extends SimpleMenuItem { } } -class UserfileContextMenuItem extends PopupMenu.PopupBaseMenuItem { - constructor(button, label, is_default, cbParams, callback) { - super({focusOnHover: false}); - - this._button = button; - this._cbParams = cbParams; - this._callback = callback; - this.label = new St.Label({ text: label }); - this.addActor(this.label); - - if (is_default) - this.label.style = "font-weight: bold;"; - } - - activate (event) { - this._callback(...this._cbParams); - return false; - } -} - class RecentButton extends SimpleMenuItem { constructor(applet, recent) { - let fileIndex = recent.uriDecoded.indexOf("file:///"); - let selectedAppUri = fileIndex === -1 ? "" : recent.uriDecoded.substr(fileIndex + 7); - - super(applet, { name: recent.name, - description: selectedAppUri, - type: 'recent', - styleClass: 'menu-application-button', - withMenu: true, - mimeType: recent.mimeType, - uri: recent.uri, - uriDecoded: recent.uriDecoded }); + let path = recent.uriDecoded.replace("file://", ""); + path = path.replace(GLib.get_home_dir(), "~").replace("/" + recent.name, ""); + + super(applet, { + name: recent.name, + description: path, + type: 'recent', + styleClass: 'appmenu-application-button', + withMenu: true, + uri: recent.uri, + }); this.icon = recent.createIcon(applet.applicationIconSize); this.addActor(this.icon); - if (!applet.showApplicationIcons) - this.icon.visible = false; - this.addLabel(this.name, 'menu-application-button-label'); + this.addLabel(this.name, 'appmenu-application-button-label'); + if (applet.showDescription) + this.addDescription(this.description, 'appmenu-application-button-description'); this.searchStrings = [ AppUtils.decomp_string(recent.name).replace(/\s/g, '') @@ -734,204 +736,84 @@ class RecentButton extends SimpleMenuItem { let source = new MessageTray.SystemNotificationSource(); Main.messageTray.add(source); let notification = new MessageTray.Notification(source, - _("This file is no longer available"), - e.message); + _("This file is no longer available"), + e.message); notification.setTransient(true); notification.setUrgency(MessageTray.Urgency.NORMAL); source.notify(notification); } } - - hasLocalPath(file) { - return file.is_native() || file.get_path() != null; - } - - populateMenu(menu) { - let menuItem; - menuItem = new PopupMenu.PopupMenuItem(_("Open with"), { reactive: false }); - menuItem.actor.style = "font-weight: bold"; - menu.addMenuItem(menuItem); - - let file = Gio.File.new_for_uri(this.uri); - - let default_info = Gio.AppInfo.get_default_for_type(this.mimeType, !this.hasLocalPath(file)); - - let infoLaunchFunc = (info, file) => { - info.launch([file], null); - this.applet.toggleContextMenu(this); - this.applet.menu.close(); - }; - - if (default_info) { - menuItem = new UserfileContextMenuItem(this, - default_info.get_display_name(), - false, - [default_info, file], - infoLaunchFunc); - menu.addMenuItem(menuItem); - } - - let infos = Gio.AppInfo.get_all_for_type(this.mimeType); - - for (let i = 0; i < infos.length; i++) { - let info = infos[i]; - - file = Gio.File.new_for_uri(this.uri); - - if (!this.hasLocalPath(file) && !info.supports_uris()) - continue; - - if (info.equal(default_info)) - continue; - - menuItem = new UserfileContextMenuItem(this, - info.get_display_name(), - false, - [info, file], - infoLaunchFunc); - menu.addMenuItem(menuItem); - } - - if (GLib.find_program_in_path ("nemo-open-with") != null) { - menuItem = new UserfileContextMenuItem(this, - _("Other application..."), - false, - [], - () => { - Util.spawnCommandLine("nemo-open-with " + this.uri); - this.applet.toggleContextMenu(this); - this.applet.menu.close(); - }); - menu.addMenuItem(menuItem); - } - } } -class FavoriteButton extends SimpleMenuItem { - constructor(applet, favoriteInfo) { - super(applet, { name: favoriteInfo.display_name, - description: decodeURIComponent(favoriteInfo.uri), - type: 'favorite', - styleClass: 'menu-application-button', - withMenu: true, - mimeType: favoriteInfo.cached_mimetype, - uri: favoriteInfo.uri }); - - this.favoriteInfo = favoriteInfo; - - let gicon = Gio.content_type_get_icon(favoriteInfo.cached_mimetype); - this.icon = new St.Icon({ gicon: gicon, icon_size: applet.applicationIconSize }) +class PathButton extends SimpleMenuItem { + constructor(applet, type, name, uri, icon) { + super(applet, { + name: name, + description: shorten_path(uri, name), + type: type, + styleClass: 'appmenu-application-button', + withMenu: false, + uri: uri, + }); + this.icon = icon; this.addActor(this.icon); - if (!applet.showApplicationIcons) - this.icon.visible = false; + this.addLabel(name, 'appmenu-application-button-label'); - this.addLabel(this.name, 'menu-application-button-label'); + if (applet.showDescription) + this.addDescription(this.description, 'appmenu-application-button-description'); this.searchStrings = [ - AppUtils.decomp_string(favoriteInfo.display_name).replace(/\s/g, '') + AppUtils.decomp_string(name).replace(/\s/g, '') ]; } activate() { try { - XApp.Favorites.get_default().launch(this.uri, 0); + Gio.app_info_launch_default_for_uri(this.uri, global.create_app_launch_context()); this.applet.menu.close(); } catch (e) { let source = new MessageTray.SystemNotificationSource(); Main.messageTray.add(source); let notification = new MessageTray.Notification(source, - _("This file is no longer available"), - e.message); + _("This file is no longer available"), + e.message); notification.setTransient(true); notification.setUrgency(MessageTray.Urgency.NORMAL); source.notify(notification); } } - - hasLocalPath(file) { - return file.is_native() || file.get_path() != null; - } - - populateMenu(menu) { - let menuItem; - menuItem = new PopupMenu.PopupMenuItem(_("Open with"), { reactive: false }); - menuItem.actor.style = "font-weight: bold"; - menu.addMenuItem(menuItem); - - let file = Gio.File.new_for_uri(this.uri); - - let default_info = Gio.AppInfo.get_default_for_type(this.mimeType, !this.hasLocalPath(file)); - - let infoLaunchFunc = (info, file) => { - info.launch([file], null); - this.applet.toggleContextMenu(this); - this.applet.menu.close(); - }; - - if (default_info) { - menuItem = new UserfileContextMenuItem(this, - default_info.get_display_name(), - false, - [default_info, file], - infoLaunchFunc); - menu.addMenuItem(menuItem); - } - - let infos = Gio.AppInfo.get_all_for_type(this.mimeType); - - for (let i = 0; i < infos.length; i++) { - let info = infos[i]; - - file = Gio.File.new_for_uri(this.uri); - - if (!this.hasLocalPath(file) && !info.supports_uris()) - continue; - - if (info.equal(default_info)) - continue; - - menuItem = new UserfileContextMenuItem(this, - info.get_display_name(), - false, - [info, file], - infoLaunchFunc); - menu.addMenuItem(menuItem); - } - - if (GLib.find_program_in_path ("nemo-open-with") != null) { - menuItem = new UserfileContextMenuItem(this, - _("Other application..."), - false, - [], - () => { - Util.spawnCommandLine("nemo-open-with " + this.uri); - this.applet.toggleContextMenu(this); - this.applet.menu.close(); - }); - menu.addMenuItem(menuItem); - } - } } class CategoryButton extends SimpleMenuItem { constructor(applet, categoryId, label, icon, symbolic=false) { - super(applet, { name: label, - type: 'category', - styleClass: 'menu-category-button', - categoryId: categoryId }); + super(applet, { + name: label, + type: 'category', + styleClass: 'appmenu-category-button', + categoryId: categoryId, + }); this.actor.accessible_role = Atk.Role.LIST_ITEM; + let size = applet.categoryIconSize; + if (applet.symbolicCategoryIcons) { + size = 16; + symbolic = true; + if (categoryId == 'recent') + icon = 'folder-recent'; + else if (categoryId == 'favorite') + icon = 'xapp-user-favorites'; + else + icon = 'cinnamon-all-applications'; + } + if (typeof icon === 'string') - this.addIcon(applet.categoryIconSize, icon, null, symbolic); + this.addIcon(size, icon, null, symbolic); else if (icon) - this.addIcon(applet.categoryIconSize, null, icon, symbolic); - - if (this.icon && !applet.showCategoryIcons) - this.icon.visible = false; + this.addIcon(size, null, icon, symbolic); - this.addLabel(this.name, 'menu-category-button-label'); + this.addLabel(this.name, 'appmenu-category-button-label'); this.actor_motion_id = 0; } @@ -940,21 +822,22 @@ class CategoryButton extends SimpleMenuItem { if(this.applet.searchActive || this.categoryId === this.applet.lastSelectedCategory) return; this.applet._select_category(this.categoryId); - this.applet._previousSelectedAppActor = null; - this.applet.categoriesBox.get_children().forEach(child => - child.set_style_class_name("menu-category-button")); - this.actor.style_class = "menu-category-button-selected"; + this.applet.hoveredApp = null; + this.applet.categoriesBox.get_children().forEach(child => + child.set_style_class_name("appmenu-category-button")); + this.actor.style_class = "appmenu-category-button-selected"; } } class FavoritesButton extends GenericApplicationButton { constructor(applet, app) { - super(applet, app, 'fav', false, 'menu-favorites-button'); - this.icon = app.create_icon_texture(applet.favIconSize); + super(applet, app, 'fav', false, 'appmenu-favorites-button'); + this.icon = app.create_icon_texture(applet.sidebarIconSize); this.addActor(this.icon); + this.addLabel(this.name); this._draggable = DND.makeDraggable(this.actor); - this._signals.connect(this._draggable, 'drag-end', Lang.bind(this, this._onDragEnd)); + this._signals.connect(this._draggable, 'drag-end', this._onDragEnd.bind(this)); this.isDraggableApp = true; } @@ -984,11 +867,13 @@ class FavoritesButton extends GenericApplicationButton { class SystemButton extends SimpleMenuItem { constructor(applet, iconName, name, desc) { - super(applet, { name: name, - description: desc, - type: 'system', - styleClass: 'menu-favorites-button' }); - this.addIcon(applet.favIconSize, iconName); + super(applet, { + name: name, + description: desc, + type: 'system', + styleClass: 'system-button', + }); + this.addIcon(16, iconName, null, true); } } @@ -1016,9 +901,24 @@ class CategoriesApplicationsBox { } } -class FavoritesBox { +class SidebarAppsBox { + constructor() { + this.actor = new St.BoxLayout({ + vertical: true, + y_expand: true, + y_align: Clutter.ActorAlign.START, + }); + this.actor._delegate = this; + } +} + +class FavoriteAppsBox { constructor() { - this.actor = new St.BoxLayout({ vertical: true, y_expand: true, y_align: Clutter.ActorAlign.START }); + this.actor = new St.BoxLayout({ + vertical: true, + y_expand: true, + y_align: Clutter.ActorAlign.START, + }); this.actor._delegate = this; this._dragPlaceholder = null; @@ -1071,10 +971,9 @@ class FavoritesBox { if (this._dragPlaceholder) { this._dragPlaceholder.animateOutAndDestroy(); this._animatingPlaceholdersCount++; - this._dragPlaceholder.actor.connect('destroy', - Lang.bind(this, function() { - this._animatingPlaceholdersCount--; - })); + this._dragPlaceholder.actor.connect('destroy', () => { + this._animatingPlaceholdersCount--; + }); } this._dragPlaceholder = null; @@ -1137,15 +1036,14 @@ class FavoritesBox { favPos++; } - Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this, - function () { + Meta.later_add(Meta.LaterType.BEFORE_REDRAW, () => { let appFavorites = AppFavorites.getAppFavorites(); if (srcIsFavorite) appFavorites.moveFavoriteToPos(id, favPos); else appFavorites.addFavoriteAtPos(id, favPos); return false; - })); + }); return true; } @@ -1199,7 +1097,6 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { () => this.popup_height * global.ui_scale); this.settings.bind("show-favorites", "showFavorites", () => this.queueRefresh(RefreshFlags.FAV_DOC)); - this.settings.bind("show-places", "showPlaces", () => this.queueRefresh(RefreshFlags.PLACE)); this.settings.bind("show-recents", "showRecents", () => this.queueRefresh(RefreshFlags.RECENT)); this._appletEnterEventId = 0; @@ -1210,8 +1107,8 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { this.settings.bind("activate-on-hover", "activateOnHover", this._updateActivateOnHover); this._updateActivateOnHover(); - this.menu.setCustomStyleClass('menu-background'); - this.menu.connect('open-state-changed', Lang.bind(this, this._onOpenStateChanged)); + this.menu.setCustomStyleClass('appmenu-background'); + this.menu.connect('open-state-changed', this._onOpenStateChanged.bind(this)); this.menu.connect('menu-animated-closed', () => { this._clearAllSelections(); this._hideAllAppActors(); @@ -1222,28 +1119,40 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { this.settings.bind("menu-icon-size", "menuIconSize", this._updateIconAndLabel); this.settings.bind("menu-label", "menuLabel", this._updateIconAndLabel); this.settings.bind("overlay-key", "overlayKey", this._updateKeybinding); - this.settings.bind("show-category-icons", "showCategoryIcons", () => this._updateShowIcons(this.categoriesBox, this.showCategoryIcons)); - this.settings.bind("category-icon-size", "categoryIconSize", () => this.queueRefresh(RefreshFlags.PLACE | RefreshFlags.RECENT | RefreshFlags.APP)); - this.settings.bind("show-application-icons", "showApplicationIcons", () => this._updateShowIcons(this.applicationsBox, this.showApplicationIcons)); + this.settings.bind("symbolic-category-icons", "symbolicCategoryIcons", () => this.queueRefresh(REFRESH_ALL_MASK)); + this.settings.bind("category-icon-size", "categoryIconSize", () => this.queueRefresh(REFRESH_ALL_MASK)); this.settings.bind("category-hover", "categoryHover", this._updateCategoryHover); - this.settings.bind("application-icon-size", "applicationIconSize", () => this.queueRefresh(RefreshFlags.PLACE | RefreshFlags.RECENT | RefreshFlags.APP)); - this.settings.bind("favbox-show", "favBoxShow", this._favboxtoggle); - this.settings.bind("fav-icon-size", "favIconSize", () => this.queueRefresh(RefreshFlags.FAV_APP | RefreshFlags.SYSTEM)); + this.settings.bind("application-icon-size", "applicationIconSize", () => this.queueRefresh(REFRESH_ALL_MASK)); + this.settings.bind("show-description", "showDescription", () => this.queueRefresh(REFRESH_ALL_MASK)); + this.settings.bind("show-sidebar", "showSidebar", this._sidebarToggle); + this.settings.bind("show-home", "showHome", () => this.queueRefresh(REFRESH_ALL_MASK)); + this.settings.bind("show-desktop", "showDesktop", () => this.queueRefresh(REFRESH_ALL_MASK)); + this.settings.bind("show-downloads", "showDownloads", () => this.queueRefresh(REFRESH_ALL_MASK)); + this.settings.bind("show-documents", "showDocuments", () => this.queueRefresh(REFRESH_ALL_MASK)); + this.settings.bind("show-music", "showMusic", () => this.queueRefresh(REFRESH_ALL_MASK)); + this.settings.bind("show-pictures", "showPictures", () => this.queueRefresh(REFRESH_ALL_MASK)); + this.settings.bind("show-videos", "showVideos", () => this.queueRefresh(REFRESH_ALL_MASK)); + this.settings.bind("show-bookmarks", "showBookmarks", () => this.queueRefresh(REFRESH_ALL_MASK)); + this.settings.bind("sidebar-icon-size", "sidebarIconSize", () => this.queueRefresh(REFRESH_ALL_MASK)); this.settings.bind("enable-animation", "enableAnimation", null); this.settings.bind("popup-width", "popup_width"); this.settings.bind("popup-height", "popup_height"); this._updateKeybinding(); - Main.themeManager.connect("theme-set", Lang.bind(this, this._theme_set)); + Main.themeManager.connect("theme-set", this._theme_set.bind(this)); this._updateIconAndLabel(); - this._searchInactiveIcon = new St.Icon({ style_class: 'menu-search-entry-icon', + this._searchInactiveIcon = new St.Icon({ + style_class: 'appmenu-search-entry-icon', icon_name: 'edit-find', - icon_type: St.IconType.SYMBOLIC }); - this._searchActiveIcon = new St.Icon({ style_class: 'menu-search-entry-icon', + icon_type: St.IconType.SYMBOLIC, + }); + this._searchActiveIcon = new St.Icon({ + style_class: 'appmenu-search-entry-icon', icon_name: 'edit-clear', - icon_type: St.IconType.SYMBOLIC }); + icon_type: St.IconType.SYMBOLIC, + }); this._searchIconClickedId = 0; this._applicationsButtons = []; this._favoriteAppButtons = []; @@ -1255,8 +1164,8 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { this._favoriteDocButtons = []; this._categoryButtons = []; this._searchProviderButtons = []; - this._previousSelectedAppActor = null; - this._previousCategoryHoverActor = null; + this.hoveredApp = null; + this.hoveredCategory = null; this._activeContainer = null; this._activeActor = null; this._knownApps = new Set(); // Used to keep track of apps that are already installed, so we can highlight newly installed ones @@ -1274,10 +1183,8 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { this.RecentManager.connect('changed', () => this.queueRefresh(RefreshFlags.RECENT)); this.privacy_settings.connect("changed::" + REMEMBER_RECENT_KEY, () => this.queueRefresh(RefreshFlags.RECENT)); XApp.Favorites.get_default().connect("changed", () => this.queueRefresh(RefreshFlags.FAV_DOC)); - this._fileFolderAccessActive = false; this._pathCompleter = new Gio.FilenameCompleter(); this._pathCompleter.set_dirs_only(false); - this.settings.bind("search-filesystem", "searchFilesystem"); this.contextMenu = null; this.lastSelectedCategory = null; this.settings.bind("force-show-panel", "forceShowPanel"); @@ -1297,16 +1204,6 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { this.set_show_label_in_vertical_panels(false); } - _updateShowIcons(container, show) { - container.get_children().forEach( c => { - let b = c._delegate; - if (!(b instanceof SimpleMenuItem)) - return; - if (b.icon) - b.icon.visible = show; - }); - } - _onBoxResized(width, height) { width = (width / global.ui_scale).clamp(POPUP_MIN_WIDTH, POPUP_MAX_WIDTH); height = (height / global.ui_scale).clamp(POPUP_MIN_HEIGHT, POPUP_MAX_HEIGHT); @@ -1321,14 +1218,14 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { } _updateKeybinding() { - Main.keybindingManager.addHotKey("overlay-key-" + this.instance_id, this.overlayKey, Lang.bind(this, function() { + Main.keybindingManager.addHotKey("overlay-key-" + this.instance_id, this.overlayKey, () => { if (!Main.overview.visible && !Main.expo.visible) { if (this.forceShowPanel && !this.isOpen) { this.panel.peekPanel(); } this.menu.toggle_with_options(this.enableAnimation); } - })); + }); } _updateCategoryHover() { @@ -1339,7 +1236,7 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { } if (this.categoryHover) { - child._delegate.actor_motion_id = child.connect("motion-event", Lang.bind(this, this._categoryMotionEvent)); + child._delegate.actor_motion_id = child.connect("motion-event", this._categoryMotionEvent.bind(this)); } }, this); } @@ -1361,14 +1258,14 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { let m = this.refreshMask; if ((m & RefreshFlags.APP) === RefreshFlags.APP) this._refreshApps(); - if ((m & RefreshFlags.FAV_APP) === RefreshFlags.FAV_APP) - this._refreshFavApps(); if ((m & RefreshFlags.SYSTEM) === RefreshFlags.SYSTEM) this._refreshSystemButtons(); if ((m & RefreshFlags.FAV_DOC) === RefreshFlags.FAV_DOC) this._refreshFavDocs(); if ((m & RefreshFlags.PLACE) === RefreshFlags.PLACE) this._refreshPlaces(); + if ((m & RefreshFlags.FAV_APP) === RefreshFlags.FAV_APP) + this._refreshFavApps(); if ((m & RefreshFlags.RECENT) === RefreshFlags.RECENT) this._refreshRecent(); @@ -1379,10 +1276,6 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { this.categoriesBox.set_child_at_index(this.favoriteDocsButton.actor, -1); } - if (this.placesButton) { - this.categoriesBox.set_child_at_index(this.placesButton.actor, -1); - } - if (this.recentButton) { this.categoriesBox.set_child_at_index(this.recentButton.actor, -1); } @@ -1439,24 +1332,9 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { _setMenuSize(width, height) { this.main_container.natural_height = (height * global.ui_scale); this.main_container.natural_width = (width * global.ui_scale); - - this._update_scroll_policy(this.favoritesBox, this.favoritesScrollBox); - this._update_scroll_policy(this.categoriesBox, this.categoriesScrollBox); - this._size_dirty = false; } - _update_scroll_policy(box, scrollview) { - let h = box.get_preferred_height(-1)[1]; - let alloc = box.get_allocation_box(); - - if (alloc.y2 - alloc.y1 < h) { - scrollview.vscroll.visible = true; - } else { - scrollview.vscroll.visible = false; - } - } - on_orientation_changed (orientation) { this._updateIconAndLabel(); this._size_dirty = true; @@ -1477,7 +1355,6 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { this._setMenuSize(this.popup_width, this.popup_height); } - // on_applet_clicked(event) { this.menu.toggle_with_options(this.enableAnimation); @@ -1501,33 +1378,28 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { for (let i = 0; i < n; i++) { this._applicationsButtons[i].actor.show(); } - this._allAppsCategoryButton.actor.style_class = "menu-category-button-selected"; + this._allAppsCategoryButton.actor.style_class = "appmenu-category-button-selected"; - Mainloop.idle_add(Lang.bind(this, this._initial_cat_selection, n)); + Mainloop.idle_add(() => { + if(this.lastSelectedCategory !== null) //if a category is already selected + return; + for (let i = n; i < this._applicationsButtons.length; i++) + this._applicationsButtons[i].actor.show(); + }); } else { this.actor.remove_style_pseudo_class('active'); if (this.searchActive) { this.resetSearch(); } - this.selectedAppTitle.set_text(""); - this.selectedAppDescription.set_text(""); - this._previousCategoryHoverActor = null; - this._previousSelectedAppActor = null; + + this.hoveredCategory = null; + this.hoveredApp = null; this.closeContextMenu(false); - + this._disableVectorMask(); this._scrollToButton(null, this.applicationsScrollBox); this._scrollToButton(null, this.categoriesScrollBox); - this._scrollToButton(null, this.favoritesScrollBox); - } - } - - _initial_cat_selection (start_index) { - if(this.lastSelectedCategory !== null) //if a category is already selected - return; - let n = this._applicationsButtons.length; - for (let i = start_index; i < n; i++) { - this._applicationsButtons[i].actor.show(); + this._scrollToButton(null, this.sidebarAppsScrollBox); } } @@ -1538,12 +1410,12 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { this.emit('destroy'); } - _favboxtoggle() { - if (!this.favBoxShow) { - this.left_box.hide(); - } else { - this.left_box.show(); - } + _sidebarToggle() { + if (!this.showSidebar) + this.sidebar.hide(); + else + this.sidebar.show(); + this.updateNavigation(); } // Override js/applet.js so _updateIconAndLabel doesn't have to fight with size changes @@ -1656,8 +1528,8 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { return false; }; - menu.actor.set_style_class_name('menu-context-menu'); - menu.connect('open-state-changed', Lang.bind(this, this._contextMenuOpenStateChanged)); + menu.actor.set_style_class_name('appmenu-context-menu'); + menu.connect('open-state-changed', this._contextMenuOpenStateChanged.bind(this)); this.contextMenu = menu; this.applicationsBox.add_actor(menu.actor); } else if (this.contextMenu.isOpen && @@ -1745,6 +1617,7 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { let item_actor; this.appBoxIter.reloadVisible(); this.catBoxIter.reloadVisible(); + this.placesBoxIter.reloadVisible(); this.favBoxIter.reloadVisible(); this.sysBoxIter.reloadVisible(); @@ -1755,19 +1628,19 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { Switches between left/right key presses */ if(St.Widget.get_default_direction() === St.TextDirection.RTL) { switch(symbol) { - case Clutter.KEY_Right: + case Clutter.KEY_Right: symbol = Clutter.KEY_Left; - break; - case Clutter.KEY_KP_Right: - symbol = Clutter.KEY_RP_Left; - break; - case Clutter.KEY_Left: - symbol = Clutter.KEY_Right; - break; + break; + case Clutter.KEY_KP_Right: + symbol = Clutter.KEY_RP_Left; + break; + case Clutter.KEY_Left: + symbol = Clutter.KEY_Right; + break; case Clutter.KEY_KP_Left: - symbol = Clutter.KEY_KP_Right; - break; - } + symbol = Clutter.KEY_KP_Right; + break; + } } /* check for a keybinding and quit early, otherwise we get a double hit @@ -1810,366 +1683,125 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { return true; } - let navigationKey = true; - let whichWay = "none"; if (this._activeContainer === null) { - this._setKeyFocusToCurrentCategoryButton(); + this._setKeyFocusToCurrentCategoryButton(); } - + + let iter = this._activeContainer._vis_iter; + let active = this._activeActor; switch (symbol) { case Clutter.KEY_Up: case Clutter.KEY_KP_Up: - whichWay = "up"; - if (this._activeContainer === this.favoritesBox && ctrlKey && - this._activeActor._delegate instanceof FavoritesButton) - navigationKey = false; + item_actor = iter.prev(active); + if (iter.up && active === iter.first()) + item_actor = iter.up.last(); break; case Clutter.KEY_Down: case Clutter.KEY_KP_Down: - whichWay = "down"; - if (this._activeContainer === this.favoritesBox && ctrlKey && - this._activeActor._delegate instanceof FavoritesButton) - navigationKey = false; + item_actor = iter.next(active); + if (iter.down && active === iter.last()) + item_actor = iter.down.first(); break; - case Clutter.KEY_Page_Up: - whichWay = "top"; break; - case Clutter.KEY_Page_Down: - whichWay = "bottom"; break; case Clutter.KEY_Right: case Clutter.KEY_KP_Right: - if (!this.searchActive) - whichWay = "right"; - if (this._activeContainer === this.applicationsBox) - whichWay = "none"; - else if (this._activeContainer === this.categoriesBox && this.noRecentDocuments && - this._activeActor._delegate.categoryId === "recent") - whichWay = "none"; + case Clutter.KEY_Tab: + if (!this.searchActive) { + item_actor = iter.right.first(); + if (iter.right === this.catBoxIter) + item_actor = this.hoveredCategory || iter.right.first(); + else if (iter.right === this.appBoxIter) + item_actor = this.hoveredApp || iter.right.first(); + if (this._activeContainer === this.systemButtonsBox) { + if (active === iter.last()) + item_actor = iter.right.first(); + else + item_actor = iter.next(active); + } + } break; case Clutter.KEY_Left: case Clutter.KEY_KP_Left: - if (!this.searchActive) - whichWay = "left"; - if (this._activeContainer === this.favoritesBox || this._activeContainer === this.systemButtonsBox) - whichWay = "none"; - else if (!this.favBoxShow && this._activeContainer === this.categoriesBox) - whichWay = "none"; - break; - case Clutter.KEY_Tab: - if (!this.searchActive) - whichWay = "right"; - else - navigationKey = false; - break; case Clutter.KEY_ISO_Left_Tab: - if (!this.searchActive) - whichWay = "left"; - else - navigationKey = false; - break; - default: - navigationKey = false; - } - - if (navigationKey) { - switch (this._activeContainer) { - case this.categoriesBox: - switch (whichWay) { - case "up": - item_actor = this.catBoxIter.getPrevVisible(this._activeActor); - break; - case "down": - item_actor = this.catBoxIter.getNextVisible(this._activeActor); - break; - case "right": - if (this._activeActor._delegate.categoryId === "recent" && - this.noRecentDocuments) { - if(this.favBoxShow) { - item_actor = this.favBoxIter.getFirstVisible(); - } - } else { - item_actor = (this._previousSelectedAppActor != null) ? - this._previousSelectedAppActor : this.appBoxIter.getFirstVisible(); - } - break; - case "left": - if(this.favBoxShow) { - item_actor = this.favBoxIter.getFirstVisible(); - } else if (this._activeActor._delegate.categoryId != "recent" || - !this.noRecentDocuments) { - item_actor = (this._previousSelectedAppActor != null) ? - this._previousSelectedAppActor : - this.appBoxIter.getFirstVisible(); - } - break; - case "top": - item_actor = this.catBoxIter.getFirstVisible(); - break; - case "bottom": - item_actor = this.catBoxIter.getLastVisible(); - break; - } - break; - case this.applicationsBox: - switch (whichWay) { - case "up": - item_actor = this.appBoxIter.getPrevVisible(this._activeActor); - break; - case "down": - item_actor = this.appBoxIter.getNextVisible(this._activeActor); - break; - case "right": - if (this.favBoxShow) { - item_actor = this.favBoxIter.getFirstVisible(); - } else { - item_actor = (this._previousCategoryHoverActor != null) ? - this._previousCategoryHoverActor : - this.catBoxIter.getFirstVisible(); - } - break; - case "left": - item_actor = (this._previousCategoryHoverActor != null) ? - this._previousCategoryHoverActor : - this.catBoxIter.getFirstVisible(); - break; - case "top": - item_actor = this.appBoxIter.getFirstVisible(); - break; - case "bottom": - item_actor = this.appBoxIter.getLastVisible(); - break; + if (!this.searchActive) { + item_actor = iter.left.first(); + if (iter.left === this.catBoxIter) + item_actor = this.hoveredCategory || iter.left.first(); + else if (iter.left === this.appBoxIter) + item_actor = this.hoveredApp || iter.left.first(); + else if (iter.left === this.sysBoxIter) + item_actor = iter.left.last(); + if (this._activeContainer === this.systemButtonsBox) { + if (active === iter.first()) + item_actor = iter.left.first(); + else + item_actor = iter.prev(active); } - break; - case this.favoritesBox: - switch (whichWay) { - case "up": - if (this._activeActor === this.favBoxIter.getFirstVisible()) { - item_actor = this.sysBoxIter.getLastVisible(); - } else { - item_actor = this.favBoxIter.getPrevVisible(this._activeActor); - } - break; - case "down": - if (this._activeActor === this.favBoxIter.getLastVisible()) { - item_actor = this.sysBoxIter.getFirstVisible(); - } else { - item_actor = this.favBoxIter.getNextVisible(this._activeActor); - } - break; - case "right": - item_actor = (this._previousCategoryHoverActor != null) ? - this._previousCategoryHoverActor : - this.catBoxIter.getFirstVisible(); - break; - case "left": - /*item_actor = (this._previousCategoryHoverActor != null) ? - this._previousCategoryHoverActor : - this.catBoxIter.getFirstVisible(); - this._previousCategoryHoverActor = item_actor; - index = item_actor.get_parent()._vis_iter.getAbsoluteIndexOfChild(item_actor); - - this._buttonEnterEvent(item_actor._delegate);*/ - item_actor = (this._previousSelectedAppActor != null) ? - this._previousSelectedAppActor : - this.appBoxIter.getFirstVisible(); - break; - case "top": - item_actor = this.favBoxIter.getFirstVisible(); - break; - case "bottom": - item_actor = this.favBoxIter.getLastVisible(); - break; - } - break; - case this.systemButtonsBox: - switch (whichWay) { - case "up": - if (this._activeActor === this.sysBoxIter.getFirstVisible()) { - item_actor = this.favBoxIter.getLastVisible(); - } else { - item_actor = this.sysBoxIter.getPrevVisible(this._activeActor); - } - break; - case "down": - if (this._activeActor === this.sysBoxIter.getLastVisible()) { - item_actor = this.favBoxIter.getFirstVisible(); - } else { - item_actor = this.sysBoxIter.getNextVisible(this._activeActor); - } - break; - case "right": - item_actor = (this._previousCategoryHoverActor != null) ? - this._previousCategoryHoverActor : - this.catBoxIter.getFirstVisible(); - break; - case "left": - /*item_actor = (this._previousCategoryHoverActor != null) ? - this._previousCategoryHoverActor : - this.catBoxIter.getFirstVisible(); - this._previousCategoryHoverActor = item_actor; - index = item_actor.get_parent()._vis_iter.getAbsoluteIndexOfChild(item_actor); - - this._buttonEnterEvent(item_actor._delegate);*/ - item_actor = (this._previousSelectedAppActor != null) ? - this._previousSelectedAppActor : - this.appBoxIter.getFirstVisible(); - break; - case "top": - item_actor = this.sysBoxIter.getFirstVisible(); - break; - case "bottom": - item_actor = this.sysBoxIter.getLastVisible(); - break; - } - break; - default: - break; - } - if (!item_actor) - return false; - } else { - if (this._activeContainer && (symbol === Clutter.KEY_Return || symbol === Clutter.KEY_KP_Enter)) { - if (!ctrlKey) { - this._activeActor._delegate.activate(); - } else if (ctrlKey && this._activeContainer === this.applicationsBox) { - this.toggleContextMenu(this._activeActor._delegate); - } - return true; - } else if (this._activeContainer === this.applicationsBox && symbol === Clutter.KEY_Menu) { - this.toggleContextMenu(this._activeActor._delegate); - return true; - } else if (!this.searchActive && this._activeContainer === this.favoritesBox && symbol === Clutter.KEY_Delete) { - item_actor = this._activeActor; - const selectedItemIndex = this._activeContainer._vis_iter.getAbsoluteIndexOfChild(this._activeActor); - if (item_actor._delegate instanceof FavoritesButton) { - let favorites = AppFavorites.getAppFavorites().getFavorites(); - let numFavorites = favorites.length; - AppFavorites.getAppFavorites().removeFavorite(item_actor._delegate.app.get_id()); - if (selectedItemIndex == (numFavorites-1)) - item_actor = this.favoritesBox.get_child_at_index(selectedItemIndex-1); - else - item_actor = this.favoritesBox.get_child_at_index(selectedItemIndex); } - } else if (this._activeContainer === this.favoritesBox && - (symbol === Clutter.KEY_Down || symbol === Clutter.KEY_KP_Down || - symbol === Clutter.KEY_Up || symbol === Clutter.KEY_KP_Up) && - ctrlKey && this._activeActor._delegate instanceof FavoritesButton) { - const selectedItemIndex = this._activeContainer._vis_iter.getAbsoluteIndexOfChild(this._activeActor); - item_actor = this._activeActor; - let id = item_actor._delegate.app.get_id(); - let appFavorites = AppFavorites.getAppFavorites(); - let favorites = appFavorites.getFavorites(); - let numFavorites = favorites.length; - let favPos = 0; - if (selectedItemIndex == (numFavorites-1) && (symbol === Clutter.KEY_Down || symbol === Clutter.KEY_KP_Down)) - favPos = 0; - else if (selectedItemIndex == 0 && (symbol === Clutter.KEY_Up || symbol === Clutter.KEY_KP_Up)) - favPos = numFavorites-1; - else if (symbol === Clutter.KEY_Down || symbol === Clutter.KEY_KP_Down) - favPos = selectedItemIndex + 1; - else - favPos = selectedItemIndex - 1; - appFavorites.moveFavoriteToPos(id, favPos); - item_actor = this.favoritesBox.get_child_at_index(favPos); - } else if (this.searchFilesystem && (this._fileFolderAccessActive || symbol === Clutter.KEY_slash)) { - if (symbol === Clutter.KEY_Return || symbol === Clutter.KEY_KP_Enter) { - if (this._run(this.searchEntry.get_text())) { - this.menu.close(); - } + break; + case Clutter.KEY_Return: + case Clutter.KEY_KP_Enter: + if (ctrlKey && this._activeContainer === this.applicationsBox) { + this.toggleContextMenu(active._delegate); return true; } - if (symbol === Clutter.KEY_Escape) { - this.searchEntry.set_text(''); - this._fileFolderAccessActive = false; - } - if (symbol === Clutter.KEY_slash) { - // Need preload data before get completion. GFilenameCompleter load content of parent directory. - // Parent directory for /usr/include/ is /usr/. So need to add fake name('a'). - let text = this.searchEntry.get_text().concat('/a'); - let prefix; - if (!text.includes(' ')) - prefix = text; - else - prefix = text.substr(text.lastIndexOf(' ') + 1); - this._getCompletion(prefix); - - return false; - } - if (symbol === Clutter.KEY_Tab) { - let text = actor.get_text(); - let prefix; - if (!text.includes(' ')) - prefix = text; - else - prefix = text.substr(text.lastIndexOf(' ') + 1); - let postfix = this._getCompletion(prefix); - if (postfix != null && postfix.length > 0) { - actor.insert_text(postfix, -1); - actor.set_cursor_position(text.length + postfix.length); - if (postfix[postfix.length - 1] == '/') - this._getCompletion(text + postfix + 'a'); - } + else { + active._delegate.activate(); return true; } - if (symbol === Clutter.KEY_ISO_Left_Tab) { + break; + case Clutter.KEY_Menu: + if (this._activeContainer === this.applicationsBox) { + this.toggleContextMenu(active._delegate); return true; } - return false; - } else if (symbol === Clutter.KEY_Tab || symbol === Clutter.KEY_ISO_Left_Tab) { - return true; - } else { - return false; - } + default: + break; } - this.selectedAppTitle.set_text(""); - this.selectedAppDescription.set_text(""); - if (!item_actor || item_actor === this.searchEntry) { return false; } - if (item_actor._delegate instanceof CategoryButton) { + if (item_actor._delegate instanceof CategoryButton) this._scrollToButton(item_actor._delegate, this.categoriesScrollBox); - } else if (item_actor._delegate instanceof FavoritesButton) { - this._scrollToButton(item_actor._delegate, this.favoritesScrollBox); - } else if (item_actor.get_parent() === this.applicationsBox) { + else if (item_actor._delegate instanceof FavoritesButton) + this._scrollToButton(item_actor._delegate, this.sidebarAppsScrollBox); + else if (item_actor.get_parent() === this.applicationsBox) this._scrollToButton(item_actor._delegate, this.applicationsScrollBox); - } - + this._buttonEnterEvent(item_actor._delegate); return true; } _buttonEnterEvent(button) { this.categoriesBox.get_children().forEach(child => child.remove_style_pseudo_class("hover")); - this.applicationsBox.get_children().forEach(child => child.set_style_class_name("menu-application-button")); - this.favoritesBox.get_children().forEach(child => child.remove_style_pseudo_class("hover")); + this.applicationsBox.get_children().forEach(child => child.set_style_class_name("appmenu-application-button")); + this.favoriteAppsBox.get_children().forEach(child => child.remove_style_pseudo_class("hover")); + this.placesBox.get_children().forEach(child => child.remove_style_pseudo_class("hover")); this.systemButtonsBox.get_children().forEach(child => child.remove_style_pseudo_class("hover")); - + if (button instanceof CategoryButton) { if (this.searchActive) return; - + if (button.categoryId !== this.lastSelectedCategory) { if (this.categoryHover) { - this.categoriesBox.get_children().forEach(child => - child.set_style_class_name("menu-category-button")); + this.categoriesBox.get_children().forEach(child => + child.set_style_class_name("appmenu-category-button")); button.activate(); } else { button.actor.add_style_pseudo_class("hover"); } } - this._previousCategoryHoverActor = button.actor; + this.hoveredCategory = button.actor; } else { - const isFav = button instanceof FavoritesButton || button instanceof SystemButton; + const isFav = button instanceof FavoritesButton || button instanceof SystemButton || button instanceof PlaceButton; if (isFav) { button.actor.add_style_pseudo_class("hover"); } else { button.actor.set_style_class_name(`${button.styleClass}-selected`); - this._previousSelectedAppActor = button.actor; + this.hoveredApp = button.actor; } - this.selectedAppTitle.set_text(button.name); - this.selectedAppDescription.set_text(button.description); } @@ -2187,9 +1819,6 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { } } } else { - this.selectedAppTitle.set_text(""); - this.selectedAppDescription.set_text(""); - if (button instanceof FavoritesButton || button instanceof SystemButton) button.actor.remove_style_pseudo_class("hover"); else @@ -2239,7 +1868,7 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { */ static DEBUG_VMASK = false; - static POLL_INTERVAL = 20; + static POLL_INTERVAL = 30; static MIN_MOVEMENT = 2; // Movement smaller than this disables the mask. _getNewVectorInfo() { @@ -2363,7 +1992,7 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { // While the mask is active, disable category buttons. this._setCategoryButtonsReactive(false); - this.vector_update_loop = Mainloop.timeout_add(CinnamonMenuApplet.POLL_INTERVAL, Lang.bind(this, this._maskPollTimeout)); + this.vector_update_loop = Mainloop.timeout_add(CinnamonMenuApplet.POLL_INTERVAL, this._maskPollTimeout.bind(this)); } _maskPollTimeout() { @@ -2399,65 +2028,77 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { } _setCategoryButtonsReactive(active) { - for (let i = 0; i < this._categoryButtons.length; i++) { - this._categoryButtons[i].actor.reactive = active; - this._categoryButtons[i].actor.queue_redraw(); + for (let button of this._categoryButtons) { + button.actor.reactive = active; + button.actor.queue_redraw(); } } - _refreshPlaces () { - for (let i = 0; i < this._placesButtons.length; i ++) { - this._placesButtons[i].actor.destroy(); - } + _refreshPlaces() { + //Remove all places + this.placesBox.destroy_all_children(); + //Load places again this._placesButtons = []; - for (let i = 0; i < this._categoryButtons.length; i++) { - if (this._categoryButtons[i].categoryId === 'place') { - this._categoryButtons[i].destroy(); - this._categoryButtons.splice(i, 1); - this.placesButton = null; - break; + let places = [...Main.placesManager.getDefaultPlaces(), ...Main.placesManager.getBookmarks()]; + for (let place of places) { + let path = place.idDecoded.replace("bookmark:file://", "") + switch (path) { + case "special:home": + if (!this.showHome) + continue; + break; + case "special:desktop": + if (!this.showDesktop) + continue; + break; + case GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_DOWNLOAD): + if (!this.showDownloads) + continue; + break; + case GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_DOCUMENTS): + if (!this.showDocuments) + continue; + break; + case GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_MUSIC): + if (!this.showMusic) + continue; + break; + case GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_PICTURES): + if (!this.showPictures) + continue; + break; + case GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_VIDEOS): + if (!this.showVideos) + continue; + break; + default: + if (!this.showBookmarks) + continue; + break; } - } - - if (!this.showPlaces) { - return; - } - - // Now generate Places category and places buttons and add to the list - if (!this.placesButton) { - this.placesButton = new CategoryButton(this, 'place', _('Places'), 'folder'); - this._categoryButtons.push(this.placesButton); - this.categoriesBox.add_actor(this.placesButton.actor); - } - - // places go after applications. we add them in reverse starting below the last ApplicationButton - let sibling = this._applicationsButtons[this._applicationsButtons.length - 1].actor; - let places = Main.placesManager.getAllPlaces(); - for (let i = places.length - 1; i >= 0; i--) { - let button = new PlaceButton(this, places[i]); + let button = new PlaceButton(this, place); this._placesButtons.push(button); - this.applicationsBox.insert_child_below(button.actor, sibling); - button.actor.visible = this.menu.isOpen && this.lastSelectedCategory === "place"; - sibling = button.actor; + this.placesBox.add(button.actor, { + y_align: St.Align.END, + y_fill: false + }); } + // Update navigation because the presence/absence of places + // can impact it. + this.updateNavigation(); } _refreshRecent () { - for (let i = 0; i < this._recentButtons.length; i++) { - this._recentButtons[i].destroy(); - } - + this._recentButtons.forEach(button => button.destroy()); this._recentButtons = []; - for (let i = 0; i < this._categoryButtons.length; i++) { - if (this._categoryButtons[i].categoryId === 'recent') { - this._categoryButtons[i].destroy(); - this._categoryButtons.splice(i, 1); - this.recentButton = null; - break; - } + const index = this._categoryButtons.findIndex(button => button.categoryId === 'recent'); + if (index !== -1) { + this._categoryButtons[index].destroy(); + this._categoryButtons.splice(index, 1); + this.recentButton = null; } if (!this.showRecents || !this.privacy_settings.get_boolean(REMEMBER_RECENT_KEY)) { @@ -2474,7 +2115,8 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { if (recents.length > 0) { this.noRecentDocuments = false; recents.forEach( info => { - let button = new RecentButton(this, info); + let icon = info.createIcon(this.applicationIconSize); + let button = new PathButton(this, 'recent', info.name, info.uri, icon); this._recentButtons.push(button); this.applicationsBox.add_actor(button.actor); button.actor.visible = this.menu.isOpen && this.lastSelectedCategory === "recent"; @@ -2483,18 +2125,15 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { let button = new SimpleMenuItem(this, { name: _("Clear list"), description: _("Clear all recent documents"), type: 'recent-clear', - styleClass: 'menu-application-button' }); + styleClass: 'appmenu-application-button' }); button.addIcon(22, 'edit-clear', null, true); - button.addLabel(button.name, 'menu-application-button-label'); + button.addLabel(button.name, 'appmenu-application-button-label'); button.label.set_style('font-weight: bold;'); button.activate = () => { this.menu.close(); (new Gtk.RecentManager()).purge_items(); }; - if (!this.showApplicationIcons) - button.icon.visible = false; - this._recentButtons.push(button); this.applicationsBox.add_actor(button.actor); button.actor.visible = this.menu.isOpen && this.lastSelectedCategory === "recent"; @@ -2502,10 +2141,10 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { this.noRecentDocuments = true; let button = new SimpleMenuItem(this, { name: _("No recent documents"), type: 'no-recent', - styleClass: 'menu-application-button', + styleClass: 'appmenu-application-button', reactive: false, activatable: false }); - button.addLabel(button.name, 'menu-application-button-label'); + button.addLabel(button.name, 'appmenu-application-button-label'); this._recentButtons.push(button); this.applicationsBox.add_actor(button.actor); button.actor.visible = this.menu.isOpen && this.lastSelectedCategory === "recent"; @@ -2513,19 +2152,14 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { } _refreshFavDocs() { - for (let i = 0; i < this._favoriteDocButtons.length; i++) { - this._favoriteDocButtons[i].destroy(); - } - + this._favoriteDocButtons.forEach(button => button.destroy()); this._favoriteDocButtons = []; - for (let i = 0; i < this._categoryButtons.length; i++) { - if (this._categoryButtons[i].categoryId === 'favorite') { - this._categoryButtons[i].destroy(); - this._categoryButtons.splice(i, 1); - this.favoriteDocsButton = null; - break; - } + const index = this._categoryButtons.findIndex(button => button.categoryId === 'favorite'); + if (index !== -1) { + this._categoryButtons[index].destroy(); + this._categoryButtons.splice(index, 1); + this.favoriteDocsButton = null; } let favorite_infos = XApp.Favorites.get_default().get_favorites(null); @@ -2541,7 +2175,11 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { } favorite_infos.forEach( info => { - let button = new FavoriteButton(this, info); + let icon = new St.Icon({ + gicon: Gio.content_type_get_icon(info.cached_mimetype), + icon_size: this.applicationIconSize + }); + let button = new PathButton(this, 'favorite', info.display_name, info.uri, icon); this._favoriteDocButtons.push(button); this.applicationsBox.add_actor(button.actor); button.actor.visible = this.menu.isOpen && this.lastSelectedCategory === "favorite"; @@ -2553,8 +2191,7 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { * the remaining elements */ for (let i = this._categoryButtons.length - 1; i > -1; i--) { let b = this._categoryButtons[i]; - if (b === this._allAppsCategoryButton || - ['place', 'recent', 'favorite'].includes(b.categoryId)) + if (['recent', 'favorite'].includes(b.categoryId)) continue; this._categoryButtons[i].destroy(); this._categoryButtons.splice(i, 1); @@ -2563,11 +2200,15 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { this._applicationsButtons.forEach(button => button.destroy()); this._applicationsButtons = []; - if (!this._allAppsCategoryButton) { - this._allAppsCategoryButton = new CategoryButton(this, null, _("All Applications"), "cinnamon-all-applications", true); - this.categoriesBox.add_actor(this._allAppsCategoryButton.actor); - this._categoryButtons.push(this._allAppsCategoryButton); + const index = this._categoryButtons.findIndex(button => button.categoryId == null); + if (index !== -1) { + this._categoryButtons[index].destroy(); + this._categoryButtons.splice(index, 1); + this._allAppsCategoryButton = null; } + this._allAppsCategoryButton = new CategoryButton(this, null, _("All Applications"), "cinnamon-all-applications", true); + this.categoriesBox.add_actor(this._allAppsCategoryButton.actor); + this._categoryButtons.push(this._allAppsCategoryButton); // grab top level directories and all apps in them let [apps, dirs] = AppUtils.getApps(); @@ -2608,17 +2249,21 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { _refreshFavApps() { //Remove all favorites - this.favoritesBox.destroy_all_children(); + this.favoriteAppsBox.destroy_all_children(); - //Load favorites again + //Load favorites again addding the separator first + if (this._placesButtons.length > 0) { + let separator = new PopupMenu.PopupSeparatorMenuItem(); + this.favoriteAppsBox.add_actor(separator.actor); + } this._favoriteAppButtons = []; let launchers = global.settings.get_strv('favorite-apps'); - for ( let i = 0; i < launchers.length; ++i ) { - let app = appsys.lookup_app(launchers[i]); + for (let launcher of launchers) { + let app = appsys.lookup_app(launcher); if (app) { let button = new FavoritesButton(this, app); this._favoriteAppButtons[app] = button; - this.favoritesBox.add(button.actor, { y_align: St.Align.END, y_fill: false }); + this.favoriteAppsBox.add(button.actor, { y_align: St.Align.END, y_fill: false }); } } } @@ -2653,7 +2298,7 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { } }; - this.systemButtonsBox.add(button.actor, { y_align: St.Align.END, y_fill: false }); + this.systemButtonsBox.add(button.actor, { y_align: St.Align.MIDDLE, y_fill: false }); //Logout button button = new SystemButton(this, "system-log-out", @@ -2665,7 +2310,7 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { this._session.LogoutRemote(0); }; - this.systemButtonsBox.add(button.actor, { y_align: St.Align.END, y_fill: false }); + this.systemButtonsBox.add(button.actor, { y_align: St.Align.MIDDLE, y_fill: false }); //Shutdown button button = new SystemButton(this, "system-shutdown", @@ -2677,7 +2322,7 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { this._session.ShutdownRemote(); }; - this.systemButtonsBox.add(button.actor, { y_align: St.Align.END, y_fill: false }); + this.systemButtonsBox.add(button.actor, { y_align: St.Align.MIDDLE, y_fill: false }); } _scrollToButton(button, scrollBox = this.applicationsScrollBox) { @@ -2701,181 +2346,260 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { } } + _buildSidebar() { + this.sidebar = new St.BoxLayout({ + style_class: 'appmenu-sidebar', + vertical: true + }); + + this.userBox = new St.BoxLayout({ + style_class: 'sidebar-user-box', + vertical: true + }); + + let user = AccountsService.UserManager.get_default().get_user(GLib.get_user_name()); + let userIcon = new UserWidget.UserWidget(user, Clutter.Orientation.VERTICAL); + this.userBox.add(userIcon); + + this.sidebar.add(this.userBox, { + x_fill: true, + y_fill: true, + x_align: St.Align.MIDDLE, + y_align: St.Align.START + }); + + this.sidebar.add(new PopupMenu.PopupSeparatorMenuItem().actor); + + this.sidebarAppsBox = new SidebarAppsBox().actor; + this.sidebarAppsScrollBox = new St.ScrollView({ + y_align: St.Align.START, + style_class: 'appmenu-sidebar-scrollbox' + }); + this.sidebarAppsScrollBox.set_policy(St.PolicyType.NEVER, St.PolicyType.AUTOMATIC); + this.sidebarAppsScrollBox.add_actor(this.sidebarAppsBox); + this.sidebarAppsScrollBox.get_vscroll_bar().hide(); + + this.sidebar.add(this.sidebarAppsScrollBox, { expand: true }); + + this.placesBox = new St.BoxLayout({ + vertical: true, + y_align: Clutter.ActorAlign.START + }); + + this.sidebarAppsBox.add(this.placesBox); + + this.favoriteAppsBox = new FavoriteAppsBox().actor; + this.sidebarAppsBox.add(this.favoriteAppsBox); + + this.main_container.add(this.sidebar, { span: 1 }); + } + _display() { this._activeContainer = null; this._activeActor = null; this.actor_motion_id = 0; this.vector_update_loop = 0; - this.foobar = 0; let section = new PopupMenu.PopupMenuSection(); this.menu.addMenuItem(section); - this.main_container = new St.BoxLayout({ vertical: false, style_class: 'menu-applications-outer-box' }); - this.main_container.add_style_class_name('menu-applications-box'); //this is to support old themes + this.main_container = new St.BoxLayout({ + vertical: false, + style_class: 'appmenu-main-box' + }); this.main_container._delegate = null; - section.addActor(this.main_container, { expand: true, span: -1, align: St.Align.START }); + section.addActor(this.main_container, { + expand: true, + span: -1, + align: St.Align.START, + }); - this.left_box = new St.BoxLayout({ style_class: 'menu-favorites-box', vertical: true }); - this.main_container.add(this.left_box, { span: 1 }); + this._buildSidebar(); this.right_box = new St.BoxLayout({ vertical: true }); this.main_container.add(this.right_box, { expand: true }); - this.searchBox = new St.BoxLayout({ style_class: 'menu-search-box', vertical: false }); - this.searchEntry = new St.Entry({ name: 'menu-search-entry', - track_hover: true, - can_focus: true }); - this.searchBox.add(this.searchEntry, { x_align: St.Align.START, y_align: St.Align.MIDDLE, expand: true}); + this.searchBox = new St.BoxLayout({ + style_class: 'appmenu-search-box', + vertical: false, + }); + this.searchEntry = new St.Entry({ + name: 'appmenu-search-entry', + track_hover: true, + can_focus: true, + }); + this.searchBox.add(this.searchEntry, { + x_align: St.Align.START, + y_align: St.Align.MIDDLE, + expand: true, + }); this.searchEntry.set_secondary_icon(this._searchInactiveIcon); this.searchActive = false; this.searchEntryText = this.searchEntry.clutter_text; - this.searchEntryText.connect('text-changed', Lang.bind(this, this._onSearchTextChanged)); - this.searchEntryText.connect('key-press-event', Lang.bind(this, this._onMenuKeyPress)); + this.searchEntryText.connect('text-changed', this._onSearchTextChanged.bind(this)); + this.searchEntryText.connect('key-press-event', this._onMenuKeyPress.bind(this)); this._previousSearchPattern = ""; this.right_box.add(this.searchBox, {span: 1}); this.categoriesApplicationsBox = new CategoriesApplicationsBox(); - this.right_box.add(this.categoriesApplicationsBox.actor, { expand: true, span: 1 }); + this.right_box.add(this.categoriesApplicationsBox.actor, { + expand: true, + span: 1, + }); + + this.categoriesBox = new St.BoxLayout({ + style_class: 'appmenu-categories-box', + vertical: true, + accessible_role: Atk.Role.LIST + }); - this.categoriesBox = new St.BoxLayout({ style_class: 'menu-categories-box', - vertical: true, - accessible_role: Atk.Role.LIST }); - this.categoriesScrollBox = new St.ScrollView({ style_class: 'vfade menu-applications-scrollbox' }); + this.categoriesScrollBox = new St.ScrollView({ style_class: 'appmenu-categories-scrollbox' }); this.categoriesScrollBox.add_actor(this.categoriesBox); this.categoriesScrollBox.set_policy(St.PolicyType.NEVER, St.PolicyType.AUTOMATIC); this.categoriesScrollBox.set_clip_to_allocation(true); + this.categoriesScrollBox.get_vscroll_bar().hide(); this.categoriesApplicationsBox.actor.add(this.categoriesScrollBox); - this.applicationsBox = new St.BoxLayout({ style_class: 'menu-applications-inner-box', vertical:true }); - this.applicationsBox.add_style_class_name('menu-applications-box'); //this is to support old themes - this.applicationsScrollBox = new St.ScrollView({ style_class: 'vfade menu-applications-scrollbox'}); + this.applicationsBox = new St.BoxLayout({ + style_class: 'appmenu-applications-box', + vertical:true + }); + this.applicationsScrollBox = new St.ScrollView({ style_class: 'vfade appmenu-applications-scrollbox'}); this.applicationsScrollBox.add_actor(this.applicationsBox); this.applicationsScrollBox.set_policy(St.PolicyType.NEVER, St.PolicyType.AUTOMATIC); this.applicationsScrollBox.set_clip_to_allocation(true); let vscroll = this.applicationsScrollBox.get_vscroll_bar(); - vscroll.connect('scroll-start', - Lang.bind(this, function() { - this.menu.passEvents = true; - })); - vscroll.connect('scroll-stop', - Lang.bind(this, function() { - this.menu.passEvents = false; - })); + vscroll.connect('scroll-start', () => { + this.menu.passEvents = true; + }); + vscroll.connect('scroll-stop', () => { + this.menu.passEvents = false; + }); let vscrollCat = this.categoriesScrollBox.get_vscroll_bar(); - vscrollCat.connect('scroll-start', - Lang.bind(this, function() { - this.menu.passEvents = true; - })); - vscrollCat.connect('scroll-stop', - Lang.bind(this, function() { - this.menu.passEvents = false; - })); - this.categoriesApplicationsBox.actor.add(this.applicationsScrollBox, {span: -1, expand: true}); - - this.favoritesBox = new FavoritesBox().actor; - this.favoritesScrollBox = new St.ScrollView({ y_align: St.Align.START, style_class: 'vfade menu-favorites-scrollbox' }); - this.favoritesScrollBox.set_policy(St.PolicyType.NEVER, St.PolicyType.AUTOMATIC); - this.favoritesScrollBox.set_clip_to_allocation(true); - this.favoritesScrollBox.add_actor(this.favoritesBox); - - this.left_box.add(this.favoritesScrollBox, { expand: true }); + vscrollCat.connect('scroll-start', () => { + this.menu.passEvents = true; + }); + vscrollCat.connect('scroll-stop', () => { + this.menu.passEvents = false; + }); - this.systemButtonsBox = new St.BoxLayout({ vertical: true, y_expand: false, y_align: Clutter.ActorAlign.END }); - this.left_box.add(this.systemButtonsBox, { expand: true }); + this.categoriesApplicationsBox.actor.add(this.applicationsScrollBox, {span: -1, expand: true}); - this.selectedAppBox = new St.BoxLayout({ style_class: 'menu-selected-app-box', vertical: true }); - this.selectedAppTitle = new St.Label({ style_class: 'menu-selected-app-title', text: " " }); - this.selectedAppBox.add(this.selectedAppTitle); - this.selectedAppDescription = new St.Label({ style_class: 'menu-selected-app-description', text: " " }); - this.selectedAppBox.add(this.selectedAppDescription); - this.selectedAppBox._delegate = null; + this.systemButtonsBox = new St.BoxLayout({ + style_class: 'appmenu-system-buttons-box', + y_expand: false, + x_expand: false, + x_align: Clutter.ActorAlign.END + }); - this.right_box.add(this.selectedAppBox, {span: 1}); + this.searchBox.add(this.systemButtonsBox); this.appBoxIter = new VisibleChildIterator(this.applicationsBox); this.applicationsBox._vis_iter = this.appBoxIter; this.catBoxIter = new VisibleChildIterator(this.categoriesBox); this.categoriesBox._vis_iter = this.catBoxIter; - this.favBoxIter = new VisibleChildIterator(this.favoritesBox); - this.favoritesBox._vis_iter = this.favBoxIter; + this.placesBoxIter = new VisibleChildIterator(this.placesBox); + this.placesBox._vis_iter = this.placesBoxIter; + this.favBoxIter = new VisibleChildIterator(this.favoriteAppsBox); + this.favoriteAppsBox._vis_iter = this.favBoxIter; this.sysBoxIter = new VisibleChildIterator(this.systemButtonsBox); this.systemButtonsBox._vis_iter = this.sysBoxIter; - Mainloop.idle_add(Lang.bind(this, function() { + this.updateNavigation(); + + Mainloop.idle_add(() => { this._clearAllSelections(); this._hideAllAppActors(); - })); + }); this.a11y_settings = new Gio.Settings({ schema_id: "org.cinnamon.desktop.a11y.applications" }); - this.a11y_settings.connect("changed::screen-magnifier-enabled", Lang.bind(this, this._updateVFade)); + this.a11y_settings.connect("changed::screen-magnifier-enabled", this._updateVFade.bind(this)); this.a11y_mag_settings = new Gio.Settings({ schema_id: "org.cinnamon.desktop.a11y.magnifier" }); - this.a11y_mag_settings.connect("changed::mag-factor", Lang.bind(this, this._updateVFade)); + this.a11y_mag_settings.connect("changed::mag-factor", this._updateVFade.bind(this)); this._updateVFade(); this.settings.bind("enable-autoscroll", "autoscroll_enabled", this._update_autoscroll); this._update_autoscroll(); - this._favboxtoggle(); + this._sidebarToggle(); + } + + updateNavigation() { + this.placesBoxIter.left = this.sysBoxIter; + this.placesBoxIter.right = this.catBoxIter; + this.placesBoxIter.up = this.favBoxIter; + this.placesBoxIter.down = this.favBoxIter; + this.favBoxIter.left = this.sysBoxIter; + this.favBoxIter.right = this.catBoxIter; + this.favBoxIter.up = null; + this.favBoxIter.down = null; + this.catBoxIter.right = this.appBoxIter; + this.catBoxIter.left = this.sysBoxIter; + this.appBoxIter.left = this.catBoxIter; + this.appBoxIter.right = this.sysBoxIter; + this.sysBoxIter.left = this.appBoxIter; + this.sysBoxIter.right = this.catBoxIter; + if (this.showSidebar) { + if (this._placesButtons.length > 0) { + this.favBoxIter.up = this.placesBoxIter; + this.favBoxIter.down = this.placesBoxIter; + this.catBoxIter.left = this.placesBoxIter; + this.sysBoxIter.right = this.placesBoxIter; + } + else { + this.catBoxIter.left = this.favBoxIter; + this.sysBoxIter.right = this.favBoxIter; + } + } } _updateVFade() { let mag_on = this.a11y_settings.get_boolean("screen-magnifier-enabled") && this.a11y_mag_settings.get_double("mag-factor") > 1.0; if (mag_on) { - this.applicationsScrollBox.style_class = "menu-applications-scrollbox"; - this.categoriesScrollBox.style_class = "menu-applications-scrollbox"; - this.favoritesScrollBox.style_class = "menu-favorites-scrollbox"; + this.applicationsScrollBox.style_class = "appmenu-applications-scrollbox"; } else { - this.applicationsScrollBox.style_class = "vfade menu-applications-scrollbox"; - this.categoriesScrollBox.style_class = "vfade menu-applications-scrollbox"; - this.favoritesScrollBox.style_class = "vfade menu-favorites-scrollbox"; + this.applicationsScrollBox.style_class = "vfade appmenu-applications-scrollbox"; } } _update_autoscroll() { this.applicationsScrollBox.set_auto_scrolling(this.autoscroll_enabled); this.categoriesScrollBox.set_auto_scrolling(this.autoscroll_enabled); - this.favoritesScrollBox.set_auto_scrolling(this.autoscroll_enabled); + this.sidebarAppsScrollBox.set_auto_scrolling(this.autoscroll_enabled); } _hideAllAppActors() { - let actors = this.applicationsBox.get_children(); - for (let i = 0; i < actors.length; i++) { - let actor = actors[i]; + this.applicationsBox.get_children().forEach(actor => { actor.hide(); - } + }); } _clearAllSelections() { - let actors = this.applicationsBox.get_children(); - for (let i = 0; i < actors.length; i++) { - let actor = actors[i]; - actor.style_class = "menu-application-button"; - } - actors = this.categoriesBox.get_children(); - for (let i = 0; i < actors.length; i++){ - let actor = actors[i]; + this.applicationsBox.get_children().forEach(actor => { + actor.style_class = "appmenu-application-button"; + }); + this.categoriesBox.get_children().forEach(actor => { actor.remove_style_pseudo_class("hover") - actor.style_class = "menu-category-button"; + actor.style_class = "appmenu-category-button"; actor.show(); - } - actors = this.favoritesBox.get_children(); - for (let i = 0; i < actors.length; i++){ - let actor = actors[i]; + }); + this.placesBox.get_children().forEach(actor => { actor.remove_style_pseudo_class("hover"); actor.show(); - } - actors = this.systemButtonsBox.get_children(); - for (let i = 0; i < actors.length; i++){ - let actor = actors[i]; + }); + this.favoriteAppsBox.get_children().forEach(actor => { actor.remove_style_pseudo_class("hover"); actor.show(); - } + }); + this.systemButtonsBox.get_children().forEach(actor => { + actor.remove_style_pseudo_class("hover"); + actor.show(); + }); } _resetSortOrder() { @@ -2889,10 +2613,6 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { this.applicationsBox.set_child_at_index(this._favoriteDocButtons[i].actor, pos++); } - for (let i = 0; i < this._placesButtons.length; i++) { - this.applicationsBox.set_child_at_index(this._placesButtons[i].actor, pos++); - } - for (let i = 0; i < this._recentButtons.length; i++) { this.applicationsBox.set_child_at_index(this._recentButtons[i].actor, pos++); } @@ -3000,12 +2720,12 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { let button = categoriesButtons[i]; let icon = button._delegate.icon; if (active){ - button.set_style_class_name("menu-category-button"); + button.set_style_class_name("appmenu-category-button"); if (icon) { icon.set_opacity(255); } } else { - button.set_style_class_name("menu-category-button-greyed"); + button.set_style_class_name("appmenu-category-button-greyed"); if (icon) { let icon_opacity = icon.get_theme_node().get_double('opacity'); icon_opacity = Math.min(Math.max(0, icon_opacity), 1); @@ -3034,7 +2754,6 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { this._previousSearchPattern = searchString; this.searchActive = searchActive; - this._fileFolderAccessActive = searchActive && this.searchFilesystem; this._clearAllSelections(); if (searchActive) { @@ -3058,10 +2777,8 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { this._previousSearchPattern = ""; this._setCategoriesButtonActive(true); this._select_category(); - this._allAppsCategoryButton.actor.style_class = "menu-category-button-selected"; + this._allAppsCategoryButton.actor.style_class = "appmenu-category-button-selected"; this._activeContainer = null; - this.selectedAppTitle.set_text(""); - this.selectedAppDescription.set_text(""); } } @@ -3069,16 +2786,16 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { let ret = []; let regexpPattern = new RegExp(Util.escapeRegExp(pattern)); - for (let i = 0; i < buttons.length; i++) { - if (buttons[i].type == "recent-clear" || buttons[i].type == "no-recent") { + for (let button of buttons) { + if (button.type == "recent-clear" || button.type == "no-recent") { continue; } - let res = buttons[i].searchStrings[0].match(regexpPattern); + let res = button.searchStrings[0].match(regexpPattern); if (res) { - buttons[i].matchIndex = res.index; - ret.push(buttons[i]); + button.matchIndex = res.index; + ret.push(button); } else { - buttons[i].matchIndex = NO_MATCH; + button.matchIndex = NO_MATCH; } } @@ -3092,13 +2809,11 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { let apps = []; let regexpPattern = new RegExp(Util.escapeRegExp(pattern)); - for (let i in this._applicationsButtons) { - let button = this._applicationsButtons[i]; - - for (let j = 0; j < button.searchStrings.length; j++) { - let res = button.searchStrings[j].match(regexpPattern); + for (let button of this._applicationsButtons) { + for (let i = 0; i < button.searchStrings.length; i++) { + let res = button.searchStrings[i].match(regexpPattern); if (res) { - button.matchIndex = res.index + MATCH_ADDERS[j]; + button.matchIndex = res.index + MATCH_ADDERS[i]; apps.push(button); break; } else { @@ -3117,51 +2832,39 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { this._searchTimeoutId = 0; this._activeContainer = null; this._activeActor = null; - this._previousCategoryHoverActor = null; + this.hoveredCategory = null; var acResultButtons = []; // search box autocompletion results var buttons = [] - if (this.searchFilesystem && ["~", "/"].includes(rawPattern[0])) { - // Don't use the pattern here, as filesystem is case sensitive - acResultButtons = this._getCompletions(rawPattern); - } else { - buttons = this._listApplications(pattern); - - let result = this._matchNames(this._favoriteDocButtons, pattern); - buttons = [...buttons, ...result]; + buttons = this._listApplications(pattern); - result = this._matchNames(this._placesButtons, pattern); - buttons = [...buttons, ...result]; + let result = this._matchNames(this._favoriteDocButtons, pattern); + buttons = [...buttons, ...result]; - result = this._matchNames(this._recentButtons, pattern); - buttons = [...buttons, ...result]; - } + result = this._matchNames(this._recentButtons, pattern); + buttons = [...buttons, ...result]; this._displayButtons(null, buttons, acResultButtons); if (buttons.length || acResultButtons.length) { this.appBoxIter.reloadVisible(); - this._activeActor = this.appBoxIter.getFirstVisible(); + this._activeActor = this.appBoxIter.first(); this._activeContainer = this.applicationsBox; this._scrollToButton(this._activeActor._delegate); this._buttonEnterEvent(this._activeActor._delegate); - } else { - this.selectedAppTitle.set_text(""); - this.selectedAppDescription.set_text(""); } - SearchProviderManager.launch_all(lowerPattern, Lang.bind(this, function(provider, results) { + SearchProviderManager.launch_all(lowerPattern, (provider, results) => { try { - for (var i in results) { - if (results[i].type != 'software') - { - let button = new SearchProviderResultButton(this, provider, results[i]); + for (let result of results) { + if (result.type != 'software') { + let button = new SearchProviderResultButton(this, provider, result); this._searchProviderButtons.push(button); this.applicationsBox.add_actor(button.actor); if (this._activeActor === null) { this.appBoxIter.reloadVisible(); - this._activeActor = this.appBoxIter.getFirstVisible(); + this._activeActor = this.appBoxIter.first(); this._activeContainer = this.applicationsBox; if (this._activeActor && this._activeActor != this.searchEntry) { this._buttonEnterEvent(this._activeActor._delegate); @@ -3172,55 +2875,10 @@ class CinnamonMenuApplet extends Applet.TextIconApplet { } catch(e) { global.log(e); } - })); + }); return false; } - - _getCompletion (text) { - if (!text.includes('/') || text.endsWith('/')) - return ''; - return this._pathCompleter.get_completion_suffix(text); - } - - _getCompletions (text) { - if (!text.includes('/')) - return []; - return this._pathCompleter.get_completions(text); - } - - _run (input) { - this._commandError = false; - if (input) { - let path = null; - if (input.startsWith('/')) { - path = input; - } else { - if (input.startsWith('~')) - input = input.slice(1); - path = GLib.get_home_dir() + '/' + input; - } - - if (GLib.file_test(path, GLib.FileTest.EXISTS)) { - let file = Gio.file_new_for_path(path); - try { - Gio.app_info_launch_default_for_uri(file.get_uri(), - global.create_app_launch_context()); - } catch (e) { - // The exception from gjs contains an error string like: - // Error invoking Gio.app_info_launch_default_for_uri: No application - // is registered as handling this file - // We are only interested in the part after the first colon. - //let message = e.message.replace(/[^:]*: *(.+)/, '$1'); - return false; - } - } else { - return false; - } - } - - return true; - } }; function main(metadata, orientation, panel_height, instance_id) { diff --git a/files/usr/share/cinnamon/applets/menu@cinnamon.org/settings-schema.json b/files/usr/share/cinnamon/applets/menu@cinnamon.org/settings-schema.json index 509ba08afa..1c0613ed5d 100644 --- a/files/usr/share/cinnamon/applets/menu@cinnamon.org/settings-schema.json +++ b/files/usr/share/cinnamon/applets/menu@cinnamon.org/settings-schema.json @@ -1,38 +1,53 @@ { - "layout" : { + "layout1" : { "type" : "layout", - "pages" : ["panel", "menu"], - "panel" : { + "pages" : ["layout", "appearance", "behavior"], + "layout" : { "type" : "page", - "title" : "Panel", - "sections" : ["panel-appear", "panel-behave"] + "title" : "Layout", + "sections" : ["layout-places", "layout-content"] }, - "menu" : { + "appearance" : { "type" : "page", - "title" : "Menu", - "sections" : ["menu-layout", "menu-behave"] + "title" : "Appearance", + "sections" : ["appearance-menu"] + }, + "behavior" : { + "type" : "page", + "title" : "Behavior", + "sections" : ["behavior-menu", "behavior-panel"] }, - "panel-appear" : { + "behavior-menu" : { "type" : "section", - "title" : "Appearance", - "keys" : ["menu-custom", "menu-icon", "menu-icon-size", "menu-label"] + "title" : "Menu", + "keys" : ["category-hover", "enable-autoscroll"] }, - "panel-behave" : { + "behavior-panel" : { "type" : "section", - "title" : "Behavior", + "title" : "Panel", "keys" : ["overlay-key", "activate-on-hover", "hover-delay", "force-show-panel", "enable-animation"] }, - "menu-layout" : { + "appearance-menu" : { "type" : "section", - "title" : "Layout and content", - "keys" : ["show-category-icons", - "category-icon-size", "show-application-icons", "application-icon-size", - "favbox-show", "fav-icon-size", "show-places", "show-recents", "menu-editor-button", "reset-menu-size-button"] + "title" : "Menu", + "keys" : ["show-description", "symbolic-category-icons", "category-icon-size", + "application-icon-size", "sidebar-icon-size", + "reset-menu-size-button"] }, - "menu-behave" : { + "appearance-panel" : { "type" : "section", - "title" : "Behavior", - "keys" : ["category-hover", "enable-autoscroll", "search-filesystem"] + "title" : "Panel", + "keys" : ["menu-custom", "menu-icon", "menu-icon-size", "menu-label"] + }, + "layout-places" : { + "type" : "section", + "title" : "Places", + "keys" : ["show-home", "show-desktop", "show-documents", "show-downloads", "show-music", "show-pictures", "show-videos", "show-bookmarks"] + }, + "layout-content" : { + "type" : "section", + "title" : "Content", + "keys" : ["show-sidebar", "show-favorites", "show-recents", "menu-editor-button"] } }, "overlay-key" : { @@ -71,72 +86,113 @@ "tooltip" : "Enter custom text to show in the panel.", "dependency" : "menu-custom" }, - "show-category-icons" : { + "symbolic-category-icons" : { "type" : "switch", "default" : true, - "description" : "Show category icons", - "tooltip" : "Choose whether or not to show icons on categories." + "description" : "Use symbolic icons for categories", + "tooltip" : "Choose whether or not to use symbolic icons for categories." }, "category-icon-size" : { "type": "spinbutton", - "default" : 22, + "default" : 32, "min" : 16, "max" : 48, "step" : 1, "units" : "px", "description" : "Categories icon size", - "dependency" : "show-category-icons" - }, - "show-application-icons" : { - "type" : "switch", - "default" : true, - "description" : "Show application icons", - "tooltip" : "Choose whether or not to show icons on applications." + "dependency" : "!symbolic-category-icons" }, "application-icon-size" : { "type": "spinbutton", - "default" : 22, + "default" : 32, "min" : 16, "max" : 48, "step" : 1, "units" : "px", - "description" : "Applications icon size", - "dependency" : "show-application-icons" + "description" : "Applications icon size" }, - "favbox-show" : { + "show-sidebar" : { "type" : "switch", "default" : true, - "description" : "Show favorites and session buttons", + "description" : "Sidebar", "tooltip" : "Choose whether or not to show the left pane of the menu." }, - "fav-icon-size" : { +"show-home" : { + "type" : "switch", + "default" : true, + "description" : "Home", + "tooltip" : "Choose whether or not to show the home directory." + }, +"show-desktop" : { + "type" : "switch", + "default" : true, + "description" : "Desktop", + "tooltip" : "Choose whether or not to show the desktop." + }, +"show-documents" : { + "type" : "switch", + "default" : true, + "description" : "Documents", + "tooltip" : "Choose whether or not to show the documents folder." + }, +"show-downloads" : { + "type" : "switch", + "default" : true, + "description" : "Downloads", + "tooltip" : "Choose whether or not to show the downloads folder." + }, + "show-music" : { + "type" : "switch", + "default" : true, + "description" : "Music", + "tooltip" : "Choose whether or not to show the music folder." + }, +"show-pictures" : { + "type" : "switch", + "default" : true, + "description" : "Pictures", + "tooltip" : "Choose whether or not to show the pictures folder." + }, + "show-videos" : { + "type" : "switch", + "default" : true, + "description" : "Videos", + "tooltip" : "Choose whether or not to show the videos folder." + }, + "show-bookmarks" : { + "type" : "switch", + "default" : true, + "description" : "Other bookmarks", + "tooltip" : "Choose whether or not to show other bookmarks." + }, + "sidebar-icon-size" : { "type": "spinbutton", - "default" : 32, + "default" : 24, "min" : 16, - "max" : 64, + "max" : 48, "step" : 1, "units" : "px", - "description" : "Favorites icon size", - "dependency" : "favbox-show" + "description" : "Sidebar icon size", + "dependency" : "show-sidebar" }, "show-favorites" : { "type" : "switch", "default" : true, - "description": "Show favorites", + "description": "Favorites", "tooltip": "Choose whether or not to show favorite files in the menu." }, - "show-places" : { - "type" : "switch", - "default" : true, - "description": "Show bookmarks and places", - "tooltip": "Choose whether or not to show bookmarks and places in the menu." - }, "show-recents" : { "type" : "switch", "default" : true, - "description": "Show recents", + "description": "Recents", "tooltip": "Choose whether or not to show recents in the menu." }, +"show-description" : { + "type" : "switch", + "default" : true, + "description": "Show application descriptions", + "tooltip": "Choose whether or not to show application descriptions in the menu." + }, "category-hover" : { "type" : "switch", "default" : true, @@ -149,12 +205,6 @@ "description": "Enable autoscrolling in application list", "tooltip": "Choose whether or not to enable smooth autoscrolling in the application list." }, -"search-filesystem" : { - "type" : "switch", - "default" : false, - "description": "Enable filesystem path entry in search box", - "tooltip": "Allows path entry in the menu search box." - }, "force-show-panel" : { "type" : "switch", "default" : true, @@ -196,7 +246,7 @@ }, "popup-height" : { "type" : "generic", - "default" : 515 + "default" : 560 }, "reset-menu-size-button" : { "type" : "button",