diff --git a/data/icons/Makefile.am b/data/icons/Makefile.am index f17ba6ecc6..4a7a7a2fa6 100644 --- a/data/icons/Makefile.am +++ b/data/icons/Makefile.am @@ -5,6 +5,12 @@ public_icons_themes = \ $(NULL) public_icons = \ + hicolor_actions_scalable_pan-down-symbolic.svg \ + hicolor_actions_scalable_pan-end-symbolic.svg \ + hicolor_actions_scalable_pan-end-symbolic-rtl.svg \ + hicolor_actions_scalable_pan-start-symbolic.svg \ + hicolor_actions_scalable_pan-start-symbolic-rtl.svg \ + hicolor_actions_scalable_pan-up-symbolic.svg \ hicolor_categories_16x16_cs-desklets.svg \ hicolor_categories_16x16_cs-backgrounds.svg \ hicolor_categories_scalable_cs-applets.svg \ diff --git a/data/icons/hicolor_actions_scalable_pan-down-symbolic.svg b/data/icons/hicolor_actions_scalable_pan-down-symbolic.svg new file mode 100644 index 0000000000..1c29242306 --- /dev/null +++ b/data/icons/hicolor_actions_scalable_pan-down-symbolic.svg @@ -0,0 +1,31 @@ + + + + + + + + image/svg+xml + + Gnome Symbolic Icon Theme + + + + + + + Gnome Symbolic Icon Theme + + + + + + + + + + + + + + diff --git a/data/icons/hicolor_actions_scalable_pan-end-symbolic-rtl.svg b/data/icons/hicolor_actions_scalable_pan-end-symbolic-rtl.svg new file mode 100644 index 0000000000..934bf4c3d7 --- /dev/null +++ b/data/icons/hicolor_actions_scalable_pan-end-symbolic-rtl.svg @@ -0,0 +1,31 @@ + + + + + + + + image/svg+xml + + Gnome Symbolic Icon Theme + + + + + + + Gnome Symbolic Icon Theme + + + + + + + + + + + + + + diff --git a/data/icons/hicolor_actions_scalable_pan-end-symbolic.svg b/data/icons/hicolor_actions_scalable_pan-end-symbolic.svg new file mode 100644 index 0000000000..ae9ae004a0 --- /dev/null +++ b/data/icons/hicolor_actions_scalable_pan-end-symbolic.svg @@ -0,0 +1,31 @@ + + + + + + + + image/svg+xml + + Gnome Symbolic Icon Theme + + + + + + + Gnome Symbolic Icon Theme + + + + + + + + + + + + + + diff --git a/data/icons/hicolor_actions_scalable_pan-start-symbolic-rtl.svg b/data/icons/hicolor_actions_scalable_pan-start-symbolic-rtl.svg new file mode 100644 index 0000000000..ae9ae004a0 --- /dev/null +++ b/data/icons/hicolor_actions_scalable_pan-start-symbolic-rtl.svg @@ -0,0 +1,31 @@ + + + + + + + + image/svg+xml + + Gnome Symbolic Icon Theme + + + + + + + Gnome Symbolic Icon Theme + + + + + + + + + + + + + + diff --git a/data/icons/hicolor_actions_scalable_pan-start-symbolic.svg b/data/icons/hicolor_actions_scalable_pan-start-symbolic.svg new file mode 100644 index 0000000000..934bf4c3d7 --- /dev/null +++ b/data/icons/hicolor_actions_scalable_pan-start-symbolic.svg @@ -0,0 +1,31 @@ + + + + + + + + image/svg+xml + + Gnome Symbolic Icon Theme + + + + + + + Gnome Symbolic Icon Theme + + + + + + + + + + + + + + diff --git a/data/icons/hicolor_actions_scalable_pan-up-symbolic.svg b/data/icons/hicolor_actions_scalable_pan-up-symbolic.svg new file mode 100644 index 0000000000..15f8dc5fb5 --- /dev/null +++ b/data/icons/hicolor_actions_scalable_pan-up-symbolic.svg @@ -0,0 +1,31 @@ + + + + + + + + image/svg+xml + + Gnome Symbolic Icon Theme + + + + + + + Gnome Symbolic Icon Theme + + + + + + + + + + + + + + diff --git a/data/theme/cinnamon.css b/data/theme/cinnamon.css index 0a93afbe1b..fe4ad90fe4 100644 --- a/data/theme/cinnamon.css +++ b/data/theme/cinnamon.css @@ -101,6 +101,9 @@ StScrollBar StButton#vhandle:hover { font-size: 9.5pt; min-width: 100px; } +.popup-menu-arrow { + icon-size: 1.14em; +} .popup-submenu-menu-item:open { background-color: #4c4c4c; } diff --git a/files/usr/share/cinnamon/applets/network@cinnamon.org/applet.js b/files/usr/share/cinnamon/applets/network@cinnamon.org/applet.js index c500d31b6b..d84a8f43ff 100644 --- a/files/usr/share/cinnamon/applets/network@cinnamon.org/applet.js +++ b/files/usr/share/cinnamon/applets/network@cinnamon.org/applet.js @@ -592,7 +592,7 @@ NMDevice.prototype = { if (j + activeOffset >= NUM_VISIBLE_NETWORKS) { if (!this._overflowItem) { - this._overflowItem = new PopupMenu.PopupSubMenuMenuItem(_("More..."), true); + this._overflowItem = new PopupMenu.PopupSubMenuMenuItem(_("More")); this.section.addMenuItem(this._overflowItem); } this._overflowItem.menu.addMenuItem(obj.item); @@ -1567,7 +1567,7 @@ NMDeviceWireless.prototype = { this.section.addMenuItem(apObj.item, position); } else { if (!this._overflowItem) { - this._overflowItem = new PopupMenu.PopupSubMenuMenuItem(_("More..."), true); + this._overflowItem = new PopupMenu.PopupSubMenuMenuItem(_("More")); this.section.addMenuItem(this._overflowItem); } this._overflowItem.menu.addMenuItem(apObj.item, position - NUM_VISIBLE_NETWORKS); diff --git a/files/usr/share/cinnamon/applets/sound@cinnamon.org/applet.js b/files/usr/share/cinnamon/applets/sound@cinnamon.org/applet.js index 2f8271e3ff..ec089190f7 100644 --- a/files/usr/share/cinnamon/applets/sound@cinnamon.org/applet.js +++ b/files/usr/share/cinnamon/applets/sound@cinnamon.org/applet.js @@ -1232,11 +1232,11 @@ MyApplet.prototype = { _showFixedElements: function() { //we'll show the launch player item or the selector item + a player section - this._launchPlayerItem = new PopupMenu.PopupSubMenuMenuItem(_("Launch player..."), true); + this._launchPlayerItem = new PopupMenu.PopupSubMenuMenuItem(_("Launch player")); this.menu.addMenuItem(this._launchPlayerItem); this._updateLaunchPlayer(); - this._playerSelector = new PopupMenu.PopupSubMenuMenuItem("", true); + this._playerSelector = new PopupMenu.PopupSubMenuMenuItem(""); this._playerSelector.actor.remove_style_class_name("popup-submenu-menu-item"); this._playerSelector.actor.hide(); this.menu.addMenuItem(this._playerSelector); @@ -1246,10 +1246,11 @@ MyApplet.prototype = { this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem); this._outputVolumeSection = new VolumeSlider(this, null, _("Volume"), null); this._outputVolumeSection.connect("values-changed", Lang.bind(this, this._outputValuesChanged)); - this._outputApplicationsMenu = new PopupMenu.PopupSubMenuMenuItem(_("Applications..."), true); - this._selectOutputDeviceItem = new PopupMenu.PopupSubMenuMenuItem(_("Output device..."), true); + this._outputApplicationsMenu = new PopupMenu.PopupSubMenuMenuItem(_("Applications")); + this._selectOutputDeviceItem = new PopupMenu.PopupSubMenuMenuItem(_("Output device")); this.menu.addMenuItem(this._outputVolumeSection); + this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem); this.menu.addMenuItem(this._outputApplicationsMenu); this.menu.addMenuItem(this._selectOutputDeviceItem); @@ -1258,7 +1259,7 @@ MyApplet.prototype = { this._inputSection = new PopupMenu.PopupMenuSection; this._inputVolumeSection = new VolumeSlider(this, null, _("Microphone"), null); - this._selectInputDeviceItem = new PopupMenu.PopupSubMenuMenuItem(_("Input device..."), true); + this._selectInputDeviceItem = new PopupMenu.PopupSubMenuMenuItem(_("Input device")); this._inputSection.addMenuItem(this._inputVolumeSection); this._inputSection.addMenuItem(this._selectInputDeviceItem); diff --git a/files/usr/share/cinnamon/applets/window-list@cinnamon.org/applet.js b/files/usr/share/cinnamon/applets/window-list@cinnamon.org/applet.js index fe785de2e5..a54bf1222c 100644 --- a/files/usr/share/cinnamon/applets/window-list@cinnamon.org/applet.js +++ b/files/usr/share/cinnamon/applets/window-list@cinnamon.org/applet.js @@ -517,6 +517,28 @@ AppMenuButtonRightClickMenu.prototype = { this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); + // Move to monitor + if ((length = Main.layoutManager.monitors.length) == 2) { + Main.layoutManager.monitors.forEach(function (monitor, index) { + if (index === mw.get_monitor()) return; + item = new PopupMenu.PopupMenuItem(_("Move to the other monitor")); + item.connect('activate', function() { + mw.move_to_monitor(index); + }); + this.addMenuItem(item); + }, this); + } + else if ((length = Main.layoutManager.monitors.length) > 2) { + Main.layoutManager.monitors.forEach(function (monitor, index) { + if (index === mw.get_monitor()) return; + item = new PopupMenu.PopupMenuItem(_("Move to monitor %d").format(index + 1)); + item.connect('activate', function() { + mw.move_to_monitor(index); + }); + this.addMenuItem(item); + }, this); + } + // Move to workspace if ((length = global.screen.n_workspaces) > 1) { if (mw.is_on_all_workspaces()) { @@ -532,7 +554,7 @@ AppMenuButtonRightClickMenu.prototype = { }); this.addMenuItem(item); - item = new PopupMenu.PopupSubMenuMenuItem(_("Move to another workspace ..."), true); + item = new PopupMenu.PopupSubMenuMenuItem(_("Move to another workspace")); this.addMenuItem(item); let curr_index = mw.get_workspace().index(); @@ -547,29 +569,8 @@ AppMenuButtonRightClickMenu.prototype = { mw.change_workspace(global.screen.get_workspace_by_index(j)); }); } - } - } - // Move to monitor - if ((length = Main.layoutManager.monitors.length) == 2) { - Main.layoutManager.monitors.forEach(function (monitor, index) { - if (index === mw.get_monitor()) return; - item = new PopupMenu.PopupMenuItem(_("Move to the other monitor")); - item.connect('activate', function() { - mw.move_to_monitor(index); - }); - this.addMenuItem(item); - }, this); - } - else if ((length = Main.layoutManager.monitors.length) > 2) { - Main.layoutManager.monitors.forEach(function (monitor, index) { - if (index === mw.get_monitor()) return; - item = new PopupMenu.PopupMenuItem(_("Move to monitor %d").format(index + 1)); - item.connect('activate', function() { - mw.move_to_monitor(index); - }); - this.addMenuItem(item); - }, this); + } } this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); diff --git a/js/ui/panel.js b/js/ui/panel.js index 7e78bd0f10..4711b59029 100644 --- a/js/ui/panel.js +++ b/js/ui/panel.js @@ -973,7 +973,7 @@ SettingsLauncher.prototype = { function populateSettingsMenu(menu, panelId) { - menu.troubleshootItem = new PopupMenu.PopupSubMenuMenuItem(_("Troubleshoot ..."), true); + menu.troubleshootItem = new PopupMenu.PopupSubMenuMenuItem(_("Troubleshoot")); menu.troubleshootItem.menu.addAction(_("Restart Cinnamon"), function(event) { global.reexec_self(); }); @@ -995,9 +995,7 @@ function populateSettingsMenu(menu, panelId) { menu.addMenuItem(menu.troubleshootItem); - menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); - - let panelSettingsSection = new PopupMenu.PopupSubMenuMenuItem(_("Modify panel ..."), true); + let panelSettingsSection = new PopupMenu.PopupSubMenuMenuItem(_("Modify panel")); let menuItem = new PopupMenu.PopupIconMenuItem(_("Remove panel"), "list-remove", St.IconType.SYMBOLIC); menuItem.activate = Lang.bind(menu, function() { @@ -1048,9 +1046,10 @@ function populateSettingsMenu(menu, panelId) { }); panelSettingsSection.menu.addMenuItem(menu.clearAppletItem); - menu.addMenuItem(panelSettingsSection); + menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); + // Panel Edit mode let editMode = global.settings.get_boolean("panel-edit-mode"); let panelEditMode = new PopupMenu.PopupSwitchMenuItem(_("Panel edit mode"), editMode); diff --git a/js/ui/popupMenu.js b/js/ui/popupMenu.js index 6a4161eb95..0c6beb4836 100644 --- a/js/ui/popupMenu.js +++ b/js/ui/popupMenu.js @@ -30,6 +30,36 @@ function _ensureStyle(actor) { actor.ensure_style(); } +/** + * @side Side to which the arrow points. + */ +function arrowIcon(side) { + let iconName; + switch (side) { + case St.Side.TOP: + iconName = 'pan-up'; + break; + case St.Side.RIGHT: + iconName = 'pan-end'; + break; + case St.Side.BOTTOM: + iconName = 'pan-down'; + break; + case St.Side.LEFT: + iconName = 'pan-start'; + break; + } + + let arrow = new St.Icon({ style_class: 'popup-menu-arrow', + icon_name: iconName, + icon_type: St.IconType.SYMBOLIC, + y_expand: true, + y_align: Clutter.ActorAlign.CENTER, + important: true }); + + return arrow; +} + function PopupBaseMenuItem(params) { this._init(params); } @@ -1615,7 +1645,6 @@ PopupSubMenu.prototype = { PopupMenuBase.prototype._init.call(this, sourceActor); this._arrow = sourceArrow; - if (this._arrow) this._arrow.rotation_center_z_gravity = Clutter.Gravity.CENTER; this.actor = new St.ScrollView({ style_class: 'popup-sub-menu', hscrollbar_policy: Gtk.PolicyType.NEVER, @@ -1698,23 +1727,23 @@ PopupSubMenu.prototype = { if (animate && needsScrollbar) animate = false; - let rotation_angle = 90; - if (this.actor.get_direction() == St.TextDirection.RTL) { - rotation_angle = 270; - } + let targetAngle = this.actor.text_direction == Clutter.TextDirection.RTL ? -90 : 90; if (animate) { let [minHeight, naturalHeight] = this.actor.get_preferred_height(-1); this.actor.height = 0; - if (this._arrow) this.actor._arrow_rotation = this._arrow.rotation_angle_z; - else this.actor._arrow_rotation = 0; + if (this._arrow) + this.actor._arrowRotation = this._arrow.rotation_angle_z; + else + this.actor._arrowRotation = targetAngle; Tweener.addTween(this.actor, - { _arrow_rotation: rotation_angle, + { _arrowRotation: targetAngle, height: naturalHeight, time: 0.25, onUpdateScope: this, onUpdate: function() { - if (this._arrow) this._arrow.rotation_angle_z = this.actor._arrow_rotation; + if (this._arrow) + this._arrow.rotation_angle_z = this.actor._arrowRotation; }, onCompleteScope: this, onComplete: function() { @@ -1723,7 +1752,8 @@ PopupSubMenu.prototype = { } }); } else { - if (this._arrow) this._arrow.rotation_angle_z = rotation_angle; + if (this._arrow) + this._arrow.rotation_angle_z = targetAngle; this.emit('open-state-changed', true); } }, @@ -1745,17 +1775,12 @@ PopupSubMenu.prototype = { if (animate && this._needsScrollbar()) animate = false; - - let rotation_angle = 90; - if (this.actor.get_direction() == St.TextDirection.RTL) { - rotation_angle = 270; - } if (animate) { - if (this._arrow) this.actor._arrow_rotation = this._arrow.rotation_angle_z; - else this.actor._arrow_rotation = rotation_angle; + if (this._arrow) + this.actor._arrowRotation = this._arrow.rotation_angle_z; Tweener.addTween(this.actor, - { _arrow_rotation: 0, + { _arrowRotation: 0, height: 0, time: 0.25, onCompleteScope: this, @@ -1767,11 +1792,13 @@ PopupSubMenu.prototype = { }, onUpdateScope: this, onUpdate: function() { - if (this._arrow) this._arrow.rotation_angle_z = this.actor._arrow_rotation; + if (this._arrow) + this._arrow.rotation_angle_z = this.actor._arrowRotation; } }); } else { - if (this._arrow) this._arrow.rotation_angle_z = 0; + if (this._arrow) + this._arrow.rotation_angle_z = 0; this.actor.hide(); this.isOpen = false; @@ -1835,34 +1862,25 @@ function PopupSubMenuMenuItem() { PopupSubMenuMenuItem.prototype = { __proto__: PopupBaseMenuItem.prototype, - _init: function(text, hide_expander) { + _init: function(text) { PopupBaseMenuItem.prototype._init.call(this); this.actor.add_style_class_name('popup-submenu-menu-item'); - let table = new St.Table({ homogeneous: false, - reactive: true }); - - if (!hide_expander) { - this._triangle = new St.Icon({ icon_name: "media-playback-start", - icon_type: St.IconType.SYMBOLIC, - style_class: 'popup-menu-icon' }); - - table.add(this._triangle, - {row: 0, col: 0, col_span: 1, x_expand: false, x_align: St.Align.START}); - - this.label = new St.Label({ text: text }); - this.label.set_margin_left(6.0); - table.add(this.label, - {row: 0, col: 1, col_span: 1, x_align: St.Align.START}); - } - else { - this.label = new St.Label({ text: text }); - table.add(this.label, - {row: 0, col: 0, col_span: 1, x_align: St.Align.START}); - } + this.label = new St.Label({ text: text, + y_expand: true, + y_align: Clutter.ActorAlign.CENTER }); + this.addActor(this.label); this.actor.label_actor = this.label; - this.addActor(table, { expand: true, span: 1, align: St.Align.START }); + + this._triangleBin = new St.Bin({ x_align: St.Align.END }); + this.addActor(this._triangleBin, { expand: true, + span: -1, + align: St.Align.END }); + + this._triangle = arrowIcon(St.Side.RIGHT); + this._triangle.pivot_point = new Clutter.Point({ x: 0.5, y: 0.6 }); + this._triangleBin.child = this._triangle; this.menu = new PopupSubMenu(this.actor, this._triangle); this.menu.connect('open-state-changed', Lang.bind(this, this._subMenuOpenStateChanged)); diff --git a/js/ui/runDialog.js b/js/ui/runDialog.js index 893cdf1d29..c3e3bdc6dd 100644 --- a/js/ui/runDialog.js +++ b/js/ui/runDialog.js @@ -75,8 +75,9 @@ const DEVEL_COMMANDS = { 'lg': x => Main.createLookingGlass().open(), * Returns (array): The tuple `[postfix, completions]`. */ function completeCommand(text) { - // FIXME: need to avoid splitting at escaped quotes - let last = text.match(/[^ ]*$/)[0]; + // Replace an escaped space "\ " with a random unicode character, find the + // last space, and then restore "\ " since we don't want to split at escaped strings + let last = text.replace(/\\ /g, '\uf001').match(/[^ ]*$/)[0].replace(/\uf001/g, '\\ '); if (last.length == 0) return ["",[]]; @@ -104,6 +105,8 @@ function completeCommand(text) { while ((info = fileEnum.next_file(null))) { let name = last_path + info.get_name(); + // Escape strings + name = name.replace(/ /g, "\\ ") if (info.get_file_type() == Gio.FileType.DIRECTORY) name += "/";