Use correct coordinates when calculate sensitivity area for autohide.
[lxde/lxpanel.git] / src / panel.c
1 /**
2 * Copyright (c) 2006-2014 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
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
22
23 #include <glib/gi18n.h>
24 #include <stdlib.h>
25 #include <glib/gstdio.h>
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>
32 #include <gdk/gdkx.h>
33 #include <libfm/fm-gtk.h>
34
35 #define __LXPANEL_INTERNALS__
36
37 #include "private.h"
38 #include "misc.h"
39 #include "bg.h"
40
41 #include "lxpanelctl.h"
42 #include "dbg.h"
43
44 static gchar *cfgfile = NULL;
45 static gchar version[] = VERSION;
46 gchar *cprofile = "default";
47
48 static GtkWindowGroup* win_grp; /* window group used to limit the scope of model dialog. */
49
50 static int config = 0;
51 FbEv *fbev = NULL;
52
53 GSList* all_panels = NULL; /* a single-linked list storing all panels */
54
55 gboolean is_restarting = FALSE;
56
57 gboolean is_in_lxde = FALSE;
58
59 static void panel_start_gui(LXPanel *p);
60 static void ah_start(LXPanel *p);
61 static void ah_stop(LXPanel *p);
62 static void on_root_bg_changed(FbBg *bg, LXPanel* p);
63
64
65 G_DEFINE_TYPE(PanelToplevel, lxpanel, GTK_TYPE_WINDOW);
66
67 static void lxpanel_finalize(GObject *object)
68 {
69 LXPanel *self = LXPANEL(object);
70 Panel *p = self->priv;
71
72 if( p->config_changed )
73 lxpanel_config_save( self );
74 config_destroy(p->config);
75
76 g_free(p->workarea);
77 g_free( p->background_file );
78 g_slist_free( p->system_menus );
79
80 g_free( p->name );
81 g_free(p);
82
83 G_OBJECT_CLASS(lxpanel_parent_class)->finalize(object);
84 }
85
86 static void lxpanel_destroy(GtkObject *object)
87 {
88 LXPanel *self = LXPANEL(object);
89 Panel *p = self->priv;
90 Display *xdisplay;
91
92 if (p->autohide)
93 ah_stop(self);
94
95 if (p->pref_dialog != NULL)
96 gtk_widget_destroy(p->pref_dialog);
97 p->pref_dialog = NULL;
98
99 if (p->plugin_pref_dialog != NULL)
100 /* just close the dialog, it will do all required cleanup */
101 gtk_dialog_response(GTK_DIALOG(p->plugin_pref_dialog), GTK_RESPONSE_CLOSE);
102
103 if (p->bg != NULL)
104 {
105 g_signal_handlers_disconnect_by_func(G_OBJECT(p->bg), on_root_bg_changed, self);
106 g_object_unref(p->bg);
107 p->bg = NULL;
108 }
109
110 if (p->initialized)
111 {
112 gtk_window_group_remove_window(win_grp, GTK_WINDOW(self));
113 xdisplay = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
114 gdk_flush();
115 XFlush(xdisplay);
116 XSync(xdisplay, True);
117 p->initialized = FALSE;
118 }
119
120 GTK_OBJECT_CLASS(lxpanel_parent_class)->destroy(object);
121 }
122
123 static gboolean delay_update_background( GtkWidget* p )
124 {
125 /* Panel could be destroyed while background update scheduled */
126 #if GTK_CHECK_VERSION(2, 20, 0)
127 if (gtk_widget_get_realized(p))
128 #else
129 if (GTK_WIDGET_REALIZED(p))
130 #endif
131 {
132 gdk_display_sync( gtk_widget_get_display(p) );
133 _panel_update_background( LXPANEL(p) );
134 }
135
136 return FALSE;
137 }
138
139 static void lxpanel_realize(GtkWidget *widget)
140 {
141 GTK_WIDGET_CLASS(lxpanel_parent_class)->realize(widget);
142
143 g_idle_add_full( G_PRIORITY_LOW,
144 (GSourceFunc)delay_update_background, widget, NULL );
145 }
146
147 static void lxpanel_style_set(GtkWidget *widget, GtkStyle* prev)
148 {
149 GTK_WIDGET_CLASS(lxpanel_parent_class)->style_set(widget, prev);
150
151 /* FIXME: This dirty hack is used to fix the background of systray... */
152 #if GTK_CHECK_VERSION(2, 20, 0)
153 if (gtk_widget_get_realized(widget))
154 #else
155 if( GTK_WIDGET_REALIZED( widget ) )
156 #endif
157 g_idle_add_full( G_PRIORITY_LOW,
158 (GSourceFunc)delay_update_background, widget, NULL );
159 }
160
161 static void lxpanel_size_request(GtkWidget *widget, GtkRequisition *req)
162 {
163 Panel *p = LXPANEL(widget)->priv;
164
165 GTK_WIDGET_CLASS(lxpanel_parent_class)->size_request(widget, req);
166
167 if (!p->visible)
168 /* When the panel is in invisible state, the content box also got hidden, thus always
169 * report 0 size. Ask the content box instead for its size. */
170 gtk_widget_size_request(p->box, req);
171
172 /* FIXME: is this ever required? */
173 if (p->widthtype == WIDTH_REQUEST)
174 p->width = (p->orientation == GTK_ORIENTATION_HORIZONTAL) ? req->width : req->height;
175 if (p->heighttype == HEIGHT_REQUEST)
176 p->height = (p->orientation == GTK_ORIENTATION_HORIZONTAL) ? req->height : req->width;
177 calculate_position(p);
178
179 gtk_widget_set_size_request( widget, p->aw, p->ah );
180 }
181
182 static void lxpanel_size_allocate(GtkWidget *widget, GtkAllocation *a)
183 {
184 Panel *p = LXPANEL(widget)->priv;
185
186 GTK_WIDGET_CLASS(lxpanel_parent_class)->size_allocate(widget, a);
187
188 if (p->widthtype == WIDTH_REQUEST)
189 p->width = (p->orientation == GTK_ORIENTATION_HORIZONTAL) ? a->width : a->height;
190 if (p->heighttype == HEIGHT_REQUEST)
191 p->height = (p->orientation == GTK_ORIENTATION_HORIZONTAL) ? a->height : a->width;
192 calculate_position(p);
193
194 if (a->width != p->aw || a->height != p->ah || a->x != p->ax || a->y != p->ay)
195 {
196 gtk_window_move(GTK_WINDOW(widget), p->ax, p->ay);
197 _panel_set_wm_strut(LXPANEL(widget));
198 }
199 }
200
201 static gboolean lxpanel_configure_event (GtkWidget *widget, GdkEventConfigure *e)
202 {
203 Panel *p = LXPANEL(widget)->priv;
204
205 if (e->width == p->cw && e->height == p->ch && e->x == p->cx && e->y == p->cy)
206 goto ok;
207 p->cw = e->width;
208 p->ch = e->height;
209 p->cx = e->x;
210 p->cy = e->y;
211
212 if (p->transparent)
213 fb_bg_notify_changed_bg(p->bg);
214 ok:
215 return GTK_WIDGET_CLASS(lxpanel_parent_class)->configure_event(widget, e);
216 }
217
218 static gboolean lxpanel_map_event(GtkWidget *widget, GdkEventAny *event)
219 {
220 Panel *p = PLUGIN_PANEL(widget)->priv;
221
222 if (p->autohide)
223 ah_start(LXPANEL(widget));
224 return GTK_WIDGET_CLASS(lxpanel_parent_class)->map_event(widget, event);
225 }
226
227 /* Handler for "button_press_event" signal with Panel as parameter. */
228 static gboolean lxpanel_button_press(GtkWidget *widget, GdkEventButton *event)
229 {
230 if (event->button == 3) /* right button */
231 {
232 GtkMenu* popup = (GtkMenu*) lxpanel_get_plugin_menu(LXPANEL(widget), NULL, FALSE);
233 gtk_menu_popup(popup, NULL, NULL, NULL, NULL, event->button, event->time);
234 return TRUE;
235 }
236 return FALSE;
237 }
238
239 static void lxpanel_class_init(PanelToplevelClass *klass)
240 {
241 GObjectClass *gobject_class = (GObjectClass *)klass;
242 GtkObjectClass *gtk_object_class = (GtkObjectClass *)klass;
243 GtkWidgetClass *widget_class = (GtkWidgetClass *)klass;
244
245 gobject_class->finalize = lxpanel_finalize;
246 gtk_object_class->destroy = lxpanel_destroy;
247 widget_class->realize = lxpanel_realize;
248 widget_class->size_request = lxpanel_size_request;
249 widget_class->size_allocate = lxpanel_size_allocate;
250 widget_class->configure_event = lxpanel_configure_event;
251 widget_class->style_set = lxpanel_style_set;
252 widget_class->map_event = lxpanel_map_event;
253 widget_class->button_press_event = lxpanel_button_press;
254 }
255
256 static void lxpanel_init(PanelToplevel *self)
257 {
258 Panel *p = g_new0(Panel, 1);
259
260 self->priv = p;
261 p->topgwin = self;
262 p->allign = ALLIGN_CENTER;
263 p->edge = EDGE_NONE;
264 p->widthtype = WIDTH_PERCENT;
265 p->width = 100;
266 p->heighttype = HEIGHT_PIXEL;
267 p->height = PANEL_HEIGHT_DEFAULT;
268 p->monitor = 0;
269 p->setdocktype = 1;
270 p->setstrut = 1;
271 p->round_corners = 0;
272 p->autohide = 0;
273 p->visible = TRUE;
274 p->height_when_hidden = 2;
275 p->transparent = 0;
276 p->alpha = 255;
277 gdk_color_parse("white", &p->gtintcolor);
278 p->tintcolor = gcolor2rgb24(&p->gtintcolor);
279 p->usefontcolor = 0;
280 p->fontcolor = 0x00000000;
281 p->usefontsize = 0;
282 p->fontsize = 10;
283 p->spacing = 0;
284 p->icon_size = PANEL_ICON_SIZE;
285 p->icon_theme = gtk_icon_theme_get_default();
286 p->config = config_new();
287 p->defstyle = gtk_widget_get_default_style();
288 gtk_window_set_type_hint(GTK_WINDOW(self), GDK_WINDOW_TYPE_HINT_DOCK);
289 }
290
291 /* Allocate and initialize new Panel structure. */
292 static LXPanel* panel_allocate(void)
293 {
294 return g_object_new(LX_TYPE_PANEL, NULL);
295 }
296
297 /* Normalize panel configuration after load from file or reconfiguration. */
298 static void panel_normalize_configuration(Panel* p)
299 {
300 panel_set_panel_configuration_changed( p );
301 if (p->width < 0)
302 p->width = 100;
303 if (p->widthtype == WIDTH_PERCENT && p->width > 100)
304 p->width = 100;
305 p->heighttype = HEIGHT_PIXEL;
306 if (p->heighttype == HEIGHT_PIXEL) {
307 if (p->height < PANEL_HEIGHT_MIN)
308 p->height = PANEL_HEIGHT_MIN;
309 else if (p->height > PANEL_HEIGHT_MAX)
310 p->height = PANEL_HEIGHT_MAX;
311 }
312 if (p->monitor < 0)
313 p->monitor = 0;
314 if (p->background)
315 p->transparent = 0;
316 }
317
318 /****************************************************
319 * panel's handlers for WM events *
320 ****************************************************/
321
322 void panel_set_wm_strut(Panel *p)
323 {
324 _panel_set_wm_strut(p->topgwin);
325 }
326
327 void _panel_set_wm_strut(LXPanel *panel)
328 {
329 int index;
330 Display *xdisplay = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
331 Panel *p = panel->priv;
332 gulong strut_size;
333 gulong strut_lower;
334 gulong strut_upper;
335
336 #if GTK_CHECK_VERSION(2, 20, 0)
337 if (!gtk_widget_get_mapped(GTK_WIDGET(panel)))
338 #else
339 if (!GTK_WIDGET_MAPPED(panel))
340 #endif
341 return;
342 /* most wm's tend to ignore struts of unmapped windows, and that's how
343 * lxpanel hides itself. so no reason to set it. */
344 if (p->autohide && p->height_when_hidden <= 0)
345 return;
346
347 /* Dispatch on edge to set up strut parameters. */
348 switch (p->edge)
349 {
350 case EDGE_LEFT:
351 index = 0;
352 strut_size = p->aw;
353 strut_lower = p->ay;
354 strut_upper = p->ay + p->ah;
355 break;
356 case EDGE_RIGHT:
357 index = 1;
358 strut_size = p->aw;
359 strut_lower = p->ay;
360 strut_upper = p->ay + p->ah;
361 break;
362 case EDGE_TOP:
363 index = 2;
364 strut_size = p->ah;
365 strut_lower = p->ax;
366 strut_upper = p->ax + p->aw;
367 break;
368 case EDGE_BOTTOM:
369 index = 3;
370 strut_size = p->ah;
371 strut_lower = p->ax;
372 strut_upper = p->ax + p->aw;
373 break;
374 default:
375 return;
376 }
377
378 /* Handle autohide case. EWMH recommends having the strut be the minimized size. */
379 if (p->autohide)
380 strut_size = p->height_when_hidden;
381
382 /* Set up strut value in property format. */
383 guint32 desired_strut[12];
384 memset(desired_strut, 0, sizeof(desired_strut));
385 if (p->setstrut)
386 {
387 desired_strut[index] = strut_size;
388 desired_strut[4 + index * 2] = strut_lower;
389 desired_strut[5 + index * 2] = strut_upper;
390 }
391 else
392 {
393 strut_size = 0;
394 strut_lower = 0;
395 strut_upper = 0;
396 }
397
398 /* If strut value changed, set the property value on the panel window.
399 * This avoids property change traffic when the panel layout is recalculated but strut geometry hasn't changed. */
400 if ((p->strut_size != strut_size) || (p->strut_lower != strut_lower) || (p->strut_upper != strut_upper) || (p->strut_edge != p->edge))
401 {
402 p->strut_size = strut_size;
403 p->strut_lower = strut_lower;
404 p->strut_upper = strut_upper;
405 p->strut_edge = p->edge;
406
407 /* If window manager supports STRUT_PARTIAL, it will ignore STRUT.
408 * Set STRUT also for window managers that do not support STRUT_PARTIAL. */
409 if (strut_size != 0)
410 {
411 XChangeProperty(xdisplay, p->topxwin, a_NET_WM_STRUT_PARTIAL,
412 XA_CARDINAL, 32, PropModeReplace, (unsigned char *) desired_strut, 12);
413 XChangeProperty(xdisplay, p->topxwin, a_NET_WM_STRUT,
414 XA_CARDINAL, 32, PropModeReplace, (unsigned char *) desired_strut, 4);
415 }
416 else
417 {
418 XDeleteProperty(xdisplay, p->topxwin, a_NET_WM_STRUT);
419 XDeleteProperty(xdisplay, p->topxwin, a_NET_WM_STRUT_PARTIAL);
420 }
421 }
422 }
423
424 static void process_client_msg ( XClientMessageEvent* ev )
425 {
426 int cmd = ev->data.b[0];
427 switch( cmd )
428 {
429 #ifndef DISABLE_MENU
430 case LXPANEL_CMD_SYS_MENU:
431 {
432 GSList* l;
433 for( l = all_panels; l; l = l->next )
434 {
435 LXPanel* p = (LXPanel*)l->data;
436 GList *plugins, *pl;
437
438 plugins = gtk_container_get_children(GTK_CONTAINER(p->priv->box));
439 for (pl = plugins; pl; pl = pl->next)
440 {
441 const LXPanelPluginInit *init = PLUGIN_CLASS(pl->data);
442 if (init->show_system_menu)
443 /* queue to show system menu */
444 init->show_system_menu(pl->data);
445 }
446 g_list_free(plugins);
447 }
448 break;
449 }
450 #endif
451 case LXPANEL_CMD_RUN:
452 gtk_run();
453 break;
454 case LXPANEL_CMD_CONFIG:
455 {
456 LXPanel * p = ((all_panels != NULL) ? all_panels->data : NULL);
457 if (p != NULL)
458 panel_configure(p, 0);
459 }
460 break;
461 case LXPANEL_CMD_RESTART:
462 restart();
463 break;
464 case LXPANEL_CMD_EXIT:
465 gtk_main_quit();
466 break;
467 }
468 }
469
470 static GdkFilterReturn
471 panel_event_filter(GdkXEvent *xevent, GdkEvent *event, gpointer not_used)
472 {
473 Atom at;
474 Window win;
475 XEvent *ev = (XEvent *) xevent;
476
477 ENTER;
478 DBG("win = 0x%x\n", ev->xproperty.window);
479 if (ev->type != PropertyNotify )
480 {
481 /* private client message from lxpanelctl */
482 if( ev->type == ClientMessage && ev->xproperty.atom == a_LXPANEL_CMD )
483 {
484 process_client_msg( (XClientMessageEvent*)ev );
485 }
486 else if( ev->type == DestroyNotify )
487 {
488 fb_ev_emit_destroy( fbev, ((XDestroyWindowEvent*)ev)->window );
489 }
490 RET(GDK_FILTER_CONTINUE);
491 }
492
493 at = ev->xproperty.atom;
494 win = ev->xproperty.window;
495 if (win == GDK_ROOT_WINDOW())
496 {
497 if (at == a_NET_CLIENT_LIST)
498 {
499 fb_ev_emit(fbev, EV_CLIENT_LIST);
500 }
501 else if (at == a_NET_CURRENT_DESKTOP)
502 {
503 GSList* l;
504 for( l = all_panels; l; l = l->next )
505 ((LXPanel*)l->data)->priv->curdesk = get_net_current_desktop();
506 fb_ev_emit(fbev, EV_CURRENT_DESKTOP);
507 }
508 else if (at == a_NET_NUMBER_OF_DESKTOPS)
509 {
510 GSList* l;
511 for( l = all_panels; l; l = l->next )
512 ((LXPanel*)l->data)->priv->desknum = get_net_number_of_desktops();
513 fb_ev_emit(fbev, EV_NUMBER_OF_DESKTOPS);
514 }
515 else if (at == a_NET_DESKTOP_NAMES)
516 {
517 fb_ev_emit(fbev, EV_DESKTOP_NAMES);
518 }
519 else if (at == a_NET_ACTIVE_WINDOW)
520 {
521 fb_ev_emit(fbev, EV_ACTIVE_WINDOW );
522 }
523 else if (at == a_NET_CLIENT_LIST_STACKING)
524 {
525 fb_ev_emit(fbev, EV_CLIENT_LIST_STACKING);
526 }
527 else if (at == a_XROOTPMAP_ID)
528 {
529 GSList* l;
530 for( l = all_panels; l; l = l->next )
531 {
532 LXPanel* p = (LXPanel*)l->data;
533 if (p->priv->transparent) {
534 fb_bg_notify_changed_bg(p->priv->bg);
535 }
536 }
537 }
538 else if (at == a_NET_WORKAREA)
539 {
540 GSList* l;
541 for( l = all_panels; l; l = l->next )
542 {
543 LXPanel* p = (LXPanel*)l->data;
544 g_free( p->priv->workarea );
545 p->priv->workarea = get_xaproperty (GDK_ROOT_WINDOW(), a_NET_WORKAREA, XA_CARDINAL, &p->priv->wa_len);
546 /* print_wmdata(p); */
547 }
548 }
549 else
550 return GDK_FILTER_CONTINUE;
551
552 return GDK_FILTER_REMOVE;
553 }
554 return GDK_FILTER_CONTINUE;
555 }
556
557 /****************************************************
558 * panel's handlers for GTK events *
559 ****************************************************/
560
561
562 static void
563 on_root_bg_changed(FbBg *bg, LXPanel* p)
564 {
565 _panel_update_background( p );
566 }
567
568 void panel_determine_background_pixmap(Panel * panel, GtkWidget * widget, GdkWindow * window)
569 {
570 _panel_determine_background_pixmap(panel->topgwin, widget);
571 }
572
573 void _panel_determine_background_pixmap(LXPanel * panel, GtkWidget * widget)
574 {
575 GdkPixmap * pixmap = NULL;
576 GdkWindow * window = gtk_widget_get_window(widget);
577 Panel * p = panel->priv;
578
579 /* Free p->bg if it is not going to be used. */
580 if (( ! p->transparent) && (p->bg != NULL))
581 {
582 g_signal_handlers_disconnect_by_func(G_OBJECT(p->bg), on_root_bg_changed, panel);
583 g_object_unref(p->bg);
584 p->bg = NULL;
585 }
586
587 if (p->background)
588 {
589 /* User specified background pixmap. */
590 if (p->background_file != NULL)
591 pixmap = fb_bg_get_pix_from_file(widget, p->background_file);
592 }
593
594 else if (p->transparent)
595 {
596 /* Transparent. Determine the appropriate value from the root pixmap. */
597 if (p->bg == NULL)
598 {
599 p->bg = fb_bg_get_for_display();
600 g_signal_connect(G_OBJECT(p->bg), "changed", G_CALLBACK(on_root_bg_changed), panel);
601 }
602 pixmap = fb_bg_get_xroot_pix_for_win(p->bg, widget);
603 if ((pixmap != NULL) && (pixmap != GDK_NO_BG) && (p->alpha != 0))
604 fb_bg_composite(pixmap, &p->gtintcolor, p->alpha);
605 }
606
607 if (pixmap != NULL)
608 {
609 gtk_widget_set_app_paintable(widget, TRUE );
610 gdk_window_set_back_pixmap(window, pixmap, FALSE);
611 g_object_unref(pixmap);
612 }
613 else
614 gtk_widget_set_app_paintable(widget, FALSE);
615 }
616
617 /* Update the background of the entire panel.
618 * This function should only be called after the panel has been realized. */
619 void panel_update_background(Panel * p)
620 {
621 _panel_update_background(p->topgwin);
622 }
623
624 void _panel_update_background(LXPanel * p)
625 {
626 GtkWidget *w = GTK_WIDGET(p);
627 GList *plugins, *l;
628
629 /* Redraw the top level widget. */
630 _panel_determine_background_pixmap(p, w);
631 gdk_window_clear(gtk_widget_get_window(w));
632 gtk_widget_queue_draw(w);
633
634 /* Loop over all plugins redrawing each plugin. */
635 plugins = gtk_container_get_children(GTK_CONTAINER(p->priv->box));
636 for (l = plugins; l != NULL; l = l->next)
637 plugin_widget_set_background(l->data, p);
638 g_list_free(plugins);
639 }
640
641 /****************************************************
642 * autohide : borrowed from fbpanel *
643 ****************************************************/
644
645 /* Autohide is behaviour when panel hides itself when mouse is "far enough"
646 * and pops up again when mouse comes "close enough".
647 * Formally, it's a state machine with 3 states that driven by mouse
648 * coordinates and timer:
649 * 1. VISIBLE - ensures that panel is visible. When/if mouse goes "far enough"
650 * switches to WAITING state
651 * 2. WAITING - starts timer. If mouse comes "close enough", stops timer and
652 * switches to VISIBLE. If timer expires, switches to HIDDEN
653 * 3. HIDDEN - hides panel. When mouse comes "close enough" switches to VISIBLE
654 *
655 * Note 1
656 * Mouse coordinates are queried every PERIOD milisec
657 *
658 * Note 2
659 * If mouse is less then GAP pixels to panel it's considered to be close,
660 * otherwise it's far
661 */
662
663 #define GAP 2
664 #define PERIOD 300
665
666 typedef enum
667 {
668 AH_STATE_VISIBLE,
669 AH_STATE_WAITING,
670 AH_STATE_HIDDEN
671 } PanelAHState;
672
673 static void ah_state_set(LXPanel *p, PanelAHState ah_state);
674
675 static gboolean
676 mouse_watch(LXPanel *panel)
677 {
678 Panel *p = panel->priv;
679 gint x, y;
680
681 if (g_source_is_destroyed(g_main_current_source()))
682 return FALSE;
683
684 ENTER;
685 gdk_display_get_pointer(gdk_display_get_default(), NULL, &x, &y, NULL);
686
687 /* Reduce sensitivity area
688 p->ah_far = ((x < p->cx - GAP) || (x > p->cx + p->cw + GAP)
689 || (y < p->cy - GAP) || (y > p->cy + p->ch + GAP));
690 */
691
692 gint cx, cy, cw, ch, gap;
693
694 cx = p->cx;
695 cy = p->cy;
696 cw = p->cw;
697 ch = p->ch;
698
699 /* reduce area which will raise panel so it does not interfere with apps */
700 if (p->ah_state == AH_STATE_HIDDEN) {
701 gap = MAX(p->height_when_hidden, GAP);
702 switch (p->edge) {
703 case EDGE_LEFT:
704 cw = gap;
705 break;
706 case EDGE_RIGHT:
707 cx = cx + cw - gap;
708 cw = gap;
709 break;
710 case EDGE_TOP:
711 ch = gap;
712 break;
713 case EDGE_BOTTOM:
714 cy = cy + ch - gap;
715 ch = gap;
716 break;
717 }
718 }
719 p->ah_far = ((x < cx) || (x > cx + cw) || (y < cy) || (y > cy + ch));
720
721 ah_state_set(panel, p->ah_state);
722 RET(TRUE);
723 }
724
725 static gboolean ah_state_hide_timeout(gpointer p)
726 {
727 if (!g_source_is_destroyed(g_main_current_source()))
728 {
729 ah_state_set(p, AH_STATE_HIDDEN);
730 ((LXPanel *)p)->priv->hide_timeout = 0;
731 }
732 return FALSE;
733 }
734
735 static void ah_state_set(LXPanel *panel, PanelAHState ah_state)
736 {
737 Panel *p = panel->priv;
738
739 ENTER;
740 if (p->ah_state != ah_state) {
741 p->ah_state = ah_state;
742 switch (ah_state) {
743 case AH_STATE_VISIBLE:
744 gtk_widget_show(GTK_WIDGET(panel));
745 gtk_widget_show(p->box);
746 gtk_window_stick(GTK_WINDOW(panel));
747 p->visible = TRUE;
748 break;
749 case AH_STATE_WAITING:
750 p->hide_timeout = g_timeout_add(2 * PERIOD, ah_state_hide_timeout, panel);
751 break;
752 case AH_STATE_HIDDEN:
753 if (p->height_when_hidden > 0)
754 gtk_widget_hide(p->box);
755 else
756 gtk_widget_hide(GTK_WIDGET(panel));
757 p->visible = FALSE;
758 }
759 } else if (p->autohide && p->ah_far) {
760 switch (ah_state) {
761 case AH_STATE_VISIBLE:
762 ah_state_set(panel, AH_STATE_WAITING);
763 break;
764 case AH_STATE_WAITING:
765 break;
766 case AH_STATE_HIDDEN:
767 /* configurator might change height_when_hidden value */
768 if (p->height_when_hidden > 0)
769 {
770 if (gtk_widget_get_visible(p->box))
771 {
772 gtk_widget_hide(p->box);
773 gtk_widget_show(GTK_WIDGET(panel));
774 }
775 }
776 else
777 if (gtk_widget_get_visible(GTK_WIDGET(panel)))
778 {
779 gtk_widget_hide(GTK_WIDGET(panel));
780 gtk_widget_show(p->box);
781 }
782 }
783 } else {
784 switch (ah_state) {
785 case AH_STATE_VISIBLE:
786 break;
787 case AH_STATE_WAITING:
788 if (p->hide_timeout)
789 g_source_remove(p->hide_timeout);
790 p->hide_timeout = 0;
791 /* continue with setting visible */
792 case AH_STATE_HIDDEN:
793 ah_state_set(panel, AH_STATE_VISIBLE);
794 }
795 }
796 RET();
797 }
798
799 /* starts autohide behaviour */
800 static void ah_start(LXPanel *p)
801 {
802 ENTER;
803 if (!p->priv->mouse_timeout)
804 p->priv->mouse_timeout = g_timeout_add(PERIOD, (GSourceFunc) mouse_watch, p);
805 RET();
806 }
807
808 /* stops autohide */
809 static void ah_stop(LXPanel *p)
810 {
811 ENTER;
812 if (p->priv->mouse_timeout) {
813 g_source_remove(p->priv->mouse_timeout);
814 p->priv->mouse_timeout = 0;
815 }
816 if (p->priv->hide_timeout) {
817 g_source_remove(p->priv->hide_timeout);
818 p->priv->hide_timeout = 0;
819 }
820 RET();
821 }
822 /* end of the autohide code
823 * ------------------------------------------------------------- */
824
825 static gint
826 panel_popupmenu_configure(GtkWidget *widget, gpointer user_data)
827 {
828 panel_configure( (LXPanel*)user_data, 0 );
829 return TRUE;
830 }
831
832 static void panel_popupmenu_config_plugin( GtkMenuItem* item, GtkWidget* plugin )
833 {
834 Panel *panel = PLUGIN_PANEL(plugin)->priv;
835
836 lxpanel_plugin_show_config_dialog(plugin);
837
838 /* FIXME: this should be more elegant */
839 panel->config_changed = TRUE;
840 }
841
842 static void panel_popupmenu_add_item( GtkMenuItem* item, LXPanel* panel )
843 {
844 /* panel_add_plugin( panel, panel->topgwin ); */
845 panel_configure( panel, 2 );
846 }
847
848 static void panel_popupmenu_remove_item( GtkMenuItem* item, GtkWidget* plugin )
849 {
850 Panel* panel = PLUGIN_PANEL(plugin)->priv;
851
852 /* If the configuration dialog is open, there will certainly be a crash if the
853 * user manipulates the Configured Plugins list, after we remove this entry.
854 * Close the configuration dialog if it is open. */
855 if (panel->pref_dialog != NULL)
856 {
857 gtk_widget_destroy(panel->pref_dialog);
858 panel->pref_dialog = NULL;
859 }
860 config_setting_destroy(g_object_get_qdata(G_OBJECT(plugin), lxpanel_plugin_qconf));
861 /* reset conf pointer because the widget still may be referenced by configurator */
862 g_object_set_qdata(G_OBJECT(plugin), lxpanel_plugin_qconf, NULL);
863
864 lxpanel_config_save(PLUGIN_PANEL(plugin));
865 gtk_widget_destroy(plugin);
866 }
867
868 /* FIXME: Potentially we can support multiple panels at the same edge,
869 * but currently this cannot be done due to some positioning problems. */
870 static char* gen_panel_name( int edge, gint monitor )
871 {
872 const char* edge_str = num2str( edge_pair, edge, "" );
873 char* name = NULL;
874 char* dir = _user_config_file_name("panels", NULL);
875 int i;
876 for( i = 0; i < G_MAXINT; ++i )
877 {
878 char* f;
879 if(monitor != 0)
880 name = g_strdup_printf( "%s-m%d-%d", edge_str, monitor, i );
881 else if( G_LIKELY( i > 0 ) )
882 name = g_strdup_printf( "%s%d", edge_str, i );
883 else
884 name = g_strdup( edge_str );
885
886 f = g_build_filename( dir, name, NULL );
887 if( ! g_file_test( f, G_FILE_TEST_EXISTS ) )
888 {
889 g_free( f );
890 break;
891 }
892 g_free( name );
893 g_free( f );
894 }
895 g_free( dir );
896 return name;
897 }
898
899 /* FIXME: Potentially we can support multiple panels at the same edge,
900 * but currently this cannot be done due to some positioning problems. */
901 static void panel_popupmenu_create_panel( GtkMenuItem* item, LXPanel* panel )
902 {
903 gint m, e, monitors;
904 GdkScreen *screen;
905 LXPanel *new_panel = panel_allocate();
906 Panel *p = new_panel->priv;
907
908 /* Allocate the edge. */
909 screen = gdk_screen_get_default();
910 g_assert(screen);
911 monitors = gdk_screen_get_n_monitors(screen);
912 for(m=0; m<monitors; ++m)
913 {
914 /* try each of the four edges */
915 for(e=1; e<5; ++e)
916 {
917 if(panel_edge_available(p,e,m)) {
918 p->edge = e;
919 p->monitor = m;
920 goto found_edge;
921 }
922 }
923 }
924
925 gtk_widget_destroy(GTK_WIDGET(new_panel));
926 g_warning("Error adding panel: There is no room for another panel. All the edges are taken.");
927 fm_show_error(NULL, NULL, _("There is no room for another panel. All the edges are taken."));
928 return;
929
930 found_edge:
931 p->name = gen_panel_name(p->edge, p->monitor);
932
933 /* create new config with first group "Global" */
934 config_group_add_subgroup(config_root_setting(p->config), "Global");
935 panel_configure(new_panel, 0);
936 panel_normalize_configuration(p);
937 panel_start_gui(new_panel);
938 gtk_widget_show_all(GTK_WIDGET(new_panel));
939
940 lxpanel_config_save(new_panel);
941 all_panels = g_slist_prepend(all_panels, new_panel);
942 }
943
944 static void panel_popupmenu_delete_panel( GtkMenuItem* item, LXPanel* panel )
945 {
946 GtkWidget* dlg;
947 gboolean ok;
948 dlg = gtk_message_dialog_new_with_markup( GTK_WINDOW(panel),
949 GTK_DIALOG_MODAL,
950 GTK_MESSAGE_QUESTION,
951 GTK_BUTTONS_OK_CANCEL,
952 _("Really delete this panel?\n<b>Warning: This can not be recovered.</b>") );
953 panel_apply_icon(GTK_WINDOW(dlg));
954 gtk_window_set_title( (GtkWindow*)dlg, _("Confirm") );
955 ok = ( gtk_dialog_run( (GtkDialog*)dlg ) == GTK_RESPONSE_OK );
956 gtk_widget_destroy( dlg );
957 if( ok )
958 {
959 gchar *fname;
960 all_panels = g_slist_remove( all_panels, panel );
961
962 /* delete the config file of this panel */
963 fname = _user_config_file_name("panels", panel->priv->name);
964 g_unlink( fname );
965 g_free(fname);
966 panel->priv->config_changed = 0;
967 gtk_widget_destroy(GTK_WIDGET(panel));
968 }
969 }
970
971 static void panel_popupmenu_about( GtkMenuItem* item, Panel* panel )
972 {
973 GtkWidget *about;
974 const gchar* authors[] = {
975 "Hong Jen Yee (PCMan) <pcman.tw@gmail.com>",
976 "Jim Huang <jserv.tw@gmail.com>",
977 "Greg McNew <gmcnew@gmail.com> (battery plugin)",
978 "Fred Chien <cfsghost@gmail.com>",
979 "Daniel Kesler <kesler.daniel@gmail.com>",
980 "Juergen Hoetzel <juergen@archlinux.org>",
981 "Marty Jack <martyj19@comcast.net>",
982 "Martin Bagge <brother@bsnet.se>",
983 "Andriy Grytsenko <andrej@rep.kiev.ua>",
984 "Giuseppe Penone <giuspen@gmail.com>",
985 "Piotr Sipika <piotr.sipika@gmail.com>",
986 NULL
987 };
988 /* TRANSLATORS: Replace this string with your names, one name per line. */
989 gchar *translators = _( "translator-credits" );
990
991 about = gtk_about_dialog_new();
992 panel_apply_icon(GTK_WINDOW(about));
993 gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(about), VERSION);
994 gtk_about_dialog_set_program_name(GTK_ABOUT_DIALOG(about), _("LXPanel"));
995
996 if(gtk_icon_theme_has_icon(panel->icon_theme, "video-display"))
997 {
998 gtk_about_dialog_set_logo( GTK_ABOUT_DIALOG(about),
999 gtk_icon_theme_load_icon(panel->icon_theme, "video-display", 48, 0, NULL));
1000 }
1001 else if (gtk_icon_theme_has_icon(panel->icon_theme, "start-here"))
1002 {
1003 gtk_about_dialog_set_logo( GTK_ABOUT_DIALOG(about),
1004 gtk_icon_theme_load_icon(panel->icon_theme, "start-here", 48, 0, NULL));
1005 }
1006 else
1007 {
1008 gtk_about_dialog_set_logo( GTK_ABOUT_DIALOG(about),
1009 gdk_pixbuf_new_from_file(PACKAGE_DATA_DIR "/images/my-computer.png", NULL));
1010 }
1011
1012 gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(about), _("Copyright (C) 2008-2014"));
1013 gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(about), _( "Desktop panel for LXDE project"));
1014 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.");
1015 gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(about), "http://lxde.org/");
1016 gtk_about_dialog_set_authors(GTK_ABOUT_DIALOG(about), authors);
1017 gtk_about_dialog_set_translator_credits(GTK_ABOUT_DIALOG(about), translators);
1018 gtk_dialog_run(GTK_DIALOG(about));
1019 gtk_widget_destroy(about);
1020 }
1021
1022 void panel_apply_icon( GtkWindow *w )
1023 {
1024 GdkPixbuf* window_icon;
1025
1026 if(gtk_icon_theme_has_icon(gtk_icon_theme_get_default(), "video-display"))
1027 {
1028 window_icon = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), "video-display", 24, 0, NULL);
1029 }
1030 else if(gtk_icon_theme_has_icon(gtk_icon_theme_get_default(), "start-here"))
1031 {
1032 window_icon = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), "start-here", 24, 0, NULL);
1033 }
1034 else
1035 {
1036 window_icon = gdk_pixbuf_new_from_file(PACKAGE_DATA_DIR "/images/my-computer.png", NULL);
1037 }
1038 gtk_window_set_icon(w, window_icon);
1039 }
1040
1041 GtkMenu* lxpanel_get_plugin_menu( LXPanel* panel, GtkWidget* plugin, gboolean use_sub_menu )
1042 {
1043 GtkWidget *menu_item, *img;
1044 GtkMenu *ret,*menu;
1045 const LXPanelPluginInit *init;
1046 char* tmp;
1047
1048 ret = menu = GTK_MENU(gtk_menu_new());
1049
1050 if (plugin)
1051 {
1052 init = PLUGIN_CLASS(plugin);
1053 /* create single item - plugin instance settings */
1054 img = gtk_image_new_from_stock( GTK_STOCK_PREFERENCES, GTK_ICON_SIZE_MENU );
1055 tmp = g_strdup_printf( _("\"%s\" Settings"), _(init->name) );
1056 menu_item = gtk_image_menu_item_new_with_label( tmp );
1057 g_free( tmp );
1058 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
1059 gtk_menu_shell_prepend(GTK_MENU_SHELL(ret), menu_item);
1060 if( init->config )
1061 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_config_plugin), plugin );
1062 else
1063 gtk_widget_set_sensitive( menu_item, FALSE );
1064 /* add custom items by plugin if requested */
1065 if (init->update_context_menu != NULL)
1066 use_sub_menu = init->update_context_menu(plugin, ret);
1067 /* append a separator */
1068 menu_item = gtk_separator_menu_item_new();
1069 gtk_menu_shell_append(GTK_MENU_SHELL(ret), menu_item);
1070 }
1071 if (use_sub_menu)
1072 menu = GTK_MENU(gtk_menu_new());
1073
1074 img = gtk_image_new_from_stock( GTK_STOCK_EDIT, GTK_ICON_SIZE_MENU );
1075 menu_item = gtk_image_menu_item_new_with_label(_("Add / Remove Panel Items"));
1076 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
1077 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1078 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_add_item), panel );
1079
1080 if( plugin )
1081 {
1082 img = gtk_image_new_from_stock( GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU );
1083 tmp = g_strdup_printf( _("Remove \"%s\" From Panel"), _(init->name) );
1084 menu_item = gtk_image_menu_item_new_with_label( tmp );
1085 g_free( tmp );
1086 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
1087 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1088 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_remove_item), plugin );
1089 }
1090
1091 menu_item = gtk_separator_menu_item_new();
1092 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1093
1094 img = gtk_image_new_from_stock( GTK_STOCK_PREFERENCES, GTK_ICON_SIZE_MENU );
1095 menu_item = gtk_image_menu_item_new_with_label(_("Panel Settings"));
1096 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
1097 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1098 g_signal_connect(G_OBJECT(menu_item), "activate", G_CALLBACK(panel_popupmenu_configure), panel );
1099
1100 img = gtk_image_new_from_stock( GTK_STOCK_NEW, GTK_ICON_SIZE_MENU );
1101 menu_item = gtk_image_menu_item_new_with_label(_("Create New Panel"));
1102 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
1103 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1104 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_create_panel), panel );
1105
1106 img = gtk_image_new_from_stock( GTK_STOCK_DELETE, GTK_ICON_SIZE_MENU );
1107 menu_item = gtk_image_menu_item_new_with_label(_("Delete This Panel"));
1108 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
1109 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1110 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_delete_panel), panel );
1111 if( ! all_panels->next ) /* if this is the only panel */
1112 gtk_widget_set_sensitive( menu_item, FALSE );
1113
1114 menu_item = gtk_separator_menu_item_new();
1115 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1116
1117 img = gtk_image_new_from_stock( GTK_STOCK_ABOUT, GTK_ICON_SIZE_MENU );
1118 menu_item = gtk_image_menu_item_new_with_label(_("About"));
1119 gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
1120 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
1121 g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_about), panel->priv );
1122
1123 if( use_sub_menu )
1124 {
1125 menu_item = gtk_image_menu_item_new_with_label(_("Panel"));
1126 gtk_menu_shell_append(GTK_MENU_SHELL(ret), menu_item);
1127 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), GTK_WIDGET(menu) );
1128 }
1129
1130 gtk_widget_show_all(GTK_WIDGET(ret));
1131
1132 g_signal_connect( ret, "selection-done", G_CALLBACK(gtk_widget_destroy), NULL );
1133 return ret;
1134 }
1135
1136 /* for old plugins compatibility */
1137 GtkMenu* lxpanel_get_panel_menu( Panel* panel, Plugin* plugin, gboolean use_sub_menu )
1138 {
1139 return lxpanel_get_plugin_menu(panel->topgwin, plugin->pwid, use_sub_menu);
1140 }
1141
1142 /****************************************************
1143 * panel creation *
1144 ****************************************************/
1145
1146 static void
1147 make_round_corners(Panel *p)
1148 {
1149 /* FIXME: This should be re-written with shape extension of X11 */
1150 /* gdk_window_shape_combine_mask() can be used */
1151 }
1152
1153 void panel_set_dock_type(Panel *p)
1154 {
1155 Display *xdisplay = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
1156
1157 if (p->setdocktype) {
1158 Atom state = a_NET_WM_WINDOW_TYPE_DOCK;
1159 XChangeProperty(xdisplay, p->topxwin,
1160 a_NET_WM_WINDOW_TYPE, XA_ATOM, 32,
1161 PropModeReplace, (unsigned char *) &state, 1);
1162 }
1163 else {
1164 XDeleteProperty( xdisplay, p->topxwin, a_NET_WM_WINDOW_TYPE );
1165 }
1166 }
1167
1168 void panel_establish_autohide(Panel *p)
1169 {
1170 _panel_establish_autohide(p->topgwin);
1171 }
1172
1173 void _panel_establish_autohide(LXPanel *p)
1174 {
1175 if (p->priv->autohide)
1176 ah_start(p);
1177 else
1178 {
1179 ah_stop(p);
1180 ah_state_set(p, AH_STATE_VISIBLE);
1181 }
1182 }
1183
1184 /* Set an image from a file with scaling to the panel icon size. */
1185 void panel_image_set_from_file(Panel * p, GtkWidget * image, const char * file)
1186 {
1187 GdkPixbuf * pixbuf = gdk_pixbuf_new_from_file_at_scale(file, p->icon_size, p->icon_size, TRUE, NULL);
1188 if (pixbuf != NULL)
1189 {
1190 gtk_image_set_from_pixbuf(GTK_IMAGE(image), pixbuf);
1191 g_object_unref(pixbuf);
1192 }
1193 }
1194
1195 void lxpanel_image_set_from_file(LXPanel * p, GtkWidget * image, const char * file)
1196 {
1197 panel_image_set_from_file(p->priv, image, file);
1198 }
1199
1200 /* Set an image from a icon theme with scaling to the panel icon size. */
1201 gboolean panel_image_set_icon_theme(Panel * p, GtkWidget * image, const gchar * icon)
1202 {
1203 if (gtk_icon_theme_has_icon(p->icon_theme, icon))
1204 {
1205 GdkPixbuf * pixbuf = gtk_icon_theme_load_icon(p->icon_theme, icon, p->icon_size, 0, NULL);
1206 gtk_image_set_from_pixbuf(GTK_IMAGE(image), pixbuf);
1207 g_object_unref(pixbuf);
1208 return TRUE;
1209 }
1210 return FALSE;
1211 }
1212
1213 gboolean lxpanel_image_set_icon_theme(LXPanel * p, GtkWidget * image, const gchar * icon)
1214 {
1215 return panel_image_set_icon_theme(p->priv, image, icon);
1216 }
1217
1218 static void
1219 panel_start_gui(LXPanel *panel)
1220 {
1221 Atom state[3];
1222 XWMHints wmhints;
1223 guint32 val;
1224 Display *xdisplay = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
1225 Panel *p = panel->priv;
1226 GtkWidget *w = GTK_WIDGET(panel);
1227
1228 ENTER;
1229
1230 p->curdesk = get_net_current_desktop();
1231 p->desknum = get_net_number_of_desktops();
1232 p->workarea = get_xaproperty (GDK_ROOT_WINDOW(), a_NET_WORKAREA, XA_CARDINAL, &p->wa_len);
1233
1234 /* main toplevel window */
1235 /* p->topgwin = gtk_window_new(GTK_WINDOW_TOPLEVEL); */
1236 gtk_widget_set_name(w, "PanelToplevel");
1237 p->display = gdk_display_get_default();
1238 gtk_container_set_border_width(GTK_CONTAINER(panel), 0);
1239 gtk_window_set_resizable(GTK_WINDOW(panel), FALSE);
1240 gtk_window_set_wmclass(GTK_WINDOW(panel), "panel", "lxpanel");
1241 gtk_window_set_title(GTK_WINDOW(panel), "panel");
1242 gtk_window_set_position(GTK_WINDOW(panel), GTK_WIN_POS_NONE);
1243 gtk_window_set_decorated(GTK_WINDOW(panel), FALSE);
1244
1245 gtk_window_group_add_window( win_grp, (GtkWindow*)panel );
1246
1247 gtk_widget_add_events( w, GDK_BUTTON_PRESS_MASK );
1248
1249 gtk_widget_realize(w);
1250 //gdk_window_set_decorations(gtk_widget_get_window(p->topgwin), 0);
1251
1252 // main layout manager as a single child of panel
1253 p->box = panel_box_new(panel, FALSE, 0);
1254 gtk_container_set_border_width(GTK_CONTAINER(p->box), 0);
1255 gtk_container_add(GTK_CONTAINER(panel), p->box);
1256 gtk_widget_show(p->box);
1257 if (p->round_corners)
1258 make_round_corners(p);
1259
1260 p->topxwin = GDK_WINDOW_XWINDOW(gtk_widget_get_window(w));
1261 DBG("topxwin = %x\n", p->topxwin);
1262
1263 /* the settings that should be done before window is mapped */
1264 wmhints.flags = InputHint;
1265 wmhints.input = 0;
1266 XSetWMHints (xdisplay, p->topxwin, &wmhints);
1267 #define WIN_HINTS_SKIP_FOCUS (1<<0) /* "alt-tab" skips this win */
1268 val = WIN_HINTS_SKIP_FOCUS;
1269 XChangeProperty(xdisplay, p->topxwin,
1270 XInternAtom(xdisplay, "_WIN_HINTS", False), XA_CARDINAL, 32,
1271 PropModeReplace, (unsigned char *) &val, 1);
1272
1273 panel_set_dock_type(p);
1274
1275 /* window mapping point */
1276 gtk_widget_show_all(w);
1277
1278 /* the settings that should be done after window is mapped */
1279 _panel_establish_autohide(panel);
1280
1281 /* send it to running wm */
1282 Xclimsg(p->topxwin, a_NET_WM_DESKTOP, 0xFFFFFFFF, 0, 0, 0, 0);
1283 /* and assign it ourself just for case when wm is not running */
1284 val = 0xFFFFFFFF;
1285 XChangeProperty(xdisplay, p->topxwin, a_NET_WM_DESKTOP, XA_CARDINAL, 32,
1286 PropModeReplace, (unsigned char *) &val, 1);
1287
1288 state[0] = a_NET_WM_STATE_SKIP_PAGER;
1289 state[1] = a_NET_WM_STATE_SKIP_TASKBAR;
1290 state[2] = a_NET_WM_STATE_STICKY;
1291 XChangeProperty(xdisplay, p->topxwin, a_NET_WM_STATE, XA_ATOM,
1292 32, PropModeReplace, (unsigned char *) state, 3);
1293
1294 _calculate_position(panel);
1295 gdk_window_move_resize(gtk_widget_get_window(w), p->ax, p->ay, p->aw, p->ah);
1296 _panel_set_wm_strut(panel);
1297 p->initialized = TRUE;
1298
1299 RET();
1300 }
1301
1302 /* Exchange the "width" and "height" terminology for vertical and horizontal panels. */
1303 void panel_adjust_geometry_terminology(Panel * p)
1304 {
1305 if ((p->height_label != NULL) && (p->width_label != NULL)
1306 && (p->alignment_left_label != NULL) && (p->alignment_right_label != NULL))
1307 {
1308 if ((p->edge == EDGE_TOP) || (p->edge == EDGE_BOTTOM))
1309 {
1310 gtk_label_set_text(GTK_LABEL(p->height_label), _("Height:"));
1311 gtk_label_set_text(GTK_LABEL(p->width_label), _("Width:"));
1312 gtk_button_set_label(GTK_BUTTON(p->alignment_left_label), _("Left"));
1313 gtk_button_set_label(GTK_BUTTON(p->alignment_right_label), _("Right"));
1314 }
1315 else
1316 {
1317 gtk_label_set_text(GTK_LABEL(p->height_label), _("Width:"));
1318 gtk_label_set_text(GTK_LABEL(p->width_label), _("Height:"));
1319 gtk_button_set_label(GTK_BUTTON(p->alignment_left_label), _("Top"));
1320 gtk_button_set_label(GTK_BUTTON(p->alignment_right_label), _("Bottom"));
1321 }
1322 }
1323 }
1324
1325 /* Draw text into a label, with the user preference color and optionally bold. */
1326 void panel_draw_label_text(Panel * p, GtkWidget * label, const char * text,
1327 gboolean bold, float custom_size_factor,
1328 gboolean custom_color)
1329 {
1330 if (text == NULL)
1331 {
1332 /* Null string. */
1333 gtk_label_set_text(GTK_LABEL(label), NULL);
1334 return;
1335 }
1336
1337 /* Compute an appropriate size so the font will scale with the panel's icon size. */
1338 int font_desc;
1339 if (p->usefontsize)
1340 font_desc = p->fontsize;
1341 else
1342 {
1343 GtkStyle *style = gtk_widget_get_style(label);
1344 font_desc = pango_font_description_get_size(style->font_desc) / PANGO_SCALE;
1345 }
1346 font_desc *= custom_size_factor;
1347
1348 /* Check the string for characters that need to be escaped.
1349 * If any are found, create the properly escaped string and use it instead. */
1350 const char * valid_markup = text;
1351 char * escaped_text = NULL;
1352 const char * q;
1353 for (q = text; *q != '\0'; q += 1)
1354 {
1355 if ((*q == '<') || (*q == '>') || (*q == '&'))
1356 {
1357 escaped_text = g_markup_escape_text(text, -1);
1358 valid_markup = escaped_text;
1359 break;
1360 }
1361 }
1362
1363 gchar * formatted_text;
1364 if ((custom_color) && (p->usefontcolor))
1365 {
1366 /* Color, optionally bold. */
1367 formatted_text = g_strdup_printf("<span font_desc=\"%d\" color=\"#%06x\">%s%s%s</span>",
1368 font_desc,
1369 gcolor2rgb24(&p->gfontcolor),
1370 ((bold) ? "<b>" : ""),
1371 valid_markup,
1372 ((bold) ? "</b>" : ""));
1373 }
1374 else
1375 {
1376 /* No color, optionally bold. */
1377 formatted_text = g_strdup_printf("<span font_desc=\"%d\">%s%s%s</span>",
1378 font_desc,
1379 ((bold) ? "<b>" : ""),
1380 valid_markup,
1381 ((bold) ? "</b>" : ""));
1382 }
1383
1384 gtk_label_set_markup(GTK_LABEL(label), formatted_text);
1385 g_free(formatted_text);
1386 g_free(escaped_text);
1387 }
1388
1389 void lxpanel_draw_label_text(LXPanel * p, GtkWidget * label, const char * text,
1390 gboolean bold, float custom_size_factor,
1391 gboolean custom_color)
1392 {
1393 panel_draw_label_text(p->priv, label, text, bold, custom_size_factor, custom_color);
1394 }
1395
1396 void panel_set_panel_configuration_changed(Panel *p)
1397 {
1398 _panel_set_panel_configuration_changed(p->topgwin);
1399 }
1400
1401 void _panel_set_panel_configuration_changed(LXPanel *panel)
1402 {
1403 Panel *p = panel->priv;
1404 GList *plugins, *l;
1405
1406 GtkOrientation previous_orientation = p->orientation;
1407 p->orientation = (p->edge == EDGE_TOP || p->edge == EDGE_BOTTOM)
1408 ? GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL;
1409
1410 /* either first run or orientation was changed */
1411 if (!p->initialized || previous_orientation != p->orientation)
1412 {
1413 panel_adjust_geometry_terminology(p);
1414 if (p->initialized)
1415 p->height = ((p->orientation == GTK_ORIENTATION_HORIZONTAL) ? PANEL_HEIGHT_DEFAULT : PANEL_WIDTH_DEFAULT);
1416 if (p->height_control != NULL)
1417 gtk_spin_button_set_value(GTK_SPIN_BUTTON(p->height_control), p->height);
1418 if ((p->widthtype == WIDTH_PIXEL) && (p->width_control != NULL))
1419 {
1420 int value = ((p->orientation == GTK_ORIENTATION_HORIZONTAL) ? gdk_screen_width() : gdk_screen_height());
1421 gtk_spin_button_set_range(GTK_SPIN_BUTTON(p->width_control), 0, value);
1422 gtk_spin_button_set_value(GTK_SPIN_BUTTON(p->width_control), value);
1423 }
1424 }
1425
1426 /* FIXME: it's deprecated, kept for binary compatibility */
1427 if (p->orientation == GTK_ORIENTATION_HORIZONTAL) {
1428 p->my_box_new = gtk_hbox_new;
1429 p->my_separator_new = gtk_vseparator_new;
1430 } else {
1431 p->my_box_new = gtk_vbox_new;
1432 p->my_separator_new = gtk_hseparator_new;
1433 }
1434
1435 /* recreate the main layout box */
1436 if (p->box != NULL)
1437 {
1438 gtk_orientable_set_orientation(GTK_ORIENTABLE(p->box), p->orientation);
1439 }
1440
1441 /* NOTE: This loop won't be executed when panel started since
1442 plugins are not loaded at that time.
1443 This is used when the orientation of the panel is changed
1444 from the config dialog, and plugins should be re-layout.
1445 */
1446 plugins = p->box ? gtk_container_get_children(GTK_CONTAINER(p->box)) : NULL;
1447 for( l = plugins; l; l = l->next ) {
1448 GtkWidget *w = (GtkWidget*)l->data;
1449 const LXPanelPluginInit *init = PLUGIN_CLASS(w);
1450 if (init->reconfigure)
1451 init->reconfigure(panel, w);
1452 }
1453 g_list_free(plugins);
1454 /* panel geometry changed? update panel background then */
1455 g_idle_add_full( G_PRIORITY_LOW,
1456 (GSourceFunc)delay_update_background, panel, NULL );
1457 }
1458
1459 static int
1460 panel_parse_global(Panel *p, config_setting_t *cfg)
1461 {
1462 const char *str;
1463 gint i;
1464
1465 /* check Global config */
1466 if (!cfg || strcmp(config_setting_get_name(cfg), "Global") != 0)
1467 {
1468 g_warning( "lxpanel: Global section not found");
1469 RET(0);
1470 }
1471 if (config_setting_lookup_string(cfg, "edge", &str))
1472 p->edge = str2num(edge_pair, str, EDGE_NONE);
1473 if (config_setting_lookup_string(cfg, "allign", &str))
1474 p->allign = str2num(allign_pair, str, ALLIGN_NONE);
1475 config_setting_lookup_int(cfg, "monitor", &p->monitor);
1476 config_setting_lookup_int(cfg, "margin", &p->margin);
1477 if (config_setting_lookup_string(cfg, "widthtype", &str))
1478 p->widthtype = str2num(width_pair, str, WIDTH_NONE);
1479 config_setting_lookup_int(cfg, "width", &p->width);
1480 if (config_setting_lookup_string(cfg, "heighttype", &str))
1481 p->heighttype = str2num(height_pair, str, HEIGHT_NONE);
1482 config_setting_lookup_int(cfg, "height", &p->height);
1483 if (config_setting_lookup_int(cfg, "spacing", &i) && i > 0)
1484 p->spacing = i;
1485 if (config_setting_lookup_int(cfg, "setdocktype", &i))
1486 p->setdocktype = i != 0;
1487 if (config_setting_lookup_int(cfg, "setpartialstrut", &i))
1488 p->setstrut = i != 0;
1489 if (config_setting_lookup_int(cfg, "RoundCorners", &i))
1490 p->round_corners = i != 0;
1491 if (config_setting_lookup_int(cfg, "transparent", &i))
1492 p->transparent = i != 0;
1493 if (config_setting_lookup_int(cfg, "alpha", &p->alpha))
1494 {
1495 if (p->alpha > 255)
1496 p->alpha = 255;
1497 }
1498 if (config_setting_lookup_int(cfg, "autohide", &i))
1499 p->autohide = i != 0;
1500 if (config_setting_lookup_int(cfg, "heightwhenhidden", &i))
1501 p->height_when_hidden = MAX(0, i);
1502 if (config_setting_lookup_string(cfg, "tintcolor", &str))
1503 {
1504 if (!gdk_color_parse (str, &p->gtintcolor))
1505 gdk_color_parse ("white", &p->gtintcolor);
1506 p->tintcolor = gcolor2rgb24(&p->gtintcolor);
1507 DBG("tintcolor=%x\n", p->tintcolor);
1508 }
1509 if (config_setting_lookup_int(cfg, "usefontcolor", &i))
1510 p->usefontcolor = i != 0;
1511 if (config_setting_lookup_string(cfg, "fontcolor", &str))
1512 {
1513 if (!gdk_color_parse (str, &p->gfontcolor))
1514 gdk_color_parse ("black", &p->gfontcolor);
1515 p->fontcolor = gcolor2rgb24(&p->gfontcolor);
1516 DBG("fontcolor=%x\n", p->fontcolor);
1517 }
1518 if (config_setting_lookup_int(cfg, "usefontsize", &i))
1519 p->usefontsize = i != 0;
1520 if (config_setting_lookup_int(cfg, "fontsize", &i) && i > 0)
1521 p->fontsize = i;
1522 if (config_setting_lookup_int(cfg, "background", &i))
1523 p->background = i != 0;
1524 if (config_setting_lookup_string(cfg, "backgroundfile", &str))
1525 p->background_file = g_strdup(str);
1526 config_setting_lookup_int(cfg, "iconsize", &p->icon_size);
1527
1528 panel_normalize_configuration(p);
1529
1530 return 1;
1531 }
1532
1533 static int
1534 panel_parse_plugin(LXPanel *p, config_setting_t *cfg)
1535 {
1536 const char *type = NULL;
1537
1538 ENTER;
1539 config_setting_lookup_string(cfg, "type", &type);
1540 DBG("plug %s\n", type);
1541
1542 if (!type || lxpanel_add_plugin(p, type, cfg, -1) == NULL) {
1543 g_warning( "lxpanel: can't load %s plugin", type);
1544 goto error;
1545 }
1546 RET(1);
1547
1548 error:
1549 RET(0);
1550 }
1551
1552 static int panel_start( LXPanel *p )
1553 {
1554 config_setting_t *list, *s;
1555 int i;
1556
1557 /* parse global section */
1558 ENTER;
1559
1560 list = config_setting_get_member(config_root_setting(p->priv->config), "");
1561 if (!list || !panel_parse_global(p->priv, config_setting_get_elem(list, 0)))
1562 RET(0);
1563
1564 panel_start_gui(p);
1565
1566 for (i = 1; (s = config_setting_get_elem(list, i)) != NULL; )
1567 if (strcmp(config_setting_get_name(s), "Plugin") == 0 &&
1568 panel_parse_plugin(p, s)) /* success on plugin start */
1569 i++;
1570 else /* remove invalid data from config */
1571 config_setting_remove_elem(list, i);
1572
1573 /* update backgrond of panel and all plugins */
1574 _panel_update_background(p);
1575 return 1;
1576 }
1577
1578 void panel_destroy(Panel *p)
1579 {
1580 gtk_widget_destroy(GTK_WIDGET(p->topgwin));
1581 }
1582
1583 static LXPanel* panel_new( const char* config_file, const char* config_name )
1584 {
1585 LXPanel* panel = NULL;
1586
1587 if (G_LIKELY(config_file))
1588 {
1589 panel = panel_allocate();
1590 panel->priv->name = g_strdup(config_name);
1591 g_debug("starting panel from file %s",config_file);
1592 if (!config_read_file(panel->priv->config, config_file) ||
1593 !panel_start(panel))
1594 {
1595 g_warning( "lxpanel: can't start panel");
1596 gtk_widget_destroy(GTK_WIDGET(panel));
1597 panel = NULL;
1598 }
1599 }
1600 return panel;
1601 }
1602
1603 static void
1604 usage()
1605 {
1606 g_print(_("lxpanel %s - lightweight GTK2+ panel for UNIX desktops\n"), version);
1607 g_print(_("Command line options:\n"));
1608 g_print(_(" --help -- print this help and exit\n"));
1609 g_print(_(" --version -- print version and exit\n"));
1610 // g_print(_(" --log <number> -- set log level 0-5. 0 - none 5 - chatty\n"));
1611 // g_print(_(" --configure -- launch configuration utility\n"));
1612 g_print(_(" --profile name -- use specified profile\n"));
1613 g_print("\n");
1614 g_print(_(" -h -- same as --help\n"));
1615 g_print(_(" -p -- same as --profile\n"));
1616 g_print(_(" -v -- same as --version\n"));
1617 // g_print(_(" -C -- same as --configure\n"));
1618 g_print(_("\nVisit http://lxde.org/ for detail.\n\n"));
1619 }
1620
1621 /* Lightweight lock related functions - X clipboard hacks */
1622
1623 #define CLIPBOARD_NAME "LXPANEL_SELECTION"
1624
1625 /*
1626 * clipboard_get_func - dummy get_func for gtk_clipboard_set_with_data ()
1627 */
1628 static void
1629 clipboard_get_func(
1630 GtkClipboard *clipboard G_GNUC_UNUSED,
1631 GtkSelectionData *selection_data G_GNUC_UNUSED,
1632 guint info G_GNUC_UNUSED,
1633 gpointer user_data_or_owner G_GNUC_UNUSED)
1634 {
1635 }
1636
1637 /*
1638 * clipboard_clear_func - dummy clear_func for gtk_clipboard_set_with_data ()
1639 */
1640 static void clipboard_clear_func(
1641 GtkClipboard *clipboard G_GNUC_UNUSED,
1642 gpointer user_data_or_owner G_GNUC_UNUSED)
1643 {
1644 }
1645
1646 /*
1647 * Lightweight version for checking single instance.
1648 * Try and get the CLIPBOARD_NAME clipboard instead of using file manipulation.
1649 *
1650 * Returns TRUE if successfully retrieved and FALSE otherwise.
1651 */
1652 static gboolean check_main_lock()
1653 {
1654 static const GtkTargetEntry targets[] = { { CLIPBOARD_NAME, 0, 0 } };
1655 gboolean retval = FALSE;
1656 GtkClipboard *clipboard;
1657 Atom atom;
1658 Display *xdisplay = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
1659
1660 atom = gdk_x11_get_xatom_by_name(CLIPBOARD_NAME);
1661
1662 XGrabServer(xdisplay);
1663
1664 if (XGetSelectionOwner(xdisplay, atom) != None)
1665 goto out;
1666
1667 clipboard = gtk_clipboard_get(gdk_atom_intern(CLIPBOARD_NAME, FALSE));
1668
1669 if (gtk_clipboard_set_with_data(clipboard, targets,
1670 G_N_ELEMENTS (targets),
1671 clipboard_get_func,
1672 clipboard_clear_func, NULL))
1673 retval = TRUE;
1674
1675 out:
1676 XUngrabServer (xdisplay);
1677 gdk_flush ();
1678
1679 return retval;
1680 }
1681 #undef CLIPBOARD_NAME
1682
1683 static void _start_panels_from_dir(const char *panel_dir)
1684 {
1685 GDir* dir = g_dir_open( panel_dir, 0, NULL );
1686 const gchar* name;
1687
1688 if( ! dir )
1689 {
1690 return;
1691 }
1692
1693 while((name = g_dir_read_name(dir)) != NULL)
1694 {
1695 char* panel_config = g_build_filename( panel_dir, name, NULL );
1696 if (strchr(panel_config, '~') == NULL) /* Skip editor backup files in case user has hand edited in this directory */
1697 {
1698 LXPanel* panel = panel_new( panel_config, name );
1699 if( panel )
1700 all_panels = g_slist_prepend( all_panels, panel );
1701 }
1702 g_free( panel_config );
1703 }
1704 g_dir_close( dir );
1705 }
1706
1707 static gboolean start_all_panels( )
1708 {
1709 char *panel_dir;
1710 const gchar * const * dir;
1711
1712 /* try user panels */
1713 panel_dir = _user_config_file_name("panels", NULL);
1714 _start_panels_from_dir(panel_dir);
1715 g_free(panel_dir);
1716 if (all_panels != NULL)
1717 return TRUE;
1718 /* else try XDG fallbacks */
1719 dir = g_get_system_config_dirs();
1720 if (dir) while (dir[0])
1721 {
1722 panel_dir = _system_config_file_name(dir[0], "panels");
1723 _start_panels_from_dir(panel_dir);
1724 g_free(panel_dir);
1725 if (all_panels != NULL)
1726 return TRUE;
1727 dir++;
1728 }
1729 /* last try at old fallback for compatibility reasons */
1730 panel_dir = _old_system_config_file_name("panels");
1731 _start_panels_from_dir(panel_dir);
1732 g_free(panel_dir);
1733 return all_panels != NULL;
1734 }
1735
1736 void load_global_config();
1737 void free_global_config();
1738
1739 static void _ensure_user_config_dirs(void)
1740 {
1741 char *dir = g_build_filename(g_get_user_config_dir(), "lxpanel", cprofile,
1742 "panels", NULL);
1743
1744 /* make sure the private profile and panels dir exists */
1745 g_mkdir_with_parents(dir, 0700);
1746 g_free(dir);
1747 }
1748
1749 int main(int argc, char *argv[], char *env[])
1750 {
1751 int i;
1752 const char* desktop_name;
1753 char *file;
1754
1755 setlocale(LC_CTYPE, "");
1756
1757 g_thread_init(NULL);
1758 /* gdk_threads_init();
1759 gdk_threads_enter(); */
1760
1761 gtk_init(&argc, &argv);
1762
1763 #ifdef ENABLE_NLS
1764 bindtextdomain ( GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR );
1765 bind_textdomain_codeset ( GETTEXT_PACKAGE, "UTF-8" );
1766 textdomain ( GETTEXT_PACKAGE );
1767 #endif
1768
1769 XSetLocaleModifiers("");
1770 XSetErrorHandler((XErrorHandler) panel_handle_x_error);
1771
1772 resolve_atoms();
1773
1774 desktop_name = g_getenv("XDG_CURRENT_DESKTOP");
1775 is_in_lxde = desktop_name && (0 == strcmp(desktop_name, "LXDE"));
1776
1777 for (i = 1; i < argc; i++) {
1778 if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
1779 usage();
1780 exit(0);
1781 } else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) {
1782 printf("lxpanel %s\n", version);
1783 exit(0);
1784 } else if (!strcmp(argv[i], "--log")) {
1785 i++;
1786 if (i == argc) {
1787 g_critical( "lxpanel: missing log level");
1788 usage();
1789 exit(1);
1790 } else {
1791 /* deprecated */
1792 }
1793 } else if (!strcmp(argv[i], "--configure") || !strcmp(argv[i], "-C")) {
1794 config = 1;
1795 } else if (!strcmp(argv[i], "--profile") || !strcmp(argv[i], "-p")) {
1796 i++;
1797 if (i == argc) {
1798 g_critical( "lxpanel: missing profile name");
1799 usage();
1800 exit(1);
1801 } else {
1802 cprofile = g_strdup(argv[i]);
1803 }
1804 } else {
1805 printf("lxpanel: unknown option - %s\n", argv[i]);
1806 usage();
1807 exit(1);
1808 }
1809 }
1810
1811 /* Add a gtkrc file to be parsed too. */
1812 file = _user_config_file_name("gtkrc", NULL);
1813 gtk_rc_parse(file);
1814 g_free(file);
1815
1816 /* Check for duplicated lxpanel instances */
1817 if (!check_main_lock() && !config) {
1818 printf("There is already an instance of LXPanel. Now to exit\n");
1819 exit(1);
1820 }
1821
1822 _ensure_user_config_dirs();
1823
1824 /* Add our own icons to the search path of icon theme */
1825 gtk_icon_theme_append_search_path( gtk_icon_theme_get_default(), PACKAGE_DATA_DIR "/images" );
1826
1827 fbev = fb_ev_new();
1828 win_grp = gtk_window_group_new();
1829
1830 is_restarting = FALSE;
1831
1832 /* init LibFM */
1833 fm_gtk_init(NULL);
1834
1835 /* prepare modules data */
1836 _prepare_modules();
1837
1838 load_global_config();
1839
1840 /* NOTE: StructureNotifyMask is required by XRandR
1841 * See init_randr_support() in gdkscreen-x11.c of gtk+ for detail.
1842 */
1843 gdk_window_set_events(gdk_get_default_root_window(), GDK_STRUCTURE_MASK |
1844 GDK_SUBSTRUCTURE_MASK | GDK_PROPERTY_CHANGE_MASK);
1845 gdk_window_add_filter(gdk_get_default_root_window (), (GdkFilterFunc)panel_event_filter, NULL);
1846
1847 if( G_UNLIKELY( ! start_all_panels() ) )
1848 g_warning( "Config files are not found.\n" );
1849 /*
1850 * FIXME: configure??
1851 if (config)
1852 configure();
1853 */
1854 gtk_main();
1855
1856 XSelectInput (GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), GDK_ROOT_WINDOW(), NoEventMask);
1857 gdk_window_remove_filter(gdk_get_default_root_window (), (GdkFilterFunc)panel_event_filter, NULL);
1858
1859 /* destroy all panels */
1860 g_slist_foreach( all_panels, (GFunc) gtk_widget_destroy, NULL );
1861 g_slist_free( all_panels );
1862 all_panels = NULL;
1863 g_free( cfgfile );
1864
1865 free_global_config();
1866
1867 _unload_modules();
1868 fm_gtk_finalize();
1869
1870 /* gdk_threads_leave(); */
1871
1872 g_object_unref(win_grp);
1873 g_object_unref(fbev);
1874
1875 if (!is_restarting)
1876 return 0;
1877 if (strchr(argv[0], G_DIR_SEPARATOR))
1878 execve(argv[0], argv, env);
1879 else
1880 execve(g_find_program_in_path(argv[0]), argv, env);
1881 return 1;
1882 }
1883
1884 GtkOrientation panel_get_orientation(LXPanel *panel)
1885 {
1886 return panel->priv->orientation;
1887 }
1888
1889 gint panel_get_icon_size(LXPanel *panel)
1890 {
1891 return panel->priv->icon_size;
1892 }
1893
1894 gint panel_get_height(LXPanel *panel)
1895 {
1896 return panel->priv->height;
1897 }
1898
1899 Window panel_get_xwindow(LXPanel *panel)
1900 {
1901 return panel->priv->topxwin;
1902 }
1903
1904 gint panel_get_monitor(LXPanel *panel)
1905 {
1906 return panel->priv->monitor;
1907 }
1908
1909 GtkStyle *panel_get_defstyle(LXPanel *panel)
1910 {
1911 return panel->priv->defstyle;
1912 }
1913
1914 GtkIconTheme *panel_get_icon_theme(LXPanel *panel)
1915 {
1916 return panel->priv->icon_theme;
1917 }
1918
1919 gboolean panel_is_at_bottom(LXPanel *panel)
1920 {
1921 return panel->priv->edge == EDGE_BOTTOM;
1922 }
1923
1924 gboolean panel_is_dynamic(LXPanel *panel)
1925 {
1926 return panel->priv->widthtype == WIDTH_REQUEST;
1927 }
1928
1929 GtkWidget *panel_box_new(LXPanel *panel, gboolean homogeneous, gint spacing)
1930 {
1931 if (panel->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
1932 return gtk_hbox_new(homogeneous, spacing);
1933 return gtk_vbox_new(homogeneous, spacing);
1934 }
1935
1936 GtkWidget *panel_separator_new(LXPanel *panel)
1937 {
1938 if (panel->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
1939 return gtk_vseparator_new();
1940 return gtk_hseparator_new();
1941 }
1942
1943 gboolean _class_is_present(const LXPanelPluginInit *init)
1944 {
1945 GSList *sl;
1946
1947 for (sl = all_panels; sl; sl = sl->next )
1948 {
1949 LXPanel *panel = (LXPanel*)sl->data;
1950 GList *plugins, *p;
1951
1952 plugins = gtk_container_get_children(GTK_CONTAINER(panel->priv->box));
1953 for (p = plugins; p; p = p->next)
1954 if (PLUGIN_CLASS(p->data) == init)
1955 {
1956 g_list_free(plugins);
1957 return TRUE;
1958 }
1959 g_list_free(plugins);
1960 }
1961 return FALSE;
1962 }