Add GTK+3 support code into paint_root_pixmap(), never tested.
[lxde/lxpanel.git] / src / panel.c
index bedbbc2..58cb199 100644 (file)
 
 #include "private.h"
 #include "misc.h"
-#include "bg.h"
 
 #include "lxpanelctl.h"
 #include "dbg.h"
+#include "gtk-compat.h"
 
 gchar *cprofile = "default";
 
-GtkWindowGroup* win_grp = NULL; /* window group used to limit the scope of model dialog. */
-
 GSList* all_panels = NULL;  /* a single-linked list storing all panels */
-static gulong monitors_handler = 0;
 
 gboolean is_in_lxde = FALSE;
 
+static GtkWindowGroup* win_grp = NULL; /* window group used to limit the scope of model dialog. */
+
+static gulong monitors_handler = 0;
+
 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 on_root_bg_changed(FbBg *bg, LXPanel* p);
 static void _panel_update_background(LXPanel * p);
 
+enum
+{
+    ICON_SIZE_CHANGED,
+    PANEL_FONT_CHANGED,
+    N_SIGNALS
+};
+
+static guint signals[N_SIGNALS];
+
 G_DEFINE_TYPE(PanelToplevel, lxpanel, GTK_TYPE_WINDOW);
 
 static void lxpanel_finalize(GObject *object)
@@ -67,7 +76,7 @@ static void lxpanel_finalize(GObject *object)
         lxpanel_config_save( self );
     config_destroy(p->config);
 
-    XFree(p->workarea);
+    //XFree(p->workarea);
     g_free( p->background_file );
     g_slist_free( p->system_menus );
 
@@ -94,12 +103,6 @@ static void panel_stop_gui(LXPanel *self)
         /* 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, self);
-        g_object_unref(p->bg);
-        p->bg = NULL;
-    }
 
     if (p->initialized)
     {
@@ -110,12 +113,22 @@ static void panel_stop_gui(LXPanel *self)
         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)))
     {
@@ -141,11 +154,7 @@ static gboolean idle_update_background(gpointer p)
         return FALSE;
 
     /* Panel could be destroyed while background update scheduled */
-#if GTK_CHECK_VERSION(2, 20, 0)
     if (gtk_widget_get_realized(p))
-#else
-    if (GTK_WIDGET_REALIZED(p))
-#endif
     {
         gdk_display_sync( gtk_widget_get_display(p) );
         _panel_update_background(panel);
@@ -164,6 +173,19 @@ void _panel_queue_update_background(LXPanel *panel)
                                                             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);
@@ -181,7 +203,9 @@ static void lxpanel_style_set(GtkWidget *widget, GtkStyle* prev)
 
 static void lxpanel_size_request(GtkWidget *widget, GtkRequisition *req)
 {
-    Panel *p = LXPANEL(widget)->priv;
+    LXPanel *panel = LXPANEL(widget);
+    Panel *p = panel->priv;
+    GdkRectangle rect;
 
     GTK_WIDGET_CLASS(lxpanel_parent_class)->size_request(widget, req);
 
@@ -190,19 +214,19 @@ static void lxpanel_size_request(GtkWidget *widget, GtkRequisition *req)
          * report 0 size.  Ask the content box instead for its size. */
         gtk_widget_size_request(p->box, req);
 
-    /* FIXME: is this ever required? */
-    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;
-    calculate_position(p);
-
-    gtk_widget_set_size_request( widget, p->aw, p->ah );
+    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)
 {
-    Panel *p = LXPANEL(widget)->priv;
+    LXPanel *panel = LXPANEL(widget);
+    Panel *p = panel->priv;
+    GdkRectangle rect;
+    gint x, y;
 
     GTK_WIDGET_CLASS(lxpanel_parent_class)->size_allocate(widget, a);
 
@@ -210,40 +234,44 @@ static void lxpanel_size_allocate(GtkWidget *widget, GtkAllocation *a)
         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);
 
