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