Add GTK+3 support code into paint_root_pixmap(), never tested.
[lxde/lxpanel.git] / src / panel.c
index 3d25116..58cb199 100644 (file)
@@ -1,5 +1,5 @@
-/**
- * Copyright (c) 2006 LxDE Developers, see the file AUTHORS for details.
+/*
+ * Copyright (c) 2006-2014 LxDE Developers, see the file AUTHORS for details.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 #include <gdk/gdkx.h>
 #include <libfm/fm-gtk.h>
 
+#define __LXPANEL_INTERNALS__
+
 #include "private.h"
 #include "misc.h"
-#include "bg.h"
 
 #include "lxpanelctl.h"
 #include "dbg.h"
+#include "gtk-compat.h"
 
-static gchar *cfgfile = NULL;
-static gchar version[] = VERSION;
 gchar *cprofile = "default";
 
-static GtkWindowGroup* win_grp; /* window group used to limit the scope of model dialog. */
-
-static int config = 0;
-FbEv *fbev = NULL;
-
 GSList* all_panels = NULL;  /* a single-linked list storing all panels */
 
-gboolean is_restarting = FALSE;
+gboolean is_in_lxde = FALSE;
 
-static int panel_start(Panel *p);
-static void panel_start_gui(Panel *p);
+static GtkWindowGroup* win_grp = NULL; /* window group used to limit the scope of model dialog. */
 
-gboolean is_in_lxde = FALSE;
+static gulong monitors_handler = 0;
 
-/* A hack used to be compatible with Gnome panel for gtk+ themes.
- * Some gtk+ themes define special styles for desktop panels.
- * http://live.gnome.org/GnomeArt/Tutorials/GtkThemes/GnomePanel
- * So we make a derived class from GtkWindow named PanelToplevel
- * and create the panels with it to be compatible with Gnome themes.
- */
-#define PANEL_TOPLEVEL_TYPE                            (panel_toplevel_get_type())
+static void panel_start_gui(LXPanel *p, config_setting_t *list);
+static void ah_start(LXPanel *p);
+static void ah_stop(LXPanel *p);
+static void _panel_update_background(LXPanel * p);
 
-typedef struct _PanelToplevel                  PanelToplevel;
-typedef struct _PanelToplevelClass             PanelToplevelClass;
-struct _PanelToplevel
+enum
 {
-       GtkWindow parent;
+    ICON_SIZE_CHANGED,
+    PANEL_FONT_CHANGED,
+    N_SIGNALS
 };
-struct _PanelToplevelClass
+
+static guint signals[N_SIGNALS];
+
+G_DEFINE_TYPE(PanelToplevel, lxpanel, GTK_TYPE_WINDOW);
+
+static void lxpanel_finalize(GObject *object)
 {
-       GtkWindowClass parent_class;
-};
-G_DEFINE_TYPE(PanelToplevel, panel_toplevel, GTK_TYPE_WINDOW);
-static void panel_toplevel_class_init(PanelToplevelClass *klass)
+    LXPanel *self = LXPANEL(object);
+    Panel *p = self->priv;
+
+    if( p->config_changed )
+        lxpanel_config_save( self );
+    config_destroy(p->config);
+
+    //XFree(p->workarea);
+    g_free( p->background_file );
+    g_slist_free( p->system_menus );
+
+    g_free( p->name );
+    g_free(p);
+
+    G_OBJECT_CLASS(lxpanel_parent_class)->finalize(object);
+}
+
+static void panel_stop_gui(LXPanel *self)
+{
+    Panel *p = self->priv;
+    Display *xdisplay;
+
+    g_debug("panel_stop_gui on '%s'", p->name);
+    if (p->autohide)
+        ah_stop(self);
+
+    if (p->pref_dialog != NULL)
+        gtk_widget_destroy(p->pref_dialog);
+    p->pref_dialog = NULL;
+
+    if (p->plugin_pref_dialog != NULL)
+        /* just close the dialog, it will do all required cleanup */
+        gtk_dialog_response(GTK_DIALOG(p->plugin_pref_dialog), GTK_RESPONSE_CLOSE);
+
+
+    if (p->initialized)
+    {
+        gtk_window_group_remove_window(win_grp, GTK_WINDOW(self));
+        xdisplay = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
+        gdk_flush();
+        XFlush(xdisplay);
+        XSync(xdisplay, True);
+        p->initialized = FALSE;
+    }
+    if (p->surface != NULL)
+    {
+        cairo_surface_destroy(p->surface);
+        p->surface = NULL;
+    }
+
+    if (p->background_update_queued)
+    {
+        g_source_remove(p->background_update_queued);
+        p->background_update_queued = 0;
+    }
+    if (p->strut_update_queued)
+    {
+        g_source_remove(p->strut_update_queued);
+        p->strut_update_queued = 0;
+    }
+
+    if (gtk_bin_get_child(GTK_BIN(self)))
+    {
+        gtk_widget_destroy(p->box);
+        p->box = NULL;
+    }
+}
+
+static void lxpanel_destroy(GtkObject *object)
 {
+    LXPanel *self = LXPANEL(object);
+
+    panel_stop_gui(self);
+
+    GTK_OBJECT_CLASS(lxpanel_parent_class)->destroy(object);
 }
-static void panel_toplevel_init(PanelToplevel *self)
+
+static gboolean idle_update_background(gpointer p)
 {
+    LXPanel *panel = LXPANEL(p);
+
+    if (g_source_is_destroyed(g_main_current_source()))
+        return FALSE;
+
+    /* Panel could be destroyed while background update scheduled */
+    if (gtk_widget_get_realized(p))
+    {
+        gdk_display_sync( gtk_widget_get_display(p) );
+        _panel_update_background(panel);
+    }
+    panel->priv->background_update_queued = 0;
+
+    return FALSE;
 }
 
-/* Allocate and initialize new Panel structure. */
-static Panel* panel_allocate(void)
+void _panel_queue_update_background(LXPanel *panel)
+{
+    if (panel->priv->background_update_queued)
+        return;
+    panel->priv->background_update_queued = g_idle_add_full(G_PRIORITY_HIGH,
+                                                            idle_update_background,
+                                                            panel, NULL);
+}
+
+static gboolean idle_update_strut(gpointer p)
+{
+    LXPanel *panel = LXPANEL(p);
+
+    if (g_source_is_destroyed(g_main_current_source()))
+        return FALSE;
+
+    _panel_set_wm_strut(panel);
+    panel->priv->strut_update_queued = 0;
+
+    return FALSE;
+}
+
+static void lxpanel_realize(GtkWidget *widget)
+{
+    GTK_WIDGET_CLASS(lxpanel_parent_class)->realize(widget);
+
+    _panel_queue_update_background(LXPANEL(widget));
+}
+
+static void lxpanel_style_set(GtkWidget *widget, GtkStyle* prev)
+{
+    GTK_WIDGET_CLASS(lxpanel_parent_class)->style_set(widget, prev);
+
+    /* FIXME: This dirty hack is used to fix the background of systray... */
+    _panel_queue_update_background(LXPANEL(widget));
+}
+
+static void lxpanel_size_request(GtkWidget *widget, GtkRequisition *req)
+{
+    LXPanel *panel = LXPANEL(widget);
+    Panel *p = panel->priv;
+    GdkRectangle rect;
+
+    GTK_WIDGET_CLASS(lxpanel_parent_class)->size_request(widget, req);
+
+    if (!p->visible)
+        /* When the panel is in invisible state, the content box also got hidden, thus always
+         * report 0 size.  Ask the content box instead for its size. */
+        gtk_widget_size_request(p->box, req);
+
+    rect.width = req->width;
+    rect.height = req->height;
+    _calculate_position(panel, &rect);
+    req->width = rect.width;
+    req->height = rect.height;
+}
+
+static void lxpanel_size_allocate(GtkWidget *widget, GtkAllocation *a)
+{
+    LXPanel *panel = LXPANEL(widget);
+    Panel *p = panel->priv;
+    GdkRectangle rect;
+    gint x, y;
+
+    GTK_WIDGET_CLASS(lxpanel_parent_class)->size_allocate(widget, a);
+
+    if (p->widthtype == WIDTH_REQUEST)
+        p->width = (p->orientation == GTK_ORIENTATION_HORIZONTAL) ? a->width : a->height;
+    if (p->heighttype == HEIGHT_REQUEST)
+        p->height = (p->orientation == GTK_ORIENTATION_HORIZONTAL) ? a->height : a->width;
+
+    if (!gtk_widget_get_realized(widget))
+        return;
+
+    rect = *a;
+    /* get real coords since a contains 0, 0 */
+    gdk_window_get_origin(gtk_widget_get_window(widget), &x, &y);
+    _calculate_position(panel, &rect);
+    p->ax = rect.x;
+    p->ay = rect.y;
+
+    if (a->width != p->aw || a->height != p->ah || x != p->ax || y != p->ay)
+    {
+        p->aw = a->width;
+        p->ah = a->height;
+        /* FIXME: should we "correct" requested sizes? */
+        gtk_window_move(GTK_WINDOW(widget), p->ax, p->ay);
+        /* SF bug #708: strut update does not work while in size allocation */
+        if (!panel->priv->strut_update_queued)
+            panel->priv->strut_update_queued = g_idle_add_full(G_PRIORITY_HIGH,
+                                                               idle_update_strut,
+                                                               panel, NULL);
+        _panel_queue_update_background(panel);
+    }
+
+    if (gtk_widget_get_mapped(widget))
+        _panel_establish_autohide(panel);
+}
+
+static gboolean lxpanel_configure_event (GtkWidget *widget, GdkEventConfigure *e)
+{
+    Panel *p = LXPANEL(widget)->priv;
+
+    p->cw = e->width;
+    p->ch = e->height;
+    p->cx = e->x;
+    p->cy = e->y;
+
+    return GTK_WIDGET_CLASS(lxpanel_parent_class)->configure_event(widget, e);
+}
+
+static gboolean lxpanel_map_event(GtkWidget *widget, GdkEventAny *event)
 {
-    Panel* p = g_new0(Panel, 1);
+    Panel *p = PLUGIN_PANEL(widget)->priv;
+
+    if (p->autohide)
+        ah_start(LXPANEL(widget));
+    return GTK_WIDGET_CLASS(lxpanel_parent_class)->map_event(widget, event);
+}
+
+/* Handler for "button_press_event" signal with Panel as parameter. */
+static gboolean lxpanel_button_press(GtkWidget *widget, GdkEventButton *event)
+{
+    if (event->button == 3) /* right button */
+    {
+        GtkMenu* popup = (GtkMenu*) lxpanel_get_plugin_menu(LXPANEL(widget), NULL, FALSE);
+        gtk_menu_popup(popup, NULL, NULL, NULL, NULL, event->button, event->time);
+        return TRUE;
+    }
+    return FALSE;
+}
+
+static void lxpanel_class_init(PanelToplevelClass *klass)
+{
+    GObjectClass *gobject_class = (GObjectClass *)klass;
+    GtkObjectClass *gtk_object_class = (GtkObjectClass *)klass;
+    GtkWidgetClass *widget_class = (GtkWidgetClass *)klass;
+
+    gobject_class->finalize = lxpanel_finalize;
+    gtk_object_class->destroy = lxpanel_destroy;
+    widget_class->realize = lxpanel_realize;
+    widget_class->size_request = lxpanel_size_request;
+    widget_class->size_allocate = lxpanel_size_allocate;
+    widget_class->configure_event = lxpanel_configure_event;
+    widget_class->style_set = lxpanel_style_set;
+    widget_class->map_event = lxpanel_map_event;
+    widget_class->button_press_event = lxpanel_button_press;
+
+    signals[ICON_SIZE_CHANGED] =
+        g_signal_new("icon-size-changed",
+                     G_TYPE_FROM_CLASS(klass),
+                     G_SIGNAL_RUN_LAST,
+                     G_STRUCT_OFFSET(PanelToplevelClass, icon_size_changed),
+                     NULL, NULL,
+                     g_cclosure_marshal_VOID__VOID,
+                     G_TYPE_NONE, 0, G_TYPE_NONE);
+
+    signals[PANEL_FONT_CHANGED] =
+        g_signal_new("panel-font-changed",
+                     G_TYPE_FROM_CLASS(klass),
+                     G_SIGNAL_RUN_LAST,
+                     G_STRUCT_OFFSET(PanelToplevelClass, panel_font_changed),
+                     NULL, NULL,
+                     g_cclosure_marshal_VOID__VOID,
+                     G_TYPE_NONE, 0, G_TYPE_NONE);
+}
+
+static void lxpanel_init(PanelToplevel *self)
+{
+    Panel *p = g_new0(Panel, 1);
+
+    self->priv = p;
+    p->topgwin = self;
     p->allign = ALLIGN_CENTER;
     p->edge = EDGE_NONE;
     p->widthtype = WIDTH_PERCENT;
@@ -112,7 +362,31 @@ static Panel* panel_allocate(void)
     p->icon_size = PANEL_ICON_SIZE;
     p->icon_theme = gtk_icon_theme_get_default();
     p->config = config_new();
-    return p;
+    p->defstyle = gtk_widget_get_default_style();
+}
+
+/* Allocate and initialize new Panel structure. */
+static LXPanel* panel_allocate(void)
+{
+    return g_object_new(LX_TYPE_PANEL,
+                        "border-width", 0,
+                        "decorated", FALSE,
+                        "name", "PanelToplevel",
+                        "resizable", FALSE,
+                        "title", "panel",
+                        "type-hint", GDK_WINDOW_TYPE_HINT_DOCK,
+                        "window-position", GTK_WIN_POS_NONE,
+                        NULL);
+}
+
+void _panel_emit_icon_size_changed(LXPanel *p)
+{
+    g_signal_emit(p, signals[ICON_SIZE_CHANGED], 0);
+}
+
+void _panel_emit_font_changed(LXPanel *p)
+{
+    g_signal_emit(p, signals[PANEL_FONT_CHANGED], 0);
 }
 
 /* Normalize panel configuration after load from file or reconfiguration. */
