1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2
3 /*
4 * Copyright (c) 2008 Intel Corp.
5 *
6 * Author: Tomas Frydrych <tf@linux.intel.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the
11 * License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA
21 * 02110-1335, USA.
22 */
23
24 /**
25 * SECTION:meta-plugin
26 * @title: MetaPlugin
27 * @short_description: Entry point for plugins
28 */
29
30 #include <meta/meta-plugin.h>
31 #include "meta-plugin-manager.h"
32 #include <meta/screen.h>
33 #include <meta/display.h>
34
35 #include <string.h>
36 #include <X11/Xlib.h>
37 #include <X11/extensions/Xfixes.h>
38 #include <X11/extensions/shape.h>
39 #include <clutter/x11/clutter-x11.h>
40
41 #include "compositor-private.h"
42 #include "meta-window-actor-private.h"
43
44 G_DEFINE_ABSTRACT_TYPE (MetaPlugin, meta_plugin, G_TYPE_OBJECT);
45
46 #define META_PLUGIN_GET_PRIVATE(obj) \
47 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), META_TYPE_PLUGIN, MetaPluginPrivate))
48
49 enum
50 {
51 PROP_0,
52 PROP_SCREEN,
53 PROP_DEBUG_MODE,
54 };
55
56 struct _MetaPluginPrivate
57 {
58 MetaScreen *screen;
59
60 gint running;
61 gboolean debug : 1;
62 };
63
64 static void
meta_plugin_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)65 meta_plugin_set_property (GObject *object,
66 guint prop_id,
67 const GValue *value,
68 GParamSpec *pspec)
69 {
70 MetaPluginPrivate *priv = META_PLUGIN (object)->priv;
71
72 switch (prop_id)
73 {
74 case PROP_SCREEN:
75 priv->screen = g_value_get_object (value);
76 break;
77 case PROP_DEBUG_MODE:
78 priv->debug = g_value_get_boolean (value);
79 break;
80 default:
81 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
82 break;
83 }
84 }
85
86 static void
meta_plugin_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)87 meta_plugin_get_property (GObject *object,
88 guint prop_id,
89 GValue *value,
90 GParamSpec *pspec)
91 {
92 MetaPluginPrivate *priv = META_PLUGIN (object)->priv;
93
94 switch (prop_id)
95 {
96 case PROP_SCREEN:
97 g_value_set_object (value, priv->screen);
98 break;
99 case PROP_DEBUG_MODE:
100 g_value_set_boolean (value, priv->debug);
101 break;
102 default:
103 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
104 break;
105 }
106 }
107
108
109 static void
meta_plugin_class_init(MetaPluginClass * klass)110 meta_plugin_class_init (MetaPluginClass *klass)
111 {
112 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
113
114 gobject_class->set_property = meta_plugin_set_property;
115 gobject_class->get_property = meta_plugin_get_property;
116
117 g_object_class_install_property (gobject_class,
118 PROP_SCREEN,
119 g_param_spec_object ("screen",
120 "MetaScreen",
121 "MetaScreen",
122 META_TYPE_SCREEN,
123 G_PARAM_READWRITE));
124
125 g_object_class_install_property (gobject_class,
126 PROP_DEBUG_MODE,
127 g_param_spec_boolean ("debug-mode",
128 "Debug Mode",
129 "Debug Mode",
130 FALSE,
131 G_PARAM_READABLE));
132
133 g_type_class_add_private (gobject_class, sizeof (MetaPluginPrivate));
134 }
135
136 static void
meta_plugin_init(MetaPlugin * self)137 meta_plugin_init (MetaPlugin *self)
138 {
139 MetaPluginPrivate *priv;
140
141 self->priv = priv = META_PLUGIN_GET_PRIVATE (self);
142 }
143
144 gboolean
meta_plugin_running(MetaPlugin * plugin)145 meta_plugin_running (MetaPlugin *plugin)
146 {
147 MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
148
149 return (priv->running > 0);
150 }
151
152 gboolean
meta_plugin_debug_mode(MetaPlugin * plugin)153 meta_plugin_debug_mode (MetaPlugin *plugin)
154 {
155 MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
156
157 return priv->debug;
158 }
159
160 const MetaPluginInfo *
meta_plugin_get_info(MetaPlugin * plugin)161 meta_plugin_get_info (MetaPlugin *plugin)
162 {
163 MetaPluginClass *klass = META_PLUGIN_GET_CLASS (plugin);
164
165 if (klass && klass->plugin_info)
166 return klass->plugin_info (plugin);
167
168 return NULL;
169 }
170
171 /**
172 * _meta_plugin_effect_started:
173 * @plugin: the plugin
174 *
175 * Mark that an effect has started for the plugin. This is called
176 * internally by MetaPluginManager.
177 */
178 void
_meta_plugin_effect_started(MetaPlugin * plugin)179 _meta_plugin_effect_started (MetaPlugin *plugin)
180 {
181 MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
182
183 priv->running++;
184 }
185
186 void
meta_plugin_switch_workspace_completed(MetaPlugin * plugin)187 meta_plugin_switch_workspace_completed (MetaPlugin *plugin)
188 {
189 MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
190
191 MetaScreen *screen = priv->screen;
192
193 if (priv->running-- < 0)
194 {
195 g_warning ("Error in running effect accounting, adjusting.");
196 priv->running = 0;
197 }
198
199 meta_switch_workspace_completed (screen);
200 }
201
202 static void
meta_plugin_window_effect_completed(MetaPlugin * plugin,MetaWindowActor * actor,unsigned long event)203 meta_plugin_window_effect_completed (MetaPlugin *plugin,
204 MetaWindowActor *actor,
205 unsigned long event)
206 {
207 MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
208
209 if (priv->running-- < 0)
210 {
211 g_warning ("Error in running effect accounting, adjusting.");
212 priv->running = 0;
213 }
214
215 if (!actor)
216 {
217 const MetaPluginInfo *info;
218 const gchar *name = NULL;
219
220 if (plugin && (info = meta_plugin_get_info (plugin)))
221 name = info->name;
222
223 g_warning ("Plugin [%s] passed NULL for actor!",
224 name ? name : "unknown");
225 }
226
227 meta_window_actor_effect_completed (actor, event);
228 }
229
230 void
meta_plugin_minimize_completed(MetaPlugin * plugin,MetaWindowActor * actor)231 meta_plugin_minimize_completed (MetaPlugin *plugin,
232 MetaWindowActor *actor)
233 {
234 meta_plugin_window_effect_completed (plugin, actor, META_PLUGIN_MINIMIZE);
235 }
236
237 void
meta_plugin_maximize_completed(MetaPlugin * plugin,MetaWindowActor * actor)238 meta_plugin_maximize_completed (MetaPlugin *plugin,
239 MetaWindowActor *actor)
240 {
241 meta_plugin_window_effect_completed (plugin, actor, META_PLUGIN_MAXIMIZE);
242 }
243
244 void
meta_plugin_unmaximize_completed(MetaPlugin * plugin,MetaWindowActor * actor)245 meta_plugin_unmaximize_completed (MetaPlugin *plugin,
246 MetaWindowActor *actor)
247 {
248 meta_plugin_window_effect_completed (plugin, actor, META_PLUGIN_UNMAXIMIZE);
249 }
250
251 void
meta_plugin_tile_completed(MetaPlugin * plugin,MetaWindowActor * actor)252 meta_plugin_tile_completed (MetaPlugin *plugin,
253 MetaWindowActor *actor)
254 {
255 meta_plugin_window_effect_completed (plugin, actor, META_PLUGIN_TILE);
256 }
257
258 void
meta_plugin_map_completed(MetaPlugin * plugin,MetaWindowActor * actor)259 meta_plugin_map_completed (MetaPlugin *plugin,
260 MetaWindowActor *actor)
261 {
262 meta_plugin_window_effect_completed (plugin, actor, META_PLUGIN_MAP);
263 }
264
265 void
meta_plugin_destroy_completed(MetaPlugin * plugin,MetaWindowActor * actor)266 meta_plugin_destroy_completed (MetaPlugin *plugin,
267 MetaWindowActor *actor)
268 {
269 meta_plugin_window_effect_completed (plugin, actor, META_PLUGIN_DESTROY);
270 }
271
272 /**
273 * meta_plugin_begin_modal:
274 * @plugin: a #MetaPlugin
275 * @grab_window: the X window to grab the keyboard and mouse on
276 * @cursor: the cursor to use for the pointer grab, or None,
277 * to use the normal cursor for the grab window and
278 * its descendants.
279 * @options: flags that modify the behavior of the modal grab
280 * @timestamp: the timestamp used for establishing grabs
281 *
282 * This function is used to grab the keyboard and mouse for the exclusive
283 * use of the plugin. Correct operation requires that both the keyboard
284 * and mouse are grabbed, or thing will break. (In particular, other
285 * passive X grabs in Meta can trigger but not be handled by the normal
286 * keybinding handling code.) However, the plugin can establish the keyboard
287 * and/or mouse grabs ahead of time and pass in the
288 * %META_MODAL_POINTER_ALREADY_GRABBED and/or %META_MODAL_KEYBOARD_ALREADY_GRABBED
289 * options. This facility is provided for two reasons: first to allow using
290 * this function to establish modality after a passive grab, and second to
291 * allow using obscure features of XGrabPointer() and XGrabKeyboard() without
292 * having to add them to this API.
293 *
294 * Return value: whether we successfully grabbed the keyboard and
295 * mouse and made the plugin modal.
296 */
297 gboolean
meta_plugin_begin_modal(MetaPlugin * plugin,Window grab_window,Cursor cursor,MetaModalOptions options,guint32 timestamp)298 meta_plugin_begin_modal (MetaPlugin *plugin,
299 Window grab_window,
300 Cursor cursor,
301 MetaModalOptions options,
302 guint32 timestamp)
303 {
304 MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
305
306 return meta_begin_modal_for_plugin (priv->screen, plugin,
307 grab_window, cursor, options, timestamp);
308 }
309
310 /**
311 * meta_plugin_end_modal:
312 * @plugin: a #MetaPlugin
313 * @timestamp: the time used for releasing grabs
314 *
315 * Ends the modal operation begun with meta_plugin_begin_modal(). This
316 * ungrabs both the mouse and keyboard even when
317 * %META_MODAL_POINTER_ALREADY_GRABBED or
318 * %META_MODAL_KEYBOARD_ALREADY_GRABBED were provided as options
319 * when beginnning the modal operation.
320 */
321 void
meta_plugin_end_modal(MetaPlugin * plugin,guint32 timestamp)322 meta_plugin_end_modal (MetaPlugin *plugin,
323 guint32 timestamp)
324 {
325 MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
326
327 meta_end_modal_for_plugin (priv->screen, plugin, timestamp);
328 }
329
330 /**
331 * meta_plugin_get_screen:
332 * @plugin: a #MetaPlugin
333 *
334 * Gets the #MetaScreen corresponding to a plugin. Each plugin instance
335 * is associated with exactly one screen; if Metacity is managing
336 * multiple screens, multiple plugin instances will be created.
337 *
338 * Return value: (transfer none): the #MetaScreen for the plugin
339 */
340 MetaScreen *
meta_plugin_get_screen(MetaPlugin * plugin)341 meta_plugin_get_screen (MetaPlugin *plugin)
342 {
343 MetaPluginPrivate *priv = META_PLUGIN (plugin)->priv;
344
345 return priv->screen;
346 }
347