No issues found
1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2
3 /*
4 * Copyright (c) 2008 Red Hat, Inc.
5 * Copyright (c) 2008 Intel Corp.
6 *
7 * Based on plugin skeleton by:
8 * Author: Tomas Frydrych <tf@linux.intel.com>
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License as
12 * published by the Free Software Foundation; either version 2 of the
13 * License, or (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
23 * 02111-1307, USA.
24 */
25
26 #include "config.h"
27
28 #include <stdlib.h>
29 #include <string.h>
30
31 #include <clutter/clutter.h>
32 #include <clutter/x11/clutter-x11.h>
33 #include <GL/glx.h>
34 #include <GL/glxext.h>
35 #include <gjs/gjs.h>
36 #include <meta/display.h>
37 #include <meta/meta-plugin.h>
38
39 #include "shell-global-private.h"
40 #include "shell-perf-log.h"
41 #include "shell-wm-private.h"
42
43 static void gnome_shell_plugin_start (MetaPlugin *plugin);
44 static void gnome_shell_plugin_minimize (MetaPlugin *plugin,
45 MetaWindowActor *actor);
46 static void gnome_shell_plugin_maximize (MetaPlugin *plugin,
47 MetaWindowActor *actor,
48 gint x,
49 gint y,
50 gint width,
51 gint height);
52 static void gnome_shell_plugin_unmaximize (MetaPlugin *plugin,
53 MetaWindowActor *actor,
54 gint x,
55 gint y,
56 gint width,
57 gint height);
58 static void gnome_shell_plugin_map (MetaPlugin *plugin,
59 MetaWindowActor *actor);
60 static void gnome_shell_plugin_destroy (MetaPlugin *plugin,
61 MetaWindowActor *actor);
62
63 static void gnome_shell_plugin_switch_workspace (MetaPlugin *plugin,
64 gint from,
65 gint to,
66 MetaMotionDirection direction);
67
68 static void gnome_shell_plugin_kill_window_effects (MetaPlugin *plugin,
69 MetaWindowActor *actor);
70 static void gnome_shell_plugin_kill_switch_workspace (MetaPlugin *plugin);
71
72
73 static gboolean gnome_shell_plugin_xevent_filter (MetaPlugin *plugin,
74 XEvent *event);
75 static const MetaPluginInfo *gnome_shell_plugin_plugin_info (MetaPlugin *plugin);
76
77
78 #define GNOME_TYPE_SHELL_PLUGIN (gnome_shell_plugin_get_type ())
79 #define GNOME_SHELL_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GNOME_TYPE_SHELL_PLUGIN, GnomeShellPlugin))
80 #define GNOME_SHELL_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GNOME_TYPE_SHELL_PLUGIN, GnomeShellPluginClass))
81 #define GNOME_IS_SHELL_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GNOME_SHELL_PLUGIN_TYPE))
82 #define GNOME_IS_SHELL_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GNOME_TYPE_SHELL_PLUGIN))
83 #define GNOME_SHELL_PLUGIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GNOME_TYPE_SHELL_PLUGIN, GnomeShellPluginClass))
84
85 typedef struct _GnomeShellPlugin GnomeShellPlugin;
86 typedef struct _GnomeShellPluginClass GnomeShellPluginClass;
87
88 struct _GnomeShellPlugin
89 {
90 MetaPlugin parent;
91
92 Atom panel_action;
93 Atom panel_action_run_dialog;
94 Atom panel_action_main_menu;
95
96 int glx_error_base;
97 int glx_event_base;
98 guint have_swap_event : 1;
99
100 ShellGlobal *global;
101 };
102
103 struct _GnomeShellPluginClass
104 {
105 MetaPluginClass parent_class;
106 };
107
108 GType gnome_shell_plugin_get_type (void);
109
110 G_DEFINE_TYPE (GnomeShellPlugin, gnome_shell_plugin, META_TYPE_PLUGIN)
111
112 static void
113 gnome_shell_plugin_class_init (GnomeShellPluginClass *klass)
114 {
115 MetaPluginClass *plugin_class = META_PLUGIN_CLASS (klass);
116
117 plugin_class->start = gnome_shell_plugin_start;
118 plugin_class->map = gnome_shell_plugin_map;
119 plugin_class->minimize = gnome_shell_plugin_minimize;
120 plugin_class->maximize = gnome_shell_plugin_maximize;
121 plugin_class->unmaximize = gnome_shell_plugin_unmaximize;
122 plugin_class->destroy = gnome_shell_plugin_destroy;
123
124 plugin_class->switch_workspace = gnome_shell_plugin_switch_workspace;
125
126 plugin_class->kill_window_effects = gnome_shell_plugin_kill_window_effects;
127 plugin_class->kill_switch_workspace = gnome_shell_plugin_kill_switch_workspace;
128
129 plugin_class->xevent_filter = gnome_shell_plugin_xevent_filter;
130 plugin_class->plugin_info = gnome_shell_plugin_plugin_info;
131 }
132
133 static void
134 gnome_shell_plugin_init (GnomeShellPlugin *shell_plugin)
135 {
136 }
137
138 static void
139 gnome_shell_plugin_start (MetaPlugin *plugin)
140 {
141 GnomeShellPlugin *shell_plugin = GNOME_SHELL_PLUGIN (plugin);
142 MetaScreen *screen;
143 MetaDisplay *display;
144 Display *xdisplay;
145 GError *error = NULL;
146 int status;
147 const char *glx_extensions;
148 GjsContext *gjs_context;
149
150 screen = meta_plugin_get_screen (plugin);
151 display = meta_screen_get_display (screen);
152
153 xdisplay = meta_display_get_xdisplay (display);
154
155 glXQueryExtension (xdisplay,
156 &shell_plugin->glx_error_base,
157 &shell_plugin->glx_event_base);
158
159 glx_extensions = glXQueryExtensionsString (xdisplay,
160 meta_screen_get_screen_number (screen));
161 shell_plugin->have_swap_event = strstr (glx_extensions, "GLX_INTEL_swap_event") != NULL;
162
163 shell_perf_log_define_event (shell_perf_log_get_default (),
164 "glx.swapComplete",
165 "GL buffer swap complete event received (with timestamp of completion)",
166 "x");
167
168 shell_plugin->global = shell_global_get ();
169 _shell_global_set_plugin (shell_plugin->global, META_PLUGIN (shell_plugin));
170
171 gjs_context = _shell_global_get_gjs_context (shell_plugin->global);
172
173 if (!gjs_context_eval (gjs_context,
174 "imports.ui.environment.init();"
175 "imports.ui.main.start();",
176 -1,
177 "<main>",
178 &status,
179 &error))
180 {
181 g_message ("Execution of main.js threw exception: %s", error->message);
182 g_error_free (error);
183 /* We just exit() here, since in a development environment you'll get the
184 * error in your shell output, and it's way better than a busted WM,
185 * which typically manifests as a white screen.
186 *
187 * In production, we shouldn't crash =) But if we do, we should get
188 * restarted by the session infrastructure, which is likely going
189 * to be better than some undefined state.
190 *
191 * If there was a generic "hook into bug-buddy for non-C crashes"
192 * infrastructure, here would be the place to put it.
193 */
194 exit (1);
195 }
196 }
197
198 static ShellWM *
199 get_shell_wm (void)
200 {
201 ShellWM *wm;
202
203 g_object_get (shell_global_get (),
204 "window-manager", &wm,
205 NULL);
206 /* drop extra ref added by g_object_get */
207 g_object_unref (wm);
208
209 return wm;
210 }
211
212 static void
213 gnome_shell_plugin_minimize (MetaPlugin *plugin,
214 MetaWindowActor *actor)
215 {
216 _shell_wm_minimize (get_shell_wm (),
217 actor);
218
219 }
220
221 static void
222 gnome_shell_plugin_maximize (MetaPlugin *plugin,
223 MetaWindowActor *actor,
224 gint x,
225 gint y,
226 gint width,
227 gint height)
228 {
229 _shell_wm_maximize (get_shell_wm (),
230 actor, x, y, width, height);
231 }
232
233 static void
234 gnome_shell_plugin_unmaximize (MetaPlugin *plugin,
235 MetaWindowActor *actor,
236 gint x,
237 gint y,
238 gint width,
239 gint height)
240 {
241 _shell_wm_unmaximize (get_shell_wm (),
242 actor, x, y, width, height);
243 }
244
245 static void
246 gnome_shell_plugin_map (MetaPlugin *plugin,
247 MetaWindowActor *actor)
248 {
249 _shell_wm_map (get_shell_wm (),
250 actor);
251 }
252
253 static void
254 gnome_shell_plugin_destroy (MetaPlugin *plugin,
255 MetaWindowActor *actor)
256 {
257 _shell_wm_destroy (get_shell_wm (),
258 actor);
259 }
260
261 static void
262 gnome_shell_plugin_switch_workspace (MetaPlugin *plugin,
263 gint from,
264 gint to,
265 MetaMotionDirection direction)
266 {
267 _shell_wm_switch_workspace (get_shell_wm(), from, to, direction);
268 }
269
270 static void
271 gnome_shell_plugin_kill_window_effects (MetaPlugin *plugin,
272 MetaWindowActor *actor)
273 {
274 _shell_wm_kill_window_effects (get_shell_wm(), actor);
275 }
276
277 static void
278 gnome_shell_plugin_kill_switch_workspace (MetaPlugin *plugin)
279 {
280 _shell_wm_kill_switch_workspace (get_shell_wm());
281 }
282
283 static gboolean
284 gnome_shell_plugin_xevent_filter (MetaPlugin *plugin,
285 XEvent *xev)
286 {
287 MetaScreen *screen = meta_plugin_get_screen (plugin);
288 ClutterStage *stage = CLUTTER_STAGE (meta_get_stage_for_screen (screen));
289
290 GnomeShellPlugin *shell_plugin = GNOME_SHELL_PLUGIN (plugin);
291 #ifdef GLX_INTEL_swap_event
292 if (shell_plugin->have_swap_event &&
293 xev->type == (shell_plugin->glx_event_base + GLX_BufferSwapComplete))
294 {
295 GLXBufferSwapComplete *swap_complete_event;
296 swap_complete_event = (GLXBufferSwapComplete *)xev;
297
298 /* Buggy early versions of the INTEL_swap_event implementation in Mesa
299 * can send this with a ust of 0. Simplify life for consumers
300 * by ignoring such events */
301 if (swap_complete_event->ust != 0)
302 shell_perf_log_event_x (shell_perf_log_get_default (),
303 "glx.swapComplete",
304 swap_complete_event->ust);
305 }
306 #endif
307
308 if ((xev->xany.type == EnterNotify || xev->xany.type == LeaveNotify)
309 && xev->xcrossing.window == clutter_x11_get_stage_window (stage))
310 {
311 /* If the pointer enters a child of the stage window (eg, a
312 * trayicon), we want to consider it to still be in the stage,
313 * so don't let Clutter see the event.
314 */
315 if (xev->xcrossing.detail == NotifyInferior)
316 return TRUE;
317
318 /* If the pointer is grabbed by a window it is not currently in,
319 * filter that out as well. In particular, if a trayicon grabs
320 * the pointer after a click on its label, we don't want to hide
321 * the message tray. Filtering out this event will leave Clutter
322 * out of sync, but that happens fairly often with grabs, and we
323 * can work around it. (Eg, shell_global_sync_pointer().)
324 */
325 if (xev->xcrossing.mode == NotifyGrab &&
326 (xev->xcrossing.detail == NotifyNonlinear ||
327 xev->xcrossing.detail == NotifyNonlinearVirtual))
328 return TRUE;
329 }
330
331 /*
332 * Pass the event to shell-global
333 */
334 if (_shell_global_check_xdnd_event (shell_plugin->global, xev))
335 return TRUE;
336
337 return clutter_x11_handle_event (xev) != CLUTTER_X11_FILTER_CONTINUE;
338 }
339
340 static const
341 MetaPluginInfo *gnome_shell_plugin_plugin_info (MetaPlugin *plugin)
342 {
343 static const MetaPluginInfo info = {
344 .name = "GNOME Shell",
345 .version = "0.1",
346 .author = "Various",
347 .license = "GPLv2+",
348 .description = "Provides GNOME Shell core functionality"
349 };
350
351 return &info;
352 }
353
354 #if HAVE_BLUETOOTH
355 /* HACK:
356 Add a non-static function that calls into libgnome-bluetooth-applet.so,
357 to avoid the linker being too smart and removing the dependency.
358 This function is never actually called.
359 */
360 extern GType bluetooth_applet_get_type(void);
361 void _shell_link_to_bluetooth(void);
362
363 void _shell_link_to_bluetooth(void) {
364 bluetooth_applet_get_type();
365 }
366 #endif