@@ -131,46 +405,142 @@ static void panel_normalize_configuration(Panel* p)
             p->height = PANEL_HEIGHT_MAX;
     }
     if (p->monitor < 0)
-        p->monitor = 0;
+        p->monitor = -1;
     if (p->background)
         p->transparent = 0;
 }
 
+gboolean _panel_edge_can_strut(LXPanel *panel, int edge, gint monitor, gulong *size)
+{
+    Panel *p;
+    GdkScreen *screen;
+    GdkRectangle rect;
+    GdkRectangle rect2;
+    gint n, i;
+    gulong s;
+
+    if (!gtk_widget_get_mapped(GTK_WIDGET(panel)))
+        return FALSE;
+
+    p = panel->priv;
+    /* Handle autohide case.  EWMH recommends having the strut be the minimized size. */
+    if (p->autohide)
+        s = p->height_when_hidden;
+    else switch (edge)
+    {
+    case EDGE_LEFT:
+    case EDGE_RIGHT:
+        s = p->aw;
+        break;
+    case EDGE_TOP:
+    case EDGE_BOTTOM:
+        s = p->ah;
+        break;
+    default: /* error! */
+        return FALSE;
+    }
+    if (s == 0)
+        return FALSE; /* nothing to strut here */
+
+    if (monitor < 0) /* screen span */
+    {
+        if (G_LIKELY(size))
+            *size = s;
+        return TRUE;
+    }
+
+    screen = gtk_widget_get_screen(GTK_WIDGET(panel));
+    n = gdk_screen_get_n_monitors(screen);
+    if (monitor >= n) /* hidden now */
+        return FALSE;
+    gdk_screen_get_monitor_geometry(screen, monitor, &rect);
+    switch (edge)
+    {
+        case EDGE_LEFT:
+            rect.width = rect.x;
+            rect.x = 0;
+            s += rect.width;
+            break;
+        case EDGE_RIGHT:
+            rect.x += rect.width;
+            rect.width = gdk_screen_get_width(screen) - rect.x;
+            s += rect.width;
+            break;
+        case EDGE_TOP:
+            rect.height = rect.y;
+            rect.y = 0;
+            s += rect.height;
+            break;
+        case EDGE_BOTTOM:
+            rect.y += rect.height;
+            rect.height = gdk_screen_get_height(screen) - rect.y;
+            s += rect.height;
+            break;
+        default: ;
+    }
+    if (rect.height == 0 || rect.width == 0) ; /* on a border of monitor */
+    else
+    {
+        for (i = 0; i < n; i++)
+        {
+            if (i == monitor)
+                continue;
+            gdk_screen_get_monitor_geometry(screen, i, &rect2);
+            if (gdk_rectangle_intersect(&rect, &rect2, NULL))
+                /* that monitor lies over the edge */
+                return FALSE;
+        }
+    }
+    if (G_LIKELY(size))
+        *size = s;
+    return TRUE;
+}
+
 /****************************************************
  *         panel's handlers for WM events           *
  ****************************************************/
 
 void panel_set_wm_strut(Panel *p)
 {
+    _panel_set_wm_strut(p->topgwin);
+}
+
+void _panel_set_wm_strut(LXPanel *panel)
+{
     int index;
+    Display *xdisplay = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
+    Panel *p = panel->priv;
     gulong strut_size;
     gulong strut_lower;
     gulong strut_upper;
 
+    if (!gtk_widget_get_mapped(GTK_WIDGET(panel)))
+        return;
+    /* most wm's tend to ignore struts of unmapped windows, and that's how
+     * lxpanel hides itself. so no reason to set it. */
+    if (p->autohide && p->height_when_hidden <= 0)
+        return;
+
     /* Dispatch on edge to set up strut parameters. */
     switch (p->edge)
     {
         case EDGE_LEFT:
             index = 0;
-            strut_size = p->aw;
             strut_lower = p->ay;
             strut_upper = p->ay + p->ah;
             break;
         case EDGE_RIGHT:
             index = 1;
-            strut_size = p->aw;
             strut_lower = p->ay;
             strut_upper = p->ay + p->ah;
             break;
         case EDGE_TOP:
             index = 2;
-            strut_size = p->ah;
             strut_lower = p->ax;
             strut_upper = p->ax + p->aw;
             break;
         case EDGE_BOTTOM:
             index = 3;
-            strut_size = p->ah;
             strut_lower = p->ax;
             strut_upper = p->ax + p->aw;
             break;
@@ -178,18 +548,15 @@ void panel_set_wm_strut(Panel *p)
             return;
     }
 
-    /* Handle autohide case.  EWMH recommends having the strut be the minimized size. */
-    if (p->autohide)
-        strut_size = p->height_when_hidden;
-
     /* Set up strut value in property format. */
     gulong desired_strut[12];
     memset(desired_strut, 0, sizeof(desired_strut));
-    if (p->setstrut)
+    if (p->setstrut &&
+        _panel_edge_can_strut(panel, p->edge, p->monitor, &strut_size))
     {
         desired_strut[index] = strut_size;
         desired_strut[4 + index * 2] = strut_lower;
-        desired_strut[5 + index * 2] = strut_upper;
+        desired_strut[5 + index * 2] = strut_upper - 1;
     }
     else
     {
@@ -200,8 +567,7 @@ void panel_set_wm_strut(Panel *p)
 
     /* If strut value changed, set the property value on the panel window.
      * This avoids property change traffic when the panel layout is recalculated but strut geometry hasn't changed. */
-    if ((GTK_WIDGET_MAPPED(p->topgwin))
-    && ((p->strut_size != strut_size) || (p->strut_lower != strut_lower) || (p->strut_upper != strut_upper) || (p->strut_edge != p->edge)))
+    if ((p->strut_size != strut_size) || (p->strut_lower != strut_lower) || (p->strut_upper != strut_upper) || (p->strut_edge != p->edge))
     {
         p->strut_size = strut_size;
         p->strut_lower = strut_lower;
@@ -212,365 +578,409 @@ void panel_set_wm_strut(Panel *p)
          * Set STRUT also for window managers that do not support STRUT_PARTIAL. */
         if (strut_size != 0)
         {
-            XChangeProperty(GDK_DISPLAY(), p->topxwin, a_NET_WM_STRUT_PARTIAL,
+            XChangeProperty(xdisplay, p->topxwin, a_NET_WM_STRUT_PARTIAL,
                 XA_CARDINAL, 32, PropModeReplace,  (unsigned char *) desired_strut, 12);
-            XChangeProperty(GDK_DISPLAY(), p->topxwin, a_NET_WM_STRUT,
+            XChangeProperty(xdisplay, p->topxwin, a_NET_WM_STRUT,
                 XA_CARDINAL, 32, PropModeReplace,  (unsigned char *) desired_strut, 4);
         }
         else
         {
-            XDeleteProperty(GDK_DISPLAY(), p->topxwin, a_NET_WM_STRUT);
-            XDeleteProperty(GDK_DISPLAY(), p->topxwin, a_NET_WM_STRUT_PARTIAL);
+            XDeleteProperty(xdisplay, p->topxwin, a_NET_WM_STRUT);
+            XDeleteProperty(xdisplay, p->topxwin, a_NET_WM_STRUT_PARTIAL);
         }
     }
 }
 
-/* defined in configurator.c */
-void panel_configure(Panel* p, int sel_page );
-gboolean panel_edge_available(Panel* p, int edge, gint monitor);
-
-/* built-in commands, defined in configurator.c */
-void restart(void);
-void gtk_run(void);
-void panel_destroy(Panel *p);
+/****************************************************
+ *         panel's handlers for GTK events          *
+ ****************************************************/
 
-static void process_client_msg ( XClientMessageEvent* ev )
-{
-    int cmd = ev->data.b[0];
-    switch( cmd )
+static void paint_root_pixmap(LXPanel *panel, cairo_t *cr)
+{
+    /*
+     * this code was extracted from code for FbBg object
+     *
+     * Copyright (C) 2001, 2002 Ian McKellar <yakk@yakk.net>
+     *                     2002 Sun Microsystems, Inc.
+     */
+    XGCValues gcv;
+    uint mask;
+    Window xroot;
+    GC gc;
+    Display *dpy;
+    Pixmap *prop;
+#if GTK_CHECK_VERSION(3, 0, 0)
+    cairo_surface_t *surface;
+#else
+    GdkPixmap *pixmap;
+#endif
+    Pixmap xpixmap;
+    Panel *p = panel->priv;
+
+    dpy = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
+    xroot = DefaultRootWindow(dpy);
+    gcv.ts_x_origin = 0;
+    gcv.ts_y_origin = 0;
+    gcv.fill_style = FillTiled;
+    mask = GCTileStipXOrigin | GCTileStipYOrigin | GCFillStyle;
+    prop = get_xaproperty(xroot, a_XROOTPMAP_ID, XA_PIXMAP, NULL);
+    if (prop)
     {
-#ifndef DISABLE_MENU
-        case LXPANEL_CMD_SYS_MENU:
-        {
-            GSList* l;
-            for( l = all_panels; l; l = l->next )
-            {
-                Panel* p = (Panel*)l->data;
-                GList *plugins, *pl;
-
-                plugins = gtk_container_get_children(GTK_CONTAINER(p->box));
-                for (pl = plugins; pl; pl = pl->next)
-                {
-                    LXPanelPluginInit *init = PLUGIN_CLASS(pl->data);
-                    if (init->show_system_menu)
-                        /* queue to show system menu */
-                        init->show_system_menu(pl->data);
-                }
-                g_list_free(plugins);
-            }
-            break;
-        }
+        gcv.tile = *prop;
+        mask |= GCTile;
+        XFree(prop);
+    }
+    gc = XCreateGC(dpy, xroot, mask, &gcv);
+#if GTK_CHECK_VERSION(3, 0, 0)
+    xpixmap = XCreatePixmap(dpy, xroot, p->aw, p->ah,
+                            DefaultDepth(dpy, DefaultScreen(dpy)));
+    surface = cairo_xlib_surface_create(dpy, xpixmap,
+                                        DefaultVisual(dpy, DefaultScreen(dpy)),
+                                        p->aw, p->ah);
+#else
+    pixmap = gdk_pixmap_new(gtk_widget_get_window(GTK_WIDGET(panel)),
+                            p->aw, p->ah, -1);
+    xpixmap = gdk_x11_drawable_get_xid(pixmap);
 #endif
-#ifndef DISABLE_MENU
-        case LXPANEL_CMD_RUN:
-            gtk_run();
-            break;
+    XSetTSOrigin(dpy, gc, -p->ax, -p->ay);
+    XFillRectangle(dpy, xpixmap, gc, 0, 0, p->aw, p->ah);
+    XFreeGC(dpy, gc);
+#if GTK_CHECK_VERSION(3, 0, 0)
+    cairo_set_source_surface(cr, surface, 0, 0);
+#else
+    gdk_cairo_set_source_pixmap(cr, pixmap, 0, 0);
+#endif
+    cairo_paint(cr);
+#if GTK_CHECK_VERSION(3, 0, 0)
+    cairo_surface_destroy(surface);
+    XFreePixmap(xpixmap);
+#else
+    g_object_unref(pixmap);
 #endif
-        case LXPANEL_CMD_CONFIG:
-            {
-            Panel * p = ((all_panels != NULL) ? all_panels->data : NULL);
-            if (p != NULL)
-                panel_configure(p, 0);
-            }
-            break;
-        case LXPANEL_CMD_RESTART:
-            restart();
-            break;
-        case LXPANEL_CMD_EXIT:
-            gtk_main_quit();
-            break;
-    }
 }
 
-static GdkFilterReturn
-panel_event_filter(GdkXEvent *xevent, GdkEvent *event, gpointer not_used)
+void panel_determine_background_pixmap(Panel * panel, GtkWidget * widget, GdkWindow * window)
 {
-    Atom at;
-    Window win;
-    XEvent *ev = (XEvent *) xevent;
+    _panel_determine_background_pixmap(panel->topgwin, widget);
+}
 
-    ENTER;
-    DBG("win = 0x%x\n", ev->xproperty.window);
-    if (ev->type != PropertyNotify )
+void _panel_determine_background_pixmap(LXPanel * panel, GtkWidget * widget)
+{
+    GdkPixmap * pixmap = NULL;
+    GdkWindow * window = gtk_widget_get_window(widget);
+    Panel * p = panel->priv;
+    cairo_t *cr;
+    GtkAllocation alloc;
+    gint x = 0, y = 0;
+
+    if (!p->background && !p->transparent)
+        goto not_paintable;
+    else if (p->aw <= 1 || p->ah <= 1)
+        goto not_paintable;
+    else if (p->surface == NULL)
     {
-        /* private client message from lxpanelctl */
-        if( ev->type == ClientMessage && ev->xproperty.atom == a_LXPANEL_CMD )
-        {
-            process_client_msg( (XClientMessageEvent*)ev );
-        }
-        else if( ev->type == DestroyNotify )
-        {
-            fb_ev_emit_destroy( fbev, ((XDestroyWindowEvent*)ev)->window );
-        }
-        RET(GDK_FILTER_CONTINUE);
-    }
+        GdkPixbuf *pixbuf = NULL;
 
-    at = ev->xproperty.atom;
-    win = ev->xproperty.window;
-    if (win == GDK_ROOT_WINDOW())
-    {
-        if (at == a_NET_CLIENT_LIST)
-        {
-            fb_ev_emit(fbev, EV_CLIENT_LIST);
-        }
-        else if (at == a_NET_CURRENT_DESKTOP)
+        p->surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, p->aw, p->ah);
+        cr = cairo_create(p->surface);
+        if (p->background)
         {
-            GSList* l;
-            for( l = all_panels; l; l = l->next )
-                ((Panel*)l->data)->curdesk = get_net_current_desktop();
-            fb_ev_emit(fbev, EV_CURRENT_DESKTOP);
+            /* User specified background pixmap. */
+            pixbuf = gdk_pixbuf_new_from_file(p->background_file, NULL);
         }
-        else if (at == a_NET_NUMBER_OF_DESKTOPS)
+        if ((p->transparent && p->alpha != 255) || /* ignore it for opaque panel */
+            (pixbuf != NULL && gdk_pixbuf_get_has_alpha(pixbuf)))
         {
-            GSList* l;
-            for( l = all_panels; l; l = l->next )
-                ((Panel*)l->data)->desknum = get_net_number_of_desktops();
-            fb_ev_emit(fbev, EV_NUMBER_OF_DESKTOPS);
+            /* Transparent.  Determine the appropriate value from the root pixmap. */
+            paint_root_pixmap(panel, cr);
         }
-        else if (at == a_NET_DESKTOP_NAMES)
+        if (pixbuf != NULL)
         {
-            fb_ev_emit(fbev, EV_DESKTOP_NAMES);
-        }
-        else if (at == a_NET_ACTIVE_WINDOW)
-        {
-            fb_ev_emit(fbev, EV_ACTIVE_WINDOW );
-        }
-        else if (at == a_NET_CLIENT_LIST_STACKING)
-        {
-            fb_ev_emit(fbev, EV_CLIENT_LIST_STACKING);
-        }
-        else if (at == a_XROOTPMAP_ID)
-        {
-            GSList* l;
-            for( l = all_panels; l; l = l->next )
-            {
-                Panel* p = (Panel*)l->data;
-                if (p->transparent) {
-                    fb_bg_notify_changed_bg(p->bg);
+            gint w = gdk_pixbuf_get_width(pixbuf);
+            gint h = gdk_pixbuf_get_height(pixbuf);
+
+            /* Tile the image */
+            for (y = 0; y < p->ah; y += h)
+                for (x = 0; x < p->aw; x += w)
+                {
+                    gdk_cairo_set_source_pixbuf(cr, pixbuf, x, y);
+                    cairo_paint(cr);
                 }
-            }
-        }
-        else if (at == a_NET_WORKAREA)
-        {
-            GSList* l;
-            for( l = all_panels; l; l = l->next )
-            {
-                Panel* p = (Panel*)l->data;
-                g_free( p->workarea );
-                p->workarea = get_xaproperty (GDK_ROOT_WINDOW(), a_NET_WORKAREA, XA_CARDINAL, &p->wa_len);
-                /* print_wmdata(p); */
-            }
+            y = 0;
+            g_object_unref(pixbuf);
         }
         else
-            return GDK_FILTER_CONTINUE;
-
-        return GDK_FILTER_REMOVE;
-    }
-    return GDK_FILTER_CONTINUE;
-}
-
-/****************************************************
- *         panel's handlers for GTK events          *
- ****************************************************/
-
-
-static gint
-panel_delete_event(GtkWidget * widget, GdkEvent * event, gpointer data)
-{
-    ENTER;
-    RET(FALSE);
-}
-
-static gint
-panel_destroy_event(GtkWidget * widget, GdkEvent * event, gpointer data)
-{
-    //Panel *p = (Panel *) data;
-    //if (!p->self_destroy)
-    gtk_main_quit();
-    RET(FALSE);
-}
-
-static void
-on_root_bg_changed(FbBg *bg, Panel* p)
-{
-    panel_update_background( p );
-}
-
-void panel_determine_background_pixmap(Panel * p, GtkWidget * widget, GdkWindow * window)
-{
-    GdkPixmap * pixmap = NULL;
-
-    /* Free p->bg if it is not going to be used. */
-    if (( ! p->transparent) && (p->bg != NULL))
-    {
-        g_signal_handlers_disconnect_by_func(G_OBJECT(p->bg), on_root_bg_changed, p);
-        g_object_unref(p->bg);
-        p->bg = NULL;
-    }
-
-    if (p->background)
-    {
-        /* User specified background pixmap. */
-        if (p->background_file != NULL)
-            pixmap = fb_bg_get_pix_from_file(widget, p->background_file);
-    }
-
-    else if (p->transparent)
-    {
-        /* Transparent.  Determine the appropriate value from the root pixmap. */
-        if (p->bg == NULL)
         {
-            p->bg = fb_bg_get_for_display();
-            g_signal_connect(G_OBJECT(p->bg), "changed", G_CALLBACK(on_root_bg_changed), p);
+            /* Either color is set or image is invalid, fill the background */
+            gdk_cairo_set_source_color(cr, &p->gtintcolor);
+            cairo_paint_with_alpha(cr, p->transparent ? (double)p->alpha/255 : 1.0);
         }
-        pixmap = fb_bg_get_xroot_pix_for_win(p->bg, widget);
-        if ((pixmap != NULL) && (pixmap != GDK_NO_BG) && (p->alpha != 0))
-            fb_bg_composite(pixmap, &p->gtintcolor, p->alpha);
+        cairo_destroy(cr);
     }
 
-    if (pixmap != NULL)
+    if (p->surface != NULL)
     {
-        gtk_widget_set_app_paintable(widget, TRUE );
+        gtk_widget_set_app_paintable(widget, TRUE);
+        gtk_widget_get_allocation(widget, &alloc);
+        pixmap = gdk_pixmap_new(window, alloc.width, alloc.height, -1);
+        cr = gdk_cairo_create(pixmap);
+        gtk_widget_translate_coordinates(widget, GTK_WIDGET(panel), 0, 0, &x, &y);
+        cairo_set_source_surface(cr, p->surface, 0.0 - x, 0.0 - y);
+        cairo_paint(cr);
+        cairo_destroy(cr);
         gdk_window_set_back_pixmap(window, pixmap, FALSE);
         g_object_unref(pixmap);
     }
     else
+    {
+not_paintable:
         gtk_widget_set_app_paintable(widget, FALSE);
+        /* Free p->bg if it is not going to be used. */
+    }
 }
 
 /* Update the background of the entire panel.
  * This function should only be called after the panel has been realized. */
 void panel_update_background(Panel * p)
 {
-    GList *plugins, *l;
+    _panel_update_background(p->topgwin);
+}
+
+static void _panel_update_background(LXPanel * p)
+{
+    GtkWidget *w = GTK_WIDGET(p);
+    GList *plugins = NULL, *l;
+
+    /* reset background image */
+    if (p->priv->surface != NULL)
+    {
+        cairo_surface_destroy(p->priv->surface);
+        p->priv->surface = NULL;
+    }
 
     /* Redraw the top level widget. */
-    panel_determine_background_pixmap(p, p->topgwin, p->topgwin->window);
-    gdk_window_clear(p->topgwin->window);
-    gtk_widget_queue_draw(p->topgwin);
+    _panel_determine_background_pixmap(p, w);
+    gdk_window_clear(gtk_widget_get_window(w));
+    gtk_widget_queue_draw(w);
 
     /* Loop over all plugins redrawing each plugin. */
-    plugins = gtk_container_get_children(GTK_CONTAINER(p->box));
+    if (p->priv->box != NULL)
+        plugins = gtk_container_get_children(GTK_CONTAINER(p->priv->box));
     for (l = plugins; l != NULL; l = l->next)
         plugin_widget_set_background(l->data, p);
     g_list_free(plugins);
 }
 
-static gboolean delay_update_background( Panel* p )
-{
-    /* Panel could be destroyed while background update scheduled */
-    if ( p->topgwin && GTK_WIDGET_REALIZED ( p->topgwin ) ) {
-       gdk_display_sync( gtk_widget_get_display(p->topgwin) );
-       panel_update_background( p );
-    }
-    
-    return FALSE;
-}
+/****************************************************
+ *         autohide : borrowed from fbpanel         *
+ ****************************************************/
 
-static void
-panel_realize(GtkWidget *widget, Panel *p)
-{
-    g_idle_add_full( G_PRIORITY_LOW, 
-            (GSourceFunc)delay_update_background, p, NULL );
-}
+/* Autohide is behaviour when panel hides itself when mouse is "far enough"
+ * and pops up again when mouse comes "close enough".
+ * Formally, it's a state machine with 3 states that driven by mouse
+ * coordinates and timer:
+ * 1. VISIBLE - ensures that panel is visible. When/if mouse goes "far enough"
+ *      switches to WAITING state
+ * 2. WAITING - starts timer. If mouse comes "close enough", stops timer and
+ *      switches to VISIBLE.  If timer expires, switches to HIDDEN
+ * 3. HIDDEN - hides panel. When mouse comes "close enough" switches to VISIBLE
+ *
+ * Note 1
+ * Mouse coordinates are queried every PERIOD milisec
+ *
+ * Note 2
+ * If mouse is less then GAP pixels to panel it's considered to be close,
+ * otherwise it's far
+ */
 
-static void
-panel_style_set(GtkWidget *widget, GtkStyle* prev, Panel *p)
-{
-    /* FIXME: This dirty hack is used to fix the background of systray... */
-    if( GTK_WIDGET_REALIZED( widget ) )
-        g_idle_add_full( G_PRIORITY_LOW, 
-                (GSourceFunc)delay_update_background, p, NULL );
-}
+#define GAP 2
+#define PERIOD 300
 
-static gint
-panel_size_req(GtkWidget *widget, GtkRequisition *req, Panel *p)
+typedef enum
 {
-    ENTER;
+    AH_STATE_VISIBLE,
+    AH_STATE_WAITING,
+    AH_STATE_HIDDEN
+} PanelAHState;
 
-    if (p->autohide && !p->visible)
-        /* When the panel is in invisible state, the content box also got hidden, thus always
-         * report 0 size.  Ask the content box instead for its size. */
-        gtk_widget_size_request(p->box, req);
+static void ah_state_set(LXPanel *p, PanelAHState ah_state);
 
-    if (p->widthtype == WIDTH_REQUEST)
-        p->width = (p->orientation == GTK_ORIENTATION_HORIZONTAL) ? req->width : req->height;
-    if (p->heighttype == HEIGHT_REQUEST)
-        p->height = (p->orientation == GTK_ORIENTATION_HORIZONTAL) ? req->height : req->width;
+static gboolean
+mouse_watch(LXPanel *panel)
+{
+    Panel *p = panel->priv;
+    gint x, y;
 
-    calculate_position(p);
+    if (g_source_is_destroyed(g_main_current_source()))
+        return FALSE;
 
-    gtk_widget_set_size_request( widget, p->aw, p->ah );
+    ENTER;
+    gdk_display_get_pointer(gdk_display_get_default(), NULL, &x, &y, NULL);
 
-    RET( TRUE );
-}
+/*  Reduce sensitivity area
+    p->ah_far = ((x < p->cx - GAP) || (x > p->cx + p->cw + GAP)
+        || (y < p->cy - GAP) || (y > p->cy + p->ch + GAP));
+*/
 
-static gint
-panel_size_alloc(GtkWidget *widget, GtkAllocation *a, Panel *p)
-{
-    ENTER;
-    if (p->widthtype == WIDTH_REQUEST)
-        p->width = (p->orientation == GTK_ORIENTATION_HORIZONTAL) ? a->width : a->height;
-    if (p->heighttype == HEIGHT_REQUEST)
-        p->height = (p->orientation == GTK_ORIENTATION_HORIZONTAL) ? a->height : a->width;
-    calculate_position(p);
+    gint cx, cy, cw, ch, gap;
 
-    if (a->width == p->aw && a->height == p->ah && a->x == p->ax && a->y == p ->ay) {
-        RET(TRUE);
+    cx = p->ax;
+    cy = p->ay;
+    cw = p->cw;
+    ch = p->ch;
+
+    if (cw == 1) cw = 0;
+    if (ch == 1) ch = 0;
+    /* reduce area which will raise panel so it does not interfere with apps */
+    if (p->ah_state == AH_STATE_HIDDEN) {
+        gap = MAX(p->height_when_hidden, GAP);
+        switch (p->edge) {
+        case EDGE_LEFT:
+            cw = gap;
+            break;
+        case EDGE_RIGHT:
+            cx = cx + cw - gap;
+            cw = gap;
+            break;
+        case EDGE_TOP:
+            ch = gap;
+            break;
+        case EDGE_BOTTOM:
+            cy = cy + ch - gap;
+            ch = gap;
+            break;
+       }
     }
+    p->ah_far = ((x < cx) || (x > cx + cw) || (y < cy) || (y > cy + ch));
 
-    gtk_window_move(GTK_WINDOW(p->topgwin), p->ax, p->ay);
-    panel_set_wm_strut(p);
+    ah_state_set(panel, p->ah_state);
     RET(TRUE);
 }
 
-static  gboolean
-panel_configure_event (GtkWidget *widget, GdkEventConfigure *e, Panel *p)
+static gboolean ah_state_hide_timeout(gpointer p)
 {
-    ENTER;
-    if (e->width == p->cw && e->height == p->ch && e->x == p->cx && e->y == p->cy)
-        RET(TRUE);
-    p->cw = e->width;
-    p->ch = e->height;
-    p->cx = e->x;
-    p->cy = e->y;
+    if (!g_source_is_destroyed(g_main_current_source()))
+    {
+        ah_state_set(p, AH_STATE_HIDDEN);
+        ((LXPanel *)p)->priv->hide_timeout = 0;
+    }
+    return FALSE;
+}
 
-    if (p->transparent)
-        fb_bg_notify_changed_bg(p->bg);
+static void ah_state_set(LXPanel *panel, PanelAHState ah_state)
+{
+    Panel *p = panel->priv;
+    GdkRectangle rect;
 
-    RET(FALSE);
+    ENTER;
+    if (p->ah_state != ah_state) {
+        p->ah_state = ah_state;
+        switch (ah_state) {
+        case AH_STATE_VISIBLE:
+            p->visible = TRUE;
+            _calculate_position(panel, &rect);
+            gtk_window_move(GTK_WINDOW(panel), rect.x, rect.y);
+            gtk_widget_show(GTK_WIDGET(panel));
+            gtk_widget_show(p->box);
+            gtk_widget_queue_resize(GTK_WIDGET(panel));
+            gtk_window_stick(GTK_WINDOW(panel));
+            break;
+        case AH_STATE_WAITING:
+            if (p->hide_timeout)
+                g_source_remove(p->hide_timeout);
+            p->hide_timeout = g_timeout_add(2 * PERIOD, ah_state_hide_timeout, panel);
+            break;
+        case AH_STATE_HIDDEN:
+            if (p->height_when_hidden > 0)
+                gtk_widget_hide(p->box);
+            else
+                gtk_widget_hide(GTK_WIDGET(panel));
+            p->visible = FALSE;
+        }
+    } else if (p->autohide && p->ah_far) {
+        switch (ah_state) {
+        case AH_STATE_VISIBLE:
+            ah_state_set(panel, AH_STATE_WAITING);
+            break;
+        case AH_STATE_WAITING:
+            break;
+        case AH_STATE_HIDDEN:
+            /* configurator might change height_when_hidden value */
+            if (p->height_when_hidden > 0)
+            {
+                if (gtk_widget_get_visible(p->box))
+                {
+                    gtk_widget_hide(p->box);
+                    gtk_widget_show(GTK_WIDGET(panel));
+                }
+            }
+            else
+                if (gtk_widget_get_visible(GTK_WIDGET(panel)))
+                {
+                    gtk_widget_hide(GTK_WIDGET(panel));
+                    gtk_widget_show(p->box);
+                }
+        }
+    } else {
+        switch (ah_state) {
+        case AH_STATE_VISIBLE:
+            break;
+        case AH_STATE_WAITING:
+            if (p->hide_timeout)
+                g_source_remove(p->hide_timeout);
+            p->hide_timeout = 0;
+            /* continue with setting visible */
+        case AH_STATE_HIDDEN:
+            ah_state_set(panel, AH_STATE_VISIBLE);
+        }
+    }
+    RET();
 }
 
-static gint
-panel_popupmenu_configure(GtkWidget *widget, gpointer user_data)
+/* starts autohide behaviour */
+static void ah_start(LXPanel *p)
 {
-    panel_configure( (Panel*)user_data, 0 );
-    return TRUE;
+    ENTER;
+    if (!p->priv->mouse_timeout)
+        p->priv->mouse_timeout = g_timeout_add(PERIOD, (GSourceFunc) mouse_watch, p);
+    RET();
 }
 
-/* Handler for "button_press_event" signal with Panel as parameter. */
-static gboolean panel_button_press_event_with_panel(GtkWidget *widget, GdkEventButton *event, Panel *panel)
+/* stops autohide */
+static void ah_stop(LXPanel *p)
 {
-    if (event->button == 3)     /* right button */
-    {
-        GtkMenu* popup = (GtkMenu*) lxpanel_get_plugin_menu(panel, NULL, FALSE);
-        gtk_menu_popup(popup, NULL, NULL, NULL, NULL, event->button, event->time);
-        return TRUE;
-    }    
-    return FALSE;
+    ENTER;
+    if (p->priv->mouse_timeout) {
+        g_source_remove(p->priv->mouse_timeout);
+        p->priv->mouse_timeout = 0;
+    }
+    if (p->priv->hide_timeout) {
+        g_source_remove(p->priv->hide_timeout);
+        p->priv->hide_timeout = 0;
+    }
+    RET();
+}
+/* end of the autohide code
+ * ------------------------------------------------------------- */
+
+static gint
+panel_popupmenu_configure(GtkWidget *widget, gpointer user_data)
+{
+    panel_configure( (LXPanel*)user_data, 0 );
+    return TRUE;
 }
 
 static void panel_popupmenu_config_plugin( GtkMenuItem* item, GtkWidget* plugin )
 {
-    Panel *panel = PLUGIN_PANEL(plugin);
+    Panel *panel = PLUGIN_PANEL(plugin)->priv;
 
-    lxpanel_plugin_show_config_dialog(panel, plugin);
+    lxpanel_plugin_show_config_dialog(plugin);
 
     /* FIXME: this should be more elegant */
     panel->config_changed = TRUE;
 }
 
-static void panel_popupmenu_add_item( GtkMenuItem* item, Panel* panel )
+static void panel_popupmenu_add_item( GtkMenuItem* item, LXPanel* panel )
 {
     /* panel_add_plugin( panel, panel->topgwin ); */
     panel_configure( panel, 2 );
@@ -578,7 +988,7 @@ static void panel_popupmenu_add_item( GtkMenuItem* item, Panel* panel )
 
 static void panel_popupmenu_remove_item( GtkMenuItem* item, GtkWidget* plugin )
 {
-    Panel* panel = PLUGIN_PANEL(plugin);
+    Panel* panel = PLUGIN_PANEL(plugin)->priv;
 
     /* If the configuration dialog is open, there will certainly be a crash if the
      * user manipulates the Configured Plugins list, after we remove this entry.
@@ -592,7 +1002,7 @@ static void panel_popupmenu_remove_item( GtkMenuItem* item, GtkWidget* plugin )
     /* reset conf pointer because the widget still may be referenced by configurator */
     g_object_set_qdata(G_OBJECT(plugin), lxpanel_plugin_qconf, NULL);
 
-    panel_config_save(panel);
+    lxpanel_config_save(PLUGIN_PANEL(plugin));
     gtk_widget_destroy(plugin);
 }
 
@@ -602,7 +1012,7 @@ static char* gen_panel_name( int edge, gint monitor )
 {
     const char* edge_str = num2str( edge_pair, edge, "" );
     char* name = NULL;
-    char* dir = get_config_file( cprofile, "panels", FALSE );
+    char* dir = _user_config_file_name("panels", NULL);
     int i;
     for( i = 0; i < G_MAXINT; ++i )
     {
@@ -629,56 +1039,75 @@ static char* gen_panel_name( int edge, gint monitor )
 
 /* FIXME: Potentially we can support multiple panels at the same edge,
  * but currently this cannot be done due to some positioning problems. */
-static void panel_popupmenu_create_panel( GtkMenuItem* item, Panel* panel )
+static void panel_popupmenu_create_panel( GtkMenuItem* item, LXPanel* panel )
 {
     gint m, e, monitors;
     GdkScreen *screen;
-    GtkWidget *err;
-    Panel* new_panel = panel_allocate();
+    LXPanel *new_panel = panel_allocate();
+    Panel *p = new_panel->priv;
+    config_setting_t *global;
 
     /* Allocate the edge. */
-    screen = gdk_screen_get_default();
+    screen = gtk_widget_get_screen(GTK_WIDGET(panel));
     g_assert(screen);
     monitors = gdk_screen_get_n_monitors(screen);
+    /* try to allocate edge on current monitor first */
+    m = panel->priv->monitor;
+    if (m < 0)
+    {
+        /* panel is spanned over the screen, guess from pointer now */
+        gint x, y;
+        gdk_display_get_pointer(gdk_display_get_default(), NULL, &x, &y, NULL);
+        m = gdk_screen_get_monitor_at_point(screen, x, y);
+    }
+    for (e = 1; e < 5; ++e)
+    {
+        if (panel_edge_available(p, e, m))
+        {
+            p->edge = e;
+            p->monitor = m;
+            goto found_edge;
+        }
+    }
+    /* try all monitors */
     for(m=0; m<monitors; ++m)
     {
         /* try each of the four edges */
         for(e=1; e<5; ++e)
         {
-            if(panel_edge_available(new_panel,e,m)) {
-                new_panel->edge = e;
-                new_panel->monitor = m;
+            if(panel_edge_available(p,e,m)) {
+                p->edge = e;
+                p->monitor = m;
                 goto found_edge;
             }
         }
     }
 
-    panel_destroy(new_panel);
-    ERR("Error adding panel: There is no room for another panel. All the edges are taken.\n");
-    err = gtk_message_dialog_new(NULL,0,GTK_MESSAGE_ERROR,GTK_BUTTONS_OK,_("There is no room for another panel. All the edges are taken."));
-    gtk_dialog_run(GTK_DIALOG(err));
-    gtk_widget_destroy(err);
+    gtk_widget_destroy(GTK_WIDGET(new_panel));
+    g_warning("Error adding panel: There is no room for another panel. All the edges are taken.");
+    fm_show_error(NULL, NULL, _("There is no room for another panel. All the edges are taken."));
     return;
 
 found_edge:
-    new_panel->name = gen_panel_name(new_panel->edge,new_panel->monitor);
+    p->name = gen_panel_name(p->edge, p->monitor);
 
     /* create new config with first group "Global" */
-    config_group_add_subgroup(config_root_setting(new_panel->config), "Global");
+    global = config_group_add_subgroup(config_root_setting(p->config), "Global");
+    config_group_set_string(global, "edge", num2str(edge_pair, p->edge, "none"));
+    config_group_set_int(global, "monitor", p->monitor);
     panel_configure(new_panel, 0);
-    panel_normalize_configuration(new_panel);
-    panel_start_gui(new_panel);
-    gtk_widget_show_all(new_panel->topgwin);
+    panel_normalize_configuration(p);
+    panel_start_gui(new_panel, NULL);
 
-    panel_config_save(new_panel);
+    lxpanel_config_save(new_panel);
     all_panels = g_slist_prepend(all_panels, new_panel);
 }
 
-static void panel_popupmenu_delete_panel( GtkMenuItem* item, Panel* panel )
+static void panel_popupmenu_delete_panel( GtkMenuItem* item, LXPanel* panel )
 {
     GtkWidget* dlg;
     gboolean ok;
-    dlg = gtk_message_dialog_new_with_markup( GTK_WINDOW(panel->topgwin),
+    dlg = gtk_message_dialog_new_with_markup( GTK_WINDOW(panel),
                                                     GTK_DIALOG_MODAL,
                                                     GTK_MESSAGE_QUESTION,
                                                     GTK_BUTTONS_OK_CANCEL,
@@ -689,16 +1118,15 @@ static void panel_popupmenu_delete_panel( GtkMenuItem* item, Panel* panel )
     gtk_widget_destroy( dlg );
     if( ok )
     {
-        gchar *fname, *dir;
+        gchar *fname;
         all_panels = g_slist_remove( all_panels, panel );
 
         /* delete the config file of this panel */
-        dir = get_config_file( cprofile, "panels", FALSE );
-        fname = g_build_filename( dir, panel->name, NULL );
-        g_free( dir );
+        fname = _user_config_file_name("panels", panel->priv->name);
         g_unlink( fname );
-        panel->config_changed = 0;
-        panel_destroy( panel );
+        g_free(fname);
+        panel->priv->config_changed = 0;
+        gtk_widget_destroy(GTK_WIDGET(panel));
     }
 }
 
@@ -714,6 +1142,9 @@ static void panel_popupmenu_about( GtkMenuItem* item, Panel* panel )
         "Juergen Hoetzel <juergen@archlinux.org>",
         "Marty Jack <martyj19@comcast.net>",
         "Martin Bagge <brother@bsnet.se>",
+        "Andriy Grytsenko <andrej@rep.kiev.ua>",
+        "Giuseppe Penone <giuspen@gmail.com>",
+        "Piotr Sipika <piotr.sipika@gmail.com>",
         NULL
     };
     /* TRANSLATORS: Replace this string with your names, one name per line. */
@@ -722,7 +1153,7 @@ static void panel_popupmenu_about( GtkMenuItem* item, Panel* panel )
     about = gtk_about_dialog_new();
     panel_apply_icon(GTK_WINDOW(about));
     gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(about), VERSION);
-    gtk_about_dialog_set_name(GTK_ABOUT_DIALOG(about), _("LXPanel"));
+    gtk_about_dialog_set_program_name(GTK_ABOUT_DIALOG(about), _("LXPanel"));
 
     if(gtk_icon_theme_has_icon(panel->icon_theme, "video-display"))
     {
@@ -734,49 +1165,74 @@ static void panel_popupmenu_about( GtkMenuItem* item, Panel* panel )
          gtk_about_dialog_set_logo( GTK_ABOUT_DIALOG(about),
                                     gtk_icon_theme_load_icon(panel->icon_theme, "start-here", 48, 0, NULL));
     }
-    else 
+    else
     {
         gtk_about_dialog_set_logo(  GTK_ABOUT_DIALOG(about),
-                                    gdk_pixbuf_new_from_file(PACKAGE_DATA_DIR "/lxpanel/images/my-computer.png", NULL));
+                                    gdk_pixbuf_new_from_file(PACKAGE_DATA_DIR "/images/my-computer.png", NULL));
     }
 
-    gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(about), _("Copyright (C) 2008-2013"));
+    gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(about), _("Copyright (C) 2008-2014"));
     gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(about), _( "Desktop panel for LXDE project"));
     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.");
     gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(about), "http://lxde.org/");
     gtk_about_dialog_set_authors(GTK_ABOUT_DIALOG(about), authors);
     gtk_about_dialog_set_translator_credits(GTK_ABOUT_DIALOG(about), translators);
     gtk_dialog_run(GTK_DIALOG(about));
-    gtk_widget_destroy(about); 
+    gtk_widget_destroy(about);
 }
 
 void panel_apply_icon( GtkWindow *w )
 {
-       GdkPixbuf* window_icon;
-       
-       if(gtk_icon_theme_has_icon(gtk_icon_theme_get_default(), "video-display"))
+    GdkPixbuf* window_icon;
+
+    if(gtk_icon_theme_has_icon(gtk_icon_theme_get_default(), "video-display"))
     {
-               window_icon = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), "video-display", 24, 0, NULL);
-       }
-       else if(gtk_icon_theme_has_icon(gtk_icon_theme_get_default(), "start-here"))
+        window_icon = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), "video-display", 24, 0, NULL);
+    }
+    else if(gtk_icon_theme_has_icon(gtk_icon_theme_get_default(), "start-here"))
     {
-               window_icon = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), "start-here", 24, 0, NULL);
-       }
+        window_icon = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), "start-here", 24, 0, NULL);
+    }
     else
     {
-               window_icon = gdk_pixbuf_new_from_file(PACKAGE_DATA_DIR "/lxpanel/images/my-computer.png", NULL);
-       }
+        window_icon = gdk_pixbuf_new_from_file(PACKAGE_DATA_DIR "/images/my-computer.png", NULL);
+    }
     gtk_window_set_icon(w, window_icon);
 }
 
