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