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