[Xfce4-commits] <xfce4-panel:devel> Improved panel window code.

Nick Schermer nick at xfce.org
Tue Aug 11 20:32:07 CEST 2009


Updating branch refs/heads/devel
         to e880cd58799da5d8210ffec4d9ac3b5eb110e7a1 (commit)
       from 44ea6d39ab089aad38255a9bad67644a572d0e26 (commit)

commit e880cd58799da5d8210ffec4d9ac3b5eb110e7a1
Author: Nick Schermer <nick at xfce.org>
Date:   Sun May 17 20:51:35 2009 +0200

    Improved panel window code.
    
    Not entirely finished but good enough for normal usage. The code
    basically splits the window layer in two: a base window class that
    is used for the normal window and the auto hide window and
    a panel window class.
    The screen positioning code has been improved too and should work
    a lot better with multi screen setups and randr.
    
    Also dropped the last bits of the glue code.

 panel/Makefile.am                    |    4 +-
 panel/panel-application.c            |   70 +-
 panel/panel-base-window.c            |  628 ++++++++
 panel/panel-base-window.h            |   87 ++
 panel/panel-glue.c                   |  129 --
 panel/panel-glue.h                   |   37 -
 panel/panel-plugin-external.c        |    3 +-
 panel/panel-preferences-dialog.c     |   11 +-
 panel/panel-preferences-dialog.glade |    2 +-
 panel/panel-window.c                 | 2759 ++++++++++++++++------------------
 panel/panel-window.h                 |   63 +-
 11 files changed, 2039 insertions(+), 1754 deletions(-)

diff --git a/panel/Makefile.am b/panel/Makefile.am
index 8fb29ef..894f83b 100644
--- a/panel/Makefile.am
+++ b/panel/Makefile.am
@@ -27,14 +27,14 @@ xfce4_panel_SOURCES = \
 	main.c \
 	panel-application.c \
 	panel-application.h \
+	panel-base-window.c \
+	panel-base-window.h \
 	panel-dbus-client.c \
 	panel-dbus-client.h \
 	panel-dbus-service.c \
 	panel-dbus-service.h \
 	panel-dialogs.c \
 	panel-dialogs.h \
-	panel-glue.c \
-	panel-glue.h \
 	panel-item-dialog.c \
 	panel-item-dialog.h \
 	panel-itembar.c \
diff --git a/panel/panel-application.c b/panel/panel-application.c
index ddb0fe7..5263dcb 100644
--- a/panel/panel-application.c
+++ b/panel/panel-application.c
@@ -42,7 +42,6 @@
 #include <panel/panel-preferences-dialog.h>
 #include <panel/panel-item-dialog.h>
 #include <panel/panel-dialogs.h>
-#include <panel/panel-glue.h>
 #include <panel/panel-plugin-external.h>
 
 #define AUTOSAVE_INTERVAL (10 * 60)
@@ -248,55 +247,46 @@ panel_application_xfconf_window_bindings (PanelApplication *application,
   guint          i;
   guint          panel_n = g_slist_index (application->windows, window);
   GValue         value = { 0, };
-  const gchar   *bool_properties[] = { "locked", "autohide", "span-monitors",
-                                       "horizontal" };
-  const gchar   *uint_properties[] = { "size", "length", "x-offset",
-                                       "y-offset", "enter-opacity",
-                                       "leave-opacity", "snap-edge",
-                                       "background-alpha" };
+  const struct 
+  {
+    const gchar *name;
+    GType        type;
+  } properties[] = 
+  {
+    { "locked", G_TYPE_BOOLEAN },
+    { "autohide", G_TYPE_BOOLEAN },
+    { "span-monitors", G_TYPE_BOOLEAN },
+    { "horizontal", G_TYPE_BOOLEAN },
+    { "horizontal", G_TYPE_BOOLEAN },
+    { "size", G_TYPE_UINT },
+    { "length", G_TYPE_UINT },
+    { "enter-opacity", G_TYPE_UINT },
+    { "leave-opacity", G_TYPE_UINT },
+    { "background-alpha", G_TYPE_UINT },
+    { "output-name", G_TYPE_STRING },
+    { "position", G_TYPE_STRING }
+  };
 
   /* connect the boolean properties */
-  for (i = 0; i < G_N_ELEMENTS (bool_properties); i++)
+  for (i = 0; i < G_N_ELEMENTS (properties); i++)
     {
       /* create xfconf property name */
       g_snprintf (buf, sizeof (buf), "/panels/panel-%u/%s",
-                  panel_n, bool_properties[i]);
+                  panel_n, properties[i].name);
 
       /* store the window settings in the channel before we create the binding,
        * so we don't loose the panel settings */
       if (store_settings)
         {
-          g_value_init (&value, G_TYPE_BOOLEAN);
-          g_object_get_property (G_OBJECT (window), bool_properties[i], &value);
+          g_value_init (&value, properties[i].type);
+          g_object_get_property (G_OBJECT (window), properties[i].name, &value);
           xfconf_channel_set_property (channel, buf, &value);
           g_value_unset (&value);
         }
 
       /* create binding */
-      xfconf_g_property_bind (channel, buf, G_TYPE_BOOLEAN,
-                              window, bool_properties[i]);
-    }
-
-  /* connect the unsigned intergets */
-  for (i = 0; i < G_N_ELEMENTS (uint_properties); i++)
-    {
-      /* create xfconf property name */
-      g_snprintf (buf, sizeof (buf), "/panels/panel-%u/%s",
-                  panel_n, uint_properties[i]);
-
-      /* store the window settings in the channel before we create the binding,
-       * so we don't loose the panel settings */
-      if (store_settings)
-        {
-          g_value_init(&value, G_TYPE_UINT);
-          g_object_get_property (G_OBJECT (window), uint_properties[i], &value);
-          xfconf_channel_set_property (channel, buf, &value);
-          g_value_unset (&value);
-        }
-
-      /* create binding */
-      xfconf_g_property_bind (channel, buf, G_TYPE_UINT,
-                              window, uint_properties[i]);
+      xfconf_g_property_bind (channel, buf, properties[i].type,
+                              window, properties[i].name);
     }
 }
 
@@ -332,7 +322,7 @@ panel_application_load (PanelApplication *application)
           /* get the plugin module name */
           g_snprintf (buf, sizeof (buf), "/panels/panel-%u/plugins/plugin-%u/module", i, j);
           name = xfconf_channel_get_string (channel, buf, NULL);
