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