[gnome-shell] [AppSwitcher] Port Alt-Tab switcher to custom_handler interface



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]