-          if (G_LIKELY (name))
+          if (IS_STRING (name))
             {
               /* read the plugin id */
               g_snprintf (buf, sizeof (buf), "/panels/panel-%u/plugins/plugin-%u/id", i, j);
@@ -573,7 +563,7 @@ panel_application_plugin_insert (PanelApplication  *application,
                         GTK_WIDGET (provider), position);
 
   /* send all the needed info about the panel to the plugin */
-  panel_glue_set_provider_info (XFCE_PANEL_PLUGIN_PROVIDER (provider), window);
+  panel_window_set_povider_info (window, provider);
 
   /* show the plugin */
   gtk_widget_show (provider);
@@ -807,7 +797,7 @@ panel_application_drag_data_received (GtkWidget        *itembar,
             panel_itembar_reorder_child (PANEL_ITEMBAR (itembar), provider, position);
 
             /* send all the needed panel information to the plugin */
-            panel_glue_set_provider_info (XFCE_PANEL_PLUGIN_PROVIDER (provider), window);
+            panel_window_set_povider_info (window, provider);
           }
 
         /* everything went fine */
@@ -1130,7 +1120,7 @@ panel_application_new_window (PanelApplication *application,
   panel_return_val_if_fail (XFCONF_IS_CHANNEL (application->xfconf), NULL);
 
   /* create panel window */
-  window = g_object_new (PANEL_TYPE_WINDOW, NULL);
+  window = panel_window_new ();
 
   /* realize */
   gtk_widget_realize (window);
@@ -1227,7 +1217,7 @@ panel_application_window_select (PanelApplication *application,
 
   /* update state for all windows */
   for (li = application->windows; li != NULL; li = li->next)
-    panel_window_set_active_panel (PANEL_WINDOW (li->data), !!(li->data == window));
+    g_object_set (G_OBJECT (li->data), "active", li->data == window, NULL);
 }
 
 
diff --git a/panel/panel-base-window.c b/panel/panel-base-window.c
new file mode 100644
index 0000000..16c36b2
--- /dev/null
+++ b/panel/panel-base-window.c
@@ -0,0 +1,628 @@
+/* $Id$ */
+/*
+ * Copyright (C) 2009 Nick Schermer <nick at xfce.org>
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_MATH_H
+#include <math.h>
+#endif
+
+#include <exo/exo.h>
+#include <libxfce4panel/libxfce4panel.h>
+#include <libxfce4panel/xfce-panel-plugin-provider.h>
+#include <common/panel-private.h>
+#include <panel/panel-base-window.h>
+#include <panel/panel-plugin-external.h>
+
+
+
+#define PANEL_BASE_WINDOW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
+                                            PANEL_TYPE_BASE_WINDOW, \
+                                            PanelBaseWindowPrivate))
+
+
+
+static void     panel_base_window_get_property                (GObject              *object,
+                                                               guint                 prop_id,
+                                                               GValue               *value,
+                                                               GParamSpec           *pspec);
+static void     panel_base_window_set_property                (GObject              *object,
+                                                               guint                 prop_id,
+                                                               const GValue         *value,
+                                                               GParamSpec           *pspec);
+static void     panel_base_window_finalize                    (GObject              *object);
+static gboolean panel_base_window_expose_event                (GtkWidget            *widget,
+                                                               GdkEventExpose       *event);
+static gboolean panel_base_window_enter_notify_event          (GtkWidget            *widget,
+                                                               GdkEventCrossing     *event);
+static gboolean panel_base_window_leave_notify_event          (GtkWidget            *widget,
+                                                               GdkEventCrossing     *event);
+static void     panel_base_window_composited_changed          (GtkWidget            *widget);
+static gboolean panel_base_window_active_timeout              (gpointer              user_data);
+static void     panel_base_window_active_timeout_destroyed    (gpointer              user_data);
+static void     panel_base_window_set_plugin_background_alpha (GtkWidget            *widget,
+                                                               gpointer              user_data);
+
+
+
+enum
+{
+  PROP_0,
+  PROP_ENTER_OPACITY,
+  PROP_LEAVE_OPACITY,
+  PROP_BACKGROUND_ALPHA,
+  PROP_BORDERS,
+  PROP_ACTIVE,
+  PROP_COMPOSITED,
+};
+
+struct _PanelBaseWindowPrivate
+{
+  /* borders */
+  PanelBorders borders;
+
+  /* settings */
+  gdouble      enter_opacity;
+  gdouble      leave_opacity;
+
+  /* active window timeout id */
+  guint        active_timeout_id;
+};
+
+
+
+G_DEFINE_TYPE (PanelBaseWindow, panel_base_window, GTK_TYPE_WINDOW)
+
+
+
+static void
+panel_base_window_class_init (PanelBaseWindowClass *klass)
+{
+  GObjectClass   *gobject_class;
+  GtkWidgetClass *gtkwidget_class;
+
+  /* add private data */
+  g_type_class_add_private (klass, sizeof (PanelBaseWindowPrivate));
+
+  gobject_class = G_OBJECT_CLASS (klass);
+  gobject_class->get_property = panel_base_window_get_property;
+  gobject_class->set_property = panel_base_window_set_property;
+  gobject_class->finalize = panel_base_window_finalize;
+
+  gtkwidget_class = GTK_WIDGET_CLASS (klass);
+  gtkwidget_class->expose_event = panel_base_window_expose_event;
+  gtkwidget_class->enter_notify_event = panel_base_window_enter_notify_event;
+  gtkwidget_class->leave_notify_event = panel_base_window_leave_notify_event;
+  gtkwidget_class->composited_changed = panel_base_window_composited_changed;
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_ENTER_OPACITY,
+                                   g_param_spec_uint ("enter-opacity", NULL, NULL,
+                                                      0, 100, 100,
+                                                      EXO_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_LEAVE_OPACITY,
+                                   g_param_spec_uint ("leave-opacity", NULL, NULL,
+                                                      0, 100, 100,
+                                                      EXO_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_BACKGROUND_ALPHA,
+                                   g_param_spec_uint ("background-alpha", NULL, NULL,
+                                                      0, 100, 100,
+                                                      EXO_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_BORDERS,
+                                   g_param_spec_uint ("borders", NULL, NULL,
+                                                      0, G_MAXUINT,
+                                                      PANEL_BORDER_NONE,
+                                                      EXO_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_ACTIVE,
+                                   g_param_spec_boolean ("active", NULL, NULL,
+                                                         FALSE,
+                                                         EXO_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_COMPOSITED,
+                                   g_param_spec_boolean ("composited", NULL, NULL,
+                                                         FALSE,
+                                                         EXO_PARAM_READABLE));
+}
+
+
+
+static void
+panel_base_window_init (PanelBaseWindow *window)
+{
+  /* set window properties */
+  gtk_window_set_resizable (GTK_WINDOW (window), TRUE);
+  gtk_window_set_decorated (GTK_WINDOW (window), FALSE);
+  gtk_window_set_type_hint (GTK_WINDOW (window), GDK_WINDOW_TYPE_HINT_DOCK);
+  gtk_window_set_gravity (GTK_WINDOW (window), GDK_GRAVITY_STATIC);
+
+  /* set private pointer */
+  window->priv = PANEL_BASE_WINDOW_GET_PRIVATE (window);
+
+  /* init */
+  window->is_composited = FALSE;
+  window->background_alpha = 1.00;
+
+  window->priv->enter_opacity = 1.00;
+  window->priv->leave_opacity = 1.00;
+  window->priv->borders = PANEL_BORDER_MASK;
+  window->priv->active_timeout_id = 0;
+
+  /* set compositing */
+  panel_base_window_composited_changed (GTK_WIDGET (window));
+}
+
+
+
+static void
+panel_base_window_get_property (GObject    *object,
+                                guint       prop_id,
+                                GValue     *value,
+                                GParamSpec *pspec)
+{
+  PanelBaseWindow        *window = PANEL_BASE_WINDOW (object);
+  PanelBaseWindowPrivate *priv = window->priv;
+
+  switch (prop_id)
+    {
+      case PROP_ENTER_OPACITY:
+        g_value_set_uint (value, rint (priv->enter_opacity * 100.00));
+        break;
+
+      case PROP_LEAVE_OPACITY:
+        g_value_set_uint (value, rint (priv->leave_opacity * 100.00));
+        break;
+
+      case PROP_BACKGROUND_ALPHA:
+        g_value_set_uint (value, rint (window->background_alpha * 100.00));
+        break;
+
+      case PROP_BORDERS:
+        g_value_set_uint (value, priv->borders);
+        break;
+
+      case PROP_ACTIVE:
+        g_value_set_boolean (value, !!(priv->active_timeout_id != 0));
+        break;
+
+      case PROP_COMPOSITED:
+        g_value_set_boolean (value, window->is_composited);
+        break;
+
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+        break;
+    }
+}
+
+
+
+static void
+panel_base_window_set_property (GObject      *object,
+                                guint         prop_id,
+                                const GValue *value,
+                                GParamSpec   *pspec)
+{
+  PanelBaseWindow        *window = PANEL_BASE_WINDOW (object);
+  PanelBaseWindowPrivate *priv = window->priv;
+  GtkWidget              *itembar;
+
+  switch (prop_id)
+    {
+      case PROP_ENTER_OPACITY:
+        /* set the new enter opacity */
+        priv->enter_opacity = g_value_get_uint (value) / 100.00;
+        break;
+
+      case PROP_LEAVE_OPACITY:
+        /* set the new leave opacity */
+        priv->leave_opacity = g_value_get_uint (value) / 100.00;
+        if (window->is_composited)
+          gtk_window_set_opacity (GTK_WINDOW (object), priv->leave_opacity);
+        break;
+
+      case PROP_BACKGROUND_ALPHA:
+        /* set the new background alpha */
+        window->background_alpha = g_value_get_uint (value) / 100.00;
+        if (window->is_composited)
+          gtk_widget_queue_draw (GTK_WIDGET (object));
+
+        /* send the new background alpha to the external plugins */
+        itembar = gtk_bin_get_child (GTK_BIN (window));
+        if (G_LIKELY (itembar != NULL))
+          gtk_container_foreach (GTK_CONTAINER (itembar),
+              panel_base_window_set_plugin_background_alpha, window);
+        break;
+
+      case PROP_BORDERS:
+        /* set new window borders and redraw the widget */
+        panel_base_window_set_borders (PANEL_BASE_WINDOW (object),
+                                       g_value_get_uint (value));
+        break;
+
+      case PROP_ACTIVE:
+        if (g_value_get_boolean (value))
+          {
+            /* start new timeout if not already running */
+            if (priv->active_timeout_id == 0)
+              priv->active_timeout_id = g_timeout_add_seconds_full (
+                  G_PRIORITY_DEFAULT_IDLE, 1,
+                  panel_base_window_active_timeout, object,
+                  panel_base_window_active_timeout_destroyed);
+          }
+        else if (priv->active_timeout_id != 0)
+          {
+            /* stop timeout */
+            g_source_remove (priv->active_timeout_id);
+          }
+
+        /* queue a draw */
+        gtk_widget_queue_resize (GTK_WIDGET (object));
+        break;
+
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+        break;
+    }
+}
+
+
+
+static void
+panel_base_window_finalize (GObject *object)
+{
+  PanelBaseWindowPrivate *priv = PANEL_BASE_WINDOW (object)->priv;
+
+  /* stop running active timeout */
+  if (priv->active_timeout_id != 0)
+    g_source_remove (priv->active_timeout_id);
+
+  (*G_OBJECT_CLASS (panel_base_window_parent_class)->finalize) (object);
+}
+
+
+
+static gboolean
+panel_base_window_expose_event (GtkWidget      *widget,
+                                GdkEventExpose *event)
+{
+  cairo_t                *cr;
+  GdkColor               *color;
+  PanelBaseWindow        *window = PANEL_BASE_WINDOW (widget);
+  PanelBaseWindowPrivate *priv = window->priv;
+  gdouble                 alpha;
+  gdouble                 width = widget->allocation.width;
+  gdouble                 height = widget->allocation.height;
+  const gdouble           dashes[] = { 4.00, 4.00 };
+  GTimeVal                timeval;
+  gboolean                result;
+
+  /* let gtk do it's thing */
+  result = (*GTK_WIDGET_CLASS (panel_base_window_parent_class)->expose_event) (widget, event);
+
+  if (!GTK_WIDGET_DRAWABLE (widget))
+    return result;
+
+  /* create cairo context and set some default properties */
+  cr = gdk_cairo_create (widget->window);
+  panel_return_val_if_fail (cr != NULL, result);
+  cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
+  cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+  cairo_set_line_width (cr, 1.00);
+
+  /* clip the drawing area */
+  gdk_cairo_rectangle (cr, &event->area);
+
+  /* get background alpha */
+  alpha = window->is_composited ? window->background_alpha : 1.00;
+
+  /* only do something with the background when compositing is enabled */
+  if (G_UNLIKELY (alpha < 1.00))
+    {
+      /* clip the drawing area, but preserve the rectangle */
+      cairo_clip_preserve (cr);
+
+      /* make the background transparent */
+      color = &(widget->style->bg[GTK_STATE_NORMAL]);
+      panel_util_set_source_rgba (cr, color, alpha);
+      cairo_fill (cr);
+    }
+  else
+    {
+      /* clip the drawing area */
+      cairo_clip (cr);
+    }
+
+  if (G_UNLIKELY (priv->active_timeout_id != 0))
+    {
+      /* set black color, no alpha */
+      color = &(widget->style->dark[GTK_STATE_SELECTED]);
+      panel_util_set_source_rgba (cr, color, 1.00);
+
+      /* set dash based on time (odd/even) */
+      g_get_current_time (&timeval);
+      cairo_set_dash (cr, dashes, G_N_ELEMENTS (dashes),
+                      (timeval.tv_sec % 4) * 2);
+
+      /* draw rectangle */
+      cairo_rectangle (cr, 0, 0, width - 1.00, height - 1.00);
+      cairo_stroke (cr);
+    }
+  else
+    {
+      /* safe some time if the bottom and right borders are not drawn */
+      if (PANEL_HAS_FLAG (priv->borders, PANEL_BORDER_BOTTOM | PANEL_BORDER_RIGHT))
+        {
+          /* set dark color */
+          color = &(widget->style->dark[GTK_STATE_NORMAL]);
+          panel_util_set_source_rgba (cr, color, alpha);
+
+          /* bottom line */
+          if (PANEL_HAS_FLAG (priv->borders, PANEL_BORDER_BOTTOM))
+            {
+              cairo_move_to (cr, 0.00, height - 1.00);
+              cairo_rel_line_to (cr, width, 0.00);
+            }
+
+          /* right line */
+          if (PANEL_HAS_FLAG (priv->borders, PANEL_BORDER_RIGHT))
+            {
+              cairo_move_to (cr, width - 1.00, 0.00);
+              cairo_rel_line_to (cr, 0.00, height);
+            }
+
+          /* stroke the dark lines */
+          cairo_stroke (cr);
+        }
+
+      /* safe some time if the top and left borders are not drawn */
+      if (PANEL_HAS_FLAG (priv->borders, PANEL_BORDER_TOP | PANEL_BORDER_LEFT))
+        {
+          /* set light color */
+          color = &(widget->style->light[GTK_STATE_NORMAL]);
+          panel_util_set_source_rgba (cr, color, alpha);
+
+          /* left line */
+          if (PANEL_HAS_FLAG (priv->borders, PANEL_BORDER_LEFT))
+            {
+              cairo_move_to (cr, 0.00, 0.00);
+              cairo_rel_line_to (cr, 0.00, height);
+            }
+
+          /* top line */
+          if (PANEL_HAS_FLAG (priv->borders, PANEL_BORDER_TOP))
+            {
+              cairo_move_to (cr, 0.00, 0.00);
+              cairo_rel_line_to (cr, width, 0.00);
+            }
+
+          /* stroke the light lines */
+          cairo_stroke (cr);
+        }
+    }
+
+  /* destroy cairo context */
+  cairo_destroy (cr);
+
+  return result;
+}
+
+
+
+static gboolean
+panel_base_window_enter_notify_event (GtkWidget        *widget,
+                                      GdkEventCrossing *event)
+{
+  PanelBaseWindow *window = PANEL_BASE_WINDOW (widget);
+
+  /* set the opacity (when they differ) */
+  if (event->detail != GDK_NOTIFY_INFERIOR
+      && window->is_composited
+      && window->priv->leave_opacity != window->priv->enter_opacity)
+    gtk_window_set_opacity (GTK_WINDOW (widget), window->priv->enter_opacity);
+
+  return FALSE;
+}
+
+
+
+static gboolean
+panel_base_window_leave_notify_event (GtkWidget        *widget,
+                                      GdkEventCrossing *event)
+{
+  PanelBaseWindow *window = PANEL_BASE_WINDOW (widget);
+
+  /* set the opacity (when they differ) */
+  if (event->detail != GDK_NOTIFY_INFERIOR
+      && window->is_composited
+      && window->priv->leave_opacity != window->priv->enter_opacity)
+    gtk_window_set_opacity (GTK_WINDOW (widget), window->priv->leave_opacity);
+
+  return FALSE;
+}
+
+
+
+static void
+panel_base_window_composited_changed (GtkWidget *widget)
+{
+  PanelBaseWindow *window = PANEL_BASE_WINDOW (widget);
+  GdkColormap     *colormap = NULL;
+  gboolean         was_composited = window->is_composited;
+  gboolean         was_visible;
+  GdkScreen       *screen;
+
+  panel_return_if_fail (PANEL_IS_BASE_WINDOW (widget));
+
+  /* check if the window is visible, if so, hide and unrealize it */
+  was_visible = GTK_WIDGET_VISIBLE (widget);
+  if (was_visible)
+    {
+      gtk_widget_hide (widget);
+      gtk_widget_unrealize (widget);
+    }
+
+  /* get the widget screen */
+  screen = gtk_window_get_screen (GTK_WINDOW (widget));
+  panel_return_if_fail (GDK_IS_SCREEN (screen));
+
+  /* get the rgba colormap if compositing is supported */
+  if (gtk_widget_is_composited (widget))
+    colormap = gdk_screen_get_rgba_colormap (screen);
+
+  /* fallback to the old colormap */
+  if (colormap == NULL)
+    {
+      window->is_composited = FALSE;
+      colormap = gdk_screen_get_rgb_colormap (screen);
+    }
+  else
+    {
+      window->is_composited = TRUE;
+      gtk_window_set_opacity (GTK_WINDOW (widget), window->priv->leave_opacity);
+    }
+
+  /* set the new colormap */
+  panel_return_if_fail (GDK_IS_COLORMAP (colormap));
+  gtk_widget_set_colormap (widget, colormap);
+
+  if (was_visible)
+    {
+      /* restore the window */
+      gtk_widget_realize (widget);
+      gtk_widget_show (widget);
+    }
+
+  /* emit the property if it changed */
+  if (window->is_composited != was_composited)
+    g_object_notify (G_OBJECT (widget), "composited");
+}
+
+
+
+static gboolean
+panel_base_window_active_timeout (gpointer user_data)
+{
+  /* queue a redraw */
+  gtk_widget_queue_draw (GTK_WIDGET (user_data));
+
+  return TRUE;
+}
+
+
+
+static void
+panel_base_window_active_timeout_destroyed (gpointer user_data)
+{
+  PANEL_BASE_WINDOW (user_data)->priv->active_timeout_id = 0;
+}
+
+
+
+static void
+panel_base_window_set_plugin_background_alpha (GtkWidget *widget,
+                                               gpointer   user_data)
+{
+  panel_return_if_fail (XFCE_IS_PANEL_PLUGIN_PROVIDER (widget));
+  panel_return_if_fail (PANEL_IS_BASE_WINDOW (user_data));
+
+  if (PANEL_IS_PLUGIN_EXTERNAL (widget))
+    panel_plugin_external_set_background_alpha (PANEL_PLUGIN_EXTERNAL (widget),
+        rint (PANEL_BASE_WINDOW (user_data)->background_alpha * 100.00));
+}
+
+
+
+void
+panel_base_window_move_resize (PanelBaseWindow *window,
+                               gint             x,
+                               gint             y,
+                               gint             width,
+                               gint             height)
+{
+  panel_return_if_fail (PANEL_IS_BASE_WINDOW (window));
+
+  /* resize the window if needed */
+  if (width > 0 && height > 0)
+    gtk_window_resize (GTK_WINDOW (window), width, height);
+
+  /* move the window to the new position */
+  gtk_window_move (GTK_WINDOW (window), x, y);
+}
+
+
+
+void
+panel_base_window_set_borders (PanelBaseWindow *window,
+                               PanelBorders     borders)
+{
+  PanelBaseWindowPrivate *priv = window->priv;
+
+  panel_return_if_fail (PANEL_IS_BASE_WINDOW (window));
+
+  if (priv->borders != borders)
+    {
+      priv->borders = borders;
+      gtk_widget_queue_resize (GTK_WIDGET (window));
+    }
+}
+
+
+
+PanelBorders
+panel_base_window_get_borders (PanelBaseWindow *window)
+{
+  PanelBaseWindowPrivate *priv = window->priv;
+
+  panel_return_val_if_fail (PANEL_IS_BASE_WINDOW (window), PANEL_BORDER_NONE);
+
+  if (priv->active_timeout_id != 0)
+    return PANEL_BORDER_MASK;
+
+  return priv->borders;
+}
+
+
+
+void
+panel_util_set_source_rgba (cairo_t  *cr,
+                            GdkColor *color,
+                            gdouble   alpha)
+{
+  panel_return_if_fail (alpha >= 0.00 && alpha <= 1.00);
+
+  if (G_LIKELY (alpha == 1.00))
+    cairo_set_source_rgb (cr, color->red / 65535.00,
+                          color->green / 65535.00,
+                          color->blue / 65535.00);
+  else
+    cairo_set_source_rgba (cr, color->red / 65535.00,
+                           color->green / 65535.00,
+                           color->blue / 65535.00, alpha);
+}
diff --git a/panel/panel-base-window.h b/panel/panel-base-window.h
new file mode 100644
index 0000000..2c50eb8
--- /dev/null
+++ b/panel/panel-base-window.h
@@ -0,0 +1,87 @@
+/* $Id$ */
+/*
+ * Copyright (C) 2009 Nick Schermer <nick at xfce.org>
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef __PANEL_BASE_WINDOW_H__
+#define __PANEL_BASE_WINDOW_H__
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+typedef struct _PanelBaseWindowClass   PanelBaseWindowClass;
+typedef struct _PanelBaseWindow        PanelBaseWindow;
+typedef struct _PanelBaseWindowPrivate PanelBaseWindowPrivate;
+typedef enum   _PanelBorders           PanelBorders;
+
+#define PANEL_TYPE_BASE_WINDOW            (panel_base_window_get_type ())
+#define PANEL_BASE_WINDOW(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), PANEL_TYPE_BASE_WINDOW, PanelBaseWindow))
+#define PANEL_BASE_WINDOW_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), PANEL_TYPE_BASE_WINDOW, PanelBaseWindowClass))
+#define PANEL_IS_BASE_WINDOW(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PANEL_TYPE_BASE_WINDOW))
+#define PANEL_IS_BASE_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PANEL_TYPE_BASE_WINDOW))
+#define PANEL_BASE_WINDOW_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), PANEL_TYPE_BASE_WINDOW, PanelBaseWindowClass))
+
+enum _PanelBorders
+{
+  PANEL_BORDER_NONE   = 0,
+  PANEL_BORDER_LEFT   = 1 << 0,
+  PANEL_BORDER_RIGHT  = 1 << 1,
+  PANEL_BORDER_TOP    = 1 << 2,
+  PANEL_BORDER_BOTTOM = 1 << 3,
+  PANEL_BORDER_MASK   = 0x0f
+};
+
+struct _PanelBaseWindowClass
+{
+  GtkWindowClass __parent__;
+};
+
+struct _PanelBaseWindow
+{
+  GtkWindow __parent__;
+
+  /*< private >*/
+  PanelBaseWindowPrivate *priv;
+
+  /*< private >*/
+  guint                   is_composited : 1;
+  gdouble                 background_alpha;
+};
+
+GType        panel_base_window_get_type    (void) G_GNUC_CONST;
+
+void         panel_base_window_move_resize (PanelBaseWindow *window,
+                                            gint             x,
+                                            gint             y,
+                                            gint             width,
+                                            gint             height);
+
+void         panel_base_window_set_borders (PanelBaseWindow *window,
+                                            PanelBorders     borders);
+PanelBorders panel_base_window_get_borders (PanelBaseWindow *window);
+
+void         panel_base_window_set_active  (PanelBaseWindow *window,
+                                            gboolean         active);
+
+void         panel_util_set_source_rgba    (cairo_t         *cr,
+                                            GdkColor        *color,
+                                            gdouble          alpha);
+
+G_END_DECLS
+
+#endif /* !__PANEL_BASE_WINDOW_H__ */
diff --git a/panel/panel-glue.c b/panel/panel-glue.c
deleted file mode 100644
index 43f335e..0000000
--- a/panel/panel-glue.c
+++ /dev/null
@@ -1,129 +0,0 @@
-/* $Id$ */
-/*
- * Copyright (C) 2008-2009 Nick Schermer <nick at xfce.org>
- *
- * 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
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-
-#include <exo/exo.h>
-#include <libxfce4util/libxfce4util.h>
-#include <libxfce4panel/libxfce4panel.h>
-#include <libxfce4panel/xfce-panel-plugin-provider.h>
-
-#include <panel/panel-glue.h>
-#include <panel/panel-item-dialog.h>
-#include <panel/panel-preferences-dialog.h>
-#include <panel/panel-dialogs.h>
-#include <panel/panel-dbus-service.h>
-#include <panel/panel-plugin-external.h>
-#include <panel/panel-window.h>
-
-
-
-
-XfceScreenPosition
-panel_glue_get_screen_position (PanelWindow *window)
-{
-  gboolean            horizontal;
-  PanelWindowSnapEdge snap_edge;
-
-  panel_return_val_if_fail (PANEL_IS_WINDOW (window), XFCE_SCREEN_POSITION_NONE);
-
-  g_object_get (G_OBJECT (window), "horizontal", &horizontal,
-                "snap-edge", &snap_edge, NULL);
-
-  /* return the screen position */
-  switch (snap_edge)
-    {
-      case PANEL_SNAP_EGDE_NONE:
-        return horizontal ? XFCE_SCREEN_POSITION_FLOATING_H :
-          XFCE_SCREEN_POSITION_FLOATING_V;
-
-      case PANEL_SNAP_EGDE_NW:
-        return horizontal ? XFCE_SCREEN_POSITION_NW_H :
-          XFCE_SCREEN_POSITION_NW_V;
-
-      case PANEL_SNAP_EGDE_NE:
-        return horizontal ? XFCE_SCREEN_POSITION_NE_H :
-          XFCE_SCREEN_POSITION_NE_V;
-
-      case PANEL_SNAP_EGDE_SW:
-        return horizontal ? XFCE_SCREEN_POSITION_SW_H :
-          XFCE_SCREEN_POSITION_SW_V;
-
-      case PANEL_SNAP_EGDE_SE:
-        return horizontal ? XFCE_SCREEN_POSITION_SE_H :
-          XFCE_SCREEN_POSITION_SE_V;
-
-      case PANEL_SNAP_EGDE_W:
-      case PANEL_SNAP_EGDE_WC:
-        return horizontal ? XFCE_SCREEN_POSITION_FLOATING_H :
-          XFCE_SCREEN_POSITION_W;
-
-      case PANEL_SNAP_EGDE_E:
-      case PANEL_SNAP_EGDE_EC:
-        return horizontal ? XFCE_SCREEN_POSITION_FLOATING_H :
-          XFCE_SCREEN_POSITION_E;
-
-      case PANEL_SNAP_EGDE_S:
-      case PANEL_SNAP_EGDE_SC:
-        return horizontal ? XFCE_SCREEN_POSITION_S :
-          XFCE_SCREEN_POSITION_FLOATING_V;
-
-      case PANEL_SNAP_EGDE_N:
-      case PANEL_SNAP_EGDE_NC:
-        return horizontal ? XFCE_SCREEN_POSITION_N :
-          XFCE_SCREEN_POSITION_FLOATING_V;
-    }
-
-  return XFCE_SCREEN_POSITION_NONE;
-}
-
-
-/* TODO move to window */
-void
-panel_glue_set_provider_info (XfcePanelPluginProvider *provider,
-                              PanelWindow             *window)
-{
-  guint    size;
-  gboolean horizontal;
-  guint    background_alpha;
-
-  panel_return_if_fail (XFCE_IS_PANEL_PLUGIN_PROVIDER (provider));
-  panel_return_if_fail (PANEL_IS_WINDOW (window));
-
-  /* read settings from the window */
-  g_object_get (G_OBJECT (window), "size", &size,
-                "horizontal", &horizontal, "background-alpha",
-                &background_alpha, NULL);
-
-  /* set the background alpha if the plugin is external */
-  if (PANEL_IS_PLUGIN_EXTERNAL (provider))
-    panel_plugin_external_set_background_alpha (PANEL_PLUGIN_EXTERNAL (provider), background_alpha);
-
-  /* send plugin information */
-  xfce_panel_plugin_provider_set_screen_position (provider, panel_glue_get_screen_position (window));
-  xfce_panel_plugin_provider_set_size (provider, size);
-  xfce_panel_plugin_provider_set_orientation (provider, horizontal ? GTK_ORIENTATION_HORIZONTAL
-                                              : GTK_ORIENTATION_VERTICAL);
-}
diff --git a/panel/panel-glue.h b/panel/panel-glue.h
deleted file mode 100644
index a32fc10..0000000
--- a/panel/panel-glue.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/* $Id$ */
-/*
- * Copyright (C) 2008-2009 Nick Schermer <nick at xfce.org>
- *
- * 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
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifndef __PANEL_GLUE_H__
-#define __PANEL_GLUE_H__
-
-#include <gtk/gtk.h>
-#include <panel/panel-window.h>
-#include <libxfce4panel/libxfce4panel.h>
-#include <libxfce4panel/xfce-panel-plugin-provider.h>
-
-G_BEGIN_DECLS
-
-XfceScreenPosition panel_glue_get_screen_position (PanelWindow *window);
-
-void               panel_glue_set_provider_info   (XfcePanelPluginProvider *provider,
-                                                   PanelWindow             *window);
-
-G_END_DECLS
-
-#endif /* !__PANEL_GLUE_H__ */
diff --git a/panel/panel-plugin-external.c b/panel/panel-plugin-external.c
index 3502387..a0b673a 100644
--- a/panel/panel-plugin-external.c
+++ b/panel/panel-plugin-external.c
@@ -32,7 +32,6 @@
 #include <panel/panel-module.h>
 #include <panel/panel-plugin-external.h>
 #include <panel/panel-window.h>
-#include <panel/panel-glue.h>
 #include <panel/panel-dbus-service.h>
 
 /* Number of automatic plugin restarts before the
@@ -361,7 +360,7 @@ panel_plugin_external_plug_removed (GtkSocket *socket)
       window = PANEL_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (socket)));
 
       /* send panel information to the plugin */
-      panel_glue_set_provider_info (XFCE_PANEL_PLUGIN_PROVIDER (external), window);
+      panel_window_set_povider_info (window, GTK_WIDGET (external));
 
       /* show the socket again (realize will spawn the plugin) */
       gtk_widget_show (GTK_WIDGET (socket));
diff --git a/panel/panel-preferences-dialog.c b/panel/panel-preferences-dialog.c
index 7e1a7f2..b3e3ab8 100644
--- a/panel/panel-preferences-dialog.c
+++ b/panel/panel-preferences-dialog.c
@@ -28,7 +28,6 @@
 #include <libxfce4panel/xfce-panel-plugin-provider.h>
 
 #include <panel/panel-window.h>
-#include <panel/panel-glue.h>
 #include <panel/panel-application.h>
 #include <panel/panel-module.h>
 #include <panel/panel-itembar.h>
@@ -302,12 +301,11 @@ panel_preferences_dialog_bindings_add (PanelPreferencesDialog *dialog,
 static void
 panel_preferences_dialog_bindings_update (PanelPreferencesDialog *dialog)
 {
-  panel_return_if_fail (G_IS_OBJECT (dialog->active));
-
   /* remove all the active bindings */
   panel_preferences_dialog_bindings_unbind (dialog);
 
   /* leave when there is no active panel */
+  panel_return_if_fail (G_IS_OBJECT (dialog->active));
   if (dialog->active == NULL)
     return;
 
@@ -320,6 +318,7 @@ panel_preferences_dialog_bindings_update (PanelPreferencesDialog *dialog)
   panel_preferences_dialog_bindings_add (dialog, "background-alpha", "value");
   panel_preferences_dialog_bindings_add (dialog, "enter-opacity", "value");
   panel_preferences_dialog_bindings_add (dialog, "leave-opacity", "value");
+  panel_preferences_dialog_bindings_add (dialog, "composited", "visible");
 }
 
 
@@ -380,7 +379,8 @@ panel_preferences_dialog_panel_combobox_rebuild (PanelPreferencesDialog *dialog)
   panel_return_if_fail (GTK_IS_COMBO_BOX (combo));
 
   /* block signal */
-  g_signal_handlers_block_by_func (combo, panel_preferences_dialog_panel_combobox_changed, dialog);
+  g_signal_handlers_block_by_func (combo, 
+      panel_preferences_dialog_panel_combobox_changed, dialog);
 
   /* empty the combo box */
   gtk_list_store_clear (GTK_LIST_STORE (store));
@@ -404,7 +404,8 @@ panel_preferences_dialog_panel_combobox_rebuild (PanelPreferencesDialog *dialog)
   gtk_widget_set_sensitive (GTK_WIDGET (object), !!(n_items > 1));
 
   /* unblock signal */
-  g_signal_handlers_unblock_by_func (combo, panel_preferences_dialog_panel_combobox_changed, dialog);
+  g_signal_handlers_unblock_by_func (combo, 
+      panel_preferences_dialog_panel_combobox_changed, dialog);
 }
 
 
diff --git a/panel/panel-preferences-dialog.glade b/panel/panel-preferences-dialog.glade
index eab25f4..c54f02f 100644
--- a/panel/panel-preferences-dialog.glade
+++ b/panel/panel-preferences-dialog.glade
@@ -311,7 +311,7 @@
                   </packing>
                 </child>
                 <child>
-                  <object class="GtkVBox" id="vbox4">
+                  <object class="GtkVBox" id="composited">
                     <property name="visible">True</property>
                     <property name="border_width">6</property>
                     <property name="spacing">6</property>
diff --git a/panel/panel-window.c b/panel/panel-window.c
index d0b442f..25a8867 100644
--- a/panel/panel-window.c
+++ b/panel/panel-window.c
@@ -1,6 +1,6 @@
 /* $Id$ */
 /*
- * Copyright (C) 2008-2009 Nick Schermer <nick at xfce.org>
+ * Copyright (C) 2009 Nick Schermer <nick at xfce.org>
  *
  * 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
@@ -21,63 +21,103 @@
 #include <config.h>
 #endif
 
+#ifdef HAVE_STDIO_H
+#include <stdio.h>
+#endif
 #ifdef HAVE_MATH_H
 #include <math.h>
 #endif
 
 #include <exo/exo.h>
-#include <libxfce4panel/libxfce4panel.h>
 #include <common/panel-private.h>
+#include <libxfce4panel/libxfce4panel.h>
+#include <libxfce4panel/xfce-panel-plugin-provider.h>
+#include <panel/panel-base-window.h>
 #include <panel/panel-window.h>
-#include <panel/panel-glue.h>
-#include <panel/panel-application.h>
-#include <panel/panel-plugin-external.h>
 #include <panel/panel-item-dialog.h>
 #include <panel/panel-preferences-dialog.h>
 #include <panel/panel-dialogs.h>
 #include <panel/panel-dbus-service.h>
+#include <panel/panel-plugin-external.h>
+
+
+
+#define SNAP_DISTANCE      (10)
+#define SET_OLD_WM_STRUTS  (FALSE)
+#define STRUTS_DEBUGGING   (FALSE)
+#define POPUP_DELAY        (225)
+#define POPDOWN_DELAY      (350)
+#define HANDLE_SPACING     (4)
+#define HANDLE_DOTS        (2)
+#define HANDLE_PIXELS      (2)
+#define HANDLE_PIXEL_SPACE (1)
+#define HANDLE_SIZE        (HANDLE_DOTS * (HANDLE_PIXELS + \
+                            HANDLE_PIXEL_SPACE) - HANDLE_PIXEL_SPACE)
+#define HANDLE_SIZE_TOTAL  (2 * HANDLE_SPACING + HANDLE_SIZE)
+
+
+
+typedef enum _StrutsEgde    StrutsEgde;
+typedef enum _AutohideState AutohideState;
+typedef enum _SnapPosition  SnapPosition;
+
+
+
+static void         panel_window_get_property           (GObject          *object,
+                                                         guint             prop_id,
+                                                         GValue           *value,
+                                                         GParamSpec       *pspec);
+static void         panel_window_set_property           (GObject          *object,
+                                                         guint             prop_id,
+                                                         const GValue     *value,
+                                                         GParamSpec       *pspec);
+static void         panel_window_finalize               (GObject          *object);
+static gboolean     panel_window_expose_event           (GtkWidget        *widget,
+                                                         GdkEventExpose   *event);
+static gboolean     panel_window_enter_notify_event     (GtkWidget        *widget,
+                                                         GdkEventCrossing *event);
+static gboolean     panel_window_leave_notify_event     (GtkWidget        *widget,
+                                                         GdkEventCrossing *event);
+static gboolean     panel_window_motion_notify_event    (GtkWidget        *widget,
+                                                         GdkEventMotion   *event);
+static gboolean     panel_window_button_press_event     (GtkWidget        *widget,
+                                                         GdkEventButton   *event);
+static gboolean     panel_window_button_release_event   (GtkWidget        *widget,
+                                                         GdkEventButton   *event);
+static void         panel_window_grab_notify            (GtkWidget        *widget,
+                                                         gboolean         was_grabbed);
+static void         panel_window_size_request           (GtkWidget        *widget,
+                                                         GtkRequisition   *requisition);
+static void         panel_window_size_allocate          (GtkWidget        *widget,
+                                                         GtkAllocation    *alloc);
+static void         panel_window_size_allocate_set_xy   (PanelWindow      *window,
+                                                         gint              window_width,
+                                                         gint              window_height,
+                                                         gint             *return_x,
+                                                         gint             *return_y);
+static void         panel_window_screen_changed         (GtkWidget        *widget,
+                                                         GdkScreen        *previous_screen);
+static StrutsEgde   panel_window_screen_struts_edge     (PanelWindow      *window);
+static void         panel_window_screen_struts_set      (PanelWindow      *window);
+static void         panel_window_screen_force_update    (PanelWindow      *window);
+static void         panel_window_screen_update_borders  (PanelWindow      *window);
+static SnapPosition panel_window_snap_position          (PanelWindow      *window);
+static void         panel_window_screen_layout_changed  (GdkScreen        *screen,
+                                                         PanelWindow      *window);
+static void         panel_window_autohide_queue         (PanelWindow      *window,
+                                                         AutohideState     new_state);
+static void         panel_window_set_autohide           (PanelWindow      *window,
+                                                         gboolean          autohide);
+static void         panel_window_menu_popup             (PanelWindow      *window,
+                                                         guint32           event_time);
+static void         panel_window_set_plugin_orientation (GtkWidget        *widget,
+                                                         gpointer          user_data);
+static void         panel_window_set_plugin_size        (GtkWidget        *widget,
+                                                         gpointer          user_data);
+static void         panel_window_set_screen_position    (GtkWidget        *widget,
+                                                         gpointer          user_data);
+
 
-#define HANDLE_SIZE       (8)
-#define HANDLE_SPACING    (2)
-#define HANDLE_SIZE_TOTAL ((HANDLE_SIZE + HANDLE_SPACING) * 2)
-#define SNAP_DISTANCE     (10)
-#define POPUP_DELAY       (225)
-#define POPDOWN_DELAY     (350)
-#define HIDDEN_PANEL_SIZE (2)
-#define OFFSCREEN         (-9999)
-
-
-
-static void panel_window_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
-static void panel_window_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
-static void panel_window_finalize (GObject *object);
-static void panel_window_realize (GtkWidget *widget);
-static gboolean panel_window_expose_event (GtkWidget *widget, GdkEventExpose *event);
-static gboolean panel_window_motion_notify (GtkWidget *widget, GdkEventMotion *event);
-static gboolean panel_window_button_press_event (GtkWidget *widget, GdkEventButton *event);
-static gboolean panel_window_button_release_event (GtkWidget *widget, GdkEventButton *event);
-static gboolean panel_window_enter_notify_event (GtkWidget *widget, GdkEventCrossing *event);
-static gboolean panel_window_leave_notify_event (GtkWidget *widget, GdkEventCrossing *event);
-static void panel_window_grab_notify (GtkWidget *widget, gboolean was_grabbed);
-static void panel_window_size_request (GtkWidget *widget, GtkRequisition *requisition);
-static void panel_window_size_allocate (GtkWidget *widget, GtkAllocation *allocation);
-static void panel_window_screen_changed (GtkWidget *widget, GdkScreen *previous_screen);
-static void panel_window_paint_handle (PanelWindow *window,  gboolean start, GtkStateType state, cairo_t *rc);
-static void panel_window_paint_borders (PanelWindow *window, GtkStateType state, cairo_t *rc);
-static void panel_window_calculate_position (PanelWindow *window, gint width, gint height, gint *x, gint *y);
-static void panel_window_working_area (PanelWindow  *window, gint root_x, gint root_y, GdkRectangle *dest);
-static gboolean panel_window_struts_are_possible (PanelWindow *window, gint x, gint y, gint width, gint height);
-static void panel_window_struts_update (PanelWindow  *window, gint x, gint y, gint width, gint height);
-static void panel_window_set_colormap (PanelWindow *window);
-static void panel_window_get_position (PanelWindow *window, gint *root_x, gint *root_y);
-static void panel_window_set_borders (PanelWindow *window);
-static void panel_window_set_autohide (PanelWindow *window, gboolean autohide);
-static void panel_window_menu_quit (gpointer boolean);
-static void panel_window_menu_deactivate (GtkMenu *menu, PanelWindow *window);
-static void panel_window_menu_popup (PanelWindow *window);
-static void panel_window_set_plugin_background_alpha (GtkWidget *widget, gpointer user_data);
-static void panel_window_set_plugin_size (GtkWidget *widget, gpointer user_data);
-static void panel_window_set_plugin_orientation (GtkWidget *widget, gpointer user_data);
 
 enum
 {
@@ -86,35 +126,62 @@ enum
   PROP_SIZE,
   PROP_LENGTH,
   PROP_LOCKED,
-  PROP_X_OFFSET,
-  PROP_Y_OFFSET,
-  PROP_ENTER_OPACITY,
-  PROP_LEAVE_OPACITY,
-  PROP_SNAP_EDGE,
-  PROP_BACKGROUND_ALPHA,
+  PROP_AUTOHIDE,
   PROP_SPAN_MONITORS,
-  PROP_AUTOHIDE
+  PROP_OUTPUT_NAME,
+  PROP_POSITION
+};
+
+enum _AutohideState
+{
+  AUTOHIDE_DISABLED = 0, /* autohide is disabled */
+  AUTOHIDE_VISIBLE,      /* visible */
+  AUTOHIDE_POPDOWN,      /* visible, but hide timeout is running */
+  AUTOHIDE_POPDOWN_SLOW, /* same as popdown, but timeout is 4x longer */
+  AUTOHIDE_HIDDEN,       /* invisible */
+  AUTOHIDE_POPUP         /* invisible, but show timeout is running */
+};
+
+enum _SnapPosition
+{
+  /* no snapping */
+  SNAP_POSITION_NONE, /* snapping */
+
+  /* right edge */
+  SNAP_POSITION_E,    /* right */
+  SNAP_POSITION_NE,   /* top right */
+  SNAP_POSITION_EC,   /* right center */
+  SNAP_POSITION_SE,   /* bottom right */
+
+  /* left edge */
+  SNAP_POSITION_W,    /* left */
+  SNAP_POSITION_NW,   /* top left */
+  SNAP_POSITION_WC,   /* left center */
+  SNAP_POSITION_SW,   /* bottom left */
+
+  /* top and bottom */
+  SNAP_POSITION_NC,   /* top center */
+  SNAP_POSITION_SC,   /* bottom center */
+  SNAP_POSITION_N,    /* top */
+  SNAP_POSITION_S,    /* bottom */
 };
 
 enum
 {
-  SNAP_NONE,
-  SNAP_START,
-  SNAP_CENTER,
-  SNAP_END
+  EDGE_GRAVITY_NONE   = 0,
+  EDGE_GRAVITY_START  = (SNAP_POSITION_NE - SNAP_POSITION_E),
+  EDGE_GRAVITY_CENTER = (SNAP_POSITION_EC - SNAP_POSITION_E),
+  EDGE_GRAVITY_END    = (SNAP_POSITION_SE - SNAP_POSITION_E)
 };
 
-typedef enum
+enum _StrutsEgde
 {
-  DISABLED,
-  BLOCKED,
-  VISIBLE,
-  POPUP_QUEUED,
-  HIDDEN,
-  POPDOWN_QUEUED,
-  POPDOWN_QUEUED_SLOW
-}
-AutohideStatus;
+  STRUTS_EDGE_NONE = 0,
+  STRUTS_EDGE_LEFT,
+  STRUTS_EDGE_RIGHT,
+  STRUTS_EDGE_TOP,
+  STRUTS_EDGE_BOTTOM
+};
 
 enum
 {
@@ -135,80 +202,62 @@ enum
 
 struct _PanelWindowClass
 {
-  GtkWindowClass __parent__;
+  PanelBaseWindowClass __parent__;
 };
 
 struct _PanelWindow
 {
-  GtkWindow __parent__;
-
-  /* last allocated size, for recentering */
-  GtkAllocation        prev_allocation;
-
-  /* snapping edge of the window */
-  PanelWindowSnapEdge  snap_edge;
-
-  /* the borders we're going to draw */
-  PanelWindowBorders   borders;
+  PanelBaseWindow      __parent__;
 
-  /* whether we should apply struts for this screen position */
-  gint                 struts_possible;
+  /* screen and working area of this panel */
+  GdkScreen           *screen;
+  GdkRectangle         area;
 
-  /* the last used struts for this window */
+  /* struts information */
+  StrutsEgde           struts_edge;
   gulong               struts[N_STRUTS];
 
-  /* the last calculated panel working area */
-  GdkRectangle         working_area;
-
-  /* whether we span monitors */
-  guint                span_monitors : 1;
-
-  /* whether the panel has a rgba colormap */
-  guint                is_composited : 1;
-
-  /* whether the panel is locked */
-  guint                locked : 1;
-
-  /* active panel redraw timeout id */
-  guint                active_timeout_id;
-
-  /* panel orientation */
-  guint                horizontal : 1;
-
-  /* panel size (px) and length (%) */
+  /* window positioning */
   guint                size;
   gdouble              length;
+  guint                horizontal : 1;
+  SnapPosition         snap_position;
+  guint                span_monitors : 1;
+  gchar               *output_name;
 
-  /* autohide */
-  AutohideStatus       autohide_status;
-  guint                autohide_timer;
-  gint                 autohide_block;
+  /* allocated position of the panel */
+  GdkRectangle         alloc;
 
-  /* the window we use to show during autohide */
+  /* autohiding */
   GtkWidget           *autohide_window;
+  AutohideState        autohide_state;
+  guint                autohide_timeout_id;
+  gint                 autohide_block;
 
-  /* background alpha */
-  gdouble              background_alpha;
+  /* whether the window is locked */
+  guint                locked : 1;
 
-  /* panel enter/leave opacity */
-  gdouble              enter_opacity;
-  gdouble              leave_opacity;
+  /* window base point */
+  gint                 base_x;
+  gint                 base_y;
 
-  /* variables for dragging the panel */
-  guint                drag_motion : 1;
-  gint                 drag_start_x;
-  gint                 drag_start_y;
+  /* window drag information */
+  guint32              grab_time;
+  gint                 grab_x;
+  gint                 grab_y;
 };
 
 
 
-static GdkAtom cardinal_atom = GDK_NONE;
-static GdkAtom net_wm_strut_atom = GDK_NONE;
-static GdkAtom net_wm_strut_partial_atom = GDK_NONE;
+static GdkAtom cardinal_atom = 0;
+#if SET_OLD_WM_STRUTS
+static GdkAtom net_wm_strut_atom = 0;
+#endif
+static GdkAtom net_wm_strut_partial_atom = 0;
 
 
 
-G_DEFINE_TYPE (PanelWindow, panel_window, GTK_TYPE_WINDOW);
+G_DEFINE_TYPE (PanelWindow, panel_window, PANEL_TYPE_BASE_WINDOW)
 
 
 
@@ -224,13 +273,12 @@ panel_window_class_init (PanelWindowClass *klass)
   gobject_class->finalize = panel_window_finalize;
 
   gtkwidget_class = GTK_WIDGET_CLASS (klass);
-  gtkwidget_class->realize = panel_window_realize;
   gtkwidget_class->expose_event = panel_window_expose_event;
-  gtkwidget_class->motion_notify_event = panel_window_motion_notify;
-  gtkwidget_class->button_press_event = panel_window_button_press_event;
-  gtkwidget_class->button_release_event = panel_window_button_release_event;
   gtkwidget_class->enter_notify_event = panel_window_enter_notify_event;
   gtkwidget_class->leave_notify_event = panel_window_leave_notify_event;
+  gtkwidget_class->motion_notify_event = panel_window_motion_notify_event;
+  gtkwidget_class->button_press_event = panel_window_button_press_event;
+  gtkwidget_class->button_release_event = panel_window_button_release_event;
   gtkwidget_class->grab_notify = panel_window_grab_notify;
   gtkwidget_class->size_request = panel_window_size_request;
   gtkwidget_class->size_allocate = panel_window_size_allocate;
@@ -261,36 +309,6 @@ panel_window_class_init (PanelWindowClass *klass)
                                                          EXO_PARAM_READWRITE));
 
   g_object_class_install_property (gobject_class,
-                                   PROP_X_OFFSET,
-                                   g_param_spec_uint ("x-offset", NULL, NULL,
-                                                      0, G_MAXUINT, 0,
-                                                      EXO_PARAM_READWRITE));
-
-  g_object_class_install_property (gobject_class,
-                                   PROP_Y_OFFSET,
-                                   g_param_spec_uint ("y-offset", NULL, NULL,
-                                                      0, G_MAXUINT, 0,
-                                                      EXO_PARAM_READWRITE));
-
-  g_object_class_install_property (gobject_class,
-                                   PROP_ENTER_OPACITY,
-                                   g_param_spec_uint ("enter-opacity", NULL, NULL,
-                                                      0, 100, 100,
-                                                      EXO_PARAM_READWRITE));
-
-  g_object_class_install_property (gobject_class,
-                                   PROP_LEAVE_OPACITY,
-                                   g_param_spec_uint ("leave-opacity", NULL, NULL,
-                                                      0, 100, 100,
-                                                      EXO_PARAM_READWRITE));
-
-  g_object_class_install_property (gobject_class,
-                                   PROP_BACKGROUND_ALPHA,
-                                   g_param_spec_uint ("background-alpha", NULL, NULL,
-                                                      0, 100, 100,
-                                                      EXO_PARAM_READWRITE));
-
-  g_object_class_install_property (gobject_class,
                                    PROP_AUTOHIDE,
                                    g_param_spec_boolean ("autohide", NULL, NULL,
                                                          FALSE,
@@ -303,17 +321,23 @@ panel_window_class_init (PanelWindowClass *klass)
                                                          EXO_PARAM_READWRITE));
 
   g_object_class_install_property (gobject_class,
-                                   PROP_SNAP_EDGE,
-                                   g_param_spec_uint ("snap-edge", NULL, NULL,
-                                                      PANEL_SNAP_EGDE_NONE,
-                                                      PANEL_SNAP_EGDE_S,
-                                                      PANEL_SNAP_EGDE_NONE,
-                                                      EXO_PARAM_READWRITE));
+                                   PROP_OUTPUT_NAME,
+                                   g_param_spec_string ("output-name", NULL, NULL,
+                                                        NULL,
+                                                        EXO_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_POSITION,
+                                   g_param_spec_string ("position", NULL, NULL,
+                                                        NULL,
+                                                        EXO_PARAM_READWRITE));
 
   /* initialize the atoms */
   cardinal_atom = gdk_atom_intern_static_string ("CARDINAL");