-GtkMenu* lxpanel_get_plugin_menu( Panel* panel, GtkWidget* plugin, gboolean use_sub_menu )
+GtkMenu* lxpanel_get_plugin_menu( LXPanel* panel, GtkWidget* plugin, gboolean use_sub_menu )
 {
     GtkWidget  *menu_item, *img;
     GtkMenu *ret,*menu;
-    LXPanelPluginInit *init;
+    const LXPanelPluginInit *init;
     char* tmp;
+
     ret = menu = GTK_MENU(gtk_menu_new());
 
+    if (plugin)
+    {
+        init = PLUGIN_CLASS(plugin);
+        /* create single item - plugin instance settings */
+        img = gtk_image_new_from_stock( GTK_STOCK_PREFERENCES, GTK_ICON_SIZE_MENU );
+        tmp = g_strdup_printf( _("\"%s\" Settings"), _(init->name) );
+        menu_item = gtk_image_menu_item_new_with_label( tmp );
+        g_free( tmp );
+        gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
+        gtk_menu_shell_prepend(GTK_MENU_SHELL(ret), menu_item);
+        if( init->config )
+            g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_config_plugin), plugin );
+        else
+            gtk_widget_set_sensitive( menu_item, FALSE );
+        /* add custom items by plugin if requested */
+        if (init->update_context_menu != NULL)
+            use_sub_menu = init->update_context_menu(plugin, ret);
+        /* append a separator */
+        menu_item = gtk_separator_menu_item_new();
+        gtk_menu_shell_append(GTK_MENU_SHELL(ret), menu_item);
+    }
+    if (use_sub_menu)
+        menu = GTK_MENU(gtk_menu_new());
+
     img = gtk_image_new_from_stock( GTK_STOCK_EDIT, GTK_ICON_SIZE_MENU );
     menu_item = gtk_image_menu_item_new_with_label(_("Add / Remove Panel Items"));
     gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
