[Xfce4-commits] <xfce4-panel:andrzejr/deskbar-pager> pager: accumulated changes from andrzejr/deskbar-github branch.

Andrzej noreply at xfce.org
Mon Dec 12 16:00:12 CET 2011


Updating branch refs/heads/andrzejr/deskbar-pager
         to 11411a9a8919b17953d3a6be19e6ee6865bc39b1 (commit)
       from f9af320ee3f50582039e8f596c87948a37029770 (commit)

commit 11411a9a8919b17953d3a6be19e6ee6865bc39b1
Author: Andrzej <ndrwrdck at gmail.com>
Date:   Mon Dec 12 23:39:02 2011 +0900

    pager: accumulated changes from andrzejr/deskbar-github branch.
    
    Includes a modified copy of a WNCK pager.

 plugins/pager/Makefile.am     |    2 +
 plugins/pager/pager-buttons.c |  126 ++-
 plugins/pager/pager-buttons.h |    2 +
 plugins/pager/pager-wnck.c    | 2833 +++++++++++++++++++++++++++++++++++++++++
 plugins/pager/pager-wnck.h    |  107 ++
 plugins/pager/pager.c         |  106 ++-
 plugins/pager/pager.h         |   18 +
 7 files changed, 3166 insertions(+), 28 deletions(-)

diff --git a/plugins/pager/Makefile.am b/plugins/pager/Makefile.am
index ceb1ea7..742935e 100644
--- a/plugins/pager/Makefile.am
+++ b/plugins/pager/Makefile.am
@@ -17,6 +17,8 @@ libpager_la_SOURCES = \
 	$(libpager_built_sources) \
 	pager.c \
 	pager.h \
+	pager-wnck.h \
+	pager-wnck.c \
 	pager-buttons.h \
 	pager-buttons.c
 
diff --git a/plugins/pager/pager-buttons.c b/plugins/pager/pager-buttons.c
index b0a07fa..e201647 100644
--- a/plugins/pager/pager-buttons.c
+++ b/plugins/pager/pager-buttons.c
@@ -25,6 +25,7 @@
 #include <libxfce4panel/libxfce4panel.h>
 #include <common/panel-private.h>
 
+#include "pager.h"
 #include "pager-buttons.h"
 
 
@@ -76,6 +77,7 @@ struct _PagerButtons
 
   gint            rows;
   GtkOrientation  orientation;
+  PagerLayoutCorner starting_corner;
 };
 
 enum
@@ -83,7 +85,8 @@ enum
   PROP_0,
   PROP_SCREEN,
   PROP_ROWS,
-  PROP_ORIENTATION
+  PROP_ORIENTATION,
+  PROP_STARTING_CORNER
 };
 
 enum
@@ -131,6 +134,14 @@ pager_buttons_class_init (PagerButtonsClass *klass)
                                                      GTK_TYPE_ORIENTATION,
                                                      GTK_ORIENTATION_HORIZONTAL,
                                                      EXO_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_ORIENTATION,
+                                   g_param_spec_enum ("starting-corner",
+                                                      NULL, NULL,
+                                                      XFCE_TYPE_PAGER_LAYOUT_CORNER,
+                                                      PAGER_LAYOUT_CORNER_TOPLEFT,
+                                                      EXO_PARAM_READWRITE));
 }
 
 
@@ -141,6 +152,7 @@ pager_buttons_init (PagerButtons *pager)
   pager->rows = 1;
   pager->wnck_screen = NULL;
   pager->orientation = GTK_ORIENTATION_HORIZONTAL;
+  pager->starting_corner = PAGER_LAYOUT_CORNER_TOPLEFT;
   pager->buttons = NULL;
   pager->rebuild_id = 0;
 
@@ -170,6 +182,10 @@ pager_buttons_get_property (GObject    *object,
       g_value_set_enum (value, pager->orientation);
       break;
 
+    case PROP_STARTING_CORNER:
+      g_value_set_enum (value, pager->starting_corner);
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -212,6 +228,10 @@ pager_buttons_set_property (GObject      *object,
       pager_buttons_set_orientation (pager, g_value_get_enum (value));
       break;
 
+    case PROP_STARTING_CORNER:
+      pager_buttons_set_starting_corner (pager, g_value_get_enum (value));
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -269,6 +289,58 @@ pager_buttons_button_press_event (GtkWidget      *button,
 }
 
 
+static void
+pager_buttons_assign_position (PagerButtons  *pager, gint n, gint rows, gint cols, gint *row, gint *col)
+{
+  *row = *col = 0;
+  if (pager->orientation == GTK_ORIENTATION_HORIZONTAL)
+    switch (pager->starting_corner)
+      {
+      case PAGER_LAYOUT_CORNER_TOPLEFT:
+        *col = n / cols;
+        *row = n % cols;
+        break;
+
+      case PAGER_LAYOUT_CORNER_TOPRIGHT:
+        *col = n / cols;
+        *row = (cols - 1) - n % cols;
+        break;
+
+      case PAGER_LAYOUT_CORNER_BOTTOMLEFT:
+        *col = (rows - 1) - n / cols;
+        *row = n % cols;
+        break;
+
+      case PAGER_LAYOUT_CORNER_BOTTOMRIGHT:
+        *col = (rows - 1) - n / cols;
+        *row = (cols - 1) - n % cols;
+        break;
+      }
+  else
+    switch (pager->starting_corner)
+      {
+      case PAGER_LAYOUT_CORNER_TOPLEFT:
+        *col = n % cols;
+        *row = n / cols;
+        break;
+
+      case PAGER_LAYOUT_CORNER_TOPRIGHT:
+        *col = n % cols;
+        *row = (rows - 1) - n / cols;
+        break;
+
+      case PAGER_LAYOUT_CORNER_BOTTOMLEFT:
+        *col = (cols - 1) - n % cols;
+        *row = n / cols;
+        break;
+
+      case PAGER_LAYOUT_CORNER_BOTTOMRIGHT:
+        *col = (cols - 1) - n % cols;
+        *row = (rows - 1) - n / cols;
+        break;
+      }
+}
+
 
 static gboolean
 pager_buttons_rebuild_idle (gpointer user_data)
@@ -351,10 +423,10 @@ pager_buttons_rebuild_idle (gpointer user_data)
         cols++;
     }
 
-  if (pager->orientation != GTK_ORIENTATION_HORIZONTAL)
-    SWAP_INTEGER (rows, cols);
-
-  gtk_table_resize (GTK_TABLE (pager), rows, cols);
+  if (pager->orientation == GTK_ORIENTATION_HORIZONTAL)
+    gtk_table_resize (GTK_TABLE (pager), rows, cols);
+  else
+    gtk_table_resize (GTK_TABLE (pager), cols, rows);
 
   panel_plugin = gtk_widget_get_ancestor (GTK_WIDGET (pager), XFCE_TYPE_PANEL_PLUGIN);
 
@@ -387,18 +459,26 @@ pager_buttons_rebuild_idle (gpointer user_data)
 
           g_snprintf (text, sizeof (text), "%d", n + 1);
           label = gtk_label_new (text);
-          gtk_label_set_angle (GTK_LABEL (label),
-              pager->orientation == GTK_ORIENTATION_HORIZONTAL ? 0 : 270);
+          if (pager->orientation == GTK_ORIENTATION_HORIZONTAL)
+            gtk_label_set_angle (GTK_LABEL (label), 0);
+          else if (pager->starting_corner ==  PAGER_LAYOUT_CORNER_TOPLEFT ||
+                   pager->starting_corner ==  PAGER_LAYOUT_CORNER_BOTTOMLEFT)
+            gtk_label_set_angle (GTK_LABEL (label), 90);
+          else
+            gtk_label_set_angle (GTK_LABEL (label), 270);
           gtk_container_add (GTK_CONTAINER (button), label);
           gtk_widget_show (label);
 
-          row = n % cols;
-          col = n / cols;
+          pager->buttons = g_slist_prepend (pager->buttons, button);
+
+          row = col = 0;
+          pager_buttons_assign_position (pager, n, rows, cols, &row, &col);
 
           gtk_table_attach (GTK_TABLE (pager), button,
                             row, row + 1, col, col + 1,
                             GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND,
                             0, 0);
+
         }
     }
   else
@@ -421,15 +501,20 @@ pager_buttons_rebuild_idle (gpointer user_data)
           g_signal_connect_object (G_OBJECT (workspace), "name-changed",
               G_CALLBACK (pager_buttons_workspace_button_label), label, 0);
           pager_buttons_workspace_button_label (workspace, label);
-          gtk_label_set_angle (GTK_LABEL (label),
-              pager->orientation == GTK_ORIENTATION_HORIZONTAL ? 0 : 270);
+          if (pager->orientation == GTK_ORIENTATION_HORIZONTAL)
+            gtk_label_set_angle (GTK_LABEL (label), 0);
+          else if (pager->starting_corner ==  PAGER_LAYOUT_CORNER_TOPLEFT ||
+                   pager->starting_corner ==  PAGER_LAYOUT_CORNER_BOTTOMLEFT)
+            gtk_label_set_angle (GTK_LABEL (label), 90);
+          else
+            gtk_label_set_angle (GTK_LABEL (label), 270);
           gtk_container_add (GTK_CONTAINER (button), label);
           gtk_widget_show (label);
 
           pager->buttons = g_slist_prepend (pager->buttons, button);
 
