fixed aclocal to use AC_VERSION.
[lxde/lxpanel.git] / src / panel.c
... / ...
CommitLineData
1/**
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
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>
31#include <glib/gi18n.h>
32#include <gdk/gdkx.h>
33
34#include "plugin.h"
35#include "panel.h"
36#include "misc.h"
37#include "bg.h"
38#include "gtkbgbox.h"
39
40#include "lxpanelctl.h"
41
42static gchar *cfgfile = NULL;
43static gchar version[] = VERSION;
44gchar *cprofile = "default";
45
46static int config = 0;
47FbEv *fbev;
48
49//#define DEBUG
50#include "dbg.h"
51
52int log_level;
53panel *p;
54
55gboolean is_restarting = FALSE;
56
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
70void panel_set_wm_strut(panel *p)
71{
72 gulong data[12] = { 0 };
73 int i = 4;
74
75 ENTER;
76 if (!GTK_WIDGET_MAPPED (p->topgwin))
77 return;
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
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();
114 }
115 DBG("type %d. width %d. from %d to %d\n", i, data[i], data[4 + i*2], data[5 + i*2]);
116
117 /* if wm supports STRUT_PARTIAL it will ignore STRUT */
118 XChangeProperty(GDK_DISPLAY(), p->topxwin, a_NET_WM_STRUT_PARTIAL,
119 XA_CARDINAL, 32, PropModeReplace, (unsigned char *) data, 12);
120 /* old spec, for wms that do not support STRUT_PARTIAL */
121 XChangeProperty(GDK_DISPLAY(), p->topxwin, a_NET_WM_STRUT,
122 XA_CARDINAL, 32, PropModeReplace, (unsigned char *) data, 4);
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
146/* defined in plugins/menu.c */
147gboolean show_system_menu( gpointer system_menu );
148
149/* built-in commands, defined in configurator.c */
150void configure(void);
151void restart(void);
152void gtk_run(void);
153
154static void process_client_msg ( panel *p, XClientMessageEvent* ev )
155{
156 int cmd = ev->data.b[0];
157 switch( cmd )
158 {
159 case LXPANEL_CMD_SYS_MENU:
160 if( p->system_menus )
161 {
162 /* show_system_menu( p->system_menus->data ); */
163 /* FIXME: I've no idea why this doesn't work without timeout
164 under some WMs, like icewm. */
165 g_timeout_add( 200, (GSourceFunc)show_system_menu,
166 p->system_menus->data );
167 }
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
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);
193 if (ev->type != PropertyNotify ) {
194 /* private client message from lxpanelctl */
195 if( ev->type == ClientMessage && ev->xproperty.atom == a_LXPANEL_CMD )
196 {
197 process_client_msg( p, (XClientMessageEvent*)ev );
198 }
199 RET(GDK_FILTER_CONTINUE);
200 }
201
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");
233 g_free( p->workarea );
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
248
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
261 ENTER;
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);
311 panel_set_wm_strut(p);
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);
332
333}
334
335
336/****************************************************
337 * panel creation *
338 ****************************************************/
339static void
340make_round_corners(panel *p)
341{
342 /* FIXME: This should be re-written with shape extension of X11 */
343#if 0
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/"
349
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();
365
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;
374
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);
383 RET();
384#endif
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 }
398}
399
400static void
401panel_start_gui(panel *p)
402{
403 Atom state[3];
404 XWMHints wmhints;
405 guint32 val;
406
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);
417
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);
430
431 gtk_widget_realize(p->topgwin);
432 //gdk_window_set_decorations(p->topgwin->window, 0);
433 gtk_widget_set_app_paintable(p->topgwin, TRUE);
434
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();
442 gtk_bgbox_set_background(p->bbox, BG_ROOT, p->tintcolor, p->alpha);
443 }
444
445 // main layout manager as a single child of background widget box
446 p->box = p->my_box_new(FALSE, 0);
447 gtk_container_set_border_width(GTK_CONTAINER(p->box), 0);
448 gtk_container_add(GTK_CONTAINER(p->bbox), p->box);
449 gtk_widget_show(p->box);
450 if (p->round_corners)
451 make_round_corners(p);
452
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;
459 XSetWMHints (GDK_DISPLAY(), p->topxwin, &wmhints);
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
466 panel_set_dock_type(p);
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
486 XSelectInput (GDK_DISPLAY(), GDK_ROOT_WINDOW(), SubstructureNotifyMask|PropertyChangeMask);
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);
491 panel_set_wm_strut(p);
492
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
501 RET();
502}
503
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 ) {
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) );
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
538static int
539panel_parse_global(panel *p, char **fp)
540{
541 line s;
542 s.len = 256;
543
544 ENTER;
545 while (lxpanel_get_line(fp, &s) != LINE_NONE) {
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);
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] );
584 } else if( !g_ascii_strcasecmp(s.t[0], "LogoutCommand") ) {
585 p->logout_command = g_strdup( s.t[1] );
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 }
597 panel_set_orientation( p );
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);
613
614 panel_start_gui(p);
615 RET(1);
616}
617
618static int
619panel_parse_plugin(panel *p, char **fp)
620{
621 line s;
622 plugin *plug = NULL;
623 gchar *type = NULL;
624 int expand , padding, border;
625 char* pconfig = NULL;
626
627 ENTER;
628 s.len = 256;
629 border = expand = padding = 0;
630 while (lxpanel_get_line(fp, &s) != LINE_BLOCK_END) {
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")) {
651 pconfig = *fp;
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--;
662 }
663 }
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 }
673
674 if (!type || !(plug = plugin_load(type))) {
675 ERR( "lxpanel: can't load %s plugin\n", type);
676 goto error;
677 }
678
679 plug->panel = p;
680 plug->expand = expand;
681 plug->padding = padding;
682 plug->border = border;
683 DBG("starting\n");
684 if (!plugin_start(plug, pconfig ? &pconfig : NULL)) {
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);
690
691 g_free( type );
692 RET(1);
693
694 error:
695 g_free(type);
696 if (plug)
697 plugin_put(plug);
698 RET(0);
699}
700
701
702static int
703panel_start( panel *p, char **fp )
704{
705 line s;
706
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();
725 if ((lxpanel_get_line(fp, &s) != LINE_BLOCK_START) || g_ascii_strcasecmp(s.t[0], "Global")) {
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
732 while (lxpanel_get_line(fp, &s) != LINE_NONE) {
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 }
737 if (!panel_parse_plugin(p, fp))
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();
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;
761
762 if( p->system_menus ){
763 do{
764 } while ( g_source_remove_by_user_data( p->system_menus ) );
765 }
766
767 g_object_unref( p->tooltips );
768
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);
774 g_free( p->file_manager );
775 g_free( p->terminal );
776 g_free( p->logout_command );
777 g_slist_free( p->system_menus );
778 gdk_flush();
779 XFlush(GDK_DISPLAY());
780 XSync(GDK_DISPLAY(), True);
781 RET();
782}
783
784
785static void
786usage()
787{
788 ENTER;
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"));
802}
803
804static char*
805load_profile(gchar *profile)
806{
807 gchar *fname;
808 char* ret;
809
810 ENTER;
811 LOG(LOG_INFO, "loading %s profile\n", profile);
812 fname = g_strdup_printf("%s/.lxpanel/%s", getenv("HOME"), profile);
813 g_file_get_contents( fname, &ret, NULL, NULL );
814 if (ret) {
815 cfgfile = fname;
816 RET(ret);
817 }
818 //ERR("Can't load %s\n", fname);
819 g_free(fname);
820
821 /* check private configuration directory */
822 fname = g_strdup_printf(PACKAGE_DATA_DIR "/lxpanel/%s", profile);
823 g_file_get_contents( fname, &ret, NULL, NULL );
824 if (ret) {
825 cfgfile = fname;
826 RET(ret);
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
834static void
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
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 */
878static gboolean check_main_lock()
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
908int
909main(int argc, char *argv[], char *env[])
910{
911 int i;
912 void configure();
913 char *fp, *pfp; /* point to current position of profile data in memory */
914
915 ENTER;
916 //printf("sizeof(gulong)=%d\n", sizeof(gulong));
917 setlocale(LC_CTYPE, "");
918
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 }
963
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
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
974restart:
975 is_restarting = FALSE;
976
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);
984 }
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);
993
994 if( is_restarting )
995 goto restart;
996
997 return 0;
998}
999