Initial import.
[lxde/lxpanel.git] / src / panel.c
CommitLineData
a52c2257
HJYP
1#ifdef HAVE_CONFIG_H
2#include "config.h"
3#endif
4
5#include <stdlib.h>
6#include <stdio.h>
7#include <sys/types.h>
8#include <sys/stat.h>
9#include <unistd.h>
10#include <errno.h>
11#include <locale.h>
12#include <string.h>
13#include <signal.h>
14
15#include "plugin.h"
16#include "panel.h"
17#include "misc.h"
18#include "bg.h"
19#include "gtkbgbox.h"
20
21static gchar *cfgfile = NULL;
22static gchar version[] = VERSION;
23gchar *cprofile = "default";
24
25int config = 0;
26FbEv *fbev;
27
28//#define DEBUG
29#include "dbg.h"
30
31int log_level;
32
33FILE *pconf; // plugin part of profile file
34
35panel *p;
36
37
38/****************************************************
39 * panel's handlers for WM events *
40 ****************************************************/
41/*
42static void
43panel_del_wm_strut(panel *p)
44{
45 XDeleteProperty(GDK_DISPLAY(), p->topxwin, a_NET_WM_STRUT);
46 XDeleteProperty(GDK_DISPLAY(), p->topxwin, a_NET_WM_STRUT_PARTIAL);
47}
48*/
49
50
51static void
52panel_set_wm_strut(panel *p)
53{
54 gulong data[12] = { 0 };
55 int i = 4;
56
57 ENTER;
58 if (!GTK_WIDGET_MAPPED (p->topgwin))
59 return;
60 switch (p->edge) {
61 case EDGE_LEFT:
62 i = 0;
63 data[i] = p->aw;
64 data[4 + i*2] = p->ay;
65 data[5 + i*2] = p->ay + p->ah;
66 break;
67 case EDGE_RIGHT:
68 i = 1;
69 data[i] = p->aw;
70 data[4 + i*2] = p->ay;
71 data[5 + i*2] = p->ay + p->ah;
72 break;
73 case EDGE_TOP:
74 i = 2;
75 data[i] = p->ah;
76 data[4 + i*2] = p->ax;
77 data[5 + i*2] = p->ax + p->aw;
78 break;
79 case EDGE_BOTTOM:
80 i = 3;
81 data[i] = p->ah;
82 data[4 + i*2] = p->ax;
83 data[5 + i*2] = p->ax + p->aw;
84 break;
85 default:
86 ERR("wrong edge %d. strut won't be set\n", p->edge);
87 RET();
88 }
89 DBG("type %d. width %d. from %d to %d\n", i, data[i], data[4 + i*2], data[5 + i*2]);
90
91 /* if wm supports STRUT_PARTIAL it will ignore STRUT */
92 XChangeProperty(GDK_DISPLAY(), p->topxwin, a_NET_WM_STRUT_PARTIAL,
93 XA_CARDINAL, 32, PropModeReplace, (unsigned char *) data, 12);
94 /* old spec, for wms that do not support STRUT_PARTIAL */
95 XChangeProperty(GDK_DISPLAY(), p->topxwin, a_NET_WM_STRUT,
96 XA_CARDINAL, 32, PropModeReplace, (unsigned char *) data, 4);
97
98 RET();
99}
100
101static void
102print_wmdata(panel *p)
103{
104 int i;
105
106 ENTER;
107 RET();
108 DBG("desktop %d/%d\n", p->curdesk, p->desknum);
109 DBG("workarea\n");
110 for (i = 0; i < p->wa_len/4; i++)
111 DBG("(%d, %d) x (%d, %d)\n",
112 p->workarea[4*i + 0],
113 p->workarea[4*i + 1],
114 p->workarea[4*i + 2],
115 p->workarea[4*i + 3]);
116 RET();
117}
118
119
120static GdkFilterReturn
121panel_event_filter(GdkXEvent *xevent, GdkEvent *event, panel *p)
122{
123 Atom at;
124 Window win;
125 XEvent *ev = (XEvent *) xevent;
126
127 ENTER;
128 DBG("win = 0x%x\n", ev->xproperty.window);
129 if (ev->type != PropertyNotify )
130 RET(GDK_FILTER_CONTINUE);
131
132 at = ev->xproperty.atom;
133 win = ev->xproperty.window;
134 DBG("win=%x at=%d\n", win, at);
135 if (win == GDK_ROOT_WINDOW()) {
136 if (at == a_NET_CLIENT_LIST) {
137 DBG("A_NET_CLIENT_LIST\n");
138 fb_ev_trigger(fbev, EV_CLIENT_LIST);
139 } else if (at == a_NET_CURRENT_DESKTOP) {
140 DBG("A_NET_CURRENT_DESKTOP\n");
141 p->curdesk = get_net_current_desktop();
142 fb_ev_trigger(fbev, EV_CURRENT_DESKTOP);
143 } else if (at == a_NET_NUMBER_OF_DESKTOPS) {
144 DBG("A_NET_NUMBER_OF_DESKTOPS\n");
145 p->desknum = get_net_number_of_desktops();
146 fb_ev_trigger(fbev, EV_NUMBER_OF_DESKTOPS);
147 } else if (at == a_NET_DESKTOP_NAMES) {
148 DBG("A_NET_DESKTOP_NAMES\n");
149 fb_ev_trigger(fbev, EV_DESKTOP_NAMES);
150 } else if (at == a_NET_ACTIVE_WINDOW) {
151 DBG("A_NET_ACTIVE_WINDOW\n");
152 fb_ev_trigger(fbev, EV_ACTIVE_WINDOW);
153 }else if (at == a_NET_CLIENT_LIST_STACKING) {
154 DBG("A_NET_CLIENT_LIST_STACKING\n");
155 fb_ev_trigger(fbev, EV_CLIENT_LIST_STACKING);
156 } else if (at == a_XROOTPMAP_ID) {
157 DBG("a_XROOTPMAP_ID\n");
158 if (p->transparent) {
159 fb_bg_notify_changed_bg(p->bg);
160 }
161 } else if (at == a_NET_WORKAREA) {
162 DBG("A_NET_WORKAREA\n");
163 p->workarea = get_xaproperty (GDK_ROOT_WINDOW(), a_NET_WORKAREA, XA_CARDINAL, &p->wa_len);
164 print_wmdata(p);
165 } else
166 RET(GDK_FILTER_CONTINUE);
167 RET(GDK_FILTER_REMOVE);
168 }
169 DBG("non root %x\n", win);
170 RET(GDK_FILTER_CONTINUE);
171}
172
173/****************************************************
174 * panel's handlers for GTK events *
175 ****************************************************/
176
177
178static gint
179panel_delete_event(GtkWidget * widget, GdkEvent * event, gpointer data)
180{
181 ENTER;
182 RET(FALSE);
183}
184
185static gint
186panel_destroy_event(GtkWidget * widget, GdkEvent * event, gpointer data)
187{
188 //panel *p = (panel *) data;
189
190 ENTER;
191 //if (!p->self_destroy)
192 gtk_main_quit();
193 RET(FALSE);
194}
195
196
197static void
198panel_realize(GtkWidget *widget, panel *p)
199{
200 ENTER;
201 RET();
202
203}
204static gint
205panel_size_req(GtkWidget *widget, GtkRequisition *req, panel *p)
206{
207 ENTER;
208 DBG("IN req=(%d, %d)\n", req->width, req->height);
209 if (p->widthtype == WIDTH_REQUEST)
210 p->width = (p->orientation == ORIENT_HORIZ) ? req->width : req->height;
211 if (p->heighttype == HEIGHT_REQUEST)
212 p->height = (p->orientation == ORIENT_HORIZ) ? req->height : req->width;
213 calculate_position(p);
214 req->width = p->aw;
215 req->height = p->ah;
216 DBG("OUT req=(%d, %d)\n", req->width, req->height);
217 RET( TRUE );
218}
219
220static gint
221panel_size_alloc(GtkWidget *widget, GtkAllocation *a, panel *p)
222{
223 ENTER;
224 DBG("installed alloc: size (%d, %d). pos (%d, %d)\n", aa->width, aa->height, aa->x, aa->y);
225 DBG("suggested alloc: size (%d, %d). pos (%d, %d)\n", a->width, a->height, a->x, a->y);
226 DBG("prev pref alloc: size (%d, %d). pos (%d, %d)\n", p->aw, p->ah, p->ax, p->ay);
227 if (p->widthtype == WIDTH_REQUEST)
228 p->width = (p->orientation == ORIENT_HORIZ) ? a->width : a->height;
229 if (p->heighttype == HEIGHT_REQUEST)
230 p->height = (p->orientation == ORIENT_HORIZ) ? a->height : a->width;
231 calculate_position(p);
232 DBG("curr pref alloc: size (%d, %d). pos (%d, %d)\n", p->aw, p->ah, p->ax, p->ay);
233 if (a->width == p->aw && a->height == p->ah && a->x == p->ax && a->y == p ->ay) {
234 DBG("actual coords eq to preffered. just returning\n");
235 RET(TRUE);
236 }
237
238 gtk_window_move(GTK_WINDOW(p->topgwin), p->ax, p->ay);
239 DBG("moving to %d %d\n", p->ax, p->ay);
240 if (p->setstrut)
241 panel_set_wm_strut(p);
242 RET(TRUE);
243}
244
245
246static gboolean
247panel_configure_event (GtkWidget *widget, GdkEventConfigure *e, panel *p)
248{
249 ENTER;
250 if (e->width == p->cw && e->height == p->ch && e->x == p->cx && e->y == p->cy)
251 RET(TRUE);
252 p->cw = e->width;
253 p->ch = e->height;
254 p->cx = e->x;
255 p->cy = e->y;
256 DBG("here\n");
257 if (p->transparent)
258 fb_bg_notify_changed_bg(p->bg);
259 DBG("here\n");
260 DBG("geom: size (%d, %d). pos (%d, %d)\n", e->width, e->height, e->x, e->y);
261 RET(FALSE);
262
263}
264
265
266/****************************************************
267 * panel creation *
268 ****************************************************/
269static void
270make_round_corners(panel *p)
271{
272 GtkWidget *b1, *b2, *img;
273 GtkWidget *(*box_new) (gboolean, gint);
274 void (*box_pack)(GtkBox *, GtkWidget *, gboolean, gboolean, guint);
275 gchar *s1, *s2;
276#define IMGPREFIX PACKAGE_DATA_DIR "/lxpanel/images/"
277
278 ENTER;
279 if (p->edge == EDGE_TOP) {
280 s1 = IMGPREFIX "top-left.xpm";
281 s2 = IMGPREFIX "top-right.xpm";
282 } else if (p->edge == EDGE_BOTTOM) {
283 s1 = IMGPREFIX "bottom-left.xpm";
284 s2 = IMGPREFIX "bottom-right.xpm";
285 } else if (p->edge == EDGE_LEFT) {
286 s1 = IMGPREFIX "top-left.xpm";
287 s2 = IMGPREFIX "bottom-left.xpm";
288 } else if (p->edge == EDGE_RIGHT) {
289 s1 = IMGPREFIX "top-right.xpm";
290 s2 = IMGPREFIX "bottom-right.xpm";
291 } else
292 RET();
293
294 box_new = (p->orientation == ORIENT_HORIZ) ? gtk_vbox_new : gtk_hbox_new;
295 b1 = box_new(0, FALSE);
296 gtk_widget_show(b1);
297 b2 = box_new(0, FALSE);
298 gtk_widget_show(b2);
299
300 box_pack = (p->edge == EDGE_TOP || p->edge == EDGE_LEFT) ?
301 gtk_box_pack_start : gtk_box_pack_end;
302
303 img = gtk_image_new_from_file(s1);
304 gtk_widget_show(img);
305 box_pack(GTK_BOX(b1), img, FALSE, FALSE, 0);
306 img = gtk_image_new_from_file(s2);
307 gtk_widget_show(img);
308 box_pack(GTK_BOX(b2), img, FALSE, FALSE, 0);
309 gtk_box_pack_start(GTK_BOX(p->lbox), b1, FALSE, FALSE, 0);
310 gtk_box_pack_end(GTK_BOX(p->lbox), b2, FALSE, FALSE, 0);
311 RET();
312}
313
314void
315panel_start_gui(panel *p)
316{
317 Atom state[3];
318 XWMHints wmhints;
319 guint32 val;
320
321
322 ENTER;
323
324 // main toplevel window
325 p->topgwin = gtk_window_new(GTK_WINDOW_TOPLEVEL);
326 gtk_container_set_border_width(GTK_CONTAINER(p->topgwin), 0);
327 gtk_window_set_resizable(GTK_WINDOW(p->topgwin), FALSE);
328 gtk_window_set_wmclass(GTK_WINDOW(p->topgwin), "panel", "lxpanel");
329 gtk_window_set_title(GTK_WINDOW(p->topgwin), "panel");
330 gtk_window_set_position(GTK_WINDOW(p->topgwin), GTK_WIN_POS_NONE);
331 gtk_window_set_decorated(GTK_WINDOW(p->topgwin), FALSE);
332
333 g_signal_connect(G_OBJECT(p->topgwin), "delete-event",
334 G_CALLBACK(panel_delete_event), p);
335 g_signal_connect(G_OBJECT(p->topgwin), "destroy-event",
336 G_CALLBACK(panel_destroy_event), p);
337 g_signal_connect (G_OBJECT (p->topgwin), "size-request",
338 (GCallback) panel_size_req, p);
339 g_signal_connect (G_OBJECT (p->topgwin), "size-allocate",
340 (GCallback) panel_size_alloc, p);
341 g_signal_connect (G_OBJECT (p->topgwin), "configure-event",
342 (GCallback) panel_configure_event, p);
343 g_signal_connect (G_OBJECT (p->topgwin), "realize",
344 (GCallback) panel_realize, p);
345
346 gtk_widget_realize(p->topgwin);
347 //gdk_window_set_decorations(p->topgwin->window, 0);
348 gtk_widget_set_app_paintable(p->topgwin, TRUE);
349
350 // background box all over toplevel
351 p->bbox = gtk_bgbox_new();
352 gtk_container_add(GTK_CONTAINER(p->topgwin), p->bbox);
353 gtk_widget_show(p->bbox);
354 gtk_container_set_border_width(GTK_CONTAINER(p->bbox), 0);
355 if (p->transparent) {
356 p->bg = fb_bg_get_for_display();
357 gtk_bgbox_set_background(p->bbox, BG_ROOT, p->tintcolor, p->alpha);
358 }
359
360 // main layout manager as a single child of background widget box
361 p->lbox = p->my_box_new(FALSE, 0);
362 gtk_container_set_border_width(GTK_CONTAINER(p->lbox), 0);
363 gtk_container_add(GTK_CONTAINER(p->bbox), p->lbox);
364 gtk_widget_show(p->lbox);
365 if (p->round_corners)
366 make_round_corners(p);
367
368 p->box = p->my_box_new(FALSE, p->spacing);
369 gtk_container_set_border_width(GTK_CONTAINER(p->box), 0);
370 gtk_box_pack_start(GTK_BOX(p->lbox), p->box, TRUE, TRUE, 0);
371 gtk_widget_show(p->box);
372
373 p->topxwin = GDK_WINDOW_XWINDOW(GTK_WIDGET(p->topgwin)->window);
374 DBG("topxwin = %x\n", p->topxwin);
375
376 /* the settings that should be done before window is mapped */
377 wmhints.flags = InputHint;
378 wmhints.input = 0;
379 XSetWMHints (GDK_DISPLAY(), p->topxwin, &wmhints);
380#define WIN_HINTS_SKIP_FOCUS (1<<0) /* "alt-tab" skips this win */
381 val = WIN_HINTS_SKIP_FOCUS;
382 XChangeProperty(GDK_DISPLAY(), p->topxwin,
383 XInternAtom(GDK_DISPLAY(), "_WIN_HINTS", False), XA_CARDINAL, 32,
384 PropModeReplace, (unsigned char *) &val, 1);
385
386 if (p->setdocktype) {
387 state[0] = a_NET_WM_WINDOW_TYPE_DOCK;
388 XChangeProperty(GDK_DISPLAY(), p->topxwin, a_NET_WM_WINDOW_TYPE, XA_ATOM,
389 32, PropModeReplace, (unsigned char *) state, 1);
390 }
391
392 /* window mapping point */
393 gtk_widget_show_all(p->topgwin);
394
395 /* the settings that should be done after window is mapped */
396
397 /* send it to running wm */
398 Xclimsg(p->topxwin, a_NET_WM_DESKTOP, 0xFFFFFFFF, 0, 0, 0, 0);
399 /* and assign it ourself just for case when wm is not running */
400 val = 0xFFFFFFFF;
401 XChangeProperty(GDK_DISPLAY(), p->topxwin, a_NET_WM_DESKTOP, XA_CARDINAL, 32,
402 PropModeReplace, (unsigned char *) &val, 1);
403
404 state[0] = a_NET_WM_STATE_SKIP_PAGER;
405 state[1] = a_NET_WM_STATE_SKIP_TASKBAR;
406 state[2] = a_NET_WM_STATE_STICKY;
407 XChangeProperty(GDK_DISPLAY(), p->topxwin, a_NET_WM_STATE, XA_ATOM,
408 32, PropModeReplace, (unsigned char *) state, 3);
409
410 XSelectInput (GDK_DISPLAY(), GDK_ROOT_WINDOW(), PropertyChangeMask);
411 gdk_window_add_filter(gdk_get_default_root_window (), (GdkFilterFunc)panel_event_filter, p);
412
413 calculate_position(p);
414 gdk_window_move_resize(p->topgwin->window, p->ax, p->ay, p->aw, p->ah);
415 if (p->setstrut)
416 panel_set_wm_strut(p);
417
418 RET();
419}
420
421static int
422panel_parse_global(panel *p, FILE *fp)
423{
424 line s;
425 s.len = 256;
426
427 ENTER;
428 while (get_line(fp, &s) != LINE_NONE) {
429 if (s.type == LINE_VAR) {
430 if (!g_ascii_strcasecmp(s.t[0], "edge")) {
431 p->edge = str2num(edge_pair, s.t[1], EDGE_NONE);
432 } else if (!g_ascii_strcasecmp(s.t[0], "allign")) {
433 p->allign = str2num(allign_pair, s.t[1], ALLIGN_NONE);
434 } else if (!g_ascii_strcasecmp(s.t[0], "margin")) {
435 p->margin = atoi(s.t[1]);
436 } else if (!g_ascii_strcasecmp(s.t[0], "widthtype")) {
437 p->widthtype = str2num(width_pair, s.t[1], WIDTH_NONE);
438 } else if (!g_ascii_strcasecmp(s.t[0], "width")) {
439 p->width = atoi(s.t[1]);
440 } else if (!g_ascii_strcasecmp(s.t[0], "heighttype")) {
441 p->heighttype = str2num(height_pair, s.t[1], HEIGHT_NONE);
442 } else if (!g_ascii_strcasecmp(s.t[0], "height")) {
443 p->height = atoi(s.t[1]);
444 } else if (!g_ascii_strcasecmp(s.t[0], "spacing")) {
445 p->spacing = atoi(s.t[1]);
446 } else if (!g_ascii_strcasecmp(s.t[0], "SetDockType")) {
447 p->setdocktype = str2num(bool_pair, s.t[1], 0);
448 } else if (!g_ascii_strcasecmp(s.t[0], "SetPartialStrut")) {
449 p->setstrut = str2num(bool_pair, s.t[1], 0);
450 } else if (!g_ascii_strcasecmp(s.t[0], "RoundCorners")) {
451 p->round_corners = str2num(bool_pair, s.t[1], 0);
452 } else if (!g_ascii_strcasecmp(s.t[0], "Transparent")) {
453 p->transparent = str2num(bool_pair, s.t[1], 0);
454 } else if (!g_ascii_strcasecmp(s.t[0], "Alpha")) {
455 p->alpha = atoi(s.t[1]);
456 if (p->alpha > 255)
457 p->alpha = 255;
458 } else if (!g_ascii_strcasecmp(s.t[0], "TintColor")) {
459 if (!gdk_color_parse (s.t[1], &p->gtintcolor))
460 gdk_color_parse ("white", &p->gtintcolor);
461 p->tintcolor = gcolor2rgb24(&p->gtintcolor);
462 DBG("tintcolor=%x\n", p->tintcolor);
463 } else {
464 ERR( "lxpanel: %s - unknown var in Global section\n", s.t[0]);
465 RET(0);
466 }
467 } else if (s.type == LINE_BLOCK_END) {
468 break;
469 } else {
470 ERR( "lxpanel: illegal in this context %s\n", s.str);
471 RET(0);
472 }
473 }
474 p->orientation = (p->edge == EDGE_TOP || p->edge == EDGE_BOTTOM)
475 ? ORIENT_HORIZ : ORIENT_VERT;
476 if (p->orientation == ORIENT_HORIZ) {
477 p->my_box_new = gtk_hbox_new;
478 p->my_separator_new = gtk_vseparator_new;
479 } else {
480 p->my_box_new = gtk_vbox_new;
481 p->my_separator_new = gtk_hseparator_new;
482 }
483 if (p->width < 0)
484 p->width = 100;
485 if (p->widthtype == WIDTH_PERCENT && p->width > 100)
486 p->width = 100;
487 p->heighttype = HEIGHT_PIXEL;
488 if (p->heighttype == HEIGHT_PIXEL) {
489 if (p->height < PANEL_HEIGHT_MIN)
490 p->height = PANEL_HEIGHT_MIN;
491 else if (p->height > PANEL_HEIGHT_MAX)
492 p->height = PANEL_HEIGHT_MAX;
493 }
494 p->curdesk = get_net_current_desktop();
495 p->desknum = get_net_number_of_desktops();
496 p->workarea = get_xaproperty (GDK_ROOT_WINDOW(), a_NET_WORKAREA, XA_CARDINAL, &p->wa_len);
497 print_wmdata(p);
498 panel_start_gui(p);
499 RET(1);
500}
501
502static int
503panel_parse_plugin(panel *p, FILE *fp)
504{
505 line s;
506 plugin *plug = NULL;
507 gchar *type = NULL;
508 FILE *tmpfp;
509 int expand , padding, border;
510
511 ENTER;
512 s.len = 256;
513 if (!(tmpfp = tmpfile())) {
514 ERR( "can't open temporary file with tmpfile()\n");
515 RET(0);
516 }
517 border = expand = padding = 0;
518 while (get_line(fp, &s) != LINE_BLOCK_END) {
519 if (s.type == LINE_NONE) {
520 ERR( "lxpanel: bad line %s\n", s.str);
521 goto error;
522 }
523 if (s.type == LINE_VAR) {
524 if (!g_ascii_strcasecmp(s.t[0], "type")) {
525 type = g_strdup(s.t[1]);
526 DBG("plug %s\n", type);
527 } else if (!g_ascii_strcasecmp(s.t[0], "expand"))
528 expand = str2num(bool_pair, s.t[1], 0);
529 else if (!g_ascii_strcasecmp(s.t[0], "padding"))
530 padding = atoi(s.t[1]);
531 else if (!g_ascii_strcasecmp(s.t[0], "border"))
532 border = atoi(s.t[1]);
533 else {
534 ERR( "lxpanel: unknown var %s\n", s.t[0]);
535 goto error;
536 }
537 } else if (s.type == LINE_BLOCK_START) {
538 if (!g_ascii_strcasecmp(s.t[0], "Config")) {
539 int pno = 1;
540 while (pno) {
541 get_line_as_is(fp, &s);
542 if (s.type == LINE_NONE) {
543 ERR( "lxpanel: unexpected eof\n");
544 goto error;
545 } else if (s.type == LINE_BLOCK_START) {
546 pno++;
547 } else if (s.type == LINE_BLOCK_END) {
548 pno--;
549 }
550 fprintf(tmpfp, "%s\n", s.str);
551 }
552 } else {
553 ERR( "lxpanel: unknown block %s\n", s.t[0]);
554 goto error;
555 }
556 } else {
557 ERR( "lxpanel: illegal in this context %s\n", s.str);
558 goto error;
559 }
560 }
561
562 if (!type || !(plug = plugin_load(type))) {
563 ERR( "lxpanel: can't load %s plugin\n", type);
564 goto error;
565 }
566 plug->panel = p;
567 plug->fp = tmpfp;
568 plug->expand = expand;
569 plug->padding = padding;
570 plug->border = border;
571 fprintf(tmpfp, "}\n");
572 fseek(tmpfp, 0, SEEK_SET);
573 DBG("starting\n");
574 if (!plugin_start(plug)) {
575 ERR( "lxpanel: can't start plugin %s\n", type);
576 goto error;
577 }
578 DBG("plug %s\n", type);
579 p->plugins = g_list_append(p->plugins, plug);
580 RET(1);
581
582 error:
583 fclose(tmpfp);
584 g_free(type);
585 if (plug)
586 plugin_put(plug);
587 RET(0);
588
589}
590
591
592int
593panel_start(panel *p, FILE *fp)
594{
595 line s;
596 long pos;
597
598 /* parse global section */
599 ENTER;
600 s.len = 256;
601 memset(p, 0, sizeof(panel));
602 p->allign = ALLIGN_CENTER;
603 p->edge = EDGE_BOTTOM;
604 p->widthtype = WIDTH_PERCENT;
605 p->width = 100;
606 p->heighttype = HEIGHT_PIXEL;
607 p->height = PANEL_HEIGHT_DEFAULT;
608 p->setdocktype = 1;
609 p->setstrut = 1;
610 p->round_corners = 0;
611 p->transparent = 0;
612 p->alpha = 127;
613 p->tintcolor = 0xFFFFFFFF;
614 p->spacing = 0;
615 fbev = fb_ev_new();
616 if ((get_line(fp, &s) != LINE_BLOCK_START) || g_ascii_strcasecmp(s.t[0], "Global")) {
617 ERR( "lxpanel: config file must start from Global section\n");
618 RET(0);
619 }
620 if (!panel_parse_global(p, fp))
621 RET(0);
622
623 if (!(pconf = tmpfile())) {
624 ERR("can't open temporary file\n");
625 RET(0);
626 }
627 pos = ftell(fp);
628 while (get_line_as_is(fp, &s) != LINE_NONE)
629 fprintf(pconf, "%s\n", s.str);
630 fseek(fp, pos, SEEK_SET);
631
632 while (get_line(fp, &s) != LINE_NONE) {
633 if ((s.type != LINE_BLOCK_START) || g_ascii_strcasecmp(s.t[0], "Plugin")) {
634 ERR( "lxpanel: expecting Plugin section\n");
635 RET(0);
636 }
637 if (!panel_parse_plugin(p, fp))
638 RET(0);
639 }
640 gtk_widget_show_all(p->topgwin);
641 print_wmdata(p);
642 RET(1);
643}
644
645static void
646delete_plugin(gpointer data, gpointer udata)
647{
648 ENTER;
649 plugin_stop((plugin *)data);
650 plugin_put((plugin *)data);
651 RET();
652
653}
654
655void panel_stop(panel *p)
656{
657 ENTER;
658
659 g_list_foreach(p->plugins, delete_plugin, NULL);
660 g_list_free(p->plugins);
661 p->plugins = NULL;
662
663 XSelectInput (GDK_DISPLAY(), GDK_ROOT_WINDOW(), NoEventMask);
664 gdk_window_remove_filter(gdk_get_default_root_window (), (GdkFilterFunc)panel_event_filter, p);
665 gtk_widget_destroy(p->topgwin);
666 g_object_unref(fbev);
667 g_free(p->workarea);
668 fclose(pconf);
669 gdk_flush();
670 XFlush(GDK_DISPLAY());
671 XSync(GDK_DISPLAY(), True);
672 RET();
673}
674
675
676void
677usage()
678{
679 ENTER;
680 printf("lxpanel %s - lightweight GTK2+ panel for UNIX desktops\n", version);
681 printf("Command line options:\n");
682 printf(" --help -- print this help and exit\n");
683 printf(" --version -- print version and exit\n");
684 printf(" --log <number> -- set log level 0-5. 0 - none 5 - chatty\n");
685 printf(" --configure -- launch configuration utility\n");
686 printf(" --profile name -- use specified profile\n");
687 printf("\n");
688 printf(" -h -- same as --help\n");
689 printf(" -p -- same as --profile\n");
690 printf(" -v -- same as --version\n");
691 printf(" -C -- same as --configure\n");
692 printf("\nVisit http://lxpanel.sourceforge.net/ for detailed documentation,\n\n");
693}
694
695FILE *
696open_profile(gchar *profile)
697{
698 gchar *fname;
699 FILE *fp;
700
701 ENTER;
702 LOG(LOG_INFO, "loading %s profile\n", profile);
703 fname = g_strdup_printf("%s/.lxpanel/%s", getenv("HOME"), profile);
704 fp = fopen(fname, "r");
705 LOG(LOG_INFO, " %s %s\n", fname, fp ? "ok" : "no");
706 if (fp) {
707 cfgfile = fname;
708 RET(fp);
709 }
710 //ERR("Can't load %s\n", fname);
711 g_free(fname);
712
713 /* check private configuration directory */
714 fname = g_strdup_printf(PACKAGE_DATA_DIR "/lxpanel/%s", profile);
715 fp = fopen(fname, "r");
716 LOG(LOG_INFO, " %s %s\n", fname, fp ? "ok" : "no");
717 if (fp) {
718 cfgfile = fname;
719 RET(fp);
720 }
721 //ERR("Can't load %s\n", fname);
722 g_free(fname);
723 LOG(LOG_ERR, "Can't open '%s' profile\n", profile);
724 RET(NULL);
725}
726
727void
728handle_error(Display * d, XErrorEvent * ev)
729{
730 char buf[256];
731
732 ENTER;
733 if (log_level >= LOG_WARN) {
734 XGetErrorText(GDK_DISPLAY(), ev->error_code, buf, 256);
735 LOG(LOG_WARN, "lxpanel : X error: %s\n", buf);
736 }
737 RET();
738}
739
740static void
741sig_usr(int signum)
742{
743 if (signum != SIGUSR1)
744 return;
745 gtk_main_quit();
746}
747
748int
749main(int argc, char *argv[], char *env[])
750{
751 int i;
752 int quit = 0;
753 void configure();
754 FILE *pfp; /* current profile FP */
755
756 ENTER;
757 //printf("sizeof(gulong)=%d\n", sizeof(gulong));
758 setlocale(LC_CTYPE, "");
759 gtk_init(&argc, &argv);
760
761#ifdef ENABLE_NLS
762 bindtextdomain ( GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR );
763 bind_textdomain_codeset ( GETTEXT_PACKAGE, "UTF-8" );
764 textdomain ( GETTEXT_PACKAGE );
765#endif
766
767 XSetLocaleModifiers("");
768 XSetErrorHandler((XErrorHandler) handle_error);
769 resolve_atoms();
770 for (i = 1; i < argc; i++) {
771 if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
772 usage();
773 exit(0);
774 } else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) {
775 printf("lxpanel %s\n", version);
776 exit(0);
777 } else if (!strcmp(argv[i], "--log")) {
778 i++;
779 if (i == argc) {
780 ERR( "lxpanel: missing log level\n");
781 usage();
782 exit(1);
783 } else {
784 log_level = atoi(argv[i]);
785 }
786 } else if (!strcmp(argv[i], "--configure") || !strcmp(argv[i], "-C")) {
787 config = 1;
788 } else if (!strcmp(argv[i], "--profile") || !strcmp(argv[i], "-p")) {
789 i++;
790 if (i == argc) {
791 ERR( "lxpanel: missing profile name\n");
792 usage();
793 exit(1);
794 } else {
795 cprofile = g_strdup(argv[i]);
796 }
797 } else {
798 printf("lxpanel: unknown option - %s\n", argv[i]);
799 usage();
800 exit(1);
801 }
802 }
803 signal(SIGUSR1, sig_usr);
804 do {
805 if (!(pfp = open_profile(cprofile)))
806 exit(1);
807 p = g_new0(panel, 1);
808 g_return_val_if_fail (p != NULL, 1);
809 if (!panel_start(p, pfp)) {
810 ERR( "lxpanel: can't start panel\n");
811 exit(1);
812 }
813 fclose(pfp);
814 if (config)
815 configure();
816 gtk_main();
817 panel_stop(p);
818 g_free(p);
819 } while (quit == 0);
820
821 exit(0);
822}
823