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