diff --git a/Settings.ui b/Settings.ui
index a590e07..8d11049 100644
--- a/Settings.ui
+++ b/Settings.ui
@@ -1263,6 +1263,70 @@
+
+
+
diff --git a/prefs.js b/prefs.js
index feeaa3d..90aacd3 100644
--- a/prefs.js
+++ b/prefs.js
@@ -443,6 +443,10 @@ const Settings = new Lang.Class({
this._builder.get_object('listboxrow_peek_mode_opacity'),
'sensitive',
Gio.SettingsBindFlags.DEFAULT);
+ this._settings.bind('preview-middle-click-close',
+ this._builder.get_object('preview_middle_click_close_switch'),
+ 'active',
+ Gio.SettingsBindFlags.DEFAULT);
this._builder.get_object('enter_peek_mode_timeout_spinbutton').set_value(this._settings.get_int('enter-peek-mode-timeout'));
@@ -467,6 +471,7 @@ const Settings = new Lang.Class({
this._builder.get_object('enter_peek_mode_timeout_spinbutton').set_value(this._settings.get_int('enter-peek-mode-timeout'));
this._settings.set_value('peek-mode-opacity', this._settings.get_default_value('peek-mode-opacity'));
this._builder.get_object('peek_mode_opacity_spinbutton').set_value(this._settings.get_int('peek-mode-opacity'));
+ this._settings.set_value('preview-middle-click-close', this._settings.get_default_value('preview-middle-click-close'));
} else {
// remove the settings box so it doesn't get destroyed;
diff --git a/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml b/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml
index 749415c..801126b 100644
--- a/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml
+++ b/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml
@@ -230,6 +230,11 @@
Window peeking mode opacity
All windows except for the peeked one have their opacity set to the same value.
+
+ false
+ Middle click preview to close window
+ Middle click on the window preview to close that window
+
0
Tray font size
diff --git a/windowPreview.js b/windowPreview.js
index eb76cf3..380f413 100644
--- a/windowPreview.js
+++ b/windowPreview.js
@@ -22,6 +22,7 @@
*/
+const BoxPointer = imports.ui.boxpointer;
const Clutter = imports.gi.Clutter;
const GLib = imports.gi.GLib;
const Gtk = imports.gi.Gtk;
@@ -30,9 +31,12 @@ const Main = imports.ui.main;
const Mainloop = imports.mainloop;
const Meta = imports.gi.Meta;
const PopupMenu = imports.ui.popupMenu;
+const RemoteMenu = imports.ui.remoteMenu;
const Signals = imports.signals;
+const Shell = imports.gi.Shell;
const St = imports.gi.St;
const Tweener = imports.ui.tweener;
+const WindowMenu = imports.ui.windowMenu;
const Workspace = imports.ui.workspace;
const Shell = imports.gi.Shell;
@@ -559,6 +563,8 @@ const thumbnailPreview = new Lang.Class({
Lang.bind(this, this._onLeave));
this.actor.connect('motion-event',
Lang.bind(this, this._onMotionEvent));
+
+ this._previewMenuPopupManager = new previewMenuPopupManager(window, this.actor);
},
_onEnter: function(actor, event) {
@@ -779,6 +785,37 @@ const thumbnailPreview = new Lang.Class({
}));
}
}
+ },
+
+ _onButtonReleaseEvent: function(actor, event) {
+ this.actor.remove_style_pseudo_class ('active');
+ switch (event.get_button()) {
+ case 1:
+ // Left click
+ this.activate(event);
+ break;
+ case 2:
+ // Middle click
+ if (this._getTopMenu()._dtpSettings.get_boolean('preview-middle-click-close')) {
+ this._closeWindow();
+ }
+ break;
+ case 3:
+ // Right click
+ this.showContextMenu(event);
+ break;
+ }
+ return Clutter.EVENT_STOP;
+ },
+
+ showContextMenu: function(event) {
+ let coords = event.get_coords();
+ this._previewMenuPopupManager.showWindowMenuForWindow({
+ x: coords[0],
+ y: coords[1],
+ width: 0,
+ height: 0
+ });
}
});
@@ -1043,3 +1080,67 @@ const thumbnailPreviewList = new Lang.Class({
return windowA.get_stable_sequence() > windowB.get_stable_sequence();
}
});
+
+const previewMenuPopup = new Lang.Class({
+ Name: 'previewMenuPopup',
+ Extends: WindowMenu.WindowMenu,
+
+ _init: function(window, sourceActor) {
+ this.parent(window, sourceActor);
+
+ let side = Taskbar.getPosition();
+ this._arrowSide = side;
+ this._boxPointer._arrowSide = side;
+ this._boxPointer._userArrowSide = side;
+ }
+
+ // Otherwise, just let the parent do its thing?
+});
+
+const previewMenuPopupManager = new Lang.Class({
+ Name: 'previewMenuPopupManagerTest',
+
+ _init: function(window, source) {
+ this._manager = new PopupMenu.PopupMenuManager({ actor: Main.layoutManager.dummyCursor });
+
+ this._sourceActor = new St.Widget({ reactive: true, visible: false });
+ this._sourceActor.connect('button-press-event', Lang.bind(this,
+ function() {
+ this._manager.activeMenu.toggle();
+ }));
+ Main.uiGroup.add_actor(this._sourceActor);
+
+ this.window = window;
+ },
+
+ showWindowMenuForWindow: function(rect) {
+ let menu = new previewMenuPopup(this.window, this._sourceActor);
+ let window = this.window;
+
+ this._manager.addMenu(menu);
+
+ menu.connect('activate', function() {
+ window.check_alive(global.get_current_time());
+ });
+ let destroyId = window.connect('unmanaged',
+ function() {
+ menu.close();
+ });
+
+ this._sourceActor.set_size(Math.max(1, rect.width), Math.max(1, rect.height));
+ this._sourceActor.set_position(rect.x, rect.y);
+
+ this._sourceActor.show();
+
+ menu.open(BoxPointer.PopupAnimation.NONE);
+ menu.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
+ menu.connect('open-state-changed', Lang.bind(this, function(menu_, isOpen) {
+ if (isOpen)
+ return;
+
+ this._sourceActor.hide();
+ menu.destroy();
+ window.disconnect(destroyId);
+ }));
+ }
+});
\ No newline at end of file