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