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