9dadf9e9bc69f1fa2719e6007267403a34bfce07
[lxde/lxpanel.git] / src / panel.c
1 /**
2 * Copyright (c) 2006 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 <stdio.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
34 #include "plugin.h"
35 #include "panel.h"
36 #include "misc.h"
37 #include "bg.h"
38
39 #include "glib-mem.h"
40 #include "lxpanelctl.h"
41 #include "dbg.h"
42
43 static gchar *cfgfile = NULL;
44 static gchar version[] = VERSION;
45 gchar *cprofile = "default";
46
47 static int config = 0;
48 FbEv *fbev = NULL;
49
50 int log_level;
51
52 GSList* all_panels = NULL; /* a single-linked list storing all panels */
53
54 gboolean is_restarting = FALSE;
55
56 void panel_config_save(Panel* panel); /* defined in configurator.c */
57
58 /****************************************************
59 * panel's handlers for WM events *
60 ****************************************************/
61 /*
62 static void
63 panel_del_wm_strut(Panel *p)
64 {
65 XDeleteProperty(GDK_DISPLAY(), p->topxwin, a_NET_WM_STRUT);
66 XDeleteProperty(GDK_DISPLAY(), p->topxwin, a_NET_WM_STRUT_PARTIAL);
67 }
68 */
69
70
71 void panel_set_wm_strut(Panel *p)
72 {
73 gulong data[12] = { 0 };
74 int i = 4;
75
76 if (!GTK_WIDGET_MAPPED (p->topgwin))
77 return;
78 if ( ! p->setstrut )
79 {
80 XDeleteProperty(GDK_DISPLAY(), p->topxwin, a_NET_WM_STRUT_PARTIAL);
81 /* old spec, for wms that do not support STRUT_PARTIAL */
82 XDeleteProperty(GDK_DISPLAY(), p->topxwin, a_NET_WM_STRUT);
83 return;
84 }
85
86 switch (p->edge) {
87 case EDGE_LEFT:
88 i = 0;
89 data[i] = p->aw;
90 data[4 + i*2] = p->ay;
91 data[5 + i*2] = p->ay + p->ah;
92 break;
93 case EDGE_RIGHT:
94 i = 1;
95 data[i] = p->aw;
96 data[4 + i*2] = p->ay;
97 data[5 + i*2] = p->ay + p->ah;
98 break;
99 case EDGE_TOP:
100 i = 2;
101 data[i] = p->ah;
102 data[4 + i*2] = p->ax;
103 data[5 + i*2] = p->ax + p->aw;
104 break;
105 case EDGE_BOTTOM:
106 i = 3;
107 data[i] = p->ah;
108 data[4 + i*2] = p->ax;
109 data[5 + i*2] = p->ax + p->aw;
110 break;
111 default:
112 ERR("wrong edge %d. strut won't be set\n", p->edge);
113 RET();
114 }
115 DBG("type %d. width %d. from %d to %d\n", i, data[i], data[4 + i*2], data[5 + i*2]);
116
117 /* if wm supports STRUT_PARTIAL it will ignore STRUT */
118 XChangeProperty(GDK_DISPLAY(), p->topxwin, a_NET_WM_STRUT_PARTIAL,
119 XA_CARDINAL, 32, PropModeReplace, (unsigned char *) data, 12);
120 /* old spec, for wms that do not support STRUT_PARTIAL */
121 XChangeProperty(GDK_DISPLAY(), p->topxwin, a_NET_WM_STRUT,
122 XA_CARDINAL, 32, PropModeReplace, (unsigned char *) data, 4);
123
124 RET();
125 }
126
127 static void
128 print_wmdata(Panel *p)
129 {
130 int i;
131
132 RET();
133 DBG("desktop %d/%d\n", p->curdesk, p->desknum);
134 DBG("workarea\n");
135 for (i = 0; i < p->wa_len/4; i++)
136 DBG("(%d, %d) x (%d, %d)\n",
137 p->workarea[4*i + 0],
138 p->workarea[4*i + 1],
139 p->workarea[4*i + 2],
140 p->workarea[4*i + 3]);
141 RET();
142 }
143
144
145 /* defined in plugins/menu.c */
146 gboolean show_system_menu( gpointer system_menu );
147
148 /* built-in commands, defined in configurator.c */
149 void configure(Panel* p, int sel_page );
150 void restart(void);
151 void gtk_run(void);
152
153 static void process_client_msg ( Panel *p, XClientMessageEvent* ev )
154 {
155 int cmd = ev->data.b[0];
156 switch( cmd )
157 {
158 case LXPANEL_CMD_SYS_MENU:
159 if( p->system_menus )
160 {
161 /* show_system_menu( p->system_menus->data ); */
162 /* FIXME: I've no idea why this doesn't work without timeout
163 under some WMs, like icewm. */
164 g_timeout_add( 200, (GSourceFunc)show_system_menu,
165 p->system_menus->data );
166 }
167 break;
168 case LXPANEL_CMD_RUN:
169 gtk_run();
170 break;
171 case LXPANEL_CMD_CONFIG:
172 //FIXME: configure();
173 break;
174 case LXPANEL_CMD_RESTART:
175 restart();
176 break;
177 case LXPANEL_CMD_EXIT:
178 gtk_main_quit();
179 break;
180 }
181 }
182
183 static GdkFilterReturn
184 panel_event_filter(GdkXEvent *xevent, GdkEvent *event, gpointer not_used)
185 {
186 Atom at;
187 Window win;
188 XEvent *ev = (XEvent *) xevent;
189
190 ENTER;
191 DBG("win = 0x%x\n", ev->xproperty.window);
192 if (ev->type != PropertyNotify ) {
193 /* private client message from lxpanelctl */
194 if( ev->type == ClientMessage && ev->xproperty.atom == a_LXPANEL_CMD )
195 {
196 g_slist_foreach( all_panels, (GFunc)process_client_msg, (XClientMessageEvent*)ev );
197 }
198 else if( ev->type == DestroyNotify )
199 {
200 fb_ev_emit_destroy( fbev, ((XDestroyWindowEvent*)ev)->window );
201 }
202 RET(GDK_FILTER_CONTINUE);
203 }
204
205 at = ev->xproperty.atom;
206 win = ev->xproperty.window;
207 if (win == GDK_ROOT_WINDOW()) {
208 if (at == a_NET_CLIENT_LIST) {
209 fb_ev_emit(fbev, EV_CLIENT_LIST);
210 } else if (at == a_NET_CURRENT_DESKTOP) {
211 GSList* l;
212 for( l = all_panels; l; l = l->next )
213 ((Panel*)l->data)->curdesk = get_net_current_desktop();
214 fb_ev_emit(fbev, EV_CURRENT_DESKTOP);
215 } else if (at == a_NET_NUMBER_OF_DESKTOPS) {
216 GSList* l;
217 for( l = all_panels; l; l = l->next )
218 ((Panel*)l->data)->desknum = get_net_number_of_desktops();
219 fb_ev_emit(fbev, EV_NUMBER_OF_DESKTOPS);
220 } else if (at == a_NET_DESKTOP_NAMES) {
221 fb_ev_emit(fbev, EV_DESKTOP_NAMES);
222 } else if (at == a_NET_ACTIVE_WINDOW) {
223 fb_ev_emit(fbev, EV_ACTIVE_WINDOW );
224 } else if (at == a_NET_CLIENT_LIST_STACKING) {
225 fb_ev_emit(fbev, EV_CLIENT_LIST_STACKING);
226 } else if (at == a_XROOTPMAP_ID) {
227 GSList* l;
228 for( l = all_panels; l; l = l->next )
229 {
230 Panel* p = (Panel*)l->data;
231 if (p->transparent) {
232 fb_bg_notify_changed_bg(p->bg);
233 }
234 }
235 } else if (at == a_NET_WORKAREA) {
236 GSList* l;
237 for( l = all_panels; l; l = l->next )
238 {
239 Panel* p = (Panel*)l->data;
240 g_free( p->workarea );
241 p->workarea = get_xaproperty (GDK_ROOT_WINDOW(), a_NET_WORKAREA, XA_CARDINAL, &p->wa_len);
242 print_wmdata(p);
243 }
244 } else
245 return GDK_FILTER_CONTINUE;
246
247 return GDK_FILTER_REMOVE;
248 }
249 return GDK_FILTER_CONTINUE;
250 }
251
252 /****************************************************
253 * panel's handlers for GTK events *
254 ****************************************************/
255
256
257 static gint
258 panel_delete_event(GtkWidget * widget, GdkEvent * event, gpointer data)
259 {
260 ENTER;
261 RET(FALSE);
262 }
263
264 static gint
265 panel_destroy_event(GtkWidget * widget, GdkEvent * event, gpointer data)
266 {
267 //Panel *p = (Panel *) data;
268 //if (!p->self_destroy)
269 gtk_main_quit();
270 RET(FALSE);
271 }
272
273 static void
274 on_root_bg_changed(FbBg *bg, Panel* p)
275 {
276 panel_update_background( p );
277 }
278
279 /* This function should only be called after the panel has been realized */
280 void panel_update_background( Panel* p )
281 {
282 GList* l;
283 GdkPixmap* pixmap = NULL;
284
285 /* handle background image of panel */
286 gtk_widget_set_app_paintable(p->topgwin, TRUE);
287
288 if (p->background) {
289 pixmap = fb_bg_get_pix_from_file(p->topgwin, p->background_file);
290 if( p->bg )
291 {
292 g_object_unref( p->bg );
293 p->bg = NULL;
294 }
295 } else if (p->transparent) {
296 if( ! p->bg )
297 {
298 p->bg = fb_bg_get_for_display();
299 g_signal_connect(G_OBJECT(p->bg), "changed", G_CALLBACK(on_root_bg_changed), p);
300 }
301 pixmap = fb_bg_get_xroot_pix_for_win( p->bg, p->topgwin );
302
303 if (pixmap && pixmap != GDK_NO_BG) {
304 if (p->alpha)
305 fb_bg_composite( pixmap, p->topgwin->style->black_gc, p->tintcolor, p->alpha );
306 }
307 }
308 else
309 {
310 if( p->bg )
311 {
312 g_object_unref( p->bg );
313 p->bg = NULL;
314 }
315 }
316
317 if( pixmap )
318 {
319 gtk_widget_set_app_paintable( p->topgwin, TRUE );
320 gdk_window_set_back_pixmap( p->topgwin->window, pixmap, FALSE );
321 g_object_unref( pixmap );
322 }
323 else
324 {
325 // gdk_window_set_back_pixmap( p->topgwin->window, p->topgwin->style->bg_pixmap[0], FALSE );
326 gtk_widget_set_app_paintable( p->topgwin, FALSE );
327 // gdk_window_set_background( p->topgwin->window, &p->topgwin->style->bg[0] );
328 }
329
330 for( l = p->plugins; l; l = l->next )
331 {
332 Plugin* pl = (Plugin*)l->data;
333 plugin_set_background( pl, p );
334 }
335
336 gdk_window_clear( p->topgwin->window );
337 gtk_widget_queue_draw( p->topgwin );
338 }
339
340 /*
341 static void
342 panel_realize(GtkWidget *widget, Panel *p)
343 {
344
345 }
346 */
347
348 static gboolean delay_update_background( Panel* p )
349 {
350 panel_update_background( p );
351 return FALSE;
352 }
353
354 static void
355 panel_style_set(GtkWidget *widget, GtkStyle* prev, Panel *p)
356 {
357 if( GTK_WIDGET_REALIZED( widget ) )
358 g_idle_add( delay_update_background, p );
359 }
360
361 static gint
362 panel_size_req(GtkWidget *widget, GtkRequisition *req, Panel *p)
363 {
364 ENTER;
365
366 if (p->widthtype == WIDTH_REQUEST)
367 p->width = (p->orientation == ORIENT_HORIZ) ? req->width : req->height;
368 if (p->heighttype == HEIGHT_REQUEST)
369 p->height = (p->orientation == ORIENT_HORIZ) ? req->height : req->width;
370 calculate_position(p);
371 req->width = p->aw;
372 req->height = p->ah;
373
374 RET( TRUE );
375 }
376
377 static gint
378 panel_size_alloc(GtkWidget *widget, GtkAllocation *a, Panel *p)
379 {
380 ENTER;
381 if (p->widthtype == WIDTH_REQUEST)
382 p->width = (p->orientation == ORIENT_HORIZ) ? a->width : a->height;
383 if (p->heighttype == HEIGHT_REQUEST)
384 p->height = (p->orientation == ORIENT_HORIZ) ? a->height : a->width;
385 calculate_position(p);
386
387 if (a->width == p->aw && a->height == p->ah && a->x == p->ax && a->y == p ->ay) {
388 RET(TRUE);
389 }
390
391 gtk_window_move(GTK_WINDOW(p->topgwin), p->ax, p->ay);
392 panel_set_wm_strut(p);
393 RET(TRUE);
394 }
395
396 static gboolean
397 panel_configure_event (GtkWidget *widget, GdkEventConfigure *e, Panel *p)
398 {
399 ENTER;
400 if (e->width == p->cw && e->height == p->ch && e->x == p->cx && e->y == p->cy)
401 RET(TRUE);
402 p->cw = e->width;
403 p->ch = e->height;
404 p->cx = e->x;
405 p->cy = e->y;
406
407 if (p->transparent)
408 fb_bg_notify_changed_bg(p->bg);
409
410 RET(FALSE);
411 }
412
413 static gint
414 panel_popupmenu_configure(GtkWidget *widget, gpointer user_data)
415 {
416 panel_configure( (Panel*)user_data, 0 );
417 return TRUE;
418 }
419
420 static gint
421 panel_press_button_event(GtkWidget *widget, GdkEvent *event, gpointer user_data)
422 {
423 GdkEventButton *event_button;
424 GtkWidget* img;
425
426 g_return_val_if_fail (event != NULL, FALSE);
427 event_button = (GdkEventButton *)event;
428 if (event_button->button == 3) {
429 GtkWidget *menu;
430 Panel* panel = (Panel*)user_data;
431 /* create menu */
432 menu = lxpanel_get_panel_menu( panel, NULL, TRUE );
433 gtk_menu_popup(menu, NULL, NULL, NULL, NULL, event_button->button, event_button->time);
434 return TRUE;
435 }
436
437 return FALSE;
438 }
439
440 static void panel_popupmenu_config_plugin( GtkMenuItem* item, Plugin* plugin )
441 {
442 plugin->class->config( plugin, plugin->panel->topgwin );
443 }
444
445 #if 0
446 static void on_add_plugin_response( GtkDialog* dlg,
447 int response,
448 Panel* p )
449 {
450 if( response == GTK_RESPONSE_OK )
451 {
452 GtkTreeView* view;
453 GtkTreeSelection* tree_sel;
454 GtkTreeIter it;
455 GtkTreeModel* model;
456
457 view = (GtkTreeView*)g_object_get_data( G_OBJECT(dlg), "avail-plugins" );
458 tree_sel = gtk_tree_view_get_selection( view );
459 if( gtk_tree_selection_get_selected( tree_sel, &model, &it ) )
460 {
461 char* type = NULL;
462 Plugin* pl;
463 gtk_tree_model_get( model, &it, 1, &type, -1 );
464 if( pl = plugin_load( type ) )
465 {
466 GtkTreePath* tree_path;
467
468 pl->panel = p;
469 plugin_start( pl, NULL );
470 p->plugins = g_list_append(p->plugins, pl);
471 /* FIXME: will show all cause problems? */
472 gtk_widget_show_all( pl->pwid );
473
474 /* update background of the newly added plugin */
475 plugin_widget_set_background( pl->pwid, pl->panel );
476 }
477 g_free( type );
478 }
479 }
480 gtk_widget_destroy( (GtkWidget*)dlg );
481 }
482
483 void panel_add_plugin( Panel* panel, GtkWindow* parent_win )
484 {
485 GtkWidget* dlg, *scroll;
486 GList* classes;
487 GList* tmp;
488 GtkTreeViewColumn* col;
489 GtkCellRenderer* render;
490 GtkTreeView* view;
491 GtkListStore* list;
492 GtkTreeSelection* tree_sel;
493
494 classes = plugin_get_available_classes();
495
496 dlg = gtk_dialog_new_with_buttons( _("Add plugin to panel"),
497 GTK_WINDOW(parent_win), 0,
498 GTK_STOCK_CANCEL,
499 GTK_RESPONSE_CANCEL,
500 GTK_STOCK_ADD,
501 GTK_RESPONSE_OK, NULL );
502
503 /* gtk_widget_set_sensitive( parent_win, FALSE ); */
504 scroll = gtk_scrolled_window_new( NULL, NULL );
505 gtk_scrolled_window_set_shadow_type( (GtkScrolledWindow*)scroll,
506 GTK_SHADOW_IN );
507 gtk_scrolled_window_set_policy((GtkScrolledWindow*)scroll,
508 GTK_POLICY_AUTOMATIC,
509 GTK_POLICY_AUTOMATIC );
510 gtk_box_pack_start( (GtkBox*)GTK_DIALOG(dlg)->vbox, scroll,
511 TRUE, TRUE, 4 );
512 view = (GtkTreeView*)gtk_tree_view_new();
513 gtk_container_add( (GtkContainer*)scroll, view );
514 tree_sel = gtk_tree_view_get_selection( view );
515 gtk_tree_selection_set_mode( tree_sel, GTK_SELECTION_BROWSE );
516
517 render = gtk_cell_renderer_text_new();
518 col = gtk_tree_view_column_new_with_attributes(
519 _("Available plugins"),
520 render, "text", 0, NULL );
521 gtk_tree_view_append_column( view, col );
522
523 list = gtk_list_store_new( 2,
524 G_TYPE_STRING,
525 G_TYPE_STRING );
526
527 for( tmp = classes; tmp; tmp = tmp->next ) {
528 PluginClass* pc = (PluginClass*)tmp->data;
529 if( ! pc->invisible ) {
530 /* FIXME: should we display invisible plugins? */
531 GtkTreeIter it;
532 gtk_list_store_append( list, &it );
533 gtk_list_store_set( list, &it,
534 0, _(pc->name),
535 1, pc->type, -1 );
536 /* g_debug( "%s (%s)", pc->type, _(pc->name) ); */
537 }
538 }
539
540 gtk_tree_view_set_model( view, GTK_TREE_MODEL(list) );
541 g_object_unref( list );
542
543 g_signal_connect( dlg, "response",
544 on_add_plugin_response, panel );
545 g_object_set_data( dlg, "avail-plugins", view );
546 g_object_weak_ref( dlg, plugin_class_list_free, classes );
547
548 gtk_window_set_default_size( (GtkWindow*)dlg, 320, 400 );
549 gtk_widget_show_all( dlg );
550 }
551 #endif
552
553 static void panel_popupmenu_add_item( GtkMenuItem* item, Panel* panel )
554 {
555 /* panel_add_plugin( panel, panel->topgwin ); */
556 panel_configure( panel, 1 );
557 }
558
559 static void panel_popupmenu_remove_item( GtkMenuItem* item, Plugin* plugin )
560 {
561 Panel* panel = plugin->panel;
562 panel->plugins = g_list_remove( panel->plugins, plugin );
563 plugin_stop( plugin ); /* free the plugin widget & its data */
564 plugin_put( plugin ); /* free the lib if necessary */
565
566 panel_config_save( plugin->panel );
567 }
568
569 static void panel_popupmenu_create_panel( GtkMenuItem* item, Panel* panel )
570 {
571 GtkWidget* dlg = gtk_dialog_new_with_buttons(
572 _("Create New Panel"),
573 panel->topgwin,
574 GTK_DIALOG_MODAL,
575 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
576 GTK_STOCK_OK, GTK_RESPONSE_OK, NULL );
577 gtk_widget_destroy( dlg );
578 }
579
580 static void panel_popupmenu_delete_panel( GtkMenuItem* item, Panel* panel )
581 {
582 GtkWidget* dlg;
583 gboolean ok;
584 dlg = gtk_message_dialog_new_with_markup( panel->topgwin,
585 GTK_DIALOG_MODAL,
586 GTK_MESSAGE_QUESTION,
587 GTK_BUTTONS_OK_CANCEL,
588 _("Really delete this panel?\n<b>Warning: This can not be recovered.</b>") );
589 gtk_window_set_title( (GtkWindow*)dlg, _("Confirm") );
590 ok = ( gtk_dialog_run( (GtkDialog*)dlg ) == GTK_RESPONSE_OK );
591 gtk_widget_destroy( dlg );
592 if( ok )
593 {
594 gchar *fname, *dir;
595 all_panels = g_slist_remove( all_panels, panel );
596
597 /* delete the config file of this panel */
598 dir = get_config_file( cprofile, "panels", FALSE );
599 fname = g_build_filename( dir, panel->name, NULL );
600 g_free( dir );
601 g_unlink( fname );
602
603 panel_destroy( panel );
604 }
605 }
606
607 extern GtkWidget* lxpanel_get_panel_menu( Panel* panel, Plugin* plugin, gboolean use_sub_menu )
608 {
609 GtkWidget *ret,*menu, *menu_item, *img;
610 char* tmp;
611 ret = menu = gtk_menu_new();
612
613 if( plugin )
614 {
615 img = gtk_image_new_from_stock( GTK_STOCK_PREFERENCES, GTK_ICON_SIZE_MENU );
616 tmp = g_strdup_printf( _("\"%s\" Settings"), _(plugin->class->name) );
617 menu_item = gtk_image_menu_item_new_with_label( tmp );
618 g_free( tmp );
619 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
620 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
621 if( plugin->class->config )
622 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_config_plugin), plugin );
623 else
624 gtk_widget_set_sensitive( menu_item, FALSE );
625
626 menu_item = gtk_separator_menu_item_new();
627 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
628 }
629 /*
630 img = gtk_image_new_from_stock( GTK_STOCK_ADD, GTK_ICON_SIZE_MENU );
631 menu_item = gtk_image_menu_item_new_with_label(_("Add Item To Panel"));
632 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
633 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
634 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_add_item), panel );
635 */
636
637 img = gtk_image_new_from_stock( GTK_STOCK_EDIT, GTK_ICON_SIZE_MENU );
638 menu_item = gtk_image_menu_item_new_with_label(_("Add / Remove Panel Items"));
639 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
640 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
641 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_add_item), panel );
642
643 if( plugin )
644 {
645 img = gtk_image_new_from_stock( GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU );
646 tmp = g_strdup_printf( _("Remove \"%s\" From Panel"), _(plugin->class->name) );
647 menu_item = gtk_image_menu_item_new_with_label( tmp );
648 g_free( tmp );
649 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
650 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
651 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_remove_item), plugin );
652 }
653
654 menu_item = gtk_separator_menu_item_new();
655 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
656
657 img = gtk_image_new_from_stock( GTK_STOCK_PREFERENCES, GTK_ICON_SIZE_MENU );
658 menu_item = gtk_image_menu_item_new_with_label(_("Panel Settings"));
659 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
660 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
661 g_signal_connect(G_OBJECT(menu_item), "activate", G_CALLBACK(panel_popupmenu_configure), panel );
662
663 img = gtk_image_new_from_stock( GTK_STOCK_NEW, GTK_ICON_SIZE_MENU );
664 menu_item = gtk_image_menu_item_new_with_label(_("Create New Panel"));
665 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
666 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
667 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_create_panel), panel );
668
669 img = gtk_image_new_from_stock( GTK_STOCK_DELETE, GTK_ICON_SIZE_MENU );
670 menu_item = gtk_image_menu_item_new_with_label(_("Delete This Panel"));
671 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
672 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
673 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_delete_panel), panel );
674 if( ! all_panels->next ) /* if this is the only panel */
675 gtk_widget_set_sensitive( menu_item, FALSE );
676
677 gtk_widget_show_all(menu);
678
679 if( use_sub_menu )
680 {
681 ret = gtk_menu_new();
682 menu_item = gtk_image_menu_item_new_with_label(_("Panel"));
683 gtk_menu_shell_append(GTK_MENU_SHELL(ret), menu_item);
684 gtk_menu_item_set_submenu( menu_item, menu );
685
686 gtk_widget_show_all(ret);
687 }
688
689 g_signal_connect( ret, "selection-done", G_CALLBACK(gtk_widget_destroy), NULL );
690 return ret;
691 }
692
693
694
695 /****************************************************
696 * panel creation *
697 ****************************************************/
698 static void
699 make_round_corners(Panel *p)
700 {
701 /* FIXME: This should be re-written with shape extension of X11 */
702 /* gdk_window_shape_combine_mask() can be used */
703 }
704
705 void panel_set_dock_type(Panel *p)
706 {
707 if (p->setdocktype) {
708 Atom state = a_NET_WM_WINDOW_TYPE_DOCK;
709 XChangeProperty(GDK_DISPLAY(), p->topxwin,
710 a_NET_WM_WINDOW_TYPE, XA_ATOM, 32,
711 PropModeReplace, (unsigned char *) &state, 1);
712 }
713 else {
714 XDeleteProperty( GDK_DISPLAY(), p->topxwin, a_NET_WM_WINDOW_TYPE );
715 }
716 }
717
718 static void
719 panel_start_gui(Panel *p)
720 {
721 Atom state[3];
722 XWMHints wmhints;
723 guint32 val;
724
725 ENTER;
726
727 // main toplevel window
728 p->topgwin = gtk_window_new(GTK_WINDOW_TOPLEVEL);
729 gtk_container_set_border_width(GTK_CONTAINER(p->topgwin), 0);
730 gtk_window_set_resizable(GTK_WINDOW(p->topgwin), FALSE);
731 gtk_window_set_wmclass(GTK_WINDOW(p->topgwin), "panel", "lxpanel");
732 gtk_window_set_title(GTK_WINDOW(p->topgwin), "panel");
733 gtk_window_set_position(GTK_WINDOW(p->topgwin), GTK_WIN_POS_NONE);
734 gtk_window_set_decorated(GTK_WINDOW(p->topgwin), FALSE);
735
736 g_signal_connect(G_OBJECT(p->topgwin), "delete-event",
737 G_CALLBACK(panel_delete_event), p);
738 g_signal_connect(G_OBJECT(p->topgwin), "destroy-event",
739 G_CALLBACK(panel_destroy_event), p);
740 g_signal_connect (G_OBJECT (p->topgwin), "size-request",
741 (GCallback) panel_size_req, p);
742 g_signal_connect (G_OBJECT (p->topgwin), "size-allocate",
743 (GCallback) panel_size_alloc, p);
744 g_signal_connect (G_OBJECT (p->topgwin), "configure-event",
745 (GCallback) panel_configure_event, p);
746 g_signal_connect(G_OBJECT (p->topgwin), "button_press_event",
747 (GCallback) panel_press_button_event, p);
748 /*
749 g_signal_connect (G_OBJECT (p->topgwin), "realize",
750 (GCallback) panel_realize, p);
751 */
752 g_signal_connect (G_OBJECT (p->topgwin), "style-set",
753 (GCallback)panel_style_set, p);
754 gtk_widget_realize(p->topgwin);
755 //gdk_window_set_decorations(p->topgwin->window, 0);
756
757 // main layout manager as a single child of panel
758 p->box = p->my_box_new(FALSE, 0);
759 gtk_container_set_border_width(GTK_CONTAINER(p->box), 0);
760 // gtk_container_add(GTK_CONTAINER(p->bbox), p->box);
761 gtk_container_add(GTK_CONTAINER(p->topgwin), p->box);
762 gtk_widget_show(p->box);
763 if (p->round_corners)
764 make_round_corners(p);
765
766 p->topxwin = GDK_WINDOW_XWINDOW(GTK_WIDGET(p->topgwin)->window);
767 DBG("topxwin = %x\n", p->topxwin);
768
769 /* the settings that should be done before window is mapped */
770 wmhints.flags = InputHint;
771 wmhints.input = 0;
772 XSetWMHints (GDK_DISPLAY(), p->topxwin, &wmhints);
773 #define WIN_HINTS_SKIP_FOCUS (1<<0) /* "alt-tab" skips this win */
774 val = WIN_HINTS_SKIP_FOCUS;
775 XChangeProperty(GDK_DISPLAY(), p->topxwin,
776 XInternAtom(GDK_DISPLAY(), "_WIN_HINTS", False), XA_CARDINAL, 32,
777 PropModeReplace, (unsigned char *) &val, 1);
778
779 panel_set_dock_type(p);
780
781 /* window mapping point */
782 gtk_widget_show_all(p->topgwin);
783
784 /* the settings that should be done after window is mapped */
785
786 /* send it to running wm */
787 Xclimsg(p->topxwin, a_NET_WM_DESKTOP, 0xFFFFFFFF, 0, 0, 0, 0);
788 /* and assign it ourself just for case when wm is not running */
789 val = 0xFFFFFFFF;
790 XChangeProperty(GDK_DISPLAY(), p->topxwin, a_NET_WM_DESKTOP, XA_CARDINAL, 32,
791 PropModeReplace, (unsigned char *) &val, 1);
792
793 state[0] = a_NET_WM_STATE_SKIP_PAGER;
794 state[1] = a_NET_WM_STATE_SKIP_TASKBAR;
795 state[2] = a_NET_WM_STATE_STICKY;
796 XChangeProperty(GDK_DISPLAY(), p->topxwin, a_NET_WM_STATE, XA_ATOM,
797 32, PropModeReplace, (unsigned char *) state, 3);
798
799 calculate_position(p);
800 gdk_window_move_resize(p->topgwin->window, p->ax, p->ay, p->aw, p->ah);
801 panel_set_wm_strut(p);
802
803 p->tooltips = gtk_tooltips_new();
804 #if GLIB_CHECK_VERSION( 2, 10, 0 )
805 g_object_ref_sink( p->tooltips );
806 #else
807 g_object_ref( p->tooltips );
808 gtk_object_sink( p->tooltips );
809 #endif
810
811 RET();
812 }
813
814 void panel_set_orientation(Panel *p)
815 {
816 GList* l;
817 p->orientation = (p->edge == EDGE_TOP || p->edge == EDGE_BOTTOM)
818 ? ORIENT_HORIZ : ORIENT_VERT;
819 if (p->orientation == ORIENT_HORIZ) {
820 p->my_box_new = gtk_hbox_new;
821 p->my_separator_new = gtk_vseparator_new;
822 } else {
823 p->my_box_new = gtk_vbox_new;
824 p->my_separator_new = gtk_hseparator_new;
825 }
826
827 /* recreate the main layout box */
828 if( p->box ) {
829 GtkBox* newbox = GTK_BOX(recreate_box( GTK_BOX(p->box), p->orientation ));
830 if( GTK_WIDGET(newbox) != p->box ) {
831 p->box = GTK_WIDGET(newbox);
832 gtk_container_add( GTK_CONTAINER(p->topgwin), GTK_WIDGET(newbox) );
833 }
834 }
835 /* NOTE: This loop won't be executed when panel started since
836 plugins are not loaded at that time.
837 This is used when the orientation of the panel is changed
838 from the config dialog, and plugins should be re-layout.
839 */
840 for( l = p->plugins; l; l = l->next ) {
841 Plugin* pl = (Plugin*)l->data;
842 if( pl->class->orientation ) {
843 pl->class->orientation( pl );
844 }
845 }
846 }
847
848 static int
849 panel_parse_global(Panel *p, char **fp)
850 {
851 line s;
852 s.len = 256;
853
854 ENTER;
855 while (lxpanel_get_line(fp, &s) != LINE_NONE) {
856 if (s.type == LINE_VAR) {
857 if (!g_ascii_strcasecmp(s.t[0], "edge")) {
858 p->edge = str2num(edge_pair, s.t[1], EDGE_NONE);
859 } else if (!g_ascii_strcasecmp(s.t[0], "allign")) {
860 p->allign = str2num(allign_pair, s.t[1], ALLIGN_NONE);
861 } else if (!g_ascii_strcasecmp(s.t[0], "margin")) {
862 p->margin = atoi(s.t[1]);
863 } else if (!g_ascii_strcasecmp(s.t[0], "widthtype")) {
864 p->widthtype = str2num(width_pair, s.t[1], WIDTH_NONE);
865 } else if (!g_ascii_strcasecmp(s.t[0], "width")) {
866 p->width = atoi(s.t[1]);
867 } else if (!g_ascii_strcasecmp(s.t[0], "heighttype")) {
868 p->heighttype = str2num(height_pair, s.t[1], HEIGHT_NONE);
869 } else if (!g_ascii_strcasecmp(s.t[0], "height")) {
870 p->height = atoi(s.t[1]);
871 } else if (!g_ascii_strcasecmp(s.t[0], "spacing")) {
872 p->spacing = atoi(s.t[1]);
873 } else if (!g_ascii_strcasecmp(s.t[0], "SetDockType")) {
874 p->setdocktype = str2num(bool_pair, s.t[1], 0);
875 } else if (!g_ascii_strcasecmp(s.t[0], "SetPartialStrut")) {
876 p->setstrut = str2num(bool_pair, s.t[1], 0);
877 } else if (!g_ascii_strcasecmp(s.t[0], "RoundCorners")) {
878 p->round_corners = str2num(bool_pair, s.t[1], 0);
879 } else if (!g_ascii_strcasecmp(s.t[0], "Transparent")) {
880 p->transparent = str2num(bool_pair, s.t[1], 0);
881 } else if (!g_ascii_strcasecmp(s.t[0], "Alpha")) {
882 p->alpha = atoi(s.t[1]);
883 if (p->alpha > 255)
884 p->alpha = 255;
885 } else if (!g_ascii_strcasecmp(s.t[0], "TintColor")) {
886 if (!gdk_color_parse (s.t[1], &p->gtintcolor))
887 gdk_color_parse ("white", &p->gtintcolor);
888 p->tintcolor = gcolor2rgb24(&p->gtintcolor);
889 DBG("tintcolor=%x\n", p->tintcolor);
890 } else if (!g_ascii_strcasecmp(s.t[0], "useFontColor")) {
891 p->usefontcolor = str2num(bool_pair, s.t[1], 0);
892 } else if (!g_ascii_strcasecmp(s.t[0], "FontColor")) {
893 if (!gdk_color_parse (s.t[1], &p->gfontcolor))
894 gdk_color_parse ("black", &p->gfontcolor);
895 p->fontcolor = gcolor2rgb24(&p->gfontcolor);
896 DBG("fontcolor=%x\n", p->fontcolor);
897 } else if (!g_ascii_strcasecmp(s.t[0], "Background")) {
898 p->background = str2num(bool_pair, s.t[1], 0);
899 } else if( !g_ascii_strcasecmp(s.t[0], "BackgroundFile") ) {
900 p->background_file = g_strdup( s.t[1] );
901 } else {
902 ERR( "lxpanel: %s - unknown var in Global section\n", s.t[0]);
903 RET(0);
904 }
905 } else if (s.type == LINE_BLOCK_END) {
906 break;
907 } else {
908 ERR( "lxpanel: illegal in this context %s\n", s.str);
909 RET(0);
910 }
911 }
912 panel_set_orientation( p );
913
914 if (p->width < 0)
915 p->width = 100;
916 if (p->widthtype == WIDTH_PERCENT && p->width > 100)
917 p->width = 100;
918 p->heighttype = HEIGHT_PIXEL;
919 if (p->heighttype == HEIGHT_PIXEL) {
920 if (p->height < PANEL_HEIGHT_MIN)
921 p->height = PANEL_HEIGHT_MIN;
922 else if (p->height > PANEL_HEIGHT_MAX)
923 p->height = PANEL_HEIGHT_MAX;
924 }
925
926 if (p->background)
927 p->transparent = 0;
928
929 p->curdesk = get_net_current_desktop();
930 p->desknum = get_net_number_of_desktops();
931 p->workarea = get_xaproperty (GDK_ROOT_WINDOW(), a_NET_WORKAREA, XA_CARDINAL, &p->wa_len);
932 print_wmdata(p);
933
934 panel_start_gui(p);
935 RET(1);
936 }
937
938 static int
939 panel_parse_plugin(Panel *p, char **fp)
940 {
941 line s;
942 Plugin *plug = NULL;
943 gchar *type = NULL;
944 int expand , padding, border;
945 char* pconfig = NULL;
946
947 ENTER;
948 s.len = 256;
949 border = expand = padding = 0;
950 while (lxpanel_get_line(fp, &s) != LINE_BLOCK_END) {
951 if (s.type == LINE_NONE) {
952 ERR( "lxpanel: bad line %s\n", s.str);
953 goto error;
954 }
955 if (s.type == LINE_VAR) {
956 if (!g_ascii_strcasecmp(s.t[0], "type")) {
957 type = g_strdup(s.t[1]);
958 DBG("plug %s\n", type);
959 } else if (!g_ascii_strcasecmp(s.t[0], "expand"))
960 expand = str2num(bool_pair, s.t[1], 0);
961 else if (!g_ascii_strcasecmp(s.t[0], "padding"))
962 padding = atoi(s.t[1]);
963 else if (!g_ascii_strcasecmp(s.t[0], "border"))
964 border = atoi(s.t[1]);
965 else {
966 ERR( "lxpanel: unknown var %s\n", s.t[0]);
967 goto error;
968 }
969 } else if (s.type == LINE_BLOCK_START) {
970 if (!g_ascii_strcasecmp(s.t[0], "Config")) {
971 pconfig = *fp;
972 int pno = 1;
973 while (pno) {
974 get_line_as_is(fp, &s);
975 if (s.type == LINE_NONE) {
976 ERR( "lxpanel: unexpected eof\n");
977 goto error;
978 } else if (s.type == LINE_BLOCK_START) {
979 pno++;
980 } else if (s.type == LINE_BLOCK_END) {
981 pno--;
982 }
983 }
984 } else {
985 ERR( "lxpanel: unknown block %s\n", s.t[0]);
986 goto error;
987 }
988 } else {
989 ERR( "lxpanel: illegal in this context %s\n", s.str);
990 goto error;
991 }
992 }
993
994 if (!type || !(plug = plugin_load(type))) {
995 ERR( "lxpanel: can't load %s plugin\n", type);
996 goto error;
997 }
998
999 plug->panel = p;
1000 plug->expand = expand;
1001 plug->padding = padding;
1002 plug->border = border;
1003 DBG("starting\n");
1004 if (!plugin_start(plug, pconfig ? &pconfig : NULL)) {
1005 ERR( "lxpanel: can't start plugin %s\n", type);
1006 goto error;
1007 }
1008 DBG("plug %s\n", type);
1009 p->plugins = g_list_append(p->plugins, plug);
1010
1011 g_free( type );
1012 RET(1);
1013
1014 error:
1015 g_free(type);
1016 if (plug)
1017 plugin_put(plug);
1018 RET(0);
1019 }
1020
1021
1022 static int
1023 panel_start( Panel *p, char **fp )
1024 {
1025 line s;
1026
1027 /* parse global section */
1028 ENTER;
1029 s.len = 256;
1030
1031 p->allign = ALLIGN_CENTER;
1032 p->edge = EDGE_BOTTOM;
1033 p->widthtype = WIDTH_PERCENT;
1034 p->width = 100;
1035 p->heighttype = HEIGHT_PIXEL;
1036 p->height = PANEL_HEIGHT_DEFAULT;
1037 p->setdocktype = 1;
1038 p->setstrut = 1;
1039 p->round_corners = 0;
1040 p->transparent = 0;
1041 p->alpha = 127;
1042 p->tintcolor = 0xFFFFFFFF;
1043 p->usefontcolor = 0;
1044 p->fontcolor = 0x00000000;
1045 p->spacing = 0;
1046
1047 if ((lxpanel_get_line(fp, &s) != LINE_BLOCK_START) || g_ascii_strcasecmp(s.t[0], "Global")) {
1048 ERR( "lxpanel: config file must start from Global section\n");
1049 RET(0);
1050 }
1051 if (!panel_parse_global(p, fp))
1052 RET(0);
1053
1054 while (lxpanel_get_line(fp, &s) != LINE_NONE) {
1055 if ((s.type != LINE_BLOCK_START) || g_ascii_strcasecmp(s.t[0], "Plugin")) {
1056 ERR( "lxpanel: expecting Plugin section\n");
1057 RET(0);
1058 }
1059 panel_parse_plugin(p, fp);
1060 }
1061 gtk_widget_show_all(p->topgwin);
1062
1063 /* update backgrond of panel and all plugins */
1064 panel_update_background( p );
1065
1066 print_wmdata(p);
1067 RET(1);
1068 }
1069
1070 static void
1071 delete_plugin(gpointer data, gpointer udata)
1072 {
1073 ENTER;
1074 plugin_stop((Plugin *)data);
1075 plugin_put((Plugin *)data);
1076 RET();
1077 }
1078
1079 void panel_destroy(Panel *p)
1080 {
1081 ENTER;
1082
1083 g_list_foreach(p->plugins, delete_plugin, NULL);
1084 g_list_free(p->plugins);
1085 p->plugins = NULL;
1086
1087 if( p->system_menus ){
1088 do{
1089 } while ( g_source_remove_by_user_data( p->system_menus ) );
1090 }
1091
1092 if( p->tooltips )
1093 g_object_unref( p->tooltips );
1094
1095 if( p->topgwin )
1096 gtk_widget_destroy(p->topgwin);
1097 g_free(p->workarea);
1098 g_free( p->background_file );
1099 g_slist_free( p->system_menus );
1100 gdk_flush();
1101 XFlush(GDK_DISPLAY());
1102 XSync(GDK_DISPLAY(), True);
1103
1104 g_free( p->name );
1105 g_slice_free( Panel, p );
1106 RET();
1107 }
1108
1109 Panel* panel_new( const char* config_file, const char* config_name )
1110 {
1111 char *fp, *pfp; /* point to current position of profile data in memory */
1112 Panel* panel = NULL;
1113 char* ret;
1114
1115 g_file_get_contents( config_file, &fp, NULL, NULL );
1116 if( fp )
1117 {
1118 panel = g_slice_new0( Panel );
1119 panel->name = g_strdup( config_name );
1120 pfp = fp;
1121
1122 if (! panel_start( panel, &pfp )) {
1123 ERR( "lxpanel: can't start panel\n");
1124 panel_destroy( panel );
1125 panel = NULL;
1126 }
1127
1128 g_free( fp );
1129 }
1130 return panel;
1131 }
1132
1133 static void
1134 usage()
1135 {
1136 g_print(_("lxpanel %s - lightweight GTK2+ panel for UNIX desktops\n"), version);
1137 g_print(_("Command line options:\n"));
1138 g_print(_(" --help -- print this help and exit\n"));
1139 g_print(_(" --version -- print version and exit\n"));
1140 g_print(_(" --log <number> -- set log level 0-5. 0 - none 5 - chatty\n"));
1141 g_print(_(" --configure -- launch configuration utility\n"));
1142 g_print(_(" --profile name -- use specified profile\n"));
1143 g_print("\n");
1144 g_print(_(" -h -- same as --help\n"));
1145 g_print(_(" -p -- same as --profile\n"));
1146 g_print(_(" -v -- same as --version\n"));
1147 g_print(_(" -C -- same as --configure\n"));
1148 g_print(_("\nVisit http://lxde.sourceforge.net/ for detail.\n\n"));
1149 }
1150
1151 static void
1152 handle_error(Display * d, XErrorEvent * ev)
1153 {
1154 char buf[256];
1155
1156 ENTER;
1157 if (log_level >= LOG_WARN) {
1158 XGetErrorText(GDK_DISPLAY(), ev->error_code, buf, 256);
1159 LOG(LOG_WARN, "lxpanel : X error: %s\n", buf);
1160 }
1161 RET();
1162 }
1163
1164 /* Lightweight lock related functions - X clipboard hacks */
1165
1166 #define CLIPBOARD_NAME "LXPANEL_SELECTION"
1167
1168 /*
1169 * clipboard_get_func - dummy get_func for gtk_clipboard_set_with_data ()
1170 */
1171 static void
1172 clipboard_get_func(
1173 GtkClipboard *clipboard G_GNUC_UNUSED,
1174 GtkSelectionData *selection_data G_GNUC_UNUSED,
1175 guint info G_GNUC_UNUSED,
1176 gpointer user_data_or_owner G_GNUC_UNUSED)
1177 {
1178 }
1179
1180 /*
1181 * clipboard_clear_func - dummy clear_func for gtk_clipboard_set_with_data ()
1182 */
1183 static void clipboard_clear_func(
1184 GtkClipboard *clipboard G_GNUC_UNUSED,
1185 gpointer user_data_or_owner G_GNUC_UNUSED)
1186 {
1187 }
1188
1189 /*
1190 * Lightweight version for checking single instance.
1191 * Try and get the CLIPBOARD_NAME clipboard instead of using file manipulation.
1192 *
1193 * Returns TRUE if successfully retrieved and FALSE otherwise.
1194 */
1195 static gboolean check_main_lock()
1196 {
1197 static const GtkTargetEntry targets[] = { { CLIPBOARD_NAME, 0, 0 } };
1198 gboolean retval = FALSE;
1199 GtkClipboard *clipboard;
1200 Atom atom;
1201
1202 atom = gdk_x11_get_xatom_by_name(CLIPBOARD_NAME);
1203
1204 XGrabServer(GDK_DISPLAY());
1205
1206 if (XGetSelectionOwner(GDK_DISPLAY(), atom) != None)
1207 goto out;
1208
1209 clipboard = gtk_clipboard_get(gdk_atom_intern(CLIPBOARD_NAME, FALSE));
1210
1211 if (gtk_clipboard_set_with_data(clipboard, targets,
1212 G_N_ELEMENTS (targets),
1213 clipboard_get_func,
1214 clipboard_clear_func, NULL))
1215 retval = TRUE;
1216
1217 out:
1218 XUngrabServer (GDK_DISPLAY ());
1219 gdk_flush ();
1220
1221 return retval;
1222 }
1223 #undef CLIPBOARD_NAME
1224
1225 static gboolean start_all_panels( )
1226 {
1227 gboolean is_global;
1228 for( is_global = 0; ! all_panels && is_global < 2; ++is_global )
1229 {
1230 char* panel_dir = get_config_file( cprofile, "panels", is_global );
1231 GDir* dir = g_dir_open( panel_dir, 0, NULL );
1232 char* name;
1233
1234 if( ! dir )
1235 {
1236 g_free( panel_dir );
1237 continue;
1238 }
1239
1240 while( name = g_dir_read_name( dir ) )
1241 {
1242 char* panel_config = g_build_filename( panel_dir, name, NULL );
1243 Panel* panel = panel_new( panel_config, name );
1244 if( panel )
1245 all_panels = g_slist_prepend( all_panels, panel );
1246 g_free( panel_config );
1247 }
1248 g_dir_close( dir );
1249 g_free( panel_dir );
1250 }
1251 return all_panels != NULL;
1252 }
1253
1254 void load_global_config();
1255 void free_global_config();
1256
1257 int main(int argc, char *argv[], char *env[])
1258 {
1259 int i;
1260
1261 setlocale(LC_CTYPE, "");
1262
1263 gtk_init(&argc, &argv);
1264
1265 #ifdef ENABLE_NLS
1266 bindtextdomain ( GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR );
1267 bind_textdomain_codeset ( GETTEXT_PACKAGE, "UTF-8" );
1268 textdomain ( GETTEXT_PACKAGE );
1269 #endif
1270
1271 XSetLocaleModifiers("");
1272 XSetErrorHandler((XErrorHandler) handle_error);
1273
1274 resolve_atoms();
1275
1276 for (i = 1; i < argc; i++) {
1277 if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
1278 usage();
1279 exit(0);
1280 } else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) {
1281 printf("lxpanel %s\n", version);
1282 exit(0);
1283 } else if (!strcmp(argv[i], "--log")) {
1284 i++;
1285 if (i == argc) {
1286 ERR( "lxpanel: missing log level\n");
1287 usage();
1288 exit(1);
1289 } else {
1290 log_level = atoi(argv[i]);
1291 }
1292 } else if (!strcmp(argv[i], "--configure") || !strcmp(argv[i], "-C")) {
1293 config = 1;
1294 } else if (!strcmp(argv[i], "--profile") || !strcmp(argv[i], "-p")) {
1295 i++;
1296 if (i == argc) {
1297 ERR( "lxpanel: missing profile name\n");
1298 usage();
1299 exit(1);
1300 } else {
1301 cprofile = g_strdup(argv[i]);
1302 }
1303 } else {
1304 printf("lxpanel: unknown option - %s\n", argv[i]);
1305 usage();
1306 exit(1);
1307 }
1308 }
1309
1310 /* Check for duplicated lxpanel instances */
1311 if (!check_main_lock() && !config) {
1312 printf("There is alreay an instance of LXPanel. Now to exit\n");
1313 exit(1);
1314 }
1315
1316 /* Add our own icons to the search path of icon theme */
1317 gtk_icon_theme_append_search_path( gtk_icon_theme_get_default(),
1318 PACKAGE_DATA_DIR "/lxpanel/images" );
1319
1320 fbev = fb_ev_new();
1321
1322 restart:
1323 is_restarting = FALSE;
1324
1325 load_global_config();
1326
1327 XSelectInput (GDK_DISPLAY(), GDK_ROOT_WINDOW(), SubstructureNotifyMask|PropertyChangeMask);
1328 gdk_window_add_filter(gdk_get_default_root_window (), (GdkFilterFunc)panel_event_filter, NULL);
1329
1330 if( G_UNLIKELY( ! start_all_panels() ) )
1331 g_warning( "Config files are not found.\n" );
1332 /*
1333 * FIXME: configure??
1334 if (config)
1335 configure();
1336 */
1337 gtk_main();
1338
1339 XSelectInput (GDK_DISPLAY(), GDK_ROOT_WINDOW(), NoEventMask);
1340 gdk_window_remove_filter(gdk_get_default_root_window (), (GdkFilterFunc)panel_event_filter, NULL);
1341
1342 /* destroy all panels */
1343 g_slist_foreach( all_panels, (GFunc) panel_destroy, NULL );
1344 g_free( cfgfile );
1345
1346 free_global_config();
1347
1348 if( is_restarting )
1349 goto restart;
1350
1351 g_object_unref(fbev);
1352
1353 return 0;
1354 }