@@ -785,7 +1241,6 @@ GtkMenu* lxpanel_get_plugin_menu( Panel* panel, GtkWidget* plugin, gboolean use_
 
     if( plugin )
     {
-        init = PLUGIN_CLASS(plugin);
         img = gtk_image_new_from_stock( GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU );
         tmp = g_strdup_printf( _("Remove \"%s\" From Panel"), _(init->name) );
         menu_item = gtk_image_menu_item_new_with_label( tmp );
@@ -825,36 +1280,16 @@ GtkMenu* lxpanel_get_plugin_menu( Panel* panel, GtkWidget* plugin, gboolean use_
     menu_item = gtk_image_menu_item_new_with_label(_("About"));
     gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
     gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item);
-    g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_about), panel );
+    g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_about), panel->priv );
 
     if( use_sub_menu )
     {
-        ret = GTK_MENU(gtk_menu_new());
         menu_item = gtk_image_menu_item_new_with_label(_("Panel"));
         gtk_menu_shell_append(GTK_MENU_SHELL(ret), menu_item);
         gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), GTK_WIDGET(menu) );
-
-        gtk_widget_show_all(GTK_WIDGET(ret));
-    }
-
-    if( plugin )
-    {
-        menu_item = gtk_separator_menu_item_new();
-        gtk_menu_shell_prepend(GTK_MENU_SHELL(ret), menu_item);
-
-        img = gtk_image_new_from_stock( GTK_STOCK_PREFERENCES, GTK_ICON_SIZE_MENU );
-        tmp = g_strdup_printf( _("\"%s\" Settings"), _(init->name) );
-        menu_item = gtk_image_menu_item_new_with_label( tmp );
-        g_free( tmp );
-        gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
-        gtk_menu_shell_prepend(GTK_MENU_SHELL(ret), menu_item);
-        if( init->config )
-            g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_config_plugin), plugin );
-        else
-            gtk_widget_set_sensitive( menu_item, FALSE );
     }
 
