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