-  net_wm_strut_atom = gdk_atom_intern_static_string ("_NET_WM_STRUT");
   net_wm_strut_partial_atom = gdk_atom_intern_static_string ("_NET_WM_STRUT_PARTIAL");
+#if SET_OLD_WM_STRUTS
+  net_wm_strut_atom = gdk_atom_intern_static_string ("_NET_WM_STRUT");
+#endif
 }
 
 
@@ -321,50 +345,41 @@ panel_window_class_init (PanelWindowClass *klass)
 static void
 panel_window_init (PanelWindow *window)
 {
-  GdkScreen *screen;
-
-  /* set window properties */
+  /* no resizable, so allocation will follow size request */
   gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
-  gtk_window_set_decorated (GTK_WINDOW (window), FALSE);
-  gtk_window_set_type_hint (GTK_WINDOW (window), GDK_WINDOW_TYPE_HINT_DOCK);
-  gtk_window_set_gravity (GTK_WINDOW (window), GDK_GRAVITY_STATIC);
+
+  /* set additional events */
+  gtk_widget_add_events (GTK_WIDGET (window), GDK_BUTTON_PRESS_MASK);
 
   /* init vars */
-  window->is_composited = FALSE;
-  window->drag_motion = FALSE;
-  window->struts_possible = -1;
-  window->size = 48;
-  window->snap_edge = PANEL_SNAP_EGDE_NONE;
-  window->borders = 0;
-  window->span_monitors = FALSE;
-  window->length = 0.25;
+  window->screen = NULL;
+  window->struts_edge = STRUTS_EDGE_NONE;
+
   window->horizontal = TRUE;
-  window->background_alpha = 1.00;
-  window->enter_opacity = 1.00;
-  window->leave_opacity = 1.00;
-  window->autohide_timer = 0;
-  window->autohide_status = DISABLED;
-  window->autohide_block = 0;
-  window->autohide_window = NULL;
-  window->active_timeout_id = 0;
+  window->size = 30;
+  window->length = 0.10;
+  window->snap_position = SNAP_POSITION_NONE;
+  window->span_monitors = FALSE;
 
-  /* set additional events we want to have */
-  gtk_widget_add_events (GTK_WIDGET (window), GDK_BUTTON_PRESS_MASK);
+  window->locked = FALSE;
+
+  window->autohide_state = AUTOHIDE_DISABLED;
+  window->autohide_timeout_id = 0;
+  window->autohide_block = 0;
 
-  /* connect signal to monitor the compositor changes */
-  g_signal_connect (G_OBJECT (window), "composited-changed", G_CALLBACK (panel_window_set_colormap), NULL);
+  window->base_x = 100;
+  window->base_y = 100;
 
-  /* set the colormap */
-  panel_window_set_colormap (window);
+  window->grab_time = 0;
+  window->grab_x = 0;
+  window->grab_y = 0;
 
-  /* get the window screen */
-  screen = gtk_window_get_screen (GTK_WINDOW (window));
+  /* set the screen */
+  panel_window_screen_changed (GTK_WIDGET (window), NULL);
 
-  /* connect screen update signals */
-  g_signal_connect_swapped (G_OBJECT (screen), "size-changed", G_CALLBACK (panel_window_screen_changed), window);
-#if GTK_CHECK_VERSION (2,14,0)
-  g_signal_connect_swapped (G_OBJECT (screen), "monitors-changed", G_CALLBACK (panel_window_screen_changed), window);
-#endif
+  /* watch changes in the compositing */
+  g_signal_connect (G_OBJECT (window), "notify::composited",
+      G_CALLBACK (panel_window_screen_force_update), NULL);
 }
 
 