-    gtk_widget_show_all(GTK_WIDGET(menu));
+    gtk_widget_show_all(GTK_WIDGET(ret));
 
     g_signal_connect( ret, "selection-done", G_CALLBACK(gtk_widget_destroy), NULL );
     return ret;
@@ -863,7 +1298,7 @@ GtkMenu* lxpanel_get_plugin_menu( Panel* panel, GtkWidget* plugin, gboolean use_
 /* for old plugins compatibility */
 GtkMenu* lxpanel_get_panel_menu( Panel* panel, Plugin* plugin, gboolean use_sub_menu )
 {
-    return lxpanel_get_plugin_menu(panel, plugin->pwid, use_sub_menu);
+    return lxpanel_get_plugin_menu(panel->topgwin, plugin->pwid, use_sub_menu);
 }
 
 /****************************************************
@@ -879,97 +1314,32 @@ make_round_corners(Panel *p)
 
 void panel_set_dock_type(Panel *p)
 {
+    Display *xdisplay = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
+
     if (p->setdocktype) {
         Atom state = a_NET_WM_WINDOW_TYPE_DOCK;
-        XChangeProperty(GDK_DISPLAY(), p->topxwin,
+        XChangeProperty(xdisplay, p->topxwin,
                         a_NET_WM_WINDOW_TYPE, XA_ATOM, 32,
                         PropModeReplace, (unsigned char *) &state, 1);
     }
     else {
-        XDeleteProperty( GDK_DISPLAY(), p->topxwin, a_NET_WM_WINDOW_TYPE );
+        XDeleteProperty( xdisplay, p->topxwin, a_NET_WM_WINDOW_TYPE );
     }
 }
 
-static void panel_set_visibility(Panel *p, gboolean visible)
-{
-    if ( ! visible) gtk_widget_hide(p->box);
-    p->visible = visible;
-    calculate_position(p);
-    gtk_widget_set_size_request(p->topgwin, p->aw, p->ah);
-    gdk_window_move(p->topgwin->window, p->ax, p->ay);
-    if (visible) gtk_widget_show(p->box);
-    panel_set_wm_strut(p);
-}
-
-static gboolean panel_leave_real(Panel *p)
+void panel_establish_autohide(Panel *p)
 {
-    /* If the pointer is grabbed by this application, leave the panel displayed.
-     * There is no way to determine if it is grabbed by another application, such as an application that has a systray icon. */
-    if (gdk_display_pointer_is_grabbed(p->display))
-        return TRUE;
-
-    /* If the pointer is inside the panel, leave the panel displayed. */
-    gint x, y;
-    gdk_display_get_pointer(p->display, NULL, &x, &y, NULL);
-    if ((p->cx <= x) && (x <= (p->cx + p->cw)) && (p->cy <= y) && (y <= (p->cy + p->ch)))
-        return TRUE;
-
-    /* If the panel is configured to autohide and if it is visible, hide the panel. */
-    if ((p->autohide) && (p->visible))
-        panel_set_visibility(p, FALSE);
-
-    /* Clear the timer. */
-    p->hide_timeout = 0;
-    return FALSE;
+    _panel_establish_autohide(p->topgwin);
 }
 
