diff --git a/src/compositor/clutter/compositor-clutter-plugin-manager.c b/src/compositor/clutter/compositor-clutter-plugin-manager.c new file mode 100644 index 000000000..2ff044a66 --- /dev/null +++ b/src/compositor/clutter/compositor-clutter-plugin-manager.c @@ -0,0 +1,780 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (c) 2008 Intel Corp. + * + * Author: Tomas Frydrych + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include "compositor-clutter-plugin-manager.h" +#include "compositor-clutter.h" +#include "prefs.h" +#include "errors.h" +#include "workspace.h" + +#include +#include +#include +#include +#include +#include + +static gboolean meta_compositor_clutter_plugin_manager_reload (MetaCompositorClutterPluginManager *mgr); + +struct MetaCompositorClutterPluginManager +{ + MetaScreen *screen; + + GList *plugins; /* TODO -- maybe use hash table */ + GList *unload; /* Plugins that are disabled and pending unload */ + + guint idle_unload_id; +}; + +typedef struct MetaCompositorClutterPluginPrivate MetaCompositorClutterPluginPrivate; + +struct MetaCompositorClutterPluginPrivate +{ + MetaCompositorClutterPluginManager *self; + GModule *module; + + gboolean disabled : 1; +}; + + +static void +free_plugin_workspaces (MetaCompositorClutterPlugin *plg) +{ + GList *l; + + l = plg->work_areas; + + while (l) + { + g_free (l->data); + l = l->next; + } + + if (plg->work_areas) + g_list_free (plg->work_areas); + + plg->work_areas = NULL; +} + +/* + * Gets work area geometry and stores it in list in the plugin. + * + * If the plg list is already populated, we simply replace it (we are dealing + * with a small number of items in the list and unfrequent changes). + */ +static void +update_plugin_workspaces (MetaScreen *screen, + MetaCompositorClutterPlugin *plg) +{ + GList *l, *l2 = NULL; + + l = meta_screen_get_workspaces (screen); + + while (l) + { + MetaWorkspace *w = l->data; + PluginWorkspaceRectangle *r; + + r = g_new0 (PluginWorkspaceRectangle, 1); + + meta_workspace_get_work_area_all_xineramas (w, (MetaRectangle*)r); + + l2 = g_list_append (l2, r); + + l = l->next; + } + + free_plugin_workspaces (plg); + + plg->work_areas = l2; +} + +/* + * Checks that the plugin is compatible with the WM and sets up the plugin + * struct. + */ +static MetaCompositorClutterPlugin * +meta_compositor_clutter_plugin_load (MetaCompositorClutterPluginManager *mgr, + GModule *module, + const gchar *params) +{ + MetaCompositorClutterPlugin *plg; + + if (g_module_symbol (module, + META_COMPOSITOR_CLUTTER_PLUGIN_STRUCT_NAME, + (gpointer *)&plg)) + { + if (plg->version_api == METACITY_CLUTTER_PLUGIN_API_VERSION) + { + MetaCompositorClutterPluginPrivate *priv; + gboolean (*init_func) (void); + + priv = g_new0 (MetaCompositorClutterPluginPrivate, 1); + plg->params = g_strdup (params); + plg->manager_private = priv; + priv->module = module; + priv->self = mgr; + + meta_screen_get_size (mgr->screen, + &plg->screen_width, &plg->screen_height); + + update_plugin_workspaces (mgr->screen, plg); + + /* + * Check for and run the plugin init function. + */ + if (g_module_symbol (module, + META_COMPOSITOR_CLUTTER_PLUGIN_INIT_FUNC_NAME, + (gpointer *)&init_func) && + !init_func()) + { + g_free (plg->params); + g_free (priv); + + free_plugin_workspaces (plg); + + return NULL; + } + + meta_verbose ("Loaded plugin [%s]\n", plg->name); + + return plg; + } + } + + return NULL; +} + +/* + * Attempst to unload a plugin; returns FALSE if plugin cannot be unloaded at + * present (e.g., and effect is in progress) and should be scheduled for + * removal later. + */ +static gboolean +meta_compositor_clutter_plugin_unload (MetaCompositorClutterPlugin *plg) +{ + MetaCompositorClutterPluginPrivate *priv; + GModule *module; + + priv = plg->manager_private; + module = priv->module; + + if (plg->running) + { + priv->disabled = TRUE; + return FALSE; + } + + g_free (plg->params); + plg->params = NULL; + + g_free (priv); + plg->manager_private = NULL; + + g_module_close (module); + + return TRUE; +} + +/* + * Iddle callback to remove plugins that could not be removed directly and are + * pending for removal. + */ +static gboolean +meta_compositor_clutter_plugin_manager_idle_unload (MetaCompositorClutterPluginManager *mgr) +{ + GList *l = mgr->unload; + gboolean dont_remove = TRUE; + + while (l) + { + MetaCompositorClutterPlugin *plg = l->data; + + if (meta_compositor_clutter_plugin_unload (plg)) + { + /* Remove from list */ + GList *p = l->prev; + GList *n = l->next; + + if (!p) + mgr->unload = n; + else + p->next = n; + + if (n) + n->prev = p; + + g_list_free_1 (l); + + l = n; + } + else + l = l->next; + } + + if (!mgr->unload) + { + /* If no more unloads are pending, remove the handler as well */ + dont_remove = FALSE; + mgr->idle_unload_id = 0; + } + + return dont_remove; +} + +/* + * Unloads all plugins + */ +static void +meta_compositor_clutter_plugin_manager_unload (MetaCompositorClutterPluginManager *mgr) +{ + GList *plugins = mgr->plugins; + + while (plugins) + { + MetaCompositorClutterPlugin *plg = plugins->data; + + /* If the plugin could not be removed, move it to the unload list */ + if (!meta_compositor_clutter_plugin_unload (plg)) + { + mgr->unload = g_list_prepend (mgr->unload, plg); + + if (!mgr->idle_unload_id) + { + mgr->idle_unload_id = g_idle_add ((GSourceFunc) + meta_compositor_clutter_plugin_manager_idle_unload, + mgr); + } + } + + plugins = plugins->next; + } + + g_list_free (mgr->plugins); + mgr->plugins = NULL; +} + +static void +prefs_changed_callback (MetaPreference pref, + void *data) +{ + MetaCompositorClutterPluginManager *mgr = data; + + if (pref == META_PREF_CLUTTER_PLUGINS) + { + meta_compositor_clutter_plugin_manager_reload (mgr); + } + else if (pref == META_PREF_NUM_WORKSPACES) + { + meta_compositor_clutter_plugin_manager_update_workspaces (mgr); + } +} + +/* + * Loads all plugins listed in gconf registry. + */ +static gboolean +meta_compositor_clutter_plugin_manager_load (MetaCompositorClutterPluginManager *mgr) +{ + const gchar *dpath = METACITY_PKGLIBDIR "/plugins/clutter/"; + GSList *plugins, *fallback = NULL; + + plugins = meta_prefs_get_clutter_plugins (); + + if (!plugins) + { + /* + * If no plugins are specified, try to load the default plugin. + */ + fallback = g_slist_append (fallback, "default"); + plugins = fallback; + } + + while (plugins) + { + gchar *plg_string; + gchar *params; + + plg_string = g_strdup (plugins->data); + + if (plg_string) + { + GModule *plg; + gchar *path; + + params = strchr (plg_string, ':'); + + if (params) + { + *params = 0; + ++params; + } + + path = g_strconcat (dpath, plg_string, ".so", NULL); + + if ((plg = g_module_open (path, 0))) + { + MetaCompositorClutterPlugin *p; + + if ((p = meta_compositor_clutter_plugin_load (mgr, + plg, params))) + mgr->plugins = g_list_prepend (mgr->plugins, p); + else + { + g_message ("Plugin load for [%s] failed\n", path); + g_module_close (plg); + } + } + else + g_message ("Unable to load plugin [%s]\n", path); + + g_free (path); + g_free (plg_string); + } + + plugins = plugins->next; + } + + + if (fallback) + g_slist_free (fallback); + + if (mgr->plugins != NULL) + { + meta_prefs_add_listener (prefs_changed_callback, mgr); + return TRUE; + } + + return FALSE; +} + +/* + * Reloads all plugins + */ +static gboolean +meta_compositor_clutter_plugin_manager_reload (MetaCompositorClutterPluginManager *mgr) +{ + /* TODO -- brute force; should we build a list of plugins to load and list of + * plugins to unload? We are probably not going to have large numbers of + * plugins loaded at the same time, so it might not be worth it. + */ + meta_compositor_clutter_plugin_manager_unload (mgr); + return meta_compositor_clutter_plugin_manager_load (mgr); +} + +static gboolean +meta_compositor_clutter_plugin_manager_init (MetaCompositorClutterPluginManager *mgr) +{ + return meta_compositor_clutter_plugin_manager_load (mgr); +} + +void +meta_compositor_clutter_plugin_manager_update_workspace (MetaCompositorClutterPluginManager *mgr, MetaWorkspace *w) +{ + GList *l; + gint n; + + n = meta_workspace_index (w); + l = mgr->plugins; + + while (l) + { + MetaCompositorClutterPlugin *plg = l->data; + PluginWorkspaceRectangle *r = g_list_nth_data (plg->work_areas, n); + + if (r) + { + meta_workspace_get_work_area_all_xineramas (w, (MetaRectangle*)r); + } + else + { + /* Something not entirely right; redo the whole thing */ + update_plugin_workspaces (mgr->screen, plg); + return; + } + + l = l->next; + } +} + +void +meta_compositor_clutter_plugin_manager_update_workspaces (MetaCompositorClutterPluginManager *mgr) +{ + GList *l; + + l = mgr->plugins; + while (l) + { + MetaCompositorClutterPlugin *plg = l->data; + + update_plugin_workspaces (mgr->screen, plg); + + l = l->next; + } +} + +MetaCompositorClutterPluginManager * +meta_compositor_clutter_plugin_manager_new (MetaScreen *screen) +{ + MetaCompositorClutterPluginManager *mgr; + + mgr = g_new0 (MetaCompositorClutterPluginManager, 1); + + mgr->screen = screen; + + if (!meta_compositor_clutter_plugin_manager_init (mgr)) + { + g_free (mgr); + mgr = NULL; + } + + return mgr; +} + +static void +meta_compositor_clutter_plugin_manager_kill_effect (MetaCompositorClutterPluginManager *mgr, + MetaCompWindow *actor, + unsigned long events) +{ + GList *l = mgr->plugins; + + while (l) + { + MetaCompositorClutterPlugin *plg = l->data; + MetaCompositorClutterPluginPrivate *priv = plg->manager_private; + + if (!priv->disabled && (plg->features & events) && plg->kill_effect) + plg->kill_effect (actor, events); + + l = l->next; + } +} + +#define ALL_BUT_SWITCH \ + META_COMPOSITOR_CLUTTER_PLUGIN_ALL_EFFECTS & \ + ~META_COMPOSITOR_CLUTTER_PLUGIN_SWITCH_WORKSPACE +/* + * Public method that the compositor hooks into for events that require + * no additional parameters. + * + * Returns TRUE if at least one of the plugins handled the event type (i.e., + * if the return value is FALSE, there will be no subsequent call to the + * manager completed() callback, and the compositor must ensure that any + * appropriate post-effect cleanup is carried out. + */ +gboolean +meta_compositor_clutter_plugin_manager_event_simple (MetaCompositorClutterPluginManager *mgr, + MetaCompWindow *actor, + unsigned long event) +{ + GList *l = mgr->plugins; + gboolean retval = FALSE; + + while (l) + { + MetaCompositorClutterPlugin *plg = l->data; + MetaCompositorClutterPluginPrivate *priv = plg->manager_private; + + if (!priv->disabled && (plg->features & event)) + { + retval = TRUE; + + switch (event) + { + case META_COMPOSITOR_CLUTTER_PLUGIN_MINIMIZE: + if (plg->minimize) + { + meta_compositor_clutter_plugin_manager_kill_effect (mgr, + actor, + ALL_BUT_SWITCH); + plg->minimize (actor); + } + break; + case META_COMPOSITOR_CLUTTER_PLUGIN_MAP: + if (plg->map) + { + meta_compositor_clutter_plugin_manager_kill_effect (mgr, + actor, + ALL_BUT_SWITCH); + plg->map (actor); + } + break; + case META_COMPOSITOR_CLUTTER_PLUGIN_DESTROY: + if (plg->destroy) + { + plg->destroy (actor); + } + break; + default: + g_warning ("Incorrect handler called for event %lu", event); + } + } + + l = l->next; + } + + return retval; +} + +/* + * The public method that the compositor hooks into for maximize and unmaximize + * events. + * + * Returns TRUE if at least one of the plugins handled the event type (i.e., + * if the return value is FALSE, there will be no subsequent call to the + * manager completed() callback, and the compositor must ensure that any + * appropriate post-effect cleanup is carried out. + */ +gboolean +meta_compositor_clutter_plugin_manager_event_maximize (MetaCompositorClutterPluginManager *mgr, + MetaCompWindow *actor, + unsigned long event, + gint target_x, + gint target_y, + gint target_width, + gint target_height) +{ + GList *l = mgr->plugins; + gboolean retval = FALSE; + + while (l) + { + MetaCompositorClutterPlugin *plg = l->data; + MetaCompositorClutterPluginPrivate *priv = plg->manager_private; + + if (!priv->disabled && (plg->features & event)) + { + retval = TRUE; + + switch (event) + { + case META_COMPOSITOR_CLUTTER_PLUGIN_MAXIMIZE: + if (plg->maximize) + { + meta_compositor_clutter_plugin_manager_kill_effect (mgr, + actor, + ALL_BUT_SWITCH); + plg->maximize (actor, + target_x, target_y, + target_width, target_height); + } + break; + case META_COMPOSITOR_CLUTTER_PLUGIN_UNMAXIMIZE: + if (plg->unmaximize) + { + meta_compositor_clutter_plugin_manager_kill_effect (mgr, + actor, + ALL_BUT_SWITCH); + plg->unmaximize (actor, + target_x, target_y, + target_width, target_height); + } + break; + default: + g_warning ("Incorrect handler called for event %lu", event); + } + } + + l = l->next; + } + + return retval; +} + +/* + * The public method that the compositor hooks into for desktop switching. + * + * Returns TRUE if at least one of the plugins handled the event type (i.e., + * if the return value is FALSE, there will be no subsequent call to the + * manager completed() callback, and the compositor must ensure that any + * appropriate post-effect cleanup is carried out. + */ +gboolean +meta_compositor_clutter_plugin_manager_switch_workspace (MetaCompositorClutterPluginManager *mgr, + const GList **actors, + gint from, + gint to, + MetaMotionDirection direction) +{ + GList *l = mgr->plugins; + gboolean retval = FALSE; + + while (l) + { + MetaCompositorClutterPlugin *plg = l->data; + MetaCompositorClutterPluginPrivate *priv = plg->manager_private; + + if (!priv->disabled && + (plg->features & META_COMPOSITOR_CLUTTER_PLUGIN_SWITCH_WORKSPACE) && + (actors && *actors)) + { + if (plg->switch_workspace) + { + retval = TRUE; + meta_compositor_clutter_plugin_manager_kill_effect (mgr, + META_COMP_WINDOW ((*actors)->data), + META_COMPOSITOR_CLUTTER_PLUGIN_SWITCH_WORKSPACE); + plg->switch_workspace (actors, from, to, direction); + } + } + + l = l->next; + } + + return retval; +} + +/* + * The public method that the compositor hooks into for desktop switching. + * + * Returns TRUE if at least one of the plugins handled the event type (i.e., + * if the return value is FALSE, there will be no subsequent call to the + * manager completed() callback, and the compositor must ensure that any + * appropriate post-effect cleanup is carried out. + */ +gboolean +meta_compositor_clutter_plugin_manager_xevent_filter + (MetaCompositorClutterPluginManager *mgr, XEvent *xev) +{ + GList *l; + + if (!mgr) + return FALSE; + + l = mgr->plugins; + + while (l) + { + MetaCompositorClutterPlugin *plg = l->data; + + if (plg->xevent_filter) + { + if (plg->xevent_filter (xev) == TRUE) + return TRUE; + } + + l = l->next; + } + + return FALSE; +} + +/* + * Public accessors for plugins, exposed from compositor-clutter-plugin.h + */ +ClutterActor * +meta_comp_clutter_plugin_get_overlay_group (MetaCompositorClutterPlugin *plugin) +{ + MetaCompositorClutterPluginPrivate *priv = plugin->manager_private; + MetaCompositorClutterPluginManager *mgr = priv->self; + + return meta_compositor_clutter_get_overlay_group_for_screen (mgr->screen); +} + +ClutterActor * +meta_comp_clutter_plugin_get_stage (MetaCompositorClutterPlugin *plugin) +{ + MetaCompositorClutterPluginPrivate *priv = plugin->manager_private; + MetaCompositorClutterPluginManager *mgr = priv->self; + + return meta_compositor_clutter_get_stage_for_screen (mgr->screen); +} + +void +meta_comp_clutter_plugin_effect_completed (MetaCompositorClutterPlugin *plugin, + MetaCompWindow *actor, + unsigned long event) +{ + if (!actor) + { + g_warning ("Plugin [%s] passed NULL for actor!", + (plugin && plugin->name) ? plugin->name : "unknown"); + } + + meta_compositor_clutter_window_effect_completed (actor, event); +} + + +void +meta_comp_clutter_plugin_set_stage_reactive (MetaCompositorClutterPlugin *plugin, + gboolean reactive) +{ + MetaCompositorClutterPluginPrivate *priv = plugin->manager_private; + MetaCompositorClutterPluginManager *mgr = priv->self; + MetaDisplay *display = meta_screen_get_display (mgr->screen); + Display *xdpy = meta_display_get_xdisplay (display); + Window xstage, xoverlay; + ClutterActor *stage; + + stage = meta_compositor_clutter_get_stage_for_screen (mgr->screen); + xstage = clutter_x11_get_stage_window (CLUTTER_STAGE (stage)); + xoverlay = meta_compositor_clutter_get_overlay_window (mgr->screen); + + static XserverRegion region = None; + + if (region == None) + region = XFixesCreateRegion (xdpy, NULL, 0); + + if (reactive) + { + XFixesSetWindowShapeRegion (xdpy, xstage, + ShapeInput, 0, 0, None); + XFixesSetWindowShapeRegion (xdpy, xoverlay, + ShapeInput, 0, 0, None); + } + else + { + XFixesSetWindowShapeRegion (xdpy, xstage, + ShapeInput, 0, 0, region); + XFixesSetWindowShapeRegion (xdpy, xoverlay, + ShapeInput, 0, 0, region); + } +} + +void +meta_comp_clutter_plugin_set_stage_input_area (MetaCompositorClutterPlugin *plugin, + gint x, gint y, gint width, gint height) +{ + MetaCompositorClutterPluginPrivate *priv = plugin->manager_private; + MetaCompositorClutterPluginManager *mgr = priv->self; + MetaDisplay *display = meta_screen_get_display (mgr->screen); + Display *xdpy = meta_display_get_xdisplay (display); + Window xstage, xoverlay; + ClutterActor *stage; + XRectangle rect; + XserverRegion region; + + stage = meta_compositor_clutter_get_stage_for_screen (mgr->screen); + xstage = clutter_x11_get_stage_window (CLUTTER_STAGE (stage)); + xoverlay = meta_compositor_clutter_get_overlay_window (mgr->screen); + + rect.x = x; + rect.y = y; + rect.width = width; + rect.height = height; + + region = XFixesCreateRegion (xdpy, &rect, 1); + + XFixesSetWindowShapeRegion (xdpy, xstage, ShapeInput, 0, 0, region); + XFixesSetWindowShapeRegion (xdpy, xoverlay, ShapeInput, 0, 0, region); +} diff --git a/src/compositor/mutter/compositor-mutter.c b/src/compositor/mutter/compositor-mutter.c index 960af110c..848d5ad6b 100644 --- a/src/compositor/mutter/compositor-mutter.c +++ b/src/compositor/mutter/compositor-mutter.c @@ -1645,6 +1645,7 @@ process_property_notify (Mutter *compositor, static void show_overlay_window (MetaScreen *screen, Window cow) { +#if 0 MetaDisplay *display = meta_screen_get_display (screen); Display *xdisplay = meta_display_get_xdisplay (display); XserverRegion region; @@ -1655,6 +1656,7 @@ show_overlay_window (MetaScreen *screen, Window cow) XFixesSetWindowShapeRegion (xdisplay, cow, ShapeInput, 0, 0, region); XFixesDestroyRegion (xdisplay, region); +#endif } static Window @@ -1667,7 +1669,14 @@ get_output_window (MetaScreen *screen) xroot = meta_screen_get_xroot (screen); output = XCompositeGetOverlayWindow (xdisplay, xroot); - XSelectInput (xdisplay, output, ExposureMask); + XSelectInput (xdisplay, + output, + FocusChangeMask | + ExposureMask | + PointerMotionMask | + PropertyChangeMask | + ButtonPressMask | ButtonReleaseMask | + KeyPressMask | KeyReleaseMask); return output; } @@ -1748,6 +1757,15 @@ clutter_cmp_manage_screen (MetaCompositor *compositor, XReparentWindow (xdisplay, xwin, info->output, 0, 0); + XSelectInput (xdisplay, + xwin, + FocusChangeMask | + ExposureMask | + PointerMotionMask | + PropertyChangeMask | + ButtonPressMask | ButtonReleaseMask | + KeyPressMask | KeyReleaseMask); + info->window_group = clutter_group_new (); info->overlay_group = clutter_group_new (); @@ -1842,6 +1860,29 @@ clutter_cmp_process_event (MetaCompositor *compositor, event) == TRUE) return; } + else + { + GSList *l; + Mutter *clc = (Mutter*)compositor; + + l = meta_display_get_screens (clc->display); + + while (l) + { + MetaScreen *screen = l->data; + MetaCompScreen *info; + + info = meta_screen_get_compositor_data (screen); + + if (mutter_plugin_manager_xevent_filter (info->plugin_mgr, + event) == TRUE) + { + return; + } + + l = l->next; + } + } /* * This trap is so that none of the compositor functions cause @@ -2246,6 +2287,15 @@ mutter_new (MetaDisplay *display) #endif } +Window +mutter_get_overlay_window (MetaScreen *screen) +{ + MetaCompScreen *info = meta_screen_get_compositor_data (screen); + + return info->output; +} + + /* ------------------------------- */ /* Shadow Generation */ diff --git a/src/compositor/mutter/mutter-plugin-manager.c b/src/compositor/mutter/mutter-plugin-manager.c index 0d39c4d85..a464ead4a 100644 --- a/src/compositor/mutter/mutter-plugin-manager.c +++ b/src/compositor/mutter/mutter-plugin-manager.c @@ -28,6 +28,10 @@ #include #include +#include +#include +#include +#include static gboolean mutter_plugin_manager_reload ( MutterPluginManager *plugin_mgr); @@ -117,7 +121,7 @@ static gulong parse_disable_params (const char *params, gulong features) { char *p; - + if (!params) return features; @@ -741,7 +745,7 @@ mutter_plugin_manager_xevent_filter ( * Public accessors for plugins, exposed from mutter-plugin.h */ ClutterActor * -meta_comp_clutter_plugin_get_overlay_group (MutterPlugin *plugin) +mutter_plugin_get_overlay_group (MutterPlugin *plugin) { MutterPluginPrivate *priv = plugin->manager_private; MutterPluginManager *plugin_mgr = priv->self; @@ -750,7 +754,7 @@ meta_comp_clutter_plugin_get_overlay_group (MutterPlugin *plugin) } ClutterActor * -meta_comp_clutter_plugin_get_stage (MutterPlugin *plugin) +mutter_plugin_get_stage (MutterPlugin *plugin) { MutterPluginPrivate *priv = plugin->manager_private; MutterPluginManager *plugin_mgr = priv->self; @@ -759,9 +763,9 @@ meta_comp_clutter_plugin_get_stage (MutterPlugin *plugin) } void -meta_comp_clutter_plugin_effect_completed (MutterPlugin *plugin, - MutterWindow *actor, - unsigned long event) +mutter_plugin_effect_completed (MutterPlugin *plugin, + MutterWindow *actor, + unsigned long event) { if (!actor) { @@ -773,9 +777,9 @@ meta_comp_clutter_plugin_effect_completed (MutterPlugin *plugin, } void -meta_comp_clutter_plugin_query_screen_size (MutterPlugin *plugin, - int *width, - int *height) +mutter_plugin_query_screen_size (MutterPlugin *plugin, + int *width, + int *height) { MutterPluginPrivate *priv = plugin->manager_private; MutterPluginManager *plugin_mgr = priv->self; @@ -783,3 +787,66 @@ meta_comp_clutter_plugin_query_screen_size (MutterPlugin *plugin, meta_screen_get_size (plugin_mgr->screen, width, height); } +void +mutter_plugin_set_stage_reactive (MutterPlugin *plugin, + gboolean reactive) +{ + MutterPluginPrivate *priv = plugin->manager_private; + MutterPluginManager *mgr = priv->self; + MetaDisplay *display = meta_screen_get_display (mgr->screen); + Display *xdpy = meta_display_get_xdisplay (display); + Window xstage, xoverlay; + ClutterActor *stage; + + stage = mutter_get_stage_for_screen (mgr->screen); + xstage = clutter_x11_get_stage_window (CLUTTER_STAGE (stage)); + xoverlay = mutter_get_overlay_window (mgr->screen); + + static XserverRegion region = None; + + if (region == None) + region = XFixesCreateRegion (xdpy, NULL, 0); + + if (reactive) + { + XFixesSetWindowShapeRegion (xdpy, xstage, + ShapeInput, 0, 0, None); + XFixesSetWindowShapeRegion (xdpy, xoverlay, + ShapeInput, 0, 0, None); + } + else + { + XFixesSetWindowShapeRegion (xdpy, xstage, + ShapeInput, 0, 0, region); + XFixesSetWindowShapeRegion (xdpy, xoverlay, + ShapeInput, 0, 0, region); + } +} + +void +mutter_plugin_set_stage_input_area (MutterPlugin *plugin, + gint x, gint y, gint width, gint height) +{ + MutterPluginPrivate *priv = plugin->manager_private; + MutterPluginManager *mgr = priv->self; + MetaDisplay *display = meta_screen_get_display (mgr->screen); + Display *xdpy = meta_display_get_xdisplay (display); + Window xstage, xoverlay; + ClutterActor *stage; + XRectangle rect; + XserverRegion region; + + stage = mutter_get_stage_for_screen (mgr->screen); + xstage = clutter_x11_get_stage_window (CLUTTER_STAGE (stage)); + xoverlay = mutter_get_overlay_window (mgr->screen); + + rect.x = x; + rect.y = y; + rect.width = width; + rect.height = height; + + region = XFixesCreateRegion (xdpy, &rect, 1); + + XFixesSetWindowShapeRegion (xdpy, xstage, ShapeInput, 0, 0, region); + XFixesSetWindowShapeRegion (xdpy, xoverlay, ShapeInput, 0, 0, region); +} diff --git a/src/compositor/mutter/plugins/Makefile.am b/src/compositor/mutter/plugins/Makefile.am index c822eee9a..4153f597d 100644 --- a/src/compositor/mutter/plugins/Makefile.am +++ b/src/compositor/mutter/plugins/Makefile.am @@ -12,6 +12,13 @@ default_la_SOURCES = default.c default_la_LDFLAGS = -module -avoid-version -no-undefined default_la_LIBADD = @CLUTTER_LIBS@ +moblin_la_CFLAGS = -fPIC +moblin_la_SOURCES = moblin.c +moblin_la_LDFLAGS = -module -avoid-version -no-undefined +moblin_la_LIBADD = @CLUTTER_LIBS@ + +pkglib_LTLIBRARIES = default.la moblin.la + # post-install hook to remove the .la and .a files we are not interested in # (There is no way to stop libtool generating static libs locally, and we # cannot do this globally because of libmetacity-private.so). diff --git a/src/compositor/mutter/plugins/default.c b/src/compositor/mutter/plugins/default.c index e0db90e15..73623599f 100644 --- a/src/compositor/mutter/plugins/default.c +++ b/src/compositor/mutter/plugins/default.c @@ -202,8 +202,8 @@ on_switch_workspace_effect_complete (ClutterActor *group, gpointer data) state->desktop1 = NULL; state->desktop2 = NULL; - meta_comp_clutter_plugin_effect_completed (&mutter_plugin, actor_for_cb, - MUTTER_PLUGIN_SWITCH_WORKSPACE); + mutter_plugin_effect_completed (&mutter_plugin, actor_for_cb, + MUTTER_PLUGIN_SWITCH_WORKSPACE); } static void @@ -219,9 +219,9 @@ switch_workspace (const GList **actors, gint from, gint to, ClutterActor *stage; int screen_width, screen_height; - stage = meta_comp_clutter_plugin_get_stage (plugin); + stage = mutter_plugin_get_stage (plugin); - meta_comp_clutter_plugin_query_screen_size (plugin, + mutter_plugin_query_screen_size (plugin, &screen_width, &screen_height); clutter_actor_set_anchor_point (workspace1, @@ -238,7 +238,7 @@ switch_workspace (const GList **actors, gint from, gint to, if (from == to) { - meta_comp_clutter_plugin_effect_completed (&mutter_plugin, NULL, + mutter_plugin_effect_completed (&mutter_plugin, NULL, MUTTER_PLUGIN_SWITCH_WORKSPACE); return; } @@ -331,7 +331,7 @@ on_minimize_effect_complete (ClutterActor *actor, gpointer data) /* Decrease the running effect counter */ mutter_plugin.running--; /* Now notify the manager that we are done with this effect */ - meta_comp_clutter_plugin_effect_completed (&mutter_plugin, mc_window, + mutter_plugin_effect_completed (&mutter_plugin, mc_window, MUTTER_PLUGIN_MINIMIZE); } @@ -368,7 +368,7 @@ minimize (MutterWindow *mc_window) NULL); } else - meta_comp_clutter_plugin_effect_completed (&mutter_plugin, mc_window, + mutter_plugin_effect_completed (&mutter_plugin, mc_window, MUTTER_PLUGIN_MINIMIZE); } @@ -396,7 +396,7 @@ on_maximize_effect_complete (ClutterActor *actor, gpointer data) mutter_plugin.running--; /* Now notify the manager that we are done with this effect */ - meta_comp_clutter_plugin_effect_completed (&mutter_plugin, mc_window, + mutter_plugin_effect_completed (&mutter_plugin, mc_window, MUTTER_PLUGIN_MAXIMIZE); } @@ -459,7 +459,7 @@ maximize (MutterWindow *mc_window, return; } - meta_comp_clutter_plugin_effect_completed (&mutter_plugin, mc_window, + mutter_plugin_effect_completed (&mutter_plugin, mc_window, MUTTER_PLUGIN_MAXIMIZE); } @@ -482,7 +482,7 @@ unmaximize (MutterWindow *mc_window, } /* Do this conditionally, if the effect requires completion callback. */ - meta_comp_clutter_plugin_effect_completed (&mutter_plugin, mc_window, + mutter_plugin_effect_completed (&mutter_plugin, mc_window, MUTTER_PLUGIN_UNMAXIMIZE); } @@ -504,7 +504,7 @@ on_map_effect_complete (ClutterActor *actor, gpointer data) mutter_plugin.running--; /* Now notify the manager that we are done with this effect */ - meta_comp_clutter_plugin_effect_completed (&mutter_plugin, mc_window, + mutter_plugin_effect_completed (&mutter_plugin, mc_window, MUTTER_PLUGIN_MAP); } @@ -544,7 +544,7 @@ map (MutterWindow *mc_window) } else - meta_comp_clutter_plugin_effect_completed (&mutter_plugin, mc_window, + mutter_plugin_effect_completed (&mutter_plugin, mc_window, MUTTER_PLUGIN_MAP); } @@ -564,7 +564,7 @@ on_destroy_effect_complete (ClutterActor *actor, gpointer data) mutter_plugin.running--; - meta_comp_clutter_plugin_effect_completed (plugin, mc_window, + mutter_plugin_effect_completed (plugin, mc_window, MUTTER_PLUGIN_DESTROY); } @@ -597,7 +597,7 @@ destroy (MutterWindow *mc_window) NULL); } else - meta_comp_clutter_plugin_effect_completed (&mutter_plugin, mc_window, + mutter_plugin_effect_completed (&mutter_plugin, mc_window, MUTTER_PLUGIN_DESTROY); } diff --git a/src/compositor/mutter/plugins/moblin.c b/src/compositor/mutter/plugins/moblin.c index 42c416147..225cacebc 100644 --- a/src/compositor/mutter/plugins/moblin.c +++ b/src/compositor/mutter/plugins/moblin.c @@ -29,20 +29,25 @@ #define N_(x) x #include +#include #include #include -#define DESTROY_TIMEOUT 250 -#define MINIMIZE_TIMEOUT 250 -#define MAXIMIZE_TIMEOUT 250 -#define MAP_TIMEOUT 250 -#define SWITCH_TIMEOUT 500 +#define DESTROY_TIMEOUT 250 +#define MINIMIZE_TIMEOUT 250 +#define MAXIMIZE_TIMEOUT 250 +#define MAP_TIMEOUT 250 +#define SWITCH_TIMEOUT 500 +#define PANEL_SLIDE_TIMEOUT 250; \ +#define PANEL_SLIDE_THRESHOLD 2 +#define PANEL_HEIGHT 40 #define ACTOR_DATA_KEY "MCCP-Moblin-actor-data" typedef struct PluginPrivate PluginPrivate; typedef struct ActorPrivate ActorPrivate; +static gboolean do_init (const char *params); static void minimize (MutterWindow *actor); static void map (MutterWindow *actor); static void destroy (MutterWindow *actor); @@ -56,14 +61,16 @@ static void switch_workspace (const GList **actors, gint from, gint to, static void kill_effect (MutterWindow *actor, gulong event); -static gboolean reload (void); +static gboolean xevent_filter (XEvent *xev); + +static gboolean reload (const char *params); /* * First we create the header struct and initialize its static members. * Any dynamically allocated data should be initialized in the * init () function below. */ -MutterPlugin MUTTER_PLUGIN_STRUCT = +G_MODULE_EXPORT MutterPlugin mutter_plugin = { /* * These are predefined values; do not modify. @@ -74,15 +81,17 @@ MutterPlugin MUTTER_PLUGIN_STRUCT = .version_api = METACITY_CLUTTER_PLUGIN_API_VERSION, /* Human readable name (for use in UI) */ - .name = "Default Effects", + .name = "Experimental effects", + + /* Plugin load time initialiser */ + .do_init = do_init, /* Which types of events this plugin supports */ .features = MUTTER_PLUGIN_MINIMIZE | MUTTER_PLUGIN_DESTROY | MUTTER_PLUGIN_MAP | MUTTER_PLUGIN_MAXIMIZE | - MUTTER_PLUGIN_UNMAXIMIZE | - MUTTER_PLUGIN_SWITCH_WORKSPACE, + MUTTER_PLUGIN_UNMAXIMIZE, /* And the corresponding handlers */ @@ -92,8 +101,8 @@ MutterPlugin MUTTER_PLUGIN_STRUCT = .maximize = maximize, .unmaximize = unmaximize, .switch_workspace = switch_workspace, - .kill_effect = kill_effect, + .xevent_filter = xevent_filter, /* The reload handler */ .reload = reload @@ -109,6 +118,7 @@ struct PluginPrivate ClutterEffectTemplate *maximize_effect; ClutterEffectTemplate *map_effect; ClutterEffectTemplate *switch_workspace_effect; + ClutterEffectTemplate *panel_slide_effect; /* Valid only when switch_workspace effect is in progress */ ClutterTimeline *tml_switch_workspace1; @@ -117,7 +127,12 @@ struct PluginPrivate ClutterActor *desktop1; ClutterActor *desktop2; + ClutterActor *panel; + gboolean debug_mode : 1; + gboolean panel_out : 1; + gboolean panel_out_in_progress : 1; + gboolean panel_back_in_progress : 1; }; /* @@ -157,7 +172,7 @@ static inline MutterPlugin * get_plugin () { - return &MUTTER_PLUGIN_STRUCT; + return &mutter_plugin; } static void @@ -192,8 +207,8 @@ on_switch_workspace_effect_complete (ClutterActor *group, gpointer data) ppriv->desktop1 = NULL; ppriv->desktop2 = NULL; - meta_comp_clutter_plugin_effect_completed (plugin, actor_for_cb, - MUTTER_PLUGIN_SWITCH_WORKSPACE); + mutter_plugin_effect_completed (plugin, actor_for_cb, + MUTTER_PLUGIN_SWITCH_WORKSPACE); } static void @@ -207,16 +222,17 @@ switch_workspace (const GList **actors, gint from, gint to, ClutterActor *group1 = clutter_group_new (); ClutterActor *group2 = clutter_group_new (); ClutterActor *stage; + gint screen_width; + gint screen_height; - stage = meta_comp_clutter_plugin_get_stage (plugin); + stage = mutter_plugin_get_stage (plugin); + + mutter_plugin_query_screen_size (plugin, &screen_width, &screen_height); #if 1 - clutter_actor_set_anchor_point (group2, - plugin->screen_width, - plugin->screen_height); - clutter_actor_set_position (group2, - plugin->screen_width, - plugin->screen_height); + clutter_actor_set_anchor_point (group2, screen_width, screen_height); + + clutter_actor_set_position (group2, screen_width, screen_height); #endif clutter_actor_set_scale (group2, 0.0, 0.0); @@ -226,7 +242,7 @@ switch_workspace (const GList **actors, gint from, gint to, if (from == to) { - meta_comp_clutter_plugin_effect_completed (plugin, NULL, + mutter_plugin_effect_completed (plugin, NULL, MUTTER_PLUGIN_SWITCH_WORKSPACE); return; } @@ -242,7 +258,7 @@ switch_workspace (const GList **actors, gint from, gint to, ClutterActor *a = CLUTTER_ACTOR (mcw); gint workspace; - workspace = meta_comp_window_get_workspace (mcw); + workspace = mutter_window_get_workspace (mcw); if (workspace == to || workspace == from) { @@ -318,7 +334,7 @@ on_minimize_effect_complete (ClutterActor *actor, gpointer data) plugin->running--; /* Now notify the manager that we are done with this effect */ - meta_comp_clutter_plugin_effect_completed (plugin, mcw, + mutter_plugin_effect_completed (plugin, mcw, MUTTER_PLUGIN_MINIMIZE); } @@ -330,14 +346,14 @@ static void minimize (MutterWindow *mcw) { - MutterPlugin *plugin = get_plugin (); - PluginPrivate *priv = plugin->plugin_private; - MutterWindowType type; - ClutterActor *actor = CLUTTER_ACTOR (mcw); + MutterPlugin *plugin = get_plugin (); + PluginPrivate *priv = plugin->plugin_private; + MetaCompWindowType type; + ClutterActor *actor = CLUTTER_ACTOR (mcw); - type = meta_comp_window_get_window_type (mcw); + type = mutter_window_get_window_type (mcw); - if (type == MUTTER_WINDOW_NORMAL) + if (type == META_COMP_WINDOW_NORMAL) { ActorPrivate *apriv = get_actor_private (mcw); @@ -346,7 +362,7 @@ minimize (MutterWindow *mcw) clutter_actor_move_anchor_point_from_gravity (actor, CLUTTER_GRAVITY_CENTER); - MUTTER_PLUGIN_STRUCT.running++; + plugin->running++; apriv->tml_minimize = clutter_effect_scale (priv->minimize_effect, actor, @@ -357,7 +373,7 @@ minimize (MutterWindow *mcw) NULL); } else - meta_comp_clutter_plugin_effect_completed (plugin, mcw, + mutter_plugin_effect_completed (plugin, mcw, MUTTER_PLUGIN_MINIMIZE); } @@ -385,7 +401,7 @@ on_maximize_effect_complete (ClutterActor *actor, gpointer data) plugin->running--; /* Now notify the manager that we are done with this effect */ - meta_comp_clutter_plugin_effect_completed (plugin, mcw, + mutter_plugin_effect_completed (plugin, mcw, MUTTER_PLUGIN_MAXIMIZE); } @@ -403,7 +419,7 @@ maximize (MutterWindow *mcw, { MutterPlugin *plugin = get_plugin (); PluginPrivate *priv = plugin->plugin_private; - MutterWindowType type; + MetaCompWindowType type; ClutterActor *actor = CLUTTER_ACTOR (mcw); gdouble scale_x = 1.0; @@ -411,9 +427,9 @@ maximize (MutterWindow *mcw, gint anchor_x = 0; gint anchor_y = 0; - type = meta_comp_window_get_window_type (mcw); + type = mutter_window_get_window_type (mcw); - if (type == MUTTER_WINDOW_NORMAL) + if (type == META_COMP_WINDOW_NORMAL) { ActorPrivate *apriv = get_actor_private (mcw); guint width, height; @@ -449,7 +465,7 @@ maximize (MutterWindow *mcw, return; } - meta_comp_clutter_plugin_effect_completed (plugin, mcw, + mutter_plugin_effect_completed (plugin, mcw, MUTTER_PLUGIN_MAXIMIZE); } @@ -463,11 +479,11 @@ unmaximize (MutterWindow *mcw, gint end_x, gint end_y, gint end_width, gint end_height) { MutterPlugin *plugin = get_plugin (); - MutterWindowType type; + MetaCompWindowType type; - type = meta_comp_window_get_window_type (mcw); + type = mutter_window_get_window_type (mcw); - if (type == MUTTER_WINDOW_NORMAL) + if (type == META_COMP_WINDOW_NORMAL) { ActorPrivate *apriv = get_actor_private (mcw); @@ -475,7 +491,7 @@ unmaximize (MutterWindow *mcw, } /* Do this conditionally, if the effect requires completion callback. */ - meta_comp_clutter_plugin_effect_completed (plugin, mcw, + mutter_plugin_effect_completed (plugin, mcw, MUTTER_PLUGIN_UNMAXIMIZE); } @@ -498,7 +514,7 @@ on_map_effect_complete (ClutterActor *actor, gpointer data) plugin->running--; /* Now notify the manager that we are done with this effect */ - meta_comp_clutter_plugin_effect_completed (plugin, mcw, + mutter_plugin_effect_completed (plugin, mcw, MUTTER_PLUGIN_MAP); } @@ -511,19 +527,19 @@ map (MutterWindow *mcw) { MutterPlugin *plugin = get_plugin (); PluginPrivate *priv = plugin->plugin_private; - MutterWindowType type; + MetaCompWindowType type; ClutterActor *actor = CLUTTER_ACTOR (mcw); - type = meta_comp_window_get_window_type (mcw); + type = mutter_window_get_window_type (mcw); - if (type == MUTTER_WINDOW_NORMAL) + if (type == META_COMP_WINDOW_NORMAL) { ActorPrivate *apriv = get_actor_private (mcw); clutter_actor_move_anchor_point_from_gravity (actor, CLUTTER_GRAVITY_CENTER); - MUTTER_PLUGIN_STRUCT.running++; + plugin->running++; clutter_actor_set_scale (actor, 0.0, 0.0); clutter_actor_show (actor); @@ -540,7 +556,7 @@ map (MutterWindow *mcw) } else - meta_comp_clutter_plugin_effect_completed (plugin, mcw, + mutter_plugin_effect_completed (plugin, mcw, MUTTER_PLUGIN_MAP); } @@ -560,7 +576,7 @@ on_destroy_effect_complete (ClutterActor *actor, gpointer data) plugin->running--; - meta_comp_clutter_plugin_effect_completed (plugin, mcw, + mutter_plugin_effect_completed (plugin, mcw, MUTTER_PLUGIN_DESTROY); } @@ -572,12 +588,12 @@ destroy (MutterWindow *mcw) { MutterPlugin *plugin = get_plugin (); PluginPrivate *priv = plugin->plugin_private; - MutterWindowType type; + MetaCompWindowType type; ClutterActor *actor = CLUTTER_ACTOR (mcw); - type = meta_comp_window_get_window_type (mcw); + type = mutter_window_get_window_type (mcw); - if (type == MUTTER_WINDOW_NORMAL) + if (type == META_COMP_WINDOW_NORMAL) { ActorPrivate *apriv = get_actor_private (mcw); @@ -595,10 +611,46 @@ destroy (MutterWindow *mcw) NULL); } else - meta_comp_clutter_plugin_effect_completed (plugin, mcw, + mutter_plugin_effect_completed (plugin, mcw, MUTTER_PLUGIN_DESTROY); } +static void +on_panel_effect_complete (ClutterActor *panel, gpointer data) +{ + gboolean reactive = GPOINTER_TO_INT (data); + MutterPlugin *plugin = get_plugin (); + PluginPrivate *priv = plugin->plugin_private; + gint screen_width, screen_height; + + mutter_plugin_query_screen_size (plugin, &screen_width, &screen_height); + + if (reactive) + { + priv->panel_out_in_progress = FALSE; + mutter_plugin_set_stage_reactive (plugin, reactive); + } + else + { + priv->panel_back_in_progress = FALSE; + mutter_plugin_set_stage_input_area (plugin, 0, 0, + screen_width, 1); + } +} + +static gboolean +xevent_filter (XEvent *xev) +{ + MutterPlugin *plugin = get_plugin (); + ClutterActor *stage; + + stage = mutter_plugin_get_stage (plugin); + + clutter_x11_handle_event (xev); + + return FALSE; +} + static void kill_effect (MutterWindow *mcw, gulong event) { @@ -674,30 +726,100 @@ g_module_check_init (GModule *module) } #endif +static gboolean +stage_input_cb (ClutterActor *stage, ClutterEvent *event, gpointer data) +{ + if (event->type == CLUTTER_MOTION) + { + ClutterMotionEvent *mev = (ClutterMotionEvent *) event; + MutterPlugin *plugin = get_plugin (); + PluginPrivate *priv = plugin->plugin_private; + + if (priv->panel_out_in_progress || priv->panel_back_in_progress) + return FALSE; + + if (priv->panel_out) + { + guint height = clutter_actor_get_height (priv->panel); + gint x = clutter_actor_get_x (priv->panel); + + if (mev->y > (gint)height) + { + priv->panel_back_in_progress = TRUE; + clutter_effect_move (priv->panel_slide_effect, + priv->panel, x, -height, + on_panel_effect_complete, + GINT_TO_POINTER (FALSE)); + priv->panel_out = FALSE; + } + + return TRUE; + } + else if (mev->y < PANEL_SLIDE_THRESHOLD) + { + gint x = clutter_actor_get_x (priv->panel); + + priv->panel_out_in_progress = TRUE; + clutter_effect_move (priv->panel_slide_effect, + priv->panel, x, 0, + on_panel_effect_complete, + GINT_TO_POINTER (TRUE)); + + priv->panel_out = TRUE; + + return TRUE; + } + + return FALSE; + } + + return FALSE; +} + +static ClutterActor * +make_panel (gint width) +{ + ClutterActor *panel; + ClutterActor *background; + ClutterColor clr = {0xff, 0, 0, 0xff}; + + panel = clutter_group_new (); + + /* FIME -- size and color */ + background = clutter_rectangle_new_with_color (&clr); + clutter_container_add_actor (CLUTTER_CONTAINER (panel), background); + clutter_actor_set_size (background, width, PANEL_HEIGHT); + + return panel; +} + /* * Core of the plugin init function, called for initial initialization and * by the reload() function. Returns TRUE on success. */ static gboolean -do_init () +do_init (const char *params) { MutterPlugin *plugin = get_plugin (); PluginPrivate *priv = g_new0 (PluginPrivate, 1); - const gchar *params; - guint destroy_timeout = DESTROY_TIMEOUT; - guint minimize_timeout = MINIMIZE_TIMEOUT; - guint maximize_timeout = MAXIMIZE_TIMEOUT; - guint map_timeout = MAP_TIMEOUT; - guint switch_timeout = SWITCH_TIMEOUT; + guint destroy_timeout = DESTROY_TIMEOUT; + guint minimize_timeout = MINIMIZE_TIMEOUT; + guint maximize_timeout = MAXIMIZE_TIMEOUT; + guint map_timeout = MAP_TIMEOUT; + guint switch_timeout = SWITCH_TIMEOUT; + guint panel_slide_timeout = PANEL_SLIDE_TIMEOUT; const gchar *name; + ClutterActor *overlay; + ClutterActor *panel; + gint screen_width, screen_height; plugin->plugin_private = priv; name = plugin->name; plugin->name = _(name); - params = plugin->params; + mutter_plugin_query_screen_size (plugin, &screen_width, &screen_height); if (params) { @@ -706,7 +828,7 @@ do_init () if (strstr (params, "debug")) { g_debug ("%s: Entering debug mode.", - MUTTER_PLUGIN_STRUCT.name); + plugin->name); priv->debug_mode = TRUE; @@ -777,17 +899,35 @@ do_init () switch_timeout), CLUTTER_ALPHA_SINE_INC); - return TRUE; -} + overlay = mutter_plugin_get_overlay_group (plugin); -MUTTER_PLUGIN_INIT_FUNC -{ - return do_init (); + panel = priv->panel = make_panel (screen_width); + clutter_container_add_actor (CLUTTER_CONTAINER (overlay), panel); + + priv->panel_slide_effect + = clutter_effect_template_new (clutter_timeline_new_for_duration ( + panel_slide_timeout), + CLUTTER_ALPHA_SINE_INC); + + clutter_actor_set_position (panel, 0, + -clutter_actor_get_height (panel)); + + g_signal_connect (mutter_plugin_get_stage (plugin), + "motion-event", G_CALLBACK (stage_input_cb), NULL); + + mutter_plugin_set_stage_input_area (plugin, 0, 0, screen_width, 1); + + clutter_set_motion_events_enabled (TRUE); + + return TRUE; } static void free_plugin_private (PluginPrivate *priv) { + if (!priv) + return; + g_object_unref (priv->destroy_effect); g_object_unref (priv->minimize_effect); g_object_unref (priv->maximize_effect); @@ -795,7 +935,7 @@ free_plugin_private (PluginPrivate *priv) g_free (priv); - MUTTER_PLUGIN_STRUCT.plugin_private = NULL; + get_plugin()->plugin_private = NULL; } /* @@ -803,13 +943,12 @@ free_plugin_private (PluginPrivate *priv) * changed. */ static gboolean -reload () +reload (const char *params) { - PluginPrivate *priv; + MutterPlugin *plugin = get_plugin (); + PluginPrivate *priv = plugin->plugin_private; - priv = MUTTER_PLUGIN_STRUCT.plugin_private; - - if (do_init ()) + if (do_init (params)) { /* Success; free the old private struct */ free_plugin_private (priv); @@ -818,7 +957,7 @@ reload () else { /* Fail -- fall back to the old private. */ - MUTTER_PLUGIN_STRUCT.plugin_private = priv; + plugin->plugin_private = priv; } return FALSE; @@ -827,12 +966,10 @@ reload () /* * GModule unload function -- do any cleanup required. */ -void g_module_unload (GModule *module); -void g_module_unload (GModule *module) +G_MODULE_EXPORT void g_module_unload (GModule *module); +G_MODULE_EXPORT void g_module_unload (GModule *module) { - PluginPrivate *priv; - - priv = MUTTER_PLUGIN_STRUCT.plugin_private; + PluginPrivate *priv = get_plugin()->plugin_private; free_plugin_private (priv); } diff --git a/src/include/compositor-clutter-plugin.h b/src/include/compositor-clutter-plugin.h new file mode 100644 index 000000000..46dd62e04 --- /dev/null +++ b/src/include/compositor-clutter-plugin.h @@ -0,0 +1,255 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (c) 2008 Intel Corp. + * + * Author: Tomas Frydrych + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef META_COMPOSITOR_CLUTTER_PLUGIN_H_ +#define META_COMPOSITOR_CLUTTER_PLUGIN_H_ + +#include "types.h" +#include "config.h" +#include "compositor.h" +#include "compositor-clutter.h" + +#include + +/* + * This file defines the plugin API. + * + * Effects plugin is shared library loaded via dlopen(); it is recommended + * that the GModule API is used (otherwise you are on your own to do proper + * plugin clean up when the module is unloaded). + * + * The plugin interface is exported via the MetaCompositorClutterPlugin struct. + */ + +/* + * Alias MetaRectangle to PluginWorkspaceRectangle in anticipation of + * making this file metacity-independent (we want the plugins to be portable + * between different WMs. + */ +typedef MetaRectangle PluginWorkspaceRectangle; + +/* + * The name of the header struct; use as: + * + * MetaCompositorClutterPlugin META_COMPOSITOR_CLUTTER_PLUGIN_STRUCT = + * { + * ... + * }; + * + * See clutter-plugins/simple.c for example code. + */ +#define META_COMPOSITOR_CLUTTER_PLUGIN_STRUCT MCCPS__ + +/* + * Definition for the plugin init function; use as: + * + * META_COMPOSITOR_CLUTTER_PLUGIN_INIT_FUNC + * { + * init code ... + * } + * + * See clutter-plugins/simple.c for example code. + */ +#define META_COMPOSITOR_CLUTTER_PLUGIN_INIT_FUNC \ + gboolean mccp_init__(void); \ + gboolean mccp_init__() + + +/* Private; must match the above */ +#define META_COMPOSITOR_CLUTTER_PLUGIN_STRUCT_NAME "MCCPS__" +#define META_COMPOSITOR_CLUTTER_PLUGIN_INIT_FUNC_NAME "mccp_init__" + +typedef struct MetaCompositorClutterPlugin MetaCompositorClutterPlugin; + +/* + * Feature flags: identify events that the plugin can handle; a plugin can + * handle one or more events. + */ +#define META_COMPOSITOR_CLUTTER_PLUGIN_MINIMIZE 0x00000001UL +#define META_COMPOSITOR_CLUTTER_PLUGIN_MAXIMIZE 0x00000002UL +#define META_COMPOSITOR_CLUTTER_PLUGIN_UNMAXIMIZE 0x00000004UL +#define META_COMPOSITOR_CLUTTER_PLUGIN_MAP 0x00000008UL +#define META_COMPOSITOR_CLUTTER_PLUGIN_DESTROY 0x00000010UL +#define META_COMPOSITOR_CLUTTER_PLUGIN_SWITCH_WORKSPACE 0x00000020UL + +#define META_COMPOSITOR_CLUTTER_PLUGIN_ALL_EFFECTS 0xffffffffUL + +struct MetaCompositorClutterPlugin +{ + /* + * Version information; the first three numbers match the Metacity version + * with which the plugin was compiled (see clutter-plugins/simple.c for sample + * code). + */ + guint version_major; + guint version_minor; + guint version_micro; + + /* + * Version of the plugin API; this is unrelated to the matacity version + * per se. The API version is checked by the plugin manager and must match + * the one used by it (see clutter-plugins/simple.c for sample code). + */ + guint version_api; + +#ifndef META_COMPOSITOR_CLUTTER_BUILDING_PLUGIN + const +#endif + gchar *name; /* Human-readable name for UI */ + gulong features; /* or-ed feature flags */ + + /* + * Event handlers + * + * Plugins must not make any special assumptions about the nature of + * ClutterActor, as the implementation details can change. + * + * Plugins must restore actor properties on completion (i.e., fade effects + * must restore opacity back to the original value, scale effects scale, + * etc.). + * + * On completion, each event handler must call the manager completed() + * callback function. + */ + void (*minimize) (MetaCompWindow *actor); + + void (*maximize) (MetaCompWindow *actor, + gint x, + gint y, + gint width, + gint height); + + void (*unmaximize) (MetaCompWindow *actor, + gint x, + gint y, + gint width, + gint height); + + void (*map) (MetaCompWindow *actor); + + void (*destroy) (MetaCompWindow *actor); + + /* + * Each actor in the list has a workspace number attached to it using + * g_object_set_data() with key META_COMPOSITOR_CLUTTER_PLUGIN_WORKSPACE_KEY; + * workspace < 0 indicates the window is sticky (i.e., on all desktops). + */ + void (*switch_workspace) (const GList **actors, + gint from, + gint to, + MetaMotionDirection direction); + + /* + * Called if an effect should be killed prematurely; the plugin must + * call the completed() callback as if the effect terminated naturally. + * The events parameter is a bitmask indicating which effects are to be + * killed. + */ + void (*kill_effect) (MetaCompWindow *actor, + gulong events); + + + /* + * The plugin manager will call this function when module should be reloaded. + * This happens, for example, when the parameters for the plugin changed. + */ + gboolean (*reload) (void); + + /* General XEvent filter. This is fired *before* metacity itself handles + * an event. Return TRUE to block any further processing. + */ + gboolean (*xevent_filter) (XEvent *event); + + +#ifdef META_COMPOSITOR_CLUTTER_BUILDING_PLUGIN + const +#endif + gchar *params; /* String containing additional parameters for the plugin; + * this is specified after the pluing name in the gconf + * database, separated by a colon. + * + * The following parameter tokens need to be handled by all + * plugins: + * + * 'debug' + * Indicates running in debug mode; the plugin + * might want to print useful debug info, or + * extend effect duration, etc. + * + * 'disable: ...;' + * + * The disable token indicates that the effects + * listed after the colon should be disabled. + * + * The list is comma-separated, terminated by a + * semicolon and consisting of the following + * tokens: + * + * minimize + * maximize + * unmaximize + * map + * destroy + * switch-workspace + */ + + gint screen_width; + gint screen_height; + + GList *work_areas; /* List of PluginWorkspaceRectangles defining the + * geometry of individual workspaces. + */ + + gint running; /* Plugin must increase this counter for each effect it starts + * decrease it again once the effect finishes. + */ + + void *plugin_private; /* Plugin private data go here; use the plugin init + * function to allocate and initialize any private + * data. + */ + + /* Private; manager private data. */ + void *manager_private; +}; + +void +meta_comp_clutter_plugin_effect_completed (MetaCompositorClutterPlugin *plugin, + MetaCompWindow *actor, + unsigned long event); + +ClutterActor * +meta_comp_clutter_plugin_get_overlay_group (MetaCompositorClutterPlugin *plugin); + +ClutterActor * +meta_comp_clutter_plugin_get_stage (MetaCompositorClutterPlugin *plugin); + +void +meta_comp_clutter_plugin_set_stage_reactive (MetaCompositorClutterPlugin *plugin, + gboolean reactive); + +void +meta_comp_clutter_plugin_set_stage_input_area (MetaCompositorClutterPlugin *plugin, + gint x, gint y, gint width, gint height); + +#endif diff --git a/src/include/compositor-clutter.h b/src/include/compositor-clutter.h new file mode 100644 index 000000000..7f79469be --- /dev/null +++ b/src/include/compositor-clutter.h @@ -0,0 +1,76 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ + +/* + * Copyright (C) 2008 Matthew Allum + * Copyright (C) 2007 Iain Holmes + * Based on xcompmgr - (c) 2003 Keith Packard + * xfwm4 - (c) 2005-2007 Olivier Fourdan + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef META_COMPOSITOR_CLUTTER_H_ +#define META_COMPOSITOR_CLUTTER_H_ + +#include + +#include "types.h" + +/* + * MetaCompWindow object (ClutterGroup sub-class) + */ +#define META_TYPE_COMP_WINDOW (meta_comp_window_get_type ()) +#define META_COMP_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), META_TYPE_COMP_WINDOW, MetaCompWindow)) +#define META_COMP_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), META_TYPE_COMP_WINDOW, MetaCompWindowClass)) +#define IS_META_COMP_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), META_COMP_WINDOW_TYPE)) +#define META_IS_COMP_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), META_TYPE_COMP_WINDOW)) +#define META_COMP_WINDOW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), META_TYPE_COMP_WINDOW, MetaCompWindowClass)) + +typedef struct _MetaCompWindow MetaCompWindow; +typedef struct _MetaCompWindowClass MetaCompWindowClass; +typedef struct _MetaCompWindowPrivate MetaCompWindowPrivate; + +struct _MetaCompWindowClass +{ + ClutterGroupClass parent_class; +}; + +struct _MetaCompWindow +{ + ClutterGroup parent; + + MetaCompWindowPrivate *priv; +}; + +GType meta_comp_window_get_type (void); + +Window meta_comp_window_get_x_window (MetaCompWindow *mcw); +MetaCompWindowType meta_comp_window_get_window_type (MetaCompWindow *mcw); +gint meta_comp_window_get_workspace (MetaCompWindow *mcw); + + +/* Compositor API */ +MetaCompositor *meta_compositor_clutter_new (MetaDisplay *display); + +void meta_compositor_clutter_window_effect_completed (MetaCompWindow *actor, gulong event); + +ClutterActor * meta_compositor_clutter_get_stage_for_screen (MetaScreen *screen); +ClutterActor * meta_compositor_clutter_get_overlay_group_for_screen (MetaScreen *screen); + +Window meta_compositor_clutter_get_overlay_window (MetaScreen *screen); + + +#endif diff --git a/src/include/compositor-mutter.h b/src/include/compositor-mutter.h index 23060b07f..11c86636a 100644 --- a/src/include/compositor-mutter.h +++ b/src/include/compositor-mutter.h @@ -69,5 +69,6 @@ void mutter_window_effect_completed (MutterWindow *actor, gulong event); ClutterActor * mutter_get_stage_for_screen (MetaScreen *screen); ClutterActor * mutter_get_overlay_group_for_screen (MetaScreen *screen); +Window mutter_get_overlay_window (MetaScreen *screen); #endif diff --git a/src/include/mutter-plugin.h b/src/include/mutter-plugin.h index d01990315..ae9d78094 100644 --- a/src/include/mutter-plugin.h +++ b/src/include/mutter-plugin.h @@ -79,8 +79,8 @@ struct MutterPlugin #endif gchar *name; /* Human-readable name for UI */ gulong features; /* or-ed feature flags */ - - /* + + /* * This function is called once the plugin has been loaded. * * @params is a string containing additional parameters for the plugin and is @@ -94,7 +94,7 @@ struct MutterPlugin * Indicates running in debug mode; the plugin * might want to print useful debug info, or * extend effect duration, etc. - * + * * 'disable: ...;' * * The disable token indicates that the effects @@ -185,8 +185,8 @@ struct MutterPlugin /* List of PluginWorkspaceRectangles defining the geometry of individual * workspaces. */ - GList *work_areas; - + GList *work_areas; + /* FIXME: It should be possible to hide this from plugins */ gint running; /* Plugin must increase this counter for each effect it starts * decrease it again once the effect finishes. @@ -202,19 +202,33 @@ struct MutterPlugin }; void -meta_comp_clutter_plugin_effect_completed (MutterPlugin *plugin, - MutterWindow *actor, - unsigned long event); +mutter_plugin_effect_completed (MutterPlugin *plugin, + MutterWindow *actor, + unsigned long event); ClutterActor * -meta_comp_clutter_plugin_get_overlay_group (MutterPlugin *plugin); +mutter_plugin_get_overlay_group (MutterPlugin *plugin); ClutterActor * -meta_comp_clutter_plugin_get_stage (MutterPlugin *plugin); +mutter_plugin_get_stage (MutterPlugin *plugin); void -meta_comp_clutter_plugin_query_screen_size (MutterPlugin *plugin, - int *width, - int *height); +mutter_plugin_query_screen_size (MutterPlugin *plugin, + int *width, + int *height); + +ClutterActor * +mutter_plugin_get_overlay_group (MutterPlugin *plugin); + +ClutterActor * +mutter_plugin_get_stage (MutterPlugin *plugin); + +void +mutter_plugin_set_stage_reactive (MutterPlugin *plugin, + gboolean reactive); + +void +mutter_plugin_set_stage_input_area (MutterPlugin *plugin, + gint x, gint y, gint width, gint height); #endif /* MUTTER_PLUGIN_H_ */