[gnome-shell] [AppSwitcher] Port Alt-Tab switcher to custom_handler interface
- From: Dan Winship <danw src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [gnome-shell] [AppSwitcher] Port Alt-Tab switcher to custom_handler interface
- Date: Thu, 24 Sep 2009 20:14:17 +0000 (UTC)
commit 11d884d724c71724ad54ca9c618296c872edcfaf
Author: Dan Winship <danw gnome org>
Date: Tue Sep 15 11:11:32 2009 -0400
[AppSwitcher] Port Alt-Tab switcher to custom_handler interface
https://bugzilla.gnome.org/show_bug.cgi?id=590563
js/ui/altTab.js | 82 +++++++++++++++--
js/ui/windowManager.js | 16 ++--
src/Makefile.am | 2 -
src/shell-alttab.c | 236 ------------------------------------------------
src/shell-alttab.h | 34 -------
src/shell-marshal.list | 1 +
src/shell-wm.c | 78 +++++++++++++----
src/shell-wm.h | 9 +--
8 files changed, 149 insertions(+), 309 deletions(-)
---
diff --git a/js/ui/altTab.js b/js/ui/altTab.js
index fbc1268..e4560ef 100644
--- a/js/ui/altTab.js
+++ b/js/ui/altTab.js
@@ -37,7 +37,9 @@ AltTabPopup.prototype = {
corner_radius: POPUP_GRID_SPACING,
padding: POPUP_GRID_SPACING,
spacing: POPUP_GRID_SPACING,
- orientation: Big.BoxOrientation.VERTICAL });
+ orientation: Big.BoxOrientation.VERTICAL,
+ reactive: true });
+ this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
// Icon grid. TODO: Investigate Nbtk.Grid once that lands. Currently
// just implemented using a chain of Big.Box.
@@ -70,11 +72,12 @@ AltTabPopup.prototype = {
this.actor.append(this._indicator, Big.BoxPackFlags.FIXED);
this._items = [];
+ this._haveModal = false;
global.stage.add_actor(this.actor);
},
- addWindow : function(win) {
+ _addWindow : function(win) {
let item = { window: win,
metaWindow: win.get_meta_window() };
@@ -100,6 +103,31 @@ AltTabPopup.prototype = {
},
show : function(initialSelection) {
+ let appMonitor = Shell.AppMonitor.get_default();
+ let apps = appMonitor.get_running_apps ("");
+
+ if (!apps.length)
+ return false;
+
+ if (!Main.pushModal(this.actor))
+ return false;
+ this._haveModal = true;
+
+ this._keyPressEventId = global.stage.connect('key-press-event', Lang.bind(this, this._keyPressEvent));
+ this._keyReleaseEventId = global.stage.connect('key-release-event', Lang.bind(this, this._keyReleaseEvent));
+
+ // Fill in the windows
+ let windows = [];
+ for (let i = 0; i < apps.length; i++) {
+ let appWindows = appMonitor.get_windows_for_app(apps[i].get_id());
+ windows = windows.concat(appWindows);
+ }
+
+ windows.sort(function(w1, w2) { return w2.get_user_time() - w1.get_user_time(); });
+
+ for (let i = 0; i < windows.length; i++)
+ this._addWindow(windows[i].get_compositor_private());
+
// Need to specify explicit width and height because the
// window_group may not actually cover the whole screen
this._lightbox = new Lightbox.Lightbox(global.window_group,
@@ -110,15 +138,56 @@ AltTabPopup.prototype = {
this.actor.x = Math.floor((global.screen_width - this.actor.width) / 2);
this.actor.y = Math.floor((global.screen_height - this.actor.height) / 2);
- this.select(initialSelection);
+ this._updateSelection(initialSelection);
+ return true;
+ },
+
+ _keyPressEvent : function(actor, event) {
+ let keysym = event.get_key_symbol();
+ let backwards = (event.get_state() & Clutter.ModifierType.SHIFT_MASK);
+
+ if (keysym == Clutter.Tab)
+ this._updateSelection(backwards ? -1 : 1);
+ else if (keysym == Clutter.Escape)
+ this.destroy();
+
+ return true;
+ },
+
+ _keyReleaseEvent : function(actor, event) {
+ let keysym = event.get_key_symbol();
+
+ if (keysym == Clutter.Alt_L || keysym == Clutter.Alt_R) {
+ if (this._selected) {
+ Main.activateWindow(this._selected.metaWindow,
+ event.get_time());
+ }
+ this.destroy();
+ }
+
+ return true;
},
destroy : function() {
this.actor.destroy();
- this._lightbox.destroy();
},
- select : function(n) {
+ _onDestroy : function() {
+ if (this._haveModal)
+ Main.popModal(this.actor);
+
+ if (this._lightbox)
+ this._lightbox.destroy();
+
+ if (this._keyPressEventId)
+ global.stage.disconnect(this._keyPressEventId);
+ if (this._keyReleaseEventId)
+ global.stage.disconnect(this._keyReleaseEventId);
+ },
+
+ _updateSelection : function(delta) {
+ let n = ((this._selected ? this._selected.n : 0) + this._items.length + delta) % this._items.length;
+
if (this._selected) {
// Unselect previous
@@ -177,7 +246,6 @@ AltTabPopup.prototype = {
},
_allocationChanged : function() {
- if (this._selected)
- this.select(this._selected.n);
+ this._updateSelection(0);
}
};
diff --git a/js/ui/windowManager.js b/js/ui/windowManager.js
index 2ebe5fc..4251e09 100644
--- a/js/ui/windowManager.js
+++ b/js/ui/windowManager.js
@@ -4,6 +4,7 @@ const Clutter = imports.gi.Clutter;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Meta = imports.gi.Meta;
+const Shell = imports.gi.Shell;
const AltTab = imports.ui.altTab;
const Main = imports.ui.main;
@@ -39,7 +40,8 @@ WindowManager.prototype = {
shellwm.connect('destroy', Lang.bind(this, this._destroyWindow));
shellwm.connect('kill-destroy', Lang.bind(this, this._destroyWindowDone));
- shellwm.connect('begin-alt-tab', Lang.bind(this, this._beginAltTab));
+ shellwm.takeover_keybinding('switch_windows');
+ shellwm.connect('keybinding::switch_windows', Lang.bind(this, this._startAppSwitcher));
},
_shouldAnimate : function(actor) {
@@ -300,12 +302,10 @@ WindowManager.prototype = {
shellwm.completed_switch_workspace();
},
- _beginAltTab : function(shellwm, handler) {
- let popup = new AltTab.AltTabPopup();
+ _startAppSwitcher : function(shellwm, binding, window, backwards) {
+ let tabPopup = new AltTab.AltTabPopup();
- handler.connect('window-added', function(handler, window) { popup.addWindow(window); });
- handler.connect('show', function(handler, initialSelection) { popup.show(initialSelection); });
- handler.connect('destroy', function() { popup.destroy(); });
- handler.connect('notify::selected', function() { popup.select(handler.selected); });
- }
+ if (!tabPopup.show(backwards ? -1 : 1))
+ tabPopup.destroy();
+ }
};
diff --git a/src/Makefile.am b/src/Makefile.am
index da7de38..fe81579 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -52,8 +52,6 @@ CLEANFILES += $(SHELL_STAMP_FILES)
libgnome_shell_la_SOURCES = \
$(shell_built_sources) \
gnome-shell-plugin.c \
- shell-alttab.c \
- shell-alttab.h \
shell-app-monitor.c \
shell-app-monitor.h \
shell-app-system.c \
diff --git a/src/shell-marshal.list b/src/shell-marshal.list
index 329f8b3..6a69de7 100644
--- a/src/shell-marshal.list
+++ b/src/shell-marshal.list
@@ -2,3 +2,4 @@ VOID:INT,INT,INT
VOID:OBJECT,INT,INT,INT,INT
VOID:BOXED
VOID:BOXED,OBJECT
+VOID:STRING,OBJECT,BOOLEAN
diff --git a/src/shell-wm.c b/src/shell-wm.c
index 42ec233..3b757cc 100644
--- a/src/shell-wm.c
+++ b/src/shell-wm.c
@@ -1,9 +1,13 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+#include <string.h>
+
#include "shell-wm.h"
#include "shell-global.h"
#include "shell-marshal.h"
+#include <keybindings.h>
+
struct _ShellWM {
GObject parent;
@@ -27,7 +31,7 @@ enum
SWITCH_WORKSPACE,
KILL_SWITCH_WORKSPACE,
- BEGIN_ALT_TAB,
+ KEYBINDING,
LAST_SIGNAL
};
@@ -42,7 +46,6 @@ static guint shell_wm_signals [LAST_SIGNAL] = { 0 };
static void
shell_wm_init (ShellWM *wm)
{
- meta_alt_tab_handler_register (SHELL_TYPE_ALT_TAB_HANDLER);
}
static void
@@ -169,15 +172,32 @@ shell_wm_class_init (ShellWMClass *klass)
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
- shell_wm_signals[BEGIN_ALT_TAB] =
- g_signal_new ("begin-alt-tab",
+
+ /**
+ * ShellWM::keybinding:
+ * @shellwm: the #ShellWM
+ * @binding: the keybinding name
+ * @window: for window keybindings, the #MetaWindow
+ * @backwards: for "reversible" keybindings, whether or not
+ * the backwards (Shifted) variant was invoked
+ *
+ * Emitted when a keybinding captured via
+ * shell_wm_takeover_keybinding() is invoked. The keybinding name
+ * (which has underscores, not hyphens) is also included as the
+ * detail of the signal name, so you can connect just specific
+ * keybindings.
+ */
+ shell_wm_signals[KEYBINDING] =
+ g_signal_new ("keybinding",
G_TYPE_FROM_CLASS (klass),
- G_SIGNAL_RUN_LAST,
+ G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
0,
NULL, NULL,
- g_cclosure_marshal_VOID__OBJECT,
- G_TYPE_NONE, 1,
- META_TYPE_ALT_TAB_HANDLER);
+ _shell_marshal_VOID__STRING_OBJECT_BOOLEAN,
+ G_TYPE_NONE, 3,
+ G_TYPE_STRING,
+ META_TYPE_WINDOW,
+ G_TYPE_BOOLEAN);
}
void
@@ -391,14 +411,6 @@ _shell_wm_destroy (ShellWM *wm,
g_signal_emit (wm, shell_wm_signals[DESTROY], 0, actor);
}
-/* Called from shell-alttab.c */
-void
-_shell_wm_begin_alt_tab (ShellWM *wm,
- ShellAltTabHandler *handler)
-{
- g_signal_emit (wm, shell_wm_signals[BEGIN_ALT_TAB], 0, handler);
-}
-
/**
* shell_wm_new:
* @plugin: the #MutterPlugin
@@ -417,3 +429,37 @@ shell_wm_new (MutterPlugin *plugin)
return wm;
}
+
+static void
+shell_wm_key_handler (MetaDisplay *display,
+ MetaScreen *screen,
+ MetaWindow *window,
+ XEvent *event,
+ MetaKeyBinding *binding,
+ gpointer data)
+{
+ ShellWM *wm = data;
+ gboolean backwards = (event->xkey.state & ShiftMask);
+
+ g_signal_emit (wm, shell_wm_signals[KEYBINDING],
+ g_quark_from_string (binding->name),
+ binding->name, window, backwards);
+}
+
+/**
+ * shell_wm_takeover_keybinding:
+ * @wm: the #ShellWM
+ * @binding_name: a mutter keybinding name
+ *
+ * Tells mutter to forward keypresses for @binding_name to the shell
+ * rather than processing them internally. This will cause a
+ * #ShellWM::keybinding signal to be emitted when that key is pressed.
+ */
+void
+shell_wm_takeover_keybinding (ShellWM *wm,
+ const char *binding_name)
+{
+ meta_keybindings_set_custom_handler (binding_name,
+ shell_wm_key_handler,
+ wm, NULL);
+}
diff --git a/src/shell-wm.h b/src/shell-wm.h
index 59387cf..aa8e131 100644
--- a/src/shell-wm.h
+++ b/src/shell-wm.h
@@ -4,8 +4,6 @@
#include <glib-object.h>
#include <mutter-plugin.h>
-#include "shell-alttab.h"
-
G_BEGIN_DECLS
typedef struct _ShellWM ShellWM;
@@ -73,10 +71,9 @@ void _shell_wm_kill_effect (ShellWM *wm,
MutterWindow *actor,
gulong events);
-/* Called by ShellAltTabHandler */
-
-void _shell_wm_begin_alt_tab (ShellWM *wm,
- ShellAltTabHandler *handler);
+/* Keybinding stuff */
+void shell_wm_takeover_keybinding (ShellWM *wm,
+ const char *binding_name);
G_END_DECLS
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]