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