1 
2 /*
3 * This file is a part of the Cairo-Dock project
4 *
5 * Copyright : (C) see the 'copyright' file.
6 * E-mail    : see the 'copyright' file.
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
10 * as published by the Free Software Foundation; either version 3
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20 /*****************************************************************************************************
21 **
22 ** Program:
23 **    cairo-dock
24 **
25 ** License :
26 **    This program is released under the terms of the GNU General Public License, version 3 or above.
27 **    If you don't know what that means take a look at:
28 **       http://www.gnu.org/licenses/licenses.html#GPL
29 **
30 *********************** VERSION 0 (2006) *********************
31 **
32 ** Original idea :
33 **    Mirco "MacSlow" Mueller <macslow@bangang.de>, June 2006.
34 ** With the help of:
35 **    Behdad Esfahbod <behdad@behdad.org>
36 **    David Reveman <davidr@novell.com>
37 **    Karl Lattimer <karl@qdh.org.uk>
38 ** Originally conceived as a stress-test for cairo, librsvg, and glitz.
39 **
40 *********************** VERSION 0.1 and above (2007-2014) *********************
41 **
42 ** author(s) :
43 **     Fabrice Rey <fabounet@glx-dock.org>
44 ** With the help of:
45 **     A lot of people !!! (see the About menu and the 'copyright' file)
46 **
47 *******************************************************************************/
48 
49 #include <unistd.h> // sleep, execl
50 #include <signal.h>
51 
52 #define __USE_POSIX
53 #include <time.h>
54 
55 #include <glib/gstdio.h>
56 #include <dbus/dbus-glib.h>  // dbus_g_thread_init
57 
58 #include "config.h"
59 #include "cairo-dock-icon-facility.h"  // cairo_dock_get_first_icon
60 #include "cairo-dock-module-manager.h"  // gldi_modules_new_from_directory
61 #include "cairo-dock-module-instance-manager.h"  // GldiModuleInstance
62 #include "cairo-dock-dock-manager.h"
63 #include "cairo-dock-desklet-manager.h"
64 #include "cairo-dock-themes-manager.h"
65 #include "cairo-dock-dialog-factory.h"
66 #include "cairo-dock-keyfile-utilities.h"
67 #include "cairo-dock-config.h"
68 #include "cairo-dock-file-manager.h"
69 #include "cairo-dock-log.h"
70 #include "cairo-dock-keybinder.h"
71 #include "cairo-dock-opengl.h"
72 #include "cairo-dock-packages.h"
73 #include "cairo-dock-utils.h"  // cairo_dock_launch_command
74 #include "cairo-dock-core.h"
75 
76 #include "cairo-dock-gui-manager.h"
77 #include "cairo-dock-gui-backend.h"
78 #include "cairo-dock-user-interaction.h"
79 #include "cairo-dock-user-menu.h"
80 
81 //#define CAIRO_DOCK_THEME_SERVER "http://themes.glx-dock.org"
82 #define CAIRO_DOCK_THEME_SERVER "http://download.tuxfamily.org/glxdock/themes"
83 #define CAIRO_DOCK_BACKUP_THEME_SERVER "http://fabounet03.free.fr"
84 // Nom du repertoire racine du theme courant.
85 #define CAIRO_DOCK_CURRENT_THEME_NAME "current_theme"
86 // Nom du repertoire des themes extras.
87 #define CAIRO_DOCK_EXTRAS_DIR "extras"
88 
89 extern gchar *g_cCairoDockDataDir;
90 extern gchar *g_cCurrentThemePath;
91 
92 extern gchar *g_cConfFile;
93 extern int g_iMajorVersion, g_iMinorVersion, g_iMicroVersion;
94 
95 extern CairoDock *g_pMainDock;
96 extern CairoDockGLConfig g_openglConfig;
97 
98 extern gboolean g_bUseOpenGL;
99 extern gboolean g_bEasterEggs;
100 
101 extern GldiModuleInstance *g_pCurrentModule;
102 extern GtkWidget *cairo_dock_build_simple_gui_window (void);
103 
104 gboolean g_bForceCairo = FALSE;
105 gboolean g_bLocked;
106 
107 static gboolean s_bSucessfulLaunch = FALSE;
108 static GString *s_pLaunchCommand = NULL;
109 static gchar *s_cLastVersion = NULL;
110 static gchar *s_cDefaulBackend = NULL;
111 static gint s_iGuiMode = 0;  // 0 = simple mode, 1 = advanced mode
112 static gint s_iLastYear = 0;
113 static gint s_iNbCrashes = 0;
114 static gboolean s_bPingServer = TRUE;
115 static gboolean s_bCDSessionLaunched = FALSE; // session CD already launched?
116 
117 
_on_got_server_answer(const gchar * data,G_GNUC_UNUSED gpointer user_data)118 static void _on_got_server_answer (const gchar *data, G_GNUC_UNUSED gpointer user_data)
119 {
120 	if (data != NULL)
121 	{
122 		s_bPingServer = TRUE;  // after we got the answer, we can write in the global file to not try any more.
123 		gchar *cConfFilePath = g_strdup_printf ("%s/.cairo-dock", g_cCairoDockDataDir);
124 		cairo_dock_update_conf_file (cConfFilePath,
125 			G_TYPE_BOOLEAN, "Launch", "ping server", s_bPingServer,
126 			G_TYPE_INVALID);
127 		g_free (cConfFilePath);
128 	}
129 }
_cairo_dock_successful_launch(gpointer data)130 static gboolean _cairo_dock_successful_launch (gpointer data)
131 {
132 	s_bSucessfulLaunch = TRUE;
133 	// new year greetings.
134 	time_t t = time (NULL);
135 	struct tm st;
136 	localtime_r (&t, &st);
137 
138 	if (!data && st.tm_mday <= 15 && st.tm_mon == 0 && s_iLastYear < st.tm_year + 1900)  // first 2 weeks of january + not first launch
139 	{
140 		s_iLastYear = st.tm_year + 1900;
141 		gchar *cConfFilePath = g_strdup_printf ("%s/.cairo-dock", g_cCairoDockDataDir);
142 		cairo_dock_update_conf_file (cConfFilePath,
143 			G_TYPE_INT, "Launch", "last year", s_iLastYear,
144 			G_TYPE_INVALID);
145 		g_free (cConfFilePath);
146 
147 		Icon *pIcon = gldi_icons_get_any_without_dialog ();
148 		gchar *cMessage = g_strdup_printf (_("Happy new year %d !!!"), s_iLastYear);
149 		gchar *cMessageFull = g_strdup_printf ("\n%s :-)\n", cMessage);
150 		gldi_dialog_show_temporary_with_icon (cMessageFull, pIcon, CAIRO_CONTAINER (g_pMainDock), 15000., CAIRO_DOCK_SHARE_DATA_DIR"/icons/balloons.png");
151 		g_free (cMessageFull);
152 		g_free (cMessage);
153 	}
154 
155 	if (! s_bPingServer && g_str_has_suffix (g_cCairoDockDataDir, CAIRO_DOCK_DATA_DIR))  // the server (which hosts themes, third-party applets and packages) has never been accessed yet, ping it once
156 	{
157 		s_bPingServer = TRUE;
158 		cairo_dock_get_url_data_async (CAIRO_DOCK_THEME_SERVER"/ping.txt", (GFunc)_on_got_server_answer, NULL);
159 	}
160 
161 	return FALSE;
162 }
_cairo_dock_first_launch_setup(G_GNUC_UNUSED gpointer data)163 static gboolean _cairo_dock_first_launch_setup (G_GNUC_UNUSED gpointer data)
164 {
165 	cairo_dock_launch_command (CAIRO_DOCK_SHARE_DATA_DIR"/scripts/initial-setup.sh");
166 	return FALSE;
167 }
_cairo_dock_quit(G_GNUC_UNUSED int signal)168 static void _cairo_dock_quit (G_GNUC_UNUSED int signal)
169 {
170 	gtk_main_quit ();
171 }
172 /* Crash at startup:
173  *  - First 2 crashes: retry with a delay of 2 sec (maybe due to a problem at startup)
174  *  - 3th crash: remove the applet and restart the dock
175  *  - 4th crash: show the maintenance mode
176  *  - 5th crash: quit
177  */
_cairo_dock_intercept_signal(int signal)178 static void _cairo_dock_intercept_signal (int signal)
179 {
180 	cd_warning ("Cairo-Dock has crashed (sig %d).\nIt will be restarted now.\nFeel free to report this bug on glx-dock.org to help improving the dock!", signal);
181 	g_print ("info on the system :\n");
182 	int r = system ("uname -a");
183 	if (r < 0)
184 		cd_warning ("Not able to launch this command: uname");
185 
186 	// if a module is responsible, expose it to public shame.
187 	if (g_pCurrentModule != NULL)
188 	{
189 		g_print ("The applet '%s' may be the culprit", g_pCurrentModule->pModule->pVisitCard->cModuleName);
190 		if (! s_bSucessfulLaunch)  // else, be quiet.
191 			g_string_append_printf (s_pLaunchCommand, " -x \"%s\"", g_pCurrentModule->pModule->pVisitCard->cModuleName);
192 	}
193 	else
194 	{
195 		g_print ("Couldn't guess if it was an applet's fault or not. It may have crashed inside the core or inside a thread\n");
196 	}
197 
198 	// if the crash occurs on startup, take additionnal measures; else just respawn quietly.
199 	if (! s_bSucessfulLaunch)  // a crash on startup,
200 	{
201 		if (s_iNbCrashes < 2)  // the first 2 crashes, restart with a delay (in case we were launched too early on startup).
202 			g_string_append (s_pLaunchCommand, " -w 2");  // 2s delay.
203 		else if (g_pCurrentModule == NULL || s_iNbCrashes == 3)  // crash and no culprit or 4th crash => start in maintenance mode.
204 			g_string_append (s_pLaunchCommand, " -m");
205 		g_string_append_printf (s_pLaunchCommand, " -q %d", s_iNbCrashes + 1);  // increment the first-crash counter.
206 	}  // else a random crash, respawn quietly.
207 
208 	g_print ("restarting with '%s'...\n", s_pLaunchCommand->str);
209 	execl ("/bin/sh", "/bin/sh", "-c", s_pLaunchCommand->str, (char *)NULL);  // on ne revient pas de cette fonction.
210 	//execlp ("cairo-dock", "cairo-dock", s_pLaunchCommand->str, (char *)0);
211 	cd_warning ("Sorry, couldn't restart the dock");
212 }
_cairo_dock_set_signal_interception(void)213 static void _cairo_dock_set_signal_interception (void)
214 {
215 	signal (SIGSEGV, _cairo_dock_intercept_signal);  // Segmentation violation
216 	signal (SIGFPE, _cairo_dock_intercept_signal);  // Floating-point exception
217 	signal (SIGILL, _cairo_dock_intercept_signal);  // Illegal instruction
218 	signal (SIGABRT, _cairo_dock_intercept_signal);  // Abort // kill -6
219 }
220 
on_delete_maintenance_gui(G_GNUC_UNUSED GtkWidget * pWidget,GMainLoop * pBlockingLoop)221 static gboolean on_delete_maintenance_gui (G_GNUC_UNUSED GtkWidget *pWidget, GMainLoop *pBlockingLoop)
222 {
223 	cd_debug ("%s ()", __func__);
224 	if (pBlockingLoop != NULL && g_main_loop_is_running (pBlockingLoop))
225 	{
226 		g_main_loop_quit (pBlockingLoop);
227 	}
228 	return FALSE;  // TRUE <=> ne pas detruire la fenetre.
229 }
230 
PrintMuteFunc(G_GNUC_UNUSED const gchar * string)231 static void PrintMuteFunc (G_GNUC_UNUSED const gchar *string) {}
232 
_cairo_dock_get_global_config(const gchar * cCairoDockDataDir)233 static void _cairo_dock_get_global_config (const gchar *cCairoDockDataDir)
234 {
235 	gchar *cConfFilePath = g_strdup_printf ("%s/.cairo-dock", cCairoDockDataDir);
236 	GKeyFile *pKeyFile = g_key_file_new ();
237 	if (g_file_test (cConfFilePath, G_FILE_TEST_EXISTS))
238 	{
239 		g_key_file_load_from_file (pKeyFile, cConfFilePath, 0, NULL);
240 		s_cLastVersion = g_key_file_get_string (pKeyFile, "Launch", "last version", NULL);
241 		s_cDefaulBackend = g_key_file_get_string (pKeyFile, "Launch", "default backend", NULL);
242 		if (s_cDefaulBackend && *s_cDefaulBackend == '\0')
243 		{
244 			g_free (s_cDefaulBackend);
245 			s_cDefaulBackend = NULL;
246 		}
247 		s_iGuiMode = g_key_file_get_integer (pKeyFile, "Gui", "mode", NULL);  // 0 by default
248 		s_iLastYear = g_key_file_get_integer (pKeyFile, "Launch", "last year", NULL);  // 0 by default
249 		s_bPingServer = g_key_file_get_boolean (pKeyFile, "Launch", "ping server", NULL);  // FALSE by default
250 		s_bCDSessionLaunched = g_key_file_get_boolean (pKeyFile, "Launch", "cd session", NULL);  // FALSE by default
251 	}
252 	else  // first launch or old version, the file doesn't exist yet.
253 	{
254 		gchar *cLastVersionFilePath = g_strdup_printf ("%s/.cairo-dock-last-version", cCairoDockDataDir);
255 		if (g_file_test (cLastVersionFilePath, G_FILE_TEST_EXISTS))
256 		{
257 			gsize length = 0;
258 			g_file_get_contents (cLastVersionFilePath,
259 				&s_cLastVersion,
260 				&length,
261 				NULL);
262 		}
263 		g_remove (cLastVersionFilePath);
264 		g_free (cLastVersionFilePath);
265 		g_key_file_set_string (pKeyFile, "Launch", "last version", s_cLastVersion?s_cLastVersion:"");
266 
267 		g_key_file_set_string (pKeyFile, "Launch", "default backend", "");
268 
269 		g_key_file_set_integer (pKeyFile, "Gui", "mode", s_iGuiMode);
270 
271 		g_key_file_set_integer (pKeyFile, "Launch", "last year", s_iLastYear);
272 
273 		cairo_dock_write_keys_to_file (pKeyFile, cConfFilePath);
274 	}
275 	g_key_file_free (pKeyFile);
276 	g_free (cConfFilePath);
277 }
278 
279 
main(int argc,char ** argv)280 int main (int argc, char** argv)
281 {
282 	//\___________________ build the command line used to respawn, and check if we have been launched from another life.
283 	s_pLaunchCommand = g_string_new (argv[0]);
284 	int i;
285 	for (i = 1; i < argc; i ++)
286 	{
287 		//g_print ("'%s'\n", argv[i]);
288 		if (strcmp (argv[i], "-q") == 0)  // this option is only set by the dock itself, at the end of the command line.
289 		{
290 			s_iNbCrashes = atoi (argv[i+1]);
291 			argc = i;  // remove this option, as it doesn't belong to the options table.
292 			argv[i] = NULL;
293 			break;
294 		}
295 		else if (strcmp (argv[i], "-w") == 0 || strcmp (argv[i], "-x") == 0)  // skip this option and its argument.
296 		{
297 			i ++;
298 		}
299 		else if (strcmp (argv[i], "-m") == 0)  // skip this option
300 		{
301 			// nothing else to do.
302 		}
303 		else  // keep this option in the command line.
304 		{
305 			g_string_append_printf (s_pLaunchCommand, " %s", argv[i]);
306 		}
307 	}
308 	/* Crash: 5th crash: an applet has already been removed and the maintenance
309 	 * mode has already been displayed => stop
310 	 */
311 	if (s_iNbCrashes > 4)
312 	{
313 		g_print ("Sorry, Cairo-Dock has encoutered some problems, and will quit.\n");
314 		return 1;
315 	}
316 
317 	// mute all output messages if CD is not launched from a terminal
318 	if (getenv("TERM") == NULL)  /// why not isatty(stdout) ?...
319 		g_set_print_handler(PrintMuteFunc);
320 
321 
322 	// init lib
323 	#if !defined (GLIB_VERSION_2_36) // no longer needed now... (>= 2.35)
324 	g_type_init (); // should initialise threads too on new versions of GLIB (>= 2.24)
325 	#endif
326 	#if (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION < 24)
327 	if (!g_thread_supported ())
328 		g_thread_init (NULL);
329 	#endif
330 
331 	dbus_g_thread_init (); // it's a wrapper: it will use dbus_threads_init_default ();
332 
333 	gtk_init (&argc, &argv);
334 
335 	GError *erreur = NULL;
336 
337 	//\___________________ internationalize the app.
338 	bindtextdomain (CAIRO_DOCK_GETTEXT_PACKAGE, CAIRO_DOCK_LOCALE_DIR);
339 	bind_textdomain_codeset (CAIRO_DOCK_GETTEXT_PACKAGE, "UTF-8");
340 	textdomain (CAIRO_DOCK_GETTEXT_PACKAGE);
341 
342 	//\___________________ get app's options.
343 	gboolean bSafeMode = FALSE, bMaintenance = FALSE, bNoSticky = FALSE, bCappuccino = FALSE, bPrintVersion = FALSE, bTesting = FALSE, bForceOpenGL = FALSE, bToggleIndirectRendering = FALSE, bKeepAbove = FALSE, bForceColors = FALSE, bAskBackend = FALSE, bMetacityWorkaround = FALSE;
344 	gchar *cEnvironment = NULL, *cUserDefinedDataDir = NULL, *cVerbosity = 0, *cUserDefinedModuleDir = NULL, *cExcludeModule = NULL, *cThemeServerAdress = NULL;
345 	int iDelay = 0;
346 	GOptionEntry pOptionsTable[] =
347 	{
348 		// GLDI options: cairo, opengl, indirect-opengl, env, keep-above, no-sticky
349 		{"cairo", 'c', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_NONE,
350 			&g_bForceCairo,
351 			_("Use Cairo backend."), NULL},
352 		{"opengl", 'o', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_NONE,
353 			&bForceOpenGL,
354 			_("Use OpenGL backend."), NULL},
355 		{"indirect-opengl", 'O', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_NONE,
356 			&bToggleIndirectRendering,
357 			_("Use OpenGL backend with indirect rendering. There are very few case where this option should be used."), NULL},
358 		{"ask-backend", 'A', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_NONE,
359 			&bAskBackend,
360 			_("Ask again on startup which backend to use."), NULL},
361 		{"env", 'e', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_STRING,
362 			&cEnvironment,
363 			_("Force the dock to consider this environnement - use it with care."), NULL},
364 		{"dir", 'd', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_STRING,
365 			&cUserDefinedDataDir,
366 			_("Force the dock to load from this directory, instead of ~/.config/cairo-dock."), NULL},
367 		{"server", 'S', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_STRING,
368 			&cThemeServerAdress,
369 			_("Address of a server containing additional themes. This will overwrite the default server address."), NULL},
370 		{"wait", 'w', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_INT,
371 			&iDelay,
372 			_("Wait for N seconds before starting; this is useful if you notice some problems when the dock starts with the session."), NULL},
373 		{"maintenance", 'm', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_NONE,
374 			&bMaintenance,
375 			_("Allow to edit the config before the dock is started and show the config panel on start."), NULL},
376 		{"exclude", 'x', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_STRING,
377 			&cExcludeModule,
378 			_("Exclude a given plug-in from activating (it is still loaded though)."), NULL},
379 		{"safe-mode", 'f', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_NONE,
380 			&bSafeMode,
381 			_("Don't load any plug-ins."), NULL},
382 		{"metacity-workaround", 'W', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_NONE,
383 			&bMetacityWorkaround,
384 			_("Work around some bugs in Metacity Window-Manager (invisible dialogs or sub-docks)"), NULL},
385 		{"log", 'l', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_STRING,
386 			&cVerbosity,
387 			_("Log verbosity (debug,message,warning,critical,error); default is warning."), NULL},
388 		{"colors", 'F', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_NONE,
389 			&bForceColors,
390 			_("Force to display some output messages with colors."), NULL},
391 		{"version", 'v', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_NONE,
392 			&bPrintVersion,
393 			_("Print version and quit."), NULL},
394 		{"locked", 'k', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_NONE,
395 			&g_bLocked,
396 			_("Lock the dock so that any modification is impossible for users."), NULL},
397 		// below options are probably useless for most of people.
398 		{"keep-above", 'a', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_NONE,
399 			&bKeepAbove,
400 			_("Keep the dock above other windows."), NULL},
401 		{"no-sticky", 's', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_NONE,
402 			&bNoSticky,
403 			_("Don't make the dock appear on all desktops."), NULL},
404 		{"capuccino", 'C', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_NONE,
405 			&bCappuccino,
406 			_("Cairo-Dock makes anything, including coffee !"), NULL},
407 		{"modules-dir", 'M', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_STRING,
408 			&cUserDefinedModuleDir,
409 			_("Ask the dock to load additionnal modules contained in this directory (though it is unsafe for your dock to load unnofficial modules)."), NULL},
410 		{"testing", 'T', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_NONE,
411 			&bTesting,
412 			_("For debugging purpose only. The crash manager will not be started to hunt down the bugs."), NULL},
413 		{"easter-eggs", 'E', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_NONE,
414 			&g_bEasterEggs,
415 			_("For debugging purpose only. Some hidden and still unstable options will be activated."), NULL},
416 		{NULL, 0, 0, 0,
417 			NULL,
418 			NULL, NULL}
419 	};
420 
421 	GOptionContext *context = g_option_context_new ("Cairo-Dock");
422 	g_option_context_add_main_entries (context, pOptionsTable, NULL);
423 	g_option_context_parse (context, &argc, &argv, &erreur);
424 	if (erreur != NULL)
425 	{
426 		cd_error ("ERROR in options: %s", erreur->message);
427 		return 1;
428 	}
429 
430 	if (bPrintVersion)
431 	{
432 		g_print ("%s\n", CAIRO_DOCK_VERSION);
433 		return 0;
434 	}
435 
436 	if (g_bLocked)
437 		cd_warning ("Cairo-Dock will be locked.");
438 
439 	if (cVerbosity != NULL)
440 	{
441 		cd_log_set_level_from_name (cVerbosity);
442 		g_free (cVerbosity);
443 	}
444 
445 	if (bForceColors)
446 		cd_log_force_use_color ();
447 
448 	CairoDockDesktopEnv iDesktopEnv = CAIRO_DOCK_UNKNOWN_ENV;
449 	if (cEnvironment != NULL)
450 	{
451 		if (strcmp (cEnvironment, "gnome") == 0)
452 			iDesktopEnv = CAIRO_DOCK_GNOME;
453 		else if (strcmp (cEnvironment, "kde") == 0)
454 			iDesktopEnv = CAIRO_DOCK_KDE;
455 		else if (strcmp (cEnvironment, "xfce") == 0)
456 			iDesktopEnv = CAIRO_DOCK_XFCE;
457 		else if (strcmp (cEnvironment, "none") == 0)
458 			iDesktopEnv = CAIRO_DOCK_UNKNOWN_ENV;
459 		else
460 			cd_warning ("Unknown environment '%s'", cEnvironment);
461 		g_free (cEnvironment);
462 	}
463 
464 	if (bCappuccino)
465 	{
466 		const gchar *cCappuccino = _("Cairo-Dock makes anything, including coffee !");
467 		g_print ("%s\n", cCappuccino);
468 		return 0;
469 	}
470 
471 	//\___________________ get global config.
472 	gboolean bFirstLaunch = FALSE;
473 	gchar *cRootDataDirPath;
474 	// if the user has specified the '-d' parameter.
475 	if (cUserDefinedDataDir != NULL)
476 	{
477 		// if 'cRootDataDirPath' is not a full path, we will have a few problems with image in the config panel without a full path (e.g. 'bg.svg' in the default theme)
478 		if (*cUserDefinedDataDir == '/')
479 			cRootDataDirPath = cUserDefinedDataDir;
480 		else if (*cUserDefinedDataDir == '~')
481 			cRootDataDirPath = g_strdup_printf ("%s%s", getenv("HOME"), cUserDefinedDataDir + 1);
482 		else
483 			cRootDataDirPath = g_strdup_printf ("%s/%s", g_get_current_dir(), cUserDefinedDataDir);
484 		cUserDefinedDataDir = NULL;
485 	}
486 	else
487 	{
488 		cRootDataDirPath = g_strdup_printf ("%s/.config/%s", getenv("HOME"), CAIRO_DOCK_DATA_DIR);
489 	}
490 	bFirstLaunch = ! g_file_test (cRootDataDirPath, G_FILE_TEST_IS_DIR);
491 	_cairo_dock_get_global_config (cRootDataDirPath);
492 	if (bAskBackend)
493 	{
494 		g_free (s_cDefaulBackend);
495 		s_cDefaulBackend = NULL;
496 	}
497 
498 	//\___________________ delay the startup if specified.
499 	if (iDelay > 0)
500 	{
501 		sleep (iDelay);
502 	}
503 
504 	//\___________________ initialize libgldi.
505 	GldiRenderingMethod iRendering = (bForceOpenGL ? GLDI_OPENGL : g_bForceCairo ? GLDI_CAIRO : GLDI_DEFAULT);
506 	gldi_init (iRendering);
507 
508 	//\___________________ set custom user options.
509 	if (bKeepAbove)
510 		cairo_dock_force_docks_above ();
511 
512 	if (bNoSticky)
513 		cairo_dock_set_containers_non_sticky ();
514 
515 	if (bMetacityWorkaround)
516 		cairo_dock_disable_containers_opacity ();
517 
518 	if (iDesktopEnv != CAIRO_DOCK_UNKNOWN_ENV)
519 		cairo_dock_fm_force_desktop_env (iDesktopEnv);
520 
521 	if (bToggleIndirectRendering)
522 		gldi_gl_backend_force_indirect_rendering ();
523 
524 	gchar *cExtraDirPath = g_strconcat (cRootDataDirPath, "/"CAIRO_DOCK_EXTRAS_DIR, NULL);
525 	gchar *cThemesDirPath = g_strconcat (cRootDataDirPath, "/"CAIRO_DOCK_THEMES_DIR, NULL);
526 	gchar *cCurrentThemeDirPath = g_strconcat (cRootDataDirPath, "/"CAIRO_DOCK_CURRENT_THEME_NAME, NULL);
527 
528 	cairo_dock_set_paths (cRootDataDirPath, cExtraDirPath, cThemesDirPath, cCurrentThemeDirPath, (gchar*)CAIRO_DOCK_SHARE_THEMES_DIR, (gchar*)CAIRO_DOCK_DISTANT_THEMES_DIR, cThemeServerAdress ? cThemeServerAdress : g_strdup (CAIRO_DOCK_THEME_SERVER));
529 
530 	//\___________________ Check that OpenGL is safely usable, if not ask the user what to do.
531 	if (bAskBackend || (g_bUseOpenGL && ! bForceOpenGL && ! bToggleIndirectRendering && ! gldi_gl_backend_is_safe ()))  // opengl disponible sans l'avoir force mais pas safe => on demande confirmation.
532 	{
533 		if (s_cDefaulBackend == NULL)  // pas de backend par defaut defini.
534 		{
535 			GtkWidget *dialog = gtk_dialog_new_with_buttons (_("Use OpenGL in Cairo-Dock"),
536 				NULL,
537 				GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
538 				_("Yes"),
539 				GTK_RESPONSE_YES,
540 				_("No"),
541 				GTK_RESPONSE_NO,
542 				NULL);
543 			GtkWidget *label = gtk_label_new (_("OpenGL allows you to use the hardware acceleration, reducing the CPU load to the minimum.\nIt also allows some pretty visual effects similar to Compiz.\nHowever, some cards and/or their drivers don't fully support it, which may prevent the dock from running correctly.\nDo you want to activate OpenGL ?\n (To not show this dialog, launch the dock from the Application menu,\n  or with the -o option to force OpenGL and -c to force cairo.)"));
544 			GtkWidget *pContentBox = gtk_dialog_get_content_area (GTK_DIALOG(dialog));
545 
546 			gtk_box_pack_start (GTK_BOX (pContentBox), label, FALSE, FALSE, 0);
547 
548 			GtkWidget *pAskBox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 3);
549 			gtk_box_pack_start (GTK_BOX (pContentBox), pAskBox, FALSE, FALSE, 0);
550 			label = gtk_label_new (_("Remember this choice"));
551 			GtkWidget *pCheckBox = gtk_check_button_new ();
552 			gtk_box_pack_end (GTK_BOX (pAskBox), pCheckBox, FALSE, FALSE, 0);
553 			gtk_box_pack_end (GTK_BOX (pAskBox), label, FALSE, FALSE, 0);
554 
555 			gtk_widget_show_all (dialog);
556 
557 			gint iAnswer = gtk_dialog_run (GTK_DIALOG (dialog));  // lance sa propre main loop, c'est pourquoi on peut le faire avant le gtk_main().
558 			gboolean bRememberChoice = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (pCheckBox));
559 			gtk_widget_destroy (dialog);
560 			if (iAnswer == GTK_RESPONSE_NO)
561 			{
562 				gldi_gl_backend_deactivate ();
563 			}
564 
565 			if (bRememberChoice)  // l'utilisateur a defini le choix par defaut.
566 			{
567 				s_cDefaulBackend = g_strdup (iAnswer == GTK_RESPONSE_NO ? "cairo" : "opengl");
568 				gchar *cConfFilePath = g_strdup_printf ("%s/.cairo-dock", g_cCairoDockDataDir);
569 				cairo_dock_update_conf_file (cConfFilePath,
570 					G_TYPE_STRING, "Launch", "default backend", s_cDefaulBackend,
571 					G_TYPE_INVALID);
572 				g_free (cConfFilePath);
573 			}
574 		}
575 		else if (strcmp (s_cDefaulBackend, "opengl") != 0)  // un backend par defaut qui n'est pas OpenGL.
576 		{
577 			gldi_gl_backend_deactivate ();
578 		}
579 	}
580 	g_print ("\n"
581 	" ============================================================================\n"
582 	"\tCairo-Dock version : %s\n"
583 	"\tCompiled date      : %s %s\n"
584 	"\tBuilt with GTK     : %d.%d\n"
585 	"\tRunning with OpenGL: %d\n"
586 	" ============================================================================\n\n",
587 		CAIRO_DOCK_VERSION,
588 		__DATE__, __TIME__,
589 		GTK_MAJOR_VERSION, GTK_MINOR_VERSION,
590 		g_bUseOpenGL);
591 
592 	//\___________________ load plug-ins (must be done after everything is initialized).
593 	if (! bSafeMode)
594 	{
595 		gldi_modules_new_from_directory (NULL, &erreur);  // load gldi-based plug-ins
596 		if (erreur != NULL)
597 		{
598 			cd_warning ("%s\n  no module will be available", erreur->message);
599 			g_error_free (erreur);
600 			erreur = NULL;
601 		}
602 
603 		if (cUserDefinedModuleDir != NULL)
604 		{
605 			gldi_modules_new_from_directory (cUserDefinedModuleDir, &erreur);  // load user plug-ins
606 			if (erreur != NULL)
607 			{
608 				cd_warning ("%s\n  no additionnal module will be available", erreur->message);
609 				g_error_free (erreur);
610 				erreur = NULL;
611 			}
612 			g_free (cUserDefinedModuleDir);
613 			cUserDefinedModuleDir = NULL;
614 		}
615 	}
616 
617 	//\___________________ define GUI backend.
618 	cairo_dock_load_user_gui_backend (s_iGuiMode);
619 
620 	//\___________________ register to the useful notifications.
621 	gldi_object_register_notification (&myContainerObjectMgr,
622 		NOTIFICATION_DROP_DATA,
623 		(GldiNotificationFunc) cairo_dock_notification_drop_data,
624 		GLDI_RUN_AFTER, NULL);
625 	gldi_object_register_notification (&myContainerObjectMgr,
626 		NOTIFICATION_CLICK_ICON,
627 		(GldiNotificationFunc) cairo_dock_notification_click_icon,
628 		GLDI_RUN_AFTER, NULL);
629 	gldi_object_register_notification (&myContainerObjectMgr,
630 		NOTIFICATION_MIDDLE_CLICK_ICON,
631 		(GldiNotificationFunc) cairo_dock_notification_middle_click_icon,
632 		GLDI_RUN_AFTER, NULL);
633 	gldi_object_register_notification (&myContainerObjectMgr,
634 		NOTIFICATION_SCROLL_ICON,
635 		(GldiNotificationFunc) cairo_dock_notification_scroll_icon,
636 		GLDI_RUN_AFTER, NULL);
637 	gldi_object_register_notification (&myContainerObjectMgr,
638 		NOTIFICATION_BUILD_CONTAINER_MENU,
639 		(GldiNotificationFunc) cairo_dock_notification_build_container_menu,
640 		GLDI_RUN_FIRST, NULL);
641 	gldi_object_register_notification (&myContainerObjectMgr,
642 		NOTIFICATION_BUILD_ICON_MENU,
643 		(GldiNotificationFunc) cairo_dock_notification_build_icon_menu,
644 		GLDI_RUN_AFTER, NULL);
645 
646 	gldi_object_register_notification (&myDeskletObjectMgr,
647 		NOTIFICATION_CONFIGURE_DESKLET,
648 		(GldiNotificationFunc) cairo_dock_notification_configure_desklet,
649 		GLDI_RUN_AFTER, NULL);
650 	gldi_object_register_notification (&myDockObjectMgr,
651 		NOTIFICATION_ICON_MOVED,
652 		(GldiNotificationFunc) cairo_dock_notification_icon_moved,
653 		GLDI_RUN_AFTER, NULL);
654 	gldi_object_register_notification (&myDockObjectMgr,
655 		NOTIFICATION_DESTROY,
656 		(GldiNotificationFunc) cairo_dock_notification_dock_destroyed,
657 		GLDI_RUN_AFTER, NULL);
658 	gldi_object_register_notification (&myModuleObjectMgr,
659 		NOTIFICATION_MODULE_ACTIVATED,
660 		(GldiNotificationFunc) cairo_dock_notification_module_activated,
661 		GLDI_RUN_AFTER, NULL);
662 	gldi_object_register_notification (&myModuleObjectMgr,
663 		NOTIFICATION_MODULE_REGISTERED,
664 		(GldiNotificationFunc) cairo_dock_notification_module_registered,
665 		GLDI_RUN_AFTER, NULL);
666 	gldi_object_register_notification (&myModuleInstanceObjectMgr,
667 		NOTIFICATION_MODULE_INSTANCE_DETACHED,
668 		(GldiNotificationFunc) cairo_dock_notification_module_detached,
669 		GLDI_RUN_AFTER, NULL);
670 	gldi_object_register_notification (&myDockObjectMgr,
671 		NOTIFICATION_INSERT_ICON,
672 		(GldiNotificationFunc) cairo_dock_notification_icon_inserted,
673 		GLDI_RUN_AFTER, NULL);
674 	gldi_object_register_notification (&myDockObjectMgr,
675 		NOTIFICATION_REMOVE_ICON,
676 		(GldiNotificationFunc) cairo_dock_notification_icon_removed,
677 		GLDI_RUN_AFTER, NULL);
678 	gldi_object_register_notification (&myDeskletObjectMgr,
679 		NOTIFICATION_DESTROY,
680 		(GldiNotificationFunc) cairo_dock_notification_desklet_added_removed,
681 		GLDI_RUN_AFTER, NULL);
682 	gldi_object_register_notification (&myDeskletObjectMgr,
683 		NOTIFICATION_NEW,
684 		(GldiNotificationFunc) cairo_dock_notification_desklet_added_removed,
685 		GLDI_RUN_AFTER, NULL);
686 	gldi_object_register_notification (&myShortkeyObjectMgr,
687 		NOTIFICATION_NEW,
688 		(GldiNotificationFunc) cairo_dock_notification_shortkey_added_removed_changed,
689 		GLDI_RUN_AFTER, NULL);
690 	gldi_object_register_notification (&myShortkeyObjectMgr,
691 		NOTIFICATION_DESTROY,
692 		(GldiNotificationFunc) cairo_dock_notification_shortkey_added_removed_changed,
693 		GLDI_RUN_AFTER, NULL);
694 	gldi_object_register_notification (&myShortkeyObjectMgr,
695 		NOTIFICATION_SHORTKEY_CHANGED,
696 		(GldiNotificationFunc) cairo_dock_notification_shortkey_added_removed_changed,
697 		GLDI_RUN_AFTER, NULL);
698 
699 	//\___________________ handle crashes.
700 	if (! bTesting)
701 		_cairo_dock_set_signal_interception ();
702 
703 	//\___________________ handle terminate signals to quit properly (especially when the system shuts down).
704 	signal (SIGTERM, _cairo_dock_quit);  // Term // kill -15 (system)
705 	signal (SIGHUP,  _cairo_dock_quit);  // sent to a process when its controlling terminal is closed
706 
707 	//\___________________ Disable modules that have crashed
708 	if (cExcludeModule != NULL && (s_iNbCrashes > 2 || bMaintenance)) // 3th crash or 4th (with -m)
709 	{
710 		gchar *cCommand = g_strdup_printf ("sed -i \"/modules/ s/%s//g\" \"%s\"",
711 			cExcludeModule, g_cConfFile);
712 		int r = system (cCommand);
713 		if (r < 0)
714 			cd_warning ("Not able to launch this command: %s", cCommand);
715 		else
716 			cd_warning (_("The module '%s' has been deactivated because it may "
717 			"have caused some problems.\nYou can reactivate it, if it happens "
718 			"again thanks to report it at http://glx-dock.org"), cExcludeModule);
719 		g_free (cCommand);
720 	}
721 
722 	//\___________________ maintenance mode -> show the main config panel.
723 	if (bMaintenance)
724 	{
725 		cairo_dock_load_user_gui_backend (1);  // force the advanced GUI, it can display the config before the theme is loaded.
726 
727 		GtkWidget *pWindow = cairo_dock_show_main_gui ();
728 		gtk_window_set_title (GTK_WINDOW (pWindow), _("< Maintenance mode >"));
729 		if (cExcludeModule != NULL)
730 			cairo_dock_set_status_message_printf (pWindow, "%s '%s'...", _("Something went wrong with this applet:"), cExcludeModule);
731 		gtk_window_set_modal (GTK_WINDOW (pWindow), TRUE);
732 		GMainLoop *pBlockingLoop = g_main_loop_new (NULL, FALSE);
733 		g_signal_connect (G_OBJECT (pWindow),
734 			"destroy",
735 			G_CALLBACK (on_delete_maintenance_gui),
736 			pBlockingLoop);
737 
738 		cd_warning ("showing the maintenance mode ...");
739 		g_main_loop_run (pBlockingLoop);  // pas besoin de GDK_THREADS_LEAVE/ENTER vu qu'on est pas encore dans la main loop de GTK. En fait cette boucle va jouer le role de la main loop GTK.
740 		cd_warning ("end of the maintenance mode.");
741 
742 		g_main_loop_unref (pBlockingLoop);
743 		cairo_dock_load_user_gui_backend (s_iGuiMode);  // go back to the user GUI.
744 	}
745 
746 	//\___________________ load the current theme.
747 	cd_message ("loading theme ...");
748 	const gchar *cDesktopSessionEnv = g_getenv ("DESKTOP_SESSION");
749 	if (! g_file_test (g_cConfFile, G_FILE_TEST_EXISTS))  // no theme yet, copy the default theme first.
750 	{
751 		const gchar *cThemeName;
752 		if (g_strcmp0 (cDesktopSessionEnv, "cairo-dock") == 0)
753 		{
754 			cThemeName = "Default-Panel";
755 			// We're using the CD session for the first time
756 			s_bCDSessionLaunched = TRUE;
757 			gchar *cConfFilePath = g_strdup_printf ("%s/.cairo-dock", g_cCairoDockDataDir);
758 			cairo_dock_update_conf_file (cConfFilePath,
759 				G_TYPE_BOOLEAN, "Launch", "cd session", s_bCDSessionLaunched,
760 				G_TYPE_INVALID);
761 			g_free (cConfFilePath);
762 		}
763 		else
764 			cThemeName = "Default-Single";
765 		gchar *cCommand = g_strdup_printf ("cp -r \"%s/%s\"/* \"%s\"", CAIRO_DOCK_SHARE_DATA_DIR"/themes", cThemeName, g_cCurrentThemePath);
766 		cd_message (cCommand);
767 		int r = system (cCommand);
768 		if (r < 0)
769 			cd_warning ("Not able to launch this command: %s", cCommand);
770 		g_free (cCommand);
771 	}
772 	/* The first time the Cairo-Dock session is used but not the first time the
773 	 *  dock is launched: propose to use the Default-Panel theme if a second
774 	 *  dock is not used (case: the user has already launched the dock and he
775 	 *  wants to test the Cairo-Dock session: propose a theme with two docks)
776 	 */
777 	else if (! s_bCDSessionLaunched && g_strcmp0 (cDesktopSessionEnv, "cairo-dock") == 0)
778 	{
779 		gchar *cSecondDock = g_strdup_printf ("%s/"CAIRO_DOCK_MAIN_DOCK_NAME"-2.conf", g_cCurrentThemePath);
780 		if (! g_file_test (cSecondDock, G_FILE_TEST_EXISTS))
781 		{
782 			GtkWidget *pDialog = gtk_dialog_new_with_buttons (_("You're using our Cairo-Dock session"),
783 				NULL,
784 				GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
785 				_("Yes"), GTK_RESPONSE_YES,
786 				_("No"), GTK_RESPONSE_NO,
787 				NULL);
788 			GtkWidget *pLabel = gtk_label_new (_("It can be interesting to use an adapted theme for this session.\n\nDo you want to load our \"Default-Panel\" theme?\n\nNote: your current theme will be saved and can be reimported later from the Themes manager"));
789 
790 			GtkWidget *pContentBox = gtk_dialog_get_content_area (GTK_DIALOG (pDialog));
791 			gtk_box_pack_start (GTK_BOX (pContentBox), pLabel, FALSE, FALSE, 0);
792 			gtk_widget_show_all (pDialog);
793 
794 			gint iAnswer = gtk_dialog_run (GTK_DIALOG (pDialog)); // will block the main loop
795 			gtk_widget_destroy (pDialog);
796 			if (iAnswer == GTK_RESPONSE_YES)
797 			{
798 				time_t epoch = (time_t) time (NULL);
799 				struct tm currentTime;
800 				localtime_r (&epoch, &currentTime);
801 				char cDateBuffer[22+1];
802 				strftime (cDateBuffer, 22, "Theme_%Y%m%d_%H%M%S", &currentTime);
803 
804 				cairo_dock_export_current_theme (cDateBuffer, TRUE, TRUE);
805 				cairo_dock_import_theme ("Default-Panel", TRUE, TRUE);
806 			}
807 
808 			// Force init script
809 			g_timeout_add_seconds (4, _cairo_dock_first_launch_setup, NULL);
810 		}
811 		g_free (cSecondDock);
812 
813 		// Update 'cd session' key: we already check that the user is using an adapted theme for this session
814 		s_bCDSessionLaunched = TRUE;
815 		gchar *cConfFilePath = g_strdup_printf ("%s/.cairo-dock", g_cCairoDockDataDir);
816 		cairo_dock_update_conf_file (cConfFilePath,
817 			G_TYPE_BOOLEAN, "Launch", "cd session", s_bCDSessionLaunched,
818 			G_TYPE_INVALID);
819 		g_free (cConfFilePath);
820 	}
821 	cairo_dock_load_current_theme ();
822 
823 	//\___________________ lock mode.
824 	if (g_bLocked)  // comme on ne pourra pas ouvrir le panneau de conf, ces 2 variables resteront tel quel.
825 	{
826 		myDocksParam.bLockIcons = TRUE;
827 		myDocksParam.bLockAll = TRUE;
828 	}
829 
830 	if (!bSafeMode && gldi_module_get_nb () <= 1)  // 1 en comptant l'aide
831 	{
832 		Icon *pIcon = gldi_icons_get_any_without_dialog ();
833 		gldi_dialog_show_temporary_with_icon (_("No plug-in were found.\nPlug-ins provide most of the functionalities (animations, applets, views, etc).\nSee http://glx-dock.org for more information.\nThere is almost no meaning in running the dock without them and it's probably due to a problem with the installation of these plug-ins.\nBut if you really want to use the dock without these plug-ins, you can launch the dock with the '-f' option to no longer have this message.\n"), pIcon, CAIRO_CONTAINER (g_pMainDock), 0., CAIRO_DOCK_SHARE_DATA_DIR"/"CAIRO_DOCK_ICON);
834 	}
835 
836 	//\___________________ display the changelog in case of a new version.
837 	gboolean bNewVersion = (s_cLastVersion == NULL || strcmp (s_cLastVersion, CAIRO_DOCK_VERSION) != 0);
838 	if (bNewVersion)
839 	{
840 		gchar *cConfFilePath = g_strdup_printf ("%s/.cairo-dock", g_cCairoDockDataDir);
841 		cairo_dock_update_conf_file (cConfFilePath,
842 			G_TYPE_STRING, "Launch", "last version", CAIRO_DOCK_VERSION,
843 			G_TYPE_INVALID);
844 		g_free (cConfFilePath);
845 
846 		/// If any operation must be done on the user theme (like activating a module by default, or disabling an option), it should be done here once (when CAIRO_DOCK_VERSION matches the new version).
847 	}
848 
849 	//g_print ("bFirstLaunch: %d; bNewVersion: %d\n", bFirstLaunch, bNewVersion);
850 	if (bFirstLaunch)  // first launch => set up config
851 	{
852 		g_timeout_add_seconds (4, _cairo_dock_first_launch_setup, NULL);
853 	}
854 	else if (bNewVersion)  // new version -> changelog (if it's the first launch, useless to display what's new, we already have the Welcome message).
855 	{
856 		gchar *cChangeLogFilePath = g_strdup_printf ("%s/ChangeLog.txt", CAIRO_DOCK_SHARE_DATA_DIR);
857 		GKeyFile *pKeyFile = cairo_dock_open_key_file (cChangeLogFilePath);
858 		if (pKeyFile != NULL)
859 		{
860 			gchar *cKeyName = g_strdup_printf ("%d.%d.%d", g_iMajorVersion, g_iMinorVersion, g_iMicroVersion);  // version without "alpha", "beta", "rc", etc.
861 			gchar *cChangeLogMessage = g_key_file_get_string (pKeyFile, "ChangeLog", cKeyName, NULL);
862 			g_free (cKeyName);
863 			if (cChangeLogMessage != NULL)
864 			{
865 				GString *sChangeLogMessage = g_string_new (gettext (cChangeLogMessage));
866 				g_free (cChangeLogMessage);
867 
868 				// changelog message is now split (by line): to not re-translate all the message when there is a modification
869 				int i = 0;
870 				while (TRUE)
871 				{
872 					cKeyName = g_strdup_printf ("%d.%d.%d.%d", g_iMajorVersion, g_iMinorVersion, g_iMicroVersion, i);
873 					cChangeLogMessage = g_key_file_get_string (pKeyFile, "ChangeLog", cKeyName, NULL);
874 					g_free (cKeyName);
875 
876 					if (cChangeLogMessage == NULL) // no more message
877 						break;
878 
879 					g_string_append_printf (sChangeLogMessage, "\n %s", gettext (cChangeLogMessage));
880 
881 					g_free (cChangeLogMessage);
882 					i++;
883 				}
884 
885 				Icon *pFirstIcon = cairo_dock_get_first_icon (g_pMainDock->icons);
886 
887 				CairoDialogAttr attr;
888 				memset (&attr, 0, sizeof (CairoDialogAttr));
889 				attr.cText = sChangeLogMessage->str;
890 				attr.cImageFilePath = CAIRO_DOCK_SHARE_DATA_DIR"/"CAIRO_DOCK_ICON;
891 				attr.bUseMarkup = TRUE;
892 				attr.pIcon = pFirstIcon;
893 				attr.pContainer = CAIRO_CONTAINER (g_pMainDock);
894 				gldi_dialog_new (&attr);
895 				g_string_free (sChangeLogMessage, TRUE);
896 			}
897 			g_key_file_free (pKeyFile);
898 		}
899 		// In case something has changed in Compiz/Gtk/others, we also run the script on a new version of the dock.
900 		g_timeout_add_seconds (4, _cairo_dock_first_launch_setup, NULL);
901 	}
902 	else if (cExcludeModule != NULL && ! bMaintenance && s_iNbCrashes > 1)
903 	{
904 		gchar *cMessage;
905 		if (s_iNbCrashes == 2) // <=> second crash: display a dialogue
906 			cMessage = g_strdup_printf (_("The module '%s' may have encountered a problem.\nIt has been restored successfully, but if it happens again, please report it at http://glx-dock.org"), cExcludeModule);
907 		else // since the 3th crash: the applet has been disabled
908 			cMessage = g_strdup_printf (_("The module '%s' has been deactivated because it may have caused some problems.\nYou can reactivate it, if it happens again thanks to report it at http://glx-dock.org"), cExcludeModule);
909 
910 		GldiModule *pModule = gldi_module_get (cExcludeModule);
911 		Icon *icon = gldi_icons_get_any_without_dialog ();
912 		gldi_dialog_show_temporary_with_icon (cMessage, icon, CAIRO_CONTAINER (g_pMainDock), 15000., (pModule ? pModule->pVisitCard->cIconFilePath : NULL));
913 		g_free (cMessage);
914 	}
915 
916 	if (! bTesting)
917 		g_timeout_add_seconds (5, _cairo_dock_successful_launch, GINT_TO_POINTER (bFirstLaunch));
918 
919 	// Start Mainloop
920 	gtk_main ();
921 
922 	signal (SIGSEGV, NULL);  // Segmentation violation
923 	signal (SIGFPE, NULL);  // Floating-point exception
924 	signal (SIGILL, NULL);  // Illegal instruction
925 	signal (SIGABRT, NULL);
926 	signal (SIGTERM, NULL);
927 	signal (SIGHUP, NULL);
928 
929 	gldi_free_all ();
930 
931 	#if (LIBRSVG_MAJOR_VERSION == 2 && LIBRSVG_MINOR_VERSION < 36)
932 	rsvg_term ();
933 	#endif
934 	xmlCleanupParser ();
935 	g_string_free (s_pLaunchCommand, TRUE);
936 
937 	cd_message ("Bye bye !");
938 	g_print ("\033[0m\n");
939 
940 	return 0;
941 }
942