gnome-shell-3.6.3.1/src/main.c

No issues found

  1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
  2 
  3 #include "config.h"
  4 
  5 #ifdef HAVE_MALLINFO
  6 #include <malloc.h>
  7 #endif
  8 #include <stdlib.h>
  9 #include <string.h>
 10 
 11 #include <clutter/clutter.h>
 12 #include <clutter/x11/clutter-x11.h>
 13 #include <gdk/gdk.h>
 14 #include <gdk/gdkx.h>
 15 #include <gtk/gtk.h>
 16 #include <glib/gi18n-lib.h>
 17 #include <girepository.h>
 18 #include <meta/main.h>
 19 #include <meta/meta-plugin.h>
 20 #include <meta/prefs.h>
 21 #include <atk-bridge.h>
 22 #include <telepathy-glib/debug.h>
 23 #include <telepathy-glib/debug-sender.h>
 24 
 25 #include "shell-global.h"
 26 #include "shell-global-private.h"
 27 #include "shell-js.h"
 28 #include "shell-perf-log.h"
 29 #include "st.h"
 30 
 31 #include <jsapi.h>
 32 
 33 extern GType gnome_shell_plugin_get_type (void);
 34 
 35 #define SHELL_DBUS_SERVICE "org.gnome.Shell"
 36 #define MAGNIFIER_DBUS_SERVICE "org.gnome.Magnifier"
 37 
 38 #define OVERRIDES_SCHEMA "org.gnome.shell.overrides"
 39 
 40 #define WM_NAME "GNOME Shell"
 41 #define GNOME_WM_KEYBINDINGS "Metacity,Mutter,GNOME Shell"
 42 
 43 static gboolean is_gdm_mode = FALSE;
 44 static char *session_mode = NULL;
 45 
 46 #define DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER 1
 47 #define DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER 4
 48 
 49 static void
 50 shell_dbus_acquire_name (GDBusProxy *bus,
 51                          guint32     request_name_flags,
 52                          guint32    *request_name_result,
 53                          gchar      *name,
 54                          gboolean    fatal)
 55 {
 56   GError *error = NULL;
 57   GVariant *request_name_variant;
 58 
 59   if (!(request_name_variant = g_dbus_proxy_call_sync (bus,
 60                                                        "RequestName",
 61                                                        g_variant_new ("(su)", name, request_name_flags),
 62                                                        0, /* call flags */
 63                                                        -1, /* timeout */
 64                                                        NULL, /* cancellable */
 65                                                        &error)))
 66     {
 67       g_printerr ("failed to acquire %s: %s\n", name, error->message);
 68       if (!fatal)
 69         return;
 70       exit (1);
 71     }
 72   g_variant_get (request_name_variant, "(u)", request_name_result);
 73 }
 74 
 75 static void
 76 shell_dbus_acquire_names (GDBusProxy *bus,
 77                           guint32     request_name_flags,
 78                           gchar      *name,
 79                           gboolean    fatal, ...) G_GNUC_NULL_TERMINATED;
 80 
 81 static void
 82 shell_dbus_acquire_names (GDBusProxy *bus,
 83                           guint32     request_name_flags,
 84                           gchar      *name,
 85                           gboolean    fatal, ...)
 86 {
 87   va_list al;
 88   guint32 request_name_result;
 89   va_start (al, fatal);
 90   for (;;)
 91   {
 92     shell_dbus_acquire_name (bus,
 93                              request_name_flags,
 94                              &request_name_result,
 95                              name, fatal);
 96     name = va_arg (al, gchar *);
 97     if (!name)
 98       break;
 99     fatal = va_arg (al, gboolean);
100   }
101   va_end (al);
102 }
103 
104 static void
105 shell_dbus_init (gboolean replace)
106 {
107   GDBusConnection *session;
108   GDBusProxy *bus;
109   GError *error = NULL;
110   guint32 request_name_flags;
111   guint32 request_name_result;
112 
113   session = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
114 
115   if (error) {
116     g_printerr ("Failed to connect to session bus: %s", error->message);
117     exit (1);
118   }
119 
120   bus = g_dbus_proxy_new_sync (session,
121                                G_DBUS_PROXY_FLAGS_NONE,
122                                NULL, /* interface info */
123                                "org.freedesktop.DBus",
124                                "/org/freedesktop/DBus",
125                                "org.freedesktop.DBus",
126                                NULL, /* cancellable */
127                                &error);
128 
129   request_name_flags = G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT;
130   if (replace)
131     request_name_flags |= DBUS_NAME_FLAG_REPLACE_EXISTING;
132 
133   shell_dbus_acquire_name (bus,
134                            request_name_flags,
135                            &request_name_result,
136                            SHELL_DBUS_SERVICE, TRUE);
137   if (!(request_name_result == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER
138         || request_name_result == DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER))
139     {
140       g_printerr (SHELL_DBUS_SERVICE " already exists on bus and --replace not specified\n");
141       exit (1);
142     }
143 
144   /*
145    * We always specify REPLACE_EXISTING to ensure we kill off
146    * the existing service if it was running.
147    */
148   request_name_flags |= G_BUS_NAME_OWNER_FLAGS_REPLACE;
149 
150   shell_dbus_acquire_names (bus,
151                             request_name_flags,
152   /* Also grab org.gnome.Panel to replace any existing panel process */
153                             "org.gnome.Panel", TRUE,
154   /* ...and the org.gnome.Magnifier service. */
155                             MAGNIFIER_DBUS_SERVICE, FALSE,
156   /* ...and the org.freedesktop.Notifications service. */
157                             "org.freedesktop.Notifications", FALSE,
158                             NULL);
159   /* ...and the on-screen keyboard service */
160   shell_dbus_acquire_name (bus,
161                            DBUS_NAME_FLAG_REPLACE_EXISTING,
162                            &request_name_result,
163                            "org.gnome.Caribou.Keyboard", FALSE);
164   g_object_unref (bus);
165   g_object_unref (session);
166 }
167 
168 static void
169 shell_prefs_init (void)
170 {
171   meta_prefs_override_preference_schema ("attach-modal-dialogs",
172                                          OVERRIDES_SCHEMA);
173   meta_prefs_override_preference_schema ("dynamic-workspaces",
174                                          OVERRIDES_SCHEMA);
175   meta_prefs_override_preference_schema ("workspaces-only-on-primary",
176                                          OVERRIDES_SCHEMA);
177   meta_prefs_override_preference_schema ("button-layout",
178                                          OVERRIDES_SCHEMA);
179   meta_prefs_override_preference_schema ("edge-tiling",
180                                          OVERRIDES_SCHEMA);
181   meta_prefs_override_preference_schema ("focus-change-on-pointer-rest",
182                                          OVERRIDES_SCHEMA);
183 }
184 
185 static void
186 shell_introspection_init (void)
187 {
188 
189   g_irepository_prepend_search_path (MUTTER_TYPELIB_DIR);
190   g_irepository_prepend_search_path (GNOME_SHELL_PKGLIBDIR);
191 #if HAVE_BLUETOOTH
192   g_irepository_prepend_search_path (BLUETOOTH_DIR);
193 #endif
194 
195 }
196 
197 static void
198 malloc_statistics_callback (ShellPerfLog *perf_log,
199                             gpointer      data)
200 {
201 #ifdef HAVE_MALLINFO
202   struct mallinfo info = mallinfo ();
203 
204   shell_perf_log_update_statistic_i (perf_log,
205                                      "malloc.arenaSize",
206                                      info.arena);
207   shell_perf_log_update_statistic_i (perf_log,
208                                      "malloc.mmapSize",
209                                      info.hblkhd);
210   shell_perf_log_update_statistic_i (perf_log,
211                                      "malloc.usedSize",
212                                      info.uordblks);
213 #endif
214 }
215 
216 static void
217 shell_perf_log_init (void)
218 {
219   ShellPerfLog *perf_log = shell_perf_log_get_default ();
220 
221   /* For probably historical reasons, mallinfo() defines the returned values,
222    * even those in bytes as int, not size_t. We're determined not to use
223    * more than 2G of malloc'ed memory, so are OK with that.
224    */
225   shell_perf_log_define_statistic (perf_log,
226                                    "malloc.arenaSize",
227                                    "Amount of memory allocated by malloc() with brk(), in bytes",
228                                    "i");
229   shell_perf_log_define_statistic (perf_log,
230                                    "malloc.mmapSize",
231                                    "Amount of memory allocated by malloc() with mmap(), in bytes",
232                                    "i");
233   shell_perf_log_define_statistic (perf_log,
234                                    "malloc.usedSize",
235                                    "Amount of malloc'ed memory currently in use",
236                                    "i");
237 
238   shell_perf_log_add_statistics_callback (perf_log,
239                                           malloc_statistics_callback,
240                                           NULL, NULL);
241 }
242 
243 static void
244 shell_a11y_init (void)
245 {
246   if (clutter_get_accessibility_enabled () == FALSE)
247     {
248       g_warning ("Accessibility: clutter has no accessibility enabled"
249                  " skipping the atk-bridge load");
250     }
251   else
252     {
253       atk_bridge_adaptor_init (NULL, NULL);
254     }
255 }
256 
257 static void
258 default_log_handler (const char     *log_domain,
259                      GLogLevelFlags  log_level,
260                      const char     *message,
261                      gpointer        data)
262 {
263   TpDebugSender *sender = data;
264   GTimeVal now;
265 
266   g_get_current_time (&now);
267 
268   tp_debug_sender_add_message (sender, &now, log_domain, log_level, message);
269 
270   /* Filter out telepathy-glib logs, we don't want to flood Shell's output
271    * with those. */
272   if (!g_str_has_prefix (log_domain, "tp-glib"))
273     g_log_default_handler (log_domain, log_level, message, data);
274 }
275 
276 static void
277 shut_up (const char     *domain,
278          GLogLevelFlags  level,
279          const char     *message,
280          gpointer        user_data)
281 {
282 }
283 
284 static gboolean
285 list_modes (const char  *option_name,
286             const char  *value,
287             gpointer     data,
288             GError     **error)
289 {
290   ShellGlobal *global;
291   GjsContext *context;
292   const char *script;
293   int status;
294 
295   /* Many of our imports require global to be set, so rather than
296    * tayloring our imports carefully here to avoid that dependency,
297    * we just set it.
298    * ShellGlobal has some GTK+ dependencies, so initialize GTK+; we
299    * don't really care if it fails though (e.g. when running from a tty),
300    * so we mute all warnings */
301   g_log_set_default_handler (shut_up, NULL);
302   gtk_init_check (NULL, NULL);
303 
304   _shell_global_init (NULL);
305   global = shell_global_get ();
306   context = _shell_global_get_gjs_context (global);
307 
308   shell_introspection_init ();
309 
310   script = "imports.ui.environment.init();"
311            "imports.ui.sessionMode.listModes();";
312   if (!gjs_context_eval (context, script, -1, "<main>", &status, NULL))
313       g_message ("Retrieving list of available modes failed.");
314 
315   exit (status);
316 }
317 
318 static gboolean
319 print_version (const gchar    *option_name,
320                const gchar    *value,
321                gpointer        data,
322                GError        **error)
323 {
324   g_print ("GNOME Shell %s\n", VERSION);
325   exit (0);
326 }
327 
328 GOptionEntry gnome_shell_options[] = {
329   {
330     "version", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
331     print_version,
332     N_("Print version"),
333     NULL
334   },
335   {
336     "gdm-mode", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE,
337     &is_gdm_mode,
338     N_("Mode used by GDM for login screen"),
339     NULL
340   },
341   {
342     "mode", 0, 0, G_OPTION_ARG_STRING,
343     &session_mode,
344     N_("Use a specific mode, e.g. \"gdm\" for login screen"),
345     "MODE"
346   },
347   {
348     "list-modes", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
349     list_modes,
350     N_("List possible modes"),
351     NULL
352   },
353   { NULL }
354 };
355 
356 int
357 main (int argc, char **argv)
358 {
359   GOptionContext *ctx;
360   GError *error = NULL;
361   int ecode;
362   TpDebugSender *sender;
363 
364   g_type_init ();
365 
366   bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
367   bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
368   textdomain (GETTEXT_PACKAGE);
369 
370   ctx = meta_get_option_context ();
371   g_option_context_add_main_entries (ctx, gnome_shell_options, GETTEXT_PACKAGE);
372   if (!g_option_context_parse (ctx, &argc, &argv, &error))
373     {
374       g_printerr ("%s: %s\n", argv[0], error->message);
375       exit (1);
376     }
377 
378   g_option_context_free (ctx);
379 
380   meta_plugin_manager_set_plugin_type (gnome_shell_plugin_get_type ());
381 
382   meta_set_wm_name (WM_NAME);
383   meta_set_gnome_wm_keybindings (GNOME_WM_KEYBINDINGS);
384 
385   /* Prevent meta_init() from causing gtk to load gail and at-bridge */
386   g_setenv ("NO_AT_BRIDGE", "1", TRUE);
387   meta_init ();
388   g_unsetenv ("NO_AT_BRIDGE");
389 
390   /* FIXME: Add gjs API to set this stuff and don't depend on the
391    * environment.  These propagate to child processes.
392    */
393   g_setenv ("GJS_DEBUG_OUTPUT", "stderr", TRUE);
394   g_setenv ("GJS_DEBUG_TOPICS", "JS ERROR;JS LOG", TRUE);
395 
396   shell_dbus_init (meta_get_replace_current_wm ());
397   shell_a11y_init ();
398   shell_perf_log_init ();
399   shell_prefs_init ();
400   shell_introspection_init ();
401 
402   /* Turn on telepathy-glib debugging but filter it out in
403    * default_log_handler. This handler also exposes all the logs over D-Bus
404    * using TpDebugSender. */
405   tp_debug_set_flags ("all");
406 
407   sender = tp_debug_sender_dup ();
408   g_log_set_default_handler (default_log_handler, sender);
409 
410   /* Initialize the global object */
411   if (session_mode == NULL)
412     session_mode = is_gdm_mode ? "gdm" : "user";
413 
414   _shell_global_init ("session-mode", session_mode, NULL);
415 
416   ecode = meta_run ();
417 
418   if (g_getenv ("GNOME_SHELL_ENABLE_CLEANUP"))
419     {
420       g_printerr ("Doing final cleanup...\n");
421       g_object_unref (shell_global_get ());
422     }
423 
424   g_object_unref (sender);
425 
426   return ecode;
427 }
428 
429 /* HACK:
430    Add a dummy function that calls into libgnome-shell-js.so to ensure it's
431    linked to /usr/bin/gnome-shell even when linking with --as-needed.
432    This function is never actually called.
433    https://bugzilla.gnome.org/show_bug.cgi?id=670477
434 */
435 void _shell_link_to_shell_js (void);
436 
437 void
438 _shell_link_to_shell_js (void)
439 {
440   shell_js_add_extension_importer (NULL, NULL, NULL, NULL);
441 }