-          row = n % cols;
-          col = n / cols;
+          row = col = 0;
+          pager_buttons_assign_position (pager, n, rows, cols, &row, &col);
 
           gtk_table_attach (GTK_TABLE (pager), button,
                             row, row + 1, col, col + 1,
@@ -647,3 +732,18 @@ pager_buttons_set_n_rows (PagerButtons *pager,
   pager->rows = rows;
   pager_buttons_queue_rebuild (pager);
 }
+
+
+void
+pager_buttons_set_starting_corner (PagerButtons      *pager,
+                                   PagerLayoutCorner  starting_corner)
+{
+  g_return_if_fail (XFCE_IS_PAGER_BUTTONS (pager));
+
+  if (pager->starting_corner == starting_corner)
+    return;
+
+  pager->starting_corner = starting_corner;
+  pager_buttons_queue_rebuild (pager);
+}
+
diff --git a/plugins/pager/pager-buttons.h b/plugins/pager/pager-buttons.h
index b8014f5..39b176a 100644
--- a/plugins/pager/pager-buttons.h
+++ b/plugins/pager/pager-buttons.h
@@ -45,6 +45,8 @@ void       pager_buttons_set_orientation (PagerButtons        *pager,
 
 void       pager_buttons_set_n_rows      (PagerButtons        *pager,
                                           gint                 rows);
+void       pager_buttons_set_starting_corner (PagerButtons       *pager,
+                                              PagerLayoutCorner   starting_corner);
 
 G_END_DECLS
 
diff --git a/plugins/pager/pager-wnck.c b/plugins/pager/pager-wnck.c
new file mode 100644
index 0000000..ef67f83
--- /dev/null
+++ b/plugins/pager/pager-wnck.c
@@ -0,0 +1,2833 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 2 -*- */
+/* vim: set sw=2 et: */
+/* pager object */
+
+/*
+ * Copyright (C) 2001 Havoc Pennington
+ * Copyright (C) 2003 Kim Woelders
+ * Copyright (C) 2003 Red Hat, Inc.
+ * Copyright (C) 2003, 2005-2007 Vincent Untz
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+
+#include <math.h>
+#include <glib/gi18n-lib.h>
+
+#include <gdk/gdkx.h>
+#include <libwnck/libwnck.h>
+
+#include "pager.h"
+#include "pager-wnck.h"
+
+#define PAGER_WNCK_NO_MANAGER_TOKEN 0 /* from wnck xutils.h */
+#define PAGER_WNCK_ACTIVATE_TIMEOUT 1000 /* from wnck private.h */
+
+
+/**
+ * SECTION:pager
+ * @short_description: a pager widget, showing the content of workspaces.
+ * @see_also: #WnckScreen
+ * @stability: Unstable
+ *
+ * A #PagerWnck shows a miniature view of the workspaces, representing managed
+ * windows by small rectangles, and allows the user to initiate various window
+ * manager actions by manipulating these representations. The #PagerWnck offers
+ * ways to move windows between workspaces and to change the current workspace.
+ *
+ * Alternatively, a #PagerWnck can be configured to only show the names of the
+ * workspace instead of their contents.
+ *
+ * The #PagerWnck is also responsible for setting the layout of the workspaces.
+ * Since only one application can be responsible for setting the layout on a
+ * screen, the #PagerWnck automatically tries to obtain the manager selection
+ * for the screen and only sets the layout if it owns the manager selection.
+ * See pager_wnck_set_orientation() and pager_wnck_set_n_rows() to change the
+ * layout.
+ */
+
+#define N_SCREEN_CONNECTIONS 11
+
+struct _PagerWnckPrivate
+{
+  WnckScreen *screen;
+  
+  int n_rows; /* really columns for vertical orientation */
+  PagerWnckDisplayMode display_mode;
+  PagerLayoutPolicy layout_policy;
+  PagerLayoutCorner starting_corner;
+  gboolean show_all_workspaces;
+  GtkShadowType shadow_type;
+  
+  GtkOrientation orientation;
+  int workspace_size;
+  guint screen_connections[N_SCREEN_CONNECTIONS];
+  int prelight; /* workspace mouse is hovering over */
+  gboolean prelight_dnd; /* is dnd happening? */
+
+  guint dragging :1;
+  int drag_start_x;
+  int drag_start_y;
+  WnckWindow *drag_window;
+
+  GdkPixbuf *bg_cache;
+
+  int layout_manager_token;
+
+  guint dnd_activate; /* GSource that triggers switching to this workspace during dnd */
+  guint dnd_time; /* time of last event during dnd (for delayed workspace activation) */
+};
+
+G_DEFINE_TYPE (PagerWnck, pager_wnck, GTK_TYPE_WIDGET);
+#define PAGER_WNCK_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), XFCE_TYPE_PAGER_WNCK, PagerWnckPrivate))
+
+enum
+{
+  dummy, /* remove this when you add more signals */
+  LAST_SIGNAL
+};
+
+
+#define POINT_IN_RECT(xcoord, ycoord, rect) \
+ ((xcoord) >= (rect).x &&                   \
+  (xcoord) <  ((rect).x + (rect).width) &&  \
+  (ycoord) >= (rect).y &&                   \
+  (ycoord) <  ((rect).y + (rect).height))
+
+/* static void pager_wnck_init        (PagerWnck      *pager); */
+/* static void pager_wnck_class_init  (PagerWnckClass *klass); */
+static void pager_wnck_finalize    (GObject        *object);
+
+static void     pager_wnck_realize       (GtkWidget        *widget);
+static void     pager_wnck_unrealize     (GtkWidget        *widget);
+static void     pager_wnck_size_request  (GtkWidget        *widget,
+                                          GtkRequisition   *requisition);
+static void     pager_wnck_size_allocate (GtkWidget        *widget,
+                                          GtkAllocation    *allocation);
+static gboolean pager_wnck_expose_event  (GtkWidget        *widget,
+                                          GdkEventExpose   *event);
+static gboolean pager_wnck_button_press  (GtkWidget        *widget,
+                                          GdkEventButton   *event);
+static gboolean pager_wnck_drag_motion   (GtkWidget        *widget,
+                                          GdkDragContext   *context,
+                                          gint              x,
+                                          gint              y,
+                                          guint             time);
+static void pager_wnck_drag_motion_leave (GtkWidget        *widget,
+                                          GdkDragContext   *context,
+                                          guint             time);
+static gboolean pager_wnck_drag_drop	 (GtkWidget        *widget,
+					  GdkDragContext   *context,
+					  gint              x,
+					  gint              y,
+					  guint             time);
+static void pager_wnck_drag_data_received (GtkWidget          *widget,
+			  	           GdkDragContext     *context,
+				           gint                x,
+				           gint                y,
+				           GtkSelectionData   *selection_data,
+				           guint               info,
+				           guint               time_);
+static void pager_wnck_drag_data_get      (GtkWidget        *widget,
+		                           GdkDragContext   *context,
+		                           GtkSelectionData *selection_data,
+		                           guint             info,
+		                           guint             time);
+static void pager_wnck_drag_end		  (GtkWidget        *widget,
+					   GdkDragContext   *context);
+static gboolean pager_wnck_motion        (GtkWidget        *widget,
+                                          GdkEventMotion   *event);
+static gboolean pager_wnck_leave_notify	 (GtkWidget          *widget,
+					  GdkEventCrossing   *event);
+static gboolean pager_wnck_button_release (GtkWidget        *widget,
+                                           GdkEventButton   *event);
+static gboolean pager_wnck_focus         (GtkWidget        *widget,
+                                          GtkDirectionType  direction);
+static gboolean pager_wnck_query_tooltip (GtkWidget  *widget,
+                                          gint        x,
+                                          gint        y,
+                                          gboolean    keyboard_tip,
+                                          GtkTooltip *tooltip);
+static void workspace_name_changed_callback (WnckWorkspace *workspace,
+                                             gpointer       data);
+
+static gboolean pager_wnck_window_state_is_relevant (int state);
+static gint pager_wnck_window_get_workspace   (WnckWindow  *window,
+                                               gboolean     is_state_relevant);
+static void pager_wnck_queue_draw_workspace   (PagerWnck   *pager,
+					       gint	    i);
+static void pager_wnck_queue_draw_window (PagerWnck	   *pager,
+					  WnckWindow	   *window);
+
+static void pager_wnck_connect_screen    (PagerWnck  *pager);
+static void pager_wnck_connect_window    (PagerWnck  *pager,
+                                          WnckWindow *window);
+static void pager_wnck_disconnect_screen (PagerWnck  *pager);
+static void pager_wnck_disconnect_window (PagerWnck  *pager,
+                                          WnckWindow *window);
+
+static gboolean pager_wnck_set_layout_hint (PagerWnck  *pager);
+
+static void pager_wnck_clear_drag (PagerWnck *pager);
+static void pager_wnck_check_prelight (PagerWnck *pager,
+				       gint	  x,
+				       gint	  y,
+				       gboolean	  dnd);
+
+static GdkPixbuf* pager_wnck_get_background (PagerWnck *pager,
+                                             int        width,
+                                             int        height);
+
+static AtkObject* pager_wnck_get_accessible (GtkWidget *widget);
+static void
+_pager_wnck_window_set_as_drag_icon (WnckWindow     *window,
+                               GdkDragContext *context,
+                               GtkWidget      *drag_source);
+static void           _pager_wnck_set_screen           (PagerWnck *pager);
+
+static GdkPixbuf*     _pager_wnck_gdk_pixbuf_get_from_pixmap (GdkPixbuf   *dest,
+							      Pixmap       xpixmap,
+							      int          src_x,
+							      int          src_y,
+							      int          dest_x,
+							      int          dest_y,
+							      int          width,
+							      int          height);
+static Display*       _pager_wnck_get_default_display         (void);
+
+
+
+static void
+pager_wnck_init (PagerWnck *pager)
+{  
+  int i;
+  static const GtkTargetEntry targets[] = {
+    { "application/x-wnck-window-id", 0, 0}
+  };
+
+  pager->priv = PAGER_WNCK_GET_PRIVATE (pager);
+
+  pager->priv->n_rows = 1;
+  pager->priv->display_mode = PAGER_WNCK_DISPLAY_CONTENT;
+  pager->priv->show_all_workspaces = TRUE;
+  pager->priv->shadow_type = GTK_SHADOW_NONE;
+
+  pager->priv->orientation = GTK_ORIENTATION_HORIZONTAL;
+  pager->priv->layout_policy = PAGER_LAYOUT_POLICY_WIDTH_FOR_HEIGHT;
+  pager->priv->starting_corner = PAGER_LAYOUT_CORNER_TOPLEFT;
+  pager->priv->workspace_size = 48;
+
+  for (i = 0; i < N_SCREEN_CONNECTIONS; i++)
+    pager->priv->screen_connections[i] = 0;
+
+  pager->priv->prelight = -1;
+  pager->priv->prelight_dnd = FALSE;
+
+  pager->priv->dragging = FALSE;
+  pager->priv->drag_start_x = 0;
+  pager->priv->drag_start_y = 0;
+  pager->priv->drag_window = NULL;
+
+  pager->priv->bg_cache = NULL;
+
+  pager->priv->layout_manager_token = PAGER_WNCK_NO_MANAGER_TOKEN;
+
+  pager->priv->dnd_activate = 0;
+  pager->priv->dnd_time = 0;
+
+  g_object_set (pager, "has-tooltip", TRUE, NULL);
+
+  gtk_drag_dest_set (GTK_WIDGET (pager), 0, targets, G_N_ELEMENTS (targets), GDK_ACTION_MOVE);
+  gtk_widget_set_can_focus (GTK_WIDGET (pager), TRUE);
+}
+
+static void
+pager_wnck_class_init (PagerWnckClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (PagerWnckPrivate));
+
+  object_class->finalize = pager_wnck_finalize;
+
+  widget_class->realize = pager_wnck_realize;
+  widget_class->unrealize = pager_wnck_unrealize;
+  widget_class->size_request = pager_wnck_size_request;
+  widget_class->size_allocate = pager_wnck_size_allocate;
+  widget_class->expose_event = pager_wnck_expose_event;
+  widget_class->button_press_event = pager_wnck_button_press;
+  widget_class->button_release_event = pager_wnck_button_release;
+  widget_class->motion_notify_event = pager_wnck_motion;
+  widget_class->leave_notify_event = pager_wnck_leave_notify;
+  widget_class->focus = pager_wnck_focus;
+  widget_class->get_accessible = pager_wnck_get_accessible;
+  widget_class->drag_leave = pager_wnck_drag_motion_leave;
+  widget_class->drag_motion = pager_wnck_drag_motion;
+  widget_class->drag_drop = pager_wnck_drag_drop;
+  widget_class->drag_data_received = pager_wnck_drag_data_received;
+  widget_class->drag_data_get = pager_wnck_drag_data_get;
+  widget_class->drag_end = pager_wnck_drag_end;
+  widget_class->query_tooltip = pager_wnck_query_tooltip;
+}
+
+static void
+pager_wnck_finalize (GObject *object)
+{
+  PagerWnck *pager;
+
+  pager = XFCE_PAGER_WNCK (object);
+
+  if (pager->priv->bg_cache)
+    {
+      g_object_unref (G_OBJECT (pager->priv->bg_cache));
+      pager->priv->bg_cache = NULL;
+    }
+
+  if (pager->priv->dnd_activate != 0)
+    {
+      g_source_remove (pager->priv->dnd_activate);
+      pager->priv->dnd_activate = 0;
+    }
+  
+  G_OBJECT_CLASS (pager_wnck_parent_class)->finalize (object);
+}
+
+static void
+_pager_wnck_set_screen (PagerWnck *pager)
+{
+  GdkScreen *gdkscreen;
+
+  if (!gtk_widget_has_screen (GTK_WIDGET (pager)))
+    return;
+
+  gdkscreen = gtk_widget_get_screen (GTK_WIDGET (pager));
+  pager->priv->screen = wnck_screen_get (gdk_screen_get_number (gdkscreen));
+
+  if (!pager_wnck_set_layout_hint (pager))
+    {
+      _WnckLayoutOrientation orientation;
+
+      /* we couldn't set the layout on the screen. This means someone else owns
+       * it. Let's at least show the correct layout. */
+      //_wnck_screen_get_workspace_layout (pager->priv->screen,
+      //                                   &orientation,
+      //                                   &pager->priv->n_rows,
+      //                                   NULL, NULL);
+
+      /* test in this order to default to horizontal in case there was in issue
+       * when fetching the layout */
+      if (orientation == WNCK_LAYOUT_ORIENTATION_VERTICAL)
+        pager->priv->orientation = GTK_ORIENTATION_VERTICAL;
+      else
+        pager->priv->orientation = GTK_ORIENTATION_HORIZONTAL;
+
+      gtk_widget_queue_resize (GTK_WIDGET (pager));
+    }
+
+  pager_wnck_connect_screen (pager);
+}
+
+static void
+pager_wnck_realize (GtkWidget *widget)
+{
+
+  GdkWindowAttr attributes;
+  gint attributes_mask;
+  PagerWnck *pager;
+  GtkAllocation allocation;
+  GdkWindow *window;
+  GtkStyle *style;
+  GtkStyle *new_style;
+
+  pager = XFCE_PAGER_WNCK (widget);
+
+  /* do not call the parent class realize since we're doing things a bit
+   * differently here */
+  gtk_widget_set_realized (widget, TRUE);
+
+  gtk_widget_get_allocation (widget, &allocation);
+
+  attributes.window_type = GDK_WINDOW_CHILD;
+  attributes.x = allocation.x;
+  attributes.y = allocation.y;
+  attributes.width = allocation.width;
+  attributes.height = allocation.height;
+  attributes.wclass = GDK_INPUT_OUTPUT;
+  attributes.visual = gtk_widget_get_visual (widget);
+  attributes.colormap = gtk_widget_get_colormap (widget);
+  attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK |
+	  		  GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
+			  GDK_LEAVE_NOTIFY_MASK | GDK_POINTER_MOTION_MASK |
+			  GDK_POINTER_MOTION_HINT_MASK;
+
+  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
+
+  window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
+  gtk_widget_set_window (widget, window);
+  gdk_window_set_user_data (window, widget);
+
+  style = gtk_widget_get_style (widget);
+
+  new_style = gtk_style_attach (style, window);
+  if (new_style != style)
+    {
+      gtk_widget_set_style (widget, style);
+      style = new_style;
+    }
+
+  gtk_style_set_background (style, window, GTK_STATE_NORMAL);
+
+  /* connect to the screen of this pager. In theory, this will already have
+   * been done in pager_wnck_size_request() */
+  if (pager->priv->screen == NULL)
+    _pager_wnck_set_screen (pager);
+  g_assert (pager->priv->screen != NULL);
+}
+
+static void
+pager_wnck_unrealize (GtkWidget *widget)
+{
+  PagerWnck *pager;
+  
+  pager = XFCE_PAGER_WNCK (widget);
+
+  pager_wnck_clear_drag (pager);
+  pager->priv->prelight = -1;
+  pager->priv->prelight_dnd = FALSE;
+
+  wnck_screen_release_workspace_layout (pager->priv->screen,
+                                        pager->priv->layout_manager_token);
+  pager->priv->layout_manager_token = PAGER_WNCK_NO_MANAGER_TOKEN;
+  
+  pager_wnck_disconnect_screen (pager);
+  pager->priv->screen = NULL;
+
+  GTK_WIDGET_CLASS (pager_wnck_parent_class)->unrealize (widget);
+}
+
+static void
+pager_wnck_size_request  (GtkWidget      *widget,
+                          GtkRequisition *requisition)
+{
+  PagerWnck *pager;
+  int n_spaces;
+  int spaces_per_row;
+  double screen_aspect;
+  int other_dimension_size;
+  int size;
+  int n_rows;
+  int focus_width;
+  WnckWorkspace *space;
+
+  pager = XFCE_PAGER_WNCK (widget);
+  
+  /* if we're not realized, we don't know about our screen yet */
+  if (pager->priv->screen == NULL)
+    _pager_wnck_set_screen (pager);
+  g_assert (pager->priv->screen != NULL);
+
+  n_spaces = wnck_screen_get_workspace_count (pager->priv->screen);
+
+  g_assert (pager->priv->n_rows > 0);
+  spaces_per_row = (n_spaces + pager->priv->n_rows - 1) / pager->priv->n_rows;
+  space = wnck_screen_get_workspace (pager->priv->screen, 0);
+  
+  if (pager->priv->layout_policy == PAGER_LAYOUT_POLICY_HEIGHT_FOR_WIDTH)
+    {
+      if (space) {
+        screen_aspect =
+              (double) wnck_workspace_get_height (space) /
+              (double) wnck_workspace_get_width (space);
+      } else {
+        screen_aspect =
+              (double) wnck_screen_get_height (pager->priv->screen) /
+              (double) wnck_screen_get_width (pager->priv->screen);
+      }
+
+      /* TODO: Handle PAGER_WNCK_DISPLAY_NAME for this case */
+
+      if (pager->priv->show_all_workspaces)
+	{
+	  size = pager->priv->workspace_size;
+	  n_rows = pager->priv->n_rows;
+	}
+      else
+	{
+	  size = pager->priv->workspace_size;
+	  n_rows = 1;
+	  spaces_per_row = 1;
+	}
+      
+      other_dimension_size = screen_aspect * size;
+      
+      if (pager->priv->orientation == GTK_ORIENTATION_VERTICAL)
+	{
+	  requisition->width = size * n_rows + (n_rows - 1);
+	  requisition->height = other_dimension_size * spaces_per_row  + (spaces_per_row - 1);
+	}
+      else
+	{
+	  requisition->width = size * spaces_per_row + (spaces_per_row - 1);
+	  requisition->height = other_dimension_size * n_rows  + (n_rows - 1);
+	}
+    }
+  else
+    {
+      if (space) {
+        screen_aspect =
+              (double) wnck_workspace_get_width (space) /
+              (double) wnck_workspace_get_height (space);
+      } else {
+        screen_aspect =
+              (double) wnck_screen_get_width (pager->priv->screen) /
+              (double) wnck_screen_get_height (pager->priv->screen);
+      }
+
+      if (pager->priv->show_all_workspaces)
+	{
+	  size = pager->priv->workspace_size;
+	  n_rows = pager->priv->n_rows;
+	}
+      else
+	{
+	  size = pager->priv->workspace_size;
+	  n_rows = 1;
+	  spaces_per_row = 1;
+	}
+
+      if (pager->priv->display_mode == PAGER_WNCK_DISPLAY_CONTENT)
+	{
+	  other_dimension_size = screen_aspect * size;
+	}
+      else
+	{
+	  int i, w;
+	  WnckScreen *screen;
+	  PangoLayout *layout;
+
+	  n_spaces = wnck_screen_get_workspace_count (pager->priv->screen);
+	  layout = gtk_widget_create_pango_layout  (widget, NULL);
+	  screen = pager->priv->screen;
+	  other_dimension_size = 1;
+	  
+	  for (i = 0; i < n_spaces; i++)
+	    {
+	      pango_layout_set_text (layout,
+				     wnck_workspace_get_name (wnck_screen_get_workspace (screen, i)),
+				     -1);
+	      pango_layout_get_pixel_size (layout, &w, NULL);
+	      other_dimension_size = MAX (other_dimension_size, w);
+	    }
+	  
+	  g_object_unref (layout);
+	  
+	  other_dimension_size += 2;
+	}
+      
+      if (pager->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
+	{
+	  requisition->width = other_dimension_size * spaces_per_row + (spaces_per_row - 1);
+	  requisition->height = size * n_rows + (n_rows - 1);
+	}
+      else
+	{
+	  requisition->width = other_dimension_size * n_rows + (n_rows - 1);
+	  requisition->height = size * spaces_per_row + (spaces_per_row - 1);
+	}
+    }
+
+  if (pager->priv->shadow_type != GTK_SHADOW_NONE)
+    {
+      GtkStyle *style;
+
+      style = gtk_widget_get_style (widget);
+
+      requisition->width += 2 * style->xthickness;
+      requisition->height += 2 * style->ythickness;
+    }
+
+  gtk_widget_style_get (widget,
+			"focus-line-width", &focus_width,
+			NULL);
+                                                                                                             
+  requisition->width  += 2 * focus_width;
+  requisition->height += 2 * focus_width;
+}
+
+static void
+pager_wnck_size_allocate (GtkWidget      *widget,
+                          GtkAllocation  *allocation)
+{
+  PagerWnck *pager;
+  int workspace_size;
+  int focus_width;
+  int width;
+  int height;
+  int n_spaces;
+  int spaces_per_row;
+
+  pager = XFCE_PAGER_WNCK (widget);
+
+  gtk_widget_style_get (GTK_WIDGET (pager),
+			"focus-line-width", &focus_width,
+			NULL);
+
+  width  = allocation->width  - 2 * focus_width;
+  height = allocation->height - 2* focus_width;
+
+  if (pager->priv->shadow_type != GTK_SHADOW_NONE)
+    {
+      GtkStyle *style;
+
+      style = gtk_widget_get_style (widget);
+
+      width  -= 2 * style->xthickness;
+      height -= 2 * style->ythickness;
+    }
+
+  g_assert (pager->priv->n_rows > 0);
+
+  n_spaces = wnck_screen_get_workspace_count (pager->priv->screen);
+  spaces_per_row = (n_spaces + pager->priv->n_rows - 1) / pager->priv->n_rows;
+  if (spaces_per_row == 0)
+    spaces_per_row = 1;
+
+  if (pager->priv->layout_policy == PAGER_LAYOUT_POLICY_HEIGHT_FOR_WIDTH)
+    {
+      if (pager->priv->show_all_workspaces)
+	{
+	  if (pager->priv->orientation == GTK_ORIENTATION_VERTICAL)
+	    workspace_size = (width - (pager->priv->n_rows - 1))  / pager->priv->n_rows;
+	  else
+	    workspace_size = (width - (spaces_per_row - 1)) / spaces_per_row;
+	}
+      else
+	workspace_size = width;
+    }
+  else
+    {
+      if (pager->priv->show_all_workspaces)
+	{
+	  if (pager->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
+	    workspace_size = (height - (pager->priv->n_rows - 1))/ pager->priv->n_rows;
+	  else
+	    workspace_size = (height - (spaces_per_row - 1)) / spaces_per_row;
+	}
+      else
+	workspace_size = height;
+    }
+
+  if (workspace_size != pager->priv->workspace_size)
+    {
+      pager->priv->workspace_size = workspace_size;
+      gtk_widget_queue_resize (GTK_WIDGET (widget));
+      return;
+    }
+
+  GTK_WIDGET_CLASS (pager_wnck_parent_class)->size_allocate (widget,
+                                                             allocation);
+}
+
+static void
+pager_wnck_get_workspace_rect (PagerWnck    *pager,
+                    int           space,
+                    GdkRectangle *rect)
+{
+  int hsize, vsize;
+  int n_spaces;
+  int spaces_per_row;
+  GtkWidget *widget;
+  int col, row;
+  GtkAllocation allocation;
+  GtkStyle *style;
+  int focus_width;
+
+  widget = GTK_WIDGET (pager);
+
+  gtk_widget_get_allocation (widget, &allocation);
+
+  style = gtk_widget_get_style (widget);
+  gtk_widget_style_get (widget,
+			"focus-line-width", &focus_width,
+			NULL);
+
+  if (!pager->priv->show_all_workspaces)
+    {
+      WnckWorkspace *active_space;
+  
+      active_space = wnck_screen_get_active_workspace (pager->priv->screen);
+
+      if (active_space && space == wnck_workspace_get_number (active_space))
+	{
+	  rect->x = focus_width;
+	  rect->y = focus_width;
+	  rect->width = allocation.width - 2 * focus_width;
+	  rect->height = allocation.height - 2 * focus_width;
+
+	  if (pager->priv->shadow_type != GTK_SHADOW_NONE)
+	    {
+	      rect->x += style->xthickness;
+	      rect->y += style->ythickness;
+	      rect->width -= 2 * style->xthickness;
+	      rect->height -= 2 * style->ythickness;
+	    }
+	}
+      else
+	{
+	  rect->x = 0;
+	  rect->y = 0;
+	  rect->width = 0;
+	  rect->height = 0;
+	}
+
+      return;
+    }
+
+  hsize = allocation.width - 2 * focus_width;
+  vsize = allocation.height - 2 * focus_width;
+
+  if (pager->priv->shadow_type != GTK_SHADOW_NONE)
+    {
+      hsize -= 2 * style->xthickness;
+      vsize -= 2 * style->ythickness;
+    }
+  
+  n_spaces = wnck_screen_get_workspace_count (pager->priv->screen);
+
+  g_assert (pager->priv->n_rows > 0);
+  spaces_per_row = (n_spaces + pager->priv->n_rows - 1) / pager->priv->n_rows;
+  
+  if (pager->priv->orientation == GTK_ORIENTATION_VERTICAL)
+    {      
+      rect->width = (hsize - (pager->priv->n_rows - 1)) / pager->priv->n_rows;
+      rect->height = (vsize - (spaces_per_row - 1)) / spaces_per_row;
+
+      switch (pager->priv->starting_corner)
+	{
+	case PAGER_LAYOUT_CORNER_TOPLEFT:
+	  col = space / spaces_per_row;
+	  row = space % spaces_per_row;
+	  break;
+
+	case PAGER_LAYOUT_CORNER_TOPRIGHT:
+	  col = (pager->priv->n_rows - 1) - space / spaces_per_row;
+	  row = space % spaces_per_row;
+	  break;
+
+	case PAGER_LAYOUT_CORNER_BOTTOMLEFT:
+	  col = space / spaces_per_row;
+	  row = (spaces_per_row - 1) - space % spaces_per_row;
+	  break;
+
+	case PAGER_LAYOUT_CORNER_BOTTOMRIGHT:
+	  col = (pager->priv->n_rows - 1) - space / spaces_per_row;
+	  row = (spaces_per_row - 1) - space % spaces_per_row;
+	  break;
+
+	default:
+	  row = 0;
+	  col = 0;
+	  break;
+	}
+
+      if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
+        col = pager->priv->n_rows - col - 1;
+
+      rect->x = (rect->width + 1) * col; 
+      rect->y = (rect->height + 1) * row;
+      
+      if (col == pager->priv->n_rows - 1)
+	rect->width = hsize - rect->x;
+      
+      if (row  == spaces_per_row - 1)
+	rect->height = vsize - rect->y;
+    }
+  else
+    {
+      rect->width = (hsize - (spaces_per_row - 1)) / spaces_per_row;
+      rect->height = (vsize - (pager->priv->n_rows - 1)) / pager->priv->n_rows;
+      
+      switch (pager->priv->starting_corner)
+	{
+	case PAGER_LAYOUT_CORNER_TOPLEFT:
+	  row = space / spaces_per_row;
+	  col = space % spaces_per_row;
+	  break;
+
+	case PAGER_LAYOUT_CORNER_TOPRIGHT:
+	  row = space / spaces_per_row;
+	  col = (spaces_per_row - 1) - space % spaces_per_row;
+	  break;
+
+	case PAGER_LAYOUT_CORNER_BOTTOMLEFT:
+	  row = (pager->priv->n_rows - 1) - space / spaces_per_row;
+	  col = space % spaces_per_row;
+	  break;
+
+	case PAGER_LAYOUT_CORNER_BOTTOMRIGHT:
+	  row = (pager->priv->n_rows - 1) - space / spaces_per_row;
+	  col = (spaces_per_row - 1) - space % spaces_per_row;
+	  break;
+
+	default:
+	  row = 0;
+	  col = 0;
+	  break;
+	}
+
+      if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
+        col = spaces_per_row - col - 1;
+
+      rect->x = (rect->width + 1) * col; 
+      rect->y = (rect->height + 1) * row;
+
+      if (col == spaces_per_row - 1)
+	rect->width = hsize - rect->x;
+      
+      if (row  == pager->priv->n_rows - 1)
+	rect->height = vsize - rect->y;
+    }
+
+  rect->x += focus_width;
+  rect->y += focus_width;
+
+  if (pager->priv->shadow_type != GTK_SHADOW_NONE)
+    {
+      rect->x += style->xthickness;
+      rect->y += style->ythickness;
+    }
+}
+
+static gboolean
+pager_wnck_window_state_is_relevant (int state)
+{
+  return (state & (WNCK_WINDOW_STATE_HIDDEN | WNCK_WINDOW_STATE_SKIP_PAGER)) ? FALSE : TRUE;
+}
+
+static gint
+pager_wnck_window_get_workspace (WnckWindow *window,
+                                 gboolean    is_state_relevant)
+{
+  gint state;
+  WnckWorkspace *workspace;
+
+  state = wnck_window_get_state (window);
+  if (is_state_relevant && !pager_wnck_window_state_is_relevant (state))
+    return -1;
+  workspace = wnck_window_get_workspace (window);
+  if (workspace == NULL && wnck_window_is_pinned (window))
+    workspace = wnck_screen_get_active_workspace (wnck_window_get_screen (window));
+
+  return workspace ? wnck_workspace_get_number (workspace) : -1;
+}
+
+static GList*
+get_windows_for_workspace_in_bottom_to_top (WnckScreen    *screen,
+                                            WnckWorkspace *workspace)
+{
+  GList *result;
+  GList *windows;
+  GList *tmp;
+  int workspace_num;
+  
+  result = NULL;
+  workspace_num = wnck_workspace_get_number (workspace);
+
+  windows = wnck_screen_get_windows_stacked (screen);
+  for (tmp = windows; tmp != NULL; tmp = tmp->next)
+    {
+      WnckWindow *win = WNCK_WINDOW (tmp->data);
+      if (pager_wnck_window_get_workspace (win, TRUE) == workspace_num)
+	result = g_list_prepend (result, win);
+    }
+
+  result = g_list_reverse (result);
+
+  return result;
+}
+
+static void
+get_window_rect (WnckWindow         *window,
+                 const GdkRectangle *workspace_rect,
+                 GdkRectangle       *rect)
+{
+  double width_ratio, height_ratio;
+  int x, y, width, height;
+  WnckWorkspace *workspace;
+  GdkRectangle unclipped_win_rect;
+  
+  workspace = wnck_window_get_workspace (window);
+  if (workspace == NULL)
+    workspace = wnck_screen_get_active_workspace (wnck_window_get_screen (window));
+
+  /* scale window down by same ratio we scaled workspace down */
+  width_ratio = (double) workspace_rect->width / (double) wnck_workspace_get_width (workspace);
+  height_ratio = (double) workspace_rect->height / (double) wnck_workspace_get_height (workspace);
+  
+  wnck_window_get_geometry (window, &x, &y, &width, &height);
+  
+  x += wnck_workspace_get_viewport_x (workspace);
+  y += wnck_workspace_get_viewport_y (workspace);
+  x = x * width_ratio + 0.5;
+  y = y * height_ratio + 0.5;
+  width = width * width_ratio + 0.5;
+  height = height * height_ratio + 0.5;
+  
+  x += workspace_rect->x;
+  y += workspace_rect->y;
+  
+  if (width < 3)
+    width = 3;
+  if (height < 3)
+    height = 3;
+
+  unclipped_win_rect.x = x;
+  unclipped_win_rect.y = y;
+  unclipped_win_rect.width = width;
+  unclipped_win_rect.height = height;
+
+  gdk_rectangle_intersect ((GdkRectangle *) workspace_rect, &unclipped_win_rect, rect);
+}
+
+static void
+draw_window (GdkDrawable        *drawable,
+             GtkWidget          *widget,
+             WnckWindow         *win,
+             const GdkRectangle *winrect,
+             GtkStateType        state,
+             gboolean            translucent)
+{
+  GtkStyle *style;
+  cairo_t *cr;
+  GdkPixbuf *icon;
+  int icon_x, icon_y, icon_w, icon_h;
+  gboolean is_active;
+  GdkColor *color;
+  gdouble translucency;
+
+  style = gtk_widget_get_style (widget);
+
+  is_active = wnck_window_is_active (win);
+  translucency = translucent ? 0.4 : 1.0;
+
+  cr = gdk_cairo_create (drawable);
+  cairo_rectangle (cr, winrect->x, winrect->y, winrect->width, winrect->height);
+  cairo_clip (cr);
+
+  if (is_active)
+    color = &style->light[state];
+  else
+    color = &style->bg[state];
+  cairo_set_source_rgba (cr,
+                         color->red / 65535.,
+                         color->green / 65535.,
+                         color->blue / 65535.,
+                         translucency);
+  cairo_rectangle (cr,
+                   winrect->x + 1, winrect->y + 1,
+                   MAX (0, winrect->width - 2), MAX (0, winrect->height - 2));
+  cairo_fill (cr);
+
+  icon = wnck_window_get_icon (win);
+
+  icon_w = icon_h = 0;
+          
+  if (icon)
+    {              
+      icon_w = gdk_pixbuf_get_width (icon);
+      icon_h = gdk_pixbuf_get_height (icon);
+
+      /* If the icon is too big, fall back to mini icon.
+       * We don't arbitrarily scale the icon, because it's
+       * just too slow on my Athlon 850.
+       */
+      if (icon_w > (winrect->width - 2) ||
+          icon_h > (winrect->height - 2))
+        {
+          icon = wnck_window_get_mini_icon (win);
+          if (icon)
+            {
+              icon_w = gdk_pixbuf_get_width (icon);
+              icon_h = gdk_pixbuf_get_height (icon);
+
+              /* Give up. */
+              if (icon_w > (winrect->width - 2) ||
+                  icon_h > (winrect->height - 2))
+                icon = NULL;
+            }
+        }
+    }
+
+  if (icon)
+    {
+      icon_x = winrect->x + (winrect->width - icon_w) / 2;
+      icon_y = winrect->y + (winrect->height - icon_h) / 2;
+                
+      cairo_save (cr);
+      gdk_cairo_set_source_pixbuf (cr, icon, icon_x, icon_y);
+      cairo_rectangle (cr, icon_x, icon_y, icon_w, icon_h);
+      cairo_clip (cr);
+      cairo_paint_with_alpha (cr, translucency);
+      cairo_restore (cr);
+    }
+          
+  if (is_active)
+    color = &style->fg[state];
+  else
+    color = &style->fg[state];
+  cairo_set_source_rgba (cr,
+                         color->red / 65535.,
+                         color->green / 65535.,
+                         color->blue / 65535.,
+                         translucency);
+  cairo_set_line_width (cr, 1.0);
+  cairo_rectangle (cr,
+                   winrect->x + 0.5, winrect->y + 0.5,
+                   MAX (0, winrect->width - 1), MAX (0, winrect->height - 1));
+  cairo_stroke (cr);
+
+  cairo_destroy (cr);
+}            
+
+static WnckWindow *
+window_at_point (PagerWnck     *pager,
+                 WnckWorkspace *space,
+                 GdkRectangle  *space_rect,
+                 int            x,
+                 int            y)
+{
+  WnckWindow *window;
+  GList *windows;
+  GList *tmp;
+
+  window = NULL;
+
+  windows = get_windows_for_workspace_in_bottom_to_top (pager->priv->screen,
+                                                        space);
+
+  /* clicks on top windows first */
+  windows = g_list_reverse (windows);
+
+  for (tmp = windows; tmp != NULL; tmp = tmp->next)
+    {
+      WnckWindow *win = WNCK_WINDOW (tmp->data);
+      GdkRectangle winrect;
+
+      get_window_rect (win, space_rect, &winrect);
+
+      if (POINT_IN_RECT (x, y, winrect))
+        {
+          /* wnck_window_activate (win); */
+          window = win;
+          break;
+        }
+    }
+
+  g_list_free (windows);
+
+  return window;
+}
+
+static int
+workspace_at_point (PagerWnck *pager,
+                    int        x,
+                    int        y,
+                    int       *viewport_x,
+                    int       *viewport_y)
+{
+  GtkWidget *widget;
+  int i;
+  int n_spaces;
+  GtkAllocation allocation;
+  int focus_width;
+  int xthickness;
+  int ythickness;
+
+  widget = GTK_WIDGET (pager);
+
+  gtk_widget_get_allocation (widget, &allocation);
+
+  gtk_widget_style_get (GTK_WIDGET (pager),
+			"focus-line-width", &focus_width,
+			NULL);
+
+  if (pager->priv->shadow_type != GTK_SHADOW_NONE)
+    {
+      GtkStyle *style;
+
+      style = gtk_widget_get_style (widget);
+
+      xthickness = focus_width + style->xthickness;
+      ythickness = focus_width + style->ythickness;
+    }
+  else
+    {
+      xthickness = focus_width;
+      ythickness = focus_width;
+    }
+
+  n_spaces = wnck_screen_get_workspace_count (pager->priv->screen);
+  
+  i = 0;
+  while (i < n_spaces)
+    {
+      GdkRectangle rect;
+      
+      pager_wnck_get_workspace_rect (pager, i, &rect);
+
+      /* If workspace is on the edge, pretend points on the frame belong to the
+       * workspace.
+       * Else, pretend the right/bottom line separating two workspaces belong
+       * to the workspace.
+       */
+
+      if (rect.x == xthickness)
+        {
+          rect.x = 0;
+          rect.width += xthickness;
+        }
+      if (rect.y == ythickness)
+        {
+          rect.y = 0;
+          rect.height += ythickness;
+        }
+      if (rect.y + rect.height == allocation.height - ythickness)
+        {
+          rect.height += ythickness;
+        }
+      else
+        {
+          rect.height += 1;
+        }
+      if (rect.x + rect.width == allocation.width - xthickness)
+        {
+          rect.width += xthickness;
+        }
+      else
+        {
+          rect.width += 1;
+        }
+
+      if (POINT_IN_RECT (x, y, rect))
+        {
+	  double width_ratio, height_ratio;
+	  WnckWorkspace *space;
+
+	  space = wnck_screen_get_workspace (pager->priv->screen, i);
+          g_assert (space != NULL);
+
+          /* Scale x, y mouse coords to corresponding screenwide viewport coords */
+          
+          width_ratio = (double) wnck_workspace_get_width (space) / (double) rect.width;
+          height_ratio = (double) wnck_workspace_get_height (space) / (double) rect.height;
+
+          if (viewport_x)
+            *viewport_x = width_ratio * (x - rect.x);
+          if (viewport_y)
+            *viewport_y = height_ratio * (y - rect.y);
+
+	  return i;
+	}
+
+      ++i;
+    }
+
+  return -1;
+}
+
+
+static void
+pager_wnck_draw_workspace (PagerWnck    *pager,
+			   int           workspace,
+			   GdkRectangle *rect,
+                           GdkPixbuf    *bg_pixbuf)
+{
+  GList *windows;
+  GList *tmp;
+  gboolean is_current;
+  WnckWorkspace *space;
+  GtkWidget *widget;
+  GtkStateType state;
+  GdkWindow *window;
+  GtkStyle *style;
+  
+  space = wnck_screen_get_workspace (pager->priv->screen, workspace);
+  if (!space)
+    return;
+
+  widget = GTK_WIDGET (pager);
+  is_current = (space == wnck_screen_get_active_workspace (pager->priv->screen));
+
+  if (is_current)
+    state = GTK_STATE_SELECTED;
+  else if (workspace == pager->priv->prelight) 
+    state = GTK_STATE_PRELIGHT;
+  else
+    state = GTK_STATE_NORMAL;
+
+  window = gtk_widget_get_window (widget);
+  style = gtk_widget_get_style (widget);
+
+  /* FIXME in names mode, should probably draw things like a button.
+   */
+  
+  if (bg_pixbuf)
+    {
+      gdk_draw_pixbuf (window,
+                       style->dark_gc[state],
+                       bg_pixbuf,
+                       0, 0,
+                       rect->x, rect->y,
+                       -1, -1,
+                       GDK_RGB_DITHER_MAX,
+                       0, 0);
+    }
+  else
+    {
+      cairo_t *cr;
+
+      cr = gdk_cairo_create (window);
+
+      if (!wnck_workspace_is_virtual (space))
+        {
+          gdk_cairo_set_source_color (cr, &style->dark[state]);
+          cairo_rectangle (cr, rect->x, rect->y, rect->width, rect->height);
+          cairo_fill (cr);
+        }
+      else
+        {
+          //FIXME prelight for dnd in the viewport?
+          int workspace_width, workspace_height;
+          int screen_width, screen_height;
+          double width_ratio, height_ratio;
+          double vx, vy, vw, vh; /* viewport */
+
+          workspace_width = wnck_workspace_get_width (space);
+          workspace_height = wnck_workspace_get_height (space);
+          screen_width = wnck_screen_get_width (pager->priv->screen);
+          screen_height = wnck_screen_get_height (pager->priv->screen);
+
+          if ((workspace_width % screen_width == 0) &&
+              (workspace_height % screen_height == 0))
+            {
+              int i, j;
+              int active_i, active_j;
+              int horiz_views;
+              int verti_views;
+
+              horiz_views = workspace_width / screen_width;
+              verti_views = workspace_height / screen_height;
+
+              /* do not forget thin lines to delimit "workspaces" */
+              width_ratio = (rect->width - (horiz_views - 1)) /
+                            (double) workspace_width;
+              height_ratio = (rect->height - (verti_views - 1)) /
+                             (double) workspace_height;
+
+              if (is_current)
+                {
+                  active_i =
+                    wnck_workspace_get_viewport_x (space) / screen_width;
+                  active_j =
+                    wnck_workspace_get_viewport_y (space) / screen_height;
+                }
+              else
+                {
+                  active_i = -1;
+                  active_j = -1;
+                }
+
+              for (i = 0; i < horiz_views; i++)
+                {
+                  /* "+ i" is for the thin lines */
+                  vx = rect->x + (width_ratio * screen_width) * i + i;
+
+                  if (i == horiz_views - 1)
+                    vw = rect->width + rect->x - vx;
+                  else
+                    vw = width_ratio * screen_width;
+
+                  vh = height_ratio * screen_height;
+
+                  for (j = 0; j < verti_views; j++)
+                    {
+                      /* "+ j" is for the thin lines */
+                      vy = rect->y + (height_ratio * screen_height) * j + j;
+
+                      if (j == verti_views - 1)
+                        vh = rect->height + rect->y - vy;
+
+                      if (active_i == i && active_j == j)
+                        gdk_cairo_set_source_color (cr,
+                                                    &style->dark[GTK_STATE_SELECTED]);
+                      else
+                        gdk_cairo_set_source_color (cr,
+                                                    &style->dark[GTK_STATE_NORMAL]);
+                      cairo_rectangle (cr, vx, vy, vw, vh);
+                      cairo_fill (cr);
+                    }
+                }
+            }
+          else
+            {
+              width_ratio = rect->width / (double) workspace_width;
+              height_ratio = rect->height / (double) workspace_height;
+
+              /* first draw non-active part of the viewport */
+              gdk_cairo_set_source_color (cr, &style->dark[GTK_STATE_NORMAL]);
+              cairo_rectangle (cr, rect->x, rect->y, rect->width, rect->height);
+              cairo_fill (cr);
+
+              if (is_current)
+                {
+                  /* draw the active part of the viewport */
+                  vx = rect->x +
+                    width_ratio * wnck_workspace_get_viewport_x (space);
+                  vy = rect->y +
+                    height_ratio * wnck_workspace_get_viewport_y (space);
+                  vw = width_ratio * screen_width;
+                  vh = height_ratio * screen_height;
+
+                  gdk_cairo_set_source_color (cr, &style->dark[GTK_STATE_SELECTED]);
+                  cairo_rectangle (cr, vx, vy, vw, vh);
+                  cairo_fill (cr);
+                }
+            }
+        }
+
+      cairo_destroy (cr);
+    }
+
+  if (pager->priv->display_mode == PAGER_WNCK_DISPLAY_CONTENT)
+    {      
+      windows = get_windows_for_workspace_in_bottom_to_top (pager->priv->screen,
+							    wnck_screen_get_workspace (pager->priv->screen,
+										       workspace));
+      
+      tmp = windows;
+      while (tmp != NULL)
+	{
+	  WnckWindow *win = tmp->data;
+	  GdkRectangle winrect;
+	  
+	  get_window_rect (win, rect, &winrect);
+	  
+	  draw_window (window,
+		       widget,
+		       win,
+		       &winrect,
+                       state,
+		       win == pager->priv->drag_window && pager->priv->dragging ? TRUE : FALSE);
+	  
+	  tmp = tmp->next;
+	}
+      
+      g_list_free (windows);
+    }
+  else
+    {
+      /* Workspace name mode */
+      const char *workspace_name;
+      PangoLayout *layout;
+      int w, h;
+
+      workspace_name = wnck_workspace_get_name (wnck_screen_get_workspace (pager->priv->screen,
+									   workspace));
+      layout = gtk_widget_create_pango_layout  (widget,
+						workspace_name);
+      
+      pango_layout_get_pixel_size (layout, &w, &h);
+      
+      gdk_draw_layout  (window,
+			is_current ?
+			style->fg_gc[GTK_STATE_SELECTED] :
+			style->fg_gc[GTK_STATE_NORMAL],
+			rect->x + (rect->width - w) / 2,
+			rect->y + (rect->height - h) / 2,
+			layout);
+
+      g_object_unref (layout);
+    }
+
+  if (workspace == pager->priv->prelight && pager->priv->prelight_dnd)
+    {
+      /* stolen directly from gtk source so it matches nicely */
+      cairo_t *cr;
+      gtk_paint_shadow (style, window,
+		        GTK_STATE_NORMAL, GTK_SHADOW_OUT,
+		        NULL, widget, "dnd",
+			rect->x, rect->y, rect->width, rect->height);
+
+      cr = gdk_cairo_create (window);
+      cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); /* black */
+      cairo_set_line_width (cr, 1.0);
+      cairo_rectangle (cr,
+		       rect->x + 0.5, rect->y + 0.5,
+		       MAX (0, rect->width - 1), MAX (0, rect->height - 1));
+      cairo_stroke (cr);
+      cairo_destroy (cr);
+    }
+}
+
+static gboolean
+pager_wnck_expose_event  (GtkWidget      *widget,
+                          GdkEventExpose *event)
+{
+  PagerWnck *pager;
+  int i;
+  int n_spaces;
+  WnckWorkspace *active_space;
+  GdkPixbuf *bg_pixbuf;
+  gboolean first;
+  GdkWindow *window;
+  GtkAllocation allocation;
+  GtkStyle *style;
+  int focus_width;
+  
+  pager = XFCE_PAGER_WNCK (widget);
+
+  n_spaces = wnck_screen_get_workspace_count (pager->priv->screen);
+  active_space = wnck_screen_get_active_workspace (pager->priv->screen);
+  bg_pixbuf = NULL;
+  first = TRUE;
+
+  window = gtk_widget_get_window (widget);
+  gtk_widget_get_allocation (widget, &allocation);
+
+  style = gtk_widget_get_style (widget);
+  gtk_widget_style_get (widget,
+			"focus-line-width", &focus_width,
+			NULL);
+
+  if (gtk_widget_has_focus (widget))
+    gtk_paint_focus (style,
+		     window,
+		     gtk_widget_get_state (widget),
+		     NULL,
+		     widget,
+		     "pager",
+		     0, 0,
+		     allocation.width,
+		     allocation.height);
+
+  if (pager->priv->shadow_type != GTK_SHADOW_NONE)
+    {
+      gtk_paint_shadow (style,
+			window,
+			gtk_widget_get_state (widget),
+			pager->priv->shadow_type,
+			NULL,
+			widget,
+			"pager",
+			focus_width,
+			focus_width,
+			allocation.width - 2 * focus_width,
+			allocation.height - 2 * focus_width);
+    }
+  
+  i = 0;
+  while (i < n_spaces)
+    {
+      GdkRectangle rect, intersect;
+
+      if (pager->priv->show_all_workspaces ||
+	  (active_space && i == wnck_workspace_get_number (active_space)))
+	{
+	  pager_wnck_get_workspace_rect (pager, i, &rect);
+
+          /* We only want to do this once, even if w/h change,
+           * for efficiency. width/height will only change by
+           * one pixel at most.
+           */
+          if (first &&
+              pager->priv->display_mode == PAGER_WNCK_DISPLAY_CONTENT)
+            {
+              bg_pixbuf = pager_wnck_get_background (pager,
+                                                     rect.width,
+                                                     rect.height);
+              first = FALSE;
+            }
+          
+	  if (gdk_rectangle_intersect (&event->area, &rect, &intersect))
+	    pager_wnck_draw_workspace (pager, i, &rect, bg_pixbuf);
+	}
+ 
+      ++i;
+    }
+
+  return FALSE;
+}
+
+static gboolean
+pager_wnck_button_press (GtkWidget      *widget,
+                         GdkEventButton *event)
+{
+  PagerWnck *pager;
+  int space_number;
+  WnckWorkspace *space = NULL;
+  GdkRectangle workspace_rect;
+						    
+  if (event->button != 1)
+    return FALSE;
+
+  pager = XFCE_PAGER_WNCK (widget);
+
+  space_number = workspace_at_point (pager, event->x, event->y, NULL, NULL);
+
+  if (space_number != -1)
+  {
+    pager_wnck_get_workspace_rect (pager, space_number, &workspace_rect);
+    space = wnck_screen_get_workspace (pager->priv->screen, space_number);
+  }
+
+  if (space)
+    {
+      /* always save the start coordinates so we can know if we need to change
+       * workspace when the button is released (ie, start and end coordinates
+       * should be in the same workspace) */
+      pager->priv->drag_start_x = event->x;
+      pager->priv->drag_start_y = event->y;
+    }
+
+  if (space && (pager->priv->display_mode != PAGER_WNCK_DISPLAY_NAME))
+    {
+      pager->priv->drag_window = window_at_point (pager, space,
+                                                  &workspace_rect,
+                                                  event->x, event->y);
+    }
+
+  return TRUE;
+}
+
+static gboolean
+pager_wnck_drag_motion_timeout (gpointer data)
+{
+  PagerWnck *pager = XFCE_PAGER_WNCK (data);
+  WnckWorkspace *active_workspace, *dnd_workspace;
+
+  pager->priv->dnd_activate = 0;
+  active_workspace = wnck_screen_get_active_workspace (pager->priv->screen);
+  dnd_workspace    = wnck_screen_get_workspace (pager->priv->screen,
+                                                pager->priv->prelight);
+
+  if (dnd_workspace &&
+      (pager->priv->prelight != wnck_workspace_get_number (active_workspace)))
+    wnck_workspace_activate (dnd_workspace, pager->priv->dnd_time);
+
+  return FALSE;
+}
+
+static void
+pager_wnck_queue_draw_workspace (PagerWnck *pager,
+                                 gint       i)
+{
+  GdkRectangle rect;
+  
+  if (i < 0)
+    return;
+
+  pager_wnck_get_workspace_rect (pager, i, &rect);
+  gtk_widget_queue_draw_area (GTK_WIDGET (pager), 
+                              rect.x, rect.y, 
+			      rect.width, rect.height);
+}
+
+static void
+pager_wnck_queue_draw_window (PagerWnck  *pager,
+                              WnckWindow *window)
+{
+  gint workspace;
+
+  workspace = pager_wnck_window_get_workspace (window, TRUE);
+  if (workspace == -1)
+    return;
+
+  pager_wnck_queue_draw_workspace (pager, workspace);
+}
+
+static void
+pager_wnck_check_prelight (PagerWnck *pager,
+                           gint       x,
+                           gint       y,
+                           gboolean   prelight_dnd)
+{
+  gint id;
+
+  if (x < 0 || y < 0)
+    id = -1;
+  else
+    id = workspace_at_point (pager, x, y, NULL, NULL);
+  
+  if (id != pager->priv->prelight)
+    {
+      pager_wnck_queue_draw_workspace (pager, pager->priv->prelight);
+      pager_wnck_queue_draw_workspace (pager, id);
+      pager->priv->prelight = id;
+      pager->priv->prelight_dnd = prelight_dnd;
+    }
+  else if (prelight_dnd != pager->priv->prelight_dnd)
+    {
+      pager_wnck_queue_draw_workspace (pager, pager->priv->prelight);
+      pager->priv->prelight_dnd = prelight_dnd;
+    }
+}
+
+static gboolean 
+pager_wnck_drag_motion (GtkWidget          *widget,
+                        GdkDragContext     *context,
+                        gint                x,
+                        gint                y,
+                        guint               dnd_time)
+{
+  PagerWnck *pager;
+  gint previous_workspace;
+
+  pager = XFCE_PAGER_WNCK (widget);
+
+  previous_workspace = pager->priv->prelight;
+  pager_wnck_check_prelight (pager, x, y, TRUE);
+
+  if (gtk_drag_dest_find_target (widget, context, NULL))
+    {
+#if GTK_CHECK_VERSION(2,21,0)
+       gdk_drag_status (context,
+                        gdk_drag_context_get_suggested_action (context), dnd_time);
+#else
+       gdk_drag_status (context, context->suggested_action, dnd_time);
+#endif
+    }
+  else 
+    {
+      gdk_drag_status (context, 0, dnd_time);
+
+      if (pager->priv->prelight != previous_workspace &&
+	  pager->priv->dnd_activate != 0)
+	{
+	  /* remove timeout, the window we hover over changed */
+	  g_source_remove (pager->priv->dnd_activate);
+	  pager->priv->dnd_activate = 0;
+	  pager->priv->dnd_time = 0;
+	}
+
+      if (pager->priv->dnd_activate == 0 && pager->priv->prelight > -1)   
+	{
+	  pager->priv->dnd_activate = g_timeout_add (PAGER_WNCK_ACTIVATE_TIMEOUT,
+                                                     pager_wnck_drag_motion_timeout,
+                                                     pager);
+	  pager->priv->dnd_time = dnd_time;
+	}
+    }    
+
+  return (pager->priv->prelight != -1);
+}
+ 
+static gboolean
+pager_wnck_drag_drop  (GtkWidget        *widget,
+		       GdkDragContext   *context,
+		       gint              x,
+		       gint              y,
+		       guint             dnd_time)
+{
+  PagerWnck *pager = XFCE_PAGER_WNCK (widget);
+  GdkAtom target;
+  
+  target = gtk_drag_dest_find_target (widget, context, NULL);
+
+  if (target != GDK_NONE)
+    gtk_drag_get_data (widget, context, target, dnd_time);
+  else 
+    gtk_drag_finish (context, FALSE, FALSE, dnd_time);
+
+  pager_wnck_clear_drag (pager);
+  pager_wnck_check_prelight (pager, x, y, FALSE);
+  
+  return TRUE;
+}
+
+static void
+pager_wnck_drag_data_received (GtkWidget          *widget,
+	  	               GdkDragContext     *context,
+			       gint                x,
+			       gint                y,
+			       GtkSelectionData   *selection_data,
+			       guint               info,
+			       guint               dnd_time)
+{
+  PagerWnck *pager = XFCE_PAGER_WNCK (widget);
+  WnckWorkspace *space;
+  GList *tmp;
+  gint i;
+  gulong xid;
+
+  if ((gtk_selection_data_get_length (selection_data) != sizeof (gulong)) ||
+      (gtk_selection_data_get_format (selection_data) != 8))
+    {
+      gtk_drag_finish (context, FALSE, FALSE, dnd_time);
+      return;
+    }
+  
+  i = workspace_at_point (pager, x, y, NULL, NULL);
+  space = wnck_screen_get_workspace (pager->priv->screen, i);
+  if (!space)
+    {
+      gtk_drag_finish (context, FALSE, FALSE, dnd_time);
+      return;
+    }
+  
+  xid = *((gulong *) gtk_selection_data_get_data (selection_data));
+	      
+  for (tmp = wnck_screen_get_windows_stacked (pager->priv->screen); tmp != NULL; tmp = tmp->next)
+    {
+      if (wnck_window_get_xid (tmp->data) == xid)
+	{
+	  WnckWindow *win = tmp->data;
+	  wnck_window_move_to_workspace (win, space);
+	  if (space == wnck_screen_get_active_workspace (pager->priv->screen))
+	    wnck_window_activate (win, dnd_time);
+	  gtk_drag_finish (context, TRUE, FALSE, dnd_time);
+	  return;
+	}
+    }
+
+  gtk_drag_finish (context, FALSE, FALSE, dnd_time);
+}			       
+
+static void 
+pager_wnck_drag_data_get (GtkWidget        *widget,
+                          GdkDragContext   *context,
+                          GtkSelectionData *selection_data,
+                          guint             info,
+                          guint             dnd_time)
+{
+  PagerWnck *pager = XFCE_PAGER_WNCK (widget);
+  gulong xid;
+
+  if (pager->priv->drag_window == NULL)
+    return;
+
+  xid = wnck_window_get_xid (pager->priv->drag_window);
+  gtk_selection_data_set (selection_data,
+			  gtk_selection_data_get_target (selection_data),
+			  8, (guchar *)&xid, sizeof (gulong));
+}			  
+
+static void 
+pager_wnck_drag_end (GtkWidget        *widget,
+                     GdkDragContext   *context)
+{
+  PagerWnck *pager = XFCE_PAGER_WNCK (widget);
+
+  pager_wnck_clear_drag (pager);
+}
+
+static void
+pager_wnck_drag_motion_leave (GtkWidget          *widget,
+                              GdkDragContext     *context,
+                              guint               dnd_time)
+{
+  PagerWnck *pager = XFCE_PAGER_WNCK (widget);
+
+  if (pager->priv->dnd_activate != 0)
+    {
+      g_source_remove (pager->priv->dnd_activate);
+      pager->priv->dnd_activate = 0;
+    }
+  pager->priv->dnd_time = 0;
+  pager_wnck_check_prelight (pager, -1, -1, FALSE);
+}
+
+static void
+wnck_drag_clean_up (WnckWindow     *window,
+		    GdkDragContext *context,
+		    gboolean	    clean_up_for_context_destroy,
+		    gboolean	    clean_up_for_window_destroy);
+
+static void
+wnck_drag_context_destroyed (gpointer  windowp,
+                             GObject  *context)
+{
+  wnck_drag_clean_up (windowp, (GdkDragContext *) context, TRUE, FALSE);
+}
+
+static void
+wnck_update_drag_icon (WnckWindow     *window,
+		       GdkDragContext *context)
+{
+  gint org_w, org_h, dnd_w, dnd_h;
+  WnckWorkspace *workspace;
+  GdkRectangle rect;
+  GdkPixmap *pixmap;
+  GtkWidget *widget;
+
+  widget = g_object_get_data (G_OBJECT (context), "wnck-drag-source-widget");
+  if (!widget)
+    return;
+
+  if (!gtk_icon_size_lookup_for_settings (gtk_widget_get_settings (widget),
+					  GTK_ICON_SIZE_DND, &dnd_w, &dnd_h))
+    dnd_w = dnd_h = 32;
+  /* windows are huge, so let's make this huge */
+  dnd_w *= 3;
+ 
+  workspace = wnck_window_get_workspace (window);
+  if (workspace == NULL)
+    workspace = wnck_screen_get_active_workspace (wnck_window_get_screen (window));
+  if (workspace == NULL)
+    return;
+
+  wnck_window_get_geometry (window, NULL, NULL, &org_w, &org_h);
+
+  rect.x = rect.y = 0;
+  rect.width = 0.5 + ((double) (dnd_w * org_w) / (double) wnck_workspace_get_width (workspace));
+  rect.width = MIN (org_w, rect.width);
+  rect.height = 0.5 + ((double) (rect.width * org_h) / (double) org_w);
+
+  /* we need at least three pixels to draw the smallest window */
+  rect.width = MAX (rect.width, 3);
+  rect.height = MAX (rect.height, 3);
+
+  pixmap = gdk_pixmap_new (gtk_widget_get_window (widget),
+                           rect.width, rect.height, -1);
+  draw_window (GDK_DRAWABLE (pixmap), widget, window,
+	       &rect, GTK_STATE_NORMAL, FALSE);  
+
+  gtk_drag_set_icon_pixmap (context, 
+                            gdk_drawable_get_colormap (GDK_DRAWABLE (pixmap)),
+			    pixmap, NULL,
+			    -2, -2);
+
+  g_object_unref (pixmap);
+}
+
+static void
+wnck_drag_window_destroyed (gpointer  contextp,
+                            GObject  *window)
+{
+  wnck_drag_clean_up ((WnckWindow *) window, GDK_DRAG_CONTEXT (contextp),
+                      FALSE, TRUE);
+}
+
+static void
+wnck_drag_source_destroyed (gpointer  contextp,
+                            GObject  *drag_source)
+{
+  g_object_steal_data (G_OBJECT (contextp), "wnck-drag-source-widget");
+}
+
+/* CAREFUL: This function is a bit brittle, because the pointers given may be
+ * finalized already */
+static void
+wnck_drag_clean_up (WnckWindow     *window,
+		    GdkDragContext *context,
+		    gboolean	    clean_up_for_context_destroy,
+		    gboolean	    clean_up_for_window_destroy)
+{
+  if (clean_up_for_context_destroy)
+    {
+      GtkWidget *drag_source;
+
+      drag_source = g_object_get_data (G_OBJECT (context),
+                                       "wnck-drag-source-widget");
+      if (drag_source)
+        g_object_weak_unref (G_OBJECT (drag_source),
+                             wnck_drag_source_destroyed, context);
+
+      g_object_weak_unref (G_OBJECT (window),
+                           wnck_drag_window_destroyed, context);
+      if (g_signal_handlers_disconnect_by_func (window,
+                                                wnck_update_drag_icon, context) != 2)
+	g_assert_not_reached ();
+    }
+
+  if (clean_up_for_window_destroy)
+    {
+      g_object_steal_data (G_OBJECT (context), "wnck-drag-source-widget");
+      g_object_weak_unref (G_OBJECT (context),
+                           wnck_drag_context_destroyed, window);
+    }
+}
+
+/**
+ * wnck_window_set_as_drag_icon:
+ * @window: #WnckWindow to use as drag icon
+ * @context: #GdkDragContext to set the icon on
+ * @drag_source: #GtkWidget that started the drag, or one of its parent. This
+ * widget needs to stay alive as long as possible during the drag.
+ *
+ * Sets the given @window as the drag icon for @context.
+ **/
+static void
+_pager_wnck_window_set_as_drag_icon (WnckWindow     *window,
+                               GdkDragContext *context,
+                               GtkWidget      *drag_source)
+{
+  g_return_if_fail (WNCK_IS_WINDOW (window));
+  g_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
+
+  g_object_weak_ref (G_OBJECT (window), wnck_drag_window_destroyed, context);
+  g_signal_connect (window, "geometry_changed",
+                    G_CALLBACK (wnck_update_drag_icon), context);
+  g_signal_connect (window, "icon_changed",
+                    G_CALLBACK (wnck_update_drag_icon), context);
+
+  g_object_set_data (G_OBJECT (context), "wnck-drag-source-widget", drag_source);
+  g_object_weak_ref (G_OBJECT (drag_source), wnck_drag_source_destroyed, context);
+
+  g_object_weak_ref (G_OBJECT (context), wnck_drag_context_destroyed, window);
+
+  wnck_update_drag_icon (window, context);
+}
+
+static gboolean
+pager_wnck_motion (GtkWidget        *widget,
+                   GdkEventMotion   *event)
+{
+  PagerWnck *pager;
+  GdkWindow *window;
+  int x, y;
+
+  pager = XFCE_PAGER_WNCK (widget);
+
+  window = gtk_widget_get_window (widget);
+  gdk_window_get_pointer (window, &x, &y, NULL);
+
+  if (!pager->priv->dragging &&
+      pager->priv->drag_window != NULL &&
+      gtk_drag_check_threshold (widget,
+                                pager->priv->drag_start_x,
+                                pager->priv->drag_start_y,
+                                x, y))
+    {
+      GdkDragContext *context;
+      context = gtk_drag_begin (widget, 
+				gtk_drag_dest_get_target_list (widget),
+				GDK_ACTION_MOVE,
+				1, (GdkEvent *)event);
+      pager->priv->dragging = TRUE;
+      pager->priv->prelight_dnd = TRUE;
+      _pager_wnck_window_set_as_drag_icon (pager->priv->drag_window,
+				     context,
+				     GTK_WIDGET (pager));
+    }
+
+  pager_wnck_check_prelight (pager, x, y, pager->priv->prelight_dnd);
+
+  return TRUE;
+}
+
+static gboolean
+pager_wnck_leave_notify	 (GtkWidget          *widget,
+	      		  GdkEventCrossing   *event)
+{
+  PagerWnck *pager;
+
+  pager = XFCE_PAGER_WNCK (widget);
+
+  pager_wnck_check_prelight (pager, -1, -1, FALSE);
+
+  return FALSE;
+}
+
+static gboolean
+pager_wnck_button_release (GtkWidget        *widget,
+                           GdkEventButton   *event)
+{
+  WnckWorkspace *space;
+  PagerWnck *pager;
+  int i;
+  int j;
+  int viewport_x;
+  int viewport_y;
+  
+  if (event->button != 1)
+    return FALSE;
+
+  pager = XFCE_PAGER_WNCK (widget);
+  
+  if (!pager->priv->dragging)
+    {
+      i = workspace_at_point (pager,
+                              event->x, event->y,
+                              &viewport_x, &viewport_y);
+      j = workspace_at_point (pager,
+                              pager->priv->drag_start_x,
+                              pager->priv->drag_start_y,
+                              NULL, NULL);
+
+      if (i == j && i >= 0 &&
+          (space = wnck_screen_get_workspace (pager->priv->screen, i)))
+        {
+          int screen_width, screen_height;
+
+          /* Don't switch the desktop if we're already there */
+          if (space != wnck_screen_get_active_workspace (pager->priv->screen))
+            wnck_workspace_activate (space, event->time);
+
+          /* EWMH only lets us move the viewport for the active workspace,
+           * but we just go ahead and hackily assume that the activate
+           * just above takes effect prior to moving the viewport
+           */
+
+          /* Transform the pointer location to viewport origin, assuming
+           * that we want the nearest "regular" viewport containing the
+           * pointer.
+           */
+          screen_width  = wnck_screen_get_width  (pager->priv->screen);
+          screen_height = wnck_screen_get_height (pager->priv->screen);
+          viewport_x = (viewport_x / screen_width)  * screen_width;
+          viewport_y = (viewport_y / screen_height) * screen_height;
+            
+          if (wnck_workspace_get_viewport_x (space) != viewport_x ||
+              wnck_workspace_get_viewport_y (space) != viewport_y)
+            wnck_screen_move_viewport (pager->priv->screen, viewport_x, viewport_y);
+        }
+      
+      pager_wnck_clear_drag (pager);
+    }
+
+  return FALSE;
+}
+
+static gboolean
+pager_wnck_focus (GtkWidget        *widget,
+                  GtkDirectionType  direction)
+{
+  /* PagerWnck *pager; */
+
+  /* pager = XFCE_PAGER_WNCK (widget); */
+  
+  return GTK_WIDGET_CLASS (pager_wnck_parent_class)->focus (widget, direction);
+}
+
+static gboolean
+pager_wnck_query_tooltip (GtkWidget  *widget,
+                          gint        x,
+                          gint        y,
+                          gboolean    keyboard_tip,
+                          GtkTooltip *tooltip)
+{
+  int i;
+  PagerWnck *pager;
+  WnckScreen *screen;
+  WnckWorkspace *space;
+  char *name;
+
+  pager = XFCE_PAGER_WNCK (widget);
+  screen = pager->priv->screen;
+
+  i = workspace_at_point (pager, x, y, NULL, NULL);
+  space = wnck_screen_get_workspace (screen, i);
+  if (!space)
+    return GTK_WIDGET_CLASS (pager_wnck_parent_class)->query_tooltip (widget,
+                                                                      x, y,
+                                                                      keyboard_tip,
+                                                                      tooltip);
+
+  if (wnck_screen_get_active_workspace (screen) == space)
+    {
+      WnckWindow *window;
+      GdkRectangle workspace_rect;
+
+      pager_wnck_get_workspace_rect (pager, i, &workspace_rect);
+
+      window = window_at_point (pager, space, &workspace_rect, x, y);
+
+      if (window)
+        name = g_strdup_printf (_("Click to start dragging \"%s\""),
+                                wnck_window_get_name (window));
+      else
+        name = g_strdup_printf (_("Current workspace: \"%s\""),
+                                wnck_workspace_get_name (space));
+    }
+  else
+    {
+      name = g_strdup_printf (_("Click to switch to \"%s\""),
+                              wnck_workspace_get_name (space));
+    }
+
+  gtk_tooltip_set_text (tooltip, name);
+
+  g_free (name);
+
+  return TRUE;
+}
+
+/**
+ * pager_wnck_new:
+ * @screen: deprecated argument, can be %NULL.
+ *
+ * Creates a new #PagerWnck. The #PagerWnck will show the #WnckWorkspace of the
+ * #WnckScreen it is on.
+ *
+ * Return value: a newly created #PagerWnck.
+ */
+/* TODO: when we break API again, remove the screen from here */
+GtkWidget*
+pager_wnck_new (WnckScreen *screen)
+{
+  PagerWnck *pager;
+  
+  pager = g_object_new (XFCE_TYPE_PAGER_WNCK, NULL);
+
+  return GTK_WIDGET (pager);
+}
+
+static gboolean
+pager_wnck_set_layout_hint (PagerWnck *pager)
+{
+  int layout_rows;
+  int layout_cols;
+
+  /* if we're not realized, we don't know about our screen yet */
+  if (pager->priv->screen == NULL)
+    _pager_wnck_set_screen (pager);
+  /* can still happen if the pager was not added to a widget hierarchy */
+  if (pager->priv->screen == NULL)
+    return FALSE;
+
+  /* The visual representation of the pager doesn't
+   * correspond to the layout of the workspaces
+   * here. i.e. the user will not pay any attention
+   * to the n_rows setting on this pager.
+   */
+  if (!pager->priv->show_all_workspaces)
+    return FALSE;
+
+  layout_rows = pager->priv->n_rows;
+  layout_cols = 0;
+
+  pager->priv->layout_manager_token =
+    wnck_screen_try_set_workspace_layout (pager->priv->screen,
+                                          pager->priv->layout_manager_token,
+                                          layout_rows,
+                                          layout_cols);
+
+  return (pager->priv->layout_manager_token != PAGER_WNCK_NO_MANAGER_TOKEN);
+}
+
+void
+pager_wnck_set_orientation (PagerWnck     *pager,
+                            GtkOrientation orientation)
+{
+  g_return_if_fail (XFCE_IS_PAGER_WNCK (pager));
+
+  if (pager->priv->orientation == orientation)
+    return;
+
+  pager->priv->orientation = orientation;
+}
+
+/* Setting the number of rows of the workspace layout */
+/* will be removed once the switch is moved to the workspace settings. */
+gboolean
+pager_wnck_set_n_rows (PagerWnck *pager,
+		       int        n_rows)
+{
+  int      old_n_rows;
+  gboolean old_n_rows_is_valid;
+
+  g_return_val_if_fail (XFCE_IS_PAGER_WNCK (pager), FALSE);
+  g_return_val_if_fail (n_rows > 0, FALSE);
+
+  if (pager->priv->n_rows == n_rows)
+    return TRUE;
+
+  old_n_rows = pager->priv->n_rows;
+  old_n_rows_is_valid = pager->priv->screen != NULL;
+
+  pager->priv->n_rows = n_rows;
+
+  if (pager_wnck_set_layout_hint (pager))
+    {
+      gtk_widget_queue_resize (GTK_WIDGET (pager));
+      return TRUE;
+    }
+  else
+    {
+      if (old_n_rows_is_valid)
+        pager->priv->n_rows = old_n_rows;
+      return FALSE;
+    }
+}
+
+/**
+ * pager_wnck_set_display_mode:
+ * @pager: a #PagerWnck.
+ * @mode: a display mode.
+ *
+ * Sets the display mode for @pager to @mode.
+ */
+void
+pager_wnck_set_display_mode (PagerWnck            *pager,
+			     PagerWnckDisplayMode  mode)
+{
+  g_return_if_fail (XFCE_IS_PAGER_WNCK (pager));
+
+  if (pager->priv->display_mode == mode)
+    return;
+
+  g_object_set (pager, "has-tooltip", mode != PAGER_WNCK_DISPLAY_NAME, NULL);
+
+  pager->priv->display_mode = mode;
+  gtk_widget_queue_resize (GTK_WIDGET (pager));
+}
+
+/**
+ * pager_wnck_set_starting_corner:
+ * @pager: a #PagerWnck.
+ * @starting_corner: location of a starting corner.
+ *
+ * Sets the starting corner of the @pager to @starting_corner.
+ */
+void
+pager_wnck_set_starting_corner (PagerWnck         *pager,
+				PagerLayoutCorner  starting_corner)
+{
+  g_return_if_fail (XFCE_IS_PAGER_WNCK (pager));
+
+  if (pager->priv->starting_corner == starting_corner)
+    return;
+
+  pager->priv->starting_corner = starting_corner;
+  gtk_widget_queue_resize (GTK_WIDGET (pager));
+}
+
+/**
+ * pager_wnck_set_layout_policy:
+ * @pager: a #PagerWnck.
+ * @policy: a layout policy.
+ *
+ * Sets the layout policy for @pager to @policy.
+ */
+void
+pager_wnck_set_layout_policy (PagerWnck         *pager,
+			      PagerLayoutPolicy  policy)
+{
+  g_return_if_fail (XFCE_IS_PAGER_WNCK (pager));
+
+  if (pager->priv->layout_policy == policy)
+    return;
+
+  pager->priv->layout_policy = policy;
+  gtk_widget_queue_resize (GTK_WIDGET (pager));
+}
+
+/**
+ * pager_wnck_set_show_all:
+ * @pager: a #PagerWnck.
+ * @show_all_workspaces: whether to display all #WnckWorkspace in @pager.
+ *
+ * Sets @pager to display all #WnckWorkspace or not, according to
+ * @show_all_workspaces.
+ */
+void
+pager_wnck_set_show_all (PagerWnck *pager,
+			 gboolean   show_all_workspaces)
+{
+  g_return_if_fail (XFCE_IS_PAGER_WNCK (pager));
+
+  show_all_workspaces = (show_all_workspaces != 0);
+
+  if (pager->priv->show_all_workspaces == show_all_workspaces)
+    return;
+
+  pager->priv->show_all_workspaces = show_all_workspaces;
+  gtk_widget_queue_resize (GTK_WIDGET (pager));
+}
+
+/**
+ * pager_wnck_set_shadow_type:
+ * @pager: a #PagerWnck.
+ * @shadow_type: a shadow type.
+ *
+ * Sets the shadow type for @pager to @shadow_type. The main use of this
+ * function is proper integration of #PagerWnck in panels with non-system
+ * backgrounds.
+ *
+ * Since: 2.2
+ */
+void
+pager_wnck_set_shadow_type (PagerWnck *   pager,
+			    GtkShadowType shadow_type)
+{
+  g_return_if_fail (XFCE_IS_PAGER_WNCK (pager));
+
+  if (pager->priv->shadow_type == shadow_type)
+    return;
+
+  pager->priv->shadow_type = shadow_type;
+  gtk_widget_queue_resize (GTK_WIDGET (pager));
+}
+
+static void
+active_window_changed_callback    (WnckScreen      *screen,
+                                   WnckWindow      *previous_window,
+                                   gpointer         data)
+{
+  PagerWnck *pager = XFCE_PAGER_WNCK (data);
+  gtk_widget_queue_draw (GTK_WIDGET (pager));
+}
+
+static void
+active_workspace_changed_callback (WnckScreen      *screen,
+                                   WnckWorkspace   *previous_workspace,
+                                   gpointer         data)
+{
+  PagerWnck *pager = XFCE_PAGER_WNCK (data);
+  gtk_widget_queue_draw (GTK_WIDGET (pager));
+}
+
+static void
+window_stacking_changed_callback  (WnckScreen      *screen,
+                                   gpointer         data)
+{
+  PagerWnck *pager = XFCE_PAGER_WNCK (data);
+  gtk_widget_queue_draw (GTK_WIDGET (pager));
+}
+
+static void
+window_opened_callback            (WnckScreen      *screen,
+                                   WnckWindow      *window,
+                                   gpointer         data)
+{
+  PagerWnck *pager = XFCE_PAGER_WNCK (data);
+
+  pager_wnck_connect_window (pager, window);
+  pager_wnck_queue_draw_window (pager, window);
+}
+
+static void
+window_closed_callback            (WnckScreen      *screen,
+                                   WnckWindow      *window,
+                                   gpointer         data)
+{
+  PagerWnck *pager = XFCE_PAGER_WNCK (data);
+
+  if (pager->priv->drag_window == window)
+    pager_wnck_clear_drag (pager);
+  
+  pager_wnck_queue_draw_window (pager, window);
+}
+
+static void
+workspace_created_callback        (WnckScreen      *screen,
+                                   WnckWorkspace   *space,
+                                   gpointer         data)
+{
+  PagerWnck *pager = XFCE_PAGER_WNCK (data);
+  g_signal_connect (space, "name_changed",
+                    G_CALLBACK (workspace_name_changed_callback), pager);
+  gtk_widget_queue_resize (GTK_WIDGET (pager));
+}
+
+static void
+workspace_destroyed_callback      (WnckScreen      *screen,
+                                   WnckWorkspace   *space,
+                                   gpointer         data)
+{
+  PagerWnck *pager = XFCE_PAGER_WNCK (data);
+  g_signal_handlers_disconnect_by_func (space, G_CALLBACK (workspace_name_changed_callback), pager);
+  gtk_widget_queue_resize (GTK_WIDGET (pager));
+}
+
+static void
+application_opened_callback       (WnckScreen      *screen,
+                                   WnckApplication *app,
+                                   gpointer         data)
+{
+  /*   PagerWnck *pager = XFCE_PAGER_WNCK (data); */
+}
+
+static void
+application_closed_callback       (WnckScreen      *screen,
+                                   WnckApplication *app,
+                                   gpointer         data)
+{
+  /*   PagerWnck *pager = XFCE_PAGER_WNCK (data); */
+}
+
+static void
+window_name_changed_callback      (WnckWindow      *window,
+                                   gpointer         data)
+{
+  PagerWnck *pager = XFCE_PAGER_WNCK (data);
+  pager_wnck_queue_draw_window (pager, window);
+}
+
+static void
+window_state_changed_callback     (WnckWindow      *window,
+                                   WnckWindowState  changed,
+                                   WnckWindowState  new,
+                                   gpointer         data)
+{
+  PagerWnck *pager = XFCE_PAGER_WNCK (data);
+
+  /* if the changed state changes the visibility in the pager, we need to
+   * redraw the whole workspace. pager_wnck_queue_draw_window() might not be
+   * enough */
+  if (!pager_wnck_window_state_is_relevant (changed))
+    pager_wnck_queue_draw_workspace (pager,
+                                     pager_wnck_window_get_workspace (window,
+                                                                      FALSE));
+  else
+    pager_wnck_queue_draw_window (pager, window);
+}
+
+static void
+window_workspace_changed_callback (WnckWindow      *window,
+                                   gpointer         data)
+{
+  PagerWnck *pager = XFCE_PAGER_WNCK (data);
+  gtk_widget_queue_draw (GTK_WIDGET (pager));
+}
+
+static void
+window_icon_changed_callback      (WnckWindow      *window,
+                                   gpointer         data)
+{
+  PagerWnck *pager = XFCE_PAGER_WNCK (data);
+  pager_wnck_queue_draw_window (pager, window);
+}
+
+static void
+window_geometry_changed_callback  (WnckWindow      *window,
+                                   gpointer         data)
+{
+  PagerWnck *pager = XFCE_PAGER_WNCK (data);
+  
+  pager_wnck_queue_draw_window (pager, window);
+}
+
+static void
+background_changed_callback (WnckWindow *window,
+                             gpointer    data)
+{
+  PagerWnck *pager = XFCE_PAGER_WNCK (data);
+
+  if (pager->priv->bg_cache)
+    {
+      g_object_unref (G_OBJECT (pager->priv->bg_cache));
+      pager->priv->bg_cache = NULL;
+    }
+  
+  gtk_widget_queue_draw (GTK_WIDGET (pager));
+}
+
+static void
+workspace_name_changed_callback (WnckWorkspace *space,
+                                 gpointer       data)
+{
+  gtk_widget_queue_resize (GTK_WIDGET (data));
+}
+
+static void
+viewports_changed_callback (WnckWorkspace *space,
+                            gpointer       data)
+{
+  gtk_widget_queue_resize (GTK_WIDGET (data));
+}
+
+static void
+pager_wnck_connect_screen (PagerWnck *pager)
+{
+  int i;
+  guint *c;
+  GList *tmp;
+  WnckScreen *screen;
+  
+  g_return_if_fail (pager->priv->screen != NULL);
+
+  screen = pager->priv->screen;
+  
+  for (tmp = wnck_screen_get_windows (screen); tmp; tmp = tmp->next)
+    {
+      pager_wnck_connect_window (pager, WNCK_WINDOW (tmp->data));
+    }
+  
+  i = 0;
+  c = pager->priv->screen_connections;
+  
+  c[i] = g_signal_connect (G_OBJECT (screen), "active_window_changed",
+                           G_CALLBACK (active_window_changed_callback),
+                           pager);
+  ++i;
+  
+  c[i] = g_signal_connect (G_OBJECT (screen), "active_workspace_changed",
+                           G_CALLBACK (active_workspace_changed_callback),
+                           pager);
+  ++i;  
+
+  c[i] = g_signal_connect (G_OBJECT (screen), "window_stacking_changed",
+                           G_CALLBACK (window_stacking_changed_callback),
+                           pager);
+  ++i;
+
+  c[i] = g_signal_connect (G_OBJECT (screen), "window_opened",
+                           G_CALLBACK (window_opened_callback),
+                           pager);
+  ++i;
+
+  c[i] = g_signal_connect (G_OBJECT (screen), "window_closed",
+                           G_CALLBACK (window_closed_callback),
+                           pager);
+  ++i;
+
+  c[i] = g_signal_connect (G_OBJECT (screen), "workspace_created",
+                           G_CALLBACK (workspace_created_callback),
+                           pager);
+  ++i;
+
+  c[i] = g_signal_connect (G_OBJECT (screen), "workspace_destroyed",
+                           G_CALLBACK (workspace_destroyed_callback),
+                           pager);
+  ++i;
+
+  c[i] = g_signal_connect (G_OBJECT (screen), "application_opened",
+                           G_CALLBACK (application_opened_callback),
+                           pager);
+  ++i;  
+
+  c[i] = g_signal_connect (G_OBJECT (screen), "application_closed",
+                           G_CALLBACK (application_closed_callback),
+                           pager);
+  ++i;
+
+  c[i] = g_signal_connect (G_OBJECT (screen), "background_changed",
+                           G_CALLBACK (background_changed_callback),
+                           pager);
+  ++i;
+
+  c[i] = g_signal_connect (G_OBJECT (screen), "viewports_changed",
+                           G_CALLBACK (viewports_changed_callback),
+                           pager);
+  ++i;
+  
+  g_assert (i == N_SCREEN_CONNECTIONS);
+
+  /* connect to name_changed on each workspace */
+  for (i = 0; i < wnck_screen_get_workspace_count (pager->priv->screen); i++)
+    {
+      WnckWorkspace *space;
+      space = wnck_screen_get_workspace (pager->priv->screen, i);
+      g_signal_connect (space, "name_changed",
+                        G_CALLBACK (workspace_name_changed_callback), pager);
+    }
+}
+
+static void
+pager_wnck_connect_window (PagerWnck  *pager,
+                           WnckWindow *window)
+{
+  g_signal_connect (G_OBJECT (window), "name_changed",
+                    G_CALLBACK (window_name_changed_callback),
+                    pager);
+  g_signal_connect (G_OBJECT (window), "state_changed",
+                    G_CALLBACK (window_state_changed_callback),
+                    pager);
+  g_signal_connect (G_OBJECT (window), "workspace_changed",
+                    G_CALLBACK (window_workspace_changed_callback),
+                    pager);
+  g_signal_connect (G_OBJECT (window), "icon_changed",
+                    G_CALLBACK (window_icon_changed_callback),
+                    pager);
+  g_signal_connect (G_OBJECT (window), "geometry_changed",
+                    G_CALLBACK (window_geometry_changed_callback),
+                    pager);
+}
+
+static void
+pager_wnck_disconnect_screen (PagerWnck  *pager)
+{
+  int i;
+  GList *tmp;
+
+  if (pager->priv->screen == NULL)
+    return;
+  
+  i = 0;
+  while (i < N_SCREEN_CONNECTIONS)
+    {
+      if (pager->priv->screen_connections[i] != 0)
+        g_signal_handler_disconnect (G_OBJECT (pager->priv->screen),
+                                     pager->priv->screen_connections[i]);
+
+      pager->priv->screen_connections[i] = 0;
+      
+      ++i;
+    }
+
+  for (i = 0; i < wnck_screen_get_workspace_count (pager->priv->screen); i++)
+    {
+      WnckWorkspace *space;
+      space = wnck_screen_get_workspace (pager->priv->screen, i);
+      g_signal_handlers_disconnect_by_func (space, G_CALLBACK (workspace_name_changed_callback), pager);
+    }
+ 
+  for (tmp = wnck_screen_get_windows (pager->priv->screen); tmp; tmp = tmp->next)
+    {
+      pager_wnck_disconnect_window (pager, WNCK_WINDOW (tmp->data));
+    }
+}
+
+static void
+pager_wnck_disconnect_window (PagerWnck  *pager,
+                              WnckWindow *window)
+{
+  g_signal_handlers_disconnect_by_func (G_OBJECT (window),
+                                        G_CALLBACK (window_name_changed_callback),
+                                        pager);
+  g_signal_handlers_disconnect_by_func (G_OBJECT (window),
+                                        G_CALLBACK (window_state_changed_callback),
+                                        pager);
+  g_signal_handlers_disconnect_by_func (G_OBJECT (window),
+                                        G_CALLBACK (window_workspace_changed_callback),
+                                        pager);
+  g_signal_handlers_disconnect_by_func (G_OBJECT (window),
+                                        G_CALLBACK (window_icon_changed_callback),
+                                        pager);
+  g_signal_handlers_disconnect_by_func (G_OBJECT (window),
+                                        G_CALLBACK (window_geometry_changed_callback),
+                                        pager);
+}
+
+static void
+pager_wnck_clear_drag (PagerWnck *pager)
+{
+  if (pager->priv->dragging)
+    pager_wnck_queue_draw_window (pager, pager->priv->drag_window);
+
+  pager->priv->dragging = FALSE;
+  pager->priv->drag_window = NULL;
+  pager->priv->drag_start_x = -1;
+  pager->priv->drag_start_y = -1;
+}
+
+/* Copied from libwnck xutils.c */
+static GdkColormap*
+_pager_wnck_get_cmap (GdkPixmap *pixmap)
+{
+  GdkColormap *cmap;
+
+  cmap = gdk_drawable_get_colormap (pixmap);
+  if (cmap)
+    g_object_ref (G_OBJECT (cmap));
+
+  if (cmap == NULL)
+    {
+      if (gdk_drawable_get_depth (pixmap) == 1)
+        {
+          /* try null cmap */
+          cmap = NULL;
+        }
+      else
+        {
+          /* Try system cmap */
+          GdkScreen *screen = gdk_drawable_get_screen (GDK_DRAWABLE (pixmap));
+          cmap = gdk_screen_get_system_colormap (screen);
+          g_object_ref (G_OBJECT (cmap));
+        }
+    }
+
+  /* Be sure we aren't going to blow up due to visual mismatch */
+  if (cmap &&
+#if GTK_CHECK_VERSION(2,21,0)
+      (gdk_visual_get_depth (gdk_colormap_get_visual (cmap)) !=
+       gdk_drawable_get_depth (pixmap))
+#else
+      (gdk_colormap_get_visual (cmap)->depth !=
+       gdk_drawable_get_depth (pixmap))
+#endif
+     )
+    {
+      g_object_unref (G_OBJECT (cmap));
+      cmap = NULL;
+    }
+
+  return cmap;
+}
+
+/* Copied from libwnck xutils.c */
+static GdkPixbuf*
+_pager_wnck_gdk_pixbuf_get_from_pixmap (GdkPixbuf   *dest,
+                                  Pixmap       xpixmap,
+                                  int          src_x,
+                                  int          src_y,
+                                  int          dest_x,
+                                  int          dest_y,
+                                  int          width,
+                                  int          height)
+{
+  GdkDrawable *drawable;
+  GdkPixbuf *retval;
+  GdkColormap *cmap;
+
+  retval = NULL;
+  cmap = NULL;
+
+  drawable = gdk_xid_table_lookup (xpixmap);
+
+  if (drawable)
+    g_object_ref (G_OBJECT (drawable));
+  else
+    drawable = gdk_pixmap_foreign_new (xpixmap);
+
+  if (drawable)
+    {
+      cmap = _pager_wnck_get_cmap (drawable);
+
+      /* GDK is supposed to do this but doesn't in GTK 2.0.2,
+       * fixed in 2.0.3
+       */
+      if (width < 0)
+        gdk_drawable_get_size (drawable, &width, NULL);
+      if (height < 0)
+        gdk_drawable_get_size (drawable, NULL, &height);
+
+      retval = gdk_pixbuf_get_from_drawable (dest,
+                                             drawable,
+                                             cmap,
+                                             src_x, src_y,
+                                             dest_x, dest_y,
+                                             width, height);
+    }
+
+  if (cmap)
+    g_object_unref (G_OBJECT (cmap));
+  if (drawable)
+    g_object_unref (G_OBJECT (drawable));
+
+  return retval;
+}
+
+/* Copied from libwnck utils.c */
+static Display *
+_pager_wnck_get_default_display (void)
+{
+  /* FIXME: when we fix libwnck to not use the GDK default display, we will
+   * need to fix wnckprop accordingly. */
+  return GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
+}
+
+static GdkPixbuf*
+pager_wnck_get_background (PagerWnck *pager,
+                           int        width,
+                           int        height)
+{
+  Pixmap p;
+  GdkPixbuf *pix = NULL;
+  
+  /* We have to be careful not to keep alternating between
+   * width/height values, otherwise this would get really slow.
+   */
+  if (pager->priv->bg_cache &&
+      gdk_pixbuf_get_width (pager->priv->bg_cache) == width &&
+      gdk_pixbuf_get_height (pager->priv->bg_cache) == height)
+    return pager->priv->bg_cache;
+
+  if (pager->priv->bg_cache)
+    {
+      g_object_unref (G_OBJECT (pager->priv->bg_cache));
+      pager->priv->bg_cache = NULL;
+    }
+
+  if (pager->priv->screen == NULL)
+    return NULL;
+
+  /* FIXME this just globally disables the thumbnailing feature */
+  return NULL;
+  
+#define MIN_BG_SIZE 10
+  
+  if (width < MIN_BG_SIZE || height < MIN_BG_SIZE)
+    return NULL;
+  
+  p = wnck_screen_get_background_pixmap (pager->priv->screen);
+
+  if (p != None)
+    {
+      /* _wnck_error_trap_push (); */
+      gdk_error_trap_push ();
+      pix = _pager_wnck_gdk_pixbuf_get_from_pixmap (NULL,
+                                              p,
+                                              0, 0, 0, 0,
+                                              -1, -1);
+      /* _wnck_error_trap_pop (); */
+      XSync (_pager_wnck_get_default_display(), False);
+      gdk_error_trap_pop ();
+
+    }
+
+  if (pix)
+    {
+      pager->priv->bg_cache = gdk_pixbuf_scale_simple (pix,
+                                                       width,
+                                                       height,
+                                                       GDK_INTERP_BILINEAR);
+
+      g_object_unref (G_OBJECT (pix));
+    }
+
+  return pager->priv->bg_cache;
+}
+
+/* 
+ *This will return aobj_pager whose parent is wnck's atk object -Gail Container
+ */
+static AtkObject *
+pager_wnck_get_accessible (GtkWidget *widget)
+{
+  static gboolean first_time = TRUE;
+
+  if (first_time) 
+    {
+      AtkObjectFactory *factory;
+      AtkRegistry *registry;
+      GType derived_type;
+      GType derived_atk_type;
+
+      /*
+       * Figure out whether accessibility is enabled by looking at the
+       * type of the accessible object which would be created for
+       * the parent type PagerWnck.
+       */
+      derived_type = g_type_parent (XFCE_TYPE_PAGER_WNCK);
+
+      registry = atk_get_default_registry ();
+      factory = atk_registry_get_factory (registry,
+                                          derived_type);
+      derived_atk_type = atk_object_factory_get_accessible_type (factory);
+
+      if (g_type_is_a (derived_atk_type, GTK_TYPE_ACCESSIBLE)) 
+        {
+          /*
+           * Specify what factory to use to create accessible
+           * objects
+           */
+          /* atk_registry_set_factory_type (registry, */
+          /*                                WNCK_TYPE_PAGER, */
+          /*                                WNCK_TYPE_PAGER_ACCESSIBLE_FACTORY); */
+
+          /* atk_registry_set_factory_type (registry, */
+          /*                                WNCK_TYPE_WORKSPACE, */
+          /*                                WNCK_TYPE_WORKSPACE_ACCESSIBLE_FACTORY); */
+        }
+      first_time = FALSE;
+    }
+  return GTK_WIDGET_CLASS (pager_wnck_parent_class)->get_accessible (widget);
+}
diff --git a/plugins/pager/pager-wnck.h b/plugins/pager/pager-wnck.h
new file mode 100644
index 0000000..2f5401c
--- /dev/null
+++ b/plugins/pager/pager-wnck.h
@@ -0,0 +1,107 @@
+/* pager object */
+/* vim: set sw=2 et: */
+
+/*
+ * Copyright (C) 2001 Havoc Pennington
+ * Copyright (C) 2003, 2005-2007 Vincent Untz
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __PAGER_WNCK_H__
+#define __PAGER_WNCK_H__
+
+#include <gtk/gtk.h>
+#include <libwnck/screen.h>
+
+G_BEGIN_DECLS
+
+#define XFCE_TYPE_PAGER_WNCK              (pager_wnck_get_type ())
+#define XFCE_PAGER_WNCK(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), XFCE_TYPE_PAGER_WNCK, PagerWnck))
+#define XFCE_PAGER_WNCK_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), XFCE_TYPE_PAGER_WNCK, PagerWnckClass))
+#define XFCE_IS_PAGER_WNCK(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), XFCE_TYPE_PAGER_WNCK))
+#define XFCE_IS_PAGER_WNCK_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), XFCE_TYPE_PAGER_WNCK))
+#define XFCE_PAGER_WNCK_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), XFCE_TYPE_PAGER_WNCK, PagerWnckClass))
+
+typedef struct _PagerWnck        PagerWnck;
+typedef struct _PagerWnckClass   PagerWnckClass;
+typedef struct _PagerWnckPrivate PagerWnckPrivate;
+
+/**
+ * PagerWnck:
+ *
+ * The #PagerWnck struct contains only private fields and should not be
+ * directly accessed.
+ */
+struct _PagerWnck
+{
+  GtkContainer parent_instance;
+
+  PagerWnckPrivate *priv;
+};
+
+struct _PagerWnckClass
+{
+  GtkContainerClass parent_class;
+  
+  /* Padding for future expansion */
+  void (* pad1) (void);
+  void (* pad2) (void);
+  void (* pad3) (void);
+  void (* pad4) (void);
+};
+
+/**
+ * PagerWnckDisplayMode:
+ * @PAGER_WNCK_DISPLAY_NAME: the #PagerWnck will only display the names of the
+ * workspaces.
+ * @PAGER_WNCK_DISPLAY_CONTENT: the #PagerWnck will display a representation
+ * for each window in the workspaces.
+ *
+ * Mode defining what a #PagerWnck will display.
+ */
+typedef enum {
+  PAGER_WNCK_DISPLAY_NAME,
+  PAGER_WNCK_DISPLAY_CONTENT
+} PagerWnckDisplayMode;
+
+GType pager_wnck_get_type (void) G_GNUC_CONST;
+
+void       pager_wnck_register_type   (XfcePanelTypeModule *type_module);
+
+GtkWidget* pager_wnck_new (WnckScreen *screen);
+
+void pager_wnck_set_orientation  (PagerWnck            *pager,
+                                  GtkOrientation        orientation);
+gboolean pager_wnck_set_n_rows   (PagerWnck            *pager,
+				  int                   n_rows);
+void pager_wnck_set_display_mode (PagerWnck            *pager,
+				  PagerWnckDisplayMode  mode);
+void pager_wnck_set_starting_corner (PagerWnck         *pager,
+                                    PagerLayoutCorner   starting_corner);
+void pager_wnck_set_layout_policy (PagerWnck           *pager,
+				   PagerLayoutPolicy    layout_policy);
+void pager_wnck_set_show_all     (PagerWnck            *pager,
+				  gboolean              show_all_workspaces);
+void pager_wnck_set_shadow_type  (PagerWnck	       *pager,
+				  GtkShadowType		shadow_type);
+
+
+G_END_DECLS
+
+#endif /* !__PAGER_WNCK_H__ */
+
+
diff --git a/plugins/pager/pager.c b/plugins/pager/pager.c
index 16e3d94..39f2cb3 100644
--- a/plugins/pager/pager.c
+++ b/plugins/pager/pager.c
@@ -32,6 +32,7 @@
 #include <exo/exo.h>
 
 #include "pager.h"
+#include "pager-wnck.h"
 #include "pager-buttons.h"
 #include "pager-dialog_ui.h"
 
@@ -57,13 +58,35 @@ static void     pager_plugin_construct                    (XfcePanelPlugin   *pa
 static void     pager_plugin_free_data                    (XfcePanelPlugin   *panel_plugin);
 static gboolean pager_plugin_size_changed                 (XfcePanelPlugin   *panel_plugin,
                                                            gint               size);
-static void     pager_plugin_orientation_changed          (XfcePanelPlugin   *panel_plugin,
-                                                           GtkOrientation     orientation);
+static void     pager_plugin_mode_changed                 (XfcePanelPlugin     *panel_plugin,
+                                                           XfcePanelPluginMode  mode);
 static void     pager_plugin_configure_workspace_settings (GtkWidget         *button);
 static void     pager_plugin_configure_plugin             (XfcePanelPlugin   *panel_plugin);
 static void     pager_plugin_screen_layout_changed        (PagerPlugin       *plugin);
+static void     pager_plugin_size_request                 (GtkWidget         *widget,
+                                                           GtkRequisition    *requisition);
 
-
+GType
+pager_layout_corner_get_type (void)
+{
+  static GType layout_corner_type = 0;
+
+  if (!layout_corner_type) {
+    static GEnumValue corner_types[] = {
+      { PAGER_LAYOUT_CORNER_TOPLEFT,     "First workspace in top-left corner",     "top-left" },
+      { PAGER_LAYOUT_CORNER_TOPRIGHT,    "First workspace in top-right corner",    "top-right" },
+      { PAGER_LAYOUT_CORNER_BOTTOMLEFT,  "First workspace in bottom-left corner",  "bottom-left" },
+      { PAGER_LAYOUT_CORNER_BOTTOMRIGHT, "First workspace in bottom-right corner", "bottom-right" },
+      { 0, NULL, NULL },
+    };
+
+    layout_corner_type =
+	g_enum_register_static ("PagerLayoutCorner",
+				corner_types);
+  }
+
+  return layout_corner_type;
+}
 
 struct _PagerPluginClass
 {
@@ -113,12 +136,13 @@ pager_plugin_class_init (PagerPluginClass *klass)
 
   widget_class = GTK_WIDGET_CLASS (klass);
   widget_class->scroll_event = pager_plugin_scroll_event;
+  widget_class->size_request = pager_plugin_size_request;
 
   plugin_class = XFCE_PANEL_PLUGIN_CLASS (klass);
   plugin_class->construct = pager_plugin_construct;
   plugin_class->free_data = pager_plugin_free_data;
   plugin_class->size_changed = pager_plugin_size_changed;
-  plugin_class->orientation_changed = pager_plugin_orientation_changed;
+  plugin_class->mode_changed = pager_plugin_mode_changed;
   plugin_class->configure_plugin = pager_plugin_configure_plugin;
 
   g_object_class_install_property (gobject_class,
@@ -214,7 +238,7 @@ pager_plugin_set_property (GObject      *object,
         {
           if (plugin->miniature_view)
             {
-              if (!wnck_pager_set_n_rows (WNCK_PAGER (plugin->pager), plugin->rows))
+              if (!pager_wnck_set_n_rows (XFCE_PAGER_WNCK (plugin->pager), plugin->rows))
                 g_message ("Failed to set the number of pager rows. You probably "
                            "have more than 1 pager in your panel setup.");
             }
@@ -275,6 +299,7 @@ pager_plugin_scroll_event (GtkWidget      *widget,
 static void
 pager_plugin_screen_layout_changed (PagerPlugin *plugin)
 {
+  XfcePanelPluginMode mode;
   GtkOrientation orientation;
 
   panel_return_if_fail (XFCE_IS_PAGER_PLUGIN (plugin));
@@ -286,21 +311,36 @@ pager_plugin_screen_layout_changed (PagerPlugin *plugin)
       wnck_screen_force_update (plugin->wnck_screen);
     }
 
-  orientation = xfce_panel_plugin_get_orientation (XFCE_PANEL_PLUGIN (plugin));
+  mode = xfce_panel_plugin_get_mode (XFCE_PANEL_PLUGIN (plugin));
+  orientation = (mode != XFCE_PANEL_PLUGIN_MODE_VERTICAL) ?
+    GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL;
+
 
   if (plugin->miniature_view)
     {
-      plugin->pager = wnck_pager_new (plugin->wnck_screen);
-      wnck_pager_set_display_mode (WNCK_PAGER (plugin->pager), WNCK_PAGER_DISPLAY_CONTENT);
-      if (!wnck_pager_set_n_rows (WNCK_PAGER (plugin->pager), plugin->rows))
+      plugin->pager = pager_wnck_new (plugin->wnck_screen);
+      pager_wnck_set_display_mode (XFCE_PAGER_WNCK (plugin->pager), PAGER_WNCK_DISPLAY_CONTENT);
+      if (!pager_wnck_set_n_rows (XFCE_PAGER_WNCK (plugin->pager), plugin->rows))
         g_message ("Setting the pager rows returned false. Maybe the setting is not applied.");
-      wnck_pager_set_orientation (WNCK_PAGER (plugin->pager), orientation);
+      if (mode == XFCE_PANEL_PLUGIN_MODE_HORIZONTAL)
+        pager_wnck_set_layout_policy (XFCE_PAGER_WNCK (plugin->pager), PAGER_LAYOUT_POLICY_WIDTH_FOR_HEIGHT);
+      else
+        pager_wnck_set_layout_policy (XFCE_PAGER_WNCK (plugin->pager), PAGER_LAYOUT_POLICY_HEIGHT_FOR_WIDTH);
+      pager_wnck_set_orientation (XFCE_PAGER_WNCK (plugin->pager), orientation);
+      if (mode != XFCE_PANEL_PLUGIN_MODE_VERTICAL)
+        pager_wnck_set_starting_corner (XFCE_PAGER_WNCK (plugin->pager), PAGER_LAYOUT_CORNER_TOPLEFT);
+      else
+        pager_wnck_set_starting_corner (XFCE_PAGER_WNCK (plugin->pager), PAGER_LAYOUT_CORNER_TOPRIGHT);
     }
   else
     {
       plugin->pager = pager_buttons_new (plugin->wnck_screen);
       pager_buttons_set_n_rows (XFCE_PAGER_BUTTONS (plugin->pager), plugin->rows);
       pager_buttons_set_orientation (XFCE_PAGER_BUTTONS (plugin->pager), orientation);
+      if (mode != XFCE_PANEL_PLUGIN_MODE_VERTICAL)
+        pager_buttons_set_starting_corner (XFCE_PAGER_BUTTONS (plugin->pager), PAGER_LAYOUT_CORNER_TOPLEFT);
+      else
+        pager_buttons_set_starting_corner (XFCE_PAGER_BUTTONS (plugin->pager), PAGER_LAYOUT_CORNER_TOPRIGHT);
     }
 
   gtk_container_add (GTK_CONTAINER (plugin), plugin->pager);
@@ -382,6 +422,19 @@ pager_plugin_free_data (XfcePanelPlugin *panel_plugin)
 
 
 
+static void
+pager_plugin_size_request (GtkWidget      *widget,
+                           GtkRequisition *requisition)
+{
+  PagerPlugin        *plugin;
+
+  plugin = XFCE_PAGER_PLUGIN (widget);
+
+  gtk_widget_size_request (plugin->pager, requisition);
+}
+
+
+
 static gboolean
 pager_plugin_size_changed (XfcePanelPlugin *panel_plugin,
                            gint             size)
@@ -393,19 +446,42 @@ pager_plugin_size_changed (XfcePanelPlugin *panel_plugin,
 
 
 static void
-pager_plugin_orientation_changed (XfcePanelPlugin *panel_plugin,
-                                  GtkOrientation   orientation)
+pager_plugin_mode_changed (XfcePanelPlugin      *panel_plugin,
+                           XfcePanelPluginMode   mode)
 {
   PagerPlugin *plugin = XFCE_PAGER_PLUGIN (panel_plugin);
+  GtkOrientation orientation;
+
+  orientation = (mode != XFCE_PANEL_PLUGIN_MODE_VERTICAL) ?
+    GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL;
+
+  if (plugin->miniature_view)
+    {
+      if (mode == XFCE_PANEL_PLUGIN_MODE_HORIZONTAL)
+        pager_wnck_set_layout_policy (XFCE_PAGER_WNCK (plugin->pager), PAGER_LAYOUT_POLICY_WIDTH_FOR_HEIGHT);
+      else
+        pager_wnck_set_layout_policy (XFCE_PAGER_WNCK (plugin->pager), PAGER_LAYOUT_POLICY_HEIGHT_FOR_WIDTH);
+    }
 
   if (plugin->miniature_view)
-    wnck_pager_set_orientation (WNCK_PAGER (plugin->pager), orientation);
+    {
+      pager_wnck_set_orientation (XFCE_PAGER_WNCK (plugin->pager), orientation);
+      if (mode != XFCE_PANEL_PLUGIN_MODE_VERTICAL)
+        pager_wnck_set_starting_corner (XFCE_PAGER_WNCK (plugin->pager), PAGER_LAYOUT_CORNER_TOPLEFT);
+      else
+        pager_wnck_set_starting_corner (XFCE_PAGER_WNCK (plugin->pager), PAGER_LAYOUT_CORNER_TOPRIGHT);
+    }
   else
-    pager_buttons_set_orientation (XFCE_PAGER_BUTTONS (plugin->pager), orientation);
+    {
+      pager_buttons_set_orientation (XFCE_PAGER_BUTTONS (plugin->pager), orientation);
+      if (mode != XFCE_PANEL_PLUGIN_MODE_VERTICAL)
+        pager_buttons_set_starting_corner (XFCE_PAGER_BUTTONS (plugin->pager), PAGER_LAYOUT_CORNER_TOPLEFT);
+      else
+        pager_buttons_set_starting_corner (XFCE_PAGER_BUTTONS (plugin->pager), PAGER_LAYOUT_CORNER_TOPRIGHT);
+    }
 }
 
 
-
 static void
 pager_plugin_configure_workspace_settings (GtkWidget *button)
 {
diff --git a/plugins/pager/pager.h b/plugins/pager/pager.h
index 1d65f59..96dd2a8 100644
--- a/plugins/pager/pager.h
+++ b/plugins/pager/pager.h
@@ -20,6 +20,7 @@
 #define __PAGER_H__
 
 #include <gtk/gtk.h>
+#include <libxfce4panel/libxfce4panel.h>
 
 G_BEGIN_DECLS
 
@@ -37,6 +38,23 @@ GType pager_plugin_get_type      (void) G_GNUC_CONST;
 
 void  pager_plugin_register_type (XfcePanelTypeModule *type_module);
 
+typedef enum {
+  PAGER_LAYOUT_POLICY_WIDTH_FOR_HEIGHT,
+  PAGER_LAYOUT_POLICY_HEIGHT_FOR_WIDTH
+} PagerLayoutPolicy;
+
+typedef enum
+{
+  PAGER_LAYOUT_CORNER_TOPLEFT,
+  PAGER_LAYOUT_CORNER_TOPRIGHT,
+  PAGER_LAYOUT_CORNER_BOTTOMRIGHT,
+  PAGER_LAYOUT_CORNER_BOTTOMLEFT
+} PagerLayoutCorner;
+
+#define XFCE_TYPE_PAGER_LAYOUT_CORNER (pager_layout_corner_get_type ())
+
+GType pager_layout_corner_get_type (void);
+
 G_END_DECLS
 
 #endif /* !__PAGER_H__ */


More information about the Xfce4-commits mailing list