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