From 7dba934b961f676561841e65ee40e603f748e5ea Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Fri, 21 Nov 2008 14:02:09 +0000 Subject: [PATCH] add the initial framework of a window management interface. #561724 svn path=/trunk/; revision=70 --- js/ui/main.js | 6 +- js/ui/windowmanager.js | 29 ++++++ src/Makefile.am | 34 ++++++- src/gnome-shell-plugin.c | 7 +- src/shell-global.c | 33 ++++++- src/shell-global.h | 4 +- src/shell-marshal.list | 1 + src/shell-wm.c | 194 +++++++++++++++++++++++++++++++++++++++ src/shell-wm.h | 33 +++++++ 9 files changed, 335 insertions(+), 6 deletions(-) create mode 100644 js/ui/windowmanager.js create mode 100644 src/shell-marshal.list create mode 100644 src/shell-wm.c create mode 100644 src/shell-wm.h diff --git a/js/ui/main.js b/js/ui/main.js index 5b21ea41b..6b394e8e4 100644 --- a/js/ui/main.js +++ b/js/ui/main.js @@ -6,6 +6,7 @@ const Clutter = imports.gi.Clutter; const Panel = imports.ui.panel; const Overlay = imports.ui.overlay; const RunDialog = imports.ui.run_dialog; +const WindowManager = imports.ui.windowmanager; const DEFAULT_BACKGROUND_COLOR = new Clutter.Color(); DEFAULT_BACKGROUND_COLOR.from_pixel(0x2266bbff); @@ -13,6 +14,7 @@ DEFAULT_BACKGROUND_COLOR.from_pixel(0x2266bbff); let panel = null; let overlay = null; let run_dialog = null; +let wm = null; function start() { let global = Shell.global_get(); @@ -43,8 +45,10 @@ function start() { }); panel = new Panel.Panel(); - overlay = new Overlay.Overlay(); global.set_stage_input_area(0, 0, global.screen_width, Panel.PANEL_HEIGHT); + + overlay = new Overlay.Overlay(); + wm = new WindowManager.WindowManager(); } function show_overlay() { diff --git a/js/ui/windowmanager.js b/js/ui/windowmanager.js new file mode 100644 index 000000000..b8d8a6d05 --- /dev/null +++ b/js/ui/windowmanager.js @@ -0,0 +1,29 @@ +/* -*- mode: js2; js2-basic-offset: 4; -*- */ + +const Clutter = imports.gi.Clutter; +const Mainloop = imports.mainloop; +const Shell = imports.gi.Shell; + +const Main = imports.ui.main; + +function WindowManager(shellwm) { + this._init(shellwm); +} + +WindowManager.prototype = { + _init : function(shellwm) { + let global = Shell.global_get(); + let shellwm = global.window_manager; + + shellwm.connect('switch-workspace', + function(o, from, to, direction) { + let actors = shellwm.get_switch_workspace_actors(); + for (let i = 0; i < actors.length; i++) { + if (actors[i].get_workspace() == from) + actors[i].hide(); + else if (actors[i].get_workspace() == to) + actors[i].show(); + } + }); + } +}; diff --git a/src/Makefile.am b/src/Makefile.am index 3f0a53dad..3098f9cad 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -13,7 +13,17 @@ gnome_shell_cflags = \ plugindir = $(libdir)/metacity/plugins/clutter plugin_LTLIBRARIES = libgnome-shell.la +shell_built_sources = \ + shell-marshal.h \ + shell-marshal.c + +BUILT_SOURCES += $(shell_built_sources) + +SHELL_STAMP_FILES = stamp-shell-marshal.h +CLEANFILES += $(SHELL_STAMP_FILES) + libgnome_shell_la_SOURCES = \ + $(shell_built_sources) \ gnome-shell-plugin.c \ shell-app-monitor.c \ shell-app-monitor.h \ @@ -22,7 +32,29 @@ libgnome_shell_la_SOURCES = \ shell-global.c \ shell-global.h \ shell-tray-manager.c \ - shell-tray-manager.h + shell-tray-manager.h \ + shell-wm.c \ + shell-wm.h + +shell-marshal.h: stamp-shell-marshal.h + @true +stamp-shell-marshal.h: Makefile shell-marshal.list + $(GLIB_GENMARSHAL) \ + --prefix=_shell_marshal \ + --header \ + $(srcdir)/shell-marshal.list > xgen-tmh && \ + (cmp -s xgen-tmh shell-marshal.h || cp -f xgen-tmh shell-marshal.h) && \ + rm -f xgen-tmh && \ + echo timestamp > $(@F) + +shell-marshal.c: Makefile shell-marshal.list + (echo "#include \"shell-marshal.h\"" ; \ + $(GLIB_GENMARSHAL) \ + --prefix=_shell_marshal \ + --body \ + $(srcdir)/shell-marshal.list ) > xgen-tmc && \ + cp -f xgen-tmc shell-marshal.c && \ + rm -f xgen-tmc libgnome_shell_la_LDFLAGS = -avoid-version -module libgnome_shell_la_LIBADD = \ diff --git a/src/gnome-shell-plugin.c b/src/gnome-shell-plugin.c index 861776ba6..edc2aa7de 100644 --- a/src/gnome-shell-plugin.c +++ b/src/gnome-shell-plugin.c @@ -84,6 +84,11 @@ g_module_check_init (GModule *module) /* Event handling */ plugin->xevent_filter = xevent_filter; + /* This will also create the ShellWM, which will set the appropriate + * window management callbacks in plugin. + */ + _shell_global_set_plugin (shell_global_get(), plugin); + return NULL; } @@ -125,8 +130,6 @@ do_init (const char *params) plugin_state->gjs_context = gjs_context_new_with_search_path(search_path); g_strfreev(search_path); - _shell_global_set_plugin (shell_global_get(), plugin); - plugin_state->panel_action = XInternAtom (meta_display_get_xdisplay (display), "_GNOME_PANEL_ACTION", FALSE); plugin_state->panel_action_run_dialog = XInternAtom (meta_display_get_xdisplay (display), diff --git a/src/shell-global.c b/src/shell-global.c index 0ae6372a3..7f49cd5fb 100644 --- a/src/shell-global.c +++ b/src/shell-global.c @@ -1,6 +1,7 @@ /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ #include "shell-global.h" +#include "shell-wm.h" #include "display.h" #include @@ -9,6 +10,7 @@ struct _ShellGlobal { GObject parent; MutterPlugin *plugin; + ShellWM *wm; }; enum { @@ -19,7 +21,8 @@ enum { PROP_SCREEN_WIDTH, PROP_SCREEN_HEIGHT, PROP_STAGE, - PROP_WINDOW_GROUP + PROP_WINDOW_GROUP, + PROP_WINDOW_MANAGER }; /* Signals */ @@ -86,6 +89,9 @@ shell_global_get_property(GObject *object, case PROP_WINDOW_GROUP: g_value_set_object (value, mutter_plugin_get_window_group (global->plugin)); break; + case PROP_WINDOW_MANAGER: + g_value_set_object (value, global->wm); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -166,6 +172,13 @@ shell_global_class_init (ShellGlobalClass *klass) "Actor holding window actors", CLUTTER_TYPE_ACTOR, G_PARAM_READABLE)); + g_object_class_install_property (gobject_class, + PROP_WINDOW_MANAGER, + g_param_spec_object ("window-manager", + "Window Manager", + "Window management interface", + SHELL_TYPE_WM, + G_PARAM_READABLE)); } /** @@ -253,8 +266,10 @@ _shell_global_set_plugin (ShellGlobal *global, MutterPlugin *plugin) { g_return_if_fail (SHELL_IS_GLOBAL (global)); + g_return_if_fail (global->plugin == NULL); global->plugin = plugin; + global->wm = shell_wm_new (plugin); } /** @@ -274,3 +289,19 @@ shell_global_focus_stage (ShellGlobal *global) Window stagewin = clutter_x11_get_stage_window (stage); XSetInputFocus (xdisplay, stagewin, RevertToParent, CurrentTime); } + +ClutterActor * +shell_global_get_overlay_group (ShellGlobal *global) +{ + g_return_val_if_fail (SHELL_IS_GLOBAL (global), NULL); + + return mutter_plugin_get_overlay_group (global->plugin); +} + +ClutterActor * +shell_global_get_window_group (ShellGlobal *global) +{ + g_return_val_if_fail (SHELL_IS_GLOBAL (global), NULL); + + return mutter_plugin_get_window_group (global->plugin); +} diff --git a/src/shell-global.h b/src/shell-global.h index d85796234..83de63438 100644 --- a/src/shell-global.h +++ b/src/shell-global.h @@ -42,7 +42,9 @@ void shell_global_set_stage_input_area (ShellGlobal *global, int width, int height); -GList *shell_global_get_windows (ShellGlobal *global); +GList *shell_global_get_windows (ShellGlobal *global); +ClutterActor *shell_global_get_window_group (ShellGlobal *global); +ClutterActor *shell_global_get_overlay_group (ShellGlobal *global); void _shell_global_set_plugin (ShellGlobal *global, MutterPlugin *plugin); diff --git a/src/shell-marshal.list b/src/shell-marshal.list new file mode 100644 index 000000000..11ef833a0 --- /dev/null +++ b/src/shell-marshal.list @@ -0,0 +1 @@ +VOID:INT,INT,INT diff --git a/src/shell-wm.c b/src/shell-wm.c new file mode 100644 index 000000000..a7d2b3ca8 --- /dev/null +++ b/src/shell-wm.c @@ -0,0 +1,194 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +#include "shell-wm.h" +#include "shell-global.h" +#include "shell-marshal.h" + +struct _ShellWM { + GObject parent; + + GList *switch_workspace_actors; +}; + +/* Signals */ +enum +{ +#ifdef NOT_YET + MINIMIZE, + KILL_MINIMIZE, + MAXIMIZE, + KILL_MAXIMIZE, + UNMAXIMIZE, + KILL_UNMAXIMIZE, + MAP, + KILL_MAP, + DESTROY, + KILL_DESTROY, +#endif + SWITCH_WORKSPACE, + KILL_SWITCH_WORKSPACE, + + LAST_SIGNAL +}; + +G_DEFINE_TYPE(ShellWM, shell_wm, G_TYPE_OBJECT); + +static void shell_wm_set_switch_workspace_actors (ShellWM *wm, + GList *actors); + +static guint shell_wm_signals [LAST_SIGNAL] = { 0 }; + +static void +shell_wm_init (ShellWM *wm) +{ +} + +static void +shell_wm_finalize (GObject *object) +{ + ShellWM *wm = SHELL_WM (object); + + shell_wm_set_switch_workspace_actors (wm, NULL); + + G_OBJECT_CLASS (shell_wm_parent_class)->finalize (object); +} + +static void +shell_wm_class_init (ShellWMClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->finalize = shell_wm_finalize; + + shell_wm_signals[SWITCH_WORKSPACE] = + g_signal_new ("switch-workspace", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + _shell_marshal_VOID__INT_INT_INT, + G_TYPE_NONE, 3, + G_TYPE_INT, G_TYPE_INT, G_TYPE_INT); + shell_wm_signals[KILL_SWITCH_WORKSPACE] = + g_signal_new ("kill-switch-workspace", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); +} + +static ShellWM * +shell_wm_get (void) +{ + ShellWM *wm; + + g_object_get (shell_global_get (), + "window-manager", &wm, + NULL); + /* drop extra ref added by g_object_get */ + g_object_unref (wm); + + return wm; +} + +static void +shell_wm_switch_workspace (const GList **actors, + gint from, + gint to, + MetaMotionDirection direction) +{ + ShellWM *wm = shell_wm_get (); + + shell_wm_set_switch_workspace_actors (wm, (GList *)*actors); + g_signal_emit (wm, shell_wm_signals[SWITCH_WORKSPACE], 0, + from, to, direction); + shell_wm_set_switch_workspace_actors (wm, NULL); +} + +static void +shell_wm_kill_effect (MutterWindow *actor, + gulong events) +{ + ShellWM *wm = shell_wm_get (); + +#ifdef NOT_YET + if (events & MUTTER_PLUGIN_MINIMIZE) + g_signal_emit (wm, shell_wm_signals[KILL_MINIMIZE], 0); + if (events & MUTTER_PLUGIN_MAXIMIZE) + g_signal_emit (wm, shell_wm_signals[KILL_MAXIMIZE], 0); + if (events & MUTTER_PLUGIN_UNMAXIMIZE) + g_signal_emit (wm, shell_wm_signals[KILL_UNMAXIMIZE], 0); + if (events & MUTTER_PLUGIN_MAP) + g_signal_emit (wm, shell_wm_signals[KILL_MAP], 0); + if (events & MUTTER_PLUGIN_DESTROY) + g_signal_emit (wm, shell_wm_signals[KILL_DESTROY], 0); +#endif + if (events & MUTTER_PLUGIN_SWITCH_WORKSPACE) + g_signal_emit (wm, shell_wm_signals[KILL_SWITCH_WORKSPACE], 0); +} + + +/** + * shell_wm_new: + * @plugin: the #MutterPlugin + * + * Creates a new window management interface by hooking into @plugin. + * + * Return value: the new window-management interface + **/ +ShellWM * +shell_wm_new (MutterPlugin *plugin) +{ +#ifdef NOT_YET + plugin->minimize = shell_wm_minimize; + plugin->maximize = shell_wm_maximize; + plugin->unmaximize = shell_wm_unmaximize; + plugin->map = shell_wm_map; + plugin->destroy = shell_wm_destroy; +#endif + plugin->switch_workspace = shell_wm_switch_workspace; + plugin->kill_effect = shell_wm_kill_effect; + + return g_object_new (SHELL_TYPE_WM, NULL); +} + +/** + * shell_wm_get_switch_workspace_actors: + * @wm: the #ShellWM + * + * A workaround for a missing feature in gobject-introspection. Returns + * the list of windows involved in a switch-workspace operation (which + * cannot be passed directly to the signal handler because there's no + * way to annotate the element-type of a signal parameter.) + * + * You must call this from the #ShellWM::switch-workspace signal + * handler itself; if you need the value again later, you must save a + * copy yourself. + * + * Return value: (element-type MutterWindow) (transfer full): the list + * of windows + **/ +GList * +shell_wm_get_switch_workspace_actors (ShellWM *wm) +{ + GList *l; + + for (l = wm->switch_workspace_actors; l; l = l->next) + g_object_ref (l->data); + return g_list_copy (wm->switch_workspace_actors); +} + +static void +shell_wm_set_switch_workspace_actors (ShellWM *wm, GList *actors) +{ + const GList *l; + + for (l = wm->switch_workspace_actors; l; l = l->next) + g_object_unref (l->data); + g_list_free (wm->switch_workspace_actors); + wm->switch_workspace_actors = g_list_copy (actors); + for (l = wm->switch_workspace_actors; l; l = l->next) + g_object_ref (l->data); +} diff --git a/src/shell-wm.h b/src/shell-wm.h new file mode 100644 index 000000000..54d81a32e --- /dev/null +++ b/src/shell-wm.h @@ -0,0 +1,33 @@ +#ifndef __SHELL_WM_H__ +#define __SHELL_WM_H__ + +#include +#include + +G_BEGIN_DECLS + +typedef struct _ShellWM ShellWM; +typedef struct _ShellWMClass ShellWMClass; + +#define SHELL_TYPE_WM (shell_wm_get_type ()) +#define SHELL_WM(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), SHELL_TYPE_WM, ShellWM)) +#define SHELL_WM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SHELL_TYPE_WM, ShellWMClass)) +#define SHELL_IS_WM(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), SHELL_TYPE_WM)) +#define SHELL_IS_WM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SHELL_TYPE_WM)) +#define SHELL_WM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SHELL_TYPE_WM, ShellWMClass)) + +struct _ShellWMClass +{ + GObjectClass parent_class; + +}; + +GType shell_wm_get_type (void) G_GNUC_CONST; + +ShellWM *shell_wm_new (MutterPlugin *plugin); + +GList *shell_wm_get_switch_workspace_actors (ShellWM *wm); + +G_END_DECLS + +#endif /* __SHELL_WM_H__ */