From c61eb77a70617e1d52fc1646bfac3417f3cfc915 Mon Sep 17 00:00:00 2001 From: Tomas Frydrych Date: Wed, 17 Dec 2008 09:33:56 +0000 Subject: [PATCH] GObjectified MutterPlugin. --- configure.in | 2 +- src/Makefile.am | 3 + src/compositor/mutter/compositor-mutter.c | 10 + src/compositor/mutter/mutter-module.c | 206 +++++++ src/compositor/mutter/mutter-module.h | 57 ++ src/compositor/mutter/mutter-plugin-manager.c | 558 +++-------------- src/compositor/mutter/mutter-plugin.c | 574 ++++++++++++++++++ src/compositor/mutter/mutter-shaped-texture.c | 82 ++- src/compositor/mutter/plugins/default.c | 520 +++++++++------- src/include/mutter-plugin.h | 312 +++++----- 10 files changed, 1474 insertions(+), 850 deletions(-) create mode 100644 src/compositor/mutter/mutter-module.c create mode 100644 src/compositor/mutter/mutter-module.h create mode 100644 src/compositor/mutter/mutter-plugin.c diff --git a/configure.in b/configure.in index 9eac03b5e..6b87c03cf 100644 --- a/configure.in +++ b/configure.in @@ -9,7 +9,7 @@ m4_define([metacity_micro_version], [2]) m4_define([metacity_version], [metacity_major_version.metacity_minor_version.metacity_micro_version]) -m4_define([metacity_clutter_plugin_api_version], [1]) +m4_define([metacity_clutter_plugin_api_version], [2]) AC_INIT([metacity], [metacity_version], [http://bugzilla.gnome.org/enter_bug.cgi?product=metacity]) diff --git a/src/Makefile.am b/src/Makefile.am index 2c6176169..47d158826 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -112,6 +112,9 @@ metacity_SOURCES += \ compositor/mutter/mutter-plugin-manager.h \ compositor/mutter/tidy/tidy-texture-frame.c \ compositor/mutter/tidy/tidy-texture-frame.h \ + compositor/mutter/mutter-module.c \ + compositor/mutter/mutter-module.h \ + compositor/mutter/mutter-plugin.c \ include/mutter-plugin.h endif diff --git a/src/compositor/mutter/compositor-mutter.c b/src/compositor/mutter/compositor-mutter.c index bc83867f4..4a22c2e34 100644 --- a/src/compositor/mutter/compositor-mutter.c +++ b/src/compositor/mutter/compositor-mutter.c @@ -348,6 +348,11 @@ mutter_window_constructed (GObject *object) } priv->actor = mutter_shaped_texture_new (); + + if (!clutter_glx_texture_pixmap_using_extension ( + CLUTTER_GLX_TEXTURE_PIXMAP (priv->actor))) + g_warning ("NOTE: Not using GLX TFP!\n"); + clutter_container_add_actor (CLUTTER_CONTAINER (self), priv->actor); update_shape ((Mutter *) @@ -2291,6 +2296,10 @@ clutter_cmp_update_workspace_geometry (MetaCompositor *compositor, MetaWorkspace *workspace) { #ifdef HAVE_COMPOSITE_EXTENSIONS +#if 0 + /* FIXME -- should do away with this function in favour of MetaWorkspace + * signal. + */ MetaScreen *screen = meta_workspace_get_screen (workspace); MetaCompScreen *info; MutterPluginManager *mgr; @@ -2303,6 +2312,7 @@ clutter_cmp_update_workspace_geometry (MetaCompositor *compositor, mutter_plugin_manager_update_workspace (mgr, workspace); #endif +#endif } static void diff --git a/src/compositor/mutter/mutter-module.c b/src/compositor/mutter/mutter-module.c new file mode 100644 index 000000000..d965b8d23 --- /dev/null +++ b/src/compositor/mutter/mutter-module.c @@ -0,0 +1,206 @@ +/* -*- 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 "mutter-plugin.h" +#include "mutter-module.h" + +#include + +enum +{ + PROP_0, + PROP_PATH, +}; + +struct _MutterModulePrivate +{ + GModule *lib; + gchar *path; + GType plugin_type; +}; + +#define MUTTER_MODULE_GET_PRIVATE(obj) \ +(G_TYPE_INSTANCE_GET_PRIVATE ((obj), MUTTER_TYPE_MODULE, MutterModulePrivate)) + +G_DEFINE_TYPE (MutterModule, mutter_module, G_TYPE_TYPE_MODULE); + +static gboolean +mutter_module_load (GTypeModule *gmodule) +{ + MutterModulePrivate *priv = MUTTER_MODULE (gmodule)->priv; + MutterPluginVersion *info = NULL; + GType (*register_type) (GTypeModule *) = NULL; + + if (priv->lib && priv->plugin_type) + return TRUE; + + g_assert (priv->path); + + if (!priv->lib && + !(priv->lib = g_module_open (priv->path, G_MODULE_BIND_LOCAL))) + { + g_warning ("Could not load library [%s]", priv->path); + return FALSE; + } + + if (g_module_symbol (priv->lib, "mutter_plugin_version", (gpointer *)&info) && + g_module_symbol (priv->lib, "mutter_plugin_register_type", + (gpointer *)®ister_type) && + info && register_type) + { + if (info->version_api != METACITY_CLUTTER_PLUGIN_API_VERSION) + g_warning ("Plugin API mismatch for [%s]", priv->path); + else + { + GType plugin_type; + + if (!(plugin_type = register_type (gmodule))) + { + g_warning ("Could not register type for plugin %s", + priv->path); + return FALSE; + } + else + { + priv->plugin_type = plugin_type; + } + + return TRUE; + } + } + else + g_warning ("Broken plugin module [%s]", priv->path); + + return FALSE; +} + +static void +mutter_module_unload (GTypeModule *gmodule) +{ + MutterModulePrivate *priv = MUTTER_MODULE (gmodule)->priv; + + g_module_close (priv->lib); + + priv->lib = NULL; + priv->plugin_type = 0; +} + +static void +mutter_module_dispose (GObject *object) +{ + G_OBJECT_CLASS (mutter_module_parent_class)->dispose (object); +} + +static void +mutter_module_finalize (GObject *object) +{ + MutterModulePrivate *priv = MUTTER_MODULE (object)->priv; + + g_free (priv->path); + priv->path = NULL; + + G_OBJECT_CLASS (mutter_module_parent_class)->finalize (object); +} + +static void +mutter_module_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + MutterModulePrivate *priv = MUTTER_MODULE (object)->priv; + + switch (prop_id) + { + case PROP_PATH: + g_free (priv->path); + priv->path = g_value_dup_string (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +mutter_module_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + MutterModulePrivate *priv = MUTTER_MODULE (object)->priv; + + switch (prop_id) + { + case PROP_PATH: + g_value_set_string (value, priv->path); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +mutter_module_class_init (MutterModuleClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GTypeModuleClass *gmodule_class = G_TYPE_MODULE_CLASS (klass); + + gobject_class->finalize = mutter_module_finalize; + gobject_class->dispose = mutter_module_dispose; + gobject_class->set_property = mutter_module_set_property; + gobject_class->get_property = mutter_module_get_property; + + gmodule_class->load = mutter_module_load; + gmodule_class->unload = mutter_module_unload; + + g_object_class_install_property (gobject_class, + PROP_PATH, + g_param_spec_string ("path", + "Path", + "Load path", + NULL, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY)); + + g_type_class_add_private (gobject_class, sizeof (MutterModulePrivate)); +} + +static void +mutter_module_init (MutterModule *self) +{ + MutterModulePrivate *priv; + + self->priv = priv = MUTTER_MODULE_GET_PRIVATE (self); + +} + +GType +mutter_module_get_plugin_type (MutterModule *module) +{ + MutterModulePrivate *priv = MUTTER_MODULE (module)->priv; + + return priv->plugin_type; +} + diff --git a/src/compositor/mutter/mutter-module.h b/src/compositor/mutter/mutter-module.h new file mode 100644 index 000000000..07265d097 --- /dev/null +++ b/src/compositor/mutter/mutter-module.h @@ -0,0 +1,57 @@ +/* -*- 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 MUTTER_MODULE_H_ +#define MUTTER_MODULE_H_ + +#include + +#define MUTTER_TYPE_MODULE (mutter_module_get_type ()) +#define MUTTER_MODULE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MUTTER_TYPE_MODULE, MutterModule)) +#define MUTTER_MODULE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MUTTER_TYPE_MODULE, MutterModuleClass)) +#define MUTTER_IS_MODULE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MUTTER_MODULE_TYPE)) +#define MUTTER_IS_MODULE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MUTTER_TYPE_MODULE)) +#define MUTTER_MODULE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MUTTER_TYPE_MODULE, MutterModuleClass)) + +typedef struct _MutterModule MutterModule; +typedef struct _MutterModuleClass MutterModuleClass; +typedef struct _MutterModulePrivate MutterModulePrivate; + +struct _MutterModule +{ + GTypeModule parent; + + MutterModulePrivate *priv; +}; + +struct _MutterModuleClass +{ + GTypeModuleClass parent_class; +}; + + +GType mutter_module_get_type (void); + +GType mutter_module_get_plugin_type (MutterModule *module); + +#endif diff --git a/src/compositor/mutter/mutter-plugin-manager.c b/src/compositor/mutter/mutter-plugin-manager.c index 4f936834f..4d89dbba8 100644 --- a/src/compositor/mutter/mutter-plugin-manager.c +++ b/src/compositor/mutter/mutter-plugin-manager.c @@ -26,215 +26,52 @@ #include "prefs.h" #include "errors.h" #include "workspace.h" +#include "mutter-module.h" -#include #include -#include -#include -#include -#include -static gboolean mutter_plugin_manager_reload ( - MutterPluginManager *plugin_mgr); +/* + * There is only one instace of each module per the process. + */ +static GHashTable *plugin_modules = NULL; + +static gboolean mutter_plugin_manager_reload (MutterPluginManager *plugin_mgr); struct MutterPluginManager { MetaScreen *screen; - GList *plugins; /* TODO -- maybe use hash table */ + GList *plugins; GList *unload; /* Plugins that are disabled and pending unload */ guint idle_unload_id; }; -typedef struct MutterPluginPrivate -{ - char *name; - MutterPluginManager *self; - GModule *module; - gulong features; - /* We use this to track the number of effects currently being managed - * by a plugin. Currently this is used to block unloading while effects - * are in progress. */ - gint running; - - gboolean disabled : 1; -} MutterPluginPrivate; - - -static void -free_plugin_workspaces (MutterPlugin *plugin) -{ - GList *l; - - l = plugin->work_areas; - - while (l) - { - g_free (l->data); - l = l->next; - } - - if (plugin->work_areas) - g_list_free (plugin->work_areas); - - plugin->work_areas = NULL; -} - -/* - * Gets work area geometry and stores it in list in the plugin. - * - * If the plugin 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, - MutterPlugin *plugin) -{ - GList *l, *l2 = NULL; - - l = meta_screen_get_workspaces (screen); - - while (l) - { - MetaWorkspace *w = l->data; - MetaRectangle *r; - - r = g_new0 (MetaRectangle, 1); - - meta_workspace_get_work_area_all_xineramas (w, (MetaRectangle*)r); - - l2 = g_list_append (l2, r); - - l = l->next; - } - - free_plugin_workspaces (plugin); - - plugin->work_areas = l2; -} - -/** - * parse_disable_params: - * @params: as read from gconf, a ':' seperated list of plugin options - * @features: The mask of features the plugin advertises - * - * This function returns a new mask of features removing anything that - * the user has disabled. - */ -static gulong -parse_disable_params (const char *params, MutterPlugin *plugin) -{ - char *p; - gulong features = 0; - -/* - * Feature flags: identify events that the plugin can handle; a plugin can - * handle one or more events. - */ - if (plugin->minimize) - features |= MUTTER_PLUGIN_MINIMIZE; - - if (plugin->maximize) - features |= MUTTER_PLUGIN_MAXIMIZE; - - if (plugin->unmaximize) - features |= MUTTER_PLUGIN_UNMAXIMIZE; - - if (plugin->map) - features |= MUTTER_PLUGIN_MAP; - - if (plugin->destroy) - features |= MUTTER_PLUGIN_DESTROY; - - if (plugin->switch_workspace) - features |= MUTTER_PLUGIN_SWITCH_WORKSPACE; - - if (!params) - return features; - - if ((p = strstr (params, "disable:"))) - { - gchar *d = g_strdup (p+8); - - p = strchr (d, ';'); - - if (p) - *p = 0; - - if (strstr (d, "minimize")) - features &= ~ MUTTER_PLUGIN_MINIMIZE; - - if (strstr (d, "maximize")) - features &= ~ MUTTER_PLUGIN_MAXIMIZE; - - if (strstr (d, "unmaximize")) - features &= ~ MUTTER_PLUGIN_UNMAXIMIZE; - - if (strstr (d, "map")) - features &= ~ MUTTER_PLUGIN_MAP; - - if (strstr (d, "destroy")) - features &= ~ MUTTER_PLUGIN_DESTROY; - - if (strstr (d, "switch-workspace")) - features &= ~MUTTER_PLUGIN_SWITCH_WORKSPACE; - - g_free (d); - } - return features; -} /* * Checks that the plugin is compatible with the WM and sets up the plugin * struct. */ static MutterPlugin * -mutter_plugin_load (MutterPluginManager *plugin_mgr, - GModule *module, +mutter_plugin_load (MutterPluginManager *mgr, + MutterModule *module, const gchar *params) { - MutterPlugin *plugin; + MutterPlugin *plugin = NULL; + GType plugin_type = mutter_module_get_plugin_type (module); - if (g_module_symbol (module, "mutter_plugin", (gpointer *)&plugin)) + if (!plugin_type) { - if (plugin->version_api == METACITY_CLUTTER_PLUGIN_API_VERSION) - { - MutterPluginPrivate *priv; - - priv = g_new0 (MutterPluginPrivate, 1); - priv->name = _(plugin->name); - priv->module = module; - priv->self = plugin_mgr; - - /* FIXME: instead of hanging private data of the plugin descriptor - * we could make the descriptor const if we were to hang it off - * a plugin manager structure */ - plugin->manager_private = priv; - - update_plugin_workspaces (plugin_mgr->screen, plugin); - - priv->features = parse_disable_params (params, plugin); - - /* - * Check for and run the plugin init function. - */ - if (!plugin->do_init || !(plugin->do_init (params))) - { - g_free (priv); - - free_plugin_workspaces (plugin); - - return NULL; - } - - meta_verbose ("Loaded plugin [%s]\n", priv->name); - - return plugin; - } + g_warning ("Plugin type not registered !!!"); + return NULL; } - return NULL; + plugin = g_object_new (plugin_type, + "screen", mgr->screen, + "params", params, + NULL); + + return plugin; } /* @@ -245,22 +82,13 @@ mutter_plugin_load (MutterPluginManager *plugin_mgr, static gboolean mutter_plugin_unload (MutterPlugin *plugin) { - MutterPluginPrivate *priv; - GModule *module; - - priv = plugin->manager_private; - module = priv->module; - - if (priv->running) + if (mutter_plugin_running (plugin)) { - priv->disabled = TRUE; + g_object_set (plugin, "disabled", TRUE, NULL); return FALSE; } - g_free (priv); - plugin->manager_private = NULL; - - g_module_close (module); + g_object_unref (plugin); return TRUE; } @@ -353,10 +181,20 @@ prefs_changed_callback (MetaPreference pref, { mutter_plugin_manager_reload (plugin_mgr); } - else if (pref == META_PREF_NUM_WORKSPACES) +} + +static MutterModule * +mutter_plugin_manager_get_module (const gchar *path) +{ + MutterModule *module = g_hash_table_lookup (plugin_modules, path); + + if (!module && + (module = g_object_new (MUTTER_TYPE_MODULE, "path", path, NULL))) { - mutter_plugin_manager_update_workspaces (plugin_mgr); + g_hash_table_insert (plugin_modules, g_strdup (path), module); } + + return module; } /* @@ -388,8 +226,8 @@ mutter_plugin_manager_load (MutterPluginManager *plugin_mgr) if (plugin_string) { - GModule *plugin; - gchar *path; + MutterModule *module; + gchar *path; params = strchr (plugin_string, ':'); @@ -404,20 +242,35 @@ mutter_plugin_manager_load (MutterPluginManager *plugin_mgr) else path = g_strconcat (dpath, plugin_string, ".so", NULL); - if ((plugin = g_module_open (path, G_MODULE_BIND_LOCAL))) + module = mutter_plugin_manager_get_module (path); + + if (module) { MutterPlugin *p; - if ((p = mutter_plugin_load (plugin_mgr, plugin, params))) - plugin_mgr->plugins = g_list_prepend (plugin_mgr->plugins, p); + /* + * This dlopens the module and registers the plugin type with the + * GType system, if the module is not already loaded. When we + * create a plugin, the type system also calls g_type_module_use() + * to guarantee the module will not be unloaded during the plugin + * life time. Consequently we can unuse() the module again. + */ + g_type_module_use (G_TYPE_MODULE (module)); + + if ((p = mutter_plugin_load (plugin_mgr, module, params))) + { + plugin_mgr->plugins = g_list_prepend (plugin_mgr->plugins, p); + } else { - g_message ("Plugin load for [%s] failed", path); - g_module_close (plugin); + g_warning ("Plugin load for [%s] failed", path); } + + g_type_module_unuse (G_TYPE_MODULE (module)); } else - g_message ("Unable to load plugin [%s]: %s", path, g_module_error()); + g_warning ("Unable to load plugin module [%s]: %s", + path, g_module_error()); g_free (path); g_free (plugin_string); @@ -459,57 +312,17 @@ mutter_plugin_manager_init (MutterPluginManager *plugin_mgr) return mutter_plugin_manager_load (plugin_mgr); } -void -mutter_plugin_manager_update_workspace (MutterPluginManager *plugin_mgr, - MetaWorkspace *workspace) -{ - GList *l; - gint index; - - index = meta_workspace_index (workspace); - l = plugin_mgr->plugins; - - while (l) - { - MutterPlugin *plugin = l->data; - MetaRectangle *rect = g_list_nth_data (plugin->work_areas, index); - - if (rect) - { - meta_workspace_get_work_area_all_xineramas (workspace, rect); - } - else - { - /* Something not entirely right; redo the whole thing */ - update_plugin_workspaces (plugin_mgr->screen, plugin); - return; - } - - l = l->next; - } -} - -void -mutter_plugin_manager_update_workspaces (MutterPluginManager *plugin_mgr) -{ - GList *l; - - l = plugin_mgr->plugins; - while (l) - { - MutterPlugin *plugin = l->data; - - update_plugin_workspaces (plugin_mgr->screen, plugin); - - l = l->next; - } -} - MutterPluginManager * mutter_plugin_manager_new (MetaScreen *screen) { MutterPluginManager *plugin_mgr; + if (!plugin_modules) + { + plugin_modules = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, + NULL); + } + plugin_mgr = g_new0 (MutterPluginManager, 1); plugin_mgr->screen = screen; @@ -533,12 +346,12 @@ mutter_plugin_manager_kill_effect (MutterPluginManager *plugin_mgr, while (l) { MutterPlugin *plugin = l->data; - MutterPluginPrivate *priv = plugin->manager_private; + MutterPluginClass *klass = MUTTER_PLUGIN_GET_CLASS (plugin); - if (!priv->disabled - && (priv->features & events) - && plugin->kill_effect) - plugin->kill_effect (actor, events); + if (!mutter_plugin_disabled (plugin) + && (mutter_plugin_features (plugin) & events) + && klass->kill_effect) + klass->kill_effect (plugin, actor, events); l = l->next; } @@ -567,43 +380,41 @@ mutter_plugin_manager_event_simple (MutterPluginManager *plugin_mgr, while (l) { MutterPlugin *plugin = l->data; - MutterPluginPrivate *priv = plugin->manager_private; + MutterPluginClass *klass = MUTTER_PLUGIN_GET_CLASS (plugin); - if (!priv->disabled && (priv->features & event)) + if (!mutter_plugin_disabled (plugin) && + (mutter_plugin_features (plugin) & event)) { retval = TRUE; switch (event) { case MUTTER_PLUGIN_MINIMIZE: - if (plugin->minimize) + if (klass->minimize) { mutter_plugin_manager_kill_effect ( plugin_mgr, actor, ALL_BUT_SWITCH); - priv->running++; - plugin->minimize (actor); + klass->minimize (plugin, actor); } break; case MUTTER_PLUGIN_MAP: - if (plugin->map) + if (klass->map) { mutter_plugin_manager_kill_effect ( plugin_mgr, actor, ALL_BUT_SWITCH); - priv->running++; - plugin->map (actor); + klass->map (plugin, actor); } break; case MUTTER_PLUGIN_DESTROY: - if (plugin->destroy) + if (klass->destroy) { - priv->running++; - plugin->destroy (actor); + klass->destroy (plugin, actor); } break; default: @@ -641,37 +452,38 @@ mutter_plugin_manager_event_maximize (MutterPluginManager *plugin_mgr, while (l) { MutterPlugin *plugin = l->data; - MutterPluginPrivate *priv = plugin->manager_private; + MutterPluginClass *klass = MUTTER_PLUGIN_GET_CLASS (plugin); - if (!priv->disabled && (priv->features & event)) + if (!mutter_plugin_disabled (plugin) && + (mutter_plugin_features (plugin) & event)) { retval = TRUE; switch (event) { case MUTTER_PLUGIN_MAXIMIZE: - if (plugin->maximize) + if (klass->maximize) { mutter_plugin_manager_kill_effect ( plugin_mgr, actor, ALL_BUT_SWITCH); - plugin->maximize (actor, - target_x, target_y, - target_width, target_height); + klass->maximize (plugin, actor, + target_x, target_y, + target_width, target_height); } break; case MUTTER_PLUGIN_UNMAXIMIZE: - if (plugin->unmaximize) + if (klass->unmaximize) { mutter_plugin_manager_kill_effect ( plugin_mgr, actor, ALL_BUT_SWITCH); - plugin->unmaximize (actor, - target_x, target_y, - target_width, target_height); + klass->unmaximize (plugin, actor, + target_x, target_y, + target_width, target_height); } break; default: @@ -706,13 +518,13 @@ mutter_plugin_manager_switch_workspace (MutterPluginManager *plugin_mgr, while (l) { MutterPlugin *plugin = l->data; - MutterPluginPrivate *priv = plugin->manager_private; + MutterPluginClass *klass = MUTTER_PLUGIN_GET_CLASS (plugin); - if (!priv->disabled && - (priv->features & MUTTER_PLUGIN_SWITCH_WORKSPACE) && + if (!mutter_plugin_disabled (plugin) && + (mutter_plugin_features (plugin) & MUTTER_PLUGIN_SWITCH_WORKSPACE) && (actors && *actors)) { - if (plugin->switch_workspace) + if (klass->switch_workspace) { retval = TRUE; mutter_plugin_manager_kill_effect ( @@ -720,7 +532,7 @@ mutter_plugin_manager_switch_workspace (MutterPluginManager *plugin_mgr, MUTTER_WINDOW ((*actors)->data), MUTTER_PLUGIN_SWITCH_WORKSPACE); - plugin->switch_workspace (actors, from, to, direction); + klass->switch_workspace (plugin, actors, from, to, direction); } } @@ -751,11 +563,12 @@ mutter_plugin_manager_xevent_filter (MutterPluginManager *plugin_mgr, while (l) { - MutterPlugin *plugin = l->data; + MutterPlugin *plugin = l->data; + MutterPluginClass *klass = MUTTER_PLUGIN_GET_CLASS (plugin); - if (plugin->xevent_filter) + if (klass->xevent_filter) { - if (plugin->xevent_filter (xev) == TRUE) + if (klass->xevent_filter (plugin, xev) == TRUE) return TRUE; } @@ -765,176 +578,3 @@ mutter_plugin_manager_xevent_filter (MutterPluginManager *plugin_mgr, return FALSE; } -/* - * Public accessors for plugins, exposed from mutter-plugin.h - */ -ClutterActor * -mutter_plugin_get_overlay_group (MutterPlugin *plugin) -{ - MutterPluginPrivate *priv = plugin->manager_private; - MutterPluginManager *plugin_mgr = priv->self; - - return mutter_get_overlay_group_for_screen (plugin_mgr->screen); -} - -ClutterActor * -mutter_plugin_get_stage (MutterPlugin *plugin) -{ - MutterPluginPrivate *priv = plugin->manager_private; - MutterPluginManager *plugin_mgr = priv->self; - - return mutter_get_stage_for_screen (plugin_mgr->screen); -} - -ClutterActor * -mutter_plugin_get_window_group (MutterPlugin *plugin) -{ - MutterPluginPrivate *priv = plugin->manager_private; - MutterPluginManager *plugin_mgr = priv->self; - - return mutter_get_window_group_for_screen (plugin_mgr->screen); -} - -void -mutter_plugin_effect_completed (MutterPlugin *plugin, - MutterWindow *actor, - unsigned long event) -{ - MutterPluginPrivate *priv = plugin->manager_private; - - priv->running--; - - if (!actor) - { - g_warning ("Plugin [%s] passed NULL for actor!", - (plugin && plugin->name) ? plugin->name : "unknown"); - } - - mutter_window_effect_completed (actor, event); -} - -void -mutter_plugin_query_screen_size (MutterPlugin *plugin, - int *width, - int *height) -{ - MutterPluginPrivate *priv = plugin->manager_private; - MutterPluginManager *plugin_mgr = priv->self; - - 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); - - XFixesDestroyRegion (xdpy, region); -} - -void -mutter_plugin_set_stage_input_region (MutterPlugin *plugin, - XserverRegion region) -{ - 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); - - XFixesSetWindowShapeRegion (xdpy, xstage, ShapeInput, 0, 0, region); - XFixesSetWindowShapeRegion (xdpy, xoverlay, ShapeInput, 0, 0, region); -} - -GList * -mutter_plugin_get_windows (MutterPlugin *plugin) -{ - MutterPluginPrivate *priv = plugin->manager_private; - MutterPluginManager *plugin_mgr = priv->self; - - return mutter_get_windows (plugin_mgr->screen); -} - -Display * -mutter_plugin_get_xdisplay (MutterPlugin *plugin) -{ - MutterPluginPrivate *priv = plugin->manager_private; - MutterPluginManager *mgr = priv->self; - MetaDisplay *display = meta_screen_get_display (mgr->screen); - Display *xdpy = meta_display_get_xdisplay (display); - - return xdpy; -} - -MetaScreen * -mutter_plugin_get_screen (MutterPlugin *plugin) -{ - MutterPluginPrivate *priv = plugin->manager_private; - MutterPluginManager *mgr = priv->self; - - return mgr->screen; -} - diff --git a/src/compositor/mutter/mutter-plugin.c b/src/compositor/mutter/mutter-plugin.c new file mode 100644 index 000000000..32a6b1fca --- /dev/null +++ b/src/compositor/mutter/mutter-plugin.c @@ -0,0 +1,574 @@ +/* -*- 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 "mutter-plugin.h" +#include "screen.h" +#include "display.h" + +#include +#include +#include +#include +#include + +G_DEFINE_ABSTRACT_TYPE (MutterPlugin, mutter_plugin, G_TYPE_OBJECT); + +#define MUTTER_PLUGIN_GET_PRIVATE(obj) \ +(G_TYPE_INSTANCE_GET_PRIVATE ((obj), MUTTER_TYPE_PLUGIN, MutterPluginPrivate)) + +enum +{ + PROP_0, + PROP_SCREEN, + PROP_PARAMS, + PROP_FEATURES, + PROP_DISABLED, + PROP_DEBUG_MODE, +}; + +struct _MutterPluginPrivate +{ + MetaScreen *screen; + gchar *params; + gulong features; + + gint running; + + gboolean disabled : 1; + gboolean debug : 1; +}; + +static void +mutter_plugin_dispose (GObject *object) +{ + G_OBJECT_CLASS (mutter_plugin_parent_class)->dispose (object); +} + +static void +mutter_plugin_finalize (GObject *object) +{ + MutterPluginPrivate *priv = MUTTER_PLUGIN (object)->priv; + + g_free (priv->params); + priv->params = NULL; + + G_OBJECT_CLASS (mutter_plugin_parent_class)->finalize (object); +} + +static void +mutter_plugin_parse_params (MutterPlugin *plugin) +{ + char *p; + gulong features = 0; + MutterPluginPrivate *priv = plugin->priv; + MutterPluginClass *klass = MUTTER_PLUGIN_GET_CLASS (plugin); + +/* + * Feature flags: identify events that the plugin can handle; a plugin can + * handle one or more events. + */ + if (klass->minimize) + features |= MUTTER_PLUGIN_MINIMIZE; + + if (klass->maximize) + features |= MUTTER_PLUGIN_MAXIMIZE; + + if (klass->unmaximize) + features |= MUTTER_PLUGIN_UNMAXIMIZE; + + if (klass->map) + features |= MUTTER_PLUGIN_MAP; + + if (klass->destroy) + features |= MUTTER_PLUGIN_DESTROY; + + if (klass->switch_workspace) + features |= MUTTER_PLUGIN_SWITCH_WORKSPACE; + + if (priv->params) + { + gboolean debug = FALSE; + + if ((p = strstr (priv->params, "disable:"))) + { + gchar *d = g_strdup (p+8); + + p = strchr (d, ';'); + + if (p) + *p = 0; + + if (strstr (d, "minimize")) + features &= ~ MUTTER_PLUGIN_MINIMIZE; + + if (strstr (d, "maximize")) + features &= ~ MUTTER_PLUGIN_MAXIMIZE; + + if (strstr (d, "unmaximize")) + features &= ~ MUTTER_PLUGIN_UNMAXIMIZE; + + if (strstr (d, "map")) + features &= ~ MUTTER_PLUGIN_MAP; + + if (strstr (d, "destroy")) + features &= ~ MUTTER_PLUGIN_DESTROY; + + if (strstr (d, "switch-workspace")) + features &= ~MUTTER_PLUGIN_SWITCH_WORKSPACE; + + g_free (d); + } + + if (strstr (priv->params, "debug")) + debug = TRUE; + + if (debug != priv->debug) + { + priv->debug = debug; + + g_object_notify (G_OBJECT (plugin), "debug-mode"); + } + } + + if (features != priv->features) + { + priv->features = features; + + g_object_notify (G_OBJECT (plugin), "features"); + } +} + +static void +mutter_plugin_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + MutterPluginPrivate *priv = MUTTER_PLUGIN (object)->priv; + + switch (prop_id) + { + case PROP_SCREEN: + priv->screen = g_value_get_object (value); + break; + case PROP_PARAMS: + priv->params = g_value_dup_string (value); + mutter_plugin_parse_params (MUTTER_PLUGIN (object)); + break; + case PROP_DISABLED: + priv->disabled = g_value_get_boolean (value); + break; + case PROP_DEBUG_MODE: + priv->debug = g_value_get_boolean (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +mutter_plugin_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + MutterPluginPrivate *priv = MUTTER_PLUGIN (object)->priv; + + switch (prop_id) + { + case PROP_SCREEN: + g_value_set_object (value, priv->screen); + break; + case PROP_PARAMS: + g_value_set_string (value, priv->params); + break; + case PROP_DISABLED: + g_value_set_boolean (value, priv->disabled); + break; + case PROP_DEBUG_MODE: + g_value_set_boolean (value, priv->debug); + break; + case PROP_FEATURES: + g_value_set_ulong (value, priv->features); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +mutter_plugin_real_minimize (MutterPlugin *plugin, MutterWindow *actor) +{ + MutterPluginPrivate *priv = MUTTER_PLUGIN (plugin)->priv; + + priv->running++; +} + +static void +mutter_plugin_real_maximize (MutterPlugin *plugin, + MutterWindow *actor, + gint x, + gint y, + gint width, + gint height) +{ + MutterPluginPrivate *priv = MUTTER_PLUGIN (plugin)->priv; + + priv->running++; +} + + +static void +mutter_plugin_real_unmaximize (MutterPlugin *plugin, + MutterWindow *actor, + gint x, + gint y, + gint width, + gint height) +{ + MutterPluginPrivate *priv = MUTTER_PLUGIN (plugin)->priv; + + priv->running++; +} + + +static void +mutter_plugin_real_map (MutterPlugin *plugin, MutterWindow *actor) +{ + MutterPluginPrivate *priv = MUTTER_PLUGIN (plugin)->priv; + + priv->running++; +} + + +static void +mutter_plugin_real_destroy (MutterPlugin *plugin, MutterWindow *actor) +{ + MutterPluginPrivate *priv = MUTTER_PLUGIN (plugin)->priv; + + priv->running++; +} + + +static void +mutter_plugin_real_switch_workspace (MutterPlugin *plugin, + const GList **actors, + gint from, + gint to, + MetaMotionDirection direction) +{ + MutterPluginPrivate *priv = MUTTER_PLUGIN (plugin)->priv; + + priv->running++; +} + + +static void +mutter_plugin_class_init (MutterPluginClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + MutterPluginClass *plugin_class = MUTTER_PLUGIN_CLASS (klass); + + gobject_class->finalize = mutter_plugin_finalize; + gobject_class->dispose = mutter_plugin_dispose; + gobject_class->set_property = mutter_plugin_set_property; + gobject_class->get_property = mutter_plugin_get_property; + + plugin_class->map = mutter_plugin_real_map; + plugin_class->minimize = mutter_plugin_real_minimize; + plugin_class->maximize = mutter_plugin_real_maximize; + plugin_class->unmaximize = mutter_plugin_real_unmaximize; + plugin_class->destroy = mutter_plugin_real_destroy; + plugin_class->switch_workspace = mutter_plugin_real_switch_workspace; + + g_object_class_install_property (gobject_class, + PROP_SCREEN, + g_param_spec_object ("screen", + "MetaScreen", + "MetaScreen", + META_TYPE_SCREEN, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY)); + + g_object_class_install_property (gobject_class, + PROP_PARAMS, + g_param_spec_string ("params", + "Parameters", + "Plugin Parameters", + NULL, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property (gobject_class, + PROP_FEATURES, + g_param_spec_ulong ("features", + "Features", + "Plugin Features", + 0 , G_MAXULONG, 0, + G_PARAM_READABLE)); + + g_object_class_install_property (gobject_class, + PROP_DISABLED, + g_param_spec_boolean ("disabled", + "Plugin disabled", + "Plugin disabled", + FALSE, + G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, + PROP_DEBUG_MODE, + g_param_spec_boolean ("debug-mode", + "Debug Mode", + "Debug Mode", + FALSE, + G_PARAM_READABLE)); + + g_type_class_add_private (gobject_class, sizeof (MutterPluginPrivate)); +} + +static void +mutter_plugin_init (MutterPlugin *self) +{ + MutterPluginPrivate *priv; + + self->priv = priv = MUTTER_PLUGIN_GET_PRIVATE (self); +} + +gulong +mutter_plugin_features (MutterPlugin *plugin) +{ + MutterPluginPrivate *priv = MUTTER_PLUGIN (plugin)->priv; + + return priv->features; +} + +gboolean +mutter_plugin_disabled (MutterPlugin *plugin) +{ + MutterPluginPrivate *priv = MUTTER_PLUGIN (plugin)->priv; + + return priv->disabled; +} + +gboolean +mutter_plugin_running (MutterPlugin *plugin) +{ + MutterPluginPrivate *priv = MUTTER_PLUGIN (plugin)->priv; + + return (priv->running > 0); +} + +gboolean +mutter_plugin_debug_mode (MutterPlugin *plugin) +{ + MutterPluginPrivate *priv = MUTTER_PLUGIN (plugin)->priv; + + return priv->debug; +} + +const MutterPluginInfo * +mutter_plugin_get_info (MutterPlugin *plugin) +{ + MutterPluginClass *klass = MUTTER_PLUGIN_GET_CLASS (plugin); + + if (klass && klass->plugin_info) + return klass->plugin_info (plugin); + + return NULL; +} + +ClutterActor * +mutter_plugin_get_overlay_group (MutterPlugin *plugin) +{ + MutterPluginPrivate *priv = MUTTER_PLUGIN (plugin)->priv; + + return mutter_get_overlay_group_for_screen (priv->screen); +} + +ClutterActor * +mutter_plugin_get_stage (MutterPlugin *plugin) +{ + MutterPluginPrivate *priv = MUTTER_PLUGIN (plugin)->priv; + + return mutter_get_stage_for_screen (priv->screen); +} + +ClutterActor * +mutter_plugin_get_window_group (MutterPlugin *plugin) +{ + MutterPluginPrivate *priv = MUTTER_PLUGIN (plugin)->priv; + + return mutter_get_window_group_for_screen (priv->screen); +} + +void +mutter_plugin_effect_completed (MutterPlugin *plugin, + MutterWindow *actor, + unsigned long event) +{ + MutterPluginPrivate *priv = MUTTER_PLUGIN (plugin)->priv; + + if (priv->running-- < 0) + { + g_warning ("Error in running effect accounting, adjusting."); + priv->running = 0; + } + + if (!actor) + { + const MutterPluginInfo *info; + const gchar *name = NULL; + + if (plugin && (info = mutter_plugin_get_info (plugin))) + name = info->name; + + g_warning ("Plugin [%s] passed NULL for actor!", + name ? name : "unknown"); + } + + mutter_window_effect_completed (actor, event); +} + +void +mutter_plugin_query_screen_size (MutterPlugin *plugin, + int *width, + int *height) +{ + MutterPluginPrivate *priv = MUTTER_PLUGIN (plugin)->priv; + + meta_screen_get_size (priv->screen, width, height); +} + +void +mutter_plugin_set_stage_reactive (MutterPlugin *plugin, + gboolean reactive) +{ + MutterPluginPrivate *priv = MUTTER_PLUGIN (plugin)->priv; + MetaScreen *screen = priv->screen; + MetaDisplay *display = meta_screen_get_display (screen); + Display *xdpy = meta_display_get_xdisplay (display); + Window xstage, xoverlay; + ClutterActor *stage; + + stage = mutter_get_stage_for_screen (screen); + xstage = clutter_x11_get_stage_window (CLUTTER_STAGE (stage)); + xoverlay = mutter_get_overlay_window (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 = MUTTER_PLUGIN (plugin)->priv; + MetaScreen *screen = priv->screen; + MetaDisplay *display = meta_screen_get_display (screen); + Display *xdpy = meta_display_get_xdisplay (display); + Window xstage, xoverlay; + ClutterActor *stage; + XRectangle rect; + XserverRegion region; + + stage = mutter_get_stage_for_screen (screen); + xstage = clutter_x11_get_stage_window (CLUTTER_STAGE (stage)); + xoverlay = mutter_get_overlay_window (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); + + XFixesDestroyRegion (xdpy, region); +} + +void +mutter_plugin_set_stage_input_region (MutterPlugin *plugin, + XserverRegion region) +{ + MutterPluginPrivate *priv = MUTTER_PLUGIN (plugin)->priv; + MetaScreen *screen = priv->screen; + MetaDisplay *display = meta_screen_get_display (screen); + Display *xdpy = meta_display_get_xdisplay (display); + Window xstage, xoverlay; + ClutterActor *stage; + + stage = mutter_get_stage_for_screen (screen); + xstage = clutter_x11_get_stage_window (CLUTTER_STAGE (stage)); + xoverlay = mutter_get_overlay_window (screen); + + XFixesSetWindowShapeRegion (xdpy, xstage, ShapeInput, 0, 0, region); + XFixesSetWindowShapeRegion (xdpy, xoverlay, ShapeInput, 0, 0, region); +} + +GList * +mutter_plugin_get_windows (MutterPlugin *plugin) +{ + MutterPluginPrivate *priv = MUTTER_PLUGIN (plugin)->priv; + + return mutter_get_windows (priv->screen); +} + +Display * +mutter_plugin_get_xdisplay (MutterPlugin *plugin) +{ + MutterPluginPrivate *priv = MUTTER_PLUGIN (plugin)->priv; + MetaDisplay *display = meta_screen_get_display (priv->screen); + Display *xdpy = meta_display_get_xdisplay (display); + + return xdpy; +} + +MetaScreen * +mutter_plugin_get_screen (MutterPlugin *plugin) +{ + MutterPluginPrivate *priv = MUTTER_PLUGIN (plugin)->priv; + + return priv->screen; +} + diff --git a/src/compositor/mutter/mutter-shaped-texture.c b/src/compositor/mutter/mutter-shaped-texture.c index 19e850eba..31e432339 100644 --- a/src/compositor/mutter/mutter-shaped-texture.c +++ b/src/compositor/mutter/mutter-shaped-texture.c @@ -138,6 +138,15 @@ mutter_shaped_texture_dirty_mask (MutterShapedTexture *stex) if (priv->mask_texture != COGL_INVALID_HANDLE) { + GLuint mask_gl_tex; + GLenum mask_gl_target; + + cogl_texture_get_gl_texture (priv->mask_texture, + &mask_gl_tex, &mask_gl_target); + + if (mask_gl_target == CGL_TEXTURE_RECTANGLE_ARB) + glDeleteTextures (1, &mask_gl_tex); + cogl_texture_unref (priv->mask_texture); priv->mask_texture = COGL_INVALID_HANDLE; } @@ -233,6 +242,7 @@ mutter_shaped_texture_ensure_mask (MutterShapedTexture *stex) CoglHandle paint_tex; guint tex_width, tex_height; GLuint mask_gl_tex; + GLenum mask_target; paint_tex = clutter_texture_get_cogl_texture (CLUTTER_TEXTURE (stex)); @@ -253,6 +263,7 @@ mutter_shaped_texture_ensure_mask (MutterShapedTexture *stex) { guchar *mask_data; const XRectangle *rect; + GLenum paint_gl_target; /* Create data for an empty image */ mask_data = g_malloc0 (tex_width * tex_height); @@ -279,26 +290,53 @@ mutter_shaped_texture_ensure_mask (MutterShapedTexture *stex) memset (p, 255, x2 - x1); } - priv->mask_texture = cogl_texture_new_from_data (tex_width, tex_height, - -1, FALSE, - COGL_PIXEL_FORMAT_A_8, - COGL_PIXEL_FORMAT_ANY, - tex_width, - mask_data); + cogl_texture_get_gl_texture (paint_tex, NULL, &paint_gl_target); + + if (paint_gl_target == CGL_TEXTURE_RECTANGLE_ARB) + { + GLuint tex; + + glGenTextures (1, &tex); + glBindTexture (CGL_TEXTURE_RECTANGLE_ARB, tex); + glPixelStorei (GL_UNPACK_ROW_LENGTH, tex_width); + glPixelStorei (GL_UNPACK_ALIGNMENT, 1); + glPixelStorei (GL_UNPACK_SKIP_ROWS, 0); + glPixelStorei (GL_UNPACK_SKIP_PIXELS, 0); + glTexImage2D (CGL_TEXTURE_RECTANGLE_ARB, 0, + GL_ALPHA, tex_width, tex_height, + 0, GL_ALPHA, GL_UNSIGNED_BYTE, mask_data); + + priv->mask_texture + = cogl_texture_new_from_foreign (tex, + CGL_TEXTURE_RECTANGLE_ARB, + tex_width, tex_height, + 0, 0, + COGL_PIXEL_FORMAT_A_8); + } + else + priv->mask_texture = cogl_texture_new_from_data (tex_width, tex_height, + -1, FALSE, + COGL_PIXEL_FORMAT_A_8, + COGL_PIXEL_FORMAT_ANY, + tex_width, + mask_data); g_free (mask_data); priv->mask_width = tex_width; priv->mask_height = tex_height; - cogl_texture_get_gl_texture (priv->mask_texture, &mask_gl_tex, NULL); + cogl_texture_get_gl_texture (priv->mask_texture, &mask_gl_tex, &mask_target); mutter_shaped_texture_get_gl_size (priv->mask_texture, &priv->mask_gl_width, &priv->mask_gl_height); - if ((guint) priv->mask_gl_width == tex_width - && (guint) priv->mask_gl_height == tex_height) + if (mask_target == GL_TEXTURE_RECTANGLE_ARB) + mutter_shaped_texture_set_coord_array (0.0f, 0.0f, tex_width, tex_height, + priv->mask_tex_coords); + else if ((guint) priv->mask_gl_width == tex_width + && (guint) priv->mask_gl_height == tex_height) mutter_shaped_texture_set_coord_array (0.0f, 0.0f, 1.0f, 1.0f, priv->mask_tex_coords); else @@ -322,6 +360,7 @@ mutter_shaped_texture_paint (ClutterActor *actor) GLboolean vertex_array_was_enabled, tex_coord_array_was_enabled; GLboolean color_array_was_enabled; GLuint paint_gl_tex, mask_gl_tex; + GLenum paint_target, mask_target; guint paint_gl_width, paint_gl_height; GLfloat vertex_coords[8], paint_tex_coords[8]; ClutterActorBox alloc; @@ -358,18 +397,18 @@ mutter_shaped_texture_paint (ClutterActor *actor) mutter_shaped_texture_ensure_mask (stex); - cogl_texture_get_gl_texture (paint_tex, &paint_gl_tex, NULL); - cogl_texture_get_gl_texture (priv->mask_texture, &mask_gl_tex, NULL); + cogl_texture_get_gl_texture (paint_tex, &paint_gl_tex, &paint_target); + cogl_texture_get_gl_texture (priv->mask_texture, &mask_gl_tex, &mask_target); /* We need to keep track of the some of the old state so that we don't confuse Cogl */ - texture_was_enabled = glIsEnabled (GL_TEXTURE_2D); + texture_was_enabled = glIsEnabled (paint_target); blend_was_enabled = glIsEnabled (GL_BLEND); vertex_array_was_enabled = glIsEnabled (GL_VERTEX_ARRAY); tex_coord_array_was_enabled = glIsEnabled (GL_TEXTURE_COORD_ARRAY); color_array_was_enabled = glIsEnabled (GL_COLOR_ARRAY); - glEnable (GL_TEXTURE_2D); + glEnable (paint_target); glEnable (GL_BLEND); glEnableClientState (GL_VERTEX_ARRAY); glEnableClientState (GL_TEXTURE_COORD_ARRAY); @@ -379,7 +418,7 @@ mutter_shaped_texture_paint (ClutterActor *actor) cogl_color (&white); /* Put the main painting texture in the first texture unit */ - glBindTexture (GL_TEXTURE_2D, paint_gl_tex); + glBindTexture (paint_target, paint_gl_tex); /* We need the actual size of the texture so that we can calculate the right texture coordinates if NPOTs textures are not supported @@ -391,9 +430,9 @@ mutter_shaped_texture_paint (ClutterActor *actor) /* Put the mask texture in the second texture unit */ tst_active_texture (GL_TEXTURE1); tst_client_active_texture (GL_TEXTURE1); - glBindTexture (GL_TEXTURE_2D, mask_gl_tex); + glBindTexture (mask_target, mask_gl_tex); - glEnable (GL_TEXTURE_2D); + glEnable (mask_target); glEnableClientState (GL_TEXTURE_COORD_ARRAY); glTexCoordPointer (2, GL_FLOAT, 0, priv->mask_tex_coords); @@ -419,8 +458,11 @@ mutter_shaped_texture_paint (ClutterActor *actor) - alloc.y1), vertex_coords); - if ((guint) paint_gl_width == tex_width - && (guint) paint_gl_height == tex_height) + if (paint_target == GL_TEXTURE_RECTANGLE_ARB) + mutter_shaped_texture_set_coord_array (0.0f, 0.0f, tex_width, tex_height, + paint_tex_coords); + else if ((guint) paint_gl_width == tex_width + && (guint) paint_gl_height == tex_height) mutter_shaped_texture_set_coord_array (0.0f, 0.0f, 1.0f, 1.0f, paint_tex_coords); else @@ -434,7 +476,7 @@ mutter_shaped_texture_paint (ClutterActor *actor) glDrawArrays (GL_TRIANGLE_STRIP, 0, 4); /* Disable the second texture unit and coord array */ - glDisable (GL_TEXTURE_2D); + glDisable (mask_target); glDisableClientState (GL_TEXTURE_COORD_ARRAY); /* Go back to operating on the first texture unit */ @@ -443,7 +485,7 @@ mutter_shaped_texture_paint (ClutterActor *actor) /* Restore the old state */ if (!texture_was_enabled) - glDisable (GL_TEXTURE_2D); + glDisable (paint_target); if (!blend_was_enabled) glDisable (GL_BLEND); if (!vertex_array_was_enabled) diff --git a/src/compositor/mutter/plugins/default.c b/src/compositor/mutter/plugins/default.c index a459e842a..7e4702f95 100644 --- a/src/compositor/mutter/plugins/default.c +++ b/src/compositor/mutter/plugins/default.c @@ -21,7 +21,6 @@ * 02111-1307, USA. */ -#define MUTTER_BUILDING_PLUGIN 1 #include "mutter-plugin.h" #include @@ -39,35 +38,63 @@ #define SWITCH_TIMEOUT 500 #define ACTOR_DATA_KEY "MCCP-Default-actor-data" + +#define MUTTER_TYPE_DEFAULT_PLUGIN (mutter_default_plugin_get_type ()) +#define MUTTER_DEFAULT_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MUTTER_TYPE_DEFAULT_PLUGIN, MutterDefaultPlugin)) +#define MUTTER_DEFAULT_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MUTTER_TYPE_DEFAULT_PLUGIN, MutterDefaultPluginClass)) +#define MUTTER_IS_DEFAULT_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MUTTER_DEFAULT_PLUGIN_TYPE)) +#define MUTTER_IS_DEFAULT_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MUTTER_TYPE_DEFAULT_PLUGIN)) +#define MUTTER_DEFAULT_PLUGIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MUTTER_TYPE_DEFAULT_PLUGIN, MutterDefaultPluginClass)) + +#define MUTTER_DEFAULT_PLUGIN_GET_PRIVATE(obj) \ +(G_TYPE_INSTANCE_GET_PRIVATE ((obj), MUTTER_TYPE_DEFAULT_PLUGIN, MutterDefaultPluginPrivate)) + +typedef struct _MutterDefaultPlugin MutterDefaultPlugin; +typedef struct _MutterDefaultPluginClass MutterDefaultPluginClass; +typedef struct _MutterDefaultPluginPrivate MutterDefaultPluginPrivate; + +struct _MutterDefaultPlugin +{ + MutterPlugin parent; + + MutterDefaultPluginPrivate *priv; +}; + +struct _MutterDefaultPluginClass +{ + MutterPluginClass parent_class; +}; + static GQuark actor_data_quark = 0; -static gboolean do_init (const char *params); -static void minimize (MutterWindow *actor); -static void map (MutterWindow *actor); -static void destroy (MutterWindow *actor); -static void maximize (MutterWindow *actor, +static void minimize (MutterPlugin *plugin, + MutterWindow *actor); +static void map (MutterPlugin *plugin, + MutterWindow *actor); +static void destroy (MutterPlugin *plugin, + MutterWindow *actor); +static void maximize (MutterPlugin *plugin, + MutterWindow *actor, gint x, gint y, gint width, gint height); -static void unmaximize (MutterWindow *actor, +static void unmaximize (MutterPlugin *plugin, + MutterWindow *actor, gint x, gint y, gint width, gint height); -static void switch_workspace (const GList **actors, gint from, gint to, +static void switch_workspace (MutterPlugin *plugin, + const GList **actors, gint from, gint to, MetaMotionDirection direction); -static void kill_effect (MutterWindow *actor, gulong event); +static void kill_effect (MutterPlugin *plugin, + MutterWindow *actor, gulong event); -static gboolean reload (const char *params); +static const MutterPluginInfo * plugin_info (MutterPlugin *plugin); - -/* - * Create the plugin struct; function pointers initialized in - * g_module_check_init(). - */ -MUTTER_DECLARE_PLUGIN(); +MUTTER_PLUGIN_DECLARE(MutterDefaultPlugin, mutter_default_plugin); /* * Plugin private data that we store in the .plugin_private member. */ -typedef struct _PluginState +struct _MutterDefaultPluginPrivate { ClutterEffectTemplate *destroy_effect; ClutterEffectTemplate *minimize_effect; @@ -82,8 +109,150 @@ typedef struct _PluginState ClutterActor *desktop1; ClutterActor *desktop2; + MutterPluginInfo info; + gboolean debug_mode : 1; -} PluginState; +}; + +static void +mutter_default_plugin_dispose (GObject *object) +{ + MutterDefaultPluginPrivate *priv = MUTTER_DEFAULT_PLUGIN (object)->priv; + + g_object_unref (priv->destroy_effect); + g_object_unref (priv->minimize_effect); + g_object_unref (priv->maximize_effect); + g_object_unref (priv->switch_workspace_effect); + + G_OBJECT_CLASS (mutter_default_plugin_parent_class)->dispose (object); +} + +static void +mutter_default_plugin_finalize (GObject *object) +{ + G_OBJECT_CLASS (mutter_default_plugin_parent_class)->finalize (object); +} + +static void +mutter_default_plugin_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (prop_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +mutter_default_plugin_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + switch (prop_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +mutter_default_plugin_constructed (GObject *object) +{ + MutterPlugin *plugin = MUTTER_PLUGIN (object); + MutterDefaultPluginPrivate *priv = MUTTER_DEFAULT_PLUGIN (object)->priv; + + 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; + + if (mutter_plugin_debug_mode (plugin)) + { + g_debug ("Plugin %s: Entering debug mode.", priv->info.name); + + priv->debug_mode = TRUE; + + /* + * Double the effect duration to make them easier to observe. + */ + destroy_timeout *= 2; + minimize_timeout *= 2; + maximize_timeout *= 2; + map_timeout *= 2; + switch_timeout *= 2; + } + + priv->destroy_effect + = clutter_effect_template_new (clutter_timeline_new_for_duration ( + destroy_timeout), + CLUTTER_ALPHA_SINE_INC); + + + priv->minimize_effect + = clutter_effect_template_new (clutter_timeline_new_for_duration ( + minimize_timeout), + CLUTTER_ALPHA_SINE_INC); + + priv->maximize_effect + = clutter_effect_template_new (clutter_timeline_new_for_duration ( + maximize_timeout), + CLUTTER_ALPHA_SINE_INC); + + priv->map_effect + = clutter_effect_template_new (clutter_timeline_new_for_duration ( + map_timeout), + CLUTTER_ALPHA_SINE_INC); + + priv->switch_workspace_effect + = clutter_effect_template_new (clutter_timeline_new_for_duration ( + switch_timeout), + CLUTTER_ALPHA_SINE_INC); +} + +static void +mutter_default_plugin_class_init (MutterDefaultPluginClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + MutterPluginClass *plugin_class = MUTTER_PLUGIN_CLASS (klass); + + gobject_class->finalize = mutter_default_plugin_finalize; + gobject_class->dispose = mutter_default_plugin_dispose; + gobject_class->constructed = mutter_default_plugin_constructed; + gobject_class->set_property = mutter_default_plugin_set_property; + gobject_class->get_property = mutter_default_plugin_get_property; + + plugin_class->map = map; + plugin_class->minimize = minimize; + plugin_class->maximize = maximize; + plugin_class->unmaximize = unmaximize; + plugin_class->destroy = destroy; + plugin_class->switch_workspace = switch_workspace; + plugin_class->kill_effect = kill_effect; + plugin_class->plugin_info = plugin_info; + + g_type_class_add_private (gobject_class, sizeof (MutterDefaultPluginPrivate)); +} + +static void +mutter_default_plugin_init (MutterDefaultPlugin *self) +{ + MutterDefaultPluginPrivate *priv; + + self->priv = priv = MUTTER_DEFAULT_PLUGIN_GET_PRIVATE (self); + + priv->info.name = "Default Effects"; + priv->info.version = "0.1"; + priv->info.author = "Intel Corp."; + priv->info.license = "GPL"; + priv->info.description = "This is an example of a plugin implementation."; +} /* @@ -102,8 +271,6 @@ typedef struct _ActorPrivate gboolean is_maximized : 1; } ActorPrivate; -static PluginState *plugin_state; - /* * Actor private data accessor */ @@ -134,53 +301,72 @@ get_actor_private (MutterWindow *actor) return priv; } +typedef struct SwitchWorkspaceData +{ + MutterPlugin *plugin; + const GList **actors; +} SwitchWorkspaceData; + static void on_switch_workspace_effect_complete (ClutterActor *group, gpointer data) { - PluginState *state = plugin_state; - GList *l = *((GList**)data); + SwitchWorkspaceData *sw_data = data; + MutterPlugin *plugin = sw_data->plugin; + MutterDefaultPluginPrivate *priv = MUTTER_DEFAULT_PLUGIN (plugin)->priv; + GList *l = *((GList**)sw_data->actors); MutterWindow *actor_for_cb = l->data; while (l) { ClutterActor *a = l->data; MutterWindow *mc_window = MUTTER_WINDOW (a); - ActorPrivate *priv = get_actor_private (mc_window); + ActorPrivate *apriv = get_actor_private (mc_window); - if (priv->orig_parent) + if (apriv->orig_parent) { - clutter_actor_reparent (a, priv->orig_parent); - priv->orig_parent = NULL; + clutter_actor_reparent (a, apriv->orig_parent); + apriv->orig_parent = NULL; } l = l->next; } - clutter_actor_destroy (state->desktop1); - clutter_actor_destroy (state->desktop2); + clutter_actor_destroy (priv->desktop1); + clutter_actor_destroy (priv->desktop2); - state->actors = NULL; - state->tml_switch_workspace1 = NULL; - state->tml_switch_workspace2 = NULL; - state->desktop1 = NULL; - state->desktop2 = NULL; + priv->actors = NULL; + priv->tml_switch_workspace1 = NULL; + priv->tml_switch_workspace2 = NULL; + priv->desktop1 = NULL; + priv->desktop2 = NULL; - mutter_plugin_effect_completed (mutter_get_plugin(), actor_for_cb, + g_free (data); + + mutter_plugin_effect_completed (plugin, actor_for_cb, MUTTER_PLUGIN_SWITCH_WORKSPACE); } static void -switch_workspace (const GList **actors, gint from, gint to, +switch_workspace (MutterPlugin *plugin, + const GList **actors, gint from, gint to, MetaMotionDirection direction) { - MutterPlugin *plugin = mutter_get_plugin(); - PluginState *state = plugin_state; + MutterDefaultPluginPrivate *priv = MUTTER_DEFAULT_PLUGIN (plugin)->priv; GList *l; gint n_workspaces; ClutterActor *workspace0 = clutter_group_new (); ClutterActor *workspace1 = clutter_group_new (); ClutterActor *stage; int screen_width, screen_height; + MetaScreen *screen = mutter_plugin_get_screen (plugin); + SwitchWorkspaceData *sw_data = g_new (SwitchWorkspaceData, 1); + + /* Must chain up first */ + MUTTER_PLUGIN_CLASS (mutter_default_plugin_parent_class)-> + switch_workspace (plugin, actors, from, to, direction); + + sw_data->plugin = plugin; + sw_data->actors = actors; stage = mutter_plugin_get_stage (plugin); @@ -201,19 +387,19 @@ switch_workspace (const GList **actors, gint from, gint to, if (from == to) { - mutter_plugin_effect_completed (mutter_get_plugin(), NULL, + mutter_plugin_effect_completed (plugin, NULL, MUTTER_PLUGIN_SWITCH_WORKSPACE); return; } - n_workspaces = g_list_length (plugin->work_areas); + n_workspaces = meta_screen_get_n_workspaces (screen); l = g_list_last (*((GList**) actors)); while (l) { MutterWindow *mc_window = l->data; - ActorPrivate *priv = get_actor_private (mc_window); + ActorPrivate *apriv = get_actor_private (mc_window); ClutterActor *window = CLUTTER_ACTOR (mc_window); gint win_workspace; @@ -227,7 +413,7 @@ switch_workspace (const GList **actors, gint from, gint to, clutter_actor_get_position (window, &x, &y); clutter_actor_get_size (window, &w, &h); - priv->orig_parent = clutter_actor_get_parent (window); + apriv->orig_parent = clutter_actor_get_parent (window); clutter_actor_reparent (window, win_workspace == to ? workspace1 : workspace0); @@ -237,30 +423,30 @@ switch_workspace (const GList **actors, gint from, gint to, else if (win_workspace < 0) { /* Sticky window */ - priv->orig_parent = NULL; + apriv->orig_parent = NULL; } else { /* Window on some other desktop */ clutter_actor_hide (window); - priv->orig_parent = NULL; + apriv->orig_parent = NULL; } l = l->prev; } - state->actors = (GList **)actors; - state->desktop1 = workspace0; - state->desktop2 = workspace1; + priv->actors = (GList **)actors; + priv->desktop1 = workspace0; + priv->desktop2 = workspace1; - state->tml_switch_workspace2 = - clutter_effect_scale (state->switch_workspace_effect, + priv->tml_switch_workspace2 = + clutter_effect_scale (priv->switch_workspace_effect, workspace1, 1.0, 1.0, on_switch_workspace_effect_complete, - (gpointer)actors); + (gpointer)sw_data); - state->tml_switch_workspace1 = - clutter_effect_scale (state->switch_workspace_effect, + priv->tml_switch_workspace1 = + clutter_effect_scale (priv->switch_workspace_effect, workspace0, 0.0, 0.0, NULL, NULL); } @@ -277,6 +463,7 @@ on_minimize_effect_complete (ClutterActor *actor, gpointer data) * Must reverse the effect of the effect; must hide it first to ensure * that the restoration will not be visible. */ + MutterPlugin *plugin = data; ActorPrivate *apriv; MutterWindow *mc_window = MUTTER_WINDOW (actor); @@ -292,7 +479,7 @@ on_minimize_effect_complete (ClutterActor *actor, gpointer data) CLUTTER_GRAVITY_NORTH_WEST); /* Now notify the manager that we are done with this effect */ - mutter_plugin_effect_completed (mutter_get_plugin(), mc_window, + mutter_plugin_effect_completed (plugin, mc_window, MUTTER_PLUGIN_MINIMIZE); } @@ -301,11 +488,15 @@ on_minimize_effect_complete (ClutterActor *actor, gpointer data) * completion). */ static void -minimize (MutterWindow *mc_window) +minimize (MutterPlugin *plugin, MutterWindow *mc_window) { - PluginState *state = plugin_state; - MetaCompWindowType type; - ClutterActor *actor = CLUTTER_ACTOR (mc_window); + MutterDefaultPluginPrivate *priv = MUTTER_DEFAULT_PLUGIN (plugin)->priv; + MetaCompWindowType type; + ClutterActor *actor = CLUTTER_ACTOR (mc_window); + + /* Must chain up first */ + MUTTER_PLUGIN_CLASS (mutter_default_plugin_parent_class)-> + minimize (plugin, mc_window); type = mutter_window_get_window_type (mc_window); @@ -318,16 +509,16 @@ minimize (MutterWindow *mc_window) clutter_actor_move_anchor_point_from_gravity (actor, CLUTTER_GRAVITY_CENTER); - apriv->tml_minimize = clutter_effect_scale (state->minimize_effect, + apriv->tml_minimize = clutter_effect_scale (priv->minimize_effect, actor, 0.0, 0.0, (ClutterEffectCompleteFunc) on_minimize_effect_complete, - NULL); + plugin); } else - mutter_plugin_effect_completed (mutter_get_plugin(), mc_window, + mutter_plugin_effect_completed (plugin, mc_window, MUTTER_PLUGIN_MINIMIZE); } @@ -341,6 +532,7 @@ on_maximize_effect_complete (ClutterActor *actor, gpointer data) /* * Must reverse the effect of the effect. */ + MutterPlugin * plugin = data; MutterWindow *mc_window = MUTTER_WINDOW (actor); ActorPrivate *apriv = get_actor_private (mc_window); @@ -352,7 +544,7 @@ on_maximize_effect_complete (ClutterActor *actor, gpointer data) CLUTTER_GRAVITY_NORTH_WEST); /* Now notify the manager that we are done with this effect */ - mutter_plugin_effect_completed (mutter_get_plugin(), mc_window, + mutter_plugin_effect_completed (plugin, mc_window, MUTTER_PLUGIN_MAXIMIZE); } @@ -365,9 +557,11 @@ on_maximize_effect_complete (ClutterActor *actor, gpointer data) * (Something like a sound would be more appropriate.) */ static void -maximize (MutterWindow *mc_window, +maximize (MutterPlugin *plugin, + MutterWindow *mc_window, gint end_x, gint end_y, gint end_width, gint end_height) { + MutterDefaultPluginPrivate *priv = MUTTER_DEFAULT_PLUGIN (plugin)->priv; MetaCompWindowType type; ClutterActor *actor = CLUTTER_ACTOR (mc_window); @@ -376,6 +570,10 @@ maximize (MutterWindow *mc_window, gint anchor_x = 0; gint anchor_y = 0; + /* Must chain up first */ + MUTTER_PLUGIN_CLASS (mutter_default_plugin_parent_class)-> + maximize (plugin, mc_window, end_x, end_y, end_width, end_height); + type = mutter_window_get_window_type (mc_window); if (type == META_COMP_WINDOW_NORMAL) @@ -404,18 +602,18 @@ maximize (MutterWindow *mc_window, clutter_actor_move_anchor_point (actor, anchor_x, anchor_y); apriv->tml_maximize = - clutter_effect_scale (plugin_state->maximize_effect, + clutter_effect_scale (priv->maximize_effect, actor, scale_x, scale_y, (ClutterEffectCompleteFunc) on_maximize_effect_complete, - NULL); + plugin); return; } - mutter_plugin_effect_completed (mutter_get_plugin(), mc_window, + mutter_plugin_effect_completed (plugin, mc_window, MUTTER_PLUGIN_MAXIMIZE); } @@ -425,11 +623,16 @@ maximize (MutterWindow *mc_window, * (Just a skeleton code.) */ static void -unmaximize (MutterWindow *mc_window, +unmaximize (MutterPlugin *plugin, + MutterWindow *mc_window, gint end_x, gint end_y, gint end_width, gint end_height) { MetaCompWindowType type = mutter_window_get_window_type (mc_window); + /* Must chain up first */ + MUTTER_PLUGIN_CLASS (mutter_default_plugin_parent_class)-> + unmaximize (plugin, mc_window, end_x, end_y, end_width, end_height); + if (type == META_COMP_WINDOW_NORMAL) { ActorPrivate *apriv = get_actor_private (mc_window); @@ -438,7 +641,7 @@ unmaximize (MutterWindow *mc_window, } /* Do this conditionally, if the effect requires completion callback. */ - mutter_plugin_effect_completed (mutter_get_plugin(), mc_window, + mutter_plugin_effect_completed (plugin, mc_window, MUTTER_PLUGIN_UNMAXIMIZE); } @@ -448,6 +651,7 @@ on_map_effect_complete (ClutterActor *actor, gpointer data) /* * Must reverse the effect of the effect. */ + MutterPlugin *plugin = data; MutterWindow *mc_window = MUTTER_WINDOW (actor); ActorPrivate *apriv = get_actor_private (mc_window); @@ -457,7 +661,7 @@ on_map_effect_complete (ClutterActor *actor, gpointer data) CLUTTER_GRAVITY_NORTH_WEST); /* Now notify the manager that we are done with this effect */ - mutter_plugin_effect_completed (mutter_get_plugin(), mc_window, MUTTER_PLUGIN_MAP); + mutter_plugin_effect_completed (plugin, mc_window, MUTTER_PLUGIN_MAP); } /* @@ -465,11 +669,16 @@ on_map_effect_complete (ClutterActor *actor, gpointer data) * completion). */ static void -map (MutterWindow *mc_window) +map (MutterPlugin *plugin, MutterWindow *mc_window) { + MutterDefaultPluginPrivate *priv = MUTTER_DEFAULT_PLUGIN (plugin)->priv; MetaCompWindowType type; ClutterActor *actor = CLUTTER_ACTOR (mc_window); + /* Must chain up first */ + MUTTER_PLUGIN_CLASS (mutter_default_plugin_parent_class)-> + map (plugin, mc_window); + type = mutter_window_get_window_type (mc_window); if (type == META_COMP_WINDOW_NORMAL) @@ -482,19 +691,19 @@ map (MutterWindow *mc_window) clutter_actor_set_scale (actor, 0.0, 0.0); clutter_actor_show (actor); - apriv->tml_map = clutter_effect_scale (plugin_state->map_effect, + apriv->tml_map = clutter_effect_scale (priv->map_effect, actor, 1.0, 1.0, (ClutterEffectCompleteFunc) on_map_effect_complete, - NULL); + plugin); apriv->is_minimized = FALSE; } else - mutter_plugin_effect_completed (mutter_get_plugin(), mc_window, + mutter_plugin_effect_completed (plugin, mc_window, MUTTER_PLUGIN_MAP); } @@ -505,7 +714,7 @@ map (MutterWindow *mc_window) static void on_destroy_effect_complete (ClutterActor *actor, gpointer data) { - MutterPlugin *plugin = mutter_get_plugin(); + MutterPlugin *plugin = data; MutterWindow *mc_window = MUTTER_WINDOW (actor); ActorPrivate *apriv = get_actor_private (mc_window); @@ -519,11 +728,16 @@ on_destroy_effect_complete (ClutterActor *actor, gpointer data) * Simple TV-out like effect. */ static void -destroy (MutterWindow *mc_window) +destroy (MutterPlugin *plugin, MutterWindow *mc_window) { + MutterDefaultPluginPrivate *priv = MUTTER_DEFAULT_PLUGIN (plugin)->priv; MetaCompWindowType type; ClutterActor *actor = CLUTTER_ACTOR (mc_window); + /* Must chain up first */ + MUTTER_PLUGIN_CLASS (mutter_default_plugin_parent_class)-> + destroy (plugin, mc_window); + type = mutter_window_get_window_type (mc_window); if (type == META_COMP_WINDOW_NORMAL) @@ -533,34 +747,34 @@ destroy (MutterWindow *mc_window) clutter_actor_move_anchor_point_from_gravity (actor, CLUTTER_GRAVITY_CENTER); - apriv->tml_destroy = clutter_effect_scale (plugin_state->destroy_effect, + apriv->tml_destroy = clutter_effect_scale (priv->destroy_effect, actor, 1.0, 0.0, (ClutterEffectCompleteFunc) on_destroy_effect_complete, - NULL); + plugin); } else - mutter_plugin_effect_completed (mutter_get_plugin(), mc_window, + mutter_plugin_effect_completed (plugin, mc_window, MUTTER_PLUGIN_DESTROY); } static void -kill_effect (MutterWindow *mc_window, gulong event) +kill_effect (MutterPlugin *plugin, MutterWindow *mc_window, gulong event) { ActorPrivate *apriv; ClutterActor *actor = CLUTTER_ACTOR (mc_window); if (event & MUTTER_PLUGIN_SWITCH_WORKSPACE) { - PluginState *state = plugin_state; + MutterDefaultPluginPrivate *priv = MUTTER_DEFAULT_PLUGIN (plugin)->priv; - if (state->tml_switch_workspace1) + if (priv->tml_switch_workspace1) { - clutter_timeline_stop (state->tml_switch_workspace1); - clutter_timeline_stop (state->tml_switch_workspace2); - on_switch_workspace_effect_complete (state->desktop1, state->actors); + clutter_timeline_stop (priv->tml_switch_workspace1); + clutter_timeline_stop (priv->tml_switch_workspace2); + on_switch_workspace_effect_complete (priv->desktop1, priv->actors); } if (!(event & ~MUTTER_PLUGIN_SWITCH_WORKSPACE)) @@ -597,144 +811,10 @@ kill_effect (MutterWindow *mc_window, gulong event) } } - -const gchar * g_module_check_init (GModule *module); -const gchar * -g_module_check_init (GModule *module) +static const MutterPluginInfo * +plugin_info (MutterPlugin *plugin) { - MutterPlugin *plugin = mutter_get_plugin (); + MutterDefaultPluginPrivate *priv = MUTTER_DEFAULT_PLUGIN (plugin)->priv; - /* Human readable name (for use in UI) */ - plugin->name = "Default Effects"; - - /* Plugin load time initialiser */ - plugin->do_init = do_init; - - /* Effect handlers */ - plugin->minimize = minimize; - plugin->destroy = destroy; - plugin->map = map; - plugin->maximize = maximize; - plugin->unmaximize = unmaximize; - plugin->switch_workspace = switch_workspace; - plugin->kill_effect = kill_effect; - - /* The reload handler */ - plugin->reload = reload; - - return NULL; + return &priv->info; } - -/* - * Core of the plugin init function, called for initial initialization and - * by the reload() function. Returns TRUE on success. - */ -static gboolean -do_init (const char *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; - - plugin_state = g_new0 (PluginState, 1); - - if (params) - { - if (strstr (params, "debug")) - { - g_debug ("%s: Entering debug mode.", mutter_get_plugin()->name); - - plugin_state->debug_mode = TRUE; - - /* - * Double the effect duration to make them easier to observe. - */ - destroy_timeout *= 2; - minimize_timeout *= 2; - maximize_timeout *= 2; - map_timeout *= 2; - switch_timeout *= 2; - } - } - - plugin_state->destroy_effect - = clutter_effect_template_new (clutter_timeline_new_for_duration ( - destroy_timeout), - CLUTTER_ALPHA_SINE_INC); - - - plugin_state->minimize_effect - = clutter_effect_template_new (clutter_timeline_new_for_duration ( - minimize_timeout), - CLUTTER_ALPHA_SINE_INC); - - plugin_state->maximize_effect - = clutter_effect_template_new (clutter_timeline_new_for_duration ( - maximize_timeout), - CLUTTER_ALPHA_SINE_INC); - - plugin_state->map_effect - = clutter_effect_template_new (clutter_timeline_new_for_duration ( - map_timeout), - CLUTTER_ALPHA_SINE_INC); - - plugin_state->switch_workspace_effect - = clutter_effect_template_new (clutter_timeline_new_for_duration ( - switch_timeout), - CLUTTER_ALPHA_SINE_INC); - - return TRUE; -} - -static void -free_plugin_private (PluginState *state) -{ - if (!state) - return; - - g_object_unref (state->destroy_effect); - g_object_unref (state->minimize_effect); - g_object_unref (state->maximize_effect); - g_object_unref (state->switch_workspace_effect); - - g_free (state); -} - -/* - * Called by the plugin manager when we stuff like the command line parameters - * changed. - */ -static gboolean -reload (const char *params) -{ - PluginState *state; - - state = plugin_state; - - if (do_init (params)) - { - /* Success; free the old state */ - free_plugin_private (plugin_state); - return TRUE; - } - else - { - /* Fail -- fall back to the old state. */ - plugin_state = state; - } - - return FALSE; -} - -/* - * GModule unload function -- do any cleanup required. - */ -G_MODULE_EXPORT void g_module_unload (GModule *module); -G_MODULE_EXPORT void -g_module_unload (GModule *module) -{ - free_plugin_private (plugin_state); -} - diff --git a/src/include/mutter-plugin.h b/src/include/mutter-plugin.h index e85760dc6..a0547f9a5 100644 --- a/src/include/mutter-plugin.h +++ b/src/include/mutter-plugin.h @@ -33,20 +33,8 @@ #include /* - * This file defines the plugin API. - * - * Effects plugin is shared library loaded via g_module_open(); 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 MutterPlugin struct. - */ - -typedef struct MutterPlugin MutterPlugin; - -/* - * Effect flags: identify events that the plugin can handle, used by kill_effect - * function. + * FIXME -- move these to a private include + * Required by plugin manager. */ #define MUTTER_PLUGIN_MINIMIZE (1<<0) #define MUTTER_PLUGIN_MAXIMIZE (1<<1) @@ -57,19 +45,96 @@ typedef struct MutterPlugin MutterPlugin; #define MUTTER_PLUGIN_ALL_EFFECTS (~0) -#define MUTTER_DECLARE_PLUGIN() G_MODULE_EXPORT MutterPlugin mutter_plugin = \ - { \ - METACITY_MAJOR_VERSION, \ - METACITY_MINOR_VERSION, \ - METACITY_MICRO_VERSION, \ - METACITY_CLUTTER_PLUGIN_API_VERSION \ - }; \ - static inline MutterPlugin * mutter_get_plugin () \ - { \ - return &mutter_plugin; \ - } +#define MUTTER_TYPE_PLUGIN (mutter_plugin_get_type ()) +#define MUTTER_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MUTTER_TYPE_PLUGIN, MutterPlugin)) +#define MUTTER_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MUTTER_TYPE_PLUGIN, MutterPluginClass)) +#define MUTTER_IS_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MUTTER_PLUGIN_TYPE)) +#define MUTTER_IS_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MUTTER_TYPE_PLUGIN)) +#define MUTTER_PLUGIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MUTTER_TYPE_PLUGIN, MutterPluginClass)) -struct MutterPlugin +typedef struct _MutterPlugin MutterPlugin; +typedef struct _MutterPluginClass MutterPluginClass; +typedef struct _MutterPluginVersion MutterPluginVersion; +typedef struct _MutterPluginInfo MutterPluginInfo; +typedef struct _MutterPluginPrivate MutterPluginPrivate; + +struct _MutterPlugin +{ + GObject parent; + + MutterPluginPrivate *priv; +}; + +struct _MutterPluginClass +{ + GObjectClass parent_class; + + void (*minimize) (MutterPlugin *plugin, + MutterWindow *actor); + + void (*maximize) (MutterPlugin *plugin, + MutterWindow *actor, + gint x, + gint y, + gint width, + gint height); + + void (*unmaximize) (MutterPlugin *plugin, + MutterWindow *actor, + gint x, + gint y, + gint width, + gint height); + + void (*map) (MutterPlugin *plugin, + MutterWindow *actor); + + void (*destroy) (MutterPlugin *plugin, + MutterWindow *actor); + + void (*switch_workspace) (MutterPlugin *plugin, + 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) (MutterPlugin *plugin, + MutterWindow *actor, + gulong events); + + /* General XEvent filter. This is fired *before* metacity itself handles + * an event. Return TRUE to block any further processing. + */ + gboolean (*xevent_filter) (MutterPlugin *plugin, + XEvent *event); + + const MutterPluginInfo * (*plugin_info) (MutterPlugin *plugin); +}; + +struct _MutterPluginInfo +{ + const gchar *name; + const gchar *version; + const gchar *author; + const gchar *license; + const gchar *description; +}; + +GType mutter_plugin_get_type (void); + +gulong mutter_plugin_features (MutterPlugin *plugin); +gboolean mutter_plugin_disabled (MutterPlugin *plugin); +gboolean mutter_plugin_running (MutterPlugin *plugin); +gboolean mutter_plugin_debug_mode (MutterPlugin *plugin); +const MutterPluginInfo * mutter_plugin_get_info (MutterPlugin *plugin); + +struct _MutterPluginVersion { /* * Version information; the first three numbers match the Metacity version @@ -83,134 +148,81 @@ struct MutterPlugin /* * 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). + * the one used by it (see clutter-plugins/default.c for sample code). */ guint version_api; - -#ifndef MUTTER_BUILDING_PLUGIN - const -#endif - gchar *name; /* Human-readable name for UI */ - - /* - * This function is called once the plugin has been loaded. - * - * @params is a string containing additional parameters for the plugin and is - * specified after the plugin 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 - * - * FIXME: ^^^ Instead of configuring in terms of what should be - * disabled, and needing a mechanism for coping with the user - * mistakenly not disabling the right things, it might be neater - * if plugins were enabled on a per effect basis in the first - * place. I.e. in gconf we could have effect:plugin key value - * pairs. - */ - - gboolean (*do_init) (const char *params); - - /* - * 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) (MutterWindow *actor); - - void (*maximize) (MutterWindow *actor, - gint x, - gint y, - gint width, - gint height); - - void (*unmaximize) (MutterWindow *actor, - gint x, - gint y, - gint width, - gint height); - - void (*map) (MutterWindow *actor); - - void (*destroy) (MutterWindow *actor); - - /* - * Each actor in the list has a workspace number attached to it using - * g_object_set_data() with key MUTTER_PLUGIN_WORKSPACE_KEY; - * workspace < 0 indicates the window is sticky (i.e., on all desktops). - * TODO: Add accessor for sticky bit in new MutterWindow structure - */ - 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) (MutterWindow *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) (const char *params); - - /* General XEvent filter. This is fired *before* metacity itself handles - * an event. Return TRUE to block any further processing. - */ - gboolean (*xevent_filter) (XEvent *event); - - /* List of PluginWorkspaceRectangles defining the geometry of individual - * workspaces. */ - GList *work_areas; - - 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; }; -#ifndef MUTTER_PLUGIN_FROM_MANAGER_ -static inline MutterPlugin *mutter_get_plugin (); -#endif +/* + * Convenience macro to set up the plugin type. Based on GEdit. + */ +#define MUTTER_PLUGIN_DECLARE(ObjectName, object_name) \ + G_MODULE_EXPORT MutterPluginVersion mutter_plugin_version = \ + { \ + METACITY_MAJOR_VERSION, \ + METACITY_MINOR_VERSION, \ + METACITY_MICRO_VERSION, \ + METACITY_CLUTTER_PLUGIN_API_VERSION \ + }; \ + \ + static GType g_define_type_id = 0; \ + \ + /* Prototypes */ \ + G_MODULE_EXPORT \ + GType object_name##_get_type (void); \ + \ + G_MODULE_EXPORT \ + GType object_name##_register_type (GTypeModule *type_module); \ + \ + G_MODULE_EXPORT \ + GType mutter_plugin_register_type (GTypeModule *type_module); \ + \ + GType \ + object_name##_get_type () \ + { \ + return g_define_type_id; \ + } \ + \ + static void object_name##_init (ObjectName *self); \ + static void object_name##_class_init (ObjectName##Class *klass); \ + static gpointer object_name##_parent_class = NULL; \ + static void object_name##_class_intern_init (gpointer klass) \ + { \ + object_name##_parent_class = g_type_class_peek_parent (klass); \ + object_name##_class_init ((ObjectName##Class *) klass); \ + } \ + \ + GType \ + object_name##_register_type (GTypeModule *type_module) \ + { \ + static const GTypeInfo our_info = \ + { \ + sizeof (ObjectName##Class), \ + NULL, /* base_init */ \ + NULL, /* base_finalize */ \ + (GClassInitFunc) object_name##_class_intern_init, \ + NULL, \ + NULL, /* class_data */ \ + sizeof (ObjectName), \ + 0, /* n_preallocs */ \ + (GInstanceInitFunc) object_name##_init \ + }; \ + \ + g_define_type_id = g_type_module_register_type (type_module, \ + MUTTER_TYPE_PLUGIN, \ + #ObjectName, \ + &our_info, \ + 0); \ + \ + \ + return g_define_type_id; \ + } \ + \ + G_MODULE_EXPORT GType \ + mutter_plugin_register_type (GTypeModule *type_module) \ + { \ + return object_name##_register_type (type_module); \ + } \ void mutter_plugin_effect_completed (MutterPlugin *plugin,