@@ -376,7 +391,7 @@ panel_window_get_property (GObject    *object,
                            GParamSpec *pspec)
 {
   PanelWindow *window = PANEL_WINDOW (object);
-  //gint         pos;
+  gchar       *position;
 
   switch (prop_id)
     {
@@ -396,40 +411,24 @@ panel_window_get_property (GObject    *object,
         g_value_set_boolean (value, window->locked);
         break;
 
-      case PROP_X_OFFSET:
-        //panel_window_get_position (window, &pos, NULL);
-        //g_value_set_uint (value, pos);
-        g_value_set_uint (value, 0);
-        break;
-
-      case PROP_Y_OFFSET:
-        //panel_window_get_position (window, NULL, &pos);
-        //g_value_set_uint (value, pos);
-        g_value_set_uint (value, 0);
-        break;
-
-      case PROP_ENTER_OPACITY:
-        g_value_set_uint (value, rint (window->enter_opacity * 100.00));
-        break;
-
-      case PROP_LEAVE_OPACITY:
-        g_value_set_uint (value, rint (window->leave_opacity * 100.00));
-        break;
-
-      case PROP_BACKGROUND_ALPHA:
-        g_value_set_uint (value, rint (window->background_alpha * 100.00));
-        break;
-
-      case PROP_SNAP_EDGE:
-        g_value_set_uint (value, window->snap_edge);
+      case PROP_AUTOHIDE:
+        g_value_set_boolean (value, !!(window->autohide_state != AUTOHIDE_DISABLED));
         break;
 
       case PROP_SPAN_MONITORS:
         g_value_set_boolean (value, window->span_monitors);
         break;
 
-      case PROP_AUTOHIDE:
-        g_value_set_boolean (value, !!(window->autohide_status != DISABLED));
+      case PROP_OUTPUT_NAME:
+        g_value_set_static_string (value, window->output_name);
+        break;
+
+      case PROP_POSITION:
+        position = g_strdup_printf ("p=%d;x=%d;y=%d",
+                                    window->snap_position,
+                                    window->base_x,
+                                    window->base_y);
+        g_value_take_string (value, position);
         break;
 
       default:
@@ -447,116 +446,107 @@ panel_window_set_property (GObject      *object,
                            GParamSpec   *pspec)
 {
   PanelWindow *window = PANEL_WINDOW (object);
-  //gint         pos;
+  gboolean     val_bool;
+  guint        val_uint;
+  gdouble      val_double;
+  const gchar *val_string;
+  gboolean     update = FALSE;
+  gint         x, y, snap_position;
+  GtkWidget   *itembar;
 
   switch (prop_id)
     {
       case PROP_HORIZONTAL:
-        /* set whether the panel */
-        window->horizontal = g_value_get_boolean (value);
-
-        /* update all the panel plugins */
-        gtk_container_foreach (GTK_CONTAINER (gtk_bin_get_child (GTK_BIN (window))),
-                               panel_window_set_plugin_orientation,
-                               GUINT_TO_POINTER (window->horizontal ? GTK_ORIENTATION_HORIZONTAL:
-                                                 GTK_ORIENTATION_VERTICAL));
-
-        /* queue a resize */
-        gtk_widget_queue_resize (GTK_WIDGET (window));
+        val_bool = g_value_get_boolean (value);
+        if (window->horizontal != val_bool)
+          {
+            window->horizontal = !!val_bool;
+            panel_window_screen_layout_changed (window->screen, window);
+          }
+
+        /* send the new orientation to the panel plugins */
+        itembar = gtk_bin_get_child (GTK_BIN (window));
+        gtk_container_foreach (GTK_CONTAINER (itembar),
+            panel_window_set_plugin_orientation, window);
         break;
 
       case PROP_SIZE:
-        /* update the panel size */
-        window->size = g_value_get_uint (value);
-
-        /* update all the panel plugins */
-        gtk_container_foreach (GTK_CONTAINER (gtk_bin_get_child (GTK_BIN (window))),
-                               panel_window_set_plugin_size,
-                               GUINT_TO_POINTER (window->size));
-
-        /* queue a resize */
-        gtk_widget_queue_resize (GTK_WIDGET (window));
+        val_uint = g_value_get_uint (value);
+        if (window->size != val_uint)
+          {
+            window->size = val_uint;
+            gtk_widget_queue_resize (GTK_WIDGET (window));
+          }
+
+        /* send the new size to the panel plugins */
+        itembar = gtk_bin_get_child (GTK_BIN (window));
+        gtk_container_foreach (GTK_CONTAINER (itembar),
+            panel_window_set_plugin_size, window);
         break;
 
       case PROP_LENGTH:
-        /* set the new length */
-        window->length = g_value_get_uint (value) / 100.00;
-
-        /* update the border and resize */
-        panel_window_set_borders (window);
-        gtk_widget_queue_resize (GTK_WIDGET (window));
-        break;
-
-      case PROP_LOCKED:
-        /* set new lock value and resize */
-        window->locked = g_value_get_boolean (value);
-        gtk_widget_queue_resize (GTK_WIDGET (window));
-        break;
-
-      case PROP_X_OFFSET:
-        /* get window position */
-        //gtk_window_get_position (GTK_WINDOW (window), NULL, &pos);
-        //gtk_window_move (GTK_WINDOW (window), g_value_get_uint (value), pos);
-        break;
-
-      case PROP_Y_OFFSET:
-        /* get window position */
-        //gtk_window_get_position (GTK_WINDOW (window), &pos, NULL);
-        //gtk_window_move (GTK_WINDOW (window), pos, g_value_get_uint (value));
-        break;
-
-      case PROP_ENTER_OPACITY:
-        /* set the new enter opacity */
-        window->enter_opacity = g_value_get_uint (value) / 100.00;
-        break;
+        val_double = g_value_get_uint (value) / 100.00;
+        if (window->length != val_double)
+          {
+            if (window->length == 1.00 || val_double == 1.00)
+              update = TRUE;
 
-      case PROP_LEAVE_OPACITY:
-        /* set the new leave opacity */
-        window->leave_opacity = g_value_get_uint (value) / 100.00;
+            window->length = val_double;
 
-        /* set the autohide window opacity if created */
-        if (window->autohide_window)
-          gtk_window_set_opacity (GTK_WINDOW (window->autohide_window), window->leave_opacity);
+            if (update)
+              panel_window_screen_update_borders (window);
 
-        /* update the panel window opacity */
-        gtk_window_set_opacity (GTK_WINDOW (window), window->leave_opacity);
+            gtk_widget_queue_resize (GTK_WIDGET (window));
+          }
         break;
 
-      case PROP_BACKGROUND_ALPHA:
-        /* set the new value and redraw the panel */
-        window->background_alpha = g_value_get_uint (value) / 100.00;
-        gtk_widget_queue_draw (GTK_WIDGET (window));
-
-        /* update the external plugins */
-        gtk_container_foreach (GTK_CONTAINER (gtk_bin_get_child (GTK_BIN (window))),
-                               panel_window_set_plugin_background_alpha,
-                               GUINT_TO_POINTER (g_value_get_uint (value)));
+      case PROP_LOCKED:
+        val_bool = g_value_get_boolean (value);
+        if (window->locked != val_bool)
+          {
+            window->locked = !!val_bool;
+            gtk_widget_queue_resize (GTK_WIDGET (window));
+          }
         break;
 
-      case PROP_SNAP_EDGE:
-        /* set snap edge value */
-        window->snap_edge = g_value_get_uint (value);
-
-        /* update the window borders */
-        panel_window_set_borders (window);
-
-        /* queue a resize */
-        gtk_widget_queue_resize (GTK_WIDGET (window));
+      case PROP_AUTOHIDE:
+        panel_window_set_autohide (window, g_value_get_boolean (value));
         break;
 
       case PROP_SPAN_MONITORS:
-        /* store new value */
-        window->span_monitors = g_value_get_boolean (value);
-
-        /* update the working area */
-        panel_window_working_area (window, -1, -1, &window->working_area);
+        val_bool = g_value_get_boolean (value);
+        if (window->span_monitors == val_bool)
+          {
+            window->span_monitors = !!val_bool;
+            panel_window_screen_layout_changed (window->screen, window);
+          }
+        break;
 
-        /* resize the panel */
-        gtk_widget_queue_resize (GTK_WIDGET (window));
+      case PROP_OUTPUT_NAME:
+        g_free (window->output_name);
+        window->output_name = g_value_dup_string (value);
+        panel_window_screen_layout_changed (window->screen, window);
         break;
 
-      case PROP_AUTOHIDE:
-        panel_window_set_autohide (window, g_value_get_boolean (value));
+      case PROP_POSITION:
+        val_string = g_value_get_string (value);
+        if (sscanf (val_string, "p=%d;x=%d;y=%d", &snap_position, &x, &y) == 3)
+          {
+            window->snap_position = CLAMP (snap_position, SNAP_POSITION_NONE, SNAP_POSITION_S);
+            window->base_x = x;
+            window->base_y = y;
+
+            panel_window_screen_layout_changed (window->screen, window);
+
+            /* send the new screen position to the panel plugins */
+            itembar = gtk_bin_get_child (GTK_BIN (window));
+            gtk_container_foreach (GTK_CONTAINER (itembar),
+                panel_window_set_screen_position, window);
+          }
+        else
+          {
+            g_message ("no valid position defined");
+          }
         break;
 
       default:
@@ -572,31 +562,18 @@ panel_window_finalize (GObject *object)
 {
   PanelWindow *window = PANEL_WINDOW (object);
 
-  /* stop a running active timeout id */
-  if (window->active_timeout_id != 0)
-    g_source_remove (window->active_timeout_id);
-
-  /* stop the autohide timeout */
-  if (window->autohide_timer != 0)
-    g_source_remove (window->autohide_timer);
+  /* stop running autohide timeout */
+  if (G_UNLIKELY (window->autohide_timeout_id != 0))
+    g_source_remove (window->autohide_timeout_id);
 
-  /* destroy autohide window */
+  /* destroy the autohide window */
   if (window->autohide_window != NULL)
     gtk_widget_destroy (window->autohide_window);
 
-  (*G_OBJECT_CLASS (panel_window_parent_class)->finalize) (object);
-}
-
+  /* cleanup */
+  g_free (window->output_name);
 
-
-static void
-panel_window_realize (GtkWidget *widget)
-{
-  /* realize the window */
-  (*GTK_WIDGET_CLASS (panel_window_parent_class)->realize) (widget);
-
-  /* initialize the working area */
-  panel_window_working_area (PANEL_WINDOW (widget), -1, -1, &PANEL_WINDOW (widget)->working_area);
+  (*G_OBJECT_CLASS (panel_window_parent_class)->finalize) (object);
 }
 
 
@@ -608,182 +585,90 @@ panel_window_expose_event (GtkWidget      *widget,
   PanelWindow  *window = PANEL_WINDOW (widget);
   cairo_t      *cr;
   GdkColor     *color;
-  GtkStateType  state = GTK_STATE_NORMAL;
-  gdouble       alpha = window->is_composited ? window->background_alpha : 1.00;
+  guint         xx, yy, i;
+  gint          xs, xe, ys, ye;
+  gint          handle_w, handle_h;
+  gdouble       alpha = 1.00;
+  GtkWidget    *child;
 
-  if (GTK_WIDGET_DRAWABLE (widget))
-    {
-      /* create cairo context */
-      cr = gdk_cairo_create (widget->window);
-
-      /* clip the drawing area */
-      gdk_cairo_rectangle (cr, &event->area);
-      cairo_clip (cr);
-
-      if (alpha < 1.00 || window->active_timeout_id != 0)
-        {
-          /* get the background gdk color */
-          color = &(widget->style->bg[state]);
-
-          /* set the cairo source color */
-          xfce_panel_cairo_set_source_rgba (cr, color, alpha);
+  /* expose the background and borders */
+  (*GTK_WIDGET_CLASS (panel_window_parent_class)->expose_event) (widget, event);
 
-          /* create retangle */
-          cairo_rectangle (cr, event->area.x, event->area.y,
-                           event->area.width, event->area.height);
+  if (window->locked || !GTK_WIDGET_DRAWABLE (widget))
+    goto end;
 
-          /* draw on source */
-          cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
-
-          /* paint rectangle */
-          cairo_fill (cr);
-        }
-
-      /* paint handles */
-      if (window->locked == FALSE)
-        {
-          panel_window_paint_handle (window, TRUE, state, cr);
-          panel_window_paint_handle (window, FALSE, state, cr);
-        }
+  if (window->horizontal)
+    {
+      handle_h = window->alloc.height / 2;
+      handle_w = HANDLE_SIZE;
 
-      /* paint the panel borders */
-      panel_window_paint_borders (window, state, cr);
+      xs = HANDLE_SPACING + 1;
+      xe = window->alloc.width - HANDLE_SIZE - HANDLE_SIZE;
+      ys = ye = (window->alloc.height - handle_h) / 2;
 
-      /* destroy cairo context */
-      cairo_destroy (cr);
+      /* dirty check if we have to redraw the handles */
+      if (event->area.x > xs + HANDLE_SIZE
+          && event->area.x + event->area.width < xe)
+        goto end;
     }
-
-  /* send expose event to child too */
-  if (GTK_BIN (widget)->child)
-    gtk_container_propagate_expose (GTK_CONTAINER (widget), GTK_BIN (widget)->child, event);
-
-  return FALSE;
-}
-
-
-
-static guint
-panel_window_motion_notify_snap (gint  value,
-                                 gint  length,
-                                 gint  start,
-                                 gint  end,
-                                 gint *return_value)
-{
-  gint tmp;
-
-  /* snap in the center */
-  tmp = start + ((end - start) - length) / 2;
-  if (value >= tmp - SNAP_DISTANCE && value <= tmp + SNAP_DISTANCE)
+  else
     {
-      *return_value = tmp;
-      return SNAP_CENTER;
-    }
+      handle_h = HANDLE_SIZE;
+      handle_w = window->alloc.width / 2;
 
-  /* snap on the start */
-  if (value >= start && value <= start + SNAP_DISTANCE)
-    {
-      *return_value = start;
-      return SNAP_START;
-    }
+      xs = xe = (window->alloc.width - handle_w) / 2;
+      ys = HANDLE_SPACING + 1;
+      ye = window->alloc.height - HANDLE_SIZE - HANDLE_SIZE;
 
-  /* snap on the end */
-  tmp = end - length;
-  if (value >= tmp - SNAP_DISTANCE && value <= tmp)
-    {
-      *return_value = tmp;
-      return SNAP_END;
+      /* dirty check if we have to redraw the handles */
+      if (event->area.y > ys + HANDLE_SIZE
+          && event->area.y + event->area.height < ye)
+        goto end;
     }
 
-  /* set value as return value */
-  *return_value = value;
-
-  return SNAP_NONE;
-}
-
+  /* create cairo context and set some default properties */
+  cr = gdk_cairo_create (widget->window);
+  panel_return_val_if_fail (cr != NULL, FALSE);
+  cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
+  cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
 
+  /* clip the drawing area */
+  gdk_cairo_rectangle (cr, &event->area);
+  cairo_clip (cr);
 
-static gboolean
-panel_window_motion_notify (GtkWidget      *widget,
-                            GdkEventMotion *event)
-{
-  PanelWindow         *window = PANEL_WINDOW (widget);
-  gint                 clamp_x, clamp_y;
-  gint                 window_width, window_height;
-  gint                 window_x, window_y;
-  GdkRectangle         area;
-  gint                 snap_x, snap_y;
-  guint                snap_horizontal;
-  guint                snap_vertical;
-  PanelWindowSnapEdge  snap_edge = PANEL_SNAP_EGDE_NONE;
+  /* alpha color */
+  if (PANEL_BASE_WINDOW (window)->is_composited)
+    alpha = MAX (0.50, PANEL_BASE_WINDOW (window)->background_alpha);
 
-  if (window->drag_motion)
+  for (i = HANDLE_PIXELS; i >= HANDLE_PIXELS - 1; i--)
     {
-      /* get the pointer position */
-      window_x = event->x_root;
-      window_y = event->y_root;
-
-      /* get the maximum panel area on this coordinate */
-      panel_window_working_area (window, window_x, window_y, &area);
-
-      /* convert to corner offset */
-      window_x -= window->drag_start_x;
-      window_y -= window->drag_start_y;
-
-      /* get allocated window size, but make sure it fits in the maximum area */
-      window_width = MIN (widget->allocation.width, area.width);
-      window_height = MIN (widget->allocation.height, area.height);
-
-      /* keep the panel inside the maximum area */
-      clamp_x = CLAMP (window_x, area.x, area.x + area.width - window_width);
-      clamp_y = CLAMP (window_y, area.y, area.y + area.height - window_height);
-
-      /* update the drag coordinates, so dragging feels responsive when the user hits a screen edge */
-      window->drag_start_x += window_x - clamp_x;
-      window->drag_start_y += window_y - clamp_y;
-
-      /* try to find snapping edges */
-      snap_horizontal = panel_window_motion_notify_snap (clamp_x, window_width, area.x, area.x + area.width, &snap_x);
-      snap_vertical = panel_window_motion_notify_snap (clamp_y, window_height, area.y, area.y + area.height, &snap_y);
-
-      /* detect the snap mode */
-      if (snap_horizontal == SNAP_START)
-        snap_edge = PANEL_SNAP_EGDE_W + snap_vertical;
-      else if (snap_horizontal == SNAP_END)
-        snap_edge = PANEL_SNAP_EGDE_E + snap_vertical;
-      else if (snap_horizontal == SNAP_CENTER && snap_vertical == SNAP_START)
-        snap_edge = PANEL_SNAP_EGDE_NC;
-      else if (snap_horizontal == SNAP_CENTER && snap_vertical == SNAP_END)
-        snap_edge = PANEL_SNAP_EGDE_SC;
-      else if (snap_horizontal == SNAP_NONE && snap_vertical == SNAP_START)
-        snap_edge = PANEL_SNAP_EGDE_N;
-      else if (snap_horizontal == SNAP_NONE && snap_vertical == SNAP_END)
-        snap_edge = PANEL_SNAP_EGDE_S;
-
-      /* when snapping succeeded, set the snap coordinates for visual feedback */
-      if (snap_edge != PANEL_SNAP_EGDE_NONE)
-        {
-          clamp_x = snap_x;
-          clamp_y = snap_y;
-        }
-
-      /* move and resize the window */
-      gdk_window_move_resize (widget->window, clamp_x, clamp_y, window_width, window_height);
+      /* set the source color */
+      if (i == HANDLE_PIXELS)
+        color = &(widget->style->light[GTK_STATE_NORMAL]);
+      else
+        color = &(widget->style->dark[GTK_STATE_NORMAL]);
+      panel_util_set_source_rgba (cr, color, alpha);
 
-      /* if the snap edge changed, update the border */
-      if (window->snap_edge != snap_edge)
-        {
-          /* set the new value */
-          window->snap_edge = snap_edge;
+      /* draw the dots */
+      for (xx = 0; xx < (guint) handle_w; xx += HANDLE_PIXELS + HANDLE_PIXEL_SPACE)
+        for (yy = 0; yy < (guint) handle_h; yy += HANDLE_PIXELS + HANDLE_PIXEL_SPACE)
+          {
+            cairo_rectangle (cr, xs + xx, ys + yy, i, i);
+            cairo_rectangle (cr, xe + xx, ye + yy, i, i);
+          }
 
-          /* notify the property */
-          g_object_notify (G_OBJECT (window), "snap-edge");
+      /* fill the rectangles */
+      cairo_fill (cr);
+    }
 
-          /* update the borders */
-          panel_window_set_borders (window);
-        }
+  /* destroy cairo context */
+  cairo_destroy (cr);
 
-      return TRUE;
-    }
+end:
+  /* send the expose event to the child */
+  child = gtk_bin_get_child (GTK_BIN (widget));
+  if (G_LIKELY (child != NULL))
+    gtk_container_propagate_expose (GTK_CONTAINER (widget), child, event);
 
   return FALSE;
 }
@@ -791,234 +676,163 @@ panel_window_motion_notify (GtkWidget      *widget,
 
 
 static gboolean
-panel_window_button_press_event (GtkWidget      *widget,
-                                 GdkEventButton *event)
+panel_window_enter_notify_event (GtkWidget        *widget,
+                                 GdkEventCrossing *event)
 {
   PanelWindow *window = PANEL_WINDOW (widget);
-  GdkCursor   *cursor;
-  guint        modifiers;
-
-  /* get the modifiers */
-  modifiers = event->state & gtk_accelerator_get_default_mod_mask ();
-
-  if (event->button == 1
-      && event->window == widget->window
-      && window->locked == FALSE
-      && modifiers == 0)
-    {
-      /* set initial start coordinates */
-      window->drag_start_x = event->x;
-      window->drag_start_y = event->y;
-
-      /* create a moving cursor */
-      cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget), GDK_FLEUR);
-
-      /* try to drab the pointer */
-      window->drag_motion = (gdk_pointer_grab (widget->window, FALSE,
-                                               GDK_BUTTON_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
-                                               NULL, cursor, event->time) == GDK_GRAB_SUCCESS);
-
-      /* release the cursor */
-      gdk_cursor_unref (cursor);
 
-      return TRUE;
-    }
-  else if (event->button == 3 || (event->button == 1 && modifiers == GDK_CONTROL_MASK))
+  /* update autohide status */
+  if (event->detail != GDK_NOTIFY_INFERIOR
+      && window->autohide_state != AUTOHIDE_DISABLED)
     {
-      /* popup the panel menu */
-      panel_window_menu_popup (window);
+      /* stop a running autohide timeout */
+      if (window->autohide_timeout_id != 0)
+        g_source_remove (window->autohide_timeout_id);
 
-      return TRUE;
+      /* update autohide status */
+      if (window->autohide_state == AUTOHIDE_POPDOWN)
+        window->autohide_state = AUTOHIDE_VISIBLE;
     }
 
-  return FALSE;
+  return (*GTK_WIDGET_CLASS (panel_window_parent_class)->enter_notify_event) (widget, event);
 }
 
 
 
 static gboolean
-panel_window_button_release_event (GtkWidget      *widget,
-                                   GdkEventButton *event)
+panel_window_leave_notify_event (GtkWidget        *widget,
+                                 GdkEventCrossing *event)
 {
   PanelWindow *window = PANEL_WINDOW (widget);
 
-  if (window->drag_motion)
-    {
-      /* unset the drag */
-      window->drag_motion = FALSE;
-
-      /* release the pointer */
-      gdk_pointer_ungrab (event->time);
-
-      /* update the borders */
-      panel_window_set_borders (window);
-
-      /* update working area, struts and reallocate */
-      panel_window_screen_changed (widget, gtk_window_get_screen (GTK_WINDOW (widget)));
-
-      /* update the plugins */
-      /* TODO panel function for this */
-
-      return TRUE;
-    }
+  /* queue a new autohide time if needed */
+  if (event->detail != GDK_NOTIFY_INFERIOR
+      && window->autohide_state != AUTOHIDE_DISABLED)
+    panel_window_autohide_queue (window, AUTOHIDE_POPDOWN);
 
-  return FALSE;
+  return (*GTK_WIDGET_CLASS (panel_window_parent_class)->leave_notify_event) (widget, event);
 }
 
 
 
 static gboolean
-panel_window_autohide_timeout (gpointer user_data)
-{
-  PanelWindow *window = PANEL_WINDOW (user_data);
-
-  panel_return_val_if_fail (window->autohide_status != DISABLED
-                            && window->autohide_status != BLOCKED, FALSE);
-
-  /* change status */
-  if (window->autohide_status == POPDOWN_QUEUED || window->autohide_status == POPDOWN_QUEUED_SLOW)
-    window->autohide_status = HIDDEN;
-  else if (window->autohide_status == POPUP_QUEUED)
-    window->autohide_status = VISIBLE;
-
-  gtk_widget_queue_resize (GTK_WIDGET (window));
-
-  return FALSE;
-}
-
-
-
-static void
-panel_window_autohide_timeout_destroy (gpointer user_data)
-{
-  PANEL_WINDOW (user_data)->autohide_timer = 0;
-}
-
-
-
-static void
-panel_window_autohide_queue (PanelWindow    *window,
-                             AutohideStatus  status)
+panel_window_motion_notify_event (GtkWidget      *widget,
+                                  GdkEventMotion *event)
 {
-  guint delay;
-
-  panel_return_if_fail (PANEL_IS_WINDOW (window));
+  PanelWindow  *window = PANEL_WINDOW (widget);
+  gint          pointer_x, pointer_y;
+  gint          window_x, window_y;
+  gint          high;
 
-  /* stop a running autohide timeout */
-  if (window->autohide_timer != 0)
-    g_source_remove (window->autohide_timer);
+  /* leave when the pointer is not grabbed */
+  if (G_UNLIKELY (window->grab_time == 0))
+    return FALSE;
 
-  /* set new autohide status */
-  window->autohide_status = status;
+  /* get the pointer position from the event */
+  pointer_x = event->x_root;
+  pointer_y = event->y_root;
 
-  /* leave when the autohide is disabled */
-  if (status == DISABLED || status == BLOCKED)
-    {
-      /* queue a resize to make sure everything is visible */
-      gtk_widget_queue_resize (GTK_WIDGET (window));
-    }
-  else
+  /* check if the pointer moved to another monitor */
+  if (window->span_monitors == FALSE
+      && (pointer_x < window->area.x
+          || pointer_y < window->area.y
+          || pointer_x > window->area.x + window->area.width
+          || pointer_y > window->area.y + window->area.height))
     {
-      /* get the delay */
-      if (status == POPDOWN_QUEUED)
-        delay = POPDOWN_DELAY;
-      else if (status == POPDOWN_QUEUED_SLOW)
-        delay = POPDOWN_DELAY * 3;
-      else
-        delay = POPUP_DELAY;
-
-      /* schedule a new timeout */
-      window->autohide_timer = g_timeout_add_full (G_PRIORITY_LOW, delay,
-                                                   panel_window_autohide_timeout, window,
-                                                   panel_window_autohide_timeout_destroy);
+      /* set base point to cursor position and update working area */
+      window->base_x = pointer_x;
+      window->base_y = pointer_y;
+      panel_window_screen_layout_changed (window->screen, window);
     }
-}
-
-
-
-static gboolean
-panel_window_autohide_enter_notify_event (GtkWidget        *widget,
-                                          GdkEventCrossing *event,
-                                          PanelWindow      *window)
-{
-  panel_return_val_if_fail (PANEL_IS_WINDOW (window), FALSE);
 
-  /* queue a hide timeout */
-  panel_window_autohide_queue (window, POPUP_QUEUED);
+  /* calculate the new window position, but keep it inside the working geometry */
+  window_x = pointer_x - window->grab_x;
+  high = window->area.x + window->area.width - window->alloc.width;
+  window_x = CLAMP (window_x, window->area.x, high);
 
-  return TRUE;
-}
+  window_y = pointer_y - window->grab_y;
+  high = window->area.y + window->area.height - window->alloc.height;
+  window_y = CLAMP (window_y, window->area.y, high);
 
+  /* update the grab coordinates */
+  window->grab_x = pointer_x - window_x;
+  window->grab_y = pointer_y - window_y;
 
+  /* update the base coordinates */
+  window->base_x = window_x + window->alloc.width / 2;
+  window->base_y = window_y + window->alloc.height / 2;
 
-static gboolean
-panel_window_autohide_leave_notify_event (GtkWidget        *widget,
-                                          GdkEventCrossing *event,
-                                          PanelWindow      *window)
-{
-  panel_return_val_if_fail (PANEL_IS_WINDOW (window), FALSE);
+  /* update the allocation */
+  window->alloc.x = window_x;
+  window->alloc.y = window_y;
 
-  /* stop a running autohide timeout */
-  if (window->autohide_timer != 0)
-    g_source_remove (window->autohide_timer);
+  /* update the snapping position */
+  window->snap_position = panel_window_snap_position (window);
 
-  /* update the status */
-  if (window->autohide_status == POPUP_QUEUED)
-    window->autohide_status = HIDDEN;
+  /* update the working area */
+  panel_window_screen_layout_changed (window->screen, window);
 
   return TRUE;
 }
 
 
 
-static GtkWidget *
-panel_window_autohide_window (PanelWindow *window)
+static gboolean
+panel_window_button_press_event (GtkWidget      *widget,
+                                 GdkEventButton *event)
 {
-  GtkWidget *popup;
-
-  /* create window */
-  popup = gtk_window_new (GTK_WINDOW_POPUP);
-  gtk_window_set_gravity (GTK_WINDOW (popup), GDK_GRAVITY_STATIC);
-
-  /* connect signals to monitor enter/leave events */
-  g_signal_connect (G_OBJECT (popup), "enter-notify-event", G_CALLBACK (panel_window_autohide_enter_notify_event), window);
-  g_signal_connect (G_OBJECT (popup), "leave-notify-event", G_CALLBACK (panel_window_autohide_leave_notify_event), window);
-
-  /* put the window offscreen */
-  gtk_window_move (GTK_WINDOW (popup), OFFSCREEN, OFFSCREEN);
-
-  /* set window opacity */
-  gtk_window_set_opacity (GTK_WINDOW (popup), window->leave_opacity);
+  PanelWindow   *window = PANEL_WINDOW (widget);
+  GdkCursor     *cursor;
+  GdkGrabStatus  status;
+  GdkDisplay    *display;
+  guint          modifiers;
 
-  /* show the window */
-  gtk_widget_show (popup);
+  /* leave if the event is not for this window */
+  if (event->window != widget->window)
+    return FALSE;
 
-  return popup;
-}
+  /* get the modifiers */
+  modifiers = event->state & gtk_accelerator_get_default_mod_mask ();
 
+  if (event->button == 1
+      && event->type == GDK_BUTTON_PRESS
+      && window->locked == FALSE
+      && modifiers == 0)
+    {
+      /* debug check */
+      panel_return_val_if_fail (window->grab_time == 0, FALSE);
 
+      /* create a cursor */
+      display = gdk_screen_get_display (window->screen);
+      cursor = gdk_cursor_new_for_display (display, GDK_FLEUR);
 
-static gboolean
-panel_window_enter_notify_event (GtkWidget        *widget,
-                                 GdkEventCrossing *event)
-{
-  PanelWindow *window = PANEL_WINDOW (widget);
+      /* grab the pointer for dragging the window */
+      status = gdk_pointer_grab (event->window, FALSE,
+                                 GDK_BUTTON_MOTION_MASK
+                                 | GDK_BUTTON_RELEASE_MASK,
+                                 NULL, cursor, event->time);
 
-  /* ignore event when entered from an inferior */
-  if (event->detail == GDK_NOTIFY_INFERIOR)
-    return FALSE;
+      /* release the cursor */
+      gdk_cursor_unref (cursor);
 
-  /* set the opacity (when they differ) */
-  if (window->leave_opacity != window->enter_opacity)
-    gtk_window_set_opacity (GTK_WINDOW (window), window->enter_opacity);
+      /* set the grab info if the grab was successfully made */
+      if (G_LIKELY (status == GDK_GRAB_SUCCESS))
+        {
+          window->grab_time = event->time;
+          window->grab_x = event->x;
+          window->grab_y = event->y;
+        }
 
-  /* stop a running autohide timeout */
-  if (window->autohide_timer != 0)
-    g_source_remove (window->autohide_timer);
+      return !!(status == GDK_GRAB_SUCCESS);
+    }
+  else if (event->button == 3
+           || (event->button == 1 && modifiers == GDK_CONTROL_MASK))
+    {
+      /* popup the panel menu */
+      panel_window_menu_popup (window, event->time);
 
-  /* update autohide status */
-  if (window->autohide_status == POPDOWN_QUEUED)
-    window->autohide_status = VISIBLE;
+      return TRUE;
+    }
 
   return FALSE;
 }
@@ -1026,26 +840,24 @@ panel_window_enter_notify_event (GtkWidget        *widget,
 
 
 static gboolean
-panel_window_leave_notify_event (GtkWidget        *widget,
-                                 GdkEventCrossing *event)
+panel_window_button_release_event (GtkWidget      *widget,
+                                   GdkEventButton *event)
 {
   PanelWindow *window = PANEL_WINDOW (widget);
+  GdkDisplay  *display;
 
-  /* ignore event when left towards an inferior */
-  if (event->detail == GDK_NOTIFY_INFERIOR)
-    return FALSE;
-
-  /* set the opacity (when they differ) */
-  if (window->leave_opacity != window->enter_opacity)
-    gtk_window_set_opacity (GTK_WINDOW (window), window->leave_opacity);
+  if (window->grab_time != 0)
+    {
+      /* ungrab the pointer */
+      display = gdk_screen_get_display (window->screen);
+      gdk_display_pointer_ungrab (display, window->grab_time);
+      window->grab_time = 0;
 
-  /* stop a running autohide timeout */
-  if (window->autohide_timer != 0)
-    g_source_remove (window->autohide_timer);
+      /* update the position property */
+      g_object_notify (G_OBJECT (widget), "position");
 
-  /* queue a new autohide time if needed */
-  if (window->autohide_status > BLOCKED && window->snap_edge != PANEL_SNAP_EGDE_NONE)
-    panel_window_autohide_queue (window, POPDOWN_QUEUED);
+      return TRUE;
+    }
 
   return FALSE;
 }
@@ -1056,6 +868,7 @@ static void
 panel_window_grab_notify (GtkWidget *widget,
                           gboolean   was_grabbed)
 {
+#if 0
   PanelWindow *window = PANEL_WINDOW (widget);
 
   /* avoid hiding the panel when the window is grabbed. this
@@ -1065,236 +878,242 @@ panel_window_grab_notify (GtkWidget *widget,
     panel_window_thaw_autohide (window);
   else
     panel_window_freeze_autohide (window);
+#endif
 }
 
 
 
-/**
- * panel_window_size_request:
- * @widget      : the panel window.
- * @requisition : the size we're requesting and receiving on
- *                allocation.
- *
- * In this function we request the panel size, this size must fit
- * on the screen and match all the settings. It's not nessecarily
- * that all the plugins fit (based on their requisition that is),
- * they have to respect the size we allocate, requesting is only
- * being kind to plugins (actually the itembar), and we're not ;).
- **/
 static void
 panel_window_size_request (GtkWidget      *widget,
                            GtkRequisition *requisition)
 {
   PanelWindow    *window = PANEL_WINDOW (widget);
-  GtkRequisition  child_requisition;
+  GtkRequisition  child_requisition = { 0, 0 };
+  gint            value, length;
   gint            extra_width = 0, extra_height = 0;
+  PanelBorders    borders;
 
-  if (GTK_WIDGET_REALIZED (widget))
-    {
-      /* poke the itembar to request it's size */
-      if (G_LIKELY (GTK_BIN (widget)->child))
-        gtk_widget_size_request (GTK_BIN (widget)->child, &child_requisition);
-      else
-        child_requisition.width = child_requisition.height = 0;
-
-      /* add the handle size */
-      if (window->locked == FALSE)
-        {
-          if (window->horizontal)
-            extra_width += HANDLE_SIZE_TOTAL;
-          else
-            extra_height += HANDLE_SIZE_TOTAL;
-        }
-
-      /* handle the borders */
-      if (PANEL_HAS_FLAG (window->borders, PANEL_BORDER_LEFT))
-        extra_width++;
-
-      /* handle the borders */
-      if (PANEL_HAS_FLAG (window->borders, PANEL_BORDER_RIGHT))
-        extra_width++;
-
-      /* handle the borders */
-      if (PANEL_HAS_FLAG (window->borders, PANEL_BORDER_TOP))
-        extra_height++;
-
-      /* handle the borders */
-      if (PANEL_HAS_FLAG (window->borders, PANEL_BORDER_BOTTOM))
-        extra_height++;
+  /* get the child requisition */
+  if (GTK_BIN (widget)->child != NULL)
+    gtk_widget_size_request (GTK_BIN (widget)->child, &child_requisition);
 
-      /* get the real allocated size */
+  /* handle size */
+  if (!window->locked)
+    {
       if (window->horizontal)
-        {
-          /* calculate the panel width (fits content, fits on the screen, and extands to user size) */
-          requisition->width = CLAMP (child_requisition.width + extra_width,
-                                      window->working_area.width * window->length,
-                                      window->working_area.width);
-
-          /* set height based on user setting */
-          requisition->height = window->size + extra_height;
-        }
+        extra_width += 2 * HANDLE_SIZE_TOTAL;
       else
-        {
-          /* calculate the panel width (fits content, fits on the screen, and extands to user size) */
-          requisition->height = CLAMP (child_requisition.height + extra_height,
-                                       window->working_area.height * window->length,
-                                       window->working_area.height);
+        extra_height += 2 * HANDLE_SIZE_TOTAL;
+    }
 
-          /* set width based on user setting */
-          requisition->width = window->size + extra_width;
-        }
+  /* get the active borders */
+  borders = panel_base_window_get_borders (PANEL_BASE_WINDOW (window));
+  if (PANEL_HAS_FLAG (borders, PANEL_BORDER_LEFT))
+    extra_width++;
+  if (PANEL_HAS_FLAG (borders, PANEL_BORDER_RIGHT))
+    extra_width++;
+  if (PANEL_HAS_FLAG (borders, PANEL_BORDER_TOP))
+    extra_height++;
+  if (PANEL_HAS_FLAG (borders, PANEL_BORDER_BOTTOM))
+    extra_height++;
+
+  /* set the window requisition */
+  if (window->horizontal)
+    {
+      requisition->height = window->size + extra_height;
+      length = window->area.width * window->length;
+      value = child_requisition.width + extra_width;
+      requisition->width = CLAMP (value, length, window->area.width);
+    }
+  else
+    {
+      requisition->width = window->size + extra_width;
+      length = window->area.height * window->length;
+      value = child_requisition.height + extra_height;
+      requisition->height = CLAMP (value, length, window->area.height);
     }
 }
 
 
 
-/**
- * panel_window_size_allocate:
- * @widget     : the panel window.
- * @allocation : the allocation.
- *
- * Here we position the window on the monitor/screen. The width and
- * height of the allocation cannot be changed, it's determend in
- * panel_window_size_request, so if it's wrong: fix things there.
- *
- * Because the panel window is a GtkWindow, the allocation x and y
- * are 0, which is fine for the child, but not for screen, so we
- * calculate the new screen position move and resize we window (at
- * once to avoid strange visual effects).
- *
- * The child allocation is basiclly the same, only a small change
- * to keep the handles free, when the panel is locked.
- **/
 static void
 panel_window_size_allocate (GtkWidget     *widget,
-                            GtkAllocation *allocation)
+                            GtkAllocation *alloc)
 {
   PanelWindow   *window = PANEL_WINDOW (widget);
-  GtkAllocation  child_allocation;
-  gint           root_x, root_y;
-  gint           width = HIDDEN_PANEL_SIZE, height = HIDDEN_PANEL_SIZE;
-  gint           hidden_root_x, hidden_root_y;
+  GtkAllocation  child_alloc;
+  gint           w, h, x, y;
+  PanelBorders   borders;
+  GtkWidget     *child;
 
-  if (GTK_WIDGET_REALIZED (widget))
+  widget->allocation = *alloc;
+  window->alloc = *alloc;
+
+  if (G_UNLIKELY (window->autohide_state == AUTOHIDE_HIDDEN
+                  || window->autohide_state == AUTOHIDE_POPUP))
+    {
+      /* window is invisible */
+      window->alloc.x = window->alloc.y = -9999;
+
+      /* set hidden window size */
+      w = h = 3;
+      if (window->horizontal)
+        w = alloc->width;
+      else
+        h = alloc->height;
+
+      /* position the autohide window */
+      panel_window_size_allocate_set_xy (window, w, h, &x, &y);
+      panel_base_window_move_resize (PANEL_BASE_WINDOW (window->autohide_window),
+                                     x, y, w, h);
+    }
+  else
     {
-      /* set the widget allocation */
-      widget->allocation = *allocation;
+      /* update the allocation */
+      panel_window_size_allocate_set_xy (window, alloc->width,
+          alloc->height, &window->alloc.x, &window->alloc.y);
+
+      /* update the struts if needed, leave when nothing changed */
+      if (window->struts_edge != STRUTS_EDGE_NONE
+          && window->autohide_state == AUTOHIDE_DISABLED)
+        panel_window_screen_struts_set (window);
+
+      /* move the autohide window offscreen */
+      if (window->autohide_window != NULL)
+        panel_base_window_move_resize (PANEL_BASE_WINDOW (window->autohide_window),
+                                       -9999, -9999, -1, -1);
+    }
+
+  /* move the window */
+  gtk_window_move (GTK_WINDOW (window), window->alloc.x, window->alloc.y);
 
-      /* get coordinates for the panel window */
-      panel_window_calculate_position (window, allocation->width, allocation->height, &root_x, &root_y);
+  /* position the child */
+  child = gtk_bin_get_child (GTK_BIN (widget));
+  if (G_LIKELY (child != NULL))
+    {
+      /* init child allocation */
+      child_alloc.x = 0;
+      child_alloc.y = 0;
+      child_alloc.width = alloc->width;
+      child_alloc.height = alloc->height;
+
+      /* set position against the borders */
+      borders = panel_base_window_get_borders (PANEL_BASE_WINDOW (window));
+      if (PANEL_HAS_FLAG (borders, PANEL_BORDER_LEFT))
+        {
+          child_alloc.x++;
+          child_alloc.width--;
+        }
+      if (PANEL_HAS_FLAG (borders, PANEL_BORDER_TOP))
+        {
+          child_alloc.y++;
+          child_alloc.height--;
+        }
+      if (PANEL_HAS_FLAG (borders, PANEL_BORDER_RIGHT))
+        child_alloc.width--;
+      if (PANEL_HAS_FLAG (borders, PANEL_BORDER_BOTTOM))
+        child_alloc.height--;
 
-      /* handle hidden windows */
-      if (window->autohide_status != DISABLED
-          && window->autohide_window != NULL
-          && window->snap_edge != PANEL_SNAP_EGDE_NONE)
+      /* keep space for the panel handles if not locked */
+      if (!window->locked)
         {
-          if (window->autohide_status == VISIBLE
-              || window->autohide_status == POPDOWN_QUEUED
-              ||  window->autohide_status == POPDOWN_QUEUED_SLOW
-              || window->autohide_status == BLOCKED)
+          if (window->horizontal)
             {
-              /* put the hidden window offscreen */
-              gtk_window_move (GTK_WINDOW (window->autohide_window), OFFSCREEN, OFFSCREEN);
+              child_alloc.width -= 2 * HANDLE_SIZE_TOTAL;
+              child_alloc.x += HANDLE_SIZE_TOTAL;
             }
           else
             {
-              /* init width and height */
-              width = height = HIDDEN_PANEL_SIZE;
-
-              /* get hidden panel size */
-              switch (window->snap_edge)
-                {
-                  case PANEL_SNAP_EGDE_E:
-                  case PANEL_SNAP_EGDE_EC:
-                  case PANEL_SNAP_EGDE_W:
-                  case PANEL_SNAP_EGDE_WC:
-                    height = allocation->height;
-                    break;
-
-                  case PANEL_SNAP_EGDE_NC:
-                  case PANEL_SNAP_EGDE_SC:
-                  case PANEL_SNAP_EGDE_N:
-                  case PANEL_SNAP_EGDE_S:
-                    width = allocation->width;
-                    break;
-
-                  default:
-                    if (window->horizontal)
-                      width = allocation->width;
-                    else
-                      height = allocation->height;
-                    break;
-                }
-
-              /* get coordinates for the hidden window */
-              panel_window_calculate_position (window, width, height, &hidden_root_x, &hidden_root_y);
-
-              /* position the hidden window */
-              gtk_window_move (GTK_WINDOW (window->autohide_window), hidden_root_x, hidden_root_y);
-              gtk_window_resize (GTK_WINDOW (window->autohide_window), width, height);
-
-              /* put the panel window offscreen */
-              root_x = root_y = OFFSCREEN;
+              child_alloc.height -= 2 * HANDLE_SIZE_TOTAL;
+              child_alloc.y += HANDLE_SIZE_TOTAL;
             }
         }
 
-      /* move and resize the panel window */
-      gdk_window_move_resize (widget->window, root_x, root_y, allocation->width, allocation->height);
+      /* allocate the itembar */
+      gtk_widget_size_allocate (child, &child_alloc);
+    }
+}
 
-      if (GTK_BIN (widget)->child)
-        {
-          /* set the child allocation */
-          child_allocation = *allocation;
 
-          /* extract the border sizes from the allocation */
-          if (PANEL_HAS_FLAG (window->borders, PANEL_BORDER_LEFT))
-            {
-              child_allocation.x++;
-              child_allocation.width--;
-            }
 
-          if (PANEL_HAS_FLAG (window->borders, PANEL_BORDER_TOP))
-            {
-              child_allocation.y++;
-              child_allocation.height--;
-            }
+static void
+panel_window_size_allocate_set_xy (PanelWindow *window,
+                                   gint         window_width,
+                                   gint         window_height,
+                                   gint        *return_x,
+                                   gint        *return_y)
+{
+  gint value, hight;
 
-          if (PANEL_HAS_FLAG (window->borders, PANEL_BORDER_RIGHT))
-            child_allocation.width--;
+  /* x-position */
+  switch (window->snap_position)
+    {
+      case SNAP_POSITION_NONE:
+      case SNAP_POSITION_N:
+      case SNAP_POSITION_S:
+        /* clamp base point on screen */
+        value = window->base_x - (window_width / 2);
+        hight = window->area.x + window->area.width - window_width;
+        *return_x = CLAMP (value, window->area.x, hight);
+        break;
 
-          if (PANEL_HAS_FLAG (window->borders, PANEL_BORDER_BOTTOM))
-            child_allocation.height--;
+      case SNAP_POSITION_W:
+      case SNAP_POSITION_NW:
+      case SNAP_POSITION_WC:
+      case SNAP_POSITION_SW:
+        /* left */
+        *return_x = window->area.x;
+        break;
 
-          /* keep free space for the handles if needed */
-          if (window->locked == FALSE)
-            {
-              if (window->horizontal)
-                {
-                  child_allocation.width -= HANDLE_SIZE_TOTAL;
-                  child_allocation.x += HANDLE_SIZE + HANDLE_SPACING;
-                }
-              else
-                {
-                  child_allocation.height -= HANDLE_SIZE_TOTAL;
-                  child_allocation.y += HANDLE_SIZE + HANDLE_SPACING;
-                }
-            }
+      case SNAP_POSITION_E:
+      case SNAP_POSITION_NE:
+      case SNAP_POSITION_EC:
+      case SNAP_POSITION_SE:
+        /* right */
+        *return_x = window->area.x + window->area.width - window_width;
+        break;
 
-          /* keep things positive */
-          child_allocation.width = MAX (0, child_allocation.width);
-          child_allocation.height = MAX (0, child_allocation.height);
+      case SNAP_POSITION_NC:
+      case SNAP_POSITION_SC:
+        /* center */
+        *return_x = window->area.x + (window->area.width - window_width) / 2;
+        break;
+    }
 
-          /* allocate the child */
-          gtk_widget_size_allocate (GTK_BIN (widget)->child, &child_allocation);
-        }
+  /* y-position */
+  switch (window->snap_position)
+    {
+      case SNAP_POSITION_NONE:
+      case SNAP_POSITION_E:
+      case SNAP_POSITION_W:
+        /* clamp base point on screen */
+        value = window->base_y - (window_height / 2);
+        hight = window->area.y + window->area.height - window_height;
+        *return_y = CLAMP (value, window->area.y, hight);
+        break;
 
-      /* update struts if possible */
-      if (window->struts_possible != 0)
-        panel_window_struts_update (window, root_x, root_y, allocation->width, allocation->height);
-    }
+      case SNAP_POSITION_NE:
+      case SNAP_POSITION_NW:
+      case SNAP_POSITION_NC:
+      case SNAP_POSITION_N:
+        /* top */
+        *return_y = window->area.y;
+        break;
+
+      case SNAP_POSITION_SE:
+      case SNAP_POSITION_SW:
+      case SNAP_POSITION_SC:
+      case SNAP_POSITION_S:
+        /* bottom */
+        *return_y = window->area.y + window->area.height - window_height;
+        break;
 
-  /* update previous allocation */
-  window->prev_allocation = *allocation;
+      case SNAP_POSITION_EC:
+      case SNAP_POSITION_WC:
+        /* center */
+        *return_y = window->area.y + (window->area.height - window_height) / 2;
+        break;
+    }
 }
 
 
@@ -1303,679 +1122,598 @@ static void
 panel_window_screen_changed (GtkWidget *widget,
                              GdkScreen *previous_screen)
 {
-  GdkScreen   *screen;
   PanelWindow *window = PANEL_WINDOW (widget);
-
-  panel_return_if_fail (PANEL_IS_WINDOW (widget));
-  panel_return_if_fail (GDK_IS_SCREEN (previous_screen));
+  GdkScreen   *screen;
 
   /* get the new screen */
   screen = gtk_window_get_screen (GTK_WINDOW (widget));
+  panel_return_if_fail (GDK_IS_SCREEN (screen));
+  if (G_UNLIKELY (window->screen == screen))
+    return;
+
+  /* disconnect from previous screen */
+  if (G_UNLIKELY (window->screen != NULL))
+    g_signal_handlers_disconnect_by_func (G_OBJECT (window->screen),
+        panel_window_screen_layout_changed, window);
+
+  /* set the new screen */
+  window->screen = screen;
+  g_signal_connect (G_OBJECT (window->screen), "monitors-changed",
+      G_CALLBACK (panel_window_screen_layout_changed), window);
+  g_signal_connect (G_OBJECT (window->screen), "size-changed",
+      G_CALLBACK (panel_window_screen_layout_changed), window);
+
+  /* update the screen layout */
+  panel_window_screen_layout_changed (screen, window);
+}
+
+
+
+static StrutsEgde
+panel_window_screen_struts_edge (PanelWindow *window)
+{
+  panel_return_val_if_fail (PANEL_IS_WINDOW (window), STRUTS_EDGE_NONE);
 
-  if (screen != previous_screen)
+  /* no struts when autohide is active */
+  if (window->autohide_state != AUTOHIDE_DISABLED)
+    return STRUTS_EDGE_NONE;
+
+  /* return the screen edge on which the window is
+   * visually snapped and where the struts are set */
+  switch (window->snap_position)
     {
-      /* disconnect old screen changed handles */
-      g_signal_handlers_disconnect_by_func (G_OBJECT (previous_screen), G_CALLBACK (panel_window_screen_changed), widget);
+      case SNAP_POSITION_NONE:
+        return STRUTS_EDGE_NONE;
 
-      /* connect new screen update signals */
-      g_signal_connect_swapped (G_OBJECT (screen), "size-changed", G_CALLBACK (panel_window_screen_changed), widget);
-#if GTK_CHECK_VERSION (2,14,0)
-      g_signal_connect_swapped (G_OBJECT (screen), "monitors-changed", G_CALLBACK (panel_window_screen_changed), widget);
-#endif
-    }
+      case SNAP_POSITION_E:
+      case SNAP_POSITION_EC:
+        return window->horizontal ? STRUTS_EDGE_NONE : STRUTS_EDGE_RIGHT;
 
-  /* update the panel working area */
-  panel_window_working_area (window, -1, -1, &window->working_area);
+      case SNAP_POSITION_NE:
+        return window->horizontal ? STRUTS_EDGE_TOP : STRUTS_EDGE_RIGHT;
 
-  /* check if struts are needed on the next resize */
-  window->struts_possible = -1;
+      case SNAP_POSITION_SE:
+        return window->horizontal ? STRUTS_EDGE_BOTTOM : STRUTS_EDGE_RIGHT;
 
-  /* queue a resize */
-  gtk_widget_queue_resize (widget);
+      case SNAP_POSITION_W:
+      case SNAP_POSITION_WC:
+        return window->horizontal ? STRUTS_EDGE_NONE : STRUTS_EDGE_LEFT;
+
+      case SNAP_POSITION_NW:
+        return window->horizontal ? STRUTS_EDGE_TOP : STRUTS_EDGE_LEFT;
+
+      case SNAP_POSITION_SW:
+        return window->horizontal ? STRUTS_EDGE_BOTTOM : STRUTS_EDGE_LEFT;
+
+      case SNAP_POSITION_NC:
+      case SNAP_POSITION_N:
+        return window->horizontal ? STRUTS_EDGE_TOP : STRUTS_EDGE_NONE;
+
+      case SNAP_POSITION_SC:
+      case SNAP_POSITION_S:
+        return window->horizontal ? STRUTS_EDGE_BOTTOM : STRUTS_EDGE_NONE;
+    }
+
+  return STRUTS_EDGE_NONE;
 }
 
 
 
 static void
-panel_window_paint_handle (PanelWindow  *window,
-                           gboolean      start,
-                           GtkStateType  state,
-                           cairo_t      *cr)
+panel_window_screen_struts_set (PanelWindow *window)
 {
-  GtkWidget     *widget = GTK_WIDGET (window);
-  GtkAllocation *alloc  = &(widget->allocation);
-  gint           x, y, width, height;
-  guint          i, xx, yy;
-  GdkColor      *color;
-  gdouble        alpha = 1.00;
-
-  /* set the alpha (always show to handle for atleast 50%) */
-  if (window->active_timeout_id == 0 && window->is_composited)
-    alpha = 0.50 + window->background_alpha / 2.00;
+  gulong         struts[N_STRUTS] = { 0, };
+  GdkRectangle  *alloc = &window->alloc;
+  guint          i;
+  gboolean       update_struts = FALSE;
+#if STRUTS_DEBUGGING
+  gint           n;
+  const gchar   *names1[] = { "left", "right", "top", "bottom" };
+  const gchar   *names2[] = { "y",    "y",     "x",    "x" };
+#endif
 
-  /* set initial numbers */
-  x = alloc->x + 2;
-  y = alloc->y + 2;
+  panel_return_if_fail (PANEL_IS_WINDOW (window));
+  panel_return_if_fail (GDK_IS_WINDOW (GTK_WIDGET (window)->window));
+  panel_return_if_fail (cardinal_atom != 0 && net_wm_strut_partial_atom != 0);
+  panel_return_if_fail (GDK_IS_SCREEN (window->screen));
 
-  if (window->horizontal)
+  /* set the struts */
+  /* note that struts are relative to the screen edge! */
+  if (window->struts_edge == STRUTS_EDGE_TOP)
     {
-      width = HANDLE_SIZE / 3 * 3;
-      height = alloc->height / 2;
-      y += height / 2 - 1;
-      x += (HANDLE_SIZE - width);
-
-      /* draw handle on the right */
-      if (!start)
-        x += alloc->width - HANDLE_SIZE - 4;
+      /* the window is snapped on the top screen edge */
+      struts[STRUT_TOP] = alloc->y + alloc->height;
+      struts[STRUT_TOP_START_X] = alloc->x;
+      struts[STRUT_TOP_END_X] = alloc->x + alloc->width;
     }
-  else
+  else if (window->struts_edge == STRUTS_EDGE_BOTTOM)
+    {
+      /* the window is snapped on the bottom screen edge */
+      struts[STRUT_BOTTOM] = gdk_screen_get_height (window->screen) - alloc->y;
+      struts[STRUT_BOTTOM_START_X] = alloc->x;
+      struts[STRUT_BOTTOM_END_X] = alloc->x + alloc->width;
+    }
+  else if (window->struts_edge == STRUTS_EDGE_LEFT)
+    {
+      /* the window is snapped on the left screen edge */
+      struts[STRUT_LEFT] = alloc->x + alloc->width;
+      struts[STRUT_LEFT_START_Y] = alloc->y;
+      struts[STRUT_LEFT_END_Y] = alloc->y + alloc->height;
+    }
+  else if (window->struts_edge == STRUTS_EDGE_RIGHT)
     {
-      height = HANDLE_SIZE / 3 * 3;
-      width = alloc->width / 2;
-      x += width / 2 - 1;
-      y += (HANDLE_SIZE - height);
-
-      /* draw handle on the bottom */
-      if (!start)
-        y += alloc->height - HANDLE_SIZE - 4;
+      /* the window is snapped on the right screen edge */
+      struts[STRUT_RIGHT] = gdk_screen_get_width (window->screen) - alloc->x;
+      struts[STRUT_RIGHT_START_Y] = alloc->y;
+      struts[STRUT_RIGHT_END_Y] = alloc->y + alloc->height;
     }
 
-  /* draw handler */
-  for (i = 2; i > 0; i--)
+  /* store the new struts */
+  for (i = 0; i < N_STRUTS; i++)
     {
-      /* get the color for the job */
-      if (i == 2)
-        color = &(widget->style->light[state]);
-      else
-        color = &(widget->style->dark[state]);
+      /* check if we need to update */
+      if (G_LIKELY (struts[i] == window->struts[i]))
+        continue;
 
-      /* set source color */
-      xfce_panel_cairo_set_source_rgba (cr, color, alpha);
+      /* set new value */
+      update_struts = TRUE;
+      window->struts[i] = struts[i];
+    }
 
-      /* draw the dots */
-      for (xx = 0; xx < (guint) width; xx += 3)
-        for (yy = 0; yy < (guint) height; yy += 3)
-          cairo_rectangle (cr, x + xx, y + yy, i, i);
+  /* leave when there is nothing to update */
+  if (update_struts == FALSE)
+    return;
+
+  /* don't crash on x errors */
+  gdk_error_trap_push ();
+
+  /* set the wm strut partial */
+  gdk_property_change (GTK_WIDGET (window)->window,
+                       net_wm_strut_partial_atom,
+                       cardinal_atom, 32, GDK_PROP_MODE_REPLACE,
+                       (guchar *) &struts, N_STRUTS);
+
+#if SET_OLD_WM_STRUTS
+  /* set the wm strut (old window managers) */
+  gdk_property_change (GTK_WIDGET (window)->window,
+                       net_wm_strut_atom,
+                       cardinal_atom, 32, GDK_PROP_MODE_REPLACE,
+                       (guchar *) &struts, 4);
+#endif
 
-      /* fill the rectangles */
-      cairo_fill (cr);
-    }
+  /* release the trap */
+  if (gdk_error_trap_pop () != 0)
+    g_critical ("Failed to set the struts");
+
+#if STRUTS_DEBUGGING
+  /* debugging output */
+  if (struts[STRUT_LEFT] != 0)
+    n = STRUT_LEFT;
+  else if (struts[STRUT_RIGHT] != 0)
+    n = STRUT_RIGHT;
+  else if (struts[STRUT_TOP] != 0)
+    n = STRUT_TOP;
+  else if (struts[STRUT_BOTTOM] != 0)
+    n = STRUT_BOTTOM;
+  else
+    n = -1;
+
+  if (n == -1)
+    g_message ("Struts updated: Reset to zero.");
+  else
+    g_message ("Struts updated: %s = %ld, start_%s = %ld, end_%s = %ld.",
+               names1[n], struts[n], names2[n], struts[4 + n * 2],
+               names2[n], struts[5 + n * 2]);
+#endif
 }
 
 
 
 static void
-panel_window_paint_borders (PanelWindow  *window,
-                            GtkStateType  state,
-                            cairo_t      *cr)
+panel_window_screen_force_update (PanelWindow *window)
 {
-  GtkWidget     *widget = GTK_WIDGET (window);
-  GtkAllocation *alloc = &(widget->allocation);
-  GdkColor      *color;
-  gdouble        alpha = 1.00;
-  const gdouble  dashes[] = {4.00, 4.00};
-  GTimeVal       timeval;
-
-  /* 1px line (1.5 results in a sharp 1px line) */
-  cairo_set_line_width (cr, 1.5);
-
-  if (G_UNLIKELY (window->active_timeout_id != 0))
-    g_get_current_time (&timeval);
-  else if (window->is_composited)
-    alpha = window->background_alpha;
-
-  /* possibly save some time */
-  if (PANEL_HAS_FLAG (window->borders, (PANEL_BORDER_BOTTOM | PANEL_BORDER_RIGHT)))
-    {
-      /* dark color */
-      if (G_UNLIKELY (window->active_timeout_id != 0))
-          color = &(widget->style->black);
-      else
-          color = &(widget->style->dark[state]);
-      xfce_panel_cairo_set_source_rgba (cr, color, alpha);
-
-      /* move the cursor the the bottom left */
-      cairo_move_to (cr, alloc->x, alloc->y + alloc->height);
-
-      /* bottom line */
-      if (PANEL_HAS_FLAG (window->borders, PANEL_BORDER_BOTTOM))
-        cairo_rel_line_to (cr, alloc->width, 0);
-      else
-        cairo_rel_move_to (cr, alloc->width, 0);
-
-      /* right line */
-      if (PANEL_HAS_FLAG (window->borders, PANEL_BORDER_RIGHT))
-        cairo_rel_line_to (cr, 0, -alloc->height);
-      else
-        cairo_rel_move_to (cr, 0, -alloc->height);
-
-      if (G_UNLIKELY (window->active_timeout_id != 0))
-        cairo_set_dash (cr, dashes, G_N_ELEMENTS (dashes),
-                        timeval.tv_sec % 2 ? 0.00 : 4.00);
-
-      /* stroke this part */
-      cairo_stroke (cr);
-    }
+  panel_return_if_fail (PANEL_IS_WINDOW (window));
 
-  /* possibly save some time */
-  if (PANEL_HAS_FLAG (window->borders, (PANEL_BORDER_TOP | PANEL_BORDER_LEFT)))
+  if (GTK_WIDGET_VISIBLE (window))
     {
-      /* light color */
-      if (G_UNLIKELY (window->active_timeout_id != 0))
-          color = &(widget->style->black);
-      else
-          color = &(widget->style->light[state]);
-      xfce_panel_cairo_set_source_rgba (cr, color, alpha);
-
-      /* move the cursor the the bottom left */
-      cairo_move_to (cr, alloc->x, alloc->y + alloc->height);
-
-      /* left line */
-      if (PANEL_HAS_FLAG (window->borders, PANEL_BORDER_LEFT))
-        cairo_rel_line_to (cr, 0, -alloc->height);
-      else
-        cairo_rel_move_to (cr, 0, -alloc->height);
+      /* make sure the struts are set again, when enabled */
+      if (window->struts_edge != STRUTS_EDGE_NONE
+          && window->autohide_state == AUTOHIDE_DISABLED)
+        window->struts[0] = -1;
 
-      /* top line */
-      if (PANEL_HAS_FLAG (window->borders, PANEL_BORDER_TOP))
-        cairo_rel_line_to (cr, alloc->width, 0);
-      else
-        cairo_rel_move_to (cr, alloc->width, 0);
-
-      if (G_UNLIKELY (window->active_timeout_id != 0))
-        cairo_set_dash (cr, dashes, G_N_ELEMENTS (dashes),
-                        timeval.tv_sec % 2 ? 0.00 : -4.00);
-
-      /* stroke the lines */
-      cairo_stroke (cr);
+      /* update the panel position */
+      panel_window_screen_layout_changed (window->screen, window);
     }
 }
 
 
 
 static void
-panel_window_calculate_position (PanelWindow *window,
-                                 gint         width,
-                                 gint         height,
-                                 gint        *x,
-                                 gint        *y)
+panel_window_screen_update_borders (PanelWindow *window)
 {
-  gint          root_x, root_y;
-  GdkRectangle *area = &window->working_area;
+  PanelBorders borders = PANEL_BORDER_MASK;
+  PanelBorders unset_borders = 0;
 
-  /* get the panel window position */
-  panel_window_get_position (window, &root_x, &root_y);
+  panel_return_if_fail (PANEL_IS_WINDOW (window));
 
-  /* x position of the window */
-  switch (window->snap_edge)
+  /* the border we want to hide */
+  switch (window->snap_position)
     {
-      /* left */
-      case PANEL_SNAP_EGDE_W:
-      case PANEL_SNAP_EGDE_NW:
-      case PANEL_SNAP_EGDE_WC:
-      case PANEL_SNAP_EGDE_SW:
-        *x = area->x;
+      case SNAP_POSITION_NONE:
         break;
 
-      /* right */
-      case PANEL_SNAP_EGDE_E:
-      case PANEL_SNAP_EGDE_NE:
-      case PANEL_SNAP_EGDE_EC:
-      case PANEL_SNAP_EGDE_SE:
-        *x = area->x + area->width - width;
+      case SNAP_POSITION_E:
+      case SNAP_POSITION_EC:
+        unset_borders = PANEL_BORDER_RIGHT;
         break;
 
-      /* center */
-      case PANEL_SNAP_EGDE_NC:
-      case PANEL_SNAP_EGDE_SC:
-        *x = area->x + (area->width - width) / 2;
+      case SNAP_POSITION_W:
+      case SNAP_POSITION_WC:
+        unset_borders = PANEL_BORDER_LEFT;
         break;
 
-      /* other, recenter based on previous allocation */
-      default:
-        *x = root_x + (window->prev_allocation.width - width) / 2;
-        *x = CLAMP (*x, area->x, area->x + area->width - width);
+      case SNAP_POSITION_N:
+      case SNAP_POSITION_NC:
+        unset_borders = PANEL_BORDER_TOP;
         break;
-    }
 
-  /* y position of the window */
-  switch (window->snap_edge)
-    {
-      /* north */
-      case PANEL_SNAP_EGDE_NE:
-      case PANEL_SNAP_EGDE_NW:
-      case PANEL_SNAP_EGDE_NC:
-      case PANEL_SNAP_EGDE_N:
-        *y = area->y;
+      case SNAP_POSITION_S:
+      case SNAP_POSITION_SC:
+        unset_borders = PANEL_BORDER_BOTTOM;
         break;
 
-      /* south */
-      case PANEL_SNAP_EGDE_SE:
-      case PANEL_SNAP_EGDE_SW:
-      case PANEL_SNAP_EGDE_SC:
-      case PANEL_SNAP_EGDE_S:
-        *y = area->y + area->height - height;
+      case SNAP_POSITION_NE:
+        unset_borders = PANEL_BORDER_RIGHT | PANEL_BORDER_TOP;
         break;
 
-      /* center */
-      case PANEL_SNAP_EGDE_EC:
-      case PANEL_SNAP_EGDE_WC:
-        *y = area->y + (area->height - height) / 2;
+      case SNAP_POSITION_SE:
+        unset_borders = PANEL_BORDER_RIGHT | PANEL_BORDER_BOTTOM;
         break;
 
-      /* other, recenter based on previous allocation */
-      default:
-        *y = root_y + (window->prev_allocation.height - height) / 2;
-        *y = CLAMP (*y, area->y, area->y + area->height - height);
+      case SNAP_POSITION_NW:
+        unset_borders = PANEL_BORDER_LEFT | PANEL_BORDER_TOP;
         break;
-    }
-}
-
 
+      case SNAP_POSITION_SW:
+        unset_borders = PANEL_BORDER_LEFT | PANEL_BORDER_BOTTOM;
+        break;
+    }
 
-static void
-panel_window_working_area (PanelWindow  *window,
-                           gint          root_x,
-                           gint          root_y,
-                           GdkRectangle *dest)
-{
-  GdkScreen    *screen;
-  gint          monitor_num;
-  gint          n_monitors;
-  GdkRectangle  geometry;
-  gint          i;
+  /* the visible borders */
+  PANEL_UNSET_FLAG (borders, unset_borders);
 
-  panel_return_if_fail (PANEL_IS_WINDOW (window));
-  panel_return_if_fail (GDK_IS_WINDOW (GTK_WIDGET (window)->window));
+  /* don't show the side borders if the length is 100% */
+  if (window->length == 1.00)
+    {
+      if (window->horizontal)
+        PANEL_UNSET_FLAG (borders, PANEL_BORDER_LEFT | PANEL_BORDER_RIGHT);
+      else
+        PANEL_UNSET_FLAG (borders, PANEL_BORDER_TOP | PANEL_BORDER_BOTTOM);
+    }
 
-  /* get valid coordinates if not set */
-  if (root_x == -1 && root_y == -1)
-    gtk_window_get_position (GTK_WINDOW (window), &root_x, &root_y);
+  /* set the borders */
+  panel_base_window_set_borders (PANEL_BASE_WINDOW (window), borders);
+}
 
-  /* get panel screen */
-  screen = gtk_window_get_screen (GTK_WINDOW (window));
 
-  /* get the monitor number */
-  monitor_num = gdk_screen_get_monitor_at_point (screen, root_x, root_y);
 
-  /* get the root monitor geometry */
-  gdk_screen_get_monitor_geometry (screen, monitor_num, dest);
+static inline guint
+panel_window_snap_edge_gravity (gint value,
+                                gint start,
+                                gint end)
+{
+  gint center;
 
-  if (window->span_monitors)
-    {
-      /* get the number of monitors */
-      n_monitors = gdk_screen_get_n_monitors (screen);
+  /* snap at the start */
+  if (value >= start && value <= start + SNAP_DISTANCE)
+    return EDGE_GRAVITY_START;
 
-      /* only try to extend when there are more then 2 monitors */
-      if (G_LIKELY (n_monitors > 1))
-        {
-          for (i = 0; i < n_monitors; i++)
-            {
-              /* skip the origional monitor */
-              if (i == monitor_num)
-                continue;
+  /* snap at the end */
+  if (value <= end && value >= end - SNAP_DISTANCE)
+    return EDGE_GRAVITY_END;
 
-              /* get the monitor geometry */
-              gdk_screen_get_monitor_geometry (screen, i, &geometry);
+  /* calculate the center of start and end */
+  center = start + (end - start) / 2;
 
-              g_message ("monitor %d, x=%d, y=%d, w=%d, h=%d", i, geometry.x, geometry.y, geometry.width, geometry.height);
+  /* snap at the center */
+  if (value >= center - 10 && value <= center + SNAP_DISTANCE)
+    return EDGE_GRAVITY_CENTER;
 
-              /* try to extend the dest geometry from the root coordinate's point of view */
-              if (window->horizontal
-                  && root_y >= geometry.y
-                  && root_y <= geometry.y + geometry.height
-                  && (dest->x + dest->width == geometry.x
-                      || dest->x == geometry.x + geometry.width))
-                {
-                  /* extend the maximum area horizontally */
-                  dest->x = MIN (dest->x, geometry.x);
-                  dest->width += geometry.width;
-                }
-              else if (window->horizontal == FALSE
-                       && root_x >= geometry.x
-                       && root_x <= geometry.x + geometry.width
-                       && (dest->y + dest->height == geometry.y
-                           || dest->y == geometry.y + geometry.height))
-                {
-                  /* extend the maximum area vertically */
-                  dest->y = MIN (dest->y, geometry.y);
-                  dest->height += geometry.height;
-                }
-            }
-        }
-    }
+  return EDGE_GRAVITY_NONE;
 }
 
 
 
-static gboolean
-panel_window_struts_are_possible (PanelWindow *window,
-                                  gint         x,
-                                  gint         y,
-                                  gint         width,
-                                  gint         height)
+static SnapPosition
+panel_window_snap_position (PanelWindow *window)
 {
-  GdkScreen    *screen;
-  gint          n_monitors;
-  gint          i;
-  GdkRectangle  geometry;
+  guint         snap_horz, snap_vert;
+  GdkRectangle *alloc = &window->alloc;
+
+  /* get the snap offsets */
+  snap_horz = panel_window_snap_edge_gravity (alloc->x, window->area.x,
+      window->area.x + window->area.width - alloc->width);
+  snap_vert = panel_window_snap_edge_gravity (alloc->y, window->area.y,
+      window->area.y + window->area.height - alloc->height);
+
+  /* detect the snap mode */
+  if (snap_horz == EDGE_GRAVITY_START)
+    return SNAP_POSITION_W + snap_vert;
+  else if (snap_horz == EDGE_GRAVITY_END)
+    return SNAP_POSITION_E + snap_vert;
+  else if (snap_horz == EDGE_GRAVITY_CENTER && snap_vert == EDGE_GRAVITY_START)
+    return SNAP_POSITION_NC;
+  else if (snap_horz == EDGE_GRAVITY_CENTER && snap_vert == EDGE_GRAVITY_END)
+    return SNAP_POSITION_SC;
+  else if (snap_horz == EDGE_GRAVITY_NONE && snap_vert == EDGE_GRAVITY_START)
+    return SNAP_POSITION_N;
+  else if (snap_horz == EDGE_GRAVITY_NONE && snap_vert == EDGE_GRAVITY_END)
+    return SNAP_POSITION_S;
+
+  return SNAP_POSITION_NONE;
+}
 
-  panel_return_val_if_fail (PANEL_IS_WINDOW (window), FALSE);
 
-  /* never set struts when we don't snap or when autohide is enabled */
-  if (window->snap_edge == PANEL_SNAP_EGDE_NONE || window->autohide_status != DISABLED)
-    return FALSE;
 
-  /* always set struts on the following condition */
-  if ((window->horizontal && y == 0) || (!window->horizontal && x == 0))
-    return TRUE;
+static void
+panel_window_screen_layout_changed (GdkScreen   *screen,
+                                    PanelWindow *window)
+{
+  GdkRectangle  a, b;
+  gint          monitor_num, n_monitors, n;
+  gint          dest_x, dest_y;
+  gint          dest_w, dest_h;
+  gchar        *name;
+  StrutsEgde    struts_edge;
+  gboolean      force_struts_update = FALSE;
+/* TODO test how many times this function is called */
+  panel_return_if_fail (PANEL_IS_WINDOW (window));
+  panel_return_if_fail (GDK_IS_SCREEN (screen));
+  panel_return_if_fail (window->screen == screen);
 
-  /* get panel screen */
-  screen = gtk_window_get_screen (GTK_WINDOW (window));
+  /* update the struts edge of this window and check if we need to force
+   * a struts update (ie. remove struts that are currently set) */
+  struts_edge = panel_window_screen_struts_edge (window);
+  if (window->struts_edge != struts_edge && struts_edge == STRUTS_EDGE_NONE)
+    force_struts_update = TRUE;
+  window->struts_edge = struts_edge;
 
   /* get the number of monitors */
   n_monitors = gdk_screen_get_n_monitors (screen);
+  panel_return_if_fail (n_monitors > 0);
 
-  if (G_LIKELY (n_monitors == 1))
+  if (window->span_monitors
+      || (n_monitors == 1 && window->output_name == NULL))
     {
-      /* don't set the struts when we're not at a screen edge */
-      if ((window->horizontal && y + height != gdk_screen_get_height (screen))
-          || (!window->horizontal && x + width != gdk_screen_get_width (screen)))
-        return FALSE;
+      /* get the screen geometry */
+      a.x = a.y = 0;
+      a.width = gdk_screen_get_width (screen);
+      a.height = gdk_screen_get_height (screen);
+      panel_return_if_fail (a.width > 0 && a.height > 0);
     }
   else
     {
-      for (i = 0; i < n_monitors; i++)
+      if (window->output_name == NULL)
         {
-          /* get the monitor geometry */
-          gdk_screen_get_monitor_geometry (screen, i, &geometry);
-
-          if (window->horizontal
-              && x >= geometry.x
-              && x + width <= geometry.x + geometry.width
-              && y + height < geometry.y + geometry.height)
-            return FALSE;
-
-          if (window->horizontal == FALSE
-              && y >= geometry.y
-              && y + height <= geometry.y + geometry.height
-              && x + width < geometry.x + geometry.width)
-            return FALSE;
-        }
-    }
-
-  return TRUE;
-}
-
+          normal_monitor_positioning:
 
+          /* get the monitor geometry based on the panel position */
+          monitor_num = gdk_screen_get_monitor_at_point (screen, window->base_x,
+                                                         window->base_y);
+          gdk_screen_get_monitor_geometry (screen, monitor_num, &a);
+          panel_return_if_fail (a.width > 0 && a.height > 0);
+        }
+      else
+        {
+          /* check if the monitor of this panel is present */
+          for (n = 0, monitor_num = -1; n < n_monitors && monitor_num == -1; n++)
+            {
+              name = gdk_screen_get_monitor_plug_name (screen, n);
 
-static void
-panel_window_struts_update (PanelWindow *window,
-                            gint         x,
-                            gint         y,
-                            gint         width,
-                            gint         height)
-{
-  gulong     struts[N_STRUTS] = { 0, };
-  GdkScreen *screen;
-  guint      i;
-  gboolean   update_struts = FALSE;
+              /* check if this driver supports output names */
+              if (G_UNLIKELY (name == NULL))
+                {
+                  /* send a warnings why this went wrong */
+                  g_critical ("An output is set on the panel window (%s), "
+                              "but it looks  like the driver does not "
+                              "support output names. Falling back to normal "
+                              "monitor positioning, you have to set the output "
+                              "again in the preferences to activate this feature.",
+                              window->output_name);
+
+                  /* cleanup */
+                  g_free (window->output_name);
+                  window->output_name = NULL;
+
+                  /* fall back to normal positioning */
+                  goto normal_monitor_positioning;
+                }
 
-  panel_return_if_fail (PANEL_IS_WINDOW (window));
-  panel_return_if_fail (GDK_IS_WINDOW (GTK_WIDGET (window)->window));
-  panel_return_if_fail (N_STRUTS == 12);
-  panel_return_if_fail (cardinal_atom != GDK_NONE);
-  panel_return_if_fail (net_wm_strut_atom != GDK_NONE);
-  panel_return_if_fail (net_wm_strut_partial_atom != GDK_NONE);
+              /* check if this is the monitor we're looking for */
+              if (strcmp (window->output_name, name) == 0)
+                {
+                  /* store the monitor number, get the geometry */
+                  monitor_num = n;
+                  gdk_screen_get_monitor_geometry (screen, n, &a);
+                  panel_return_if_fail (a.width > 0 && a.height > 0);
+                }
 
-  if (G_UNLIKELY (window->struts_possible == -1))
-    {
-      /* check whether struts are possible, skip to apply if not */
-      window->struts_possible = panel_window_struts_are_possible (window, x, y, width, height);
+              /* cleanup */
+              g_free (name);
+            }
 
-      /* struts are not possible, reset them only this time */
-      if (window->struts_possible == 0)
-        goto reset_only;
-    }
+          /* check if a monitor was found */
+          if (monitor_num == -1)
+            {
+              if (GTK_WIDGET_VISIBLE (window))
+                gtk_widget_hide (GTK_WIDGET (window));
+              return;
+            }
+          else if (!GTK_WIDGET_VISIBLE (window))
+            {
+              gtk_widget_show (GTK_WIDGET (window));
+            }
+        }
 
-  /* get the panel window screen */
-  screen = gtk_window_get_screen (GTK_WINDOW (window));
+      /* don't do the check if we're not setting struts anyways */
+      if (window->struts_edge == STRUTS_EDGE_NONE)
+        goto done;
 
-  if (window->horizontal)
-    {
-      if (snap_edge_is_top (window->snap_edge))
-        {
-          /* the window is snapped on the top screen edge */
-          struts[STRUT_TOP] = y + height;
-          struts[STRUT_TOP_START_X] = x;
-          struts[STRUT_TOP_END_X] = x + width;
-        }
-      else if (snap_edge_is_bottom (window->snap_edge))
-        {
-          /* the window is snapped on the bottom screen edge */
-          struts[STRUT_BOTTOM] = gdk_screen_get_height (screen) - y;
-          struts[STRUT_BOTTOM_START_X] = x;
-          struts[STRUT_BOTTOM_END_X] = x + width;
-        }
-    }
-  else /* vertical */
-    {
-      if (snap_edge_is_left (window->snap_edge))
+      /* traverse the monitors */
+      for (n = 0; n < n_monitors; n++)
         {
-          /* the window is snapped on the left screen edge */
-          struts[STRUT_LEFT] = x + width;
-          struts[STRUT_LEFT_START_Y] = y;
-          struts[STRUT_LEFT_END_Y] = y + height;
-        }
-      else if (snap_edge_is_right (window->snap_edge))
-        {
-          /* the window is snapped on the right screen edge */
-          struts[STRUT_RIGHT] = gdk_screen_get_width (screen) - x;
-          struts[STRUT_RIGHT_START_Y] = y;
-          struts[STRUT_RIGHT_END_Y] = y + height;
-        }
-    }
+          /* stop if another window prevent us from settings struts */
+          if (window->struts_edge == STRUTS_EDGE_NONE)
+            break;
 
-  reset_only:
+          /* skip the active monitor */
+          if (monitor_num == n)
+            continue;
 
-  for (i = 0; i < N_STRUTS; i++)
-    {
-      /* check if we need to update */
-      if (struts[i] != window->struts[i])
-        update_struts = TRUE;
+          /* get other monitor geometry */
+          gdk_screen_get_monitor_geometry (screen, n, &b);
 
-      /* store new strut */
-      window->struts[i] = struts[i];
+          /* check if this monitor prevents us from setting struts */
+          if ((window->struts_edge == STRUTS_EDGE_LEFT && b.x < a.x)
+              || (window->struts_edge == STRUTS_EDGE_RIGHT
+                  && b.x + b.width > a.x + a.width))
+            {
+              dest_y = MAX (a.y, b.y);
+              dest_h = MIN (a.y + a.height, b.y + b.height) - dest_y;
+              if (dest_h > 0)
+                window->struts_edge = STRUTS_EDGE_NONE;
+            }
+          else if ((window->struts_edge == STRUTS_EDGE_TOP && b.y < a.y)
+                   || (window->struts_edge == STRUTS_EDGE_BOTTOM
+                       && b.y + b.height > a.y + a.height))
+            {
+              dest_x = MAX (a.x, b.x);
+              dest_w = MIN (a.x + a.width, b.x + b.width) - dest_x;
+              if (dest_w > 0)
+                window->struts_edge = STRUTS_EDGE_NONE;
+            }
+        }
     }
 
-  if (update_struts)
-    {
-      /* don't crash on x errors */
-      gdk_error_trap_push ();
-
-      /* set the wm strut partial */
-      gdk_property_change (GTK_WIDGET (window)->window, net_wm_strut_partial_atom,
-                           cardinal_atom, 32, GDK_PROP_MODE_REPLACE, (guchar *) &struts, 12);
+done:
+  /* set the new working area of the panel */
+  window->area = a;
 
-      /* set the wm strut (old window managers) */
-      /* gdk_property_change (GTK_WIDGET (window)->window, net_wm_strut_atom,
-       *                      cardinal_atom, 32, GDK_PROP_MODE_REPLACE, (guchar *) &struts, 4);
-       */
+  /* update panel borders */
+  panel_window_screen_update_borders (window);
 
-      /* release the trap push */
-      gdk_error_trap_pop ();
+  /* queue a resize */
+  gtk_widget_queue_resize (GTK_WIDGET (window));
 
-#if 0
-      gint         n = -1;
-      const gchar *names1[] = { "left", "right", "top", "bottom" };
-      const gchar *names2[] = { "y",    "y",     "x",    "x" };
-
-      if (struts[STRUT_LEFT] != 0)
-        n = STRUT_LEFT;
-	    else if (struts[STRUT_RIGHT] != 0)
-	      n = STRUT_RIGHT;
-	    else if (struts[STRUT_TOP] != 0)
-	      n = STRUT_TOP;
-	    else if (struts[STRUT_BOTTOM] != 0)
-	      n = STRUT_BOTTOM;
-
-      if (n == -1)
-        g_print ("Struts: All set to zero\n");
-      else
-        g_print ("Struts: %s = %ld, start_%s = %ld, end_%s = %ld\n", names1[n],
-                 struts[n], names2[n], struts[4 + n * 2], names2[n], struts[5 + n * 2]);
-#endif
-    }
+  /* update the struts if needed, ie. we need to reset the struts */
+  if (force_struts_update)
+    panel_window_screen_struts_set (window);
 }
 
 
 
