[gnome-shell: 1/2] Implement MetaAltTabHandler



commit 81dbf5118f1cdf7fed6bdbab425e58a4bf472bee
Author: Dan Winship <danw gnome org>
Date:   Mon Apr 13 10:55:41 2009 -0400

    Implement MetaAltTabHandler
    
    This is a fairly simple implementation, not all that different from
    plain metacity's. Further improvements could be made to
    js/ui/altTab.js in the future.
    
    http://bugzilla.gnome.org/show_bug.cgi?id=580917
---
 js/ui/altTab.js        |  221 ++++++++++++++++++++++++++++++++++++++++++++++
 js/ui/windowManager.js |   16 +++-
 src/Makefile.am        |    2 +
 src/shell-alttab.c     |  230 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/shell-alttab.h     |   34 +++++++
 src/shell-wm.c         |   20 ++++
 src/shell-wm.h         |    7 ++
 7 files changed, 529 insertions(+), 1 deletions(-)

diff --git a/js/ui/altTab.js b/js/ui/altTab.js
new file mode 100644
index 0000000..2cb7943
--- /dev/null
+++ b/js/ui/altTab.js
@@ -0,0 +1,221 @@
+/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
+
+const Big = imports.gi.Big;
+const Clutter = imports.gi.Clutter;
+const Lang = imports.lang;
+const Pango = imports.gi.Pango;
+const Shell = imports.gi.Shell;
+
+const Main = imports.ui.main;
+const Overlay = imports.ui.overlay;
+const Tweener = imports.ui.tweener;
+
+const POPUP_BG_COLOR = new Clutter.Color();
+POPUP_BG_COLOR.from_pixel(0x00000080);
+const POPUP_INDICATOR_COLOR = new Clutter.Color();
+POPUP_INDICATOR_COLOR.from_pixel(0xf0f0f0ff);
+const POPUP_TRANSPARENT = new Clutter.Color();
+POPUP_TRANSPARENT.from_pixel(0x00000000);
+
+const RED = new Clutter.Color();
+RED.from_pixel(0xff0000ff);
+const GREEN = new Clutter.Color();
+GREEN.from_pixel(0x00ff00ff);
+const BLUE = new Clutter.Color();
+BLUE.from_pixel(0x0000ffff);
+
+const POPUP_INDICATOR_WIDTH = 4;
+const POPUP_GRID_SPACING = 8;
+const POPUP_ICON_SIZE = 48;
+const POPUP_NUM_COLUMNS = 5;
+
+const POPUP_LABEL_MAX_WIDTH = POPUP_NUM_COLUMNS * (POPUP_ICON_SIZE + POPUP_GRID_SPACING);
+
+const OVERLAY_COLOR = new Clutter.Color();
+OVERLAY_COLOR.from_pixel(0x00000044);
+
+function AltTabPopup() {
+    this._init();
+}
+
+AltTabPopup.prototype = {
+    _init : function() {
+	let global = Shell.Global.get();
+
+	this.actor = new Big.Box({ background_color : POPUP_BG_COLOR,
+                                   corner_radius: POPUP_GRID_SPACING,
+                                   padding: POPUP_GRID_SPACING,
+                                   spacing: POPUP_GRID_SPACING,
+                                   orientation: Big.BoxOrientation.VERTICAL });
+
+        // Icon grid. It would be nice to use Tidy.Grid for the this,
+        // but Tidy.Grid is lame in various ways. (Eg, it seems to
+        // have a minimum size of 200x200.) So we create a vertical
+        // Big.Box containing multiple horizontal Big.Boxes.
+	this._grid = new Big.Box({ spacing: POPUP_GRID_SPACING,
+                                   orientation: Big.BoxOrientation.VERTICAL });
+        let gcenterbox = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
+                                       x_align: Big.BoxAlignment.CENTER });
+        gcenterbox.append(this._grid, Big.BoxPackFlags.NONE);
+	this.actor.append(gcenterbox, Big.BoxPackFlags.NONE);
+
+        // Selected-window label
+	this._label = new Clutter.Text({ font_name: "Sans 12",
+                                         ellipsize: Pango.EllipsizeMode.END });
+
+        let labelbox = new Big.Box({ background_color: POPUP_INDICATOR_COLOR,
+                                     corner_radius: POPUP_GRID_SPACING / 2,
+                                     padding: POPUP_GRID_SPACING / 2 });
+        labelbox.append(this._label, Big.BoxPackFlags.EXPAND);
+        let lcenterbox = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
+                                       x_align: Big.BoxAlignment.CENTER,
+                                       width: POPUP_LABEL_MAX_WIDTH + POPUP_GRID_SPACING });
+        lcenterbox.append(labelbox, Big.BoxPackFlags.NONE);
+	this.actor.append(lcenterbox, Big.BoxPackFlags.NONE);
+
+        // Indicator around selected icon
+        this._indicator = new Big.Rectangle({ border_width: POPUP_INDICATOR_WIDTH,
+                                              corner_radius: POPUP_INDICATOR_WIDTH / 2,
+                                              border_color: POPUP_INDICATOR_COLOR,
+                                              color: POPUP_TRANSPARENT });
+        this.actor.append(this._indicator, Big.BoxPackFlags.FIXED);
+
+	this._items = [];
+        this._toplevels = global.window_group.get_children();
+
+	global.stage.add_actor(this.actor);
+
+        // Dark translucent window used to cover all but the
+        // currently-selected window while Alt-Tabbing.
+        // FIXME: share overlay code with runDialog.js
+        this._overlay = new Clutter.Rectangle({ color: OVERLAY_COLOR,
+                                                width: global.screen_width,
+                                                height: global.screen_height,
+                                                border_width: 0,
+                                                reactive: true });
+    },
+
+    addWindow : function(win) {
+        let item = { window: win,
+                     metaWindow: win.get_meta_window() };
+
+        let pixbuf = item.metaWindow.icon;
+        item.icon = new Clutter.Texture({ width: POPUP_ICON_SIZE,
+                                          height: POPUP_ICON_SIZE,
+                                          keep_aspect_ratio: true });
+        Shell.clutter_texture_set_from_pixbuf(item.icon, pixbuf);
+
+        item.box = new Big.Box({ padding: POPUP_INDICATOR_WIDTH * 2 });
+        item.box.append(item.icon, Big.BoxPackFlags.NONE);
+
+        item.above = null;
+        for (let i = 1; i < this._toplevels.length; i++) {
+            if (this._toplevels[i] == win) {
+                item.above = this._toplevels[i - 1];
+                break;
+            }
+        }
+
+        item.n = this._items.length;
+        this._items.push(item);
+
+        // Add it to the grid
+        if (!this._gridRow || this._gridRow.get_children().length == POPUP_NUM_COLUMNS) {
+            this._gridRow = new Big.Box({ spacing: POPUP_GRID_SPACING,
+                                          orientation: Big.BoxOrientation.HORIZONTAL });
+            this._grid.append(this._gridRow, Big.BoxPackFlags.NONE);
+        }
+        this._gridRow.append(item.box, Big.BoxPackFlags.NONE);
+    },
+
+    show : function(initialSelection) {
+	let global = Shell.Global.get();
+
+        Main.startModal();
+
+        global.window_group.add_actor(this._overlay);
+        this._overlay.raise_top();
+        this._overlay.show();
+
+	this.actor.show_all();
+        this.actor.x = (global.screen_width - this.actor.width) / 2;
+        this.actor.y = (global.screen_height - this.actor.height) / 2;
+
+        this.select(initialSelection);
+    },
+
+    destroy : function() {
+	this.actor.hide();
+        this._overlay.hide();
+        this._overlay.unparent();
+
+        Main.endModal();
+    },
+
+    select : function(n) {
+        if (this._selected) {
+            // Unselect previous
+
+            if (this._allocationChangedId) {
+                this._selected.box.disconnect(this._allocationChangedId);
+                delete this._allocationChangedId;
+            }
+
+            if (this._selected.above)
+                this._selected.window.raise(this._selected.above);
+            else
+                this._selected.window.lower_bottom();
+        }
+
+        let item = this._items[n];
+        let changed = this._selected && item != this._selected;
+        this._selected = item;
+
+        if (this._selected) {
+            this._label.set_size(-1, -1);
+            this._label.text = this._selected.metaWindow.title;
+            if (this._label.width > POPUP_LABEL_MAX_WIDTH)
+                this._label.width = POPUP_LABEL_MAX_WIDTH;
+
+            // Figure out this._selected.box's coordinates in terms of
+            // this.actor
+            let bx = this._selected.box.x, by = this._selected.box.y;
+            let actor = this._selected.box.get_parent();
+            while (actor != this.actor) {
+                bx += actor.x;
+                by += actor.y;
+                actor = actor.get_parent();
+            }
+
+            if (changed) {
+                Tweener.addTween(this._indicator,
+                                 { x: bx,
+                                   y: by,
+                                   width: this._selected.box.width,
+                                   height: this._selected.box.height,
+                                   time: Overlay.ANIMATION_TIME });
+            } else {
+                Tweener.removeTweens(this.indicator);
+                this._indicator.set_position(bx, by);
+                this._indicator.set_size(this._selected.box.width,
+                                         this._selected.box.height);
+            }
+            this._indicator.show();
+
+            if (this._overlay.visible)
+                this._selected.window.raise(this._overlay);
+
+            this._allocationChangedId =
+                this._selected.box.connect('notify::allocation',
+                                           Lang.bind(this, this._allocationChanged));
+        } else {
+            this._label.text = "";
+            this._indicator.hide();
+        }
+    },
+
+    _allocationChanged : function() {
+        if (this._selected)
+            this.select(this._selected.n);
+    }
+};
diff --git a/js/ui/windowManager.js b/js/ui/windowManager.js
index 2568e6a..8908cbb 100644
--- a/js/ui/windowManager.js
+++ b/js/ui/windowManager.js
@@ -5,6 +5,7 @@ const Mainloop = imports.mainloop;
 const Meta = imports.gi.Meta;
 const Shell = imports.gi.Shell;
 
