Adding upstream version 0.8.0.
[debian/lxpanel.git] / src / main.c
1 /**
2 * Copyright (c) 2006-2014 LxDE Developers, see the file AUTHORS for details.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
22
23 #include <glib/gi18n.h>
24 #include <stdlib.h>
25 #include <glib/gstdio.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <unistd.h>
29 #include <errno.h>
30 #include <locale.h>
31 #include <string.h>
32 #include <gdk/gdkx.h>
33 #include <libfm/fm-gtk.h>
34
35 #define __LXPANEL_INTERNALS__
36
37 #include "private.h"
38 #include "misc.h"
39
40 #include "lxpanelctl.h"
41 #include "dbg.h"
42
43 static gchar *cfgfile = NULL;
44 static gchar version[] = VERSION;
45 static int config = 0;
46
47 static gboolean is_restarting = FALSE;
48
49 Command commands[] = {
50 //{ "configure", N_("Preferences"), configure },
51 { "run", N_("Run"), gtk_run },
52 { "restart", N_("Restart"), restart },
53 { "logout", N_("Logout"), logout },
54 { NULL, NULL },
55 };
56
57 void restart(void)
58 {
59 ENTER;
60 is_restarting = TRUE;
61
62 gtk_main_quit();
63 RET();
64 }
65
66 static void process_client_msg ( XClientMessageEvent* ev )
67 {
68 int cmd = ev->data.b[0];
69 switch( cmd )
70 {
71 #ifndef DISABLE_MENU
72 case LXPANEL_CMD_SYS_MENU:
73 {
74 GSList* l;
75 for( l = all_panels; l; l = l->next )
76 {
77 LXPanel* p = (LXPanel*)l->data;
78 GList *plugins, *pl;
79
80 if (p->priv->box == NULL)
81 continue;
82 plugins = gtk_container_get_children(GTK_CONTAINER(p->priv->box));
83 for (pl = plugins; pl; pl = pl->next)
84 {
85 const LXPanelPluginInit *init = PLUGIN_CLASS(pl->data);
86 if (init->show_system_menu)
87 /* queue to show system menu */
88 init->show_system_menu(pl->data);
89 }
90 g_list_free(plugins);
91 }
92 break;
93 }
94 #endif
95 case LXPANEL_CMD_RUN:
96 gtk_run();
97 break;
98 case LXPANEL_CMD_CONFIG:
99 {
100 LXPanel * p = ((all_panels != NULL) ? all_panels->data : NULL);
101 if (p != NULL)
102 panel_configure(p, 0);
103 }
104 break;
105 case LXPANEL_CMD_RESTART:
106 restart();
107 break;
108 case LXPANEL_CMD_EXIT:
109 gtk_main_quit();
110 break;
111 }
112 }
113
114 static GdkFilterReturn
115 panel_event_filter(GdkXEvent *xevent, GdkEvent *event, gpointer not_used)
116 {
117 Atom at;
118 Window win;
119 XEvent *ev = (XEvent *) xevent;
120
121 ENTER;
122 DBG("win = 0x%x\n", ev->xproperty.window);
123 if (ev->type != PropertyNotify )
124 {
125 /* private client message from lxpanelctl */
126 if( ev->type == ClientMessage && ev->xproperty.atom == a_LXPANEL_CMD )
127 {
128 process_client_msg( (XClientMessageEvent*)ev );
129 }
130 else if( ev->type == DestroyNotify )
131 {
132 fb_ev_emit_destroy( fbev, ((XDestroyWindowEvent*)ev)->window );
133 }
134 RET(GDK_FILTER_CONTINUE);
135 }
136
137 at = ev->xproperty.atom;
138 win = ev->xproperty.window;
139 if (win == GDK_ROOT_WINDOW())
140 {
141 if (at == a_NET_CLIENT_LIST)
142 {
143 fb_ev_emit(fbev, EV_CLIENT_LIST);
144 }
145 else if (at == a_NET_CURRENT_DESKTOP)
146 {
147 GSList* l;
148 for( l = all_panels; l; l = l->next )
149 ((LXPanel*)l->data)->priv->curdesk = get_net_current_desktop();
150 fb_ev_emit(fbev, EV_CURRENT_DESKTOP);
151 }
152 else if (at == a_NET_NUMBER_OF_DESKTOPS)
153 {
154 GSList* l;
155 for( l = all_panels; l; l = l->next )
156 ((LXPanel*)l->data)->priv->desknum = get_net_number_of_desktops();
157 fb_ev_emit(fbev, EV_NUMBER_OF_DESKTOPS);
158 }
159 else if (at == a_NET_DESKTOP_NAMES)
160 {
161 fb_ev_emit(fbev, EV_DESKTOP_NAMES);
162 }
163 else if (at == a_NET_ACTIVE_WINDOW)
164 {
165 fb_ev_emit(fbev, EV_ACTIVE_WINDOW );
166 }
167 else if (at == a_NET_CLIENT_LIST_STACKING)
168 {
169 fb_ev_emit(fbev, EV_CLIENT_LIST_STACKING);
170 }
171 else if (at == a_XROOTPMAP_ID)
172 {
173 GSList* l;
174 for( l = all_panels; l; l = l->next )
175 _panel_queue_update_background((LXPanel*)l->data);
176 }
177 else
178 return GDK_FILTER_CONTINUE;
179
180 return GDK_FILTER_REMOVE;
181 }
182 return GDK_FILTER_CONTINUE;
183 }
184
185 /* The same for new plugins type - they will be not unloaded by FmModule */
186 #define REGISTER_STATIC_MODULE(pc) do { \
187 extern LXPanelPluginInit lxpanel_static_plugin_##pc; \
188 lxpanel_register_plugin_type(#pc, &lxpanel_static_plugin_##pc); } while (0)
189
190 /* Initialize the static plugins. */
191 static void init_static_plugins(void)
192 {
193 #ifdef STATIC_SEPARATOR
194 REGISTER_STATIC_MODULE(separator);
195 #endif
196
197 #ifdef STATIC_LAUNCHTASKBAR
198 REGISTER_STATIC_MODULE(launchtaskbar);
199 #endif
200
201 #ifdef STATIC_DCLOCK
202 REGISTER_STATIC_MODULE(dclock);
203 #endif
204
205 #ifdef STATIC_WINCMD
206 REGISTER_STATIC_MODULE(wincmd);
207 #endif
208
209 #ifdef STATIC_DIRMENU
210 REGISTER_STATIC_MODULE(dirmenu);
211 #endif
212
213 #ifdef STATIC_PAGER
214 REGISTER_STATIC_MODULE(pager);
215 #endif
216
217 #ifdef STATIC_TRAY
218 REGISTER_STATIC_MODULE(tray);
219 #endif
220
221 #ifndef DISABLE_MENU
222 #ifdef STATIC_MENU
223 REGISTER_STATIC_MODULE(menu);
224 #endif
225 #endif
226
227 #ifdef STATIC_SPACE
228 REGISTER_STATIC_MODULE(space);
229 #endif
230 }
231
232 static void
233 usage()
234 {
235 g_print(_("lxpanel %s - lightweight GTK2+ panel for UNIX desktops\n"), version);
236 g_print(_("Command line options:\n"));
237 g_print(_(" --help -- print this help and exit\n"));
238 g_print(_(" --version -- print version and exit\n"));
239 // g_print(_(" --log <number> -- set log level 0-5. 0 - none 5 - chatty\n"));
240 // g_print(_(" --configure -- launch configuration utility\n"));
241 g_print(_(" --profile name -- use specified profile\n"));
242 g_print("\n");
243 g_print(_(" -h -- same as --help\n"));
244 g_print(_(" -p -- same as --profile\n"));
245 g_print(_(" -v -- same as --version\n"));
246 // g_print(_(" -C -- same as --configure\n"));
247 g_print(_("\nVisit http://lxde.org/ for detail.\n\n"));
248 }
249
250 /* Lightweight lock related functions - X clipboard hacks */
251
252 #define CLIPBOARD_NAME "LXPANEL_SELECTION"
253
254 /*
255 * clipboard_get_func - dummy get_func for gtk_clipboard_set_with_data ()
256 */
257 static void
258 clipboard_get_func(
259 GtkClipboard *clipboard G_GNUC_UNUSED,
260 GtkSelectionData *selection_data G_GNUC_UNUSED,
261 guint info G_GNUC_UNUSED,
262 gpointer user_data_or_owner G_GNUC_UNUSED)
263 {
264 }
265
266 /*
267 * clipboard_clear_func - dummy clear_func for gtk_clipboard_set_with_data ()
268 */
269 static void clipboard_clear_func(
270 GtkClipboard *clipboard G_GNUC_UNUSED,
271 gpointer user_data_or_owner G_GNUC_UNUSED)
272 {
273 }
274
275 /*
276 * Lightweight version for checking single instance.
277 * Try and get the CLIPBOARD_NAME clipboard instead of using file manipulation.
278 *
279 * Returns TRUE if successfully retrieved and FALSE otherwise.
280 */
281 static gboolean check_main_lock()
282 {
283 static const GtkTargetEntry targets[] = { { CLIPBOARD_NAME, 0, 0 } };
284 gboolean retval = FALSE;
285 GtkClipboard *clipboard;
286 Atom atom;
287 Display *xdisplay = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
288
289 atom = gdk_x11_get_xatom_by_name(CLIPBOARD_NAME);
290
291 XGrabServer(xdisplay);
292
293 if (XGetSelectionOwner(xdisplay, atom) != None)
294 goto out;
295
296 clipboard = gtk_clipboard_get(gdk_atom_intern(CLIPBOARD_NAME, FALSE));
297
298 if (gtk_clipboard_set_with_data(clipboard, targets,
299 G_N_ELEMENTS (targets),
300 clipboard_get_func,
301 clipboard_clear_func, NULL))
302 retval = TRUE;
303
304 out:
305 XUngrabServer (xdisplay);
306 gdk_flush ();
307
308 return retval;
309 }
310 #undef CLIPBOARD_NAME
311
312 static void _start_panels_from_dir(const char *panel_dir)
313 {
314 GDir* dir = g_dir_open( panel_dir, 0, NULL );
315 const gchar* name;
316
317 if( ! dir )
318 {
319 return;
320 }
321
322 while((name = g_dir_read_name(dir)) != NULL)
323 {
324 char* panel_config = g_build_filename( panel_dir, name, NULL );
325 if (strchr(panel_config, '~') == NULL) /* Skip editor backup files in case user has hand edited in this directory */
326 {
327 LXPanel* panel = panel_new( panel_config, name );
328 if( panel )
329 all_panels = g_slist_prepend( all_panels, panel );
330 }
331 g_free( panel_config );
332 }
333 g_dir_close( dir );
334 }
335
336 static gboolean start_all_panels( )
337 {
338 char *panel_dir;
339 const gchar * const * dir;
340
341 /* try user panels */
342 panel_dir = _user_config_file_name("panels", NULL);
343 _start_panels_from_dir(panel_dir);
344 g_free(panel_dir);
345 if (all_panels != NULL)
346 return TRUE;
347 /* else try XDG fallbacks */
348 dir = g_get_system_config_dirs();
349 if (dir) while (dir[0])
350 {
351 panel_dir = _system_config_file_name(dir[0], "panels");
352 _start_panels_from_dir(panel_dir);
353 g_free(panel_dir);
354 if (all_panels != NULL)
355 return TRUE;
356 dir++;
357 }
358 /* last try at old fallback for compatibility reasons */
359 panel_dir = _old_system_config_file_name("panels");
360 _start_panels_from_dir(panel_dir);
361 g_free(panel_dir);
362 return all_panels != NULL;
363 }
364
365 void load_global_config();
366 void free_global_config();
367
368 static void _ensure_user_config_dirs(void)
369 {
370 char *dir = g_build_filename(g_get_user_config_dir(), "lxpanel", cprofile,
371 "panels", NULL);
372
373 /* make sure the private profile and panels dir exists */
374 g_mkdir_with_parents(dir, 0700);
375 g_free(dir);
376 }
377
378 int main(int argc, char *argv[], char *env[])
379 {
380 int i;
381 const char* desktop_name;
382 char *file;
383
384 setlocale(LC_CTYPE, "");
385
386 #if !GLIB_CHECK_VERSION(2, 32, 0)
387 g_thread_init(NULL);
388 #endif
389 /* gdk_threads_init();
390 gdk_threads_enter(); */
391
392 gtk_init(&argc, &argv);
393
394 #ifdef ENABLE_NLS
395 bindtextdomain ( GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR );
396 bind_textdomain_codeset ( GETTEXT_PACKAGE, "UTF-8" );
397 textdomain ( GETTEXT_PACKAGE );
398 #endif
399
400 XSetLocaleModifiers("");
401 XSetErrorHandler((XErrorHandler) panel_handle_x_error);
402
403 resolve_atoms();
404
405 desktop_name = g_getenv("XDG_CURRENT_DESKTOP");
406 is_in_lxde = desktop_name && (0 == strcmp(desktop_name, "LXDE"));
407
408 for (i = 1; i < argc; i++) {
409 if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
410 usage();
411 exit(0);
412 } else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) {
413 printf("lxpanel %s\n", version);
414 exit(0);
415 } else if (!strcmp(argv[i], "--log")) {
416 i++;
417 if (i == argc) {
418 g_critical( "lxpanel: missing log level");
419 usage();
420 exit(1);
421 } else {
422 /* deprecated */
423 }
424 } else if (!strcmp(argv[i], "--configure") || !strcmp(argv[i], "-C")) {
425 config = 1;
426 } else if (!strcmp(argv[i], "--profile") || !strcmp(argv[i], "-p")) {
427 i++;
428 if (i == argc) {
429 g_critical( "lxpanel: missing profile name");
430 usage();
431 exit(1);
432 } else {
433 cprofile = g_strdup(argv[i]);
434 }
435 } else {
436 printf("lxpanel: unknown option - %s\n", argv[i]);
437 usage();
438 exit(1);
439 }
440 }
441
442 /* Add a gtkrc file to be parsed too. */
443 file = _user_config_file_name("gtkrc", NULL);
444 gtk_rc_parse(file);
445 g_free(file);
446
447 /* Check for duplicated lxpanel instances */
448 if (!check_main_lock() && !config) {
449 printf("There is already an instance of LXPanel. Now to exit\n");
450 exit(1);
451 }
452
453 _ensure_user_config_dirs();
454
455 /* Add our own icons to the search path of icon theme */
456 gtk_icon_theme_append_search_path( gtk_icon_theme_get_default(), PACKAGE_DATA_DIR "/images" );
457
458 fbev = fb_ev_new();
459
460 is_restarting = FALSE;
461
462 /* init LibFM */
463 fm_gtk_init(NULL);
464
465 /* prepare modules data */
466 lxpanel_prepare_modules();
467 init_static_plugins();
468
469 load_global_config();
470
471 /* NOTE: StructureNotifyMask is required by XRandR
472 * See init_randr_support() in gdkscreen-x11.c of gtk+ for detail.
473 */
474 gdk_window_set_events(gdk_get_default_root_window(), GDK_STRUCTURE_MASK |
475 GDK_SUBSTRUCTURE_MASK | GDK_PROPERTY_CHANGE_MASK);
476 gdk_window_add_filter(gdk_get_default_root_window (), (GdkFilterFunc)panel_event_filter, NULL);
477
478 if( G_UNLIKELY( ! start_all_panels() ) )
479 g_warning( "Config files are not found.\n" );
480 /*
481 * FIXME: configure??
482 if (config)
483 configure();
484 */
485 gtk_main();
486
487 XSelectInput (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), GDK_ROOT_WINDOW(), NoEventMask);
488 gdk_window_remove_filter(gdk_get_default_root_window (), (GdkFilterFunc)panel_event_filter, NULL);
489
490 /* destroy all panels */
491 g_slist_foreach( all_panels, (GFunc) gtk_widget_destroy, NULL );
492 g_slist_free( all_panels );
493 all_panels = NULL;
494 g_free( cfgfile );
495
496 free_global_config();
497
498 lxpanel_unload_modules();
499 fm_gtk_finalize();
500
501 /* gdk_threads_leave(); */
502
503 g_object_unref(fbev);
504
505 if (!is_restarting)
506 return 0;
507 if (strchr(argv[0], G_DIR_SEPARATOR))
508 execve(argv[0], argv, env);
509 else
510 execve(g_find_program_in_path(argv[0]), argv, env);
511 return 1;
512 }