Fix memory leaks caused by missing g_object_unref for GdkPixbufs in launchbar.c.
[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 24#include <stdlib.h>
16fbda14 25#include <glib/gstdio.h>
a52c2257
HJYP
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
77886b88 39#include "lxpanelctl.h"
cf701cb7 40#include "dbg.h"
77886b88 41
a52c2257
HJYP
42static gchar *cfgfile = NULL;
43static gchar version[] = VERSION;
44gchar *cprofile = "default";
45
e2957bd2
HJYP
46static GtkWindowGroup* win_grp; /* window group used to limit the scope of model dialog. */
47
e68b47dc 48static int config = 0;
22242ed4 49FbEv *fbev = NULL;
a52c2257 50
cf701cb7 51GSList* all_panels = NULL; /* a single-linked list storing all panels */
a52c2257 52
f7cb330e
HJYP
53gboolean is_restarting = FALSE;
54
3e7b8eb7 55static int panel_start( Panel *p, char **fp );
9dd114c4 56static void panel_start_gui(Panel *p);
4b93d81e
HJYP
57void panel_config_save(Panel* panel); /* defined in configurator.c */
58
95095259
HJYP
59gboolean is_in_lxde = FALSE;
60
9dd114c4 61/* Allocate and initialize new Panel structure. */
62static Panel* panel_allocate(void)
63{
2918994e 64 Panel* p = g_new0(Panel, 1);
9dd114c4 65 p->allign = ALLIGN_CENTER;
66 p->edge = EDGE_NONE;
67 p->widthtype = WIDTH_PERCENT;
68 p->width = 100;
69 p->heighttype = HEIGHT_PIXEL;
70 p->height = PANEL_HEIGHT_DEFAULT;
71 p->setdocktype = 1;
72 p->setstrut = 1;
73 p->round_corners = 0;
74 p->autohide = 0;
75 p->visible = TRUE;
76 p->height_when_hidden = 2;
77 p->transparent = 0;
78 p->alpha = 127;
79 p->tintcolor = 0xFFFFFFFF;
80 p->usefontcolor = 0;
81 p->fontcolor = 0x00000000;
82 p->spacing = 0;
8f9e6256 83 p->icon_size = PANEL_ICON_SIZE;
9dd114c4 84 return p;
85}
86
87/* Normalize panel configuration after load from file or reconfiguration. */
88static void panel_normalize_configuration(Panel* p)
89{
2918994e 90 panel_set_panel_configuration_changed( p );
9dd114c4 91 if (p->width < 0)
92 p->width = 100;
93 if (p->widthtype == WIDTH_PERCENT && p->width > 100)
94 p->width = 100;
95 p->heighttype = HEIGHT_PIXEL;
96 if (p->heighttype == HEIGHT_PIXEL) {
97 if (p->height < PANEL_HEIGHT_MIN)
98 p->height = PANEL_HEIGHT_MIN;
99 else if (p->height > PANEL_HEIGHT_MAX)
100 p->height = PANEL_HEIGHT_MAX;
101 }
102 if (p->background)
103 p->transparent = 0;
104}
105
a52c2257
HJYP
106/****************************************************
107 * panel's handlers for WM events *
108 ****************************************************/
a52c2257 109
22242ed4 110void panel_set_wm_strut(Panel *p)
a52c2257 111{
d1d43629 112 int index;
113 gulong strut_size;
114 gulong strut_lower;
115 gulong strut_upper;
a52c2257 116
d1d43629 117 /* Dispatch on edge to set up strut parameters. */
118 switch (p->edge)
bee4c26e 119 {
d1d43629 120 case EDGE_LEFT:
121 index = 0;
122 strut_size = p->aw;
123 strut_lower = p->ay;
124 strut_upper = p->ay + p->ah;
125 break;
126 case EDGE_RIGHT:
127 index = 1;
128 strut_size = p->aw;
129 strut_lower = p->ay;
130 strut_upper = p->ay + p->ah;
131 break;
132 case EDGE_TOP:
133 index = 2;
134 strut_size = p->ah;
135 strut_lower = p->ax;
136 strut_upper = p->ax + p->aw;
137 break;
138 case EDGE_BOTTOM:
139 index = 3;
140 strut_size = p->ah;
141 strut_lower = p->ax;
142 strut_upper = p->ax + p->aw;
143 break;
144 default:
145 return;
bee4c26e
HJYP
146 }
147
176fb687 148 /* Handle autohide case. EWMH recommends having the strut be the minimized size. */
149 if ( ! p->visible)
150 strut_size = p->height_when_hidden;
151
d1d43629 152 /* Set up strut value in property format. */
153 gulong desired_strut[12];
154 memset(desired_strut, 0, sizeof(desired_strut));
155 if (p->setstrut)
156 {
157 desired_strut[index] = strut_size;
158 desired_strut[4 + index * 2] = strut_lower;
159 desired_strut[5 + index * 2] = strut_upper;
160 }
161 else
162 {
163 strut_size = 0;
164 strut_lower = 0;
165 strut_upper = 0;
bee4c26e 166 }
bee4c26e 167
d1d43629 168 /* If strut value changed, set the property value on the panel window.
169 * This avoids property change traffic when the panel layout is recalculated but strut geometry hasn't changed. */
170 if ((GTK_WIDGET_MAPPED(p->topgwin))
547ece89 171 && ((p->strut_size != strut_size) || (p->strut_lower != strut_lower) || (p->strut_upper != strut_upper) || (p->strut_edge != p->edge)))
d1d43629 172 {
173 p->strut_size = strut_size;
174 p->strut_lower = strut_lower;
175 p->strut_upper = strut_upper;
547ece89 176 p->strut_edge = p->edge;
a52c2257 177
d1d43629 178 /* If window manager supports STRUT_PARTIAL, it will ignore STRUT.
179 * Set STRUT also for window managers that do not support STRUT_PARTIAL. */
180 if (strut_size != 0)
181 {
182 XChangeProperty(GDK_DISPLAY(), p->topxwin, a_NET_WM_STRUT_PARTIAL,
183 XA_CARDINAL, 32, PropModeReplace, (unsigned char *) desired_strut, 12);
184 XChangeProperty(GDK_DISPLAY(), p->topxwin, a_NET_WM_STRUT,
185 XA_CARDINAL, 32, PropModeReplace, (unsigned char *) desired_strut, 4);
186 }
187 else
188 {
189 XDeleteProperty(GDK_DISPLAY(), p->topxwin, a_NET_WM_STRUT);
190 XDeleteProperty(GDK_DISPLAY(), p->topxwin, a_NET_WM_STRUT_PARTIAL);
191 }
192 }
a52c2257
HJYP
193}
194
e996608e 195/* defined in plugins/menu.c */
8c44345a 196gboolean show_system_menu( gpointer system_menu );
e996608e 197
3e7b8eb7
HJYP
198/* defined in configurator.c */
199void panel_configure(Panel* p, int sel_page );
9dd114c4 200gboolean panel_edge_available(Panel* p, int edge);
3e7b8eb7 201
e996608e 202/* built-in commands, defined in configurator.c */
77886b88
HJYP
203void restart(void);
204void gtk_run(void);
e3b89f43 205void panel_destroy(Panel *p);
77886b88 206
d18c9409 207static void process_client_msg ( XClientMessageEvent* ev )
77886b88 208{
8c44345a 209 int cmd = ev->data.b[0];
77886b88
HJYP
210 switch( cmd )
211 {
ace2a572 212#ifndef DISABLE_MENU
77886b88 213 case LXPANEL_CMD_SYS_MENU:
d18c9409
HJYP
214 {
215 GSList* l;
216 for( l = all_panels; l; l = l->next )
8c44345a 217 {
d18c9409
HJYP
218 Panel* p = (Panel*)l->data;
219 if( p->system_menus )
220 {
221 /* show_system_menu( p->system_menus->data ); */
222 /* FIXME: I've no idea why this doesn't work without timeout
223 under some WMs, like icewm. */
224 g_timeout_add( 200, (GSourceFunc)show_system_menu,
225 p->system_menus->data );
226 }
8c44345a 227 }
77886b88 228 break;
d18c9409 229 }
ace2a572
JH
230#endif
231#ifndef DISABLE_MENU
77886b88
HJYP
232 case LXPANEL_CMD_RUN:
233 gtk_run();
234 break;
ace2a572 235#endif
77886b88 236 case LXPANEL_CMD_CONFIG:
8110399f 237 //FIXME: configure();
77886b88
HJYP
238 break;
239 case LXPANEL_CMD_RESTART:
240 restart();
241 break;
242 case LXPANEL_CMD_EXIT:
243 gtk_main_quit();
244 break;
245 }
246}
247
a52c2257 248static GdkFilterReturn
cf701cb7 249panel_event_filter(GdkXEvent *xevent, GdkEvent *event, gpointer not_used)
a52c2257
HJYP
250{
251 Atom at;
252 Window win;
253 XEvent *ev = (XEvent *) xevent;
254
255 ENTER;
256 DBG("win = 0x%x\n", ev->xproperty.window);
77886b88
HJYP
257 if (ev->type != PropertyNotify ) {
258 /* private client message from lxpanelctl */
259 if( ev->type == ClientMessage && ev->xproperty.atom == a_LXPANEL_CMD )
260 {
d18c9409 261 process_client_msg( (XClientMessageEvent*)ev );
77886b88 262 }
22242ed4
HJYP
263 else if( ev->type == DestroyNotify )
264 {
cf701cb7 265 fb_ev_emit_destroy( fbev, ((XDestroyWindowEvent*)ev)->window );
22242ed4 266 }
a52c2257 267 RET(GDK_FILTER_CONTINUE);
24053345 268 }
77886b88 269
a52c2257
HJYP
270 at = ev->xproperty.atom;
271 win = ev->xproperty.window;
a52c2257 272 if (win == GDK_ROOT_WINDOW()) {
cf701cb7
HJYP
273 if (at == a_NET_CLIENT_LIST) {
274 fb_ev_emit(fbev, EV_CLIENT_LIST);
275 } else if (at == a_NET_CURRENT_DESKTOP) {
276 GSList* l;
277 for( l = all_panels; l; l = l->next )
278 ((Panel*)l->data)->curdesk = get_net_current_desktop();
22242ed4 279 fb_ev_emit(fbev, EV_CURRENT_DESKTOP);
cf701cb7
HJYP
280 } else if (at == a_NET_NUMBER_OF_DESKTOPS) {
281 GSList* l;
282 for( l = all_panels; l; l = l->next )
283 ((Panel*)l->data)->desknum = get_net_number_of_desktops();
22242ed4 284 fb_ev_emit(fbev, EV_NUMBER_OF_DESKTOPS);
cf701cb7 285 } else if (at == a_NET_DESKTOP_NAMES) {
22242ed4 286 fb_ev_emit(fbev, EV_DESKTOP_NAMES);
a52c2257 287 } else if (at == a_NET_ACTIVE_WINDOW) {
22242ed4 288 fb_ev_emit(fbev, EV_ACTIVE_WINDOW );
cf701cb7 289 } else if (at == a_NET_CLIENT_LIST_STACKING) {
22242ed4 290 fb_ev_emit(fbev, EV_CLIENT_LIST_STACKING);
a52c2257 291 } else if (at == a_XROOTPMAP_ID) {
cf701cb7
HJYP
292 GSList* l;
293 for( l = all_panels; l; l = l->next )
294 {
295 Panel* p = (Panel*)l->data;
296 if (p->transparent) {
297 fb_bg_notify_changed_bg(p->bg);
298 }
299 }
300 } else if (at == a_NET_WORKAREA) {
301 GSList* l;
302 for( l = all_panels; l; l = l->next )
303 {
304 Panel* p = (Panel*)l->data;
305 g_free( p->workarea );
306 p->workarea = get_xaproperty (GDK_ROOT_WINDOW(), a_NET_WORKAREA, XA_CARDINAL, &p->wa_len);
1d9dc649 307 /* print_wmdata(p); */
a52c2257 308 }
a52c2257 309 } else
cf701cb7
HJYP
310 return GDK_FILTER_CONTINUE;
311
312 return GDK_FILTER_REMOVE;
a52c2257 313 }
cf701cb7 314 return GDK_FILTER_CONTINUE;
a52c2257
HJYP
315}
316
317/****************************************************
318 * panel's handlers for GTK events *
319 ****************************************************/
320
bee4c26e 321
a52c2257
HJYP
322static gint
323panel_delete_event(GtkWidget * widget, GdkEvent * event, gpointer data)
324{
325 ENTER;
326 RET(FALSE);
327}
328
329static gint
330panel_destroy_event(GtkWidget * widget, GdkEvent * event, gpointer data)
331{
22242ed4 332 //Panel *p = (Panel *) data;
a52c2257
HJYP
333 //if (!p->self_destroy)
334 gtk_main_quit();
335 RET(FALSE);
336}
337
4542c20d 338static void
22242ed4 339on_root_bg_changed(FbBg *bg, Panel* p)
4542c20d
HJYP
340{
341 panel_update_background( p );
342}
343
2918994e 344void panel_determine_background_pixmap(Panel * p, GtkWidget * widget, GdkWindow * window)
4542c20d 345{
2918994e 346 GdkPixmap * pixmap = NULL;
4542c20d 347
2918994e 348 /* Free p->bg if it is not going to be used. */
349 if (( ! p->transparent) && (p->bg != NULL))
350 {
351 g_signal_handlers_disconnect_by_func(G_OBJECT(p->bg), on_root_bg_changed, p);
352 g_object_unref(p->bg);
353 p->bg = NULL;
354 }
4542c20d 355
2918994e 356 if (p->background)
357 {
358 /* User specified background pixmap. */
359 if (p->background_file != NULL)
360 pixmap = fb_bg_get_pix_from_file(widget, p->background_file);
4542c20d 361 }
2918994e 362
363 else if (p->transparent)
4542c20d 364 {
2918994e 365 /* Transparent. Determine the appropriate value from the root pixmap. */
366 if (p->bg == NULL)
4542c20d 367 {
2918994e 368 p->bg = fb_bg_get_for_display();
369 g_signal_connect(G_OBJECT(p->bg), "changed", G_CALLBACK(on_root_bg_changed), p);
4542c20d 370 }
2918994e 371 pixmap = fb_bg_get_xroot_pix_for_win(p->bg, widget);
372 if ((pixmap != NULL) && (pixmap != GDK_NO_BG) && (p->alpha != 0))
373 fb_bg_composite(pixmap, widget->style->black_gc, p->tintcolor, p->alpha);
4542c20d
HJYP
374 }
375
2918994e 376 if (pixmap != NULL)
4542c20d 377 {
2918994e 378 gtk_widget_set_app_paintable(widget, TRUE );
379 gdk_window_set_back_pixmap(window, pixmap, FALSE);
380 g_object_unref(pixmap);
4542c20d
HJYP
381 }
382 else
2918994e 383 gtk_widget_set_app_paintable(widget, FALSE);
384}
4542c20d 385
2918994e 386/* Update the background of the entire panel.
387 * This function should only be called after the panel has been realized. */
388void panel_update_background(Panel * p)
389{
390 /* Redraw the top level widget. */
391 panel_determine_background_pixmap(p, p->topgwin, p->topgwin->window);
392 gdk_window_clear(p->topgwin->window);
393 gtk_widget_queue_draw(p->topgwin);
2918994e 394
395 /* Loop over all plugins redrawing each plugin. */
396 GList * l;
397 for (l = p->plugins; l != NULL; l = l->next)
4542c20d 398 {
2918994e 399 Plugin * pl = (Plugin *) l->data;
964b8b7e 400 if (pl->pwid != NULL)
401 plugin_widget_set_background(pl->pwid, p);
4542c20d
HJYP
402 }
403
4542c20d 404}
a52c2257 405
84fc1d55
HJYP
406static gboolean delay_update_background( Panel* p )
407{
6589616e
JH
408 /* Panel could be destroyed while background update scheduled */
409 if ( p->topgwin && GTK_WIDGET_REALIZED ( p->topgwin ) ) {
410 gdk_display_sync( gtk_widget_get_display(p->topgwin) );
411 panel_update_background( p );
412 }
413
cf701cb7 414 return FALSE;
84fc1d55
HJYP
415}
416
417static void
f2d54481
HJYP
418panel_realize(GtkWidget *widget, Panel *p)
419{
e3b89f43 420 g_idle_add_full( G_PRIORITY_LOW,
421 (GSourceFunc)delay_update_background, p, NULL );
f2d54481
HJYP
422}
423
424static void
84fc1d55
HJYP
425panel_style_set(GtkWidget *widget, GtkStyle* prev, Panel *p)
426{
0987f648 427 /* FIXME: This dirty hack is used to fix the background of systray... */
cf701cb7 428 if( GTK_WIDGET_REALIZED( widget ) )
e3b89f43 429 g_idle_add_full( G_PRIORITY_LOW,
430 (GSourceFunc)delay_update_background, p, NULL );
84fc1d55 431}
4542c20d 432
a52c2257 433static gint
22242ed4 434panel_size_req(GtkWidget *widget, GtkRequisition *req, Panel *p)
a52c2257
HJYP
435{
436 ENTER;
4542c20d 437
a52c2257
HJYP
438 if (p->widthtype == WIDTH_REQUEST)
439 p->width = (p->orientation == ORIENT_HORIZ) ? req->width : req->height;
440 if (p->heighttype == HEIGHT_REQUEST)
441 p->height = (p->orientation == ORIENT_HORIZ) ? req->height : req->width;
442 calculate_position(p);
443 req->width = p->aw;
444 req->height = p->ah;
4542c20d 445
a52c2257
HJYP
446 RET( TRUE );
447}
448
449static gint
22242ed4 450panel_size_alloc(GtkWidget *widget, GtkAllocation *a, Panel *p)
a52c2257
HJYP
451{
452 ENTER;
a52c2257
HJYP
453 if (p->widthtype == WIDTH_REQUEST)
454 p->width = (p->orientation == ORIENT_HORIZ) ? a->width : a->height;
455 if (p->heighttype == HEIGHT_REQUEST)
456 p->height = (p->orientation == ORIENT_HORIZ) ? a->height : a->width;
457 calculate_position(p);
4542c20d 458
a52c2257 459 if (a->width == p->aw && a->height == p->ah && a->x == p->ax && a->y == p ->ay) {
a52c2257
HJYP
460 RET(TRUE);
461 }
462
463 gtk_window_move(GTK_WINDOW(p->topgwin), p->ax, p->ay);
bee4c26e 464 panel_set_wm_strut(p);
a52c2257
HJYP
465 RET(TRUE);
466}
467
a52c2257 468static gboolean
22242ed4 469panel_configure_event (GtkWidget *widget, GdkEventConfigure *e, Panel *p)
a52c2257
HJYP
470{
471 ENTER;
472 if (e->width == p->cw && e->height == p->ch && e->x == p->cx && e->y == p->cy)
473 RET(TRUE);
474 p->cw = e->width;
475 p->ch = e->height;
476 p->cx = e->x;
477 p->cy = e->y;
4542c20d 478
a52c2257
HJYP
479 if (p->transparent)
480 fb_bg_notify_changed_bg(p->bg);
bee4c26e 481
4542c20d 482 RET(FALSE);
a52c2257
HJYP
483}
484
fddae119
FC
485static gint
486panel_popupmenu_configure(GtkWidget *widget, gpointer user_data)
487{
4b93d81e
HJYP
488 panel_configure( (Panel*)user_data, 0 );
489 return TRUE;
fddae119
FC
490}
491
9dd114c4 492/* Handler for "button_press_event" signal with Panel as parameter. */
493static gboolean panel_button_press_event_with_panel(GtkWidget *widget, GdkEventButton *event, Panel *panel)
fddae119 494{
9dd114c4 495 if (event->button == 3) /* right button */
496 {
497 GtkMenu* popup = (GtkMenu*) lxpanel_get_panel_menu(panel, NULL, FALSE);
498 gtk_menu_popup(popup, NULL, NULL, NULL, NULL, event->button, event->time);
499 return TRUE;
500 }
fddae119
FC
501 return FALSE;
502}
503
cf701cb7
HJYP
504static void panel_popupmenu_config_plugin( GtkMenuItem* item, Plugin* plugin )
505{
e3b89f43 506 plugin->class->config( plugin, GTK_WINDOW(plugin->panel->topgwin) );
930af9fd
HJYP
507
508 /* FIXME: this should be more elegant */
509 plugin->panel->config_changed = TRUE;
cf701cb7
HJYP
510}
511
4b93d81e
HJYP
512static void panel_popupmenu_add_item( GtkMenuItem* item, Panel* panel )
513{
514 /* panel_add_plugin( panel, panel->topgwin ); */
8d8b66da 515 panel_configure( panel, 2 );
cf701cb7
HJYP
516}
517
518static void panel_popupmenu_remove_item( GtkMenuItem* item, Plugin* plugin )
519{
520 Panel* panel = plugin->panel;
521 panel->plugins = g_list_remove( panel->plugins, plugin );
2918994e 522 plugin_delete(plugin);
4b93d81e 523 panel_config_save( plugin->panel );
cf701cb7
HJYP
524}
525
3e7b8eb7
HJYP
526/* FIXME: Potentially we can support multiple panels at the same edge,
527 * but currently this cannot be done due to some positioning problems. */
528static char* gen_panel_name( int edge )
529{
530 const char* edge_str = num2str( edge_pair, edge, "" );
531 char* name = NULL;
532 char* dir = get_config_file( cprofile, "panels", FALSE );
533 int i;
534 for( i = 0; i < G_MAXINT; ++i )
535 {
536 char* f;
537 if( G_LIKELY( i > 0 ) )
538 name = g_strdup_printf( "%s%d", edge_str, i );
539 else
540 name = g_strdup( edge_str );
541 f = g_build_filename( dir, name, NULL );
542 if( ! g_file_test( f, G_FILE_TEST_EXISTS ) )
543 {
544 g_free( f );
545 break;
546 }
547 g_free( name );
548 g_free( f );
549 }
550 g_free( dir );
551 return name;
552}
553
9dd114c4 554static void try_allocate_edge(Panel* p, int edge)
555{
556 if ((p->edge == EDGE_NONE) && (panel_edge_available(p, edge)))
557 p->edge = edge;
558}
559
3e7b8eb7
HJYP
560/* FIXME: Potentially we can support multiple panels at the same edge,
561 * but currently this cannot be done due to some positioning problems. */
cf701cb7
HJYP
562static void panel_popupmenu_create_panel( GtkMenuItem* item, Panel* panel )
563{
9dd114c4 564 Panel* new_panel = panel_allocate();
565
566 /* Allocate the edge. */
567 try_allocate_edge(new_panel, EDGE_BOTTOM);
568 try_allocate_edge(new_panel, EDGE_TOP);
569 try_allocate_edge(new_panel, EDGE_LEFT);
570 try_allocate_edge(new_panel, EDGE_RIGHT);
571 new_panel->name = gen_panel_name(new_panel->edge);
572
573 panel_configure(new_panel, 0);
574 panel_normalize_configuration(new_panel);
575 panel_start_gui(new_panel);
576 gtk_widget_show_all(new_panel->topgwin);
577
578 panel_config_save(new_panel);
579 all_panels = g_slist_prepend(all_panels, new_panel);
cf701cb7
HJYP
580}
581
582static void panel_popupmenu_delete_panel( GtkMenuItem* item, Panel* panel )
583{
584 GtkWidget* dlg;
585 gboolean ok;
e3b89f43 586 dlg = gtk_message_dialog_new_with_markup( GTK_WINDOW(panel->topgwin),
cf701cb7
HJYP
587 GTK_DIALOG_MODAL,
588 GTK_MESSAGE_QUESTION,
589 GTK_BUTTONS_OK_CANCEL,
590 _("Really delete this panel?\n<b>Warning: This can not be recovered.</b>") );
d1d43629 591 panel_apply_icon(GTK_WINDOW(dlg));
cf701cb7
HJYP
592 gtk_window_set_title( (GtkWindow*)dlg, _("Confirm") );
593 ok = ( gtk_dialog_run( (GtkDialog*)dlg ) == GTK_RESPONSE_OK );
594 gtk_widget_destroy( dlg );
595 if( ok )
596 {
4b93d81e 597 gchar *fname, *dir;
cf701cb7 598 all_panels = g_slist_remove( all_panels, panel );
4b93d81e
HJYP
599
600 /* delete the config file of this panel */
601 dir = get_config_file( cprofile, "panels", FALSE );
602 fname = g_build_filename( dir, panel->name, NULL );
603 g_free( dir );
604 g_unlink( fname );
930af9fd 605 panel->config_changed = 0;
cf701cb7
HJYP
606 panel_destroy( panel );
607 }
608}
609
e7a42ecf 610static void panel_popupmenu_about( GtkMenuItem* item, Panel* panel )
611{
612 GtkWidget *about;
613 const gchar* authors[] = {
614 "Hong Jen Yee (PCMan) <pcman.tw@gmail.com>",
615 "Jim Huang <jserv.tw@gmail.com>",
616 "Greg McNew <gmcnew@gmail.com> (battery plugin)",
617 "Fred Chien <cfsghost@gmail.com>",
618 "Daniel Kesler <kesler.daniel@gmail.com>",
619 "Juergen Hoetzel <juergen@archlinux.org>",
2918994e 620 "Marty Jack <martyj19@comcast.net>",
e7a42ecf 621 NULL
622 };
623 /* TRANSLATORS: Replace this string with your names, one name per line. */
624 gchar *translators = _( "translator-credits" );
625
626 about = gtk_about_dialog_new();
627 panel_apply_icon(GTK_WINDOW(about));
628 gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(about), VERSION);
629 gtk_about_dialog_set_name(GTK_ABOUT_DIALOG(about), _("LXPanel"));
630 gtk_about_dialog_set_logo(GTK_ABOUT_DIALOG(about), gdk_pixbuf_new_from_file(PACKAGE_DATA_DIR "/lxpanel/images/my-computer.png", NULL));
631 gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(about), _("Copyright (C) 2008-2009"));
632 gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(about), _( "Desktop panel for LXDE project"));
633 gtk_about_dialog_set_license(GTK_ABOUT_DIALOG(about), "This program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.");
634 gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(about), "http://lxde.org/");
635 gtk_about_dialog_set_authors(GTK_ABOUT_DIALOG(about), authors);
636 gtk_about_dialog_set_translator_credits(GTK_ABOUT_DIALOG(about), translators);
637 gtk_dialog_run(GTK_DIALOG(about));
638 gtk_widget_destroy(about);
639}
640
641void panel_apply_icon( GtkWindow *w )
642{
643 gtk_window_set_icon_from_file(w, PACKAGE_DATA_DIR "/lxpanel/images/my-computer.png", NULL);
644}
645
9dd114c4 646GtkMenu* lxpanel_get_panel_menu( Panel* panel, Plugin* plugin, gboolean use_sub_menu )
cf701cb7 647{
e3b89f43 648 GtkWidget *menu_item, *img;
649 GtkMenu *ret,*menu;
650
cf701cb7 651 char* tmp;
e3b89f43 652 ret = menu = GTK_MENU(gtk_menu_new());
cf701cb7 653
4b93d81e
HJYP
654 img = gtk_image_new_from_stock( GTK_STOCK_EDIT, GTK_ICON_SIZE_MENU );
655 menu_item = gtk_image_menu_item_new_with_label(_("Add / Remove Panel Items"));
656 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
657 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
658 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_add_item), panel );
cf701cb7
HJYP
659
660 if( plugin )
661 {
662 img = gtk_image_new_from_stock( GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU );
663 tmp = g_strdup_printf( _("Remove \"%s\" From Panel"), _(plugin->class->name) );
664 menu_item = gtk_image_menu_item_new_with_label( tmp );
665 g_free( tmp );
666 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
667 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
668 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_remove_item), plugin );
669 }
670
671 menu_item = gtk_separator_menu_item_new();
672 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
673
4b93d81e
HJYP
674 img = gtk_image_new_from_stock( GTK_STOCK_PREFERENCES, GTK_ICON_SIZE_MENU );
675 menu_item = gtk_image_menu_item_new_with_label(_("Panel Settings"));
676 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
677 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
678 g_signal_connect(G_OBJECT(menu_item), "activate", G_CALLBACK(panel_popupmenu_configure), panel );
679
cf701cb7
HJYP
680 img = gtk_image_new_from_stock( GTK_STOCK_NEW, GTK_ICON_SIZE_MENU );
681 menu_item = gtk_image_menu_item_new_with_label(_("Create New Panel"));
682 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
683 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
684 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_create_panel), panel );
3e7b8eb7
HJYP
685 /* FIXME: Potentially we can support multiple panels at the same edge,
686 * but currently this cannot be done due to some positioning problems. */
687 /* currently, disable the option when there are already four panels */
688 if( g_slist_length( all_panels ) >= 4 )
689 gtk_widget_set_sensitive( menu_item, FALSE );
cf701cb7
HJYP
690
691 img = gtk_image_new_from_stock( GTK_STOCK_DELETE, GTK_ICON_SIZE_MENU );
692 menu_item = gtk_image_menu_item_new_with_label(_("Delete This Panel"));
693 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
694 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
695 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_delete_panel), panel );
696 if( ! all_panels->next ) /* if this is the only panel */
697 gtk_widget_set_sensitive( menu_item, FALSE );
698
e7a42ecf 699 menu_item = gtk_separator_menu_item_new();
700 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
701
702 img = gtk_image_new_from_stock( GTK_STOCK_ABOUT, GTK_ICON_SIZE_MENU );
703 menu_item = gtk_image_menu_item_new_with_label(_("About"));
704 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
705 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
706 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_about), panel );
707
cf701cb7
HJYP
708 if( use_sub_menu )
709 {
e3b89f43 710 ret = GTK_MENU(gtk_menu_new());
cf701cb7
HJYP
711 menu_item = gtk_image_menu_item_new_with_label(_("Panel"));
712 gtk_menu_shell_append(GTK_MENU_SHELL(ret), menu_item);
e3b89f43 713 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), GTK_WIDGET(menu) );
cf701cb7 714
e3b89f43 715 gtk_widget_show_all(GTK_WIDGET(ret));
cf701cb7
HJYP
716 }
717
3e7b8eb7
HJYP
718 if( plugin )
719 {
720 menu_item = gtk_separator_menu_item_new();
721 gtk_menu_shell_prepend(GTK_MENU_SHELL(ret), menu_item);
722
723 img = gtk_image_new_from_stock( GTK_STOCK_PREFERENCES, GTK_ICON_SIZE_MENU );
724 tmp = g_strdup_printf( _("\"%s\" Settings"), _(plugin->class->name) );
725 menu_item = gtk_image_menu_item_new_with_label( tmp );
726 g_free( tmp );
727 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
728 gtk_menu_shell_prepend(GTK_MENU_SHELL(ret), menu_item);
729 if( plugin->class->config )
730 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_config_plugin), plugin );
731 else
732 gtk_widget_set_sensitive( menu_item, FALSE );
733 }
734
e3b89f43 735 gtk_widget_show_all(GTK_WIDGET(menu));
3e7b8eb7 736
cf701cb7
HJYP
737 g_signal_connect( ret, "selection-done", G_CALLBACK(gtk_widget_destroy), NULL );
738 return ret;
739}
740
a52c2257
HJYP
741/****************************************************
742 * panel creation *
743 ****************************************************/
176fb687 744
a52c2257 745static void
22242ed4 746make_round_corners(Panel *p)
a52c2257 747{
a97d06a6 748 /* FIXME: This should be re-written with shape extension of X11 */
4542c20d 749 /* gdk_window_shape_combine_mask() can be used */
bee4c26e
HJYP
750}
751
22242ed4 752void panel_set_dock_type(Panel *p)
bee4c26e
HJYP
753{
754 if (p->setdocktype) {
755 Atom state = a_NET_WM_WINDOW_TYPE_DOCK;
756 XChangeProperty(GDK_DISPLAY(), p->topxwin,
757 a_NET_WM_WINDOW_TYPE, XA_ATOM, 32,
758 PropModeReplace, (unsigned char *) &state, 1);
759 }
760 else {
761 XDeleteProperty( GDK_DISPLAY(), p->topxwin, a_NET_WM_WINDOW_TYPE );
762 }
a52c2257
HJYP
763}
764
176fb687 765static void panel_set_visibility(Panel *p, gboolean visible)
766{
767 if ( ! visible) gtk_widget_hide(p->box);
768 p->visible = visible;
769 calculate_position(p);
770 gtk_widget_set_size_request(p->topgwin, p->aw, p->ah);
771 gdk_window_move(p->topgwin->window, p->ax, p->ay);
772 if (visible) gtk_widget_show(p->box);
773 panel_set_wm_strut(p);
774}
775
776static gboolean panel_leave_real(Panel *p)
777{
778 if (gdk_display_pointer_is_grabbed(p->display))
779 return TRUE;
780
781 gint x, y;
782 gdk_display_get_pointer(p->display, NULL, &x, &y, NULL);
783 if ((p->cx <= x) && (x <= (p->cx + p->cw)) && (p->cy <= y) && (y <= (p->cy + p->ch)))
784 return TRUE;
785
786 if ((p->autohide) && (p->visible))
787 panel_set_visibility(p, FALSE);
788
789 p->hide_timeout = 0;
790 return FALSE;
791}
792
793static gboolean panel_enter(GtkImage *widget, GdkEventCrossing *event, Panel *p)
794{
795 if (p->hide_timeout)
796 return FALSE;
797
798 p->hide_timeout = g_timeout_add(500, (GSourceFunc) panel_leave_real, p);
799
800 panel_set_visibility(p, TRUE);
801 return TRUE;
802}
803
804static gboolean panel_drag_motion(GtkWidget *widget, GdkDragContext *drag_context, gint x,
805 gint y, guint time, Panel *p)
806{
807 panel_enter(NULL, NULL, p);
808 return TRUE;
809}
810
811void panel_establish_autohide(Panel *p)
812{
813 if (p->autohide)
814 {
815 gtk_widget_add_events(p->topgwin, GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK);
816 g_signal_connect(G_OBJECT(p->topgwin), "enter-notify-event", G_CALLBACK(panel_enter), p);
817 g_signal_connect(G_OBJECT(p->topgwin), "drag-motion", (GCallback) panel_drag_motion, p);
818 gtk_drag_dest_set(p->topgwin, GTK_DEST_DEFAULT_MOTION, NULL, 0, 0);
819 gtk_drag_dest_set_track_motion(p->topgwin, TRUE);
820 panel_enter(NULL, NULL, p);
821 }
822 else if ( ! p->visible)
823 {
824 gtk_widget_show(p->box);
825 p->visible = TRUE;
826 }
827}
828
8f9e6256 829/* Set an image from a file with scaling to the panel icon size. */
830void panel_image_set_from_file(Panel * p, GtkWidget * image, char * file)
831{
832 GdkPixbuf * pixbuf = gdk_pixbuf_new_from_file_at_scale(file, p->icon_size, p->icon_size, TRUE, NULL);
833 if (pixbuf != NULL)
834 {
835 gtk_image_set_from_pixbuf(GTK_IMAGE(image), pixbuf);
836 g_object_unref(pixbuf);
837 }
838}
839
0defe4b9 840static void
22242ed4 841panel_start_gui(Panel *p)
a52c2257
HJYP
842{
843 Atom state[3];
844 XWMHints wmhints;
845 guint32 val;
6db11841 846
a52c2257
HJYP
847 ENTER;
848
9dd114c4 849 p->curdesk = get_net_current_desktop();
850 p->desknum = get_net_number_of_desktops();
851 p->workarea = get_xaproperty (GDK_ROOT_WINDOW(), a_NET_WORKAREA, XA_CARDINAL, &p->wa_len);
852
a52c2257
HJYP
853 // main toplevel window
854 p->topgwin = gtk_window_new(GTK_WINDOW_TOPLEVEL);
176fb687 855 p->display = gdk_display_get_default();
a52c2257
HJYP
856 gtk_container_set_border_width(GTK_CONTAINER(p->topgwin), 0);
857 gtk_window_set_resizable(GTK_WINDOW(p->topgwin), FALSE);
858 gtk_window_set_wmclass(GTK_WINDOW(p->topgwin), "panel", "lxpanel");
859 gtk_window_set_title(GTK_WINDOW(p->topgwin), "panel");
860 gtk_window_set_position(GTK_WINDOW(p->topgwin), GTK_WIN_POS_NONE);
861 gtk_window_set_decorated(GTK_WINDOW(p->topgwin), FALSE);
77886b88 862
e2957bd2
HJYP
863 gtk_window_group_add_window( win_grp, (GtkWindow*)p->topgwin );
864
a52c2257
HJYP
865 g_signal_connect(G_OBJECT(p->topgwin), "delete-event",
866 G_CALLBACK(panel_delete_event), p);
867 g_signal_connect(G_OBJECT(p->topgwin), "destroy-event",
868 G_CALLBACK(panel_destroy_event), p);
869 g_signal_connect (G_OBJECT (p->topgwin), "size-request",
870 (GCallback) panel_size_req, p);
871 g_signal_connect (G_OBJECT (p->topgwin), "size-allocate",
872 (GCallback) panel_size_alloc, p);
873 g_signal_connect (G_OBJECT (p->topgwin), "configure-event",
874 (GCallback) panel_configure_event, p);
3e7b8eb7
HJYP
875
876 gtk_widget_add_events( p->topgwin, GDK_BUTTON_PRESS_MASK );
fddae119 877 g_signal_connect(G_OBJECT (p->topgwin), "button_press_event",
9dd114c4 878 (GCallback) panel_button_press_event_with_panel, p);
f2d54481 879
a52c2257
HJYP
880 g_signal_connect (G_OBJECT (p->topgwin), "realize",
881 (GCallback) panel_realize, p);
f2d54481 882
84fc1d55
HJYP
883 g_signal_connect (G_OBJECT (p->topgwin), "style-set",
884 (GCallback)panel_style_set, p);
a52c2257
HJYP
885 gtk_widget_realize(p->topgwin);
886 //gdk_window_set_decorations(p->topgwin->window, 0);
2de71c90 887
4542c20d 888 // main layout manager as a single child of panel
a97d06a6 889 p->box = p->my_box_new(FALSE, 0);
a52c2257 890 gtk_container_set_border_width(GTK_CONTAINER(p->box), 0);
4542c20d
HJYP
891// gtk_container_add(GTK_CONTAINER(p->bbox), p->box);
892 gtk_container_add(GTK_CONTAINER(p->topgwin), p->box);
a52c2257 893 gtk_widget_show(p->box);
a97d06a6
HJYP
894 if (p->round_corners)
895 make_round_corners(p);
6db11841 896
a52c2257
HJYP
897 p->topxwin = GDK_WINDOW_XWINDOW(GTK_WIDGET(p->topgwin)->window);
898 DBG("topxwin = %x\n", p->topxwin);
899
900 /* the settings that should be done before window is mapped */
901 wmhints.flags = InputHint;
902 wmhints.input = 0;
bee4c26e 903 XSetWMHints (GDK_DISPLAY(), p->topxwin, &wmhints);
24053345 904#define WIN_HINTS_SKIP_FOCUS (1<<0) /* "alt-tab" skips this win */
a52c2257
HJYP
905 val = WIN_HINTS_SKIP_FOCUS;
906 XChangeProperty(GDK_DISPLAY(), p->topxwin,
907 XInternAtom(GDK_DISPLAY(), "_WIN_HINTS", False), XA_CARDINAL, 32,
908 PropModeReplace, (unsigned char *) &val, 1);
909
bee4c26e 910 panel_set_dock_type(p);
a52c2257
HJYP
911
912 /* window mapping point */
913 gtk_widget_show_all(p->topgwin);
914
915 /* the settings that should be done after window is mapped */
176fb687 916 panel_establish_autohide(p);
a52c2257
HJYP
917
918 /* send it to running wm */
919 Xclimsg(p->topxwin, a_NET_WM_DESKTOP, 0xFFFFFFFF, 0, 0, 0, 0);
920 /* and assign it ourself just for case when wm is not running */
921 val = 0xFFFFFFFF;
922 XChangeProperty(GDK_DISPLAY(), p->topxwin, a_NET_WM_DESKTOP, XA_CARDINAL, 32,
923 PropModeReplace, (unsigned char *) &val, 1);
924
925 state[0] = a_NET_WM_STATE_SKIP_PAGER;
926 state[1] = a_NET_WM_STATE_SKIP_TASKBAR;
927 state[2] = a_NET_WM_STATE_STICKY;
928 XChangeProperty(GDK_DISPLAY(), p->topxwin, a_NET_WM_STATE, XA_ATOM,
929 32, PropModeReplace, (unsigned char *) state, 3);
930
a52c2257
HJYP
931 calculate_position(p);
932 gdk_window_move_resize(p->topgwin->window, p->ax, p->ay, p->aw, p->ah);
bee4c26e 933 panel_set_wm_strut(p);
77886b88 934
a52c2257
HJYP
935 RET();
936}
937
2918994e 938/* Exchange the "width" and "height" terminology for vertical and horizontal panels. */
939void panel_adjust_geometry_terminology(Panel * p)
9dd114c4 940{
941 if ((p->height_label != NULL) && (p->width_label != NULL))
942 {
943 if ((p->edge == EDGE_TOP) || (p->edge == EDGE_BOTTOM))
944 {
945 gtk_label_set_text(GTK_LABEL(p->height_label), _("Height:"));
946 gtk_label_set_text(GTK_LABEL(p->width_label), _("Width:"));
2918994e 947 gtk_button_set_label(GTK_BUTTON(p->alignment_left_label), _("Left"));
948 gtk_button_set_label(GTK_BUTTON(p->alignment_right_label), _("Right"));
9dd114c4 949 }
950 else
951 {
952 gtk_label_set_text(GTK_LABEL(p->height_label), _("Width:"));
953 gtk_label_set_text(GTK_LABEL(p->width_label), _("Height:"));
2918994e 954 gtk_button_set_label(GTK_BUTTON(p->alignment_left_label), _("Top"));
955 gtk_button_set_label(GTK_BUTTON(p->alignment_right_label), _("Bottom"));
9dd114c4 956 }
957 }
958}
959
2918994e 960/* Draw text into a label, with the user preference color and optionally bold. */
6835a23e 961void panel_draw_label_text(Panel * p, GtkWidget * label, char * text, gboolean bold, gboolean custom_color)
2918994e 962{
963 char buffer[512];
964
965 if (text == NULL)
966 {
967 /* Null string. */
968 gtk_label_set_text(GTK_LABEL(label), NULL);
969 }
970
f669ce5e 971 else
2918994e 972 {
f669ce5e 973 /* Compute an appropriate size so the font will scale with the panel's icon size. */
974 int font_desc;
975 if (p->icon_size < 20)
976 font_desc = 9;
977 else if (p->icon_size >= 20 && p->icon_size < 26)
978 font_desc = 10;
f669ce5e 979 else
ee4695be 980 font_desc = 12;
2918994e 981
982 /* Check the string for characters that need to be escaped.
983 * If any are found, create the properly escaped string and use it instead. */
f669ce5e 984 char * valid_markup = text;
985 char * escaped_text = NULL;
2918994e 986 char * q;
987 for (q = text; *q != '\0'; q += 1)
988 {
989 if ((*q == '<') || (*q == '>') || (*q == '&'))
990 {
991 escaped_text = g_markup_escape_text(text, -1);
992 valid_markup = escaped_text;
993 break;
994 }
995 }
996
6835a23e 997 if ((custom_color) && (p->usefontcolor))
2918994e 998 {
999 /* Color, optionally bold. */
f669ce5e 1000 g_snprintf(buffer, sizeof(buffer), "<span font_desc=\"%d\" color=\"#%06x\">%s%s%s</span>",
1001 font_desc,
2918994e 1002 gcolor2rgb24(&p->gfontcolor),
1003 ((bold) ? "<b>" : ""),
1004 valid_markup,
1005 ((bold) ? "</b>" : ""));
1006 gtk_label_set_markup(GTK_LABEL(label), buffer);
1007 }
f669ce5e 1008 else
2918994e 1009 {
f669ce5e 1010 /* No color, optionally bold. */
1011 g_snprintf(buffer, sizeof(buffer), "<span font_desc=\"%d\">%s%s%s</span>",
1012 font_desc,
1013 ((bold) ? "<b>" : ""),
1014 valid_markup,
1015 ((bold) ? "</b>" : ""));
2918994e 1016 gtk_label_set_markup(GTK_LABEL(label), buffer);
1017 }
1018 g_free(escaped_text);
1019 }
2918994e 1020}
1021
1022void panel_set_panel_configuration_changed(Panel *p)
a97d06a6
HJYP
1023{
1024 GList* l;
9dd114c4 1025
1026 int previous_orientation = p->orientation;
a97d06a6
HJYP
1027 p->orientation = (p->edge == EDGE_TOP || p->edge == EDGE_BOTTOM)
1028 ? ORIENT_HORIZ : ORIENT_VERT;
9dd114c4 1029
1030 if (previous_orientation != p->orientation)
1031 {
1032 panel_adjust_geometry_terminology(p);
1033 p->height = ((p->orientation == ORIENT_HORIZ) ? PANEL_HEIGHT_DEFAULT : PANEL_WIDTH_DEFAULT);
1034 if (p->height_control != NULL)
1035 gtk_spin_button_set_value(GTK_SPIN_BUTTON(p->height_control), p->height);
2918994e 1036 if ((p->widthtype == WIDTH_PIXEL) && (p->width_control != NULL))
1037 {
1038 int value = ((p->orientation == ORIENT_HORIZ) ? gdk_screen_width() : gdk_screen_height());
1039 gtk_spin_button_set_range(GTK_SPIN_BUTTON(p->width_control), 0, value);
1040 gtk_spin_button_set_value(GTK_SPIN_BUTTON(p->width_control), value);
1041 }
1042
9dd114c4 1043 }
1044
a97d06a6
HJYP
1045 if (p->orientation == ORIENT_HORIZ) {
1046 p->my_box_new = gtk_hbox_new;
1047 p->my_separator_new = gtk_vseparator_new;
1048 } else {
1049 p->my_box_new = gtk_vbox_new;
1050 p->my_separator_new = gtk_hseparator_new;
1051 }
1052
1053 /* recreate the main layout box */
964b8b7e 1054 if (p->box != NULL)
1055 {
1056#if GTK_CHECK_VERSION(2,16,0)
1057 GtkOrientation bo = (p->orientation == ORIENT_HORIZ) ? GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL;
1058 gtk_orientable_set_orientation(GTK_ORIENTABLE(p->box), bo);
1059#else
1060 GtkBox * newbox = GTK_BOX(recreate_box(GTK_BOX(p->box), p->orientation));
1061 if (GTK_WIDGET(newbox) != p->box)
1062 {
5a343ad5 1063 p->box = GTK_WIDGET(newbox);
964b8b7e 1064 gtk_container_add(GTK_CONTAINER(p->topgwin), GTK_WIDGET(newbox));
a97d06a6 1065 }
964b8b7e 1066#endif
a97d06a6 1067 }
9dd114c4 1068
a97d06a6
HJYP
1069 /* NOTE: This loop won't be executed when panel started since
1070 plugins are not loaded at that time.
1071 This is used when the orientation of the panel is changed
1072 from the config dialog, and plugins should be re-layout.
1073 */
1074 for( l = p->plugins; l; l = l->next ) {
22242ed4 1075 Plugin* pl = (Plugin*)l->data;
2918994e 1076 if( pl->class->panel_configuration_changed ) {
1077 pl->class->panel_configuration_changed( pl );
a97d06a6
HJYP
1078 }
1079 }
1080}
1081
a52c2257 1082static int
22242ed4 1083panel_parse_global(Panel *p, char **fp)
a52c2257
HJYP
1084{
1085 line s;
1086 s.len = 256;
6db11841 1087
3e7b8eb7
HJYP
1088 if( G_LIKELY( fp ) )
1089 {
1090 while (lxpanel_get_line(fp, &s) != LINE_NONE) {
1091 if (s.type == LINE_VAR) {
1092 if (!g_ascii_strcasecmp(s.t[0], "edge")) {
1093 p->edge = str2num(edge_pair, s.t[1], EDGE_NONE);
1094 } else if (!g_ascii_strcasecmp(s.t[0], "allign")) {
1095 p->allign = str2num(allign_pair, s.t[1], ALLIGN_NONE);
1096 } else if (!g_ascii_strcasecmp(s.t[0], "margin")) {
1097 p->margin = atoi(s.t[1]);
1098 } else if (!g_ascii_strcasecmp(s.t[0], "widthtype")) {
1099 p->widthtype = str2num(width_pair, s.t[1], WIDTH_NONE);
1100 } else if (!g_ascii_strcasecmp(s.t[0], "width")) {
1101 p->width = atoi(s.t[1]);
1102 } else if (!g_ascii_strcasecmp(s.t[0], "heighttype")) {
1103 p->heighttype = str2num(height_pair, s.t[1], HEIGHT_NONE);
1104 } else if (!g_ascii_strcasecmp(s.t[0], "height")) {
1105 p->height = atoi(s.t[1]);
1106 } else if (!g_ascii_strcasecmp(s.t[0], "spacing")) {
1107 p->spacing = atoi(s.t[1]);
1108 } else if (!g_ascii_strcasecmp(s.t[0], "SetDockType")) {
1109 p->setdocktype = str2num(bool_pair, s.t[1], 0);
1110 } else if (!g_ascii_strcasecmp(s.t[0], "SetPartialStrut")) {
1111 p->setstrut = str2num(bool_pair, s.t[1], 0);
1112 } else if (!g_ascii_strcasecmp(s.t[0], "RoundCorners")) {
1113 p->round_corners = str2num(bool_pair, s.t[1], 0);
1114 } else if (!g_ascii_strcasecmp(s.t[0], "Transparent")) {
1115 p->transparent = str2num(bool_pair, s.t[1], 0);
1116 } else if (!g_ascii_strcasecmp(s.t[0], "Alpha")) {
1117 p->alpha = atoi(s.t[1]);
1118 if (p->alpha > 255)
1119 p->alpha = 255;
176fb687 1120 } else if (!g_ascii_strcasecmp(s.t[0], "AutoHide")) {
1121 p->autohide = str2num(bool_pair, s.t[1], 0);
1122 } else if (!g_ascii_strcasecmp(s.t[0], "HeightWhenHidden")) {
1123 p->height_when_hidden = atoi(s.t[1]);
3e7b8eb7
HJYP
1124 } else if (!g_ascii_strcasecmp(s.t[0], "TintColor")) {
1125 if (!gdk_color_parse (s.t[1], &p->gtintcolor))
1126 gdk_color_parse ("white", &p->gtintcolor);
1127 p->tintcolor = gcolor2rgb24(&p->gtintcolor);
1128 DBG("tintcolor=%x\n", p->tintcolor);
1129 } else if (!g_ascii_strcasecmp(s.t[0], "useFontColor")) {
1130 p->usefontcolor = str2num(bool_pair, s.t[1], 0);
1131 } else if (!g_ascii_strcasecmp(s.t[0], "FontColor")) {
1132 if (!gdk_color_parse (s.t[1], &p->gfontcolor))
1133 gdk_color_parse ("black", &p->gfontcolor);
1134 p->fontcolor = gcolor2rgb24(&p->gfontcolor);
1135 DBG("fontcolor=%x\n", p->fontcolor);
1136 } else if (!g_ascii_strcasecmp(s.t[0], "Background")) {
1137 p->background = str2num(bool_pair, s.t[1], 0);
1138 } else if( !g_ascii_strcasecmp(s.t[0], "BackgroundFile") ) {
1139 p->background_file = g_strdup( s.t[1] );
8f9e6256 1140 } else if (!g_ascii_strcasecmp(s.t[0], "IconSize")) {
1141 p->icon_size = atoi(s.t[1]);
3e7b8eb7
HJYP
1142 } else {
1143 ERR( "lxpanel: %s - unknown var in Global section\n", s.t[0]);
3e7b8eb7
HJYP
1144 }
1145 } else if (s.type == LINE_BLOCK_END) {
1146 break;
a52c2257 1147 } else {
3e7b8eb7 1148 ERR( "lxpanel: illegal in this context %s\n", s.str);
a52c2257
HJYP
1149 RET(0);
1150 }
a52c2257
HJYP
1151 }
1152 }
4542c20d 1153
9dd114c4 1154 panel_normalize_configuration(p);
239cb032 1155
9dd114c4 1156 return 1;
a52c2257
HJYP
1157}
1158
1159static int
22242ed4 1160panel_parse_plugin(Panel *p, char **fp)
a52c2257
HJYP
1161{
1162 line s;
22242ed4 1163 Plugin *plug = NULL;
a52c2257 1164 gchar *type = NULL;
a52c2257 1165 int expand , padding, border;
db449f6e
HJYP
1166 char* pconfig = NULL;
1167
a52c2257
HJYP
1168 ENTER;
1169 s.len = 256;
a52c2257 1170 border = expand = padding = 0;
c69ac68e 1171 while (lxpanel_get_line(fp, &s) != LINE_BLOCK_END) {
a52c2257
HJYP
1172 if (s.type == LINE_NONE) {
1173 ERR( "lxpanel: bad line %s\n", s.str);
1174 goto error;
1175 }
1176 if (s.type == LINE_VAR) {
1177 if (!g_ascii_strcasecmp(s.t[0], "type")) {
1178 type = g_strdup(s.t[1]);
1179 DBG("plug %s\n", type);
1180 } else if (!g_ascii_strcasecmp(s.t[0], "expand"))
1181 expand = str2num(bool_pair, s.t[1], 0);
1182 else if (!g_ascii_strcasecmp(s.t[0], "padding"))
1183 padding = atoi(s.t[1]);
1184 else if (!g_ascii_strcasecmp(s.t[0], "border"))
1185 border = atoi(s.t[1]);
1186 else {
1187 ERR( "lxpanel: unknown var %s\n", s.t[0]);
a52c2257
HJYP
1188 }
1189 } else if (s.type == LINE_BLOCK_START) {
1190 if (!g_ascii_strcasecmp(s.t[0], "Config")) {
db449f6e 1191 pconfig = *fp;
a52c2257
HJYP
1192 int pno = 1;
1193 while (pno) {
1194 get_line_as_is(fp, &s);
1195 if (s.type == LINE_NONE) {
1196 ERR( "lxpanel: unexpected eof\n");
1197 goto error;
1198 } else if (s.type == LINE_BLOCK_START) {
1199 pno++;
1200 } else if (s.type == LINE_BLOCK_END) {
1201 pno--;
bee4c26e 1202 }
db449f6e 1203 }
a52c2257
HJYP
1204 } else {
1205 ERR( "lxpanel: unknown block %s\n", s.t[0]);
1206 goto error;
1207 }
1208 } else {
1209 ERR( "lxpanel: illegal in this context %s\n", s.str);
1210 goto error;
1211 }
1212 }
db449f6e 1213
a52c2257
HJYP
1214 if (!type || !(plug = plugin_load(type))) {
1215 ERR( "lxpanel: can't load %s plugin\n", type);
1216 goto error;
1217 }
db449f6e 1218
a52c2257 1219 plug->panel = p;
2918994e 1220 if (plug->class->expand_available) plug->expand = expand;
a52c2257
HJYP
1221 plug->padding = padding;
1222 plug->border = border;
a52c2257 1223 DBG("starting\n");
db449f6e 1224 if (!plugin_start(plug, pconfig ? &pconfig : NULL)) {
a52c2257
HJYP
1225 ERR( "lxpanel: can't start plugin %s\n", type);
1226 goto error;
1227 }
1228 DBG("plug %s\n", type);
1229 p->plugins = g_list_append(p->plugins, plug);
0dcb6bf5
HJYP
1230
1231 g_free( type );
a52c2257 1232 RET(1);
db449f6e 1233
a52c2257 1234 error:
2918994e 1235 if (plug != NULL)
1236 plugin_unload(plug);
a52c2257 1237 g_free(type);
a52c2257 1238 RET(0);
a52c2257
HJYP
1239}
1240
3e7b8eb7 1241int panel_start( Panel *p, char **fp )
a52c2257
HJYP
1242{
1243 line s;
db449f6e 1244
a52c2257
HJYP
1245 /* parse global section */
1246 ENTER;
1247 s.len = 256;
8110399f 1248
c69ac68e 1249 if ((lxpanel_get_line(fp, &s) != LINE_BLOCK_START) || g_ascii_strcasecmp(s.t[0], "Global")) {
a52c2257
HJYP
1250 ERR( "lxpanel: config file must start from Global section\n");
1251 RET(0);
1252 }
1253 if (!panel_parse_global(p, fp))
1254 RET(0);
1255
9dd114c4 1256 panel_start_gui(p);
1257
c69ac68e 1258 while (lxpanel_get_line(fp, &s) != LINE_NONE) {
a52c2257
HJYP
1259 if ((s.type != LINE_BLOCK_START) || g_ascii_strcasecmp(s.t[0], "Plugin")) {
1260 ERR( "lxpanel: expecting Plugin section\n");
1261 RET(0);
1262 }
9939506e 1263 panel_parse_plugin(p, fp);
a52c2257 1264 }
4542c20d
HJYP
1265
1266 /* update backgrond of panel and all plugins */
1267 panel_update_background( p );
9dd114c4 1268 return 1;
a52c2257
HJYP
1269}
1270
1271static void
1272delete_plugin(gpointer data, gpointer udata)
1273{
2918994e 1274 plugin_delete((Plugin *)data);
a52c2257
HJYP
1275}
1276
8110399f 1277void panel_destroy(Panel *p)
a52c2257
HJYP
1278{
1279 ENTER;
1280
2918994e 1281 if (p->pref_dialog != NULL)
1282 gtk_widget_destroy(p->pref_dialog);
1283 if (p->plugin_pref_dialog != NULL)
1284 {
1285 gtk_widget_destroy(p->plugin_pref_dialog);
1286 p->plugin_pref_dialog = NULL;
1287 }
1288
1289 if (p->bg != NULL)
1290 {
1291 g_signal_handlers_disconnect_by_func(G_OBJECT(p->bg), on_root_bg_changed, p);
1292 g_object_unref(p->bg);
1293 }
1294
930af9fd
HJYP
1295 if( p->config_changed )
1296 panel_config_save( p );
1297
a52c2257
HJYP
1298 g_list_foreach(p->plugins, delete_plugin, NULL);
1299 g_list_free(p->plugins);
1300 p->plugins = NULL;
8c44345a 1301
5297da29 1302 if( p->system_menus ){
8c44345a 1303 do{
5297da29 1304 } while ( g_source_remove_by_user_data( p->system_menus ) );
8c44345a
HJYP
1305 }
1306
16fbda14 1307 gtk_window_group_remove_window( win_grp, GTK_WINDOW( p->topgwin ) );
e2957bd2 1308
4b93d81e
HJYP
1309 if( p->topgwin )
1310 gtk_widget_destroy(p->topgwin);
a52c2257 1311 g_free(p->workarea);
2de71c90 1312 g_free( p->background_file );
5297da29 1313 g_slist_free( p->system_menus );
a52c2257
HJYP
1314 gdk_flush();
1315 XFlush(GDK_DISPLAY());
1316 XSync(GDK_DISPLAY(), True);
8110399f
HJYP
1317
1318 g_free( p->name );
2918994e 1319 g_free(p);
a52c2257
HJYP
1320 RET();
1321}
1322
8110399f
HJYP
1323Panel* panel_new( const char* config_file, const char* config_name )
1324{
1325 char *fp, *pfp; /* point to current position of profile data in memory */
cf701cb7 1326 Panel* panel = NULL;
16fbda14 1327
3e7b8eb7 1328 if( G_LIKELY(config_file) )
cf701cb7 1329 {
3e7b8eb7
HJYP
1330 g_file_get_contents( config_file, &fp, NULL, NULL );
1331 if( fp )
1332 {
9dd114c4 1333 panel = panel_allocate();
3e7b8eb7
HJYP
1334 panel->name = g_strdup( config_name );
1335 pfp = fp;
1336
1337 if (! panel_start( panel, &pfp )) {
1338 ERR( "lxpanel: can't start panel\n");
1339 panel_destroy( panel );
1340 panel = NULL;
1341 }
cf701cb7 1342
3e7b8eb7 1343 g_free( fp );
cf701cb7 1344 }
cf701cb7
HJYP
1345 }
1346 return panel;
8110399f 1347}
a52c2257 1348
0defe4b9 1349static void
a52c2257
HJYP
1350usage()
1351{
e7cb732b
HJYP
1352 g_print(_("lxpanel %s - lightweight GTK2+ panel for UNIX desktops\n"), version);
1353 g_print(_("Command line options:\n"));
1354 g_print(_(" --help -- print this help and exit\n"));
1355 g_print(_(" --version -- print version and exit\n"));
1356 g_print(_(" --log <number> -- set log level 0-5. 0 - none 5 - chatty\n"));
2918994e 1357// g_print(_(" --configure -- launch configuration utility\n"));
e7cb732b
HJYP
1358 g_print(_(" --profile name -- use specified profile\n"));
1359 g_print("\n");
1360 g_print(_(" -h -- same as --help\n"));
1361 g_print(_(" -p -- same as --profile\n"));
1362 g_print(_(" -v -- same as --version\n"));
2918994e 1363 // g_print(_(" -C -- same as --configure\n"));
b37c9aae 1364 g_print(_("\nVisit http://lxde.org/ for detail.\n\n"));
a52c2257
HJYP
1365}
1366
2918994e 1367int panel_handle_x_error(Display * d, XErrorEvent * ev)
a52c2257
HJYP
1368{
1369 char buf[256];
1370
a52c2257
HJYP
1371 if (log_level >= LOG_WARN) {
1372 XGetErrorText(GDK_DISPLAY(), ev->error_code, buf, 256);
1373 LOG(LOG_WARN, "lxpanel : X error: %s\n", buf);
1374 }
2918994e 1375 return 0; /* Ignored */
1376}
1377
1378int panel_handle_x_error_swallow_BadWindow_BadDrawable(Display * d, XErrorEvent * ev)
1379{
1380 if ((ev->error_code != BadWindow) && (ev->error_code != BadDrawable))
1381 panel_handle_x_error(d, ev);
1382 return 0; /* Ignored */
a52c2257
HJYP
1383}
1384
e68b47dc
JH
1385/* Lightweight lock related functions - X clipboard hacks */
1386
1387#define CLIPBOARD_NAME "LXPANEL_SELECTION"
1388
1389/*
1390 * clipboard_get_func - dummy get_func for gtk_clipboard_set_with_data ()
1391 */
1392static void
1393clipboard_get_func(
1394 GtkClipboard *clipboard G_GNUC_UNUSED,
1395 GtkSelectionData *selection_data G_GNUC_UNUSED,
1396 guint info G_GNUC_UNUSED,
1397 gpointer user_data_or_owner G_GNUC_UNUSED)
1398{
1399}
1400
1401/*
1402 * clipboard_clear_func - dummy clear_func for gtk_clipboard_set_with_data ()
1403 */
1404static void clipboard_clear_func(
1405 GtkClipboard *clipboard G_GNUC_UNUSED,
1406 gpointer user_data_or_owner G_GNUC_UNUSED)
1407{
1408}
1409
1410/*
1411 * Lightweight version for checking single instance.
1412 * Try and get the CLIPBOARD_NAME clipboard instead of using file manipulation.
1413 *
1414 * Returns TRUE if successfully retrieved and FALSE otherwise.
1415 */
16fb8c2e 1416static gboolean check_main_lock()
e68b47dc
JH
1417{
1418 static const GtkTargetEntry targets[] = { { CLIPBOARD_NAME, 0, 0 } };
1419 gboolean retval = FALSE;
1420 GtkClipboard *clipboard;
1421 Atom atom;
1422
1423 atom = gdk_x11_get_xatom_by_name(CLIPBOARD_NAME);
1424
1425 XGrabServer(GDK_DISPLAY());
1426
1427 if (XGetSelectionOwner(GDK_DISPLAY(), atom) != None)
1428 goto out;
1429
1430 clipboard = gtk_clipboard_get(gdk_atom_intern(CLIPBOARD_NAME, FALSE));
1431
1432 if (gtk_clipboard_set_with_data(clipboard, targets,
1433 G_N_ELEMENTS (targets),
1434 clipboard_get_func,
1435 clipboard_clear_func, NULL))
1436 retval = TRUE;
1437
1438out:
1439 XUngrabServer (GDK_DISPLAY ());
1440 gdk_flush ();
1441
1442 return retval;
1443}
1444#undef CLIPBOARD_NAME
1445
8110399f
HJYP
1446static gboolean start_all_panels( )
1447{
cf701cb7 1448 gboolean is_global;
4b93d81e 1449 for( is_global = 0; ! all_panels && is_global < 2; ++is_global )
cf701cb7
HJYP
1450 {
1451 char* panel_dir = get_config_file( cprofile, "panels", is_global );
1452 GDir* dir = g_dir_open( panel_dir, 0, NULL );
e3b89f43 1453 const gchar* name;
cf701cb7
HJYP
1454
1455 if( ! dir )
1456 {
1457 g_free( panel_dir );
1458 continue;
1459 }
1460
547ece89 1461 while((name = g_dir_read_name(dir)) != NULL)
cf701cb7
HJYP
1462 {
1463 char* panel_config = g_build_filename( panel_dir, name, NULL );
2918994e 1464 if (strchr(panel_config, '~') == NULL) /* Skip editor backup files in case user has hand edited in this directory */
1465 {
1466 Panel* panel = panel_new( panel_config, name );
1467 if( panel )
1468 all_panels = g_slist_prepend( all_panels, panel );
1469 }
cf701cb7
HJYP
1470 g_free( panel_config );
1471 }
1472 g_dir_close( dir );
1473 g_free( panel_dir );
1474 }
1475 return all_panels != NULL;
8110399f
HJYP
1476}
1477
cf701cb7
HJYP
1478void load_global_config();
1479void free_global_config();
1480
8110399f 1481int main(int argc, char *argv[], char *env[])
a52c2257
HJYP
1482{
1483 int i;
16fbda14 1484 const char* session_name;
f277dbb7 1485
a52c2257 1486 setlocale(LC_CTYPE, "");
f277dbb7 1487
1d434622
HJYP
1488 g_thread_init(NULL);
1489 gdk_threads_init();
1490
a52c2257
HJYP
1491 gtk_init(&argc, &argv);
1492
1493#ifdef ENABLE_NLS
1494 bindtextdomain ( GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR );
1495 bind_textdomain_codeset ( GETTEXT_PACKAGE, "UTF-8" );
1496 textdomain ( GETTEXT_PACKAGE );
1497#endif
1498
1499 XSetLocaleModifiers("");
2918994e 1500 XSetErrorHandler((XErrorHandler) panel_handle_x_error);
8110399f 1501
a52c2257 1502 resolve_atoms();
8110399f 1503
95095259
HJYP
1504 session_name = g_getenv("DESKTOP_SESSION");
1505 is_in_lxde = session_name && (0 == strcmp(session_name, "LXDE"));
1506
a52c2257
HJYP
1507 for (i = 1; i < argc; i++) {
1508 if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
1509 usage();
1510 exit(0);
1511 } else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) {
1512 printf("lxpanel %s\n", version);
1513 exit(0);
1514 } else if (!strcmp(argv[i], "--log")) {
1515 i++;
1516 if (i == argc) {
1517 ERR( "lxpanel: missing log level\n");
1518 usage();
1519 exit(1);
1520 } else {
1521 log_level = atoi(argv[i]);
1522 }
1523 } else if (!strcmp(argv[i], "--configure") || !strcmp(argv[i], "-C")) {
1524 config = 1;
1525 } else if (!strcmp(argv[i], "--profile") || !strcmp(argv[i], "-p")) {
1526 i++;
1527 if (i == argc) {
1528 ERR( "lxpanel: missing profile name\n");
1529 usage();
1530 exit(1);
1531 } else {
1532 cprofile = g_strdup(argv[i]);
1533 }
1534 } else {
1535 printf("lxpanel: unknown option - %s\n", argv[i]);
1536 usage();
1537 exit(1);
1538 }
1539 }
f277dbb7 1540
8110399f 1541 /* Check for duplicated lxpanel instances */
e68b47dc 1542 if (!check_main_lock() && !config) {
e7a42ecf 1543 printf("There is already an instance of LXPanel. Now to exit\n");
e68b47dc
JH
1544 exit(1);
1545 }
1546
f277dbb7
HJYP
1547 /* Add our own icons to the search path of icon theme */
1548 gtk_icon_theme_append_search_path( gtk_icon_theme_get_default(),
1549 PACKAGE_DATA_DIR "/lxpanel/images" );
1550
cf701cb7 1551 fbev = fb_ev_new();
e2957bd2 1552 win_grp = gtk_window_group_new();
22242ed4 1553
f7cb330e
HJYP
1554restart:
1555 is_restarting = FALSE;
1556
cf701cb7
HJYP
1557 load_global_config();
1558
1d9dc649
HJYP
1559 /* NOTE: StructureNotifyMask is required by XRandR
1560 * See init_randr_support() in gdkscreen-x11.c of gtk+ for detail.
1561 */
1562 XSelectInput (GDK_DISPLAY(), GDK_ROOT_WINDOW(), StructureNotifyMask|SubstructureNotifyMask|PropertyChangeMask);
cf701cb7 1563 gdk_window_add_filter(gdk_get_default_root_window (), (GdkFilterFunc)panel_event_filter, NULL);
8110399f 1564
cf701cb7
HJYP
1565 if( G_UNLIKELY( ! start_all_panels() ) )
1566 g_warning( "Config files are not found.\n" );
8110399f
HJYP
1567/*
1568 * FIXME: configure??
6a6ad54e
HJYP
1569 if (config)
1570 configure();
8110399f 1571*/
6a6ad54e 1572 gtk_main();
8110399f 1573
cf701cb7
HJYP
1574 XSelectInput (GDK_DISPLAY(), GDK_ROOT_WINDOW(), NoEventMask);
1575 gdk_window_remove_filter(gdk_get_default_root_window (), (GdkFilterFunc)panel_event_filter, NULL);
1576
8110399f
HJYP
1577 /* destroy all panels */
1578 g_slist_foreach( all_panels, (GFunc) panel_destroy, NULL );
2a26c0d8
HJYP
1579 g_slist_free( all_panels );
1580 all_panels = NULL;
6a6ad54e 1581 g_free( cfgfile );
5541b8d2 1582
cf701cb7
HJYP
1583 free_global_config();
1584
f7cb330e
HJYP
1585 if( is_restarting )
1586 goto restart;
1587
e2957bd2 1588 g_object_unref(win_grp);
22242ed4
HJYP
1589 g_object_unref(fbev);
1590
5541b8d2 1591 return 0;
a52c2257 1592}