add disable interface function to popup-menu for netstat plugin.
[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 334
84fc1d55 335/*
a52c2257 336static void
22242ed4 337panel_realize(GtkWidget *widget, Panel *p)
a52c2257 338{
a52c2257
HJYP
339
340}
84fc1d55
HJYP
341*/
342
343static gboolean delay_update_background( Panel* p )
344{
345 panel_update_background( p );
346 return FALSE;
347}
348
349static void
350panel_style_set(GtkWidget *widget, GtkStyle* prev, Panel *p)
351{
352 if( GTK_WIDGET_REALIZED( widget ) )
353 g_idle_add( delay_update_background, p );
354}
4542c20d 355
a52c2257 356static gint
22242ed4 357panel_size_req(GtkWidget *widget, GtkRequisition *req, Panel *p)
a52c2257
HJYP
358{
359 ENTER;
4542c20d 360
a52c2257
HJYP
361 if (p->widthtype == WIDTH_REQUEST)
362 p->width = (p->orientation == ORIENT_HORIZ) ? req->width : req->height;
363 if (p->heighttype == HEIGHT_REQUEST)
364 p->height = (p->orientation == ORIENT_HORIZ) ? req->height : req->width;
365 calculate_position(p);
366 req->width = p->aw;
367 req->height = p->ah;
4542c20d 368
a52c2257
HJYP
369 RET( TRUE );
370}
371
372static gint
22242ed4 373panel_size_alloc(GtkWidget *widget, GtkAllocation *a, Panel *p)
a52c2257
HJYP
374{
375 ENTER;
a52c2257
HJYP
376 if (p->widthtype == WIDTH_REQUEST)
377 p->width = (p->orientation == ORIENT_HORIZ) ? a->width : a->height;
378 if (p->heighttype == HEIGHT_REQUEST)
379 p->height = (p->orientation == ORIENT_HORIZ) ? a->height : a->width;
380 calculate_position(p);
4542c20d 381
a52c2257 382 if (a->width == p->aw && a->height == p->ah && a->x == p->ax && a->y == p ->ay) {
a52c2257
HJYP
383 RET(TRUE);
384 }
385
386 gtk_window_move(GTK_WINDOW(p->topgwin), p->ax, p->ay);
bee4c26e 387 panel_set_wm_strut(p);
a52c2257
HJYP
388 RET(TRUE);
389}
390
391
392static gboolean
22242ed4 393panel_configure_event (GtkWidget *widget, GdkEventConfigure *e, Panel *p)
a52c2257
HJYP
394{
395 ENTER;
396 if (e->width == p->cw && e->height == p->ch && e->x == p->cx && e->y == p->cy)
397 RET(TRUE);
398 p->cw = e->width;
399 p->ch = e->height;
400 p->cx = e->x;
401 p->cy = e->y;
4542c20d 402
a52c2257
HJYP
403 if (p->transparent)
404 fb_bg_notify_changed_bg(p->bg);
bee4c26e 405
4542c20d 406 RET(FALSE);
a52c2257
HJYP
407}
408
409
410/****************************************************
411 * panel creation *
412 ****************************************************/
413static void
22242ed4 414make_round_corners(Panel *p)
a52c2257 415{
a97d06a6 416 /* FIXME: This should be re-written with shape extension of X11 */
4542c20d 417 /* gdk_window_shape_combine_mask() can be used */
bee4c26e
HJYP
418}
419
22242ed4 420void panel_set_dock_type(Panel *p)
bee4c26e
HJYP
421{
422 if (p->setdocktype) {
423 Atom state = a_NET_WM_WINDOW_TYPE_DOCK;
424 XChangeProperty(GDK_DISPLAY(), p->topxwin,
425 a_NET_WM_WINDOW_TYPE, XA_ATOM, 32,
426 PropModeReplace, (unsigned char *) &state, 1);
427 }
428 else {
429 XDeleteProperty( GDK_DISPLAY(), p->topxwin, a_NET_WM_WINDOW_TYPE );
430 }
a52c2257
HJYP
431}
432
0defe4b9 433static void
22242ed4 434panel_start_gui(Panel *p)
a52c2257
HJYP
435{
436 Atom state[3];
437 XWMHints wmhints;
438 guint32 val;
6db11841 439
a52c2257
HJYP
440 ENTER;
441
442 // main toplevel window
443 p->topgwin = gtk_window_new(GTK_WINDOW_TOPLEVEL);
444 gtk_container_set_border_width(GTK_CONTAINER(p->topgwin), 0);
445 gtk_window_set_resizable(GTK_WINDOW(p->topgwin), FALSE);
446 gtk_window_set_wmclass(GTK_WINDOW(p->topgwin), "panel", "lxpanel");
447 gtk_window_set_title(GTK_WINDOW(p->topgwin), "panel");
448 gtk_window_set_position(GTK_WINDOW(p->topgwin), GTK_WIN_POS_NONE);
449 gtk_window_set_decorated(GTK_WINDOW(p->topgwin), FALSE);
77886b88 450
a52c2257
HJYP
451 g_signal_connect(G_OBJECT(p->topgwin), "delete-event",
452 G_CALLBACK(panel_delete_event), p);
453 g_signal_connect(G_OBJECT(p->topgwin), "destroy-event",
454 G_CALLBACK(panel_destroy_event), p);
455 g_signal_connect (G_OBJECT (p->topgwin), "size-request",
456 (GCallback) panel_size_req, p);
457 g_signal_connect (G_OBJECT (p->topgwin), "size-allocate",
458 (GCallback) panel_size_alloc, p);
459 g_signal_connect (G_OBJECT (p->topgwin), "configure-event",
460 (GCallback) panel_configure_event, p);
84fc1d55 461/*
a52c2257
HJYP
462 g_signal_connect (G_OBJECT (p->topgwin), "realize",
463 (GCallback) panel_realize, p);
84fc1d55
HJYP
464*/
465 g_signal_connect (G_OBJECT (p->topgwin), "style-set",
466 (GCallback)panel_style_set, p);
a52c2257
HJYP
467 gtk_widget_realize(p->topgwin);
468 //gdk_window_set_decorations(p->topgwin->window, 0);
2de71c90 469
4542c20d 470 // main layout manager as a single child of panel
a97d06a6 471 p->box = p->my_box_new(FALSE, 0);
a52c2257 472 gtk_container_set_border_width(GTK_CONTAINER(p->box), 0);
4542c20d
HJYP
473// gtk_container_add(GTK_CONTAINER(p->bbox), p->box);
474 gtk_container_add(GTK_CONTAINER(p->topgwin), p->box);
a52c2257 475 gtk_widget_show(p->box);
a97d06a6
HJYP
476 if (p->round_corners)
477 make_round_corners(p);
6db11841 478
a52c2257
HJYP
479 p->topxwin = GDK_WINDOW_XWINDOW(GTK_WIDGET(p->topgwin)->window);
480 DBG("topxwin = %x\n", p->topxwin);
481
482 /* the settings that should be done before window is mapped */
483 wmhints.flags = InputHint;
484 wmhints.input = 0;
bee4c26e 485 XSetWMHints (GDK_DISPLAY(), p->topxwin, &wmhints);
24053345 486#define WIN_HINTS_SKIP_FOCUS (1<<0) /* "alt-tab" skips this win */
a52c2257
HJYP
487 val = WIN_HINTS_SKIP_FOCUS;
488 XChangeProperty(GDK_DISPLAY(), p->topxwin,
489 XInternAtom(GDK_DISPLAY(), "_WIN_HINTS", False), XA_CARDINAL, 32,
490 PropModeReplace, (unsigned char *) &val, 1);
491
bee4c26e 492 panel_set_dock_type(p);
a52c2257
HJYP
493
494 /* window mapping point */
495 gtk_widget_show_all(p->topgwin);
496
497 /* the settings that should be done after window is mapped */
498
499 /* send it to running wm */
500 Xclimsg(p->topxwin, a_NET_WM_DESKTOP, 0xFFFFFFFF, 0, 0, 0, 0);
501 /* and assign it ourself just for case when wm is not running */
502 val = 0xFFFFFFFF;
503 XChangeProperty(GDK_DISPLAY(), p->topxwin, a_NET_WM_DESKTOP, XA_CARDINAL, 32,
504 PropModeReplace, (unsigned char *) &val, 1);
505
506 state[0] = a_NET_WM_STATE_SKIP_PAGER;
507 state[1] = a_NET_WM_STATE_SKIP_TASKBAR;
508 state[2] = a_NET_WM_STATE_STICKY;
509 XChangeProperty(GDK_DISPLAY(), p->topxwin, a_NET_WM_STATE, XA_ATOM,
510 32, PropModeReplace, (unsigned char *) state, 3);
511
77886b88 512 XSelectInput (GDK_DISPLAY(), GDK_ROOT_WINDOW(), SubstructureNotifyMask|PropertyChangeMask);
a52c2257
HJYP
513 gdk_window_add_filter(gdk_get_default_root_window (), (GdkFilterFunc)panel_event_filter, p);
514
515 calculate_position(p);
516 gdk_window_move_resize(p->topgwin->window, p->ax, p->ay, p->aw, p->ah);
bee4c26e 517 panel_set_wm_strut(p);
77886b88 518
239cb032
HJYP
519 p->tooltips = gtk_tooltips_new();
520#if GLIB_CHECK_VERSION( 2, 10, 0 )
521 g_object_ref_sink( p->tooltips );
522#else
523 g_object_ref( p->tooltips );
524 gtk_object_sink( p->tooltips );
525#endif
526
a52c2257
HJYP
527 RET();
528}
529
22242ed4 530void panel_set_orientation(Panel *p)
a97d06a6
HJYP
531{
532 GList* l;
533 p->orientation = (p->edge == EDGE_TOP || p->edge == EDGE_BOTTOM)
534 ? ORIENT_HORIZ : ORIENT_VERT;
535 if (p->orientation == ORIENT_HORIZ) {
536 p->my_box_new = gtk_hbox_new;
537 p->my_separator_new = gtk_vseparator_new;
538 } else {
539 p->my_box_new = gtk_vbox_new;
540 p->my_separator_new = gtk_hseparator_new;
541 }
542
543 /* recreate the main layout box */
544 if( p->box ) {
5a343ad5
JH
545 GtkBox* newbox = GTK_BOX(recreate_box( GTK_BOX(p->box), p->orientation ));
546 if( GTK_WIDGET(newbox) != p->box ) {
547 p->box = GTK_WIDGET(newbox);
4542c20d 548 gtk_container_add( GTK_CONTAINER(p->topgwin), GTK_WIDGET(newbox) );
a97d06a6
HJYP
549 }
550 }
551 /* NOTE: This loop won't be executed when panel started since
552 plugins are not loaded at that time.
553 This is used when the orientation of the panel is changed
554 from the config dialog, and plugins should be re-layout.
555 */
556 for( l = p->plugins; l; l = l->next ) {
22242ed4 557 Plugin* pl = (Plugin*)l->data;
a97d06a6
HJYP
558 if( pl->class->orientation ) {
559 pl->class->orientation( pl );
560 }
561 }
562}
563
a52c2257 564static int
22242ed4 565panel_parse_global(Panel *p, char **fp)
a52c2257
HJYP
566{
567 line s;
568 s.len = 256;
6db11841 569
a52c2257 570 ENTER;
c69ac68e 571 while (lxpanel_get_line(fp, &s) != LINE_NONE) {
a52c2257
HJYP
572 if (s.type == LINE_VAR) {
573 if (!g_ascii_strcasecmp(s.t[0], "edge")) {
574 p->edge = str2num(edge_pair, s.t[1], EDGE_NONE);
575 } else if (!g_ascii_strcasecmp(s.t[0], "allign")) {
576 p->allign = str2num(allign_pair, s.t[1], ALLIGN_NONE);
577 } else if (!g_ascii_strcasecmp(s.t[0], "margin")) {
578 p->margin = atoi(s.t[1]);
579 } else if (!g_ascii_strcasecmp(s.t[0], "widthtype")) {
580 p->widthtype = str2num(width_pair, s.t[1], WIDTH_NONE);
581 } else if (!g_ascii_strcasecmp(s.t[0], "width")) {
582 p->width = atoi(s.t[1]);
583 } else if (!g_ascii_strcasecmp(s.t[0], "heighttype")) {
584 p->heighttype = str2num(height_pair, s.t[1], HEIGHT_NONE);
585 } else if (!g_ascii_strcasecmp(s.t[0], "height")) {
586 p->height = atoi(s.t[1]);
587 } else if (!g_ascii_strcasecmp(s.t[0], "spacing")) {
588 p->spacing = atoi(s.t[1]);
589 } else if (!g_ascii_strcasecmp(s.t[0], "SetDockType")) {
590 p->setdocktype = str2num(bool_pair, s.t[1], 0);
591 } else if (!g_ascii_strcasecmp(s.t[0], "SetPartialStrut")) {
592 p->setstrut = str2num(bool_pair, s.t[1], 0);
593 } else if (!g_ascii_strcasecmp(s.t[0], "RoundCorners")) {
594 p->round_corners = str2num(bool_pair, s.t[1], 0);
595 } else if (!g_ascii_strcasecmp(s.t[0], "Transparent")) {
596 p->transparent = str2num(bool_pair, s.t[1], 0);
597 } else if (!g_ascii_strcasecmp(s.t[0], "Alpha")) {
598 p->alpha = atoi(s.t[1]);
599 if (p->alpha > 255)
600 p->alpha = 255;
601 } else if (!g_ascii_strcasecmp(s.t[0], "TintColor")) {
602 if (!gdk_color_parse (s.t[1], &p->gtintcolor))
603 gdk_color_parse ("white", &p->gtintcolor);
604 p->tintcolor = gcolor2rgb24(&p->gtintcolor);
605 DBG("tintcolor=%x\n", p->tintcolor);
2de71c90
FC
606 } else if (!g_ascii_strcasecmp(s.t[0], "useFontColor")) {
607 p->usefontcolor = str2num(bool_pair, s.t[1], 0);
608 } else if (!g_ascii_strcasecmp(s.t[0], "FontColor")) {
609 if (!gdk_color_parse (s.t[1], &p->gfontcolor))
610 gdk_color_parse ("black", &p->gfontcolor);
e7ce315d 611 p->fontcolor = gcolor2rgb24(&p->gfontcolor);
2de71c90
FC
612 DBG("fontcolor=%x\n", p->fontcolor);
613 } else if (!g_ascii_strcasecmp(s.t[0], "Background")) {
614 p->background = str2num(bool_pair, s.t[1], 0);
615 } else if( !g_ascii_strcasecmp(s.t[0], "BackgroundFile") ) {
616 p->background_file = g_strdup( s.t[1] );
239cb032
HJYP
617 } else if( !g_ascii_strcasecmp(s.t[0], "FileManager") ) {
618 p->file_manager = g_strdup( s.t[1] );
619 } else if( !g_ascii_strcasecmp(s.t[0], "Terminal") ) {
620 p->terminal = g_strdup( s.t[1] );
389975e0
HJYP
621 } else if( !g_ascii_strcasecmp(s.t[0], "LogoutCommand") ) {
622 p->logout_command = g_strdup( s.t[1] );
a52c2257
HJYP
623 } else {
624 ERR( "lxpanel: %s - unknown var in Global section\n", s.t[0]);
625 RET(0);
626 }
627 } else if (s.type == LINE_BLOCK_END) {
628 break;
629 } else {
630 ERR( "lxpanel: illegal in this context %s\n", s.str);
631 RET(0);
632 }
633 }
a97d06a6 634 panel_set_orientation( p );
4542c20d 635
a52c2257
HJYP
636 if (p->width < 0)
637 p->width = 100;
638 if (p->widthtype == WIDTH_PERCENT && p->width > 100)
639 p->width = 100;
640 p->heighttype = HEIGHT_PIXEL;
641 if (p->heighttype == HEIGHT_PIXEL) {
642 if (p->height < PANEL_HEIGHT_MIN)
643 p->height = PANEL_HEIGHT_MIN;
644 else if (p->height > PANEL_HEIGHT_MAX)
645 p->height = PANEL_HEIGHT_MAX;
646 }
2de71c90
FC
647
648 if (p->background)
649 p->transparent = 0;
650
a52c2257
HJYP
651 p->curdesk = get_net_current_desktop();
652 p->desknum = get_net_number_of_desktops();
653 p->workarea = get_xaproperty (GDK_ROOT_WINDOW(), a_NET_WORKAREA, XA_CARDINAL, &p->wa_len);
654 print_wmdata(p);
239cb032 655
a52c2257
HJYP
656 panel_start_gui(p);
657 RET(1);
658}
659
660static int
22242ed4 661panel_parse_plugin(Panel *p, char **fp)
a52c2257
HJYP
662{
663 line s;
22242ed4 664 Plugin *plug = NULL;
a52c2257 665 gchar *type = NULL;
a52c2257 666 int expand , padding, border;
db449f6e
HJYP
667 char* pconfig = NULL;
668
a52c2257
HJYP
669 ENTER;
670 s.len = 256;
a52c2257 671 border = expand = padding = 0;
c69ac68e 672 while (lxpanel_get_line(fp, &s) != LINE_BLOCK_END) {
a52c2257
HJYP
673 if (s.type == LINE_NONE) {
674 ERR( "lxpanel: bad line %s\n", s.str);
675 goto error;
676 }
677 if (s.type == LINE_VAR) {
678 if (!g_ascii_strcasecmp(s.t[0], "type")) {
679 type = g_strdup(s.t[1]);
680 DBG("plug %s\n", type);
681 } else if (!g_ascii_strcasecmp(s.t[0], "expand"))
682 expand = str2num(bool_pair, s.t[1], 0);
683 else if (!g_ascii_strcasecmp(s.t[0], "padding"))
684 padding = atoi(s.t[1]);
685 else if (!g_ascii_strcasecmp(s.t[0], "border"))
686 border = atoi(s.t[1]);
687 else {
688 ERR( "lxpanel: unknown var %s\n", s.t[0]);
689 goto error;
690 }
691 } else if (s.type == LINE_BLOCK_START) {
692 if (!g_ascii_strcasecmp(s.t[0], "Config")) {
db449f6e 693 pconfig = *fp;
a52c2257
HJYP
694 int pno = 1;
695 while (pno) {
696 get_line_as_is(fp, &s);
697 if (s.type == LINE_NONE) {
698 ERR( "lxpanel: unexpected eof\n");
699 goto error;
700 } else if (s.type == LINE_BLOCK_START) {
701 pno++;
702 } else if (s.type == LINE_BLOCK_END) {
703 pno--;
bee4c26e 704 }
db449f6e 705 }
a52c2257
HJYP
706 } else {
707 ERR( "lxpanel: unknown block %s\n", s.t[0]);
708 goto error;
709 }
710 } else {
711 ERR( "lxpanel: illegal in this context %s\n", s.str);
712 goto error;
713 }
714 }
db449f6e 715
a52c2257
HJYP
716 if (!type || !(plug = plugin_load(type))) {
717 ERR( "lxpanel: can't load %s plugin\n", type);
718 goto error;
719 }
db449f6e 720
a52c2257 721 plug->panel = p;
a52c2257
HJYP
722 plug->expand = expand;
723 plug->padding = padding;
724 plug->border = border;
a52c2257 725 DBG("starting\n");
db449f6e 726 if (!plugin_start(plug, pconfig ? &pconfig : NULL)) {
a52c2257
HJYP
727 ERR( "lxpanel: can't start plugin %s\n", type);
728 goto error;
729 }
730 DBG("plug %s\n", type);
731 p->plugins = g_list_append(p->plugins, plug);
0dcb6bf5
HJYP
732
733 g_free( type );
a52c2257 734 RET(1);
db449f6e 735
a52c2257 736 error:
a52c2257
HJYP
737 g_free(type);
738 if (plug)
739 plugin_put(plug);
740 RET(0);
a52c2257
HJYP
741}
742
743
0defe4b9 744static int
22242ed4 745panel_start( Panel *p, char **fp )
a52c2257
HJYP
746{
747 line s;
db449f6e 748
a52c2257
HJYP
749 /* parse global section */
750 ENTER;
751 s.len = 256;
22242ed4 752 memset(p, 0, sizeof(Panel));
a52c2257
HJYP
753 p->allign = ALLIGN_CENTER;
754 p->edge = EDGE_BOTTOM;
755 p->widthtype = WIDTH_PERCENT;
756 p->width = 100;
757 p->heighttype = HEIGHT_PIXEL;
758 p->height = PANEL_HEIGHT_DEFAULT;
759 p->setdocktype = 1;
760 p->setstrut = 1;
761 p->round_corners = 0;
762 p->transparent = 0;
763 p->alpha = 127;
764 p->tintcolor = 0xFFFFFFFF;
2de71c90
FC
765 p->usefontcolor = 0;
766 p->fontcolor = 0x00000000;
a52c2257 767 p->spacing = 0;
22242ed4 768
c69ac68e 769 if ((lxpanel_get_line(fp, &s) != LINE_BLOCK_START) || g_ascii_strcasecmp(s.t[0], "Global")) {
a52c2257
HJYP
770 ERR( "lxpanel: config file must start from Global section\n");
771 RET(0);
772 }
773 if (!panel_parse_global(p, fp))
774 RET(0);
775
c69ac68e 776 while (lxpanel_get_line(fp, &s) != LINE_NONE) {
a52c2257
HJYP
777 if ((s.type != LINE_BLOCK_START) || g_ascii_strcasecmp(s.t[0], "Plugin")) {
778 ERR( "lxpanel: expecting Plugin section\n");
779 RET(0);
780 }
9939506e 781 panel_parse_plugin(p, fp);
a52c2257
HJYP
782 }
783 gtk_widget_show_all(p->topgwin);
4542c20d
HJYP
784
785 /* update backgrond of panel and all plugins */
786 panel_update_background( p );
787
a52c2257
HJYP
788 print_wmdata(p);
789 RET(1);
790}
791
792static void
793delete_plugin(gpointer data, gpointer udata)
794{
795 ENTER;
22242ed4
HJYP
796 plugin_stop((Plugin *)data);
797 plugin_put((Plugin *)data);
a52c2257 798 RET();
a52c2257
HJYP
799}
800
22242ed4 801void panel_stop(Panel *p)
a52c2257
HJYP
802{
803 ENTER;
804
805 g_list_foreach(p->plugins, delete_plugin, NULL);
806 g_list_free(p->plugins);
807 p->plugins = NULL;
8c44345a 808
5297da29 809 if( p->system_menus ){
8c44345a 810 do{
5297da29 811 } while ( g_source_remove_by_user_data( p->system_menus ) );
8c44345a
HJYP
812 }
813
239cb032
HJYP
814 g_object_unref( p->tooltips );
815
a52c2257
HJYP
816 XSelectInput (GDK_DISPLAY(), GDK_ROOT_WINDOW(), NoEventMask);
817 gdk_window_remove_filter(gdk_get_default_root_window (), (GdkFilterFunc)panel_event_filter, p);
818 gtk_widget_destroy(p->topgwin);
a52c2257 819 g_free(p->workarea);
2de71c90 820 g_free( p->background_file );
239cb032
HJYP
821 g_free( p->file_manager );
822 g_free( p->terminal );
389975e0 823 g_free( p->logout_command );
5297da29 824 g_slist_free( p->system_menus );
a52c2257
HJYP
825 gdk_flush();
826 XFlush(GDK_DISPLAY());
827 XSync(GDK_DISPLAY(), True);
828 RET();
829}
830
831
0defe4b9 832static void
a52c2257
HJYP
833usage()
834{
835 ENTER;
e7cb732b
HJYP
836 g_print(_("lxpanel %s - lightweight GTK2+ panel for UNIX desktops\n"), version);
837 g_print(_("Command line options:\n"));
838 g_print(_(" --help -- print this help and exit\n"));
839 g_print(_(" --version -- print version and exit\n"));
840 g_print(_(" --log <number> -- set log level 0-5. 0 - none 5 - chatty\n"));
841 g_print(_(" --configure -- launch configuration utility\n"));
842 g_print(_(" --profile name -- use specified profile\n"));
843 g_print("\n");
844 g_print(_(" -h -- same as --help\n"));
845 g_print(_(" -p -- same as --profile\n"));
846 g_print(_(" -v -- same as --version\n"));
847 g_print(_(" -C -- same as --configure\n"));
848 g_print(_("\nVisit http://lxpanel.sourceforge.net/ for detailed documentation,\n\n"));
a52c2257
HJYP
849}
850
e68b47dc 851static char*
db449f6e 852load_profile(gchar *profile)
a52c2257
HJYP
853{
854 gchar *fname;
db449f6e 855 char* ret;
a52c2257
HJYP
856
857 ENTER;
858 LOG(LOG_INFO, "loading %s profile\n", profile);
24053345
HJYP
859 /* check private configuration directory */
860 fname = get_config_file_path( profile, FALSE );
db449f6e
HJYP
861 g_file_get_contents( fname, &ret, NULL, NULL );
862 if (ret) {
a52c2257 863 cfgfile = fname;
db449f6e 864 RET(ret);
a52c2257
HJYP
865 }
866 //ERR("Can't load %s\n", fname);
867 g_free(fname);
db449f6e 868
24053345
HJYP
869 /* If private config is not available, check global configuration directory */
870 fname = get_config_file_path( profile, TRUE ); /* the global config file */
db449f6e
HJYP
871 g_file_get_contents( fname, &ret, NULL, NULL );
872 if (ret) {
a52c2257 873 cfgfile = fname;
db449f6e 874 RET(ret);
a52c2257
HJYP
875 }
876 //ERR("Can't load %s\n", fname);
877 g_free(fname);
878 LOG(LOG_ERR, "Can't open '%s' profile\n", profile);
879 RET(NULL);
880}
881
e68b47dc 882static void
a52c2257
HJYP
883handle_error(Display * d, XErrorEvent * ev)
884{
885 char buf[256];
886
887 ENTER;
888 if (log_level >= LOG_WARN) {
889 XGetErrorText(GDK_DISPLAY(), ev->error_code, buf, 256);
890 LOG(LOG_WARN, "lxpanel : X error: %s\n", buf);
891 }
892 RET();
893}
894
e68b47dc
JH
895/* Lightweight lock related functions - X clipboard hacks */
896
897#define CLIPBOARD_NAME "LXPANEL_SELECTION"
898
899/*
900 * clipboard_get_func - dummy get_func for gtk_clipboard_set_with_data ()
901 */
902static void
903clipboard_get_func(
904 GtkClipboard *clipboard G_GNUC_UNUSED,
905 GtkSelectionData *selection_data G_GNUC_UNUSED,
906 guint info G_GNUC_UNUSED,
907 gpointer user_data_or_owner G_GNUC_UNUSED)
908{
909}
910
911/*
912 * clipboard_clear_func - dummy clear_func for gtk_clipboard_set_with_data ()
913 */
914static void clipboard_clear_func(
915 GtkClipboard *clipboard G_GNUC_UNUSED,
916 gpointer user_data_or_owner G_GNUC_UNUSED)
917{
918}
919
920/*
921 * Lightweight version for checking single instance.
922 * Try and get the CLIPBOARD_NAME clipboard instead of using file manipulation.
923 *
924 * Returns TRUE if successfully retrieved and FALSE otherwise.
925 */
16fb8c2e 926static gboolean check_main_lock()
e68b47dc
JH
927{
928 static const GtkTargetEntry targets[] = { { CLIPBOARD_NAME, 0, 0 } };
929 gboolean retval = FALSE;
930 GtkClipboard *clipboard;
931 Atom atom;
932
933 atom = gdk_x11_get_xatom_by_name(CLIPBOARD_NAME);
934
935 XGrabServer(GDK_DISPLAY());
936
937 if (XGetSelectionOwner(GDK_DISPLAY(), atom) != None)
938 goto out;
939
940 clipboard = gtk_clipboard_get(gdk_atom_intern(CLIPBOARD_NAME, FALSE));
941
942 if (gtk_clipboard_set_with_data(clipboard, targets,
943 G_N_ELEMENTS (targets),
944 clipboard_get_func,
945 clipboard_clear_func, NULL))
946 retval = TRUE;
947
948out:
949 XUngrabServer (GDK_DISPLAY ());
950 gdk_flush ();
951
952 return retval;
953}
954#undef CLIPBOARD_NAME
955
a52c2257
HJYP
956int
957main(int argc, char *argv[], char *env[])
958{
959 int i;
a52c2257 960 void configure();
db449f6e 961 char *fp, *pfp; /* point to current position of profile data in memory */
f277dbb7 962
a52c2257
HJYP
963 ENTER;
964 //printf("sizeof(gulong)=%d\n", sizeof(gulong));
965 setlocale(LC_CTYPE, "");
f277dbb7 966
a52c2257
HJYP
967 gtk_init(&argc, &argv);
968
969#ifdef ENABLE_NLS
970 bindtextdomain ( GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR );
971 bind_textdomain_codeset ( GETTEXT_PACKAGE, "UTF-8" );
972 textdomain ( GETTEXT_PACKAGE );
973#endif
974
975 XSetLocaleModifiers("");
976 XSetErrorHandler((XErrorHandler) handle_error);
977 resolve_atoms();
978 for (i = 1; i < argc; i++) {
979 if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
980 usage();
981 exit(0);
982 } else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) {
983 printf("lxpanel %s\n", version);
984 exit(0);
985 } else if (!strcmp(argv[i], "--log")) {
986 i++;
987 if (i == argc) {
988 ERR( "lxpanel: missing log level\n");
989 usage();
990 exit(1);
991 } else {
992 log_level = atoi(argv[i]);
993 }
994 } else if (!strcmp(argv[i], "--configure") || !strcmp(argv[i], "-C")) {
995 config = 1;
996 } else if (!strcmp(argv[i], "--profile") || !strcmp(argv[i], "-p")) {
997 i++;
998 if (i == argc) {
999 ERR( "lxpanel: missing profile name\n");
1000 usage();
1001 exit(1);
1002 } else {
1003 cprofile = g_strdup(argv[i]);
1004 }
1005 } else {
1006 printf("lxpanel: unknown option - %s\n", argv[i]);
1007 usage();
1008 exit(1);
1009 }
1010 }
f277dbb7 1011
e68b47dc
JH
1012 /* Check for duplicated panel instances */
1013 if (!check_main_lock() && !config) {
1014 printf("There is alreay an instance of LXPanel. Now to exit\n");
1015 exit(1);
1016 }
1017
f277dbb7
HJYP
1018 /* Add our own icons to the search path of icon theme */
1019 gtk_icon_theme_append_search_path( gtk_icon_theme_get_default(),
1020 PACKAGE_DATA_DIR "/lxpanel/images" );
1021
22242ed4
HJYP
1022 fbev = fb_ev_new();
1023
f7cb330e
HJYP
1024restart:
1025 is_restarting = FALSE;
1026
6a6ad54e
HJYP
1027 if (!(fp = pfp = load_profile(cprofile)))
1028 exit(1);
22242ed4 1029 p = g_new0(Panel, 1);
6a6ad54e
HJYP
1030 g_return_val_if_fail (p != NULL, 1);
1031 if (!panel_start(p, &pfp)) {
1032 ERR( "lxpanel: can't start panel\n");
1033 exit(1);
5541b8d2 1034 }
6a6ad54e
HJYP
1035 g_free( fp );
1036 if (config)
1037 configure();
1038
1039 gtk_main();
1040 panel_stop(p);
1041 g_free( cfgfile );
1042 g_free(p);
5541b8d2 1043
f7cb330e
HJYP
1044 if( is_restarting )
1045 goto restart;
1046
22242ed4
HJYP
1047 g_object_unref(fbev);
1048
5541b8d2 1049 return 0;
a52c2257
HJYP
1050}
1051