main.c

Go to the documentation of this file.
00001 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
00002 
00003 /* Metacity main() */
00004 
00005 /* 
00006  * Copyright (C) 2001 Havoc Pennington
00007  * Copyright (C) 2006 Elijah Newren
00008  * 
00009  * This program is free software; you can redistribute it and/or
00010  * modify it under the terms of the GNU General Public License as
00011  * published by the Free Software Foundation; either version 2 of the
00012  * License, or (at your option) any later version.
00013  *
00014  * This program is distributed in the hope that it will be useful, but
00015  * WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017  * General Public License for more details.
00018  * 
00019  * You should have received a copy of the GNU General Public License
00020  * along with this program; if not, write to the Free Software
00021  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
00022  * 02111-1307, USA.
00023  */
00024 
00044 #define _GNU_SOURCE
00045 #define _SVID_SOURCE /* for putenv() and some signal-related functions */
00046 
00047 #include <config.h>
00048 #include "main.h"
00049 #include "util.h"
00050 #include "display-private.h"
00051 #include "errors.h"
00052 #include "ui.h"
00053 #include "session.h"
00054 #include "prefs.h"
00055 
00056 #include <glib-object.h>
00057 
00058 #include <stdlib.h>
00059 #include <sys/types.h>
00060 #include <stdio.h>
00061 #include <string.h>
00062 #include <signal.h>
00063 #include <unistd.h>
00064 #include <errno.h>
00065 #include <fcntl.h>
00066 #include <locale.h>
00067 #include <time.h>
00068 
00072 static MetaExitCode meta_exit_code = META_EXIT_SUCCESS;
00073 
00078 static GMainLoop *meta_main_loop = NULL;
00079 
00084 static gboolean meta_restart_after_quit = FALSE;
00085 
00086 static void prefs_changed_callback (MetaPreference pref,
00087                                     gpointer       data);
00088 
00099 static void
00100 log_handler (const gchar   *log_domain,
00101              GLogLevelFlags log_level,
00102              const gchar   *message,
00103              gpointer       user_data)
00104 {
00105   meta_warning ("Log level %d: %s\n", log_level, message);
00106   meta_print_backtrace ();
00107 }
00108 
00113 static void
00114 version (void)
00115 {
00116   g_print (_("metacity %s\n"
00117              "Copyright (C) 2001-2008 Havoc Pennington, Red Hat, Inc., and others\n"
00118              "This is free software; see the source for copying conditions.\n"
00119              "There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"),
00120            VERSION);
00121   exit (0);
00122 }
00123 
00130 static void
00131 meta_print_compilation_info (void)
00132 {
00133 #ifdef HAVE_SHAPE
00134   meta_verbose ("Compiled with shape extension\n");
00135 #else
00136   meta_verbose ("Compiled without shape extension\n");
00137 #endif
00138 #ifdef HAVE_XINERAMA
00139   meta_topic (META_DEBUG_XINERAMA, "Compiled with Xinerama extension\n");
00140 #else
00141   meta_topic (META_DEBUG_XINERAMA, "Compiled without Xinerama extension\n");
00142 #endif
00143 #ifdef HAVE_XFREE_XINERAMA
00144   meta_topic (META_DEBUG_XINERAMA, " (using XFree86 Xinerama)\n");
00145 #else
00146   meta_topic (META_DEBUG_XINERAMA, " (not using XFree86 Xinerama)\n");
00147 #endif
00148 #ifdef HAVE_SOLARIS_XINERAMA
00149   meta_topic (META_DEBUG_XINERAMA, " (using Solaris Xinerama)\n");
00150 #else
00151   meta_topic (META_DEBUG_XINERAMA, " (not using Solaris Xinerama)\n");
00152 #endif
00153 #ifdef HAVE_XSYNC
00154   meta_verbose ("Compiled with sync extension\n");
00155 #else
00156   meta_verbose ("Compiled without sync extension\n");
00157 #endif
00158 #ifdef HAVE_RANDR
00159   meta_verbose ("Compiled with randr extension\n");
00160 #else
00161   meta_verbose ("Compiled without randr extension\n");
00162 #endif
00163 #ifdef HAVE_STARTUP_NOTIFICATION
00164   meta_verbose ("Compiled with startup notification\n");
00165 #else
00166   meta_verbose ("Compiled without startup notification\n");
00167 #endif
00168 #ifdef HAVE_COMPOSITE_EXTENSIONS
00169   meta_verbose ("Compiled with composite extensions\n");
00170 #else
00171   meta_verbose ("Compiled without composite extensions\n");
00172 #endif
00173 }
00174 
00183 static void
00184 meta_print_self_identity (void)
00185 {
00186   char buf[256];
00187   GDate d;
00188   const char *charset;
00189 
00190   /* Version and current date. */
00191   g_date_clear (&d, 1);
00192   g_date_set_time_t (&d, time (NULL));
00193   g_date_strftime (buf, sizeof (buf), "%x", &d);
00194   meta_verbose ("Metacity version %s running on %s\n",
00195     VERSION, buf);
00196   
00197   /* Locale and encoding. */
00198   g_get_charset (&charset);
00199   meta_verbose ("Running in locale \"%s\" with encoding \"%s\"\n",
00200     setlocale (LC_ALL, NULL), charset);
00201 
00202   /* Compilation settings. */
00203   meta_print_compilation_info ();
00204 }
00205 
00211 typedef struct
00212 {
00213   gchar *save_file;
00214   gchar *display_name;
00215   gchar *client_id;
00216   gboolean replace_wm;
00217   gboolean disable_sm;
00218   gboolean print_version;
00219   gboolean sync;
00220 } MetaArguments;
00221 
00234 static void
00235 meta_parse_options (int *argc, char ***argv,
00236                     MetaArguments *meta_args)
00237 {
00238   MetaArguments my_args = {NULL, NULL, NULL, FALSE, FALSE, FALSE};
00239   GOptionEntry options[] = {
00240     {
00241       "sm-disable", 0, 0, G_OPTION_ARG_NONE,
00242       &my_args.disable_sm,
00243       N_("Disable connection to session manager"),
00244       NULL
00245     },
00246     {
00247       "replace", 0, 0, G_OPTION_ARG_NONE,
00248       &my_args.replace_wm,
00249       N_("Replace the running window manager with Metacity"),
00250       NULL
00251     },
00252     {
00253       "sm-client-id", 0, 0, G_OPTION_ARG_STRING,
00254       &my_args.client_id,
00255       N_("Specify session management ID"),
00256       "ID"
00257     },
00258     {
00259       "display", 0, 0, G_OPTION_ARG_STRING,
00260       &my_args.display_name, N_("X Display to use"),
00261       "DISPLAY"
00262     },
00263     {
00264       "sm-save-file", 0, 0, G_OPTION_ARG_FILENAME,
00265       &my_args.save_file,
00266       N_("Initialize session from savefile"),
00267       "FILE"
00268     },
00269     {
00270       "version", 0, 0, G_OPTION_ARG_NONE,
00271       &my_args.print_version,
00272       N_("Print version"),
00273       NULL
00274     },
00275     {
00276       "sync", 0, 0, G_OPTION_ARG_NONE,
00277       &my_args.sync,
00278       N_("Make X calls synchronous"),
00279       NULL
00280     },
00281     {NULL}
00282   };
00283   GOptionContext *ctx;
00284   GError *error = NULL;
00285 
00286   ctx = g_option_context_new (NULL);
00287   g_option_context_add_main_entries (ctx, options, "metacity");
00288   if (!g_option_context_parse (ctx, argc, argv, &error))
00289     {
00290       g_print ("metacity: %s\n", error->message);
00291       exit(1);
00292     }
00293   g_option_context_free (ctx);
00294   /* Return the parsed options through the meta_args param. */
00295   *meta_args = my_args;
00296 }
00297 
00304 static
00305 void meta_select_display (gchar *display_name)
00306 {
00307   gchar *envVar = "";
00308   if (display_name)
00309     envVar = g_strconcat ("DISPLAY=", display_name, NULL);
00310   else if (g_getenv ("METACITY_DISPLAY"))
00311     envVar = g_strconcat ("DISPLAY=",
00312       g_getenv ("METACITY_DISPLAY"), NULL);
00313   /* DO NOT FREE envVar, putenv() sucks */
00314   putenv (envVar);
00315 }
00316     
00328 int
00329 main (int argc, char **argv)
00330 {
00331   struct sigaction act;
00332   sigset_t empty_mask;
00333   MetaArguments meta_args;
00334   const gchar *log_domains[] = {
00335     NULL, G_LOG_DOMAIN, "Gtk", "Gdk", "GLib",
00336     "Pango", "GLib-GObject", "GThread"
00337   };
00338   guint i;
00339   
00340   if (setlocale (LC_ALL, "") == NULL)
00341     meta_warning ("Locale not understood by C library, internationalization will not work\n");
00342   
00343   sigemptyset (&empty_mask);
00344   act.sa_handler = SIG_IGN;
00345   act.sa_mask    = empty_mask;
00346   act.sa_flags   = 0;
00347   if (sigaction (SIGPIPE,  &act, NULL) < 0)
00348     g_printerr ("Failed to register SIGPIPE handler: %s\n",
00349                 g_strerror (errno));
00350 #ifdef SIGXFSZ
00351   if (sigaction (SIGXFSZ,  &act, NULL) < 0)
00352     g_printerr ("Failed to register SIGXFSZ handler: %s\n",
00353                 g_strerror (errno));
00354 #endif
00355 
00356   if (g_getenv ("METACITY_VERBOSE"))
00357     meta_set_verbose (TRUE);
00358   if (g_getenv ("METACITY_DEBUG"))
00359     meta_set_debugging (TRUE);
00360 
00361   if (g_get_home_dir ())
00362     chdir (g_get_home_dir ());
00363 
00364   meta_print_self_identity ();
00365   
00366   bindtextdomain (GETTEXT_PACKAGE, METACITY_LOCALEDIR);
00367   bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
00368   textdomain (GETTEXT_PACKAGE);
00369 
00370   /* Parse command line arguments.*/
00371   meta_parse_options (&argc, &argv, &meta_args);
00372 
00373   meta_set_syncing (meta_args.sync || (g_getenv ("METACITY_SYNC") != NULL));
00374 
00375   if (meta_args.print_version)
00376     version ();
00377 
00378   meta_select_display (meta_args.display_name);
00379   
00380   if (meta_args.replace_wm)
00381     meta_set_replace_current_wm (TRUE);
00382 
00383   if (meta_args.save_file && meta_args.client_id)
00384     meta_fatal ("Can't specify both SM save file and SM client id\n");
00385   
00386   meta_main_loop = g_main_loop_new (NULL, FALSE);
00387   
00388   g_type_init ();
00389 
00390   meta_ui_init (&argc, &argv);  
00391 
00392   /* must be after UI init so we can override GDK handlers */
00393   meta_errors_init ();
00394 
00395   /* Load prefs */
00396   meta_prefs_init ();
00397   meta_prefs_add_listener (prefs_changed_callback, NULL);
00398 
00399 
00400 #if 1
00401 
00402   for (i=0; i<G_N_ELEMENTS(log_domains); i++)
00403     g_log_set_handler (log_domains[i],
00404                        G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION,
00405                        log_handler, NULL);
00406 
00407 #endif
00408 
00409   if (g_getenv ("METACITY_G_FATAL_WARNINGS") != NULL)
00410     g_log_set_always_fatal (G_LOG_LEVEL_MASK);
00411   
00412   meta_ui_set_current_theme (meta_prefs_get_theme (), FALSE);
00413 
00414   /* Try to find some theme that'll work if the theme preference
00415    * doesn't exist.  First try Simple (the default theme) then just
00416    * try anything in the themes directory.
00417    */
00418   if (!meta_ui_have_a_theme ())
00419     meta_ui_set_current_theme ("Simple", FALSE);
00420   
00421   if (!meta_ui_have_a_theme ())
00422     {
00423       const char *dir_entry = NULL;
00424       GError *err = NULL;
00425       GDir   *themes_dir = NULL;
00426       
00427       if (!(themes_dir = g_dir_open (METACITY_DATADIR"/themes", 0, &err)))
00428         {
00429           meta_fatal (_("Failed to scan themes directory: %s\n"), err->message);
00430           g_error_free (err);
00431         } 
00432       else 
00433         {
00434           while (((dir_entry = g_dir_read_name (themes_dir)) != NULL) && 
00435                  (!meta_ui_have_a_theme ()))
00436             {
00437               meta_ui_set_current_theme (dir_entry, FALSE);
00438             }
00439           
00440           g_dir_close (themes_dir);
00441         }
00442     }
00443   
00444   if (!meta_ui_have_a_theme ())
00445     meta_fatal (_("Could not find a theme! Be sure %s exists and contains the usual themes.\n"),
00446                 METACITY_DATADIR"/themes");
00447   
00448   /* Connect to SM as late as possible - but before managing display,
00449    * or we might try to manage a window before we have the session
00450    * info
00451    */
00452   if (!meta_args.disable_sm)
00453     {
00454       if (meta_args.client_id == NULL)
00455         {
00456           const gchar *desktop_autostart_id;
00457   
00458           desktop_autostart_id = g_getenv ("DESKTOP_AUTOSTART_ID");
00459  
00460           if (desktop_autostart_id != NULL)
00461             meta_args.client_id = g_strdup (desktop_autostart_id);
00462         }
00463 
00464       /* Unset DESKTOP_AUTOSTART_ID in order to avoid child processes to
00465        * use the same client id. */
00466       g_unsetenv ("DESKTOP_AUTOSTART_ID");
00467 
00468       meta_session_init (meta_args.client_id, meta_args.save_file);
00469     }
00470   /* Free memory possibly allocated by the argument parsing which are
00471    * no longer needed.
00472    */
00473   g_free (meta_args.save_file);
00474   g_free (meta_args.display_name);
00475   g_free (meta_args.client_id);
00476   
00477   if (!meta_display_open ())
00478     meta_exit (META_EXIT_ERROR);
00479   
00480   g_main_loop_run (meta_main_loop);
00481 
00482   meta_display_close (meta_get_display (),
00483                       CurrentTime); /* I doubt correct timestamps matter here */
00484 
00485   meta_session_shutdown ();
00486   
00487   if (meta_restart_after_quit)
00488     {
00489       GError *err;
00490 
00491       err = NULL;
00492       if (!g_spawn_async (NULL,
00493                           argv,
00494                           NULL,
00495                           G_SPAWN_SEARCH_PATH,
00496                           NULL,
00497                           NULL,
00498                           NULL,
00499                           &err))
00500         {
00501           meta_fatal (_("Failed to restart: %s\n"),
00502                       err->message);
00503           g_error_free (err); /* not reached anyhow */
00504           meta_exit_code = META_EXIT_ERROR;
00505         }
00506     }
00507   
00508   return meta_exit_code;
00509 }
00510 
00520 void
00521 meta_quit (MetaExitCode code)
00522 {
00523   meta_exit_code = code;
00524 
00525   if (g_main_loop_is_running (meta_main_loop))
00526     g_main_loop_quit (meta_main_loop);
00527 }
00528 
00535 void
00536 meta_restart (void)
00537 {
00538   meta_restart_after_quit = TRUE;
00539   meta_quit (META_EXIT_SUCCESS);
00540 }
00541 
00551 static void
00552 prefs_changed_callback (MetaPreference pref,
00553                         gpointer       data)
00554 {
00555   switch (pref)
00556     {
00557     case META_PREF_THEME:
00558       meta_ui_set_current_theme (meta_prefs_get_theme (), FALSE);
00559       meta_display_retheme_all ();
00560       break;
00561 
00562     case META_PREF_CURSOR_THEME:
00563     case META_PREF_CURSOR_SIZE:
00564       meta_display_set_cursor_theme (meta_prefs_get_cursor_theme (),
00565                                      meta_prefs_get_cursor_size ());
00566       break;
00567     default:
00568       /* handled elsewhere or otherwise */
00569       break;
00570     }
00571 }

Generated on Sat Aug 23 22:04:17 2008 for metacity by  doxygen 1.5.5