-    if (a->width != p->aw || a->height != p->ah || a->x != p->ax || a->y != p->ay)
+    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);
-        _panel_set_wm_strut(LXPANEL(widget));
-    }
-    else if (p->background_update_queued)
-    {
-        g_source_remove(p->background_update_queued);
-        p->background_update_queued = 0;
-#if GTK_CHECK_VERSION(2, 20, 0)
-        if (gtk_widget_get_realized(widget))
-#else
-        if (GTK_WIDGET_REALIZED(widget))
-#endif
-            _panel_update_background(LXPANEL(widget));
+        /* 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;
 
-    if (e->width == p->cw && e->height == p->ch && e->x == p->cx && e->y == p->cy)
-        goto ok;
     p->cw = e->width;
     p->ch = e->height;
     p->cx = e->x;
     p->cy = e->y;
 
-    if (p->transparent)
-        fb_bg_notify_changed_bg(p->bg);
-ok:
     return GTK_WIDGET_CLASS(lxpanel_parent_class)->configure_event(widget, e);
 }
 
@@ -283,6 +311,24 @@ static void lxpanel_class_init(PanelToplevelClass *klass)
     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)
@@ -317,13 +363,30 @@ static void lxpanel_init(PanelToplevel *self)
     p->icon_theme = gtk_icon_theme_get_default();
     p->config = config_new();
     p->defstyle = gtk_widget_get_default_style();
-    gtk_window_set_type_hint(GTK_WINDOW(self), GDK_WINDOW_TYPE_HINT_DOCK);
 }
 
 /* Allocate and initialize new Panel structure. */
 static LXPanel* panel_allocate(void)
 {
-    return g_object_new(LX_TYPE_PANEL, NULL);
+    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. */
@@ -347,6 +410,92 @@ static void panel_normalize_configuration(Panel* p)
         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           *
  ****************************************************/
@@ -365,11 +514,7 @@ void _panel_set_wm_strut(LXPanel *panel)
     gulong strut_lower;
     gulong strut_upper;
 
-#if GTK_CHECK_VERSION(2, 20, 0)
     if (!gtk_widget_get_mapped(GTK_WIDGET(panel)))
-#else
-    if (!GTK_WIDGET_MAPPED(panel))
-#endif
         return;
     /* most wm's tend to ignore struts of unmapped windows, and that's how
      * lxpanel hides itself. so no reason to set it. */
@@ -381,25 +526,21 @@ void _panel_set_wm_strut(LXPanel *panel)
     {
         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;
@@ -407,18 +548,15 @@ void _panel_set_wm_strut(LXPanel *panel)
             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
     {
@@ -457,11 +595,68 @@ void _panel_set_wm_strut(LXPanel *panel)
  *         panel's handlers for GTK events          *
  ****************************************************/
 
+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;
 
-static void
-on_root_bg_changed(FbBg *bg, LXPanel* p)
-{
-    _panel_update_background( p );
+    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)
+    {
+        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
+    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
 }
 
 void panel_determine_background_pixmap(Panel * panel, GtkWidget * widget, GdkWindow * window)
@@ -474,43 +669,74 @@ void _panel_determine_background_pixmap(LXPanel * panel, GtkWidget * widget)
     GdkPixmap * pixmap = NULL;
     GdkWindow * window = gtk_widget_get_window(widget);
     Panel * p = panel->priv;
-
-    /* Free p->bg if it is not going to be used. */
-    if (( ! p->transparent) && (p->bg != NULL))
+    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)
     {
-        g_signal_handlers_disconnect_by_func(G_OBJECT(p->bg), on_root_bg_changed, panel);
-        g_object_unref(p->bg);
-        p->bg = NULL;
-    }
+        GdkPixbuf *pixbuf = NULL;
 
-    if (p->background)
-    {
-        /* User specified background pixmap. */
-        if (p->background_file != NULL)
-            pixmap = fb_bg_get_pix_from_file(widget, p->background_file);
-    }
+        p->surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, p->aw, p->ah);
+        cr = cairo_create(p->surface);
+        if (p->background)
+        {
+            /* User specified background pixmap. */
+            pixbuf = gdk_pixbuf_new_from_file(p->background_file, NULL);
+        }
+        if ((p->transparent && p->alpha != 255) || /* ignore it for opaque panel */
+            (pixbuf != NULL && gdk_pixbuf_get_has_alpha(pixbuf)))
+        {
+            /* Transparent.  Determine the appropriate value from the root pixmap. */
+            paint_root_pixmap(panel, cr);
+        }
+        if (pixbuf != NULL)
+        {
+            gint w = gdk_pixbuf_get_width(pixbuf);
+            gint h = gdk_pixbuf_get_height(pixbuf);
 
-    else if (p->transparent)
-    {
-        /* Transparent.  Determine the appropriate value from the root pixmap. */
-        if (p->bg == NULL)
+            /* 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);
+                }
+            y = 0;
+            g_object_unref(pixbuf);
+        }
+        else
         {
-            p->bg = fb_bg_get_for_display();
-            g_signal_connect(G_OBJECT(p->bg), "changed", G_CALLBACK(on_root_bg_changed), panel);
+            /* 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.
@@ -523,7 +749,14 @@ void panel_update_background(Panel * p)
 static void _panel_update_background(LXPanel * p)
 {
     GtkWidget *w = GTK_WIDGET(p);
-    GList *plugins, *l;
+    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, w);
@@ -531,7 +764,8 @@ static void _panel_update_background(LXPanel * p)
     gtk_widget_queue_draw(w);
 
     /* Loop over all plugins redrawing each plugin. */
-    plugins = gtk_container_get_children(GTK_CONTAINER(p->priv->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);
@@ -636,17 +870,20 @@ static gboolean ah_state_hide_timeout(gpointer p)
 static void ah_state_set(LXPanel *panel, PanelAHState ah_state)
 {
     Panel *p = panel->priv;
+    GdkRectangle rect;
 
     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));
-            p->visible = TRUE;
             break;
         case AH_STATE_WAITING:
             if (p->hide_timeout)
@@ -814,7 +1051,25 @@ static void panel_popupmenu_create_panel( GtkMenuItem* item, LXPanel* panel )
     screen = gtk_widget_get_screen(GTK_WIDGET(panel));
     g_assert(screen);
     monitors = gdk_screen_get_n_monitors(screen);
-    /* FIXME: try to allocate edge on current monitor first */
+    /* 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 */
@@ -1151,6 +1406,7 @@ panel_start_gui(LXPanel *panel, config_setting_t *list)
     Panel *p = panel->priv;
     GtkWidget *w = GTK_WIDGET(panel);
     config_setting_t *s;
+    GdkRectangle rect;
     int i;
 
     ENTER;
@@ -1158,20 +1414,21 @@ panel_start_gui(LXPanel *panel, config_setting_t *list)
     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); */
-    gtk_widget_set_name(w, "PanelToplevel");
     p->display = gdk_display_get_default();
-    gtk_container_set_border_width(GTK_CONTAINER(panel), 0);
-    gtk_window_set_resizable(GTK_WINDOW(panel), FALSE);
     gtk_window_set_wmclass(GTK_WINDOW(panel), "panel", "lxpanel");
-    gtk_window_set_title(GTK_WINDOW(panel), "panel");
-    gtk_window_set_position(GTK_WINDOW(panel), GTK_WIN_POS_NONE);
-    gtk_window_set_decorated(GTK_WINDOW(panel), FALSE);
 
-    gtk_window_group_add_window( win_grp, (GtkWindow*)panel );
+    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 );
 
@@ -1202,10 +1459,12 @@ panel_start_gui(LXPanel *panel, config_setting_t *list)
     panel_set_dock_type(p);
 
     /* window mapping point */
-    gtk_widget_show_all(w);
+    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(panel);
 
     /* send it to running wm */
     Xclimsg(p->topxwin, a_NET_WM_DESKTOP, G_MAXULONG, 0, 0, 0, 0);
@@ -1220,9 +1479,6 @@ panel_start_gui(LXPanel *panel, config_setting_t *list)
     XChangeProperty(xdisplay, p->topxwin, a_NET_WM_STATE, XA_ATOM,
           32, PropModeReplace, (unsigned char *) state, 3);
 
-    _calculate_position(panel);
-    gdk_window_move_resize(gtk_widget_get_window(w), p->ax, p->ay, p->aw, p->ah);
-    _panel_set_wm_strut(panel);
     p->initialized = TRUE;
 
     if (list) for (i = 1; (s = config_setting_get_elem(list, i)) != NULL; )
@@ -1232,9 +1488,6 @@ panel_start_gui(LXPanel *panel, config_setting_t *list)
         else /* remove invalid data from config */
             config_setting_remove_elem(list, i);
 
-    /* update backgrond of panel and all plugins */
-    _panel_update_background(panel);
-
     RET();
 }
 
@@ -1484,7 +1737,12 @@ static void on_monitors_changed(GdkScreen* screen, gpointer unused)
             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));
+        }
     }
 }