File: | core/main.c |
Warning: | line 429, column 18 Using a fixed address is not portable because that address will probably not be valid in all environments or platforms |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ | |||
2 | ||||
3 | /* Croma main() */ | |||
4 | ||||
5 | /* | |||
6 | * Copyright (C) 2001 Havoc Pennington | |||
7 | * Copyright (C) 2006 Elijah Newren | |||
8 | * | |||
9 | * This program is free software; you can redistribute it and/or | |||
10 | * modify it under the terms of the GNU General Public License as | |||
11 | * published by the Free Software Foundation; either version 2 of the | |||
12 | * License, or (at your option) any later version. | |||
13 | * | |||
14 | * This program is distributed in the hope that it will be useful, but | |||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
17 | * General Public License for more details. | |||
18 | * | |||
19 | * You should have received a copy of the GNU General Public License | |||
20 | * along with this program; if not, write to the Free Software | |||
21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | |||
22 | * 02110-1301, USA. | |||
23 | */ | |||
24 | ||||
25 | /** | |||
26 | * \file | |||
27 | * Program startup. | |||
28 | * Functions which parse the command-line arguments, create the display, | |||
29 | * kick everything off and then close down Croma when it's time to go. | |||
30 | */ | |||
31 | ||||
32 | /** | |||
33 | * \mainpage | |||
34 | * Croma - a boring window manager for the adult in you | |||
35 | * | |||
36 | * Many window managers are like Marshmallow Froot Loops; Croma | |||
37 | * is like Cheerios. | |||
38 | * | |||
39 | * The best way to get a handle on how the whole system fits together | |||
40 | * is discussed in doc/code-overview.txt; if you're looking for functions | |||
41 | * to investigate, read main(), meta_display_open(), and event_callback(). | |||
42 | */ | |||
43 | ||||
44 | #define _GNU_SOURCE | |||
45 | #define _XOPEN_SOURCE700 /* for putenv() and some signal-related functions */ | |||
46 | ||||
47 | #include <config.h> | |||
48 | #include "main.h" | |||
49 | #include "util.h" | |||
50 | #include "display-private.h" | |||
51 | #include "errors.h" | |||
52 | #include "ui.h" | |||
53 | #include "session.h" | |||
54 | #include "prefs.h" | |||
55 | #include "core.h" | |||
56 | ||||
57 | #include <glib-object.h> | |||
58 | #include <glib/gprintf.h> | |||
59 | ||||
60 | #include <stdlib.h> | |||
61 | #include <sys/types.h> | |||
62 | #include <sys/wait.h> | |||
63 | #include <stdio.h> | |||
64 | #include <string.h> | |||
65 | #include <signal.h> | |||
66 | #include <unistd.h> | |||
67 | #include <errno(*__errno_location ()).h> | |||
68 | #include <fcntl.h> | |||
69 | #include <locale.h> | |||
70 | #include <time.h> | |||
71 | #include <unistd.h> | |||
72 | ||||
73 | /** | |||
74 | * The exit code we'll return to our parent process when we eventually die. | |||
75 | */ | |||
76 | static MetaExitCode meta_exit_code = META_EXIT_SUCCESS; | |||
77 | ||||
78 | /** | |||
79 | * Handle on the main loop, so that we have an easy way of shutting Croma | |||
80 | * down. | |||
81 | */ | |||
82 | static GMainLoop *meta_main_loop = NULL((void*)0); | |||
83 | ||||
84 | /** | |||
85 | * If set, Croma will spawn an identical copy of itself immediately | |||
86 | * before quitting. | |||
87 | */ | |||
88 | static gboolean meta_restart_after_quit = FALSE(0); | |||
89 | ||||
90 | static void prefs_changed_callback (MetaPreference pref, | |||
91 | gpointer data); | |||
92 | ||||
93 | /** | |||
94 | * Prints log messages. If Croma was compiled with backtrace support, | |||
95 | * also prints a backtrace (see meta_print_backtrace()). | |||
96 | * | |||
97 | * \param log_domain the domain the error occurred in (we ignore this) | |||
98 | * \param log_level the log level so that we can filter out less | |||
99 | * important messages | |||
100 | * \param message the message to log | |||
101 | * \param user_data arbitrary data (we ignore this) | |||
102 | */ | |||
103 | static void | |||
104 | log_handler (const gchar *log_domain, | |||
105 | GLogLevelFlags log_level, | |||
106 | const gchar *message, | |||
107 | gpointer user_data) | |||
108 | { | |||
109 | meta_warning ("Log level %d: %s\n", log_level, message); | |||
110 | meta_print_backtrace (); | |||
111 | } | |||
112 | ||||
113 | /** | |||
114 | * Prints the version notice. This is shown when Croma is called | |||
115 | * with the --version switch. | |||
116 | */ | |||
117 | static void | |||
118 | version (void) | |||
119 | { | |||
120 | const int latest_year = 2009; | |||
121 | char yearbuffer[256]; | |||
122 | GDate date; | |||
123 | ||||
124 | /* this is all so the string to translate stays constant. | |||
125 | * see how much we love the translators. | |||
126 | */ | |||
127 | g_date_set_dmy (&date, 1, G_DATE_JANUARY, latest_year); | |||
128 | if (g_date_strftime (yearbuffer, sizeof (yearbuffer), "%Y", &date)==0) | |||
129 | /* didn't work? fall back to decimal representation */ | |||
130 | g_sprintf (yearbuffer, "%d", latest_year); | |||
131 | ||||
132 | g_print (_("croma %s\n"dgettext ("croma", "croma %s\n" "Copyright (C) 2001-%s Havoc Pennington, Red Hat, Inc., and others\n" "This is free software; see the source for copying conditions.\n" "There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n" ) | |||
133 | "Copyright (C) 2001-%s Havoc Pennington, Red Hat, Inc., and others\n"dgettext ("croma", "croma %s\n" "Copyright (C) 2001-%s Havoc Pennington, Red Hat, Inc., and others\n" "This is free software; see the source for copying conditions.\n" "There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n" ) | |||
134 | "This is free software; see the source for copying conditions.\n"dgettext ("croma", "croma %s\n" "Copyright (C) 2001-%s Havoc Pennington, Red Hat, Inc., and others\n" "This is free software; see the source for copying conditions.\n" "There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n" ) | |||
135 | "There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n")dgettext ("croma", "croma %s\n" "Copyright (C) 2001-%s Havoc Pennington, Red Hat, Inc., and others\n" "This is free software; see the source for copying conditions.\n" "There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n" ), | |||
136 | VERSION"1.25.1", yearbuffer); | |||
137 | exit (0); | |||
138 | } | |||
139 | ||||
140 | /** | |||
141 | * Prints a list of which configure script options were used to | |||
142 | * build this copy of Croma. This is actually always called | |||
143 | * on startup, but it's all no-op unless we're in verbose mode | |||
144 | * (see meta_set_verbose). | |||
145 | */ | |||
146 | static void | |||
147 | meta_print_compilation_info (void) | |||
148 | { | |||
149 | #ifdef HAVE_SHAPE | |||
150 | meta_verbosemeta_verbose_real ("Compiled with shape extension\n"); | |||
151 | #else | |||
152 | meta_verbosemeta_verbose_real ("Compiled without shape extension\n"); | |||
153 | #endif | |||
154 | #ifdef HAVE_XINERAMA | |||
155 | meta_topicmeta_topic_real (META_DEBUG_XINERAMA, "Compiled with Xinerama extension\n"); | |||
156 | #else | |||
157 | meta_topicmeta_topic_real (META_DEBUG_XINERAMA, "Compiled without Xinerama extension\n"); | |||
158 | #endif | |||
159 | #ifdef HAVE_XFREE_XINERAMA | |||
160 | meta_topicmeta_topic_real (META_DEBUG_XINERAMA, " (using XFree86 Xinerama)\n"); | |||
161 | #else | |||
162 | meta_topicmeta_topic_real (META_DEBUG_XINERAMA, " (not using XFree86 Xinerama)\n"); | |||
163 | #endif | |||
164 | #ifdef HAVE_SOLARIS_XINERAMA | |||
165 | meta_topicmeta_topic_real (META_DEBUG_XINERAMA, " (using Solaris Xinerama)\n"); | |||
166 | #else | |||
167 | meta_topicmeta_topic_real (META_DEBUG_XINERAMA, " (not using Solaris Xinerama)\n"); | |||
168 | #endif | |||
169 | #ifdef HAVE_XSYNC | |||
170 | meta_verbosemeta_verbose_real ("Compiled with sync extension\n"); | |||
171 | #else | |||
172 | meta_verbosemeta_verbose_real ("Compiled without sync extension\n"); | |||
173 | #endif | |||
174 | #ifdef HAVE_RANDR | |||
175 | meta_verbosemeta_verbose_real ("Compiled with randr extension\n"); | |||
176 | #else | |||
177 | meta_verbosemeta_verbose_real ("Compiled without randr extension\n"); | |||
178 | #endif | |||
179 | #ifdef HAVE_STARTUP_NOTIFICATION | |||
180 | meta_verbosemeta_verbose_real ("Compiled with startup notification\n"); | |||
181 | #else | |||
182 | meta_verbosemeta_verbose_real ("Compiled without startup notification\n"); | |||
183 | #endif | |||
184 | #ifdef HAVE_COMPOSITE_EXTENSIONS1 | |||
185 | meta_verbosemeta_verbose_real ("Compiled with composite extensions\n"); | |||
186 | #else | |||
187 | meta_verbosemeta_verbose_real ("Compiled without composite extensions\n"); | |||
188 | #endif | |||
189 | } | |||
190 | ||||
191 | /** | |||
192 | * Prints the version number, the current timestamp (not the | |||
193 | * build date), the locale, the character encoding, and a list | |||
194 | * of configure script options that were used to build this | |||
195 | * copy of Croma. This is actually always called | |||
196 | * on startup, but it's all no-op unless we're in verbose mode | |||
197 | * (see meta_set_verbose). | |||
198 | */ | |||
199 | static void | |||
200 | meta_print_self_identity (void) | |||
201 | { | |||
202 | char buf[256]; | |||
203 | GDate d; | |||
204 | const char *charset; | |||
205 | ||||
206 | /* Version and current date. */ | |||
207 | g_date_clear (&d, 1); | |||
208 | g_date_set_time_t (&d, time (NULL((void*)0))); | |||
209 | g_date_strftime (buf, sizeof (buf), "%x", &d); | |||
210 | meta_verbosemeta_verbose_real ("Croma version %s running on %s\n", | |||
211 | VERSION"1.25.1", buf); | |||
212 | ||||
213 | /* Locale and encoding. */ | |||
214 | g_get_charset (&charset); | |||
215 | meta_verbosemeta_verbose_real ("Running in locale \"%s\" with encoding \"%s\"\n", | |||
216 | setlocale (LC_ALL6, NULL((void*)0)), charset); | |||
217 | ||||
218 | /* Compilation settings. */ | |||
219 | meta_print_compilation_info (); | |||
220 | } | |||
221 | ||||
222 | /** | |||
223 | * The set of possible options that can be set on Croma's | |||
224 | * command line. This type exists so that meta_parse_options() can | |||
225 | * write to an instance of it. | |||
226 | */ | |||
227 | typedef struct | |||
228 | { | |||
229 | gchar *save_file; | |||
230 | gchar *display_name; | |||
231 | gchar *client_id; | |||
232 | gboolean replace_wm; | |||
233 | gboolean disable_sm; | |||
234 | gboolean print_version; | |||
235 | gboolean sync; | |||
236 | gboolean composite; | |||
237 | gboolean no_composite; | |||
238 | gboolean no_force_fullscreen; | |||
239 | } MetaArguments; | |||
240 | ||||
241 | #ifdef HAVE_COMPOSITE_EXTENSIONS1 | |||
242 | #define COMPOSITE_OPTS_FLAGS0 0 | |||
243 | #else /* HAVE_COMPOSITE_EXTENSIONS */ | |||
244 | /* No compositor, so don't show the arguments in --help */ | |||
245 | #define COMPOSITE_OPTS_FLAGS0 G_OPTION_FLAG_HIDDEN | |||
246 | #endif /* HAVE_COMPOSITE_EXTENSIONS */ | |||
247 | ||||
248 | /** | |||
249 | * Parses argc and argv and returns the | |||
250 | * arguments that Croma understands in meta_args. | |||
251 | * | |||
252 | * The strange call signature has to be written like it is so | |||
253 | * that g_option_context_parse() gets a chance to modify argc and | |||
254 | * argv. | |||
255 | * | |||
256 | * \param argc Pointer to the number of arguments Croma was given | |||
257 | * \param argv Pointer to the array of arguments Croma was given | |||
258 | * \param meta_args The result of parsing the arguments. | |||
259 | **/ | |||
260 | static void | |||
261 | meta_parse_options (int *argc, char ***argv, | |||
262 | MetaArguments *meta_args) | |||
263 | { | |||
264 | MetaArguments my_args = { .replace_wm = FALSE(0), | |||
265 | .disable_sm = FALSE(0), | |||
266 | .print_version = FALSE(0), | |||
267 | .sync = FALSE(0), | |||
268 | .composite = FALSE(0) }; | |||
269 | ||||
270 | GOptionEntry options[] = { | |||
271 | { | |||
272 | "sm-disable", 0, 0, G_OPTION_ARG_NONE, | |||
273 | &my_args.disable_sm, | |||
274 | N_("Disable connection to session manager")"Disable connection to session manager", | |||
275 | NULL((void*)0) | |||
276 | }, | |||
277 | { | |||
278 | "replace", 0, 0, G_OPTION_ARG_NONE, | |||
279 | &my_args.replace_wm, | |||
280 | N_("Replace the running window manager with Croma")"Replace the running window manager with Croma", | |||
281 | NULL((void*)0) | |||
282 | }, | |||
283 | { | |||
284 | "sm-client-id", 0, 0, G_OPTION_ARG_STRING, | |||
285 | &my_args.client_id, | |||
286 | N_("Specify session management ID")"Specify session management ID", | |||
287 | "ID" | |||
288 | }, | |||
289 | { | |||
290 | "display", 'd', 0, G_OPTION_ARG_STRING, | |||
291 | &my_args.display_name, N_("X Display to use")"X Display to use", | |||
292 | "DISPLAY" | |||
293 | }, | |||
294 | { | |||
295 | "sm-save-file", 0, 0, G_OPTION_ARG_FILENAME, | |||
296 | &my_args.save_file, | |||
297 | N_("Initialize session from savefile")"Initialize session from savefile", | |||
298 | "FILE" | |||
299 | }, | |||
300 | { | |||
301 | "version", 0, 0, G_OPTION_ARG_NONE, | |||
302 | &my_args.print_version, | |||
303 | N_("Print version")"Print version", | |||
304 | NULL((void*)0) | |||
305 | }, | |||
306 | { | |||
307 | "sync", 0, 0, G_OPTION_ARG_NONE, | |||
308 | &my_args.sync, | |||
309 | N_("Make X calls synchronous")"Make X calls synchronous", | |||
310 | NULL((void*)0) | |||
311 | }, | |||
312 | { | |||
313 | "composite", 'c', COMPOSITE_OPTS_FLAGS0, G_OPTION_ARG_NONE, | |||
314 | &my_args.composite, | |||
315 | N_("Turn compositing on")"Turn compositing on", | |||
316 | NULL((void*)0) | |||
317 | }, | |||
318 | { | |||
319 | "no-composite", 0, COMPOSITE_OPTS_FLAGS0, G_OPTION_ARG_NONE, | |||
320 | &my_args.no_composite, | |||
321 | N_("Turn compositing off")"Turn compositing off", | |||
322 | NULL((void*)0) | |||
323 | }, | |||
324 | { | |||
325 | "no-force-fullscreen", 0, COMPOSITE_OPTS_FLAGS0, G_OPTION_ARG_NONE, | |||
326 | &my_args.no_force_fullscreen, | |||
327 | N_("Don't make fullscreen windows that are maximized and have no decorations")"Don't make fullscreen windows that are maximized and have no decorations", | |||
328 | NULL((void*)0) | |||
329 | }, | |||
330 | {NULL((void*)0)} | |||
331 | }; | |||
332 | GOptionContext *ctx; | |||
333 | GError *error = NULL((void*)0); | |||
334 | ||||
335 | ctx = g_option_context_new (NULL((void*)0)); | |||
336 | g_option_context_add_main_entries (ctx, options, "croma"); | |||
337 | if (!g_option_context_parse (ctx, argc, argv, &error)) | |||
338 | { | |||
339 | g_print ("croma: %s\n", error->message); | |||
340 | exit(1); | |||
341 | } | |||
342 | g_option_context_free (ctx); | |||
343 | /* Return the parsed options through the meta_args param. */ | |||
344 | *meta_args = my_args; | |||
345 | } | |||
346 | ||||
347 | /** | |||
348 | * Selects which display Croma should use. It first tries to use | |||
349 | * display_name as the display. If display_name is NULL then | |||
350 | * try to use the environment variable CROMA_DISPLAY. If that | |||
351 | * also is NULL, use the default - :0.0 | |||
352 | */ | |||
353 | static void | |||
354 | meta_select_display (gchar *display_name) | |||
355 | { | |||
356 | gchar *envVar = ""; | |||
357 | if (display_name) | |||
358 | envVar = g_strconcat ("DISPLAY=", display_name, NULL((void*)0)); | |||
359 | else if (g_getenv ("CROMA_DISPLAY")) | |||
360 | envVar = g_strconcat ("DISPLAY=", | |||
361 | g_getenv ("CROMA_DISPLAY"), NULL((void*)0)); | |||
362 | /* DO NOT FREE envVar, putenv() sucks */ | |||
363 | putenv (envVar); | |||
364 | } | |||
365 | ||||
366 | static void | |||
367 | meta_finalize (void) | |||
368 | { | |||
369 | MetaDisplay *display = meta_get_display(); | |||
370 | if (display) | |||
371 | meta_display_close (display, | |||
372 | CurrentTime0L); /* I doubt correct timestamps matter here */ | |||
373 | ||||
374 | meta_session_shutdown (); | |||
375 | } | |||
376 | ||||
377 | static int sigterm_pipe_fds[2] = { -1, -1 }; | |||
378 | ||||
379 | static void | |||
380 | sigterm_handler (int signum) | |||
381 | { | |||
382 | if (sigterm_pipe_fds[1] >= 0) | |||
383 | { | |||
384 | G_GNUC_UNUSED__attribute__ ((__unused__)) int dummy; | |||
385 | ||||
386 | dummy = write (sigterm_pipe_fds[1], "", 1); | |||
387 | close (sigterm_pipe_fds[1]); | |||
388 | sigterm_pipe_fds[1] = -1; | |||
389 | } | |||
390 | } | |||
391 | ||||
392 | static gboolean | |||
393 | on_sigterm (GIOChannel *source, | |||
394 | GIOCondition condition, | |||
395 | gpointer user_data) | |||
396 | { | |||
397 | meta_quit (META_EXIT_SUCCESS); | |||
398 | return FALSE(0); | |||
399 | } | |||
400 | ||||
401 | /** | |||
402 | * This is where the story begins. It parses commandline options and | |||
403 | * environment variables, sets up the screen, hands control off to | |||
404 | * CTK, and cleans up afterwards. | |||
405 | * | |||
406 | * \param argc Number of arguments (as usual) | |||
407 | * \param argv Array of arguments (as usual) | |||
408 | * | |||
409 | * \bug It's a bit long. It would be good to split it out into separate | |||
410 | * functions. | |||
411 | */ | |||
412 | int | |||
413 | main (int argc, char **argv) | |||
414 | { | |||
415 | struct sigaction act; | |||
416 | sigset_t empty_mask; | |||
417 | MetaArguments meta_args; | |||
418 | const gchar *log_domains[] = { | |||
419 | NULL((void*)0), G_LOG_DOMAIN"croma", "Ctk", "Cdk", "GLib", | |||
420 | "Pango", "GLib-GObject", "GThread" | |||
421 | }; | |||
422 | guint i; | |||
423 | GIOChannel *channel; | |||
424 | ||||
425 | if (setlocale (LC_ALL6, "") == NULL((void*)0)) | |||
| ||||
426 | meta_warning ("Locale not understood by C library, internationalization will not work\n"); | |||
427 | ||||
428 | sigemptyset (&empty_mask); | |||
429 | act.sa_handler__sigaction_handler.sa_handler = SIG_IGN((__sighandler_t) 1); | |||
| ||||
430 | act.sa_mask = empty_mask; | |||
431 | act.sa_flags = 0; | |||
432 | if (sigaction (SIGPIPE13, &act, NULL((void*)0)) < 0) | |||
433 | g_printerr ("Failed to register SIGPIPE handler: %s\n", | |||
434 | g_strerror (errno(*__errno_location ()))); | |||
435 | #ifdef SIGXFSZ25 | |||
436 | if (sigaction (SIGXFSZ25, &act, NULL((void*)0)) < 0) | |||
437 | g_printerr ("Failed to register SIGXFSZ handler: %s\n", | |||
438 | g_strerror (errno(*__errno_location ()))); | |||
439 | #endif | |||
440 | ||||
441 | if (pipe (sigterm_pipe_fds) != 0) | |||
442 | g_printerr ("Failed to create SIGTERM pipe: %s\n", | |||
443 | g_strerror (errno(*__errno_location ()))); | |||
444 | ||||
445 | channel = g_io_channel_unix_new (sigterm_pipe_fds[0]); | |||
446 | g_io_channel_set_flags (channel, G_IO_FLAG_NONBLOCK, NULL((void*)0)); | |||
447 | g_io_add_watch (channel, G_IO_IN, on_sigterm, NULL((void*)0)); | |||
448 | g_io_channel_set_close_on_unref (channel, TRUE(!(0))); | |||
449 | g_io_channel_unref (channel); | |||
450 | ||||
451 | act.sa_handler__sigaction_handler.sa_handler = &sigterm_handler; | |||
452 | if (sigaction (SIGTERM15, &act, NULL((void*)0)) < 0) | |||
453 | g_printerr ("Failed to register SIGTERM handler: %s\n", | |||
454 | g_strerror (errno(*__errno_location ()))); | |||
455 | ||||
456 | if (g_getenv ("CROMA_VERBOSE")) | |||
457 | meta_set_verbose (TRUE(!(0))); | |||
458 | if (g_getenv ("CROMA_DEBUG")) | |||
459 | meta_set_debugging (TRUE(!(0))); | |||
460 | ||||
461 | if (g_get_home_dir ()) | |||
462 | if (chdir (g_get_home_dir ()) < 0) | |||
463 | meta_warning ("Could not change to home directory %s.\n", | |||
464 | g_get_home_dir ()); | |||
465 | ||||
466 | meta_print_self_identity (); | |||
467 | ||||
468 | bindtextdomain (GETTEXT_PACKAGE"croma", CROMA_LOCALEDIR"/usr/share/locale"); | |||
469 | bind_textdomain_codeset (GETTEXT_PACKAGE"croma", "UTF-8"); | |||
470 | textdomain (GETTEXT_PACKAGE"croma"); | |||
471 | ||||
472 | /* Parse command line arguments.*/ | |||
473 | meta_parse_options (&argc, &argv, &meta_args); | |||
474 | ||||
475 | meta_set_syncing (meta_args.sync || (g_getenv ("CROMA_SYNC") != NULL((void*)0))); | |||
476 | ||||
477 | if (meta_args.print_version) | |||
478 | version (); | |||
479 | ||||
480 | meta_select_display (meta_args.display_name); | |||
481 | ||||
482 | if (meta_args.replace_wm) | |||
483 | meta_set_replace_current_wm (TRUE(!(0))); | |||
484 | ||||
485 | if (meta_args.save_file && meta_args.client_id) | |||
486 | meta_fatal ("Can't specify both SM save file and SM client id\n"); | |||
487 | ||||
488 | meta_main_loop = g_main_loop_new (NULL((void*)0), FALSE(0)); | |||
489 | ||||
490 | meta_ui_init (&argc, &argv); | |||
491 | ||||
492 | /* Load prefs */ | |||
493 | meta_prefs_init (); | |||
494 | meta_prefs_add_listener (prefs_changed_callback, NULL((void*)0)); | |||
495 | ||||
496 | ||||
497 | #if 1 | |||
498 | ||||
499 | for (i=0; i<G_N_ELEMENTS(log_domains)(sizeof (log_domains) / sizeof ((log_domains)[0])); i++) | |||
500 | g_log_set_handler (log_domains[i], | |||
501 | G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION, | |||
502 | log_handler, NULL((void*)0)); | |||
503 | ||||
504 | #endif | |||
505 | ||||
506 | if (g_getenv ("CROMA_G_FATAL_WARNINGS") != NULL((void*)0)) | |||
507 | g_log_set_always_fatal (G_LOG_LEVEL_MASK); | |||
508 | ||||
509 | meta_ui_set_current_theme (meta_prefs_get_theme (), FALSE(0)); | |||
510 | ||||
511 | /* Try to find some theme that'll work if the theme preference | |||
512 | * doesn't exist. First try Simple (the default theme) then just | |||
513 | * try anything in the themes directory. | |||
514 | */ | |||
515 | if (!meta_ui_have_a_theme ()) | |||
516 | meta_ui_set_current_theme ("Simple", FALSE(0)); | |||
517 | ||||
518 | if (!meta_ui_have_a_theme ()) | |||
519 | { | |||
520 | const char *dir_entry = NULL((void*)0); | |||
521 | GError *err = NULL((void*)0); | |||
522 | GDir *themes_dir = NULL((void*)0); | |||
523 | ||||
524 | if (!(themes_dir = g_dir_open (CROMA_DATADIR"/usr/share""/themes", 0, &err))) | |||
525 | { | |||
526 | meta_fatal (_("Failed to scan themes directory: %s\n")dgettext ("croma", "Failed to scan themes directory: %s\n"), err->message); | |||
527 | g_error_free (err); | |||
528 | } | |||
529 | else | |||
530 | { | |||
531 | while (((dir_entry = g_dir_read_name (themes_dir)) != NULL((void*)0)) && | |||
532 | (!meta_ui_have_a_theme ())) | |||
533 | { | |||
534 | meta_ui_set_current_theme (dir_entry, FALSE(0)); | |||
535 | } | |||
536 | ||||
537 | g_dir_close (themes_dir); | |||
538 | } | |||
539 | } | |||
540 | ||||
541 | if (!meta_ui_have_a_theme ()) | |||
542 | meta_fatal (_("Could not find a theme! Be sure %s exists and contains the usual themes.\n")dgettext ("croma", "Could not find a theme! Be sure %s exists and contains the usual themes.\n" ), | |||
543 | CROMA_DATADIR"/usr/share""/themes"); | |||
544 | ||||
545 | /* Connect to SM as late as possible - but before managing display, | |||
546 | * or we might try to manage a window before we have the session | |||
547 | * info | |||
548 | */ | |||
549 | if (!meta_args.disable_sm) | |||
550 | { | |||
551 | if (meta_args.client_id == NULL((void*)0)) | |||
552 | { | |||
553 | const gchar *desktop_autostart_id; | |||
554 | ||||
555 | desktop_autostart_id = g_getenv ("DESKTOP_AUTOSTART_ID"); | |||
556 | ||||
557 | if (desktop_autostart_id != NULL((void*)0)) | |||
558 | meta_args.client_id = g_strdup (desktop_autostart_id)g_strdup_inline (desktop_autostart_id); | |||
559 | } | |||
560 | ||||
561 | /* Unset DESKTOP_AUTOSTART_ID in order to avoid child processes to | |||
562 | * use the same client id. */ | |||
563 | g_unsetenv ("DESKTOP_AUTOSTART_ID"); | |||
564 | ||||
565 | meta_session_init (meta_args.client_id, meta_args.save_file); | |||
566 | } | |||
567 | /* Free memory possibly allocated by the argument parsing which are | |||
568 | * no longer needed. | |||
569 | */ | |||
570 | g_free (meta_args.save_file); | |||
571 | g_free (meta_args.display_name); | |||
572 | g_free (meta_args.client_id); | |||
573 | ||||
574 | if (meta_args.composite || meta_args.no_composite) | |||
575 | meta_prefs_set_force_compositing_manager (meta_args.composite); | |||
576 | ||||
577 | if (meta_args.no_force_fullscreen) | |||
578 | meta_prefs_set_force_fullscreen (FALSE(0)); | |||
579 | ||||
580 | if (!meta_display_open ()) | |||
581 | meta_exit (META_EXIT_ERROR); | |||
582 | ||||
583 | g_main_loop_run (meta_main_loop); | |||
584 | ||||
585 | meta_finalize (); | |||
586 | ||||
587 | if (meta_restart_after_quit) | |||
588 | { | |||
589 | GError *err; | |||
590 | ||||
591 | err = NULL((void*)0); | |||
592 | if (!g_spawn_async (NULL((void*)0), | |||
593 | argv, | |||
594 | NULL((void*)0), | |||
595 | G_SPAWN_SEARCH_PATH, | |||
596 | NULL((void*)0), | |||
597 | NULL((void*)0), | |||
598 | NULL((void*)0), | |||
599 | &err)) | |||
600 | { | |||
601 | meta_fatal (_("Failed to restart: %s\n")dgettext ("croma", "Failed to restart: %s\n"), | |||
602 | err->message); | |||
603 | g_error_free (err); /* not reached anyhow */ | |||
604 | meta_exit_code = META_EXIT_ERROR; | |||
605 | } | |||
606 | } | |||
607 | ||||
608 | return meta_exit_code; | |||
609 | } | |||
610 | ||||
611 | /** | |||
612 | * Stops Croma. This tells the event loop to stop processing; it is rather | |||
613 | * dangerous to use this rather than meta_restart() because this will leave | |||
614 | * the user with no window manager. We generally do this only if, for example, | |||
615 | * the session manager asks us to; we assume the session manager knows what | |||
616 | * it's talking about. | |||
617 | * | |||
618 | * \param code The success or failure code to return to the calling process. | |||
619 | */ | |||
620 | void | |||
621 | meta_quit (MetaExitCode code) | |||
622 | { | |||
623 | meta_exit_code = code; | |||
624 | ||||
625 | if (g_main_loop_is_running (meta_main_loop)) | |||
626 | g_main_loop_quit (meta_main_loop); | |||
627 | } | |||
628 | ||||
629 | /** | |||
630 | * Restarts Croma. In practice, this tells the event loop to stop | |||
631 | * processing, having first set the meta_restart_after_quit flag which | |||
632 | * tells Croma to spawn an identical copy of itself before quitting. | |||
633 | * This happens on receipt of a _CROMA_RESTART_MESSAGE client event. | |||
634 | */ | |||
635 | void | |||
636 | meta_restart (void) | |||
637 | { | |||
638 | meta_restart_after_quit = TRUE(!(0)); | |||
639 | meta_quit (META_EXIT_SUCCESS); | |||
640 | } | |||
641 | ||||
642 | /** | |||
643 | * Called on pref changes. (One of several functions of its kind and purpose.) | |||
644 | * | |||
645 | * \bug Why are these particular prefs handled in main.c and not others? | |||
646 | * Should they be? | |||
647 | * | |||
648 | * \param pref Which preference has changed | |||
649 | * \param data Arbitrary data (which we ignore) | |||
650 | */ | |||
651 | static void | |||
652 | prefs_changed_callback (MetaPreference pref, | |||
653 | gpointer data) | |||
654 | { | |||
655 | switch (pref) | |||
656 | { | |||
657 | case META_PREF_THEME: | |||
658 | meta_ui_set_current_theme (meta_prefs_get_theme (), FALSE(0)); | |||
659 | meta_display_retheme_all (); | |||
660 | break; | |||
661 | ||||
662 | case META_PREF_CURSOR_THEME: | |||
663 | case META_PREF_CURSOR_SIZE: | |||
664 | meta_display_set_cursor_theme (meta_prefs_get_cursor_theme (), | |||
665 | meta_prefs_get_cursor_size ()); | |||
666 | break; | |||
667 | case META_PREF_ICON_SIZE: | |||
668 | meta_invalidate_all_icons(); | |||
669 | break; | |||
670 | default: | |||
671 | /* handled elsewhere or otherwise */ | |||
672 | break; | |||
673 | } | |||
674 | } |