-static gboolean panel_enter(GtkImage *widget, GdkEventCrossing *event, Panel *p)
+void _panel_establish_autohide(LXPanel *p)
 {
-    /* We may receive multiple enter-notify events when the pointer crosses into the panel.
-     * Do extra tests to make sure this does not cause misoperation such as blinking.
-     * If the pointer is inside the panel, unhide it. */
-    gint x, y;
-    gdk_display_get_pointer(p->display, NULL, &x, &y, NULL);
-    if ((p->cx <= x) && (x <= (p->cx + p->cw)) && (p->cy <= y) && (y <= (p->cy + p->ch)))
-    {
-        /* If the pointer is inside the panel and we have not already unhidden it, do so and
-         * set a timer to recheck it in a half second. */
-        if (p->hide_timeout == 0)
-        {
-            p->hide_timeout = g_timeout_add(500, (GSourceFunc) panel_leave_real, p);
-            panel_set_visibility(p, TRUE);
-        }
-    }
+    if (p->priv->autohide)
+        ah_start(p);
     else
     {
-        /* If the pointer is not inside the panel, simulate a timer expiration. */
-        panel_leave_real(p);
-    }
-    return TRUE;
-}
-
-static gboolean panel_drag_motion(GtkWidget *widget, GdkDragContext *drag_context, gint x,
-      gint y, guint time, Panel *p)
-{
-    panel_enter(NULL, NULL, p);
-    return TRUE;
-}
-
-void panel_establish_autohide(Panel *p)
-{
-    if (p->autohide)
-    {
-        gtk_widget_add_events(p->topgwin, GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK);
-        g_signal_connect(G_OBJECT(p->topgwin), "enter-notify-event", G_CALLBACK(panel_enter), p);
-        g_signal_connect(G_OBJECT(p->topgwin), "drag-motion", (GCallback) panel_drag_motion, p);
-        gtk_drag_dest_set(p->topgwin, GTK_DEST_DEFAULT_MOTION, NULL, 0, 0);
-        gtk_drag_dest_set_track_motion(p->topgwin, TRUE);
-        panel_enter(NULL, NULL, p);
-    }
-    else if ( ! p->visible)
-    {
-       gtk_widget_show(p->box);
-        p->visible = TRUE;
+        ah_stop(p);
+        ah_state_set(p, AH_STATE_VISIBLE);
     }
 }
 
@@ -984,6 +1354,11 @@ void panel_image_set_from_file(Panel * p, GtkWidget * image, const char * file)
     }
 }
 