-static void
-panel_window_set_colormap (PanelWindow *window)
+static gboolean
+panel_window_autohide_timeout (gpointer user_data)
 {
-  GdkColormap *colormap = NULL;
-  GdkScreen   *screen;
-  gboolean     restore;
-  GtkWidget   *widget = GTK_WIDGET (window);
-  gint         root_x, root_y;
-
-  panel_return_if_fail (PANEL_IS_WINDOW (window));
-
-  /* whether the widget was previously visible */
-  restore = GTK_WIDGET_REALIZED (widget);
-
-  /* unrealize the window if needed */
-  if (restore)
-    {
-      /* store the window position */
-      gtk_window_get_position (GTK_WINDOW (window), &root_x, &root_y);
-
-      /* reset the struts */
-      if (window->struts_possible == 1)
-        panel_window_struts_update (window, 0, 0, 0, 0);
-
-      /* hide the widget */
-      gtk_widget_hide (widget);
-      gtk_widget_unrealize (widget);
-    }
-
-  /* set bool */
-  window->is_composited = gtk_widget_is_composited (widget);
-
-  /* get the screen */
-  screen = gtk_window_get_screen (GTK_WINDOW (window));
-
-  /* try to get the rgba colormap */
-  if (window->is_composited)
-    colormap = gdk_screen_get_rgba_colormap (screen);
-
-  /* get the default colormap */
-  if (colormap == NULL)
-    {
-      colormap = gdk_screen_get_rgb_colormap (screen);
-      window->is_composited = FALSE;
-    }
+  PanelWindow *window = PANEL_WINDOW (user_data);
 
-  /* set the colormap */
-  if (colormap)
-    gtk_widget_set_colormap (widget, colormap);
+  panel_return_val_if_fail (window->autohide_state != AUTOHIDE_DISABLED, FALSE);
 
-  /* restore the window */
-  if (restore)
-    {
-      /* restore the position */
-      gtk_window_move (GTK_WINDOW (window), root_x, root_y);
+  /* update the status */
+  if (window->autohide_state == AUTOHIDE_POPDOWN
+      || window->autohide_state == AUTOHIDE_POPDOWN_SLOW)
+    window->autohide_state = AUTOHIDE_HIDDEN;
+  else if (window->autohide_state == AUTOHIDE_POPUP)
+    window->autohide_state = AUTOHIDE_VISIBLE;
 
-      /* show the widget again */
-      gtk_widget_realize (widget);
-      gtk_widget_show (widget);
+  /* resize the panel */
+  gtk_widget_queue_resize (GTK_WIDGET (window));
 
-      /* set the struts again */
-      if (window->struts_possible == 1)
-        panel_window_struts_update (window, root_x, root_y, widget->allocation.width, widget->allocation.height);
-    }
+  return FALSE;
 }
 
 
 
 static void
