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