+void lxpanel_image_set_from_file(LXPanel * p, GtkWidget * image, const char * file)
+{
+    panel_image_set_from_file(p->priv, image, file);
+}
+
 /* Set an image from a icon theme with scaling to the panel icon size. */
 gboolean panel_image_set_icon_theme(Panel * p, GtkWidget * image, const gchar * icon)
 {
@@ -997,102 +1372,121 @@ gboolean panel_image_set_icon_theme(Panel * p, GtkWidget * image, const gchar *
     return FALSE;
 }
 
+gboolean lxpanel_image_set_icon_theme(LXPanel * p, GtkWidget * image, const gchar * icon)
+{
+    return panel_image_set_icon_theme(p->priv, image, icon);
+}
+
+static int
+panel_parse_plugin(LXPanel *p, config_setting_t *cfg)
+{
+    const char *type = NULL;
+
+    ENTER;
+    config_setting_lookup_string(cfg, "type", &type);
+    DBG("plug %s\n", type);
+
+    if (!type || lxpanel_add_plugin(p, type, cfg, -1) == NULL) {
+        g_warning( "lxpanel: can't load %s plugin", type);
+        goto error;
+    }
+    RET(1);
+
+error:
+    RET(0);
+}
+
 static void
-panel_start_gui(Panel *p)
+panel_start_gui(LXPanel *panel, config_setting_t *list)
 {
     Atom state[3];
     XWMHints wmhints;
-    guint32 val;
+    gulong val;
+    Display *xdisplay = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
+    Panel *p = panel->priv;
+    GtkWidget *w = GTK_WIDGET(panel);
+    config_setting_t *s;
+    GdkRectangle rect;
+    int i;
 
     ENTER;
 
+    g_debug("panel_start_gui on '%s'", p->name);
     p->curdesk = get_net_current_desktop();
     p->desknum = get_net_number_of_desktops();
-    p->workarea = get_xaproperty (GDK_ROOT_WINDOW(), a_NET_WORKAREA, XA_CARDINAL, &p->wa_len);
+    //p->workarea = get_xaproperty (GDK_ROOT_WINDOW(), a_NET_WORKAREA, XA_CARDINAL, &p->wa_len);
+    p->ax = p->ay = p->aw = p->ah = 0;
 
-    /* main toplevel window */
-    /* p->topgwin =  gtk_window_new(GTK_WINDOW_TOPLEVEL); */
-    p->topgwin = (GtkWidget*)g_object_new(PANEL_TOPLEVEL_TYPE, NULL);
-    gtk_widget_set_name(p->topgwin, "PanelToplevel");
     p->display = gdk_display_get_default();
-    gtk_container_set_border_width(GTK_CONTAINER(p->topgwin), 0);
-    gtk_window_set_resizable(GTK_WINDOW(p->topgwin), FALSE);
-    gtk_window_set_wmclass(GTK_WINDOW(p->topgwin), "panel", "lxpanel");
-    gtk_window_set_title(GTK_WINDOW(p->topgwin), "panel");
-    gtk_window_set_position(GTK_WINDOW(p->topgwin), GTK_WIN_POS_NONE);
-    gtk_window_set_decorated(GTK_WINDOW(p->topgwin), FALSE);
-
-    gtk_window_group_add_window( win_grp, (GtkWindow*)p->topgwin );
-
-    g_signal_connect(G_OBJECT(p->topgwin), "delete-event",
-          G_CALLBACK(panel_delete_event), p);
-    g_signal_connect(G_OBJECT(p->topgwin), "destroy-event",
-          G_CALLBACK(panel_destroy_event), p);
-    g_signal_connect (G_OBJECT (p->topgwin), "size-request",
-          (GCallback) panel_size_req, p);
-    g_signal_connect (G_OBJECT (p->topgwin), "size-allocate",
-          (GCallback) panel_size_alloc, p);
-    g_signal_connect (G_OBJECT (p->topgwin), "configure-event",
-          (GCallback) panel_configure_event, p);
-
-    gtk_widget_add_events( p->topgwin, GDK_BUTTON_PRESS_MASK );
-    g_signal_connect(G_OBJECT (p->topgwin), "button-press-event",
-          (GCallback) panel_button_press_event_with_panel, p);
-
-    g_signal_connect (G_OBJECT (p->topgwin), "realize",
-          (GCallback) panel_realize, p);
-
-    g_signal_connect (G_OBJECT (p->topgwin), "style-set",
-          (GCallback)panel_style_set, p);
-    gtk_widget_realize(p->topgwin);
-    //gdk_window_set_decorations(p->topgwin->window, 0);
+    gtk_window_set_wmclass(GTK_WINDOW(panel), "panel", "lxpanel");
+
+    if (G_UNLIKELY(win_grp == NULL))
+    {
+        win_grp = gtk_window_group_new();
+        g_object_add_weak_pointer(G_OBJECT(win_grp), (gpointer *)&win_grp);
+        gtk_window_group_add_window(win_grp, (GtkWindow*)panel);
+        g_object_unref(win_grp);
+    }
+    else
+        gtk_window_group_add_window(win_grp, (GtkWindow*)panel);
+
+    gtk_widget_add_events( w, GDK_BUTTON_PRESS_MASK );
+
+    gtk_widget_realize(w);
+    //gdk_window_set_decorations(gtk_widget_get_window(p->topgwin), 0);
 
     // main layout manager as a single child of panel
-    p->box = p->my_box_new(FALSE, 0);
+    p->box = panel_box_new(panel, FALSE, 0);
     gtk_container_set_border_width(GTK_CONTAINER(p->box), 0);
-//    gtk_container_add(GTK_CONTAINER(p->bbox), p->box);
-    gtk_container_add(GTK_CONTAINER(p->topgwin), p->box);
+    gtk_container_add(GTK_CONTAINER(panel), p->box);
     gtk_widget_show(p->box);
     if (p->round_corners)
         make_round_corners(p);
 
-    p->topxwin = GDK_WINDOW_XWINDOW(GTK_WIDGET(p->topgwin)->window);
+    p->topxwin = GDK_WINDOW_XWINDOW(gtk_widget_get_window(w));
     DBG("topxwin = %x\n", p->topxwin);
 
     /* the settings that should be done before window is mapped */
     wmhints.flags = InputHint;
     wmhints.input = 0;
-    XSetWMHints (GDK_DISPLAY(), p->topxwin, &wmhints);
+    XSetWMHints (xdisplay, p->topxwin, &wmhints);
 #define WIN_HINTS_SKIP_FOCUS      (1<<0)    /* "alt-tab" skips this win */
     val = WIN_HINTS_SKIP_FOCUS;
-    XChangeProperty(GDK_DISPLAY(), p->topxwin,
-          XInternAtom(GDK_DISPLAY(), "_WIN_HINTS", False), XA_CARDINAL, 32,
+    XChangeProperty(xdisplay, p->topxwin,
+          XInternAtom(xdisplay, "_WIN_HINTS", False), XA_CARDINAL, 32,
           PropModeReplace, (unsigned char *) &val, 1);
 
     panel_set_dock_type(p);
 
     /* window mapping point */
-    gtk_widget_show_all(p->topgwin);
+    p->visible = TRUE;
+    _calculate_position(panel, &rect);
+    gtk_window_move(GTK_WINDOW(panel), rect.x, rect.y);
+    gtk_window_present(GTK_WINDOW(panel));
 
     /* the settings that should be done after window is mapped */
-    panel_establish_autohide(p);
 
     /* send it to running wm */
-    Xclimsg(p->topxwin, a_NET_WM_DESKTOP, 0xFFFFFFFF, 0, 0, 0, 0);
+    Xclimsg(p->topxwin, a_NET_WM_DESKTOP, G_MAXULONG, 0, 0, 0, 0);
     /* and assign it ourself just for case when wm is not running */
-    val = 0xFFFFFFFF;
-    XChangeProperty(GDK_DISPLAY(), p->topxwin, a_NET_WM_DESKTOP, XA_CARDINAL, 32,
+    val = G_MAXULONG;
+    XChangeProperty(xdisplay, p->topxwin, a_NET_WM_DESKTOP, XA_CARDINAL, 32,
           PropModeReplace, (unsigned char *) &val, 1);
 
     state[0] = a_NET_WM_STATE_SKIP_PAGER;
     state[1] = a_NET_WM_STATE_SKIP_TASKBAR;
     state[2] = a_NET_WM_STATE_STICKY;
-    XChangeProperty(GDK_DISPLAY(), p->topxwin, a_NET_WM_STATE, XA_ATOM,
+    XChangeProperty(xdisplay, p->topxwin, a_NET_WM_STATE, XA_ATOM,
           32, PropModeReplace, (unsigned char *) state, 3);
 
-    calculate_position(p);
-    gdk_window_move_resize(p->topgwin->window, p->ax, p->ay, p->aw, p->ah);
-    panel_set_wm_strut(p);
+    p->initialized = TRUE;
+
+    if (list) for (i = 1; (s = config_setting_get_elem(list, i)) != NULL; )
+        if (strcmp(config_setting_get_name(s), "Plugin") == 0 &&
+            panel_parse_plugin(panel, s)) /* success on plugin start */
+            i++;
+        else /* remove invalid data from config */
+            config_setting_remove_elem(list, i);
 
     RET();
 }
@@ -1138,12 +1532,8 @@ void panel_draw_label_text(Panel * p, GtkWidget * label, const char * text,
         font_desc = p->fontsize;
     else
     {
-        if (p->icon_size < 20)
-            font_desc = 9;
-        else if (p->icon_size >= 20 && p->icon_size < 36)
-            font_desc = 10;
-        else
-            font_desc = 12;
+        GtkStyle *style = gtk_widget_get_style(label);
+        font_desc = pango_font_description_get_size(style->font_desc) / PANGO_SCALE;
     }
     font_desc *= custom_size_factor;
 
@@ -1188,8 +1578,21 @@ void panel_draw_label_text(Panel * p, GtkWidget * label, const char * text,
     g_free(escaped_text);
 }
 
+void lxpanel_draw_label_text(LXPanel * p, GtkWidget * label, const char * text,
+                           gboolean bold, float custom_size_factor,
+                           gboolean custom_color)
+{
+    panel_draw_label_text(p->priv, label, text, bold, custom_size_factor, custom_color);
+}
+
 void panel_set_panel_configuration_changed(Panel *p)
 {
+    _panel_set_panel_configuration_changed(p->topgwin);
+}
+
+void _panel_set_panel_configuration_changed(LXPanel *panel)
+{
+    Panel *p = panel->priv;
     GList *plugins, *l;
 
     GtkOrientation previous_orientation = p->orientation;
@@ -1197,10 +1600,10 @@ void panel_set_panel_configuration_changed(Panel *p)
         ? GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL;
 
     /* either first run or orientation was changed */
-    if (p->my_box_new == NULL || previous_orientation != p->orientation)
+    if (!p->initialized || previous_orientation != p->orientation)
     {
         panel_adjust_geometry_terminology(p);
-        if (p->my_box_new != NULL)
+        if (p->initialized)
             p->height = ((p->orientation == GTK_ORIENTATION_HORIZONTAL) ? PANEL_HEIGHT_DEFAULT : PANEL_WIDTH_DEFAULT);
         if (p->height_control != NULL)
             gtk_spin_button_set_value(GTK_SPIN_BUTTON(p->height_control), p->height);
@@ -1212,6 +1615,7 @@ void panel_set_panel_configuration_changed(Panel *p)
         }
     }
 
+    /* FIXME: it's deprecated, kept for binary compatibility */
     if (p->orientation == GTK_ORIENTATION_HORIZONTAL) {
         p->my_box_new = gtk_hbox_new;
         p->my_separator_new = gtk_vseparator_new;
@@ -1234,11 +1638,13 @@ void panel_set_panel_configuration_changed(Panel *p)
     plugins = p->box ? gtk_container_get_children(GTK_CONTAINER(p->box)) : NULL;
     for( l = plugins; l; l = l->next ) {
         GtkWidget *w = (GtkWidget*)l->data;
-        LXPanelPluginInit *init = PLUGIN_CLASS(w);
+        const LXPanelPluginInit *init = PLUGIN_CLASS(w);
         if (init->reconfigure)
-            init->reconfigure(p, w);
+            init->reconfigure(panel, w);
     }
     g_list_free(plugins);
+    /* panel geometry changed? update panel background then */
+    _panel_queue_update_background(panel);
 }
 
 static int
@@ -1250,7 +1656,7 @@ panel_parse_global(Panel *p, config_setting_t *cfg)
     /* check Global config */
     if (!cfg || strcmp(config_setting_get_name(cfg), "Global") != 0)
     {
-        ERR( "lxpanel: Global section not found\n");
+        g_warning( "lxpanel: Global section not found");
         RET(0);
     }
     if (config_setting_lookup_string(cfg, "edge", &str))
@@ -1282,7 +1688,8 @@ panel_parse_global(Panel *p, config_setting_t *cfg)
     }
     if (config_setting_lookup_int(cfg, "autohide", &i))
         p->autohide = i != 0;
-    config_setting_lookup_int(cfg, "heightwhenhidden", &p->height_when_hidden);
+    if (config_setting_lookup_int(cfg, "heightwhenhidden", &i))
+        p->height_when_hidden = MAX(0, i);
     if (config_setting_lookup_string(cfg, "tintcolor", &str))
     {
         if (!gdk_color_parse (str, &p->gtintcolor))
@@ -1308,427 +1715,154 @@ panel_parse_global(Panel *p, config_setting_t *cfg)
     if (config_setting_lookup_string(cfg, "backgroundfile", &str))
         p->background_file = g_strdup(str);
     config_setting_lookup_int(cfg, "iconsize", &p->icon_size);
-    if (config_setting_lookup_int(cfg, "loglevel", &configured_log_level))
-    {
-        if (!log_level_set_on_commandline)
-            log_level = configured_log_level;
-    }
 
     panel_normalize_configuration(p);
 
     return 1;
 }
 
-static int
-panel_parse_plugin(Panel *p, config_setting_t *cfg)
+static void on_monitors_changed(GdkScreen* screen, gpointer unused)
 {
-    const char *type = NULL;
-
-    ENTER;
-    config_setting_lookup_string(cfg, "type", &type);
-    DBG("plug %s\n", type);
+    GSList *pl;
+    int monitors = gdk_screen_get_n_monitors(screen);
 
-    if (!type || lxpanel_add_plugin(p, type, cfg, -1) == NULL) {
-        ERR( "lxpanel: can't load %s plugin\n", type);
-        goto error;
+    for (pl = all_panels; pl; pl = pl->next)
+    {
+        LXPanel *p = pl->data;
+
+        /* handle connecting and disconnecting monitors now */
+        if (p->priv->monitor < monitors && !p->priv->initialized)
+            panel_start_gui(p, config_setting_get_member(config_root_setting(p->priv->config), ""));
+        else if (p->priv->monitor >= monitors && p->priv->initialized)
+            panel_stop_gui(p);
+        /* resize panel if appropriate monitor changed its size or position */
+        else
+        {
+            /* SF bug #666: after screen resize panel cannot establish
+               right size since cannot be moved while is hidden */
+            ah_state_set(p, AH_STATE_VISIBLE);
+            gtk_widget_queue_resize(GTK_WIDGET(p));
+        }
     }
-    RET(1);
-
-error:
-    RET(0);
 }
 
-int panel_start( Panel *p )
+static int panel_start(LXPanel *p)
 {
-    config_setting_t *list, *s;
-    int i;
+    config_setting_t *list;
+    GdkScreen *screen = gdk_screen_get_default();
 
     /* parse global section */
     ENTER;
 
-    list = config_setting_get_member(config_root_setting(p->config), "");
-    if (!list || !panel_parse_global(p, config_setting_get_elem(list, 0)))
+    list = config_setting_get_member(config_root_setting(p->priv->config), "");
+    if (!list || !panel_parse_global(p->priv, config_setting_get_elem(list, 0)))
         RET(0);
 
-    panel_start_gui(p);
-
-    for (i = 1; (s = config_setting_get_elem(list, i)) != NULL; )
-        if (strcmp(config_setting_get_name(s), "Plugin") == 0 &&
-            panel_parse_plugin(p, s)) /* success on plugin start */
-            i++;
-        else /* remove invalid data from config */
-            config_setting_remove_elem(list, i);
-
-    /* update backgrond of panel and all plugins */
-    panel_update_background( p );
+    if (p->priv->monitor < gdk_screen_get_n_monitors(screen))
+        panel_start_gui(p, list);
+    if (monitors_handler == 0)
+        monitors_handler = g_signal_connect(screen, "monitors-changed",
+                                            G_CALLBACK(on_monitors_changed), NULL);
     return 1;
 }
 
 void panel_destroy(Panel *p)
 {
-    ENTER;
-
-    if (p->pref_dialog != NULL)
-        gtk_widget_destroy(p->pref_dialog);
-    if (p->plugin_pref_dialog != NULL)
-        /* just close the dialog, it will do all required cleanup */
-        gtk_dialog_response(GTK_DIALOG(p->plugin_pref_dialog), GTK_RESPONSE_CLOSE);
-
-    if (p->bg != NULL)
-    {
-        g_signal_handlers_disconnect_by_func(G_OBJECT(p->bg), on_root_bg_changed, p);
-        g_object_unref(p->bg);
-    }
-
-    if( p->config_changed )
-        panel_config_save( p );
-    config_destroy(p->config);
-
-    if( p->topgwin )
-    {
-        gtk_window_group_remove_window( win_grp, GTK_WINDOW(  p->topgwin ) );
-        gtk_widget_destroy(p->topgwin);
-    }
-    g_free(p->workarea);
-    g_free( p->background_file );
-    g_slist_free( p->system_menus );
-    gdk_flush();
-    XFlush(GDK_DISPLAY());
-    XSync(GDK_DISPLAY(), True);
-
-    g_free( p->name );
-    g_free(p);
-    RET();
+    gtk_widget_destroy(GTK_WIDGET(p->topgwin));
 }
 
-Panel* panel_new( const char* config_file, const char* config_name )
+LXPanel* panel_new( const char* config_file, const char* config_name )
 {
-    Panel* panel = NULL;
+    LXPanel* panel = NULL;
 
     if (G_LIKELY(config_file))
     {
         panel = panel_allocate();
-        panel->name = g_strdup(config_name);
+        panel->priv->name = g_strdup(config_name);
         g_debug("starting panel from file %s",config_file);
-        if (!config_read_file(panel->config, config_file) ||
+        if (!config_read_file(panel->priv->config, config_file) ||
             !panel_start(panel))
         {
-            ERR( "lxpanel: can't start panel\n");
-            panel_destroy( panel );
+            g_warning( "lxpanel: can't start panel");
+            gtk_widget_destroy(GTK_WIDGET(panel));
             panel = NULL;
         }
     }
     return panel;
 }
 
-static void
-usage()
-{
-    g_print(_("lxpanel %s - lightweight GTK2+ panel for UNIX desktops\n"), version);
-    g_print(_("Command line options:\n"));
-    g_print(_(" --help      -- print this help and exit\n"));
-    g_print(_(" --version   -- print version and exit\n"));
-    g_print(_(" --log <number> -- set log level 0-5. 0 - none 5 - chatty\n"));
-//    g_print(_(" --configure -- launch configuration utility\n"));
-    g_print(_(" --profile name -- use specified profile\n"));
-    g_print("\n");
-    g_print(_(" -h  -- same as --help\n"));
-    g_print(_(" -p  -- same as --profile\n"));
-    g_print(_(" -v  -- same as --version\n"));
- //   g_print(_(" -C  -- same as --configure\n"));
-    g_print(_("\nVisit http://lxde.org/ for detail.\n\n"));
-}
-
-int panel_handle_x_error(Display * d, XErrorEvent * ev)
-{
-    char buf[256];
-
-    if (log_level >= LOG_WARN) {
-        XGetErrorText(GDK_DISPLAY(), ev->error_code, buf, 256);
-        LOG(LOG_WARN, "lxpanel : X error: %s\n", buf);
-    }
-    return 0;  /* Ignored */
-}
-
-int panel_handle_x_error_swallow_BadWindow_BadDrawable(Display * d, XErrorEvent * ev)
-{
-    if ((ev->error_code != BadWindow) && (ev->error_code != BadDrawable))
-        panel_handle_x_error(d, ev);
-    return 0;  /* Ignored */
-}
-
-/* Lightweight lock related functions - X clipboard hacks */
-
-#define CLIPBOARD_NAME "LXPANEL_SELECTION"
-
-/*
- * clipboard_get_func - dummy get_func for gtk_clipboard_set_with_data ()
- */
-static void
-clipboard_get_func(
-    GtkClipboard *clipboard G_GNUC_UNUSED,
-    GtkSelectionData *selection_data G_GNUC_UNUSED,
-    guint info G_GNUC_UNUSED,
-    gpointer user_data_or_owner G_GNUC_UNUSED)
-{
-}
-
-/*
- * clipboard_clear_func - dummy clear_func for gtk_clipboard_set_with_data ()
- */
-static void clipboard_clear_func(
-    GtkClipboard *clipboard G_GNUC_UNUSED,
-    gpointer user_data_or_owner G_GNUC_UNUSED)
-{
-}
 
-/*
- * Lightweight version for checking single instance.
- * Try and get the CLIPBOARD_NAME clipboard instead of using file manipulation.
- *
- * Returns TRUE if successfully retrieved and FALSE otherwise.
- */
-static gboolean check_main_lock()
+GtkOrientation panel_get_orientation(LXPanel *panel)
 {
-    static const GtkTargetEntry targets[] = { { CLIPBOARD_NAME, 0, 0 } };
-    gboolean retval = FALSE;
-    GtkClipboard *clipboard;
-    Atom atom;
-
-    atom = gdk_x11_get_xatom_by_name(CLIPBOARD_NAME);
-
-    XGrabServer(GDK_DISPLAY());
-
-    if (XGetSelectionOwner(GDK_DISPLAY(), atom) != None)
-        goto out;
-
-    clipboard = gtk_clipboard_get(gdk_atom_intern(CLIPBOARD_NAME, FALSE));
-
-    if (gtk_clipboard_set_with_data(clipboard, targets,
-                                    G_N_ELEMENTS (targets),
-                                    clipboard_get_func,
-                                    clipboard_clear_func, NULL))
-        retval = TRUE;
-
-out:
-    XUngrabServer (GDK_DISPLAY ());
-    gdk_flush ();
-
-    return retval;
+    return panel->priv->orientation;
 }
-#undef CLIPBOARD_NAME
 
-static gboolean start_all_panels( )
+gint panel_get_icon_size(LXPanel *panel)
 {
-    gboolean is_global;
-    for( is_global = 0; ! all_panels && is_global < 2; ++is_global )
-    {
-        char* panel_dir = get_config_file( cprofile, "panels", is_global );
-        GDir* dir = g_dir_open( panel_dir, 0, NULL );
-        const gchar* name;
-
-        if( ! dir )
-        {
-            g_free( panel_dir );
-            continue;
-        }
-
-        while((name = g_dir_read_name(dir)) != NULL)
-        {
-            char* panel_config = g_build_filename( panel_dir, name, NULL );
-            if (strchr(panel_config, '~') == NULL)     /* Skip editor backup files in case user has hand edited in this directory */
-            {
-                Panel* panel = panel_new( panel_config, name );
-                if( panel )
-                    all_panels = g_slist_prepend( all_panels, panel );
-            }
-            g_free( panel_config );
-        }
-        g_dir_close( dir );
-        g_free( panel_dir );
-    }
-    return all_panels != NULL;
+    return panel->priv->icon_size;
 }
 
-void load_global_config();
-void free_global_config();
-
-int main(int argc, char *argv[], char *env[])
+gint panel_get_height(LXPanel *panel)
 {
-    int i;
-    const char* desktop_name;
-
-    setlocale(LC_CTYPE, "");
-
-       g_thread_init(NULL);
-/*     gdk_threads_init();
-       gdk_threads_enter(); */
-
-    gtk_init(&argc, &argv);
-
-#ifdef ENABLE_NLS
-    bindtextdomain ( GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR );
-    bind_textdomain_codeset ( GETTEXT_PACKAGE, "UTF-8" );
-    textdomain ( GETTEXT_PACKAGE );
-#endif
-
-    XSetLocaleModifiers("");
-    XSetErrorHandler((XErrorHandler) panel_handle_x_error);
-
-    resolve_atoms();
-
-    desktop_name = g_getenv("XDG_CURRENT_DESKTOP");
-    is_in_lxde = desktop_name && (0 == strcmp(desktop_name, "LXDE"));
-
-    for (i = 1; i < argc; i++) {
-        if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
-            usage();
-            exit(0);
-        } else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) {
-            printf("lxpanel %s\n", version);
-            exit(0);
-        } else if (!strcmp(argv[i], "--log")) {
-            i++;
-            if (i == argc) {
-                ERR( "lxpanel: missing log level\n");
-                usage();
-                exit(1);
-            } else {
-                log_level = atoi(argv[i]);
-                log_level_set_on_commandline = true;
-            }
-        } else if (!strcmp(argv[i], "--configure") || !strcmp(argv[i], "-C")) {
-            config = 1;
-        } else if (!strcmp(argv[i], "--profile") || !strcmp(argv[i], "-p")) {
-            i++;
-            if (i == argc) {
-                ERR( "lxpanel: missing profile name\n");
-                usage();
-                exit(1);
-            } else {
-                cprofile = g_strdup(argv[i]);
-            }
-        } else {
-            printf("lxpanel: unknown option - %s\n", argv[i]);
-            usage();
-            exit(1);
-        }
-    }
-
-    /* Check for duplicated lxpanel instances */
-    if (!check_main_lock() && !config) {
-        printf("There is already an instance of LXPanel.  Now to exit\n");
-        exit(1);
-    }
-
-    /* Add our own icons to the search path of icon theme */
-    gtk_icon_theme_append_search_path( gtk_icon_theme_get_default(), PACKAGE_DATA_DIR "/lxpanel/images" );
-
-    fbev = fb_ev_new();
-    win_grp = gtk_window_group_new();
-
-restart:
-    is_restarting = FALSE;
-
-    /* init LibFM */
-    fm_gtk_init(NULL);
-
-    /* prepare modules data */
-    _prepare_modules();
-
-    load_global_config();
-
-       /* NOTE: StructureNotifyMask is required by XRandR
-        * See init_randr_support() in gdkscreen-x11.c of gtk+ for detail.
-        */
-    gdk_window_set_events(gdk_get_default_root_window(), GDK_STRUCTURE_MASK |
-            GDK_SUBSTRUCTURE_MASK | GDK_PROPERTY_CHANGE_MASK);
-    gdk_window_add_filter(gdk_get_default_root_window (), (GdkFilterFunc)panel_event_filter, NULL);
-
-    if( G_UNLIKELY( ! start_all_panels() ) )
-        g_warning( "Config files are not found.\n" );
-/*
- * FIXME: configure??
-    if (config)
-        configure();
-*/
-    gtk_main();
-
-    XSelectInput (GDK_DISPLAY(), GDK_ROOT_WINDOW(), NoEventMask);
-    gdk_window_remove_filter(gdk_get_default_root_window (), (GdkFilterFunc)panel_event_filter, NULL);
-
-    /* destroy all panels */
-    g_slist_foreach( all_panels, (GFunc) panel_destroy, NULL );
-    g_slist_free( all_panels );
-    all_panels = NULL;
-    g_free( cfgfile );
-
-    free_global_config();
-
-    _unload_modules();
-    fm_gtk_finalize();
-
-    if( is_restarting )
-        goto restart;
-
-    /* gdk_threads_leave(); */
-
-    g_object_unref(win_grp);
-    g_object_unref(fbev);
-
-    return 0;
+    return panel->priv->height;
 }
 
-extern GtkOrientation panel_get_orientation(Panel *panel)
+Window panel_get_xwindow(LXPanel *panel)
 {
-    return panel->orientation;
+    return panel->priv->topxwin;
 }
 
-extern gint panel_get_icon_size(Panel *panel)
+gint panel_get_monitor(LXPanel *panel)
 {
-    return panel->icon_size;
+    return panel->priv->monitor;
 }
 
-extern gint panel_get_height(Panel *panel)
+GtkStyle *panel_get_defstyle(LXPanel *panel)
 {
-    return panel->height;
+    return panel->priv->defstyle;
 }
 
-extern GtkWindow *panel_get_toplevel_window(Panel *panel)
+GtkIconTheme *panel_get_icon_theme(LXPanel *panel)
 {
-    return GTK_WINDOW(panel->topgwin);
+    return panel->priv->icon_theme;
 }
 
-extern GtkStyle *panel_get_defstyle(Panel *panel)
+gboolean panel_is_at_bottom(LXPanel *panel)
 {
-    return panel->defstyle;
+    return panel->priv->edge == EDGE_BOTTOM;
 }
 
-extern GtkIconTheme *panel_get_icon_theme(Panel *panel)
+gboolean panel_is_dynamic(LXPanel *panel)
 {
-    return panel->icon_theme;
+    return panel->priv->widthtype == WIDTH_REQUEST;
 }
 
-extern GtkWidget *panel_box_new(Panel *panel, gboolean homogeneous, gint spacing)
+GtkWidget *panel_box_new(LXPanel *panel, gboolean homogeneous, gint spacing)
 {
-    return panel->my_box_new(homogeneous, spacing);
+    if (panel->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
+        return gtk_hbox_new(homogeneous, spacing);
+    return gtk_vbox_new(homogeneous, spacing);
 }
 
-extern GtkWidget *panel_separator_new(Panel *panel)
+GtkWidget *panel_separator_new(LXPanel *panel)
 {
-    return panel->my_separator_new();
+    if (panel->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
+        return gtk_vseparator_new();
+    return gtk_hseparator_new();
 }
 
-gboolean _class_is_present(LXPanelPluginInit *init)
+gboolean _class_is_present(const LXPanelPluginInit *init)
 {
     GSList *sl;
 
     for (sl = all_panels; sl; sl = sl->next )
     {
-        Panel *panel = (Panel*)sl->data;
+        LXPanel *panel = (LXPanel*)sl->data;
         GList *plugins, *p;
 
-        plugins = gtk_container_get_children(GTK_CONTAINER(panel->box));
+        if (panel->priv->box == NULL)
+            continue;
+        plugins = gtk_container_get_children(GTK_CONTAINER(panel->priv->box));
         for (p = plugins; p; p = p->next)
             if (PLUGIN_CLASS(p->data) == init)
             {