l10n: Updates to Portuguese (Brazilian) (pt_BR) translation
[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 19#ifdef HAVE_CONFIG_H
cf701cb7 20#include <config.h>
a52c2257
HJYP
21#endif
22
cf701cb7 23#include <glib/gi18n.h>
a52c2257 24#include <stdlib.h>
16fbda14 25#include <glib/gstdio.h>
a52c2257
HJYP
26#include <sys/types.h>
27#include <sys/stat.h>
28#include <unistd.h>
29#include <errno.h>
30#include <locale.h>
31#include <string.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 39#include "lxpanelctl.h"
cf701cb7 40#include "dbg.h"
77886b88 41
a52c2257
HJYP
42static gchar *cfgfile = NULL;
43static gchar version[] = VERSION;
44gchar *cprofile = "default";
45
e2957bd2
HJYP
46static GtkWindowGroup* win_grp; /* window group used to limit the scope of model dialog. */
47
e68b47dc 48static int config = 0;
22242ed4 49FbEv *fbev = NULL;
a52c2257 50
cf701cb7 51GSList* all_panels = NULL; /* a single-linked list storing all panels */
a52c2257 52
f7cb330e
HJYP
53gboolean is_restarting = FALSE;
54
3e7b8eb7 55static int panel_start( Panel *p, char **fp );
9dd114c4 56static void panel_start_gui(Panel *p);
4b93d81e
HJYP
57void panel_config_save(Panel* panel); /* defined in configurator.c */
58
95095259
HJYP
59gboolean is_in_lxde = FALSE;
60
cb22c87c
HJYP
61/* A hack used to be compatible with Gnome panel for gtk+ themes.
62 * Some gtk+ themes define special styles for desktop panels.
63 * http://live.gnome.org/GnomeArt/Tutorials/GtkThemes/GnomePanel
64 * So we make a derived class from GtkWindow named PanelToplevel
65 * and create the panels with it to be compatible with Gnome themes.
66 */
67#define PANEL_TOPLEVEL_TYPE (panel_toplevel_get_type())
68
69typedef struct _PanelToplevel PanelToplevel;
70typedef struct _PanelToplevelClass PanelToplevelClass;
71struct _PanelToplevel
72{
73 GtkWindow parent;
74};
75struct _PanelToplevelClass
76{
77 GtkWindowClass parent_class;
78};
79G_DEFINE_TYPE(PanelToplevel, panel_toplevel, GTK_TYPE_WINDOW);
80static void panel_toplevel_class_init(PanelToplevelClass *klass)
81{
82}
83static void panel_toplevel_init(PanelToplevel *self)
84{
85}
86
9dd114c4 87/* Allocate and initialize new Panel structure. */
88static Panel* panel_allocate(void)
89{
2918994e 90 Panel* p = g_new0(Panel, 1);
9dd114c4 91 p->allign = ALLIGN_CENTER;
92 p->edge = EDGE_NONE;
93 p->widthtype = WIDTH_PERCENT;
94 p->width = 100;
95 p->heighttype = HEIGHT_PIXEL;
96 p->height = PANEL_HEIGHT_DEFAULT;
97 p->setdocktype = 1;
98 p->setstrut = 1;
99 p->round_corners = 0;
100 p->autohide = 0;
101 p->visible = TRUE;
102 p->height_when_hidden = 2;
103 p->transparent = 0;
104 p->alpha = 127;
105 p->tintcolor = 0xFFFFFFFF;
106 p->usefontcolor = 0;
107 p->fontcolor = 0x00000000;
108 p->spacing = 0;
8f9e6256 109 p->icon_size = PANEL_ICON_SIZE;
9dd114c4 110 return p;
111}
112
113/* Normalize panel configuration after load from file or reconfiguration. */
114static void panel_normalize_configuration(Panel* p)
115{
2918994e 116 panel_set_panel_configuration_changed( p );
9dd114c4 117 if (p->width < 0)
118 p->width = 100;
119 if (p->widthtype == WIDTH_PERCENT && p->width > 100)
120 p->width = 100;
121 p->heighttype = HEIGHT_PIXEL;
122 if (p->heighttype == HEIGHT_PIXEL) {
123 if (p->height < PANEL_HEIGHT_MIN)
124 p->height = PANEL_HEIGHT_MIN;
125 else if (p->height > PANEL_HEIGHT_MAX)
126 p->height = PANEL_HEIGHT_MAX;
127 }
128 if (p->background)
129 p->transparent = 0;
130}
131
a52c2257
HJYP
132/****************************************************
133 * panel's handlers for WM events *
134 ****************************************************/
a52c2257 135
22242ed4 136void panel_set_wm_strut(Panel *p)
a52c2257 137{
d1d43629 138 int index;
139 gulong strut_size;
140 gulong strut_lower;
141 gulong strut_upper;
a52c2257 142
d1d43629 143 /* Dispatch on edge to set up strut parameters. */
144 switch (p->edge)
bee4c26e 145 {
d1d43629 146 case EDGE_LEFT:
147 index = 0;
148 strut_size = p->aw;
149 strut_lower = p->ay;
150 strut_upper = p->ay + p->ah;
151 break;
152 case EDGE_RIGHT:
153 index = 1;
154 strut_size = p->aw;
155 strut_lower = p->ay;
156 strut_upper = p->ay + p->ah;
157 break;
158 case EDGE_TOP:
159 index = 2;
160 strut_size = p->ah;
161 strut_lower = p->ax;
162 strut_upper = p->ax + p->aw;
163 break;
164 case EDGE_BOTTOM:
165 index = 3;
166 strut_size = p->ah;
167 strut_lower = p->ax;
168 strut_upper = p->ax + p->aw;
169 break;
170 default:
171 return;
bee4c26e
HJYP
172 }
173
176fb687 174 /* Handle autohide case. EWMH recommends having the strut be the minimized size. */
175 if ( ! p->visible)
176 strut_size = p->height_when_hidden;
177
d1d43629 178 /* Set up strut value in property format. */
179 gulong desired_strut[12];
180 memset(desired_strut, 0, sizeof(desired_strut));
181 if (p->setstrut)
182 {
183 desired_strut[index] = strut_size;
184 desired_strut[4 + index * 2] = strut_lower;
185 desired_strut[5 + index * 2] = strut_upper;
186 }
187 else
188 {
189 strut_size = 0;
190 strut_lower = 0;
191 strut_upper = 0;
bee4c26e 192 }
bee4c26e 193
d1d43629 194 /* If strut value changed, set the property value on the panel window.
195 * This avoids property change traffic when the panel layout is recalculated but strut geometry hasn't changed. */
196 if ((GTK_WIDGET_MAPPED(p->topgwin))
547ece89 197 && ((p->strut_size != strut_size) || (p->strut_lower != strut_lower) || (p->strut_upper != strut_upper) || (p->strut_edge != p->edge)))
d1d43629 198 {
199 p->strut_size = strut_size;
200 p->strut_lower = strut_lower;
201 p->strut_upper = strut_upper;
547ece89 202 p->strut_edge = p->edge;
a52c2257 203
d1d43629 204 /* If window manager supports STRUT_PARTIAL, it will ignore STRUT.
205 * Set STRUT also for window managers that do not support STRUT_PARTIAL. */
206 if (strut_size != 0)
207 {
208 XChangeProperty(GDK_DISPLAY(), p->topxwin, a_NET_WM_STRUT_PARTIAL,
209 XA_CARDINAL, 32, PropModeReplace, (unsigned char *) desired_strut, 12);
210 XChangeProperty(GDK_DISPLAY(), p->topxwin, a_NET_WM_STRUT,
211 XA_CARDINAL, 32, PropModeReplace, (unsigned char *) desired_strut, 4);
212 }
213 else
214 {
215 XDeleteProperty(GDK_DISPLAY(), p->topxwin, a_NET_WM_STRUT);
216 XDeleteProperty(GDK_DISPLAY(), p->topxwin, a_NET_WM_STRUT_PARTIAL);
217 }
218 }
a52c2257
HJYP
219}
220
e996608e 221/* defined in plugins/menu.c */
8c44345a 222gboolean show_system_menu( gpointer system_menu );
e996608e 223
3e7b8eb7
HJYP
224/* defined in configurator.c */
225void panel_configure(Panel* p, int sel_page );
9dd114c4 226gboolean panel_edge_available(Panel* p, int edge);
3e7b8eb7 227
e996608e 228/* built-in commands, defined in configurator.c */
77886b88
HJYP
229void restart(void);
230void gtk_run(void);
e3b89f43 231void panel_destroy(Panel *p);
77886b88 232
d18c9409 233static void process_client_msg ( XClientMessageEvent* ev )
77886b88 234{
8c44345a 235 int cmd = ev->data.b[0];
77886b88
HJYP
236 switch( cmd )
237 {
ace2a572 238#ifndef DISABLE_MENU
77886b88 239 case LXPANEL_CMD_SYS_MENU:
d18c9409
HJYP
240 {
241 GSList* l;
242 for( l = all_panels; l; l = l->next )
8c44345a 243 {
d18c9409
HJYP
244 Panel* p = (Panel*)l->data;
245 if( p->system_menus )
246 {
247 /* show_system_menu( p->system_menus->data ); */
248 /* FIXME: I've no idea why this doesn't work without timeout
249 under some WMs, like icewm. */
250 g_timeout_add( 200, (GSourceFunc)show_system_menu,
251 p->system_menus->data );
252 }
8c44345a 253 }
77886b88 254 break;
d18c9409 255 }
ace2a572
JH
256#endif
257#ifndef DISABLE_MENU
77886b88
HJYP
258 case LXPANEL_CMD_RUN:
259 gtk_run();
260 break;
ace2a572 261#endif
77886b88 262 case LXPANEL_CMD_CONFIG:
8110399f 263 //FIXME: configure();
77886b88
HJYP
264 break;
265 case LXPANEL_CMD_RESTART:
266 restart();
267 break;
268 case LXPANEL_CMD_EXIT:
269 gtk_main_quit();
270 break;
271 }
272}
273
a52c2257 274static GdkFilterReturn
cf701cb7 275panel_event_filter(GdkXEvent *xevent, GdkEvent *event, gpointer not_used)
a52c2257
HJYP
276{
277 Atom at;
278 Window win;
279 XEvent *ev = (XEvent *) xevent;
280
281 ENTER;
282 DBG("win = 0x%x\n", ev->xproperty.window);
53b37ef2
HJYP
283 if (ev->type != PropertyNotify )
284 {
77886b88
HJYP
285 /* private client message from lxpanelctl */
286 if( ev->type == ClientMessage && ev->xproperty.atom == a_LXPANEL_CMD )
287 {
d18c9409 288 process_client_msg( (XClientMessageEvent*)ev );
77886b88 289 }
22242ed4
HJYP
290 else if( ev->type == DestroyNotify )
291 {
cf701cb7 292 fb_ev_emit_destroy( fbev, ((XDestroyWindowEvent*)ev)->window );
22242ed4 293 }
a52c2257 294 RET(GDK_FILTER_CONTINUE);
24053345 295 }
77886b88 296
a52c2257
HJYP
297 at = ev->xproperty.atom;
298 win = ev->xproperty.window;
53b37ef2
HJYP
299 if (win == GDK_ROOT_WINDOW())
300 {
301 if (at == a_NET_CLIENT_LIST)
302 {
303 fb_ev_emit(fbev, EV_CLIENT_LIST);
304 }
305 else if (at == a_NET_CURRENT_DESKTOP)
306 {
cf701cb7
HJYP
307 GSList* l;
308 for( l = all_panels; l; l = l->next )
309 ((Panel*)l->data)->curdesk = get_net_current_desktop();
22242ed4 310 fb_ev_emit(fbev, EV_CURRENT_DESKTOP);
53b37ef2
HJYP
311 }
312 else if (at == a_NET_NUMBER_OF_DESKTOPS)
313 {
cf701cb7
HJYP
314 GSList* l;
315 for( l = all_panels; l; l = l->next )
316 ((Panel*)l->data)->desknum = get_net_number_of_desktops();
22242ed4 317 fb_ev_emit(fbev, EV_NUMBER_OF_DESKTOPS);
53b37ef2
HJYP
318 }
319 else if (at == a_NET_DESKTOP_NAMES)
320 {
22242ed4 321 fb_ev_emit(fbev, EV_DESKTOP_NAMES);
53b37ef2
HJYP
322 }
323 else if (at == a_NET_ACTIVE_WINDOW)
324 {
22242ed4 325 fb_ev_emit(fbev, EV_ACTIVE_WINDOW );
53b37ef2
HJYP
326 }
327 else if (at == a_NET_CLIENT_LIST_STACKING)
328 {
22242ed4 329 fb_ev_emit(fbev, EV_CLIENT_LIST_STACKING);
53b37ef2
HJYP
330 }
331 else if (at == a_XROOTPMAP_ID)
332 {
cf701cb7
HJYP
333 GSList* l;
334 for( l = all_panels; l; l = l->next )
335 {
336 Panel* p = (Panel*)l->data;
337 if (p->transparent) {
338 fb_bg_notify_changed_bg(p->bg);
339 }
340 }
53b37ef2
HJYP
341 }
342 else if (at == a_NET_WORKAREA)
343 {
cf701cb7
HJYP
344 GSList* l;
345 for( l = all_panels; l; l = l->next )
346 {
347 Panel* p = (Panel*)l->data;
348 g_free( p->workarea );
349 p->workarea = get_xaproperty (GDK_ROOT_WINDOW(), a_NET_WORKAREA, XA_CARDINAL, &p->wa_len);
1d9dc649 350 /* print_wmdata(p); */
a52c2257 351 }
53b37ef2
HJYP
352 }
353 else
cf701cb7
HJYP
354 return GDK_FILTER_CONTINUE;
355
356 return GDK_FILTER_REMOVE;
a52c2257 357 }
cf701cb7 358 return GDK_FILTER_CONTINUE;
a52c2257
HJYP
359}
360
361/****************************************************
362 * panel's handlers for GTK events *
363 ****************************************************/
364
bee4c26e 365
a52c2257
HJYP
366static gint
367panel_delete_event(GtkWidget * widget, GdkEvent * event, gpointer data)
368{
369 ENTER;
370 RET(FALSE);
371}
372
373static gint
374panel_destroy_event(GtkWidget * widget, GdkEvent * event, gpointer data)
375{
22242ed4 376 //Panel *p = (Panel *) data;
a52c2257
HJYP
377 //if (!p->self_destroy)
378 gtk_main_quit();
379 RET(FALSE);
380}
381
4542c20d 382static void
22242ed4 383on_root_bg_changed(FbBg *bg, Panel* p)
4542c20d
HJYP
384{
385 panel_update_background( p );
386}
387
2918994e 388void panel_determine_background_pixmap(Panel * p, GtkWidget * widget, GdkWindow * window)
4542c20d 389{
2918994e 390 GdkPixmap * pixmap = NULL;
4542c20d 391
2918994e 392 /* Free p->bg if it is not going to be used. */
393 if (( ! p->transparent) && (p->bg != NULL))
394 {
395 g_signal_handlers_disconnect_by_func(G_OBJECT(p->bg), on_root_bg_changed, p);
396 g_object_unref(p->bg);
397 p->bg = NULL;
398 }
4542c20d 399
2918994e 400 if (p->background)
401 {
402 /* User specified background pixmap. */
403 if (p->background_file != NULL)
404 pixmap = fb_bg_get_pix_from_file(widget, p->background_file);
4542c20d 405 }
2918994e 406
407 else if (p->transparent)
4542c20d 408 {
2918994e 409 /* Transparent. Determine the appropriate value from the root pixmap. */
410 if (p->bg == NULL)
4542c20d 411 {
2918994e 412 p->bg = fb_bg_get_for_display();
413 g_signal_connect(G_OBJECT(p->bg), "changed", G_CALLBACK(on_root_bg_changed), p);
4542c20d 414 }
2918994e 415 pixmap = fb_bg_get_xroot_pix_for_win(p->bg, widget);
416 if ((pixmap != NULL) && (pixmap != GDK_NO_BG) && (p->alpha != 0))
417 fb_bg_composite(pixmap, widget->style->black_gc, p->tintcolor, p->alpha);
4542c20d
HJYP
418 }
419
2918994e 420 if (pixmap != NULL)
4542c20d 421 {
2918994e 422 gtk_widget_set_app_paintable(widget, TRUE );
423 gdk_window_set_back_pixmap(window, pixmap, FALSE);
424 g_object_unref(pixmap);
4542c20d
HJYP
425 }
426 else
2918994e 427 gtk_widget_set_app_paintable(widget, FALSE);
428}
4542c20d 429
2918994e 430/* Update the background of the entire panel.
431 * This function should only be called after the panel has been realized. */
432void panel_update_background(Panel * p)
433{
434 /* Redraw the top level widget. */
435 panel_determine_background_pixmap(p, p->topgwin, p->topgwin->window);
436 gdk_window_clear(p->topgwin->window);
437 gtk_widget_queue_draw(p->topgwin);
2918994e 438
439 /* Loop over all plugins redrawing each plugin. */
440 GList * l;
441 for (l = p->plugins; l != NULL; l = l->next)
4542c20d 442 {
2918994e 443 Plugin * pl = (Plugin *) l->data;
964b8b7e 444 if (pl->pwid != NULL)
445 plugin_widget_set_background(pl->pwid, p);
4542c20d
HJYP
446 }
447
4542c20d 448}
a52c2257 449
84fc1d55
HJYP
450static gboolean delay_update_background( Panel* p )
451{
6589616e
JH
452 /* Panel could be destroyed while background update scheduled */
453 if ( p->topgwin && GTK_WIDGET_REALIZED ( p->topgwin ) ) {
454 gdk_display_sync( gtk_widget_get_display(p->topgwin) );
455 panel_update_background( p );
456 }
457
cf701cb7 458 return FALSE;
84fc1d55
HJYP
459}
460
461static void
f2d54481
HJYP
462panel_realize(GtkWidget *widget, Panel *p)
463{
e3b89f43 464 g_idle_add_full( G_PRIORITY_LOW,
465 (GSourceFunc)delay_update_background, p, NULL );
f2d54481
HJYP
466}
467
468static void
84fc1d55
HJYP
469panel_style_set(GtkWidget *widget, GtkStyle* prev, Panel *p)
470{
0987f648 471 /* FIXME: This dirty hack is used to fix the background of systray... */
cf701cb7 472 if( GTK_WIDGET_REALIZED( widget ) )
e3b89f43 473 g_idle_add_full( G_PRIORITY_LOW,
474 (GSourceFunc)delay_update_background, p, NULL );
84fc1d55 475}
4542c20d 476
a52c2257 477static gint
22242ed4 478panel_size_req(GtkWidget *widget, GtkRequisition *req, Panel *p)
a52c2257
HJYP
479{
480 ENTER;
4542c20d 481
a52c2257
HJYP
482 if (p->widthtype == WIDTH_REQUEST)
483 p->width = (p->orientation == ORIENT_HORIZ) ? req->width : req->height;
484 if (p->heighttype == HEIGHT_REQUEST)
485 p->height = (p->orientation == ORIENT_HORIZ) ? req->height : req->width;
486 calculate_position(p);
487 req->width = p->aw;
488 req->height = p->ah;
4542c20d 489
a52c2257
HJYP
490 RET( TRUE );
491}
492
493static gint
22242ed4 494panel_size_alloc(GtkWidget *widget, GtkAllocation *a, Panel *p)
a52c2257
HJYP
495{
496 ENTER;
a52c2257
HJYP
497 if (p->widthtype == WIDTH_REQUEST)
498 p->width = (p->orientation == ORIENT_HORIZ) ? a->width : a->height;
499 if (p->heighttype == HEIGHT_REQUEST)
500 p->height = (p->orientation == ORIENT_HORIZ) ? a->height : a->width;
501 calculate_position(p);
4542c20d 502
a52c2257 503 if (a->width == p->aw && a->height == p->ah && a->x == p->ax && a->y == p ->ay) {
a52c2257
HJYP
504 RET(TRUE);
505 }
506
507 gtk_window_move(GTK_WINDOW(p->topgwin), p->ax, p->ay);
bee4c26e 508 panel_set_wm_strut(p);
a52c2257
HJYP
509 RET(TRUE);
510}
511
a52c2257 512static gboolean
22242ed4 513panel_configure_event (GtkWidget *widget, GdkEventConfigure *e, Panel *p)
a52c2257
HJYP
514{
515 ENTER;
516 if (e->width == p->cw && e->height == p->ch && e->x == p->cx && e->y == p->cy)
517 RET(TRUE);
518 p->cw = e->width;
519 p->ch = e->height;
520 p->cx = e->x;
521 p->cy = e->y;
4542c20d 522
a52c2257
HJYP
523 if (p->transparent)
524 fb_bg_notify_changed_bg(p->bg);
bee4c26e 525
4542c20d 526 RET(FALSE);
a52c2257
HJYP
527}
528
fddae119
FC
529static gint
530panel_popupmenu_configure(GtkWidget *widget, gpointer user_data)
531{
4b93d81e
HJYP
532 panel_configure( (Panel*)user_data, 0 );
533 return TRUE;
fddae119
FC
534}
535
9dd114c4 536/* Handler for "button_press_event" signal with Panel as parameter. */
537static gboolean panel_button_press_event_with_panel(GtkWidget *widget, GdkEventButton *event, Panel *panel)
fddae119 538{
9dd114c4 539 if (event->button == 3) /* right button */
540 {
541 GtkMenu* popup = (GtkMenu*) lxpanel_get_panel_menu(panel, NULL, FALSE);
542 gtk_menu_popup(popup, NULL, NULL, NULL, NULL, event->button, event->time);
543 return TRUE;
544 }
fddae119
FC
545 return FALSE;
546}
547
cf701cb7
HJYP
548static void panel_popupmenu_config_plugin( GtkMenuItem* item, Plugin* plugin )
549{
e3b89f43 550 plugin->class->config( plugin, GTK_WINDOW(plugin->panel->topgwin) );
930af9fd
HJYP
551
552 /* FIXME: this should be more elegant */
553 plugin->panel->config_changed = TRUE;
cf701cb7
HJYP
554}
555
4b93d81e
HJYP
556static void panel_popupmenu_add_item( GtkMenuItem* item, Panel* panel )
557{
558 /* panel_add_plugin( panel, panel->topgwin ); */
8d8b66da 559 panel_configure( panel, 2 );
cf701cb7
HJYP
560}
561
562static void panel_popupmenu_remove_item( GtkMenuItem* item, Plugin* plugin )
563{
564 Panel* panel = plugin->panel;
565 panel->plugins = g_list_remove( panel->plugins, plugin );
2918994e 566 plugin_delete(plugin);
4b93d81e 567 panel_config_save( plugin->panel );
cf701cb7
HJYP
568}
569
3e7b8eb7
HJYP
570/* FIXME: Potentially we can support multiple panels at the same edge,
571 * but currently this cannot be done due to some positioning problems. */
572static char* gen_panel_name( int edge )
573{
574 const char* edge_str = num2str( edge_pair, edge, "" );
575 char* name = NULL;
576 char* dir = get_config_file( cprofile, "panels", FALSE );
577 int i;
578 for( i = 0; i < G_MAXINT; ++i )
579 {
580 char* f;
581 if( G_LIKELY( i > 0 ) )
582 name = g_strdup_printf( "%s%d", edge_str, i );
583 else
584 name = g_strdup( edge_str );
585 f = g_build_filename( dir, name, NULL );
586 if( ! g_file_test( f, G_FILE_TEST_EXISTS ) )
587 {
588 g_free( f );
589 break;
590 }
591 g_free( name );
592 g_free( f );
593 }
594 g_free( dir );
595 return name;
596}
597
9dd114c4 598static void try_allocate_edge(Panel* p, int edge)
599{
600 if ((p->edge == EDGE_NONE) && (panel_edge_available(p, edge)))
601 p->edge = edge;
602}
603
3e7b8eb7
HJYP
604/* FIXME: Potentially we can support multiple panels at the same edge,
605 * but currently this cannot be done due to some positioning problems. */
cf701cb7
HJYP
606static void panel_popupmenu_create_panel( GtkMenuItem* item, Panel* panel )
607{
9dd114c4 608 Panel* new_panel = panel_allocate();
609
610 /* Allocate the edge. */
611 try_allocate_edge(new_panel, EDGE_BOTTOM);
612 try_allocate_edge(new_panel, EDGE_TOP);
613 try_allocate_edge(new_panel, EDGE_LEFT);
614 try_allocate_edge(new_panel, EDGE_RIGHT);
615 new_panel->name = gen_panel_name(new_panel->edge);
616
617 panel_configure(new_panel, 0);
618 panel_normalize_configuration(new_panel);
619 panel_start_gui(new_panel);
620 gtk_widget_show_all(new_panel->topgwin);
621
622 panel_config_save(new_panel);
623 all_panels = g_slist_prepend(all_panels, new_panel);
cf701cb7
HJYP
624}
625
626static void panel_popupmenu_delete_panel( GtkMenuItem* item, Panel* panel )
627{
628 GtkWidget* dlg;
629 gboolean ok;
e3b89f43 630 dlg = gtk_message_dialog_new_with_markup( GTK_WINDOW(panel->topgwin),
cf701cb7
HJYP
631 GTK_DIALOG_MODAL,
632 GTK_MESSAGE_QUESTION,
633 GTK_BUTTONS_OK_CANCEL,
634 _("Really delete this panel?\n<b>Warning: This can not be recovered.</b>") );
d1d43629 635 panel_apply_icon(GTK_WINDOW(dlg));
cf701cb7
HJYP
636 gtk_window_set_title( (GtkWindow*)dlg, _("Confirm") );
637 ok = ( gtk_dialog_run( (GtkDialog*)dlg ) == GTK_RESPONSE_OK );
638 gtk_widget_destroy( dlg );
639 if( ok )
640 {
4b93d81e 641 gchar *fname, *dir;
cf701cb7 642 all_panels = g_slist_remove( all_panels, panel );
4b93d81e
HJYP
643
644 /* delete the config file of this panel */
645 dir = get_config_file( cprofile, "panels", FALSE );
646 fname = g_build_filename( dir, panel->name, NULL );
647 g_free( dir );
648 g_unlink( fname );
930af9fd 649 panel->config_changed = 0;
cf701cb7
HJYP
650 panel_destroy( panel );
651 }
652}
653
e7a42ecf 654static void panel_popupmenu_about( GtkMenuItem* item, Panel* panel )
655{
656 GtkWidget *about;
657 const gchar* authors[] = {
658 "Hong Jen Yee (PCMan) <pcman.tw@gmail.com>",
659 "Jim Huang <jserv.tw@gmail.com>",
660 "Greg McNew <gmcnew@gmail.com> (battery plugin)",
661 "Fred Chien <cfsghost@gmail.com>",
662 "Daniel Kesler <kesler.daniel@gmail.com>",
663 "Juergen Hoetzel <juergen@archlinux.org>",
2918994e 664 "Marty Jack <martyj19@comcast.net>",
e7a42ecf 665 NULL
666 };
667 /* TRANSLATORS: Replace this string with your names, one name per line. */
668 gchar *translators = _( "translator-credits" );
669
670 about = gtk_about_dialog_new();
671 panel_apply_icon(GTK_WINDOW(about));
672 gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(about), VERSION);
673 gtk_about_dialog_set_name(GTK_ABOUT_DIALOG(about), _("LXPanel"));
674 gtk_about_dialog_set_logo(GTK_ABOUT_DIALOG(about), gdk_pixbuf_new_from_file(PACKAGE_DATA_DIR "/lxpanel/images/my-computer.png", NULL));
675 gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(about), _("Copyright (C) 2008-2009"));
676 gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(about), _( "Desktop panel for LXDE project"));
677 gtk_about_dialog_set_license(GTK_ABOUT_DIALOG(about), "This program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.");
678 gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(about), "http://lxde.org/");
679 gtk_about_dialog_set_authors(GTK_ABOUT_DIALOG(about), authors);
680 gtk_about_dialog_set_translator_credits(GTK_ABOUT_DIALOG(about), translators);
681 gtk_dialog_run(GTK_DIALOG(about));
682 gtk_widget_destroy(about);
683}
684
685void panel_apply_icon( GtkWindow *w )
686{
687 gtk_window_set_icon_from_file(w, PACKAGE_DATA_DIR "/lxpanel/images/my-computer.png", NULL);
688}
689
9dd114c4 690GtkMenu* lxpanel_get_panel_menu( Panel* panel, Plugin* plugin, gboolean use_sub_menu )
cf701cb7 691{
e3b89f43 692 GtkWidget *menu_item, *img;
693 GtkMenu *ret,*menu;
694
cf701cb7 695 char* tmp;
e3b89f43 696 ret = menu = GTK_MENU(gtk_menu_new());
cf701cb7 697
4b93d81e
HJYP
698 img = gtk_image_new_from_stock( GTK_STOCK_EDIT, GTK_ICON_SIZE_MENU );
699 menu_item = gtk_image_menu_item_new_with_label(_("Add / Remove Panel Items"));
700 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
701 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
702 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_add_item), panel );
cf701cb7
HJYP
703
704 if( plugin )
705 {
706 img = gtk_image_new_from_stock( GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU );
707 tmp = g_strdup_printf( _("Remove \"%s\" From Panel"), _(plugin->class->name) );
708 menu_item = gtk_image_menu_item_new_with_label( tmp );
709 g_free( tmp );
710 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
711 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
712 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_remove_item), plugin );
713 }
714
715 menu_item = gtk_separator_menu_item_new();
716 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
717
4b93d81e
HJYP
718 img = gtk_image_new_from_stock( GTK_STOCK_PREFERENCES, GTK_ICON_SIZE_MENU );
719 menu_item = gtk_image_menu_item_new_with_label(_("Panel Settings"));
720 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
721 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
722 g_signal_connect(G_OBJECT(menu_item), "activate", G_CALLBACK(panel_popupmenu_configure), panel );
723
cf701cb7
HJYP
724 img = gtk_image_new_from_stock( GTK_STOCK_NEW, GTK_ICON_SIZE_MENU );
725 menu_item = gtk_image_menu_item_new_with_label(_("Create New Panel"));
726 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
727 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
728 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_create_panel), panel );
3e7b8eb7
HJYP
729 /* FIXME: Potentially we can support multiple panels at the same edge,
730 * but currently this cannot be done due to some positioning problems. */
731 /* currently, disable the option when there are already four panels */
732 if( g_slist_length( all_panels ) >= 4 )
733 gtk_widget_set_sensitive( menu_item, FALSE );
cf701cb7
HJYP
734
735 img = gtk_image_new_from_stock( GTK_STOCK_DELETE, GTK_ICON_SIZE_MENU );
736 menu_item = gtk_image_menu_item_new_with_label(_("Delete This Panel"));
737 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
738 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
739 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_delete_panel), panel );
740 if( ! all_panels->next ) /* if this is the only panel */
741 gtk_widget_set_sensitive( menu_item, FALSE );
742
e7a42ecf 743 menu_item = gtk_separator_menu_item_new();
744 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
745
746 img = gtk_image_new_from_stock( GTK_STOCK_ABOUT, GTK_ICON_SIZE_MENU );
747 menu_item = gtk_image_menu_item_new_with_label(_("About"));
748 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
749 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
750 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_about), panel );
751
cf701cb7
HJYP
752 if( use_sub_menu )
753 {
e3b89f43 754 ret = GTK_MENU(gtk_menu_new());
cf701cb7
HJYP
755 menu_item = gtk_image_menu_item_new_with_label(_("Panel"));
756 gtk_menu_shell_append(GTK_MENU_SHELL(ret), menu_item);
e3b89f43 757 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), GTK_WIDGET(menu) );
cf701cb7 758
e3b89f43 759 gtk_widget_show_all(GTK_WIDGET(ret));
cf701cb7
HJYP
760 }
761
3e7b8eb7
HJYP
762 if( plugin )
763 {
764 menu_item = gtk_separator_menu_item_new();
765 gtk_menu_shell_prepend(GTK_MENU_SHELL(ret), menu_item);
766
767 img = gtk_image_new_from_stock( GTK_STOCK_PREFERENCES, GTK_ICON_SIZE_MENU );
768 tmp = g_strdup_printf( _("\"%s\" Settings"), _(plugin->class->name) );
769 menu_item = gtk_image_menu_item_new_with_label( tmp );
770 g_free( tmp );
771 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
772 gtk_menu_shell_prepend(GTK_MENU_SHELL(ret), menu_item);
773 if( plugin->class->config )
774 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_config_plugin), plugin );
775 else
776 gtk_widget_set_sensitive( menu_item, FALSE );
777 }
778
e3b89f43 779 gtk_widget_show_all(GTK_WIDGET(menu));
3e7b8eb7 780
cf701cb7
HJYP
781 g_signal_connect( ret, "selection-done", G_CALLBACK(gtk_widget_destroy), NULL );
782 return ret;
783}
784
a52c2257
HJYP
785/****************************************************
786 * panel creation *
787 ****************************************************/
176fb687 788
a52c2257 789static void
22242ed4 790make_round_corners(Panel *p)
a52c2257 791{
a97d06a6 792 /* FIXME: This should be re-written with shape extension of X11 */
4542c20d 793 /* gdk_window_shape_combine_mask() can be used */
bee4c26e
HJYP
794}
795
22242ed4 796void panel_set_dock_type(Panel *p)
bee4c26e
HJYP
797{
798 if (p->setdocktype) {
799 Atom state = a_NET_WM_WINDOW_TYPE_DOCK;
800 XChangeProperty(GDK_DISPLAY(), p->topxwin,
801 a_NET_WM_WINDOW_TYPE, XA_ATOM, 32,
802 PropModeReplace, (unsigned char *) &state, 1);
803 }
804 else {
805 XDeleteProperty( GDK_DISPLAY(), p->topxwin, a_NET_WM_WINDOW_TYPE );
806 }
a52c2257
HJYP
807}
808
176fb687 809static void panel_set_visibility(Panel *p, gboolean visible)
810{
811 if ( ! visible) gtk_widget_hide(p->box);
812 p->visible = visible;
813 calculate_position(p);
814 gtk_widget_set_size_request(p->topgwin, p->aw, p->ah);
815 gdk_window_move(p->topgwin->window, p->ax, p->ay);
816 if (visible) gtk_widget_show(p->box);
817 panel_set_wm_strut(p);
818}
819
820static gboolean panel_leave_real(Panel *p)
821{
fab48ed0 822 /* If the pointer is grabbed by this application, leave the panel displayed.
823 * There is no way to determine if it is grabbed by another application, such as an application that has a systray icon. */
176fb687 824 if (gdk_display_pointer_is_grabbed(p->display))
825 return TRUE;
826
fab48ed0 827 /* If the pointer is inside the panel, leave the panel displayed. */
176fb687 828 gint x, y;
829 gdk_display_get_pointer(p->display, NULL, &x, &y, NULL);
830 if ((p->cx <= x) && (x <= (p->cx + p->cw)) && (p->cy <= y) && (y <= (p->cy + p->ch)))
831 return TRUE;
832
fab48ed0 833 /* If the panel is configured to autohide and if it is visible, hide the panel. */
176fb687 834 if ((p->autohide) && (p->visible))
835 panel_set_visibility(p, FALSE);
836
fab48ed0 837 /* Clear the timer. */
176fb687 838 p->hide_timeout = 0;
839 return FALSE;
840}
841
842static gboolean panel_enter(GtkImage *widget, GdkEventCrossing *event, Panel *p)
843{
fab48ed0 844 /* We may receive multiple enter-notify events when the pointer crosses into the panel.
845 * Do extra tests to make sure this does not cause misoperation such as blinking.
846 * If the pointer is inside the panel, unhide it. */
847 gint x, y;
848 gdk_display_get_pointer(p->display, NULL, &x, &y, NULL);
849 if ((p->cx <= x) && (x <= (p->cx + p->cw)) && (p->cy <= y) && (y <= (p->cy + p->ch)))
850 {
851 /* If the pointer is inside the panel and we have not already unhidden it, do so and
852 * set a timer to recheck it in a half second. */
853 if (p->hide_timeout == 0)
854 {
855 p->hide_timeout = g_timeout_add(500, (GSourceFunc) panel_leave_real, p);
856 panel_set_visibility(p, TRUE);
857 }
858 }
859 else
860 {
861 /* If the pointer is not inside the panel, simulate a timer expiration. */
862 panel_leave_real(p);
863 }
176fb687 864 return TRUE;
865}
866
867static gboolean panel_drag_motion(GtkWidget *widget, GdkDragContext *drag_context, gint x,
868 gint y, guint time, Panel *p)
869{
870 panel_enter(NULL, NULL, p);
871 return TRUE;
872}
873
874void panel_establish_autohide(Panel *p)
875{
876 if (p->autohide)
877 {
878 gtk_widget_add_events(p->topgwin, GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK);
879 g_signal_connect(G_OBJECT(p->topgwin), "enter-notify-event", G_CALLBACK(panel_enter), p);
880 g_signal_connect(G_OBJECT(p->topgwin), "drag-motion", (GCallback) panel_drag_motion, p);
881 gtk_drag_dest_set(p->topgwin, GTK_DEST_DEFAULT_MOTION, NULL, 0, 0);
882 gtk_drag_dest_set_track_motion(p->topgwin, TRUE);
883 panel_enter(NULL, NULL, p);
884 }
885 else if ( ! p->visible)
886 {
887 gtk_widget_show(p->box);
888 p->visible = TRUE;
889 }
890}
891
8f9e6256 892/* Set an image from a file with scaling to the panel icon size. */
893void panel_image_set_from_file(Panel * p, GtkWidget * image, char * file)
894{
895 GdkPixbuf * pixbuf = gdk_pixbuf_new_from_file_at_scale(file, p->icon_size, p->icon_size, TRUE, NULL);
896 if (pixbuf != NULL)
897 {
898 gtk_image_set_from_pixbuf(GTK_IMAGE(image), pixbuf);
899 g_object_unref(pixbuf);
900 }
901}
902
0defe4b9 903static void
22242ed4 904panel_start_gui(Panel *p)
a52c2257
HJYP
905{
906 Atom state[3];
907 XWMHints wmhints;
908 guint32 val;
6db11841 909
a52c2257
HJYP
910 ENTER;
911
9dd114c4 912 p->curdesk = get_net_current_desktop();
913 p->desknum = get_net_number_of_desktops();
914 p->workarea = get_xaproperty (GDK_ROOT_WINDOW(), a_NET_WORKAREA, XA_CARDINAL, &p->wa_len);
915
cb22c87c
HJYP
916 /* main toplevel window */
917 /* p->topgwin = gtk_window_new(GTK_WINDOW_TOPLEVEL); */
918 p->topgwin = (GtkWidget*)g_object_new(PANEL_TOPLEVEL_TYPE, NULL);
919 gtk_widget_set_name(p->topgwin, "PanelToplevel");
176fb687 920 p->display = gdk_display_get_default();
a52c2257
HJYP
921 gtk_container_set_border_width(GTK_CONTAINER(p->topgwin), 0);
922 gtk_window_set_resizable(GTK_WINDOW(p->topgwin), FALSE);
923 gtk_window_set_wmclass(GTK_WINDOW(p->topgwin), "panel", "lxpanel");
924 gtk_window_set_title(GTK_WINDOW(p->topgwin), "panel");
925 gtk_window_set_position(GTK_WINDOW(p->topgwin), GTK_WIN_POS_NONE);
926 gtk_window_set_decorated(GTK_WINDOW(p->topgwin), FALSE);
77886b88 927
e2957bd2
HJYP
928 gtk_window_group_add_window( win_grp, (GtkWindow*)p->topgwin );
929
a52c2257
HJYP
930 g_signal_connect(G_OBJECT(p->topgwin), "delete-event",
931 G_CALLBACK(panel_delete_event), p);
932 g_signal_connect(G_OBJECT(p->topgwin), "destroy-event",
933 G_CALLBACK(panel_destroy_event), p);
934 g_signal_connect (G_OBJECT (p->topgwin), "size-request",
935 (GCallback) panel_size_req, p);
936 g_signal_connect (G_OBJECT (p->topgwin), "size-allocate",
937 (GCallback) panel_size_alloc, p);
938 g_signal_connect (G_OBJECT (p->topgwin), "configure-event",
939 (GCallback) panel_configure_event, p);
3e7b8eb7
HJYP
940
941 gtk_widget_add_events( p->topgwin, GDK_BUTTON_PRESS_MASK );
fddae119 942 g_signal_connect(G_OBJECT (p->topgwin), "button_press_event",
9dd114c4 943 (GCallback) panel_button_press_event_with_panel, p);
f2d54481 944
a52c2257
HJYP
945 g_signal_connect (G_OBJECT (p->topgwin), "realize",
946 (GCallback) panel_realize, p);
f2d54481 947
84fc1d55
HJYP
948 g_signal_connect (G_OBJECT (p->topgwin), "style-set",
949 (GCallback)panel_style_set, p);
a52c2257
HJYP
950 gtk_widget_realize(p->topgwin);
951 //gdk_window_set_decorations(p->topgwin->window, 0);
2de71c90 952
4542c20d 953 // main layout manager as a single child of panel
a97d06a6 954 p->box = p->my_box_new(FALSE, 0);
a52c2257 955 gtk_container_set_border_width(GTK_CONTAINER(p->box), 0);
4542c20d
HJYP
956// gtk_container_add(GTK_CONTAINER(p->bbox), p->box);
957 gtk_container_add(GTK_CONTAINER(p->topgwin), p->box);
a52c2257 958 gtk_widget_show(p->box);
a97d06a6
HJYP
959 if (p->round_corners)
960 make_round_corners(p);
6db11841 961
a52c2257
HJYP
962 p->topxwin = GDK_WINDOW_XWINDOW(GTK_WIDGET(p->topgwin)->window);
963 DBG("topxwin = %x\n", p->topxwin);
964
965 /* the settings that should be done before window is mapped */
966 wmhints.flags = InputHint;
967 wmhints.input = 0;
bee4c26e 968 XSetWMHints (GDK_DISPLAY(), p->topxwin, &wmhints);
24053345 969#define WIN_HINTS_SKIP_FOCUS (1<<0) /* "alt-tab" skips this win */
a52c2257
HJYP
970 val = WIN_HINTS_SKIP_FOCUS;
971 XChangeProperty(GDK_DISPLAY(), p->topxwin,
972 XInternAtom(GDK_DISPLAY(), "_WIN_HINTS", False), XA_CARDINAL, 32,
973 PropModeReplace, (unsigned char *) &val, 1);
974
bee4c26e 975 panel_set_dock_type(p);
a52c2257
HJYP
976
977 /* window mapping point */
978 gtk_widget_show_all(p->topgwin);
979
980 /* the settings that should be done after window is mapped */
176fb687 981 panel_establish_autohide(p);
a52c2257
HJYP
982
983 /* send it to running wm */
984 Xclimsg(p->topxwin, a_NET_WM_DESKTOP, 0xFFFFFFFF, 0, 0, 0, 0);
985 /* and assign it ourself just for case when wm is not running */
986 val = 0xFFFFFFFF;
987 XChangeProperty(GDK_DISPLAY(), p->topxwin, a_NET_WM_DESKTOP, XA_CARDINAL, 32,
988 PropModeReplace, (unsigned char *) &val, 1);
989
990 state[0] = a_NET_WM_STATE_SKIP_PAGER;
991 state[1] = a_NET_WM_STATE_SKIP_TASKBAR;
992 state[2] = a_NET_WM_STATE_STICKY;
993 XChangeProperty(GDK_DISPLAY(), p->topxwin, a_NET_WM_STATE, XA_ATOM,
994 32, PropModeReplace, (unsigned char *) state, 3);
995
a52c2257
HJYP
996 calculate_position(p);
997 gdk_window_move_resize(p->topgwin->window, p->ax, p->ay, p->aw, p->ah);
bee4c26e 998 panel_set_wm_strut(p);
77886b88 999
a52c2257
HJYP
1000 RET();
1001}
1002
2918994e 1003/* Exchange the "width" and "height" terminology for vertical and horizontal panels. */
1004void panel_adjust_geometry_terminology(Panel * p)
9dd114c4 1005{
8ed3b3d4 1006 if ((p->height_label != NULL) && (p->width_label != NULL)
1007 && (p->alignment_left_label != NULL) && (p->alignment_right_label != NULL))
9dd114c4 1008 {
1009 if ((p->edge == EDGE_TOP) || (p->edge == EDGE_BOTTOM))
1010 {
1011 gtk_label_set_text(GTK_LABEL(p->height_label), _("Height:"));
1012 gtk_label_set_text(GTK_LABEL(p->width_label), _("Width:"));
2918994e 1013 gtk_button_set_label(GTK_BUTTON(p->alignment_left_label), _("Left"));
1014 gtk_button_set_label(GTK_BUTTON(p->alignment_right_label), _("Right"));
9dd114c4 1015 }
1016 else
1017 {
1018 gtk_label_set_text(GTK_LABEL(p->height_label), _("Width:"));
1019 gtk_label_set_text(GTK_LABEL(p->width_label), _("Height:"));
2918994e 1020 gtk_button_set_label(GTK_BUTTON(p->alignment_left_label), _("Top"));
1021 gtk_button_set_label(GTK_BUTTON(p->alignment_right_label), _("Bottom"));
9dd114c4 1022 }
1023 }
1024}
1025
2918994e 1026/* Draw text into a label, with the user preference color and optionally bold. */
6835a23e 1027void panel_draw_label_text(Panel * p, GtkWidget * label, char * text, gboolean bold, gboolean custom_color)
2918994e 1028{
1029 char buffer[512];
1030
1031 if (text == NULL)
1032 {
1033 /* Null string. */
1034 gtk_label_set_text(GTK_LABEL(label), NULL);
1035 }
1036
f669ce5e 1037 else
2918994e 1038 {
f669ce5e 1039 /* Compute an appropriate size so the font will scale with the panel's icon size. */
1040 int font_desc;
1041 if (p->icon_size < 20)
1042 font_desc = 9;
1043 else if (p->icon_size >= 20 && p->icon_size < 26)
1044 font_desc = 10;
f669ce5e 1045 else
ee4695be 1046 font_desc = 12;
2918994e 1047
1048 /* Check the string for characters that need to be escaped.
1049 * If any are found, create the properly escaped string and use it instead. */
f669ce5e 1050 char * valid_markup = text;
1051 char * escaped_text = NULL;
2918994e 1052 char * q;
1053 for (q = text; *q != '\0'; q += 1)
1054 {
1055 if ((*q == '<') || (*q == '>') || (*q == '&'))
1056 {
1057 escaped_text = g_markup_escape_text(text, -1);
1058 valid_markup = escaped_text;
1059 break;
1060 }
1061 }
1062
6835a23e 1063 if ((custom_color) && (p->usefontcolor))
2918994e 1064 {
1065 /* Color, optionally bold. */
f669ce5e 1066 g_snprintf(buffer, sizeof(buffer), "<span font_desc=\"%d\" color=\"#%06x\">%s%s%s</span>",
1067 font_desc,
2918994e 1068 gcolor2rgb24(&p->gfontcolor),
1069 ((bold) ? "<b>" : ""),
1070 valid_markup,
1071 ((bold) ? "</b>" : ""));
1072 gtk_label_set_markup(GTK_LABEL(label), buffer);
1073 }
f669ce5e 1074 else
2918994e 1075 {
f669ce5e 1076 /* No color, optionally bold. */
1077 g_snprintf(buffer, sizeof(buffer), "<span font_desc=\"%d\">%s%s%s</span>",
1078 font_desc,
1079 ((bold) ? "<b>" : ""),
1080 valid_markup,
1081 ((bold) ? "</b>" : ""));
2918994e 1082 gtk_label_set_markup(GTK_LABEL(label), buffer);
1083 }
1084 g_free(escaped_text);
1085 }
2918994e 1086}
1087
1088void panel_set_panel_configuration_changed(Panel *p)
a97d06a6
HJYP
1089{
1090 GList* l;
9dd114c4 1091
1092 int previous_orientation = p->orientation;
a97d06a6
HJYP
1093 p->orientation = (p->edge == EDGE_TOP || p->edge == EDGE_BOTTOM)
1094 ? ORIENT_HORIZ : ORIENT_VERT;
9dd114c4 1095
1096 if (previous_orientation != p->orientation)
1097 {
1098 panel_adjust_geometry_terminology(p);
1b0b2df6 1099 if (previous_orientation != ORIENT_NONE)
1100 p->height = ((p->orientation == ORIENT_HORIZ) ? PANEL_HEIGHT_DEFAULT : PANEL_WIDTH_DEFAULT);
9dd114c4 1101 if (p->height_control != NULL)
1102 gtk_spin_button_set_value(GTK_SPIN_BUTTON(p->height_control), p->height);
2918994e 1103 if ((p->widthtype == WIDTH_PIXEL) && (p->width_control != NULL))
1104 {
1105 int value = ((p->orientation == ORIENT_HORIZ) ? gdk_screen_width() : gdk_screen_height());
1106 gtk_spin_button_set_range(GTK_SPIN_BUTTON(p->width_control), 0, value);
1107 gtk_spin_button_set_value(GTK_SPIN_BUTTON(p->width_control), value);
1108 }
1109
9dd114c4 1110 }
1111
a97d06a6
HJYP
1112 if (p->orientation == ORIENT_HORIZ) {
1113 p->my_box_new = gtk_hbox_new;
1114 p->my_separator_new = gtk_vseparator_new;
1115 } else {
1116 p->my_box_new = gtk_vbox_new;
1117 p->my_separator_new = gtk_hseparator_new;
1118 }
1119
1120 /* recreate the main layout box */
964b8b7e 1121 if (p->box != NULL)
1122 {
1123#if GTK_CHECK_VERSION(2,16,0)
1124 GtkOrientation bo = (p->orientation == ORIENT_HORIZ) ? GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL;
1125 gtk_orientable_set_orientation(GTK_ORIENTABLE(p->box), bo);
1126#else
1127 GtkBox * newbox = GTK_BOX(recreate_box(GTK_BOX(p->box), p->orientation));
1128 if (GTK_WIDGET(newbox) != p->box)
1129 {
5a343ad5 1130 p->box = GTK_WIDGET(newbox);
964b8b7e 1131 gtk_container_add(GTK_CONTAINER(p->topgwin), GTK_WIDGET(newbox));
a97d06a6 1132 }
964b8b7e 1133#endif
a97d06a6 1134 }
9dd114c4 1135
a97d06a6
HJYP
1136 /* NOTE: This loop won't be executed when panel started since
1137 plugins are not loaded at that time.
1138 This is used when the orientation of the panel is changed
1139 from the config dialog, and plugins should be re-layout.
1140 */
1141 for( l = p->plugins; l; l = l->next ) {
22242ed4 1142 Plugin* pl = (Plugin*)l->data;
2918994e 1143 if( pl->class->panel_configuration_changed ) {
1144 pl->class->panel_configuration_changed( pl );
a97d06a6
HJYP
1145 }
1146 }
1147}
1148
a52c2257 1149static int
22242ed4 1150panel_parse_global(Panel *p, char **fp)
a52c2257
HJYP
1151{
1152 line s;
1153 s.len = 256;
6db11841 1154
3e7b8eb7
HJYP
1155 if( G_LIKELY( fp ) )
1156 {
1157 while (lxpanel_get_line(fp, &s) != LINE_NONE) {
1158 if (s.type == LINE_VAR) {
1159 if (!g_ascii_strcasecmp(s.t[0], "edge")) {
1160 p->edge = str2num(edge_pair, s.t[1], EDGE_NONE);
1161 } else if (!g_ascii_strcasecmp(s.t[0], "allign")) {
1162 p->allign = str2num(allign_pair, s.t[1], ALLIGN_NONE);
1163 } else if (!g_ascii_strcasecmp(s.t[0], "margin")) {
1164 p->margin = atoi(s.t[1]);
1165 } else if (!g_ascii_strcasecmp(s.t[0], "widthtype")) {
1166 p->widthtype = str2num(width_pair, s.t[1], WIDTH_NONE);
1167 } else if (!g_ascii_strcasecmp(s.t[0], "width")) {
1168 p->width = atoi(s.t[1]);
1169 } else if (!g_ascii_strcasecmp(s.t[0], "heighttype")) {
1170 p->heighttype = str2num(height_pair, s.t[1], HEIGHT_NONE);
1171 } else if (!g_ascii_strcasecmp(s.t[0], "height")) {
1172 p->height = atoi(s.t[1]);
1173 } else if (!g_ascii_strcasecmp(s.t[0], "spacing")) {
1174 p->spacing = atoi(s.t[1]);
1175 } else if (!g_ascii_strcasecmp(s.t[0], "SetDockType")) {
1176 p->setdocktype = str2num(bool_pair, s.t[1], 0);
1177 } else if (!g_ascii_strcasecmp(s.t[0], "SetPartialStrut")) {
1178 p->setstrut = str2num(bool_pair, s.t[1], 0);
1179 } else if (!g_ascii_strcasecmp(s.t[0], "RoundCorners")) {
1180 p->round_corners = str2num(bool_pair, s.t[1], 0);
1181 } else if (!g_ascii_strcasecmp(s.t[0], "Transparent")) {
1182 p->transparent = str2num(bool_pair, s.t[1], 0);
1183 } else if (!g_ascii_strcasecmp(s.t[0], "Alpha")) {
1184 p->alpha = atoi(s.t[1]);
1185 if (p->alpha > 255)
1186 p->alpha = 255;
176fb687 1187 } else if (!g_ascii_strcasecmp(s.t[0], "AutoHide")) {
1188 p->autohide = str2num(bool_pair, s.t[1], 0);
1189 } else if (!g_ascii_strcasecmp(s.t[0], "HeightWhenHidden")) {
1190 p->height_when_hidden = atoi(s.t[1]);
3e7b8eb7
HJYP
1191 } else if (!g_ascii_strcasecmp(s.t[0], "TintColor")) {
1192 if (!gdk_color_parse (s.t[1], &p->gtintcolor))
1193 gdk_color_parse ("white", &p->gtintcolor);
1194 p->tintcolor = gcolor2rgb24(&p->gtintcolor);
1195 DBG("tintcolor=%x\n", p->tintcolor);
1196 } else if (!g_ascii_strcasecmp(s.t[0], "useFontColor")) {
1197 p->usefontcolor = str2num(bool_pair, s.t[1], 0);
1198 } else if (!g_ascii_strcasecmp(s.t[0], "FontColor")) {
1199 if (!gdk_color_parse (s.t[1], &p->gfontcolor))
1200 gdk_color_parse ("black", &p->gfontcolor);
1201 p->fontcolor = gcolor2rgb24(&p->gfontcolor);
1202 DBG("fontcolor=%x\n", p->fontcolor);
1203 } else if (!g_ascii_strcasecmp(s.t[0], "Background")) {
1204 p->background = str2num(bool_pair, s.t[1], 0);
1205 } else if( !g_ascii_strcasecmp(s.t[0], "BackgroundFile") ) {
1206 p->background_file = g_strdup( s.t[1] );
8f9e6256 1207 } else if (!g_ascii_strcasecmp(s.t[0], "IconSize")) {
1208 p->icon_size = atoi(s.t[1]);
3e7b8eb7
HJYP
1209 } else {
1210 ERR( "lxpanel: %s - unknown var in Global section\n", s.t[0]);
3e7b8eb7
HJYP
1211 }
1212 } else if (s.type == LINE_BLOCK_END) {
1213 break;
a52c2257 1214 } else {
3e7b8eb7 1215 ERR( "lxpanel: illegal in this context %s\n", s.str);
a52c2257
HJYP
1216 RET(0);
1217 }
a52c2257
HJYP
1218 }
1219 }
4542c20d 1220
9dd114c4 1221 panel_normalize_configuration(p);
239cb032 1222
9dd114c4 1223 return 1;
a52c2257
HJYP
1224}
1225
1226static int
22242ed4 1227panel_parse_plugin(Panel *p, char **fp)
a52c2257
HJYP
1228{
1229 line s;
22242ed4 1230 Plugin *plug = NULL;
a52c2257 1231 gchar *type = NULL;
a52c2257 1232 int expand , padding, border;
db449f6e
HJYP
1233 char* pconfig = NULL;
1234
a52c2257
HJYP
1235 ENTER;
1236 s.len = 256;
a52c2257 1237 border = expand = padding = 0;
c69ac68e 1238 while (lxpanel_get_line(fp, &s) != LINE_BLOCK_END) {
a52c2257
HJYP
1239 if (s.type == LINE_NONE) {
1240 ERR( "lxpanel: bad line %s\n", s.str);
1241 goto error;
1242 }
1243 if (s.type == LINE_VAR) {
1244 if (!g_ascii_strcasecmp(s.t[0], "type")) {
1245 type = g_strdup(s.t[1]);
1246 DBG("plug %s\n", type);
1247 } else if (!g_ascii_strcasecmp(s.t[0], "expand"))
1248 expand = str2num(bool_pair, s.t[1], 0);
1249 else if (!g_ascii_strcasecmp(s.t[0], "padding"))
1250 padding = atoi(s.t[1]);
1251 else if (!g_ascii_strcasecmp(s.t[0], "border"))
1252 border = atoi(s.t[1]);
1253 else {
1254 ERR( "lxpanel: unknown var %s\n", s.t[0]);
a52c2257
HJYP
1255 }
1256 } else if (s.type == LINE_BLOCK_START) {
1257 if (!g_ascii_strcasecmp(s.t[0], "Config")) {
db449f6e 1258 pconfig = *fp;
a52c2257
HJYP
1259 int pno = 1;
1260 while (pno) {
1261 get_line_as_is(fp, &s);
1262 if (s.type == LINE_NONE) {
1263 ERR( "lxpanel: unexpected eof\n");
1264 goto error;
1265 } else if (s.type == LINE_BLOCK_START) {
1266 pno++;
1267 } else if (s.type == LINE_BLOCK_END) {
1268 pno--;
bee4c26e 1269 }
db449f6e 1270 }
a52c2257
HJYP
1271 } else {
1272 ERR( "lxpanel: unknown block %s\n", s.t[0]);
1273 goto error;
1274 }
1275 } else {
1276 ERR( "lxpanel: illegal in this context %s\n", s.str);
1277 goto error;
1278 }
1279 }
db449f6e 1280
a52c2257
HJYP
1281 if (!type || !(plug = plugin_load(type))) {
1282 ERR( "lxpanel: can't load %s plugin\n", type);
1283 goto error;
1284 }
db449f6e 1285
a52c2257 1286 plug->panel = p;
2918994e 1287 if (plug->class->expand_available) plug->expand = expand;
a52c2257
HJYP
1288 plug->padding = padding;
1289 plug->border = border;
a52c2257 1290 DBG("starting\n");
db449f6e 1291 if (!plugin_start(plug, pconfig ? &pconfig : NULL)) {
a52c2257
HJYP
1292 ERR( "lxpanel: can't start plugin %s\n", type);
1293 goto error;
1294 }
1295 DBG("plug %s\n", type);
1296 p->plugins = g_list_append(p->plugins, plug);
0dcb6bf5
HJYP
1297
1298 g_free( type );
a52c2257 1299 RET(1);
db449f6e 1300
a52c2257 1301 error:
2918994e 1302 if (plug != NULL)
1303 plugin_unload(plug);
a52c2257 1304 g_free(type);
a52c2257 1305 RET(0);
a52c2257
HJYP
1306}
1307
3e7b8eb7 1308int panel_start( Panel *p, char **fp )
a52c2257
HJYP
1309{
1310 line s;
db449f6e 1311
a52c2257
HJYP
1312 /* parse global section */
1313 ENTER;
1314 s.len = 256;
8110399f 1315
c69ac68e 1316 if ((lxpanel_get_line(fp, &s) != LINE_BLOCK_START) || g_ascii_strcasecmp(s.t[0], "Global")) {
a52c2257
HJYP
1317 ERR( "lxpanel: config file must start from Global section\n");
1318 RET(0);
1319 }
1320 if (!panel_parse_global(p, fp))
1321 RET(0);
1322
9dd114c4 1323 panel_start_gui(p);
1324
c69ac68e 1325 while (lxpanel_get_line(fp, &s) != LINE_NONE) {
a52c2257
HJYP
1326 if ((s.type != LINE_BLOCK_START) || g_ascii_strcasecmp(s.t[0], "Plugin")) {
1327 ERR( "lxpanel: expecting Plugin section\n");
1328 RET(0);
1329 }
9939506e 1330 panel_parse_plugin(p, fp);
a52c2257 1331 }
4542c20d
HJYP
1332
1333 /* update backgrond of panel and all plugins */
1334 panel_update_background( p );
9dd114c4 1335 return 1;
a52c2257
HJYP
1336}
1337
1338static void
1339delete_plugin(gpointer data, gpointer udata)
1340{
2918994e 1341 plugin_delete((Plugin *)data);
a52c2257
HJYP
1342}
1343
8110399f 1344void panel_destroy(Panel *p)
a52c2257
HJYP
1345{
1346 ENTER;
1347
2918994e 1348 if (p->pref_dialog != NULL)
1349 gtk_widget_destroy(p->pref_dialog);
1350 if (p->plugin_pref_dialog != NULL)
1351 {
1352 gtk_widget_destroy(p->plugin_pref_dialog);
1353 p->plugin_pref_dialog = NULL;
1354 }
1355
1356 if (p->bg != NULL)
1357 {
1358 g_signal_handlers_disconnect_by_func(G_OBJECT(p->bg), on_root_bg_changed, p);
1359 g_object_unref(p->bg);
1360 }
1361
930af9fd
HJYP
1362 if( p->config_changed )
1363 panel_config_save( p );
1364
a52c2257
HJYP
1365 g_list_foreach(p->plugins, delete_plugin, NULL);
1366 g_list_free(p->plugins);
1367 p->plugins = NULL;
8c44345a 1368
5297da29 1369 if( p->system_menus ){
8c44345a 1370 do{
5297da29 1371 } while ( g_source_remove_by_user_data( p->system_menus ) );
8c44345a
HJYP
1372 }
1373
16fbda14 1374 gtk_window_group_remove_window( win_grp, GTK_WINDOW( p->topgwin ) );
e2957bd2 1375
4b93d81e
HJYP
1376 if( p->topgwin )
1377 gtk_widget_destroy(p->topgwin);
a52c2257 1378 g_free(p->workarea);
2de71c90 1379 g_free( p->background_file );
5297da29 1380 g_slist_free( p->system_menus );
a52c2257
HJYP
1381 gdk_flush();
1382 XFlush(GDK_DISPLAY());
1383 XSync(GDK_DISPLAY(), True);
8110399f
HJYP
1384
1385 g_free( p->name );
2918994e 1386 g_free(p);
a52c2257
HJYP
1387 RET();
1388}
1389
8110399f
HJYP
1390Panel* panel_new( const char* config_file, const char* config_name )
1391{
1392 char *fp, *pfp; /* point to current position of profile data in memory */
cf701cb7 1393 Panel* panel = NULL;
16fbda14 1394
3e7b8eb7 1395 if( G_LIKELY(config_file) )
cf701cb7 1396 {
3e7b8eb7
HJYP
1397 g_file_get_contents( config_file, &fp, NULL, NULL );
1398 if( fp )
1399 {
9dd114c4 1400 panel = panel_allocate();
8ed3b3d4 1401 panel->orientation = ORIENT_NONE;
3e7b8eb7
HJYP
1402 panel->name = g_strdup( config_name );
1403 pfp = fp;
1404
1405 if (! panel_start( panel, &pfp )) {
1406 ERR( "lxpanel: can't start panel\n");
1407 panel_destroy( panel );
1408 panel = NULL;
1409 }
cf701cb7 1410
3e7b8eb7 1411 g_free( fp );
cf701cb7 1412 }
cf701cb7
HJYP
1413 }
1414 return panel;
8110399f 1415}
a52c2257 1416
0defe4b9 1417static void
a52c2257
HJYP
1418usage()
1419{
e7cb732b
HJYP
1420 g_print(_("lxpanel %s - lightweight GTK2+ panel for UNIX desktops\n"), version);
1421 g_print(_("Command line options:\n"));
1422 g_print(_(" --help -- print this help and exit\n"));
1423 g_print(_(" --version -- print version and exit\n"));
1424 g_print(_(" --log <number> -- set log level 0-5. 0 - none 5 - chatty\n"));
2918994e 1425// g_print(_(" --configure -- launch configuration utility\n"));
e7cb732b
HJYP
1426 g_print(_(" --profile name -- use specified profile\n"));
1427 g_print("\n");
1428 g_print(_(" -h -- same as --help\n"));
1429 g_print(_(" -p -- same as --profile\n"));
1430 g_print(_(" -v -- same as --version\n"));
2918994e 1431 // g_print(_(" -C -- same as --configure\n"));
b37c9aae 1432 g_print(_("\nVisit http://lxde.org/ for detail.\n\n"));
a52c2257
HJYP
1433}
1434
2918994e 1435int panel_handle_x_error(Display * d, XErrorEvent * ev)
a52c2257
HJYP
1436{
1437 char buf[256];
1438
a52c2257
HJYP
1439 if (log_level >= LOG_WARN) {
1440 XGetErrorText(GDK_DISPLAY(), ev->error_code, buf, 256);
1441 LOG(LOG_WARN, "lxpanel : X error: %s\n", buf);
1442 }
2918994e 1443 return 0; /* Ignored */
1444}
1445
1446int panel_handle_x_error_swallow_BadWindow_BadDrawable(Display * d, XErrorEvent * ev)
1447{
1448 if ((ev->error_code != BadWindow) && (ev->error_code != BadDrawable))
1449 panel_handle_x_error(d, ev);
1450 return 0; /* Ignored */
a52c2257
HJYP
1451}
1452
e68b47dc
JH
1453/* Lightweight lock related functions - X clipboard hacks */
1454
1455#define CLIPBOARD_NAME "LXPANEL_SELECTION"
1456
1457/*
1458 * clipboard_get_func - dummy get_func for gtk_clipboard_set_with_data ()
1459 */
1460static void
1461clipboard_get_func(
1462 GtkClipboard *clipboard G_GNUC_UNUSED,
1463 GtkSelectionData *selection_data G_GNUC_UNUSED,
1464 guint info G_GNUC_UNUSED,
1465 gpointer user_data_or_owner G_GNUC_UNUSED)
1466{
1467}
1468
1469/*
1470 * clipboard_clear_func - dummy clear_func for gtk_clipboard_set_with_data ()
1471 */
1472static void clipboard_clear_func(
1473 GtkClipboard *clipboard G_GNUC_UNUSED,
1474 gpointer user_data_or_owner G_GNUC_UNUSED)
1475{
1476}
1477
1478/*
1479 * Lightweight version for checking single instance.
1480 * Try and get the CLIPBOARD_NAME clipboard instead of using file manipulation.
1481 *
1482 * Returns TRUE if successfully retrieved and FALSE otherwise.
1483 */
16fb8c2e 1484static gboolean check_main_lock()
e68b47dc
JH
1485{
1486 static const GtkTargetEntry targets[] = { { CLIPBOARD_NAME, 0, 0 } };
1487 gboolean retval = FALSE;
1488 GtkClipboard *clipboard;
1489 Atom atom;
1490
1491 atom = gdk_x11_get_xatom_by_name(CLIPBOARD_NAME);
1492
1493 XGrabServer(GDK_DISPLAY());
1494
1495 if (XGetSelectionOwner(GDK_DISPLAY(), atom) != None)
1496 goto out;
1497
1498 clipboard = gtk_clipboard_get(gdk_atom_intern(CLIPBOARD_NAME, FALSE));
1499
1500 if (gtk_clipboard_set_with_data(clipboard, targets,
1501 G_N_ELEMENTS (targets),
1502 clipboard_get_func,
1503 clipboard_clear_func, NULL))
1504 retval = TRUE;
1505
1506out:
1507 XUngrabServer (GDK_DISPLAY ());
1508 gdk_flush ();
1509
1510 return retval;
1511}
1512#undef CLIPBOARD_NAME
1513
8110399f
HJYP
1514static gboolean start_all_panels( )
1515{
cf701cb7 1516 gboolean is_global;
4b93d81e 1517 for( is_global = 0; ! all_panels && is_global < 2; ++is_global )
cf701cb7
HJYP
1518 {
1519 char* panel_dir = get_config_file( cprofile, "panels", is_global );
1520 GDir* dir = g_dir_open( panel_dir, 0, NULL );
e3b89f43 1521 const gchar* name;
cf701cb7
HJYP
1522
1523 if( ! dir )
1524 {
1525 g_free( panel_dir );
1526 continue;
1527 }
1528
547ece89 1529 while((name = g_dir_read_name(dir)) != NULL)
cf701cb7
HJYP
1530 {
1531 char* panel_config = g_build_filename( panel_dir, name, NULL );
2918994e 1532 if (strchr(panel_config, '~') == NULL) /* Skip editor backup files in case user has hand edited in this directory */
1533 {
1534 Panel* panel = panel_new( panel_config, name );
1535 if( panel )
1536 all_panels = g_slist_prepend( all_panels, panel );
1537 }
cf701cb7
HJYP
1538 g_free( panel_config );
1539 }
1540 g_dir_close( dir );
1541 g_free( panel_dir );
1542 }
1543 return all_panels != NULL;
8110399f
HJYP
1544}
1545
cf701cb7
HJYP
1546void load_global_config();
1547void free_global_config();
1548
8110399f 1549int main(int argc, char *argv[], char *env[])
a52c2257
HJYP
1550{
1551 int i;
9df6826f 1552 const char* desktop_name;
f277dbb7 1553
a52c2257 1554 setlocale(LC_CTYPE, "");
f277dbb7 1555
1d434622
HJYP
1556 g_thread_init(NULL);
1557 gdk_threads_init();
1558
a52c2257
HJYP
1559 gtk_init(&argc, &argv);
1560
1561#ifdef ENABLE_NLS
1562 bindtextdomain ( GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR );
1563 bind_textdomain_codeset ( GETTEXT_PACKAGE, "UTF-8" );
1564 textdomain ( GETTEXT_PACKAGE );
1565#endif
1566
1567 XSetLocaleModifiers("");
2918994e 1568 XSetErrorHandler((XErrorHandler) panel_handle_x_error);
8110399f 1569
a52c2257 1570 resolve_atoms();
8110399f 1571
9df6826f
HJYP
1572 desktop_name = g_getenv("XDG_CURRENT_DESKTOP");
1573 is_in_lxde = desktop_name && (0 == strcmp(desktop_name, "LXDE"));
95095259 1574
a52c2257
HJYP
1575 for (i = 1; i < argc; i++) {
1576 if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
1577 usage();
1578 exit(0);
1579 } else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) {
1580 printf("lxpanel %s\n", version);
1581 exit(0);
1582 } else if (!strcmp(argv[i], "--log")) {
1583 i++;
1584 if (i == argc) {
1585 ERR( "lxpanel: missing log level\n");
1586 usage();
1587 exit(1);
1588 } else {
1589 log_level = atoi(argv[i]);
1590 }
1591 } else if (!strcmp(argv[i], "--configure") || !strcmp(argv[i], "-C")) {
1592 config = 1;
1593 } else if (!strcmp(argv[i], "--profile") || !strcmp(argv[i], "-p")) {
1594 i++;
1595 if (i == argc) {
1596 ERR( "lxpanel: missing profile name\n");
1597 usage();
1598 exit(1);
1599 } else {
1600 cprofile = g_strdup(argv[i]);
1601 }
1602 } else {
1603 printf("lxpanel: unknown option - %s\n", argv[i]);
1604 usage();
1605 exit(1);
1606 }
1607 }
f277dbb7 1608
8110399f 1609 /* Check for duplicated lxpanel instances */
e68b47dc 1610 if (!check_main_lock() && !config) {
e7a42ecf 1611 printf("There is already an instance of LXPanel. Now to exit\n");
e68b47dc
JH
1612 exit(1);
1613 }
1614
f277dbb7
HJYP
1615 /* Add our own icons to the search path of icon theme */
1616 gtk_icon_theme_append_search_path( gtk_icon_theme_get_default(),
1617 PACKAGE_DATA_DIR "/lxpanel/images" );
1618
cf701cb7 1619 fbev = fb_ev_new();
e2957bd2 1620 win_grp = gtk_window_group_new();
22242ed4 1621
f7cb330e
HJYP
1622restart:
1623 is_restarting = FALSE;
1624
cf701cb7
HJYP
1625 load_global_config();
1626
1d9dc649
HJYP
1627 /* NOTE: StructureNotifyMask is required by XRandR
1628 * See init_randr_support() in gdkscreen-x11.c of gtk+ for detail.
1629 */
1630 XSelectInput (GDK_DISPLAY(), GDK_ROOT_WINDOW(), StructureNotifyMask|SubstructureNotifyMask|PropertyChangeMask);
cf701cb7 1631 gdk_window_add_filter(gdk_get_default_root_window (), (GdkFilterFunc)panel_event_filter, NULL);
8110399f 1632
cf701cb7
HJYP
1633 if( G_UNLIKELY( ! start_all_panels() ) )
1634 g_warning( "Config files are not found.\n" );
8110399f
HJYP
1635/*
1636 * FIXME: configure??
6a6ad54e
HJYP
1637 if (config)
1638 configure();
8110399f 1639*/
6a6ad54e 1640 gtk_main();
8110399f 1641
cf701cb7
HJYP
1642 XSelectInput (GDK_DISPLAY(), GDK_ROOT_WINDOW(), NoEventMask);
1643 gdk_window_remove_filter(gdk_get_default_root_window (), (GdkFilterFunc)panel_event_filter, NULL);
1644
8110399f
HJYP
1645 /* destroy all panels */
1646 g_slist_foreach( all_panels, (GFunc) panel_destroy, NULL );
2a26c0d8
HJYP
1647 g_slist_free( all_panels );
1648 all_panels = NULL;
6a6ad54e 1649 g_free( cfgfile );
5541b8d2 1650
cf701cb7
HJYP
1651 free_global_config();
1652
f7cb330e
HJYP
1653 if( is_restarting )
1654 goto restart;
1655
e2957bd2 1656 g_object_unref(win_grp);
22242ed4
HJYP
1657 g_object_unref(fbev);
1658
5541b8d2 1659 return 0;
a52c2257 1660}