[gnome-shell-extensions] windowsNavigator: Allow keyboard selection of windows and workspaces in overlay mode



commit 1f2b0d0ec51ad7dda4e1156eca32b71c642c584b
Author: Maxim Ermilov <zaspire rambler ru>
Date:   Wed Jan 19 00:43:37 2011 +0300

    windowsNavigator: Allow keyboard selection of windows and workspaces in overlay mode
    
    Bind alt-[1,2,3..9]  "switch window on current workspace"
    Bind ctrl-[1,2,3..9]  switch workspace
    https://bugzilla.gnome.org/show_bug.cgi?id=601393

 configure.ac                               |    3 +-
 extensions/Makefile.am                     |    2 +-
 extensions/windowsNavigator/Makefile.am    |    3 +
 extensions/windowsNavigator/extension.js   |  203 ++++++++++++++++++++++++++++
 extensions/windowsNavigator/metadata.json  |    7 +
 extensions/windowsNavigator/stylesheet.css |    9 ++
 6 files changed, 225 insertions(+), 2 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 5a012ef..6ef5eb4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -19,7 +19,7 @@ PKG_PROG_PKG_CONFIG([0.22])
 ADDITIONAL_PACKAGES=
 
 dnl keep this in sync with extensions/Makefile.am
-ALL_EXTENSIONS="example alternate-tab xrandr-indicator"
+ALL_EXTENSIONS="example alternate-tab xrandr-indicator windowsNavigator"
 AC_ARG_ENABLE([extensions],
 	[AS_HELP_STRING([--enable-extensions],[Space separated list of extensions to enable. Default is that all extensions are built.])],
 	[],
@@ -54,6 +54,7 @@ AC_CONFIG_FILES([
   extensions/Makefile
   extensions/example/Makefile
   extensions/alternate-tab/Makefile
+  extensions/windowsNavigator/Makefile
   extensions/xrandr-indicator/Makefile
   po/Makefile.in
 ])
diff --git a/extensions/Makefile.am b/extensions/Makefile.am
index b42f5d7..e2c5fba 100644
--- a/extensions/Makefile.am
+++ b/extensions/Makefile.am
@@ -1,3 +1,3 @@
-DIST_SUBDIRS = example alternate-tab xrandr-indicator
+DIST_SUBDIRS = example alternate-tab xrandr-indicator windowsNavigator
 
 SUBDIRS = $(ENABLED_EXTENSIONS)
diff --git a/extensions/windowsNavigator/Makefile.am b/extensions/windowsNavigator/Makefile.am
new file mode 100644
index 0000000..adeb886
--- /dev/null
+++ b/extensions/windowsNavigator/Makefile.am
@@ -0,0 +1,3 @@
+EXTENSION_ID = windowsNavigator
+
+include ../../extension.mk
diff --git a/extensions/windowsNavigator/extension.js b/extensions/windowsNavigator/extension.js
new file mode 100644
index 0000000..7801e53
--- /dev/null
+++ b/extensions/windowsNavigator/extension.js
@@ -0,0 +1,203 @@
+/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
+const Clutter = imports.gi.Clutter;
+const Lang = imports.lang;
+const Mainloop = imports.mainloop;
+const St = imports.gi.St;
+
+const Main = imports.ui.main;
+const Workspace = imports.ui.workspace;
+const WorkspacesView = imports.ui.workspacesView;
+
+function injectToFunction(parent, name, func) {
+    let origin = parent[name];
+    parent[name] = function() {
+        let ret;
+        ret = origin.apply(this, arguments);
+        if (ret === undefined)
+            ret = func.apply(this, arguments);
+        return ret;
+    }
+}
+
+function main() {
+    Workspace.WindowOverlay.prototype.setId = function(id) {
+        if (this._text.visible && id == null)
+            this._text.hide();
+        this._id = id;
+        if (id != null)
+            this._text.text = this._id.toString();
+    }
+    Workspace.WindowOverlay.prototype.getId = function() {
+        return this._id;
+    }
+    Workspace.WindowOverlay.prototype.showTooltip = function() {
+        if (this._id === null)
+            return;
+        this._text.raise_top();
+        this._text.show();
+        this._text.text = this._id.toString();
+    }
+    Workspace.WindowOverlay.prototype.hideTooltip = function() {
+        if (this._text.visible)
+            this._text.hide();
+    }
+
+    Workspace.Workspace.prototype.showTooltip = function() {
+        if (this._tip == null)
+            return;
+        if (this.parent)
+            return;
+        this.actor.add_actor(this._tip);
+        this._tip.raise_top();
+    }
+    Workspace.Workspace.prototype.hideTooltip = function() {
+        if (this._tip == null)
+            return;
+        if (!this._tip.get_parent())
+            return;
+        this.actor.remove_actor(this._tip);
+    }
+    Workspace.Workspace.prototype.getWindowWithTooltip = function(id) {
+        for (let i in this._windowOverlays) {
+            if (this._windowOverlays[i] == null)
+                continue;
+            if (this._windowOverlays[i].getId() === id)
+                return this._windowOverlays[i]._windowClone.metaWindow;
+        }
+        return null;
+    }
+    Workspace.Workspace.prototype.showWindowsTooltips = function() {
+        for (let i in this._windowOverlays) {
+            if (this._windowOverlays[i] != null)
+                this._windowOverlays[i].showTooltip();
+        }
+    }
+    Workspace.Workspace.prototype.hideWindowsTooltips = function() {
+        for (let i in this._windowOverlays) {
+            if (this._windowOverlays[i] != null)
+                this._windowOverlays[i].hideTooltip();
+        }
+    }
+
+    WorkspacesView.WorkspacesView.prototype._hideTooltips = function() {
+        global.stage.set_key_focus(this._prevFocusActor);
+        this._pickWindow = false;
+        for (let i = 0; i < this._workspaces.length; i++)
+            this._workspaces[i].hideWindowsTooltips();
+    }
+
+    WorkspacesView.WorkspacesView.prototype._hideWorkspacesTooltips = function() {
+        global.stage.set_key_focus(this._prevFocusActor);
+        this._pickWorkspace = false;
+        for (let i = 0; i < this._workspaces.length; i++)
+            this._workspaces[i].hideTooltip();
+    }
+
+    WorkspacesView.WorkspacesView.prototype._onKeyRelease = function(s, o) {
+        if (this._pickWindow && o.get_key_symbol() == Clutter.Alt_L)
+            this._hideTooltips();
+        if (this._pickWorkspace && o.get_key_symbol() == Clutter.Control_L)
+            this._hideWorkspacesTooltips();
+    }
+    WorkspacesView.WorkspacesView.prototype._onKeyPress = function(s, o) {
+        if (o.get_key_symbol() == Clutter.Alt_L && !this._pickWorkspace) {
+            this._prevFocusActor = global.stage.get_key_focus();
+            global.stage.set_key_focus(null);
+            this._active = global.screen.get_active_workspace_index();
+            this._pickWindow = true;
+            this._workspaces[global.screen.get_active_workspace_index()].showWindowsTooltips();
+            return true;
+        }
+        if (o.get_key_symbol() == Clutter.Control_L && !this._pickWindow) {
+            this._prevFocusActor = global.stage.get_key_focus();
+            global.stage.set_key_focus(null);
+            this._pickWorkspace = true;
+            for (let i = 0; i < this._workspaces.length; i++)
+                this._workspaces[i].showTooltip();
+            return true;
+        }
+
+        if (global.stage.get_key_focus() != global.stage)
+            return false;
+
+        if (this._pickWindow) {
+            if (this._active != global.screen.get_active_workspace_index()) {
+                this._hideTooltips();
+                return false;
+            }
+            let c = o.get_key_unicode();
+            if (c > '9'.charCodeAt(0) || c < '0'.charCodeAt(0)) {
+                this._hideTooltips();
+                return false;
+            }
+            let win = this._workspaces[this._active].getWindowWithTooltip(c - '0'.charCodeAt(0));
+            this._hideTooltips();
+            if (win)
+                Main.activateWindow(win, global.get_current_time());
+            return true;
+        }
+        if (this._pickWorkspace) {
+            let c = o.get_key_unicode();
+            if (c > '9'.charCodeAt(0) || c < '0'.charCodeAt(0)) {
+                this._hideWorkspacesTooltips();
+                return false;
+            }
+            let workspace = this._workspaces[c - '0'.charCodeAt(0) - 1];
+            if (workspace !== undefined)
+                workspace.metaWorkspace.activate(global.get_current_time());
+            this._hideWorkspacesTooltips();
+            return true;
+        }
+        return false;
+    }
+
+    injectToFunction(Workspace.WindowOverlay.prototype, '_init', function(windowClone, parentActor) {
+        this._id = null;
+        this._text = new St.Label({ style_class: 'window-tooltip' });
+        this._text.hide();
+        parentActor.add_actor(this._text);
+    });
+    injectToFunction(Workspace.WindowOverlay.prototype, 'updatePositions', function(cloneX, cloneY, cloneWidth, cloneHeight) {
+        let textX = cloneX - 2;
+        let textY = cloneY - 2;
+        this._text.set_position(Math.floor(textX), Math.floor(textY));
+        this._text.raise_top();
+    });
+    injectToFunction(Workspace.Workspace.prototype, '_init', function(metaWorkspace) {
+        if (metaWorkspace.index() < 9) {
+            this._tip = new St.Label({ style_class: 'window-tooltip',
+                                       text: (metaWorkspace.index() + 1).toString() });
+            this.actor.connect('notify::scale-x', Lang.bind(this, function() {
+                this._tip.set_scale(1 / this.actor.scale_x, 1 / this.actor.scale_x);
+            }));
+        } else
+            this._tip = null;
+    });
+    injectToFunction(Workspace.Workspace.prototype, 'positionWindows', function(flags) {
+        let visibleClones = this._getVisibleClones();
+        if (this._reservedSlot)
+            visibleClones.push(this._reservedSlot);
+
+        let slots = this._computeAllWindowSlots(visibleClones.length);
+        visibleClones = this._orderWindowsByMotionAndStartup(visibleClones, slots);
+        for (let i = 0; i < visibleClones.length; i++) {
+            let clone = visibleClones[i];
+            let metaWindow = clone.metaWindow;
+            let mainIndex = this._lookupIndex(metaWindow);
+            let overlay = this._windowOverlays[mainIndex];
+            if (overlay)
+                overlay.setId(i < 9 ? i + 1 : null);
+        }
+    });
+
+    injectToFunction(WorkspacesView.WorkspacesView.prototype, '_init', function(width, height, x, y, workspaces) {
+        this._pickWorkspace = false;
+        this._pickWindow = false;
+        this._keyPressEventId = global.stage.connect('key-press-event', Lang.bind(this, this._onKeyPress));
+        this._keyReleaseEventId = global.stage.connect('key-release-event', Lang.bind(this, this._onKeyRelease));
+    });
+    injectToFunction(WorkspacesView.WorkspacesView.prototype, '_onDestroy', function() {
+        global.stage.disconnect(this._keyPressEventId);
+        global.stage.disconnect(this._keyReleaseEventId);
+    });
+}
diff --git a/extensions/windowsNavigator/metadata.json b/extensions/windowsNavigator/metadata.json
new file mode 100644
index 0000000..50150ea
--- /dev/null
+++ b/extensions/windowsNavigator/metadata.json
@@ -0,0 +1,7 @@
+{
+    "shell-version": ["2.91.5"],
+    "uuid": "windowsNavigator gnome-shell-extensions gnome org",
+    "original-author": "zaspire rambler ru",
+    "name": "windowNavigator",
+    "description": "Allow keyboard selection of windows and workspaces in overlay mode"
+}
\ No newline at end of file
diff --git a/extensions/windowsNavigator/stylesheet.css b/extensions/windowsNavigator/stylesheet.css
new file mode 100644
index 0000000..6406652
--- /dev/null
+++ b/extensions/windowsNavigator/stylesheet.css
@@ -0,0 +1,9 @@
+.window-tooltip {
+    color: #ff0000;
+    background: rgba(0,0,0,0.8);
+    border: 1px solid rgba(128,128,128,0.40);
+    border-radius: 10px;
+    font-size: 16px;
+    padding: 2px 8px;
+    -shell-caption-spacing: 4px;
+}
\ No newline at end of file



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]