-panel_window_get_position (PanelWindow *window,
-                           gint        *root_x,
-                           gint        *root_y)
+panel_window_autohide_timeout_destroy (gpointer user_data)
 {
-  panel_return_if_fail (PANEL_IS_WINDOW (window));
-
-  /* get the window position of the visible window */
-  if (G_UNLIKELY (window->autohide_window
-      && (window->autohide_status == HIDDEN || window->autohide_status == POPUP_QUEUED)))
-    gtk_window_get_position (GTK_WINDOW (window->autohide_window), root_x, root_y);
-  else
-    gtk_window_get_position (GTK_WINDOW (window), root_x, root_y);
+  PANEL_WINDOW (user_data)->autohide_timeout_id = 0;
 }
 
 
 
 static void
-panel_window_set_borders (PanelWindow *window)
+panel_window_autohide_queue (PanelWindow   *window,
+                             AutohideState  new_state)
 {
-  PanelWindowBorders borders = 0;
+  guint delay;
 
   panel_return_if_fail (PANEL_IS_WINDOW (window));
 
-  if (window->horizontal)
-    {
-      /* only attempt to show the side borders if we're not filling the area */
-      if (window->length < 1.00)
-        {
-          /* show the left border if we don't snap to the left */
-          if (snap_edge_is_left (window->snap_edge) == FALSE)
-            PANEL_SET_FLAG (borders, PANEL_BORDER_LEFT);
+  /* stop pending timeout */
+  if (window->autohide_timeout_id != 0)
+    g_source_remove (window->autohide_timeout_id);
 
-          /* show the right border if we don't snap to the right */
-          if (snap_edge_is_right (window->snap_edge) == FALSE)
-            PANEL_SET_FLAG (borders, PANEL_BORDER_RIGHT);
-        }
+  /* set new autohide state */
+  window->autohide_state = new_state;
 
-      /* show the top border if not snapped to the top */
-      if (snap_edge_is_top (window->snap_edge) == FALSE)
-        PANEL_SET_FLAG (borders, PANEL_BORDER_TOP);
+  /* force a layout update to disable struts */
+  if (window->struts_edge != STRUTS_EDGE_NONE
+      || window->snap_position != SNAP_POSITION_NONE)
+    panel_window_screen_layout_changed (window->screen, window);
 
-      /* show the bottom border if not snapped to the bottom */
-      if (snap_edge_is_bottom (window->snap_edge) == FALSE)
-        PANEL_SET_FLAG (borders, PANEL_BORDER_BOTTOM);
+  if (new_state == AUTOHIDE_DISABLED)
+    {
+      /* queue a resize to make sure the panel is visible */
+      gtk_widget_queue_resize (GTK_WIDGET (window));
     }
   else
     {
-      /* only attempt to show the top borders if we're not filling the area */
-      if (window->length < 1.00)
-        {
-          /* show the top border if we don't snap to the top */
-          if (snap_edge_is_top (window->snap_edge) == FALSE)
-            PANEL_SET_FLAG (borders, PANEL_BORDER_TOP);
+      /* timeout delay */
+      if (new_state == AUTOHIDE_POPDOWN)
+        delay = POPDOWN_DELAY;
+      else if (new_state == AUTOHIDE_POPDOWN_SLOW)
+        delay = POPDOWN_DELAY * 4;
+      else
+        delay = POPUP_DELAY;
 
-          /* show the bottom border if we don't snap to the bottom */
-          if (snap_edge_is_bottom (window->snap_edge) == FALSE)
-            PANEL_SET_FLAG (borders, PANEL_BORDER_BOTTOM);
-        }
+      /* start a new timeout to hide the panel */
+      window->autohide_timeout_id =
+        g_timeout_add_full (G_PRIORITY_LOW, delay,
+                            panel_window_autohide_timeout, window,
+                            panel_window_autohide_timeout_destroy);
+    }
+}
 
-      /* show the left border if not snapped to the left */
-      if (snap_edge_is_left (window->snap_edge) == FALSE)
-        PANEL_SET_FLAG (borders, PANEL_BORDER_LEFT);
 
-      /* show the right border if not snapped to the right */
-      if (snap_edge_is_right (window->snap_edge) == FALSE)
-        PANEL_SET_FLAG (borders, PANEL_BORDER_RIGHT);
-    }
 
