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