GObjectified MutterPlugin.

This commit is contained in:
Tomas Frydrych 2008-12-17 09:33:56 +00:00
parent 57a2d20d61
commit c61eb77a70
10 changed files with 1474 additions and 850 deletions

View File

@ -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])

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,206 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (c) 2008 Intel Corp.
*
* Author: Tomas Frydrych <tf@linux.intel.com>
*
* 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 <gmodule.h>
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 *)&register_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;
}

View File

@ -0,0 +1,57 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (c) 2008 Intel Corp.
*
* Author: Tomas Frydrych <tf@linux.intel.com>
*
* 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 <glib-object.h>
#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

View File

@ -26,215 +26,52 @@
#include "prefs.h"
#include "errors.h"
#include "workspace.h"
#include "mutter-module.h"
#include <gmodule.h>
#include <string.h>
#include <X11/Xlib.h>
#include <X11/extensions/Xfixes.h>
#include <X11/extensions/shape.h>
#include <clutter/x11/clutter-x11.h>
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;
}

View File

@ -0,0 +1,574 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (c) 2008 Intel Corp.
*
* Author: Tomas Frydrych <tf@linux.intel.com>
*
* 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 <string.h>
#include <X11/Xlib.h>
#include <X11/extensions/Xfixes.h>
#include <X11/extensions/shape.h>
#include <clutter/x11/clutter-x11.h>
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;
}

View File

@ -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)

View File

@ -21,7 +21,6 @@
* 02111-1307, USA.
*/
#define MUTTER_BUILDING_PLUGIN 1
#include "mutter-plugin.h"
#include <libintl.h>
@ -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);
}

View File

@ -33,20 +33,8 @@
#include <gmodule.h>
/*
* 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,