-  /* set the new value and queue a resize if needed */
-  if (window->borders != borders)
+static gboolean
+panel_window_autohide_event (GtkWidget        *widget,
+                             GdkEventCrossing *event,
+                             PanelWindow      *window)
+{
+  gboolean enter = !!(event->type == GDK_ENTER_NOTIFY);
+
+  panel_return_val_if_fail (PANEL_IS_WINDOW (window), FALSE);
+  panel_return_val_if_fail (window->autohide_window == widget, FALSE);
+
+  if (enter)
+    {
+      /* queue a popup */
+      panel_window_autohide_queue (window, AUTOHIDE_POPUP);
+    }
+  else
     {
-      /* set the new value */
-      window->borders = borders;
+      /* we left the window before it was hidden, stop the queue */
+      if (window->autohide_timeout_id != 0)
+        g_source_remove (window->autohide_timeout_id);
 
-      /* queue a resize */
-      gtk_widget_queue_resize (GTK_WIDGET (window));
+      /* update the status */
+      if (window->autohide_state == AUTOHIDE_POPUP)
+        window->autohide_state = AUTOHIDE_HIDDEN;
     }
+
+  return FALSE;
 }
 
 
@@ -1984,40 +1722,53 @@ static void
 panel_window_set_autohide (PanelWindow *window,
                            gboolean     autohide)
 {
-  AutohideStatus status;
+  GtkWidget   *popup;
+  guint        i;
+  const gchar *properties[] = { "enter-opacity", "leave-opacity",
+                                "background-alpha", "borders" };
 
   panel_return_if_fail (PANEL_IS_WINDOW (window));
 
-  if (G_LIKELY ((window->autohide_status != DISABLED) != autohide))
-    {
-      /* determ whether struts are possible on the next resize */
-      window->struts_possible = -1;
-
-      if (autohide)
-        {
-          /* create popup window if needed */
-          if (window->autohide_window == NULL)
-            window->autohide_window = panel_window_autohide_window (window);
-
-          /* get the correct status */
-          status = window->autohide_block == 0 ? POPDOWN_QUEUED_SLOW : BLOCKED;
-
-          /* queue a popdown */
-          panel_window_autohide_queue (window, status);
-        }
-      else
-        {
-          /* disable autohiding */
-          panel_window_autohide_queue (window, DISABLED);
+  if ((window->autohide_state != AUTOHIDE_DISABLED) == autohide)
+    return;
 
-          /* destroy the autohide window */
-          if (window->autohide_window)
-            {
-              gtk_widget_destroy (window->autohide_window);
-              window->autohide_window = NULL;
-            }
-        }
+  if (autohide)
+    {
+      /* create the window */
+      panel_return_if_fail (window->autohide_window == NULL);
+      popup = g_object_new (PANEL_TYPE_BASE_WINDOW, "type",
+                            GTK_WINDOW_POPUP, NULL);
+
+      /* move the window offscreen */
+      panel_base_window_move_resize (PANEL_BASE_WINDOW (popup),
+                                     -9999, -9999, 3, 3);
+
+      /* bind some properties to sync the two windows */
+      for (i = 0; i < G_N_ELEMENTS (properties); i++)
+        exo_binding_new (G_OBJECT (window), properties[i],
+                         G_OBJECT (popup), properties[i]);
+
+      /* signals for pointer enter/leave events */
+      g_signal_connect (G_OBJECT (popup), "enter-notify-event",
+          G_CALLBACK (panel_window_autohide_event), window);
+      g_signal_connect (G_OBJECT (popup), "leave-notify-event",
+          G_CALLBACK (panel_window_autohide_event), window);
+
+      /* show the window */
+      window->autohide_window = popup;
+      gtk_widget_show (popup);
     }
+  else if (window->autohide_window != NULL)
+    {
+      /* destroy the autohide window */
+      panel_return_if_fail (GTK_IS_WINDOW (window->autohide_window));
+      gtk_widget_destroy (window->autohide_window);
+      window->autohide_window = NULL;
+    }
+
+  /* start or stop autohiding */
+  panel_window_autohide_queue (window,
+      autohide ? AUTOHIDE_POPDOWN_SLOW : AUTOHIDE_DISABLED);
 }
 
 
@@ -2051,7 +1802,8 @@ panel_window_menu_deactivate (GtkMenu     *menu,
 
 
 static void
-panel_window_menu_popup (PanelWindow *window)
+panel_window_menu_popup (PanelWindow *window,
+                         guint32      event_time)
 {
   GtkWidget *menu;
   GtkWidget *item;
@@ -2067,10 +1819,11 @@ panel_window_menu_popup (PanelWindow *window)
 
   /* sink the menu and add unref on deactivate */
   g_object_ref_sink (G_OBJECT (menu));
-  g_signal_connect (G_OBJECT (menu), "deactivate", G_CALLBACK (panel_window_menu_deactivate), window);
+  g_signal_connect (G_OBJECT (menu), "deactivate",
+      G_CALLBACK (panel_window_menu_deactivate), window);
 
   /* label */
-  item = gtk_image_menu_item_new_with_label (_("Xfce Panel"));
+  item = gtk_image_menu_item_new_with_label ("Xfce Panel");
   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
   gtk_widget_set_sensitive (item, FALSE);
   gtk_widget_show (item);
@@ -2082,7 +1835,8 @@ panel_window_menu_popup (PanelWindow *window)
 
   /* add new items */
   item = gtk_image_menu_item_new_with_mnemonic (_("Add _New Items..."));
-  g_signal_connect_swapped (G_OBJECT (item), "activate", G_CALLBACK (panel_item_dialog_show), window);
+  g_signal_connect_swapped (G_OBJECT (item), "activate",
+      G_CALLBACK (panel_item_dialog_show), window);
   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
   gtk_widget_show (item);
 
@@ -2092,7 +1846,8 @@ panel_window_menu_popup (PanelWindow *window)
 
   /* customize panel */
   item = gtk_image_menu_item_new_with_mnemonic (_("Panel Pr_eferences..."));
-  g_signal_connect_swapped (G_OBJECT (item), "activate", G_CALLBACK (panel_preferences_dialog_show), window);
+  g_signal_connect_swapped (G_OBJECT (item), "activate",
+      G_CALLBACK (panel_preferences_dialog_show), window);
   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
   gtk_widget_show (item);
 
@@ -2107,13 +1862,15 @@ panel_window_menu_popup (PanelWindow *window)
 
   /* quit item */
   item = gtk_image_menu_item_new_from_stock (GTK_STOCK_QUIT, NULL);
-  g_signal_connect_swapped (G_OBJECT (item), "activate", G_CALLBACK (panel_window_menu_quit), GUINT_TO_POINTER (0));
+  g_signal_connect_swapped (G_OBJECT (item), "activate",
+      G_CALLBACK (panel_window_menu_quit), GUINT_TO_POINTER (0));
   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
   gtk_widget_show (item);
 
   /* restart item */
   item = gtk_image_menu_item_new_with_mnemonic (_("_Restart"));
-  g_signal_connect_swapped (G_OBJECT (item), "activate", G_CALLBACK (panel_window_menu_quit), GUINT_TO_POINTER (1));
+  g_signal_connect_swapped (G_OBJECT (item), "activate",
+      G_CALLBACK (panel_window_menu_quit), GUINT_TO_POINTER (1));
   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
   gtk_widget_show (item);
 
@@ -2128,27 +1885,27 @@ panel_window_menu_popup (PanelWindow *window)
 
   /* about item */
   item = gtk_image_menu_item_new_from_stock (GTK_STOCK_ABOUT, NULL);
-  g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (panel_dialogs_show_about), NULL);
+  g_signal_connect (G_OBJECT (item), "activate",
+      G_CALLBACK (panel_dialogs_show_about), NULL);
   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
   gtk_widget_show (item);
 
   /* popup the menu */
-  gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL,
-                  0, gtk_get_current_event_time ());
+  gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 0, event_time);
 }
 
 
 
 static void
