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 @@
+
+
+
+
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 @@
+
+
+
+
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 @@
+
+
+
+
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 @@
+
+
+
+
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 @@
+
+
+
+
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 @@
+
+
+
+
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 += "/";