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
This commit is contained in:
Maxim Ermilov
2011-01-19 00:43:37 +03:00
parent ef663f3f0c
commit 1f2b0d0ec5
6 changed files with 225 additions and 2 deletions
+2 -1
View File
@@ -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
])
+1 -1
View File
@@ -1,3 +1,3 @@
DIST_SUBDIRS = example alternate-tab xrandr-indicator
DIST_SUBDIRS = example alternate-tab xrandr-indicator windowsNavigator
SUBDIRS = $(ENABLED_EXTENSIONS)
+3
View File
@@ -0,0 +1,3 @@
EXTENSION_ID = windowsNavigator
include ../../extension.mk
+203
View File
@@ -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);
});
}
@@ -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"
}
@@ -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;
}