-panel_window_set_plugin_background_alpha (GtkWidget *widget,
-                                          gpointer   user_data)
+panel_window_set_plugin_orientation (GtkWidget *widget,
+                                     gpointer   user_data)
 {
   panel_return_if_fail (XFCE_IS_PANEL_PLUGIN_PROVIDER (widget));
+  panel_return_if_fail (PANEL_IS_WINDOW (user_data));
 
-  /* we only have to send the alpha to external plugins */
-  if (PANEL_IS_PLUGIN_EXTERNAL (widget))
-    panel_plugin_external_set_background_alpha (PANEL_PLUGIN_EXTERNAL (widget),
-                                                GPOINTER_TO_UINT (user_data));
+  xfce_panel_plugin_provider_set_orientation (XFCE_PANEL_PLUGIN_PROVIDER (widget),
+      PANEL_WINDOW (user_data)->horizontal ? GTK_ORIENTATION_HORIZONTAL:
+          GTK_ORIENTATION_VERTICAL);
 }
 
 
@@ -2158,60 +1915,110 @@ panel_window_set_plugin_size (GtkWidget *widget,
                               gpointer   user_data)
 {
   panel_return_if_fail (XFCE_IS_PANEL_PLUGIN_PROVIDER (widget));
+  panel_return_if_fail (PANEL_IS_WINDOW (user_data));
 
-  /* set the new plugin size */
   xfce_panel_plugin_provider_set_size (XFCE_PANEL_PLUGIN_PROVIDER (widget),
-                                       GPOINTER_TO_INT (user_data));
+                                       PANEL_WINDOW (user_data)->size);
 }
 
 
 
 static void
-panel_window_set_plugin_orientation (GtkWidget *widget,
-                                     gpointer   user_data)
+panel_window_set_screen_position (GtkWidget *widget,
+                                  gpointer   user_data)
 {
+  PanelWindow        *window = PANEL_WINDOW (user_data);
+  XfceScreenPosition  position;
+
   panel_return_if_fail (XFCE_IS_PANEL_PLUGIN_PROVIDER (widget));
+  panel_return_if_fail (PANEL_IS_WINDOW (user_data));
 
-  /* set the new plugin orientation */
-  xfce_panel_plugin_provider_set_orientation (XFCE_PANEL_PLUGIN_PROVIDER (widget),
-                                              GPOINTER_TO_INT (user_data));
+  switch (window->snap_position)
+    {
+      case SNAP_POSITION_NONE:
+        position = window->horizontal ? XFCE_SCREEN_POSITION_FLOATING_H :
+            XFCE_SCREEN_POSITION_FLOATING_V;
+        break;
+
+      case SNAP_POSITION_NW:
+        position = window->horizontal ? XFCE_SCREEN_POSITION_NW_H :
+            XFCE_SCREEN_POSITION_NW_V;
+        break;
+
+      case SNAP_POSITION_NE:
+        position = window->horizontal ? XFCE_SCREEN_POSITION_NE_H :
+            XFCE_SCREEN_POSITION_NE_V;
+        break;
+
+      case SNAP_POSITION_SW:
+        position = window->horizontal ? XFCE_SCREEN_POSITION_SW_H :
+            XFCE_SCREEN_POSITION_SW_V;
+        break;
+
+      case SNAP_POSITION_SE:
+        position = window->horizontal ? XFCE_SCREEN_POSITION_SE_H :
+            XFCE_SCREEN_POSITION_SE_V;
+        break;
+
+      case SNAP_POSITION_W:
+      case SNAP_POSITION_WC:
+        position = window->horizontal ? XFCE_SCREEN_POSITION_FLOATING_H :
+            XFCE_SCREEN_POSITION_W;
+        break;
+
+      case SNAP_POSITION_E:
+      case SNAP_POSITION_EC:
+        position = window->horizontal ? XFCE_SCREEN_POSITION_FLOATING_H :
+            XFCE_SCREEN_POSITION_E;
+        break;
+
+      case SNAP_POSITION_S:
+      case SNAP_POSITION_SC:
+        position = window->horizontal ? XFCE_SCREEN_POSITION_S :
+            XFCE_SCREEN_POSITION_FLOATING_V;
+        break;
+
+      case SNAP_POSITION_N:
+      case SNAP_POSITION_NC:
+        position = window->horizontal ? XFCE_SCREEN_POSITION_N :
+            XFCE_SCREEN_POSITION_FLOATING_V;
+        break;
+
+      default:
+        panel_assert_not_reached ();
+        break;
+    }
+
+  xfce_panel_plugin_provider_set_screen_position (XFCE_PANEL_PLUGIN_PROVIDER (widget),
+                                                  position);
 }
 
 
 
-gboolean
-panel_window_is_composited (PanelWindow *window)
+GtkWidget *
+panel_window_new (void)
 {
-  panel_return_val_if_fail (PANEL_IS_WINDOW (window), FALSE);
-
-  return window->is_composited;
+  return g_object_new (PANEL_TYPE_WINDOW,
+                       "type", GTK_WINDOW_TOPLEVEL,
+                       NULL);
 }
 
 
 
 void
-panel_window_set_active_panel (PanelWindow *window,
-                               gboolean     active)
+panel_window_set_povider_info (PanelWindow *window,
+                               GtkWidget   *provider)
 {
   panel_return_if_fail (PANEL_IS_WINDOW (window));
+  panel_return_if_fail (XFCE_IS_PANEL_PLUGIN_PROVIDER (provider));
 
-  if (G_UNLIKELY ((window->active_timeout_id != 0) != active))
-    {
-      /* set new value */
-      if (active)
-        {
-          window->active_timeout_id = g_timeout_add_seconds (1,
-              (GSourceFunc) gtk_widget_queue_draw, window);
-        }
-      else
-        {
-          g_source_remove (window->active_timeout_id);
-          window->active_timeout_id = 0;
-        }
+  panel_window_set_plugin_size (provider, window);
+  panel_window_set_plugin_orientation (provider, window);
+  panel_window_set_screen_position (provider, window);
 
-      /* queue a redraw */
-      gtk_widget_queue_draw (GTK_WIDGET (window));
-    }
+  if (PANEL_IS_PLUGIN_EXTERNAL (provider))
+    panel_plugin_external_set_background_alpha (PANEL_PLUGIN_EXTERNAL (provider),
+        rint (PANEL_BASE_WINDOW (window)->background_alpha * 100.00));
 }
 
 
@@ -2220,14 +2027,6 @@ void
 panel_window_freeze_autohide (PanelWindow *window)
 {
   panel_return_if_fail (PANEL_IS_WINDOW (window));
-  panel_return_if_fail (window->autohide_block >= 0);
-
-  /* increase autohide block counter */
-  window->autohide_block++;
-
-  /* block autohide */
-  if (window->autohide_block == 1 && window->autohide_status != DISABLED)
-    panel_window_autohide_queue (window, BLOCKED);
 }
 
 
@@ -2236,12 +2035,4 @@ void
 panel_window_thaw_autohide (PanelWindow *window)
 {
   panel_return_if_fail (PANEL_IS_WINDOW (window));
-  panel_return_if_fail (window->autohide_block > 0);
-
-  /* decrease autohide block counter */
-  window->autohide_block--;
-
-  /* queue an autohide when needed */
-  if (window->autohide_block == 0 && window->autohide_status != DISABLED)
-    panel_window_autohide_queue (window, POPDOWN_QUEUED);
 }
diff --git a/panel/panel-window.h b/panel/panel-window.h
index 68990b8..21dfe68 100644
--- a/panel/panel-window.h
+++ b/panel/panel-window.h
@@ -1,6 +1,6 @@
 /* $Id$ */
 /*
- * Copyright (C) 2008-2009 Nick Schermer <nick at xfce.org>
+ * Copyright (C) 2008 Nick Schermer <nick at xfce.org>
  *
  * 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
@@ -24,10 +24,8 @@
 
 G_BEGIN_DECLS
 
-typedef struct _PanelWindowClass    PanelWindowClass;
-typedef struct _PanelWindow         PanelWindow;
-typedef enum   _PanelWindowSnapEdge PanelWindowSnapEdge;
-typedef enum   _PanelWindowBorders  PanelWindowBorders;
+typedef struct _PanelWindowClass PanelWindowClass;
+typedef struct _PanelWindow      PanelWindow;
 
 #define PANEL_TYPE_WINDOW            (panel_window_get_type ())
 #define PANEL_WINDOW(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), PANEL_TYPE_WINDOW, PanelWindow))
@@ -36,59 +34,16 @@ typedef enum   _PanelWindowBorders  PanelWindowBorders;
 #define PANEL_IS_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PANEL_TYPE_WINDOW))
 #define PANEL_WINDOW_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), PANEL_TYPE_WINDOW, PanelWindowClass))
 
-#define snap_edge_is_top(snap_edge)    (snap_edge == PANEL_SNAP_EGDE_NE || snap_edge == PANEL_SNAP_EGDE_NW || \
-                                        snap_edge == PANEL_SNAP_EGDE_NC || snap_edge == PANEL_SNAP_EGDE_N)
-#define snap_edge_is_bottom(snap_edge) (snap_edge == PANEL_SNAP_EGDE_SE || snap_edge == PANEL_SNAP_EGDE_SW || \
-                                        snap_edge == PANEL_SNAP_EGDE_SC || snap_edge == PANEL_SNAP_EGDE_S)
-#define snap_edge_is_left(snap_edge)   (snap_edge >= PANEL_SNAP_EGDE_W && snap_edge <= PANEL_SNAP_EGDE_SW)
-#define snap_edge_is_right(snap_edge)  (snap_edge >= PANEL_SNAP_EGDE_E && snap_edge <= PANEL_SNAP_EGDE_SE)
+GType      panel_window_get_type         (void) G_GNUC_CONST;
 
-#define PANEL_BORDER_ALL (PANEL_BORDER_LEFT | PANEL_BORDER_RIGHT | PANEL_BORDER_TOP | PANEL_BORDER_BOTTOM)
+GtkWidget *panel_window_new              (void);
 
+void       panel_window_set_povider_info (PanelWindow *window,
+                                          GtkWidget   *provider);
 
-enum _PanelWindowSnapEdge
-{
-  /* no snapping */
-  PANEL_SNAP_EGDE_NONE, /* 0  no snapping */
+void       panel_window_freeze_autohide  (PanelWindow *window);
 
-  /* right edge */
-  PANEL_SNAP_EGDE_E,    /* 1  right */
-  PANEL_SNAP_EGDE_NE,   /* 2  top right */
-  PANEL_SNAP_EGDE_EC,   /* 3  right center */
-  PANEL_SNAP_EGDE_SE,   /* 4  bottom right */
-
-  /* left edge */
-  PANEL_SNAP_EGDE_W,    /* 5  left */
-  PANEL_SNAP_EGDE_NW,   /* 6  top left */
-  PANEL_SNAP_EGDE_WC,   /* 7  left center */
-  PANEL_SNAP_EGDE_SW,   /* 8  bottom left */
-
-  /* top and bottom */
-  PANEL_SNAP_EGDE_NC,   /* 9  top center */
-  PANEL_SNAP_EGDE_SC,   /* 10 bottom center */
-  PANEL_SNAP_EGDE_N,    /* 11 top */
-  PANEL_SNAP_EGDE_S,    /* 12 bottom */
-};
-
-enum _PanelWindowBorders
-{
-  PANEL_BORDER_LEFT   = 1 << 0,
-  PANEL_BORDER_RIGHT  = 1 << 1,
-  PANEL_BORDER_TOP    = 1 << 2,
-  PANEL_BORDER_BOTTOM = 1 << 3,
-};
-
-
-GType                panel_window_get_type              (void) G_GNUC_CONST;
-
-gboolean             panel_window_is_composited         (PanelWindow         *window);
-
-void                 panel_window_set_active_panel      (PanelWindow         *window,
-                                                         gboolean             selected);
-
-void                 panel_window_freeze_autohide       (PanelWindow         *window);
-
-void                 panel_window_thaw_autohide         (PanelWindow         *window);
+void       panel_window_thaw_autohide    (PanelWindow *window);
 
 G_END_DECLS
 



More information about the Xfce4-commits mailing list