+const AltTab = imports.ui.altTab;
 const Main = imports.ui.main;
 const Tweener = imports.ui.tweener;
 
@@ -77,6 +78,11 @@ WindowManager.prototype = {
             function(o, actor) {
                 me._destroyWindowDone(actor);
             });
+
+        this._shellwm.connect('begin-alt-tab',
+            function(o, handler) {
+                me._beginAltTab(handler);
+            });
     },
 
     _shouldAnimate : function(actor) {
@@ -365,6 +371,14 @@ WindowManager.prototype = {
         switchData.outGroup.destroy();
 
         this._shellwm.completed_switch_workspace();
-    }
+    },
+
+    _beginAltTab : function(handler) {
+        let popup = 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); });
+    }  
 };
diff --git a/src/Makefile.am b/src/Makefile.am
index 7c53080..ac49049 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -49,6 +49,8 @@ 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-alttab.c b/src/shell-alttab.c
new file mode 100644
index 0000000..0924f31
--- /dev/null
+++ b/src/shell-alttab.c
@@ -0,0 +1,230 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+
+#include "shell-alttab.h"
+#include "shell-global.h"
+#include "shell-wm.h"
+#include <mutter-plugin.h>
+
+/* Our MetaAltTabHandler implementation; ideally we would implement
+ * this directly from JavaScript, but for now we can't. So we register
+ * this glue class as our MetaAltTabHandler and then when mutter
+ * creates one, we pass it on to ShellWM, which emits a signal to hand
+ * it off to javascript code, which then connects to the signals on
+ * this object.
+ */
+
+static void shell_alt_tab_handler_interface_init (MetaAltTabHandlerInterface *handler_iface);
+
+G_DEFINE_TYPE_WITH_CODE (ShellAltTabHandler, shell_alt_tab_handler, G_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (META_TYPE_ALT_TAB_HANDLER,
+                                                shell_alt_tab_handler_interface_init))
+
+/* Signals */
+enum
+{
+  WINDOW_ADDED,
+  SHOW,
+  DESTROY,
+
+  LAST_SIGNAL
+};
+static guint signals [LAST_SIGNAL] = { 0 };
+
+enum 
+{
+  PROP_SELECTED = 1,
+  PROP_SCREEN,
+  PROP_IMMEDIATE
+};
+
+static void
+shell_alt_tab_handler_init (ShellAltTabHandler *sth)
+{
+  sth->windows = g_ptr_array_new ();
+  sth->selected = -1;
+}
+
+static void
+shell_alt_tab_handler_constructed (GObject *object)
+{
+  ShellGlobal *global = shell_global_get ();
+  ShellWM *wm;
+
+  g_object_get (G_OBJECT (global), "window-manager", &wm, NULL);
+  _shell_wm_begin_alt_tab (wm, SHELL_ALT_TAB_HANDLER (object));
+  g_object_unref (wm);
+}
+
+static void
+shell_alt_tab_handler_set_property (GObject      *object,
+                                    guint         prop_id,
+                                    const GValue *value,
+                                    GParamSpec   *pspec)
+{
+  ShellAltTabHandler *sth = SHELL_ALT_TAB_HANDLER (object);
+
+  switch (prop_id)
+    {
+    case PROP_SCREEN:
+      /* We don't care */
+      break;
+    case PROP_IMMEDIATE:
+      sth->immediate_mode = g_value_get_boolean (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+shell_alt_tab_handler_get_property (GObject      *object,
+                                    guint         prop_id,
+                                    GValue       *value,
+                                    GParamSpec   *pspec)
+{
+  ShellAltTabHandler *sth = SHELL_ALT_TAB_HANDLER (object);
+
+  switch (prop_id)
+    {
+    case PROP_SELECTED:
+      g_value_set_int (value, sth->selected);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+shell_alt_tab_handler_finalize (GObject *object)
+{
+  ShellAltTabHandler *sth = SHELL_ALT_TAB_HANDLER (object);
+
+  g_ptr_array_free (sth->windows, FALSE);
+
+  G_OBJECT_CLASS (shell_alt_tab_handler_parent_class)->finalize (object);
+}
+
+static void
+shell_alt_tab_handler_add_window (MetaAltTabHandler *handler,
+				  MetaWindow        *window)
+{
+  ShellAltTabHandler *sth = SHELL_ALT_TAB_HANDLER (handler);
+
+  g_ptr_array_add (sth->windows, window);
+  g_signal_emit (handler, signals[WINDOW_ADDED], 0,
+                 meta_window_get_compositor_private (window));
+}
+
+static void
+shell_alt_tab_handler_show (MetaAltTabHandler *handler,
+                            MetaWindow        *initial_selection)
+{
+  ShellAltTabHandler *sth = SHELL_ALT_TAB_HANDLER (handler);
+  int i;
+
+  sth->selected = -1;
+  for (i = 0; i < sth->windows->len; i++)
+    {
+      if (sth->windows->pdata[i] == (gpointer)initial_selection)
+        {
+          sth->selected = i;
+          break;
+        }
+    }
+
+  g_signal_emit (handler, signals[SHOW], 0, sth->selected);
+}
+
+static void
+shell_alt_tab_handler_destroy (MetaAltTabHandler *handler)
+{
+  g_signal_emit (handler, signals[DESTROY], 0);
+}
+
+static void
+shell_alt_tab_handler_forward (MetaAltTabHandler *handler)
+{
+  ShellAltTabHandler *sth = SHELL_ALT_TAB_HANDLER (handler);
+
+  sth->selected = (sth->selected + 1) % sth->windows->len;
+  g_object_notify (G_OBJECT (handler), "selected");
+}
+
+static void
+shell_alt_tab_handler_backward (MetaAltTabHandler *handler)
+{
+  ShellAltTabHandler *sth = SHELL_ALT_TAB_HANDLER (handler);
+
+  sth->selected = (sth->selected - 1) % sth->windows->len;
+  g_object_notify (G_OBJECT (handler), "selected");
+}
+
+static MetaWindow *
+shell_alt_tab_handler_get_selected (MetaAltTabHandler *handler)
+{
+  ShellAltTabHandler *sth = SHELL_ALT_TAB_HANDLER (handler);
+
+  if (sth->selected > -1)
+    return sth->windows->pdata[sth->selected];
+  else
+    return NULL;
+}
+
+static void
+shell_alt_tab_handler_class_init (ShellAltTabHandlerClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->constructed  = shell_alt_tab_handler_constructed;
+  object_class->set_property = shell_alt_tab_handler_set_property;
+  object_class->get_property = shell_alt_tab_handler_get_property;
+  object_class->finalize     = shell_alt_tab_handler_finalize;
+
+  g_object_class_override_property (object_class, PROP_SCREEN, "screen");
+  g_object_class_override_property (object_class, PROP_IMMEDIATE, "immediate");
+  g_object_class_install_property (object_class,
+                                   PROP_SELECTED,
+                                   g_param_spec_int ("selected",
+                                                     "Selected",
+                                                     "Selected window",
+                                                     -1, G_MAXINT, -1,
+                                                     G_PARAM_READABLE));
+
+
+  signals[WINDOW_ADDED] = g_signal_new ("window-added",
+                                        G_TYPE_FROM_CLASS (klass),
+                                        G_SIGNAL_RUN_LAST,
+                                        0,
+                                        NULL, NULL,
+                                        g_cclosure_marshal_VOID__OBJECT,
+                                        G_TYPE_NONE, 1,
+                                        MUTTER_TYPE_COMP_WINDOW);
+  signals[SHOW] = g_signal_new ("show",
+                                G_TYPE_FROM_CLASS (klass),
+                                G_SIGNAL_RUN_LAST,
+                                0,
+                                NULL, NULL,
+                                g_cclosure_marshal_VOID__INT,
+                                G_TYPE_NONE, 1,
+                                G_TYPE_INT);
+  signals[DESTROY] = g_signal_new ("destroy",
+                                   G_TYPE_FROM_CLASS (klass),
+                                   G_SIGNAL_RUN_LAST,
+                                   0,
+                                   NULL, NULL,
+                                   g_cclosure_marshal_VOID__VOID,
+                                   G_TYPE_NONE, 0);
+}
+
+static void
+shell_alt_tab_handler_interface_init (MetaAltTabHandlerInterface *handler_iface)
+{
+  handler_iface->add_window   = shell_alt_tab_handler_add_window;
+  handler_iface->show         = shell_alt_tab_handler_show;
+  handler_iface->destroy      = shell_alt_tab_handler_destroy;
+  handler_iface->forward      = shell_alt_tab_handler_forward;
+  handler_iface->backward     = shell_alt_tab_handler_backward;
+  handler_iface->get_selected = shell_alt_tab_handler_get_selected;
+}
diff --git a/src/shell-alttab.h b/src/shell-alttab.h
new file mode 100644
index 0000000..4e04b3b
--- /dev/null
+++ b/src/shell-alttab.h
@@ -0,0 +1,34 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+
+#ifndef SHELL_ALT_TAB_HANDLER_H
+#define SHELL_ALT_TAB_HANDLER_H
+
+#include <alttabhandler.h>
+
+#define SHELL_TYPE_ALT_TAB_HANDLER            (shell_alt_tab_handler_get_type ())
+#define SHELL_ALT_TAB_HANDLER(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), SHELL_TYPE_ALT_TAB_HANDLER, ShellAltTabHandler))
+#define SHELL_ALT_TAB_HANDLER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  SHELL_TYPE_ALT_TAB_HANDLER, ShellAltTabHandlerClass))
+#define SHELL_IS_ALT_TAB_HANDLER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SHELL_ALT_TAB_HANDLER_TYPE))
+#define SHELL_IS_ALT_TAB_HANDLER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  SHELL_TYPE_ALT_TAB_HANDLER))
+#define SHELL_ALT_TAB_HANDLER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  SHELL_TYPE_ALT_TAB_HANDLER, ShellAltTabHandlerClass))
+
+typedef struct _ShellAltTabHandler      ShellAltTabHandler;
+typedef struct _ShellAltTabHandlerClass ShellAltTabHandlerClass;
+
+struct _ShellAltTabHandler {
+  GObject parent_instance;
+
+  GPtrArray *windows;
+  int selected;
+  gboolean immediate_mode;
+};
+
+struct _ShellAltTabHandlerClass {
+  GObjectClass parent_class;
+
+};
+
+GType              shell_alt_tab_handler_get_type     (void);
+
+#endif
+
diff --git a/src/shell-wm.c b/src/shell-wm.c
index 7b77a04..42ec233 100644
--- a/src/shell-wm.c
+++ b/src/shell-wm.c
@@ -27,6 +27,8 @@ enum
   SWITCH_WORKSPACE,
   KILL_SWITCH_WORKSPACE,
 
+  BEGIN_ALT_TAB,
+
   LAST_SIGNAL
 };
 
@@ -40,6 +42,7 @@ 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
@@ -166,6 +169,15 @@ 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",
+		  G_TYPE_FROM_CLASS (klass),
+		  G_SIGNAL_RUN_LAST,
+		  0,
+		  NULL, NULL,
+		  g_cclosure_marshal_VOID__OBJECT,
+		  G_TYPE_NONE, 1,
+                  META_TYPE_ALT_TAB_HANDLER);
 }
 
 void
@@ -379,6 +391,14 @@ _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
diff --git a/src/shell-wm.h b/src/shell-wm.h
index f5b349f..59387cf 100644
--- a/src/shell-wm.h
+++ b/src/shell-wm.h
@@ -4,6 +4,8 @@
 #include <glib-object.h>
 #include <mutter-plugin.h>
 
+#include "shell-alttab.h"
+
 G_BEGIN_DECLS
 
 typedef struct _ShellWM      ShellWM;
@@ -71,6 +73,11 @@ void _shell_wm_kill_effect      (ShellWM              *wm,
 				 MutterWindow         *actor,
 				 gulong                events);
 
+/* Called by ShellAltTabHandler */
+
+void _shell_wm_begin_alt_tab    (ShellWM              *wm,
+				 ShellAltTabHandler   *handler);
+
 G_END_DECLS
 
 #endif /* __SHELL_WM_H__ */



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