diff -r -u -N libwnck-2.4.0.1/libwnck/Makefile.am libwnck-2.4.0.1.topatch/libwnck/Makefile.am
--- libwnck-2.4.0.1/libwnck/Makefile.am	2003-05-21 13:56:24.000000000 -0400
+++ libwnck-2.4.0.1.topatch/libwnck/Makefile.am	2003-11-08 21:20:11.000000000 -0500
@@ -12,6 +12,7 @@
 	application.h		\
 	screen.h		\
 	tasklist.h		\
+	scroller.h		\
 	util.h			\
 	window.h 		\
 	window-action-menu.h	\
@@ -44,6 +45,7 @@
 	private.h		\
 	screen.c		\
 	tasklist.c		\
+	scroller.c		\
 	util.c			\
 	window.c		\
 	window-action-menu.c	\
diff -r -u -N libwnck-2.4.0.1/libwnck/Makefile.in libwnck-2.4.0.1.topatch/libwnck/Makefile.in
--- libwnck-2.4.0.1/libwnck/Makefile.in	2003-09-10 14:56:34.000000000 -0400
+++ libwnck-2.4.0.1.topatch/libwnck/Makefile.in	2003-11-08 21:20:11.000000000 -0500
@@ -122,6 +122,7 @@
 	application.h		\
 	screen.h		\
 	tasklist.h		\
+	scroller.h		\
 	util.h			\
 	window.h 		\
 	window-action-menu.h	\
@@ -157,6 +158,7 @@
 	private.h		\
 	screen.c		\
 	tasklist.c		\
+	scroller.c		\
 	util.c			\
 	window.c		\
 	window-action-menu.c	\
@@ -229,7 +231,7 @@
 X_EXTRA_LIBS = @X_EXTRA_LIBS@
 X_PRE_LIBS = @X_PRE_LIBS@
 libwnck_1_la_DEPENDENCIES = 
-libwnck_1_la_OBJECTS =  application.lo pager.lo screen.lo tasklist.lo \
+libwnck_1_la_OBJECTS =  application.lo pager.lo screen.lo tasklist.lo scroller.lo\
 util.lo window.lo window-action-menu.lo window-menu.lo workspace.lo \
 xutils.lo wnck-enum-types.lo wnck-marshal.lo pager-accessible.lo \
 pager-accessible-factory.lo workspace-accessible.lo \
diff -r -u -N libwnck-2.4.0.1/libwnck/scroller.c libwnck-2.4.0.1.topatch/libwnck/scroller.c
--- libwnck-2.4.0.1/libwnck/scroller.c	1969-12-31 19:00:00.000000000 -0500
+++ libwnck-2.4.0.1.topatch/libwnck/scroller.c	2003-11-08 21:20:28.000000000 -0500
@@ -0,0 +1,965 @@
+/* scroller object */
+                                                                                                                                             
+/*
+ * Copyright (C) 2003 Denis Yeldandi
+ *
+ * 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 <stdio.h>
+#include <gtk/gtkmain.h>
+#include <gtk/gtksignal.h>
+
+#include "scroller.h"
+
+#define NO_ARROW 4
+#define MIN_ARROW_WIDTH 6
+
+GtkType
+wnck_scroller_get_type (void);
+
+static void
+wnck_scroller_class_init (WnckScrollerClass *class);
+
+static void
+wnck_scroller_init (WnckScroller *scroller);
+
+GtkWidget*
+wnck_scroller_new (GtkAdjustment *adjustment);
+
+static void
+wnck_scroller_destroy (GtkObject *object);
+
+GtkAdjustment*
+wnck_scroller_get_adjustment (WnckScroller *scroller);
+
+void
+wnck_scroller_set_adjustment (WnckScroller  *scroller,
+			      GtkAdjustment *adjustment);
+
+void
+wnck_scroller_set_orientation (WnckScroller  *scroller,
+			       GtkOrientation orientation);
+
+static void
+wnck_scroller_realize (GtkWidget *widget);
+
+static void 
+wnck_scroller_size_request (GtkWidget      *widget,
+			    GtkRequisition *requisition);
+
+static void
+wnck_scroller_size_allocate (GtkWidget     *widget,
+			     GtkAllocation *allocation);
+
+static gint
+wnck_scroller_expose (GtkWidget      *widget,
+		      GdkEventExpose *event);
+                                                                                                                                             
+static gint
+wnck_scroller_vertical_expose (GtkWidget      *widget,
+		      GdkEventExpose *event);
+                                                                                                                                             
+static gint
+wnck_scroller_horizontal_expose (GtkWidget      *widget,
+		      GdkEventExpose *event);
+                                                                                                                                             
+static void
+wnck_scroller_draw_arrow (WnckScroller *scroller,
+                          GtkArrowType   arrow_type);
+
+
+static gint
+wnck_scroller_button_press (GtkWidget      *widget,
+                            GdkEventButton *event);
+
+static gint
+wnck_scroller_horizontal_button_press (GtkWidget      *widget,
+                            GdkEventButton *event);
+
+static gint
+wnck_scroller_vertical_button_press (GtkWidget      *widget,
+                            GdkEventButton *event);
+
+static gint
+wnck_scroller_button_release (GtkWidget      *widget,
+                              GdkEventButton *event);
+
+static gint
+wnck_scroller_horizontal_button_release (GtkWidget      *widget,
+                              GdkEventButton *event);
+
+static gint
+wnck_scroller_vertical_button_release (GtkWidget      *widget,
+                              GdkEventButton *event);
+
+static gint
+wnck_scroller_motion_notify (GtkWidget      *widget,
+                             GdkEventMotion *event);
+
+static gint
+wnck_scroller_horizontal_motion_notify (GtkWidget      *widget,
+                             GdkEventMotion *event);
+
+static gint
+wnck_scroller_vertical_motion_notify (GtkWidget      *widget,
+                             GdkEventMotion *event);
+
+static gint
+wnck_scroller_enter_notify (GtkWidget        *widget,
+                            GdkEventCrossing *event);
+
+static gint
+wnck_scroller_horizontal_enter_notify (GtkWidget        *widget,
+                            GdkEventCrossing *event);
+
+static gint
+wnck_scroller_vertical_enter_notify (GtkWidget        *widget,
+                            GdkEventCrossing *event);
+
+static void
+wnck_scroller_redraw (WnckScroller *scroller);
+
+static gint
+wnck_scroller_leave_notify (GtkWidget        *widget,
+                            GdkEventCrossing *event);;
+
+static gboolean
+scroller_at_limit(WnckScroller *scroller,
+                  GtkArrowType  arrow_type);
+
+static gint
+wnck_scroller_get_arrow_size (WnckScroller *scroller);
+
+static GtkWidgetClass *parent_class = NULL;
+
+GtkType
+wnck_scroller_get_type ()
+{
+  static GtkType scroller_type = 0;
+
+  if (!scroller_type)
+    {
+      static const GtkTypeInfo scroller_info =
+      {
+	"WnckScroller",
+	sizeof (WnckScroller),
+	sizeof (WnckScrollerClass),
+	(GtkClassInitFunc) wnck_scroller_class_init,
+	(GtkObjectInitFunc) wnck_scroller_init,
+	/* reserved_1 */ NULL,
+	/* reserved_1 */ NULL,
+	(GtkClassInitFunc) NULL
+      };
+
+      scroller_type = gtk_type_unique (GTK_TYPE_WIDGET, &scroller_info);
+    }
+
+  return scroller_type;
+}
+
+static void
+wnck_scroller_class_init (WnckScrollerClass *class)
+{
+  GtkObjectClass *object_class;
+  GtkWidgetClass *widget_class;
+
+  object_class = (GtkObjectClass*) class;
+  widget_class = (GtkWidgetClass*) class;
+
+  parent_class = gtk_type_class (gtk_widget_get_type ());
+
+  object_class->destroy = wnck_scroller_destroy;
+
+  widget_class->realize = wnck_scroller_realize;
+  widget_class->expose_event = wnck_scroller_expose;
+  widget_class->size_request = wnck_scroller_size_request;
+  widget_class->size_allocate = wnck_scroller_size_allocate;
+  widget_class->button_press_event = wnck_scroller_button_press;
+  widget_class->button_release_event = wnck_scroller_button_release;
+  widget_class->motion_notify_event = wnck_scroller_motion_notify;
+  widget_class->enter_notify_event = wnck_scroller_enter_notify;
+  widget_class->leave_notify_event = wnck_scroller_leave_notify;
+}
+
+static void
+wnck_scroller_init (WnckScroller *scroller)
+{
+  scroller->in_child = NO_ARROW;
+  scroller->click_child = NO_ARROW;
+  scroller->adjustment = NULL;
+}
+
+GtkWidget*
+wnck_scroller_new (GtkAdjustment *adjustment)
+{
+  WnckScroller *scroller;
+
+  scroller = gtk_type_new (wnck_scroller_get_type ());
+
+  if (!adjustment)
+    adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
+
+  wnck_scroller_set_adjustment (scroller, adjustment);
+  wnck_scroller_set_orientation (scroller, GTK_ORIENTATION_HORIZONTAL);
+
+  return GTK_WIDGET (scroller);
+}
+
+static void
+wnck_scroller_destroy (GtkObject *object)
+{
+  WnckScroller *scroller;
+  g_return_if_fail (object != NULL);
+  g_return_if_fail (WNCK_IS_SCROLLER (object));
+
+  scroller = WNCK_SCROLLER (object);
+
+  if (scroller->adjustment)
+    gtk_object_unref (GTK_OBJECT (scroller->adjustment));
+
+  if (GTK_OBJECT_CLASS (parent_class)->destroy)
+    (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
+}
+
+GtkAdjustment*
+wnck_scroller_get_adjustment (WnckScroller *scroller)
+{
+  g_return_val_if_fail (scroller != NULL, NULL);
+  g_return_val_if_fail (WNCK_IS_SCROLLER (scroller), NULL);
+
+  return scroller->adjustment;
+}
+
+void
+wnck_scroller_set_adjustment (WnckScroller  *scroller,
+			      GtkAdjustment *adjustment)
+{
+  g_return_if_fail (scroller != NULL);
+  g_return_if_fail (WNCK_IS_SCROLLER (scroller));
+
+  if (scroller->adjustment)
+  {
+    gtk_signal_disconnect_by_data (GTK_OBJECT (scroller->adjustment), (gpointer) scroller);
+    gtk_object_unref (GTK_OBJECT (scroller->adjustment));
+  }
+
+  scroller->adjustment = adjustment;
+  gtk_object_ref (GTK_OBJECT (scroller->adjustment));
+
+}
+
+void
+wnck_scroller_set_orientation (WnckScroller  *scroller,
+			       GtkOrientation orientation)
+{
+  g_return_if_fail (scroller != NULL);
+  g_return_if_fail (WNCK_IS_SCROLLER (scroller));
+
+  scroller->orientation = orientation;
+}
+
+static void
+wnck_scroller_realize (GtkWidget *widget)
+{
+  WnckScroller *scroller;
+  GdkWindowAttr attributes;
+  gint attributes_mask;
+
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (WNCK_IS_SCROLLER (widget));
+
+  GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
+  scroller = WNCK_SCROLLER (widget);
+
+  attributes.x = widget->allocation.x;
+  attributes.y = widget->allocation.y;
+  attributes.width = widget->allocation.width;
+  attributes.height = widget->allocation.height;
+  attributes.wclass = GDK_INPUT_OUTPUT;
+  attributes.window_type = GDK_WINDOW_CHILD;
+  attributes.event_mask = gtk_widget_get_events (widget) | 
+    GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | 
+    GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
+    GDK_POINTER_MOTION_HINT_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_ENTER_NOTIFY_MASK;
+  attributes.visual = gtk_widget_get_visual (widget);
+  attributes.colormap = gtk_widget_get_colormap (widget);
+
+  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
+  widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask);
+
+  widget->style = gtk_style_attach (widget->style, widget->window);
+
+  gdk_window_set_user_data (widget->window, widget);
+
+  gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE);
+}
+
+static void 
+wnck_scroller_size_request (GtkWidget      *widget,
+			    GtkRequisition *requisition)
+{
+  GTK_WIDGET_CLASS (parent_class)->size_request (widget, requisition);
+  if (WNCK_SCROLLER(widget)->orientation == GTK_ORIENTATION_VERTICAL)
+  {
+    requisition->width = wnck_scroller_get_arrow_size (WNCK_SCROLLER(widget)) + 2*widget->style->xthickness + 1;
+    requisition->height = wnck_scroller_get_arrow_size (WNCK_SCROLLER(widget)) * 2 + 3*widget->style->xthickness;
+  }
+  else
+  {
+    requisition->height = wnck_scroller_get_arrow_size (WNCK_SCROLLER(widget)) + 2*widget->style->xthickness + 1;
+    requisition->width = wnck_scroller_get_arrow_size (WNCK_SCROLLER(widget)) * 2 + 3*widget->style->xthickness;
+  }
+}
+
+static void
+wnck_scroller_size_allocate (GtkWidget     *widget,
+			     GtkAllocation *allocation)
+{
+  WnckScroller *scroller;
+
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (WNCK_IS_SCROLLER (widget));
+  g_return_if_fail (allocation != NULL);
+
+  widget->allocation = *allocation;
+
+  if (GTK_WIDGET_REALIZED (widget))
+    {
+      scroller = WNCK_SCROLLER (widget);
+
+      gdk_window_move_resize (widget->window,
+			      allocation->x, allocation->y,
+			      allocation->width, allocation->height);
+
+    }
+}
+
+static gint
+wnck_scroller_expose (GtkWidget      *widget,
+                             GdkEventExpose *event)
+{
+  WnckScroller *scroller;
+
+  g_return_val_if_fail (WNCK_IS_SCROLLER (widget), FALSE);
+  g_return_val_if_fail (event != NULL, FALSE);
+                                                                                                                                             
+  scroller = WNCK_SCROLLER (widget);
+
+  if (scroller->orientation == GTK_ORIENTATION_VERTICAL)
+    return wnck_scroller_vertical_expose(widget, event);
+  else
+    return wnck_scroller_horizontal_expose(widget, event);
+}
+
+static gint
+wnck_scroller_vertical_expose (GtkWidget        *widget,
+			     GdkEventExpose *event)
+{
+  WnckScroller *scroller = WNCK_SCROLLER (widget);
+  if (GTK_WIDGET_DRAWABLE (widget))
+  {
+    wnck_scroller_draw_arrow (scroller, GTK_ARROW_UP);
+    wnck_scroller_draw_arrow (scroller, GTK_ARROW_DOWN);
+  }
+
+  return FALSE;
+}
+
+static gint
+wnck_scroller_horizontal_expose (GtkWidget        *widget,
+			     GdkEventExpose *event)
+{
+  WnckScroller *scroller = WNCK_SCROLLER (widget);
+
+  if (GTK_WIDGET_DRAWABLE (widget))
+  {
+    wnck_scroller_draw_arrow (scroller, GTK_ARROW_LEFT);
+    wnck_scroller_draw_arrow (scroller, GTK_ARROW_RIGHT);
+  }
+
+  return FALSE;
+}
+
+
+static gint
+wnck_scroller_button_press (GtkWidget      *widget,
+                            GdkEventButton *event)
+{
+  WnckScroller *scroller = WNCK_SCROLLER (widget);
+  if (scroller->orientation == GTK_ORIENTATION_VERTICAL)
+    return wnck_scroller_vertical_button_press(widget, event);
+  else
+    return wnck_scroller_horizontal_button_press(widget, event);
+}
+
+static gint
+wnck_scroller_vertical_button_press (GtkWidget        *widget,
+                            GdkEventButton *event)
+{
+  WnckScroller *scroller = WNCK_SCROLLER (widget);
+  if (event->button != 1)
+  {
+    if (GTK_WIDGET_CLASS (parent_class)->button_press_event)
+      return (* GTK_WIDGET_CLASS (parent_class)->button_press_event) (widget, event);
+    else
+      return FALSE;
+  }
+  if (!scroller->button)
+  {
+    if (event->window == widget->window)
+    {
+      scroller->button = event->button;
+      if (event->y <= widget->requisition.height / 2)
+      {
+          scroller->click_child = GTK_ARROW_UP;
+      }
+      else
+      {
+          scroller->click_child = GTK_ARROW_DOWN;
+      }
+      wnck_scroller_redraw(scroller);
+      return TRUE;
+    }
+    else
+      if (GTK_WIDGET_CLASS (parent_class)->button_press_event)
+        return (* GTK_WIDGET_CLASS (parent_class)->button_press_event) (widget, event);
+      else
+        return FALSE;
+  }
+  if (GTK_WIDGET_CLASS (parent_class)->button_press_event)
+    return (* GTK_WIDGET_CLASS (parent_class)->button_press_event) (widget, event);
+  else
+    return FALSE;
+}
+
+
+static gint
+wnck_scroller_horizontal_button_press (GtkWidget        *widget,
+                            GdkEventButton *event)
+{
+  WnckScroller *scroller = WNCK_SCROLLER (widget);
+  if (event->button != 1)
+  {
+    if (GTK_WIDGET_CLASS (parent_class)->button_press_event)
+      return (* GTK_WIDGET_CLASS (parent_class)->button_press_event) (widget, event);
+    else
+      return FALSE;
+  }
+  if (!scroller->button)
+  {
+    if (event->window == widget->window)
+    {
+      scroller->button = event->button;
+      if (event->x <= widget->requisition.width / 2)
+      {
+          scroller->click_child = GTK_ARROW_LEFT;
+      }
+      else
+      {
+          scroller->click_child = GTK_ARROW_RIGHT;
+      }
+      wnck_scroller_redraw(scroller);
+      return TRUE;
+    }
+    else
+      if (GTK_WIDGET_CLASS (parent_class)->button_press_event)
+        return (* GTK_WIDGET_CLASS (parent_class)->button_press_event) (widget, event);
+      else
+        return FALSE;
+  }
+  if (GTK_WIDGET_CLASS (parent_class)->button_press_event)
+    return (* GTK_WIDGET_CLASS (parent_class)->button_press_event) (widget, event);
+  else
+    return FALSE;
+}
+
+static gint
+wnck_scroller_button_release (GtkWidget      *widget,
+                            GdkEventButton *event)
+{
+  WnckScroller *scroller = WNCK_SCROLLER (widget);
+  if (scroller->orientation == GTK_ORIENTATION_VERTICAL)
+    return wnck_scroller_vertical_button_release(widget, event);
+  else
+    return wnck_scroller_horizontal_button_release(widget, event);
+}
+
+static gint
+wnck_scroller_vertical_button_release (GtkWidget        *widget,
+                              GdkEventButton *event)
+{
+  WnckScroller *scroller = WNCK_SCROLLER (widget);
+  if (event->button != 1)
+  {
+    if (GTK_WIDGET_CLASS (parent_class)->button_release_event)
+      return (* GTK_WIDGET_CLASS (parent_class)->button_release_event) (widget, event);
+    else
+      return FALSE;
+  }
+
+  if (event->button == scroller->button)
+  {
+    int click_child = scroller->click_child;
+
+    if (event->y >= 0 && event->x >= 0 &&
+        event->y <= widget->requisition.height &&
+        event->x <= widget->requisition.width)
+    {
+      if (click_child == GTK_ARROW_UP &&
+          event->y <= widget->requisition.height / 2)
+      {
+        gtk_adjustment_set_value(scroller->adjustment, gtk_adjustment_get_value(scroller->adjustment) - 1.0);
+        gtk_adjustment_value_changed (scroller->adjustment);
+      }
+      else if (click_child == GTK_ARROW_DOWN &&
+               event->y > widget->requisition.height / 2)
+      {
+        gtk_adjustment_set_value(scroller->adjustment, gtk_adjustment_get_value(scroller->adjustment) + 1.0);
+        gtk_adjustment_value_changed (scroller->adjustment);
+      }
+    }
+    scroller->button = 0;
+    scroller->click_child = NO_ARROW;
+    wnck_scroller_redraw(scroller);
+    return TRUE;
+  }
+  else
+    if (GTK_WIDGET_CLASS (parent_class)->button_release_event)
+      return (* GTK_WIDGET_CLASS (parent_class)->button_release_event) (widget, event);
+    else
+      return FALSE;
+
+}
+
+static gint
+wnck_scroller_horizontal_button_release (GtkWidget        *widget,
+                              GdkEventButton *event)
+{
+  WnckScroller *scroller = WNCK_SCROLLER (widget);
+  if (event->button != 1)
+  {
+    if (GTK_WIDGET_CLASS (parent_class)->button_release_event)
+      return (* GTK_WIDGET_CLASS (parent_class)->button_release_event) (widget, event);
+    else
+      return FALSE;
+  }
+
+  if (event->button == scroller->button)
+  {
+    int click_child = scroller->click_child;
+
+    if (event->x >= 0 && event->y >= 0 &&
+        event->x <= widget->requisition.width &&
+        event->y <= widget->requisition.height)
+    {
+      if (click_child == GTK_ARROW_LEFT &&
+          event->x <= widget->requisition.width / 2)
+      {
+        gtk_adjustment_set_value(scroller->adjustment, gtk_adjustment_get_value(scroller->adjustment) - 1.0);
+        gtk_adjustment_value_changed (scroller->adjustment);
+      }
+      else if (click_child == GTK_ARROW_RIGHT &&
+               event->x > widget->requisition.width / 2)
+      {
+        gtk_adjustment_set_value(scroller->adjustment, gtk_adjustment_get_value(scroller->adjustment) + 1.0);
+        gtk_adjustment_value_changed (scroller->adjustment);
+      }
+    }
+    scroller->button = 0;
+    scroller->click_child = NO_ARROW;
+    wnck_scroller_redraw(scroller);
+    return TRUE;
+  }
+  else
+    if (GTK_WIDGET_CLASS (parent_class)->button_release_event)
+      return (* GTK_WIDGET_CLASS (parent_class)->button_release_event) (widget, event);
+    else
+      return FALSE;
+
+}
+
+static gint
+wnck_scroller_motion_notify (GtkWidget      *widget,
+                            GdkEventMotion *event)
+{
+  WnckScroller *scroller = WNCK_SCROLLER (widget);
+  if (scroller->orientation == GTK_ORIENTATION_VERTICAL)
+    return wnck_scroller_vertical_motion_notify(widget, event);
+  else
+    return wnck_scroller_horizontal_motion_notify(widget, event);
+}
+
+
+static gint
+wnck_scroller_vertical_motion_notify (GtkWidget        *widget,
+                             GdkEventMotion *event)
+{
+  WnckScroller *scroller = WNCK_SCROLLER (widget);
+  if (scroller->button)
+    return FALSE;
+                                                                                                                                             
+  if (event->window == widget->window)
+  {
+    gint y;
+                                                                                                                                             
+    gdk_window_get_pointer (widget->window, NULL, &y, NULL);
+                                                                                                                                             
+    if (y <= widget->requisition.height / 2 &&
+        scroller->in_child == GTK_ARROW_DOWN)
+    {
+      scroller->in_child = GTK_ARROW_UP;
+      wnck_scroller_redraw (scroller);
+    }
+    else if (y > widget->requisition.height / 2 &&
+             scroller->in_child == GTK_ARROW_UP)
+    {
+      scroller->in_child = GTK_ARROW_DOWN;
+      wnck_scroller_redraw (scroller);
+    }
+    return FALSE;
+  }
+  if (GTK_WIDGET_CLASS (parent_class)->motion_notify_event)
+    return (* GTK_WIDGET_CLASS (parent_class)->motion_notify_event) (widget, event);
+  else
+    return FALSE;
+}
+
+static gint
+wnck_scroller_horizontal_motion_notify (GtkWidget        *widget,
+                             GdkEventMotion *event)
+{
+  WnckScroller *scroller = WNCK_SCROLLER (widget);
+  if (scroller->button)
+    return FALSE;
+                                                                                                                                             
+  if (event->window == widget->window)
+  {
+    gint x;
+                                                                                                                                             
+    gdk_window_get_pointer (widget->window, NULL, &x, NULL);
+                                                                                                                                             
+    if (x <= widget->requisition.width / 2 &&
+        scroller->in_child == GTK_ARROW_RIGHT)
+    {
+      scroller->in_child = GTK_ARROW_LEFT;
+      wnck_scroller_redraw (scroller);
+    }
+    else if (x > widget->requisition.width / 2 &&
+             scroller->in_child == GTK_ARROW_LEFT)
+    {
+      scroller->in_child = GTK_ARROW_RIGHT;
+      wnck_scroller_redraw (scroller);
+    }
+    return FALSE;
+  }
+  if (GTK_WIDGET_CLASS (parent_class)->motion_notify_event)
+    return (* GTK_WIDGET_CLASS (parent_class)->motion_notify_event) (widget, event);
+  else
+    return FALSE;
+}
+
+static gint
+wnck_scroller_enter_notify (GtkWidget      *widget,
+                            GdkEventCrossing *event)
+{
+  WnckScroller *scroller = WNCK_SCROLLER (widget);
+  if (scroller->orientation == GTK_ORIENTATION_VERTICAL)
+    return wnck_scroller_vertical_enter_notify(widget, event);
+  else
+    return wnck_scroller_horizontal_enter_notify(widget, event);
+}
+
+static gint
+wnck_scroller_vertical_enter_notify (GtkWidget        *widget,
+                            GdkEventCrossing *event)
+{
+  WnckScroller *scroller = WNCK_SCROLLER (widget);
+                                                                                                                                             
+  if (event->window == widget->window)
+    {
+      gint x;
+      gint y;
+                                                                                                                                             
+      gdk_window_get_pointer (widget->window, &x, &y, NULL);
+                                                                                                                                             
+      if (y <= widget->requisition.height / 2)
+        scroller->in_child = GTK_ARROW_UP;
+      else
+        scroller->in_child = GTK_ARROW_DOWN;
+                                                                                                                                             
+      wnck_scroller_redraw (scroller);
+    }
+                                                                                                                                             
+  return FALSE;
+}
+
+static gint
+wnck_scroller_horizontal_enter_notify (GtkWidget        *widget,
+                            GdkEventCrossing *event)
+{
+  WnckScroller *scroller = WNCK_SCROLLER (widget);
+                                                                                                                                             
+  if (event->window == widget->window)
+    {
+      gint x;
+      gint y;
+                                                                                                                                             
+      gdk_window_get_pointer (widget->window, &x, &y, NULL);
+                                                                                                                                             
+      if (x <= widget->requisition.width / 2)
+        scroller->in_child = GTK_ARROW_LEFT;
+      else
+        scroller->in_child = GTK_ARROW_RIGHT;
+                                                                                                                                             
+      wnck_scroller_redraw (scroller);
+    }
+                                                                                                                                             
+  return FALSE;
+}
+
+static gint
+wnck_scroller_leave_notify (GtkWidget        *widget,
+                            GdkEventCrossing *event)
+{
+  WnckScroller *scroller = WNCK_SCROLLER (widget);
+  scroller->in_child = NO_ARROW;
+  wnck_scroller_redraw (scroller);
+
+  return FALSE;
+}
+
+
+static void
+wnck_scroller_redraw (WnckScroller *scroller)
+{
+  GtkWidget *widget;
+                                                                                                                                             
+  widget = GTK_WIDGET (scroller);
+                                                                                                                                             
+  if (GTK_WIDGET_DRAWABLE (widget))
+    {
+      gtk_widget_queue_draw (widget);
+      gdk_window_invalidate_rect (widget->window, NULL, TRUE);
+    }
+}
+
+
+static gint
+wnck_scroller_get_arrow_size (WnckScroller *scroller)
+{
+  gint size = pango_font_description_get_size (GTK_WIDGET (scroller)->style->font_desc);
+  gint arrow_size;
+                                                                                                                                              
+  arrow_size = MAX (PANGO_PIXELS (size), MIN_ARROW_WIDTH);
+                                                                                                                                              
+  return arrow_size - arrow_size % 2; /* force even */
+}
+
+
+static void
+wnck_scroller_draw_arrow (WnckScroller *scroller,
+                            GtkArrowType   arrow_type)
+{
+  GtkStateType state_type;
+  GtkShadowType shadow_type;
+  GtkWidget *widget;
+  gint x;
+  gint y;
+  gint height;
+  gint width;
+  gint h, w;
+
+  g_return_if_fail (WNCK_IS_SCROLLER (scroller));
+
+  widget = GTK_WIDGET (scroller);
+                                                                                                                                             
+  if (GTK_WIDGET_DRAWABLE (widget))
+    {
+                                                                                                                                             
+      if (arrow_type == GTK_ARROW_UP)
+        {
+          width = wnck_scroller_get_arrow_size (WNCK_SCROLLER(scroller)) + 2 * widget->style->xthickness + 1;
+          x = 0;
+          y = 0;
+                                                                                                                                             
+          height = widget->requisition.height / 2;
+        }
+      else if (arrow_type == GTK_ARROW_DOWN)
+        {
+          width = wnck_scroller_get_arrow_size (WNCK_SCROLLER(scroller)) + 2 * widget->style->xthickness + 1;
+          x = 0;
+          y = (widget->requisition.height) / 2;
+                                                                                                                                             
+          height = (widget->requisition.height+1) / 2;
+        }
+      else if (arrow_type == GTK_ARROW_LEFT)
+        {
+          height = wnck_scroller_get_arrow_size (WNCK_SCROLLER(scroller)) + 2 * widget->style->xthickness + 1;
+          x = 0;
+          y = 0;
+          width = widget->requisition.width / 2;
+        }
+      else //GTK_ARROW_RIGHT
+        {
+          height = wnck_scroller_get_arrow_size (WNCK_SCROLLER(scroller)) + 2 * widget->style->xthickness + 1;
+          x = (widget->requisition.width) / 2;
+          y = 0;
+          width = (widget->requisition.width+1) / 2;
+        }
+      if (scroller_at_limit (scroller, arrow_type))
+        {
+          shadow_type = GTK_SHADOW_OUT;
+          state_type = GTK_STATE_INSENSITIVE;
+        }
+      else
+        {
+          if (scroller->click_child == arrow_type)
+            {
+              state_type = GTK_STATE_ACTIVE;
+              shadow_type = GTK_SHADOW_IN;
+            }
+          else
+            {
+              if (scroller->in_child == arrow_type &&
+                  scroller->click_child == NO_ARROW)
+                {
+                  state_type = GTK_STATE_PRELIGHT;
+                }
+              else
+                {
+                  state_type = GTK_WIDGET_STATE (widget);
+                }
+                                                                                                                                             
+              shadow_type = GTK_SHADOW_OUT;
+            }
+        }
+                                                                                                                                             
+      gtk_paint_box (widget->style, widget->window,
+                     state_type, shadow_type,
+                     NULL, widget,
+                     (arrow_type == GTK_ARROW_UP)
+                     ? 
+                       "scroller_up" 
+                     : 
+                     (
+                       (arrow_type == GTK_ARROW_DOWN)
+                       ?
+                       "scroller_down"
+                       :
+                       (
+                         (arrow_type == GTK_ARROW_LEFT)
+                         ?
+                         "scroller_left"
+                         :
+                         "scroller_right"
+                       )
+                     ),
+                     x, y, width, height);
+
+      if ( (arrow_type == GTK_ARROW_DOWN) || (arrow_type == GTK_ARROW_UP) )
+        height = widget->requisition.height;
+      else
+        width = widget->requisition.width;
+                                                                                                                                             
+      if (arrow_type == GTK_ARROW_DOWN)
+        {
+          y = height / 2;
+          height = height - y - 2;
+          width -= 4;
+        }
+      else if (arrow_type == GTK_ARROW_UP)
+        {
+          y = 2;
+          height = height / 2 - 2;
+          width -= 4;
+        }
+      else if (arrow_type == GTK_ARROW_RIGHT)
+        {
+          x = width / 2;
+          width = width - x - 2;
+          height -= 4;
+        }
+      else //GTK_ARROW_LEFT
+        {
+          x = 2;
+          width = width / 2 - 2;
+          height -= 4;
+        }
+                                                                                                                                             
+      if ( (arrow_type == GTK_ARROW_DOWN) || (arrow_type == GTK_ARROW_UP) )
+      {                                                                                                                                       
+        if (widget && gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
+          x = 3;
+        else
+          x = 2;
+        w = width / 2;
+        w -= w % 2 - 1; /* force odd */
+        h = (w + 1) / 2;
+        x++;
+        y--;
+      }
+      else
+      {
+        if (widget && gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
+          y = 3;
+        else
+          y = 2;
+        h = height / 2;
+        h -= w % 2 - 1;
+        w = (h + 1) / 2;
+        x++;
+      }
+                                                                                                                                             
+      x += (width - w) / 2;
+      y += (height - h) / 2;
+                                                                                                                                             
+      height = h;
+      width = w;
+                                                                                                                                             
+      gtk_paint_arrow (widget->style, widget->window,
+                       state_type, shadow_type,
+                       NULL, widget, "scroller",
+                       arrow_type, TRUE,
+                       x, y, width, height);
+
+    }
+}
+
+static gboolean 
+scroller_at_limit(WnckScroller *scroller, 
+                  GtkArrowType  arrow_type)
+{
+  switch (arrow_type)
+  {
+    case GTK_ARROW_UP:
+    case GTK_ARROW_LEFT:
+      if (scroller->adjustment->value <= scroller->adjustment->lower)
+        return TRUE;
+      else
+        return FALSE;
+    case GTK_ARROW_DOWN:
+    case GTK_ARROW_RIGHT:
+      if (scroller->adjustment->value >= scroller->adjustment->upper)
+         return TRUE;
+      else
+        return FALSE;
+    default:
+      return FALSE;
+  }
+}
+
diff -r -u -N libwnck-2.4.0.1/libwnck/scroller.h libwnck-2.4.0.1.topatch/libwnck/scroller.h
--- libwnck-2.4.0.1/libwnck/scroller.h	1969-12-31 19:00:00.000000000 -0500
+++ libwnck-2.4.0.1.topatch/libwnck/scroller.h	2003-11-08 21:20:25.000000000 -0500
@@ -0,0 +1,64 @@
+/* tasklist object */
+
+/*
+ * Copyright (C) 2003 Denis Yeldandi
+ *
+ * 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 WNCK_SCROLLER_H
+#define WNCK_SCROLLER_H
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define WNCK_SCROLLER(object)           GTK_CHECK_CAST ((object), wnck_scroller_get_type (), WnckScroller)
+#define WNCK_SCROLLER_CLASS(klass)      GTK_CHECK_CLASS_CAST ((klass), wnck_scroller_get_type (), WnckScrollerClass)
+#define WNCK_IS_SCROLLER(object)        GTK_CHECK_TYPE ((object), wnck_scroller_get_type ())
+
+
+typedef struct _WnckScroller        WnckScroller;
+typedef struct _WnckScrollerClass   WnckScrollerClass;
+
+struct _WnckScroller
+{
+  GtkWidget widget;
+  
+  GtkAdjustment* adjustment;
+  GtkOrientation orientation;
+  GdkWindow* panel;
+  guint in_child : 3;
+  guint click_child : 3; /* valid: GTK_ARROW_UP=0, GTK_ARROW_DOWN=1, GTK_ARROW_LEFT=2, GTK_ARROW_RIGHT=3 or 4=NONE/BOTH */
+  guint button : 3;
+};
+
+struct _WnckScrollerClass
+{
+  GtkWidgetClass parent_class;
+};
+
+GtkWidget     *wnck_scroller_new (GtkAdjustment *adjustment);
+GtkType        wnck_scroller_get_type (void);
+GtkAdjustment *wnck_scroller_get_adjustment (WnckScroller *scroller);
+void           wnck_scroller_set_adjustment (WnckScroller *scroller, GtkAdjustment *adjustment);
+void           wnck_scroller_set_orientation (WnckScroller *scroller, GtkOrientation orientation);
+
+G_END_DECLS
+
+#endif /* WNCK_SCROLLER_H */
+
+
diff -r -u -N libwnck-2.4.0.1/libwnck/tasklist.c libwnck-2.4.0.1.topatch/libwnck/tasklist.c
--- libwnck-2.4.0.1/libwnck/tasklist.c	2003-07-17 16:17:50.000000000 -0400
+++ libwnck-2.4.0.1.topatch/libwnck/tasklist.c	2003-11-08 21:20:11.000000000 -0500
@@ -25,6 +25,7 @@
 #include <string.h>
 #include <stdio.h>
 #include "tasklist.h"
+#include "scroller.h"
 #include "window.h"
 #include "window-action-menu.h"
 #include "workspace.h"
@@ -57,7 +58,6 @@
 typedef struct _WnckTaskClass   WnckTaskClass;
 
 #define MINI_ICON_SIZE 16
-#define DEFAULT_GROUPING_LIMIT 80
 
 #define DEFAULT_WIDTH 1
 #define DEFAULT_HEIGHT 48
@@ -66,6 +66,9 @@
 
 #define N_SCREEN_CONNECTIONS 5
 
+#define SCROLLER_WIDTH (tasklist->priv->Scroller->requisition.width)
+#define SCROLLER_HEIGHT (tasklist->priv->Scroller->requisition.height)
+
 typedef enum
 {
   WNCK_TASK_APPLICATION,
@@ -112,6 +115,7 @@
   guint was_active : 1;      /* used to fixup activation behavior */ 
 
   guint button_activate;
+  gint order;
 };
 
 struct _WnckTaskClass
@@ -127,7 +131,7 @@
   WnckTask *active_app; /* NULL if active window not in tasklist */
   
   gboolean include_all_workspaces;
-  
+ 
   /* Calculated by update_lists */
   GList *windows;
   GList *applications;
@@ -146,23 +150,31 @@
   gboolean switch_workspace_on_unminimize;
   
   WnckTasklistGroupingType grouping;
-  gint grouping_limit;
 
   guint activate_timeout_id;
   guint screen_connections [N_SCREEN_CONNECTIONS];
 
   guint idle_callback_tag;
 
-  int *size_hints;
-  int size_hints_len;
-
   gint minimum_width;
   gint minimum_height;
 
+  gint minimum_buttons_width;
+  gint maximum_buttons_width;
+
+  WnckTasklistSortingType sorting_type;
+
   WnckLoadIconFunction icon_loader;
   void *icon_loader_data;
   GDestroyNotify free_icon_loader_data;
-  
+
+  gboolean needScroller;
+
+  GtkWidget* Scroller;
+  GtkAdjustment* ScrollerAdj;
+
+  GtkOrientation orientation;
+ 
 #ifdef HAVE_STARTUP_NOTIFICATION
   SnMonitorContext *sn_context;
   guint startup_sequence_timeout;
@@ -213,7 +225,8 @@
 					     int             max_height,
 					     int             n_buttons,
 					     int            *n_cols_out,
-					     int            *n_rows_out);
+					     int            *n_rows_out,
+					     WnckTasklist   *tasklist);
 
 static void     wnck_tasklist_active_window_changed    (WnckScreen   *screen,
 							WnckTasklist *tasklist);
@@ -247,7 +260,6 @@
                                                         WnckWindow     *window);
 #endif
 
-
 static gpointer task_parent_class;
 static gpointer tasklist_parent_class;
 
@@ -425,6 +437,13 @@
 }
 
 static void
+wnck_tasklist_scroller_adj_changed(GtkAdjustment *adjustment,
+                                   WnckTasklist *tasklist)
+{
+  gtk_widget_queue_resize (GTK_WIDGET (tasklist));
+}
+
+static void
 wnck_tasklist_init (WnckTasklist *tasklist)
 {
   GTK_WIDGET_SET_FLAGS (GTK_WIDGET (tasklist), GTK_NO_WINDOW);
@@ -437,12 +456,18 @@
   tasklist->priv->app_hash = g_hash_table_new (NULL, NULL);
   
   tasklist->priv->grouping = WNCK_TASKLIST_AUTO_GROUP;
-  tasklist->priv->grouping_limit = DEFAULT_GROUPING_LIMIT;
-
+  tasklist->priv->sorting_type = WNCK_TASKLIST_DONT_SORT;
+  tasklist->priv->orientation = GTK_ORIENTATION_HORIZONTAL;
   tasklist->priv->minimum_width = DEFAULT_WIDTH;
   tasklist->priv->minimum_height = DEFAULT_HEIGHT;
 
   tasklist->priv->idle_callback_tag = 0;
+
+  tasklist->priv->ScrollerAdj = GTK_ADJUSTMENT(gtk_adjustment_new(0, 0, 0, 0.1, 0.1, 0));
+  g_signal_connect(tasklist->priv->ScrollerAdj, "value_changed", G_CALLBACK(wnck_tasklist_scroller_adj_changed), G_OBJECT(tasklist));
+  tasklist->priv->Scroller = wnck_scroller_new(tasklist->priv->ScrollerAdj);
+  gtk_widget_set_parent (tasklist->priv->Scroller, GTK_WIDGET (tasklist));
+
 }
 
 static void
@@ -502,11 +527,6 @@
       g_object_unref (tasklist->priv->tooltips);
       tasklist->priv->tooltips = NULL;
     }
-
-  g_free (tasklist->priv->size_hints);
-  tasklist->priv->size_hints = NULL;
-  tasklist->priv->size_hints_len = 0;
-
   g_free (tasklist->priv);
   tasklist->priv = NULL;  
   
@@ -551,18 +571,6 @@
   gtk_widget_queue_resize (GTK_WIDGET (tasklist));
 }
 
-void
-wnck_tasklist_set_grouping_limit (WnckTasklist *tasklist,
-				  gint          limit)
-{
-  g_return_if_fail (WNCK_IS_TASKLIST (tasklist));
-
-  if (tasklist->priv->grouping_limit == limit)
-    return;
-
-  tasklist->priv->grouping_limit = limit;
-  gtk_widget_queue_resize (GTK_WIDGET (tasklist));
-}
 
 /* set the minimum width 
  * use -1 to unset it (resulting in the default width */
@@ -613,7 +621,82 @@
 	
   return tasklist->priv->minimum_height;
 }
+/* set the minimum buttons width 
+ * use -1 to unset it (resulting in the default width */
+void 
+wnck_tasklist_set_minimum_buttons_width (WnckTasklist *tasklist, gint size)
+{
+  g_return_if_fail (WNCK_IS_TASKLIST (tasklist));
+
+  if (size == -1) size = DEFAULT_WIDTH;
+
+  if (tasklist->priv->minimum_buttons_width == size)
+    return;
 
+  tasklist->priv->minimum_buttons_width = size;
+  gtk_widget_queue_resize (GTK_WIDGET (tasklist));
+}
+ 
+/* get the minimum buttons width */
+gint
+wnck_tasklist_get_minimum_buttons_width (WnckTasklist *tasklist)
+{
+  g_return_val_if_fail (WNCK_IS_TASKLIST (tasklist), 0);
+	
+  return tasklist->priv->minimum_buttons_width;
+}
+
+/* set the maximum buttons width 
+ * use -1 to unset it (resulting in the default width */
+void 
+wnck_tasklist_set_maximum_buttons_width (WnckTasklist *tasklist, gint size)
+{
+  g_return_if_fail (WNCK_IS_TASKLIST (tasklist));
+
+  if (size == -1) size = DEFAULT_WIDTH;
+
+  if (tasklist->priv->maximum_buttons_width == size)
+    return;
+
+  tasklist->priv->maximum_buttons_width = size;
+  gtk_widget_queue_resize (GTK_WIDGET (tasklist));
+}
+ 
+/* get the maximum buttons width */
+gint
+wnck_tasklist_get_maximum_buttons_width (WnckTasklist *tasklist)
+{
+  g_return_val_if_fail (WNCK_IS_TASKLIST (tasklist), 0);
+	
+  return tasklist->priv->maximum_buttons_width;
+}
+
+void 
+wnck_tasklist_set_sorting_type (WnckTasklist *tasklist, WnckTasklistSortingType sorting_type)
+{
+  g_return_if_fail (WNCK_IS_TASKLIST (tasklist));
+
+  if (tasklist->priv->sorting_type == sorting_type)
+    return;
+
+  tasklist->priv->sorting_type = sorting_type;
+  gtk_widget_queue_resize (GTK_WIDGET (tasklist));
+}
+
+void 
+wnck_tasklist_set_orientation (WnckTasklist *tasklist, GtkOrientation orientation)
+{
+  g_return_if_fail (WNCK_IS_TASKLIST (tasklist));
+
+  if (tasklist->priv->orientation == orientation)
+    return;
+
+  tasklist->priv->orientation = orientation;
+  wnck_scroller_set_orientation(WNCK_SCROLLER(tasklist->priv->Scroller), orientation==GTK_ORIENTATION_HORIZONTAL?GTK_ORIENTATION_VERTICAL:GTK_ORIENTATION_HORIZONTAL);
+
+  gtk_widget_queue_resize (GTK_WIDGET (tasklist));
+}
+ 
 /**
  * wnck_tasklist_set_icon_loader:
  * @tasklist: a #WnckTasklist
@@ -650,25 +733,93 @@
 		      int            max_height,
 		      int            n_buttons,
 		      int           *n_cols_out,
-		      int           *n_rows_out)
+		      int           *n_rows_out,
+		      WnckTasklist  *tasklist)
 {
   int n_cols, n_rows;
+  int buttons_width;
 
-  /* How many rows fit in the allocation */
-  n_rows = allocation->height / max_height;
-
-  /* Don't have more rows than buttons */
-  n_rows = MIN (n_rows, n_buttons);
-
-  /* At least one row */
-  n_rows = MAX (n_rows, 1);
-  
-  /* We want to use as many rows as possible to limit the width */
-  n_cols = (n_buttons + n_rows - 1) / n_rows;
-
-  /* At least one column */
-  n_cols = MAX (n_cols, 1);
-
+  if (tasklist->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
+  {
+    n_rows = allocation->height / max_height;
+    n_rows = MIN (n_rows, n_buttons);
+    n_rows = MAX (n_rows, 1);
+ 
+    buttons_width = wnck_tasklist_get_maximum_buttons_width(tasklist);
+ 
+    if (allocation->width <= 0)
+      n_cols = n_buttons;
+    else
+    {
+      buttons_width = MIN (wnck_tasklist_get_maximum_buttons_width(tasklist), (allocation->width * n_rows)/(n_buttons>0?n_buttons:1));
+      buttons_width = MAX (1, buttons_width);
+      n_cols = ( (allocation->width * n_rows) / buttons_width + n_rows - 1 ) / n_rows;
+      n_cols = MAX (n_cols, 1);
+      if (
+           (buttons_width < wnck_tasklist_get_minimum_buttons_width(tasklist)) 
+           && 
+           (allocation->width - SCROLLER_WIDTH > wnck_tasklist_get_minimum_buttons_width(tasklist))
+         )
+      {
+        wnck_scroller_set_orientation(WNCK_SCROLLER(tasklist->priv->Scroller), GTK_ORIENTATION_VERTICAL);
+        tasklist->priv->needScroller = TRUE;
+        tasklist->priv->ScrollerAdj->upper = n_cols / (int)(((double)(allocation->width-SCROLLER_WIDTH)) / wnck_tasklist_get_minimum_buttons_width(tasklist));
+        gtk_adjustment_changed (tasklist->priv->ScrollerAdj);
+        n_cols = (int)(((double)(allocation->width-SCROLLER_WIDTH)) / wnck_tasklist_get_minimum_buttons_width(tasklist));
+      }
+      else
+      {
+        tasklist->priv->needScroller = FALSE;
+        tasklist->priv->ScrollerAdj->upper = 0;
+        gtk_adjustment_changed (tasklist->priv->ScrollerAdj);
+        gtk_adjustment_set_value(tasklist->priv->ScrollerAdj, 0);
+      }
+    }
+    n_cols = MAX (1, n_cols);
+  }
+  else
+  {
+    n_rows = allocation->height / max_height;
+    n_rows = MIN (n_rows, n_buttons);
+    n_rows = MAX (n_rows, 1);
+ 
+    buttons_width = wnck_tasklist_get_maximum_buttons_width(tasklist);
+ 
+    if (allocation->width <= 0)
+      n_cols = n_buttons;
+    else
+    {
+      buttons_width = MIN (wnck_tasklist_get_maximum_buttons_width(tasklist), (allocation->width * n_rows)/(n_buttons>0?n_buttons:1));
+      buttons_width = MAX (1, buttons_width);
+      n_cols = (allocation->width ) / wnck_tasklist_get_maximum_buttons_width(tasklist);
+      n_cols = MAX (n_cols, 1);
+      if (
+           (buttons_width < wnck_tasklist_get_minimum_buttons_width(tasklist)) 
+           && 
+           (allocation->height - SCROLLER_HEIGHT >= max_height)
+           &&
+           (n_cols * n_rows < n_buttons)
+         )
+      {
+        wnck_scroller_set_orientation(WNCK_SCROLLER(tasklist->priv->Scroller), GTK_ORIENTATION_HORIZONTAL);
+        tasklist->priv->needScroller = TRUE;
+        n_rows = (allocation->height - SCROLLER_HEIGHT) / max_height;
+        n_rows = MIN (n_rows, n_buttons);
+        n_rows = MAX (n_rows, 1);
+        tasklist->priv->ScrollerAdj->upper = (n_buttons + n_rows - 1) / n_rows - 1;
+        gtk_adjustment_changed (tasklist->priv->ScrollerAdj);
+        n_cols = (int)(((double)(allocation->width)) / wnck_tasklist_get_minimum_buttons_width(tasklist));
+      }
+      else
+      {
+        tasklist->priv->needScroller = FALSE;
+        tasklist->priv->ScrollerAdj->upper = 0;
+        gtk_adjustment_changed (tasklist->priv->ScrollerAdj);
+        gtk_adjustment_set_value(tasklist->priv->ScrollerAdj, 0);
+      }
+    }
+    n_cols = MAX (1, n_cols);
+  }
   *n_cols_out = n_cols;
   *n_rows_out = n_rows;
   
@@ -760,23 +911,10 @@
 {
   WnckTasklist *tasklist;
   GtkRequisition child_req;
-  GtkAllocation  fake_allocation;
   int max_height = 1;
   int max_width = 1;
   /* int u_width, u_height; */
   GList *l;
-  GArray *array;
-  GList *ungrouped_apps;
-  int n_windows;
-  int n_startup_sequences;
-  int n_rows;
-  int n_cols, last_n_cols;
-  int n_grouped_buttons;
-  gboolean score_set;
-  int val;
-  WnckTask *app_task;
-  int lowest_range;
-  int grouping_limit;
   
   tasklist = WNCK_TASKLIST (widget);
 
@@ -825,139 +963,16 @@
       
       l = l->next;
     }
-  
+
+  gtk_widget_size_request (tasklist->priv->Scroller, &child_req);
+ 
   tasklist->priv->max_button_width = max_width;
   tasklist->priv->max_button_height = max_height;
 
-
-  /* this snippet of code seems to want to allocate at least
-   * four buttons' worth of height for the widget.  I think this isn't
-   * necessary any more now that we have the minimum_size option, so
-   * I'm commenting this out - thomasvs */
-  /*
-  gtk_widget_get_size_request (widget, &u_width, &u_height);
-
-  if (u_height != -1)
-    {
-      requisition->height = u_height;
-    }
-  else if (u_width != -1)
-    {
-      requisition->width = u_width;
-      requisition->height = 4 * max_height;
-    }
-  
-  requisition->width = MAX(requisition->width, tasklist->priv->minimum_width);
-  requisition->height = MAX(requisition->height, tasklist->priv->minimum_height);
-  */
-  requisition->width = tasklist->priv->minimum_width;
-  requisition->height = tasklist->priv->minimum_height;
-  
-  fake_allocation.width = requisition->width;
-  fake_allocation.height = requisition->height;
-
-  array = g_array_new (FALSE, FALSE, sizeof (int));
-
-  /* Calculate size_hints list */
-  
-  n_windows = g_list_length (tasklist->priv->windows);
-  n_startup_sequences = g_list_length (tasklist->priv->startup_sequences);
-  n_grouped_buttons = 0;
-  ungrouped_apps = g_list_copy (tasklist->priv->applications);
-  score_set = FALSE;
-
-  grouping_limit = MIN (tasklist->priv->grouping_limit,
-			tasklist->priv->max_button_width);
-  
-  /* Try ungrouped mode */
-  wnck_tasklist_layout (&fake_allocation,
-			tasklist->priv->max_button_width,
-			tasklist->priv->max_button_height,
-			n_windows + n_startup_sequences,
-			&n_cols, &n_rows);
-
-  last_n_cols = G_MAXINT;
-  lowest_range = G_MAXINT;
-  if (tasklist->priv->grouping != WNCK_TASKLIST_ALWAYS_GROUP)
-    {
-      val = n_cols * tasklist->priv->max_button_width;
-      g_array_insert_val (array, array->len, val);
-      val = n_cols * grouping_limit;
-      g_array_insert_val (array, array->len, val);
-
-      last_n_cols = n_cols;
-      lowest_range = val;
-    }
-
-  while (ungrouped_apps != NULL &&
-	 tasklist->priv->grouping != WNCK_TASKLIST_NEVER_GROUP)
-    {
-      if (!score_set)
-	{
-	  wnck_tasklist_score_groups (tasklist, ungrouped_apps);
-	  score_set = TRUE;
-	}
-
-      ungrouped_apps = wnck_task_get_highest_scored (ungrouped_apps, &app_task);
-
-      n_grouped_buttons += g_list_length (app_task->windows) - 1;
-
-      wnck_tasklist_layout (&fake_allocation,
-			    tasklist->priv->max_button_width,
-			    tasklist->priv->max_button_height,
-			    n_startup_sequences + n_windows - n_grouped_buttons,
-			    &n_cols, &n_rows);
-      if (n_cols != last_n_cols &&
-	  (tasklist->priv->grouping == WNCK_TASKLIST_AUTO_GROUP ||
-	   ungrouped_apps == NULL))
-	{
-	  val = n_cols * tasklist->priv->max_button_width;
-	  if (val >= lowest_range)
-	    { /* Overlaps old range */
-	      lowest_range = n_cols * grouping_limit;
-	      if (array->len > 0)
-		g_array_index(array, int, array->len-1) = lowest_range;
-	      else
-		g_array_insert_val (array, 0, lowest_range);
-	    }
-	  else
-	    {
-	      /* Full new range */
-	      g_array_insert_val (array, array->len, val);
-	      val = n_cols * grouping_limit;
-	      g_array_insert_val (array, array->len, val);
-	      lowest_range = val;
-	    }
-
-	  last_n_cols = n_cols;
-	}
-    }
-
-  /* Always let you go down to a zero size: */
-  if (array->len > 0)
-    g_array_index(array, int, array->len-1) = 0;
-  else
-    {
-      val = 0;
-      g_array_insert_val (array, 0, val);
-    }
-  
-  if (tasklist->priv->size_hints)
-    g_free (tasklist->priv->size_hints);
-
-  tasklist->priv->size_hints_len = array->len;
-    
-  tasklist->priv->size_hints = (int *)g_array_free (array, FALSE);
+  requisition->width = 0;
+  requisition->height = 0;
 }
 
-const int *
-wnck_tasklist_get_size_hint_list (WnckTasklist  *tasklist,
-				  int           *n_elements)
-{
-  *n_elements = tasklist->priv->size_hints_len;
-  return tasklist->priv->size_hints;
-}
-  
 static void
 wnck_tasklist_size_allocate (GtkWidget      *widget,
                              GtkAllocation  *allocation)
@@ -970,6 +985,7 @@
   GList *l;
   int button_width;
   int total_width;
+  int total_height;
   int n_rows;
   int n_cols;
   int n_grouped_buttons;
@@ -978,8 +994,7 @@
   GList *ungrouped_apps;
   WnckTask *win_task;
   GList *visible_tasks = NULL;
-  int grouping_limit;
-  
+
   tasklist = WNCK_TASKLIST (widget);
 
   n_windows = g_list_length (tasklist->priv->windows);
@@ -988,19 +1003,18 @@
   ungrouped_apps = g_list_copy (tasklist->priv->applications);
   score_set = FALSE;
 
-  grouping_limit = MIN (tasklist->priv->grouping_limit,
-			tasklist->priv->max_button_width);
 
   /* Try ungrouped mode */
   button_width = wnck_tasklist_layout (allocation,
 				       tasklist->priv->max_button_width,
 				       tasklist->priv->max_button_height,
 				       n_startup_sequences + n_windows,
-				       &n_cols, &n_rows);
+				       &n_cols, &n_rows, tasklist);
+
   while (ungrouped_apps != NULL &&
 	 ((tasklist->priv->grouping == WNCK_TASKLIST_ALWAYS_GROUP) ||
 	  ((tasklist->priv->grouping == WNCK_TASKLIST_AUTO_GROUP) &&
-	   (button_width < grouping_limit))))
+	   tasklist->priv->needScroller)))
     {
       if (!score_set)
 	{
@@ -1036,7 +1050,7 @@
 					   tasklist->priv->max_button_width,
 					   tasklist->priv->max_button_height,
 					   n_startup_sequences + n_windows - n_grouped_buttons,
-					   &n_cols, &n_rows);
+					   &n_cols, &n_rows, tasklist);
     }
 
   /* Add all ungrouped windows to visible_tasks, and hide their apps */
@@ -1044,7 +1058,6 @@
   while (l != NULL)
     {
       app_task = WNCK_TASK (l->data);
-      
       visible_tasks = g_list_concat (visible_tasks, g_list_copy (app_task->windows));
       gtk_widget_set_child_visible (GTK_WIDGET (app_task->button), FALSE);
       l = l->next;
@@ -1059,19 +1072,44 @@
   /* Allocate children */
   l = visible_tasks;
   i = 0;
-  total_width = tasklist->priv->max_button_width * n_cols;
-  total_width = MIN (total_width, allocation->width);
-  total_width = allocation->width;
+  total_width = wnck_tasklist_get_maximum_buttons_width(tasklist) * n_cols;
+  total_height = tasklist->priv->max_button_height * n_rows;
+
+  if (tasklist->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
+  {
+    total_width = MIN (total_width, allocation->width - (tasklist->priv->needScroller?SCROLLER_WIDTH:0));
+    total_height = MIN (total_height, allocation->height);
+    if (tasklist->priv->needScroller)
+      for (i=0; (i<n_cols*gtk_adjustment_get_value(tasklist->priv->ScrollerAdj)) && (l!=NULL); i++, l = l->next)
+        gtk_widget_set_child_visible (GTK_WIDGET(WNCK_TASK (l->data)->button), FALSE);
+
+  }
+  else
+  {
+    total_width = MIN (total_width, allocation->width);
+    total_height = MIN (total_height, allocation->height - (tasklist->priv->needScroller?SCROLLER_HEIGHT:0));
+    if (tasklist->priv->needScroller)
+      for (i=0; (i<n_rows*gtk_adjustment_get_value(tasklist->priv->ScrollerAdj)) && (l!=NULL); i++, l = l->next)
+        gtk_widget_set_child_visible (GTK_WIDGET(WNCK_TASK (l->data)->button), FALSE);
+  }
+
+  i=0;
   while (l != NULL)
     {
       WnckTask *task = WNCK_TASK (l->data);
       int col = i % n_cols;
       int row = i / n_cols;
-      
+      if (row >= n_rows)
+      {
+        gtk_widget_set_child_visible (GTK_WIDGET (task->button), FALSE);
+        i++;
+        l = l->next;
+        continue;
+      }
       child_allocation.x = total_width*col / n_cols;
-      child_allocation.y = allocation->height*row / n_rows;
+      child_allocation.y = total_height*row / n_rows;
       child_allocation.width = total_width*(col + 1) / n_cols - child_allocation.x;
-      child_allocation.height = allocation->height*(row + 1) / n_rows - child_allocation.y;
+      child_allocation.height = tasklist->priv->max_button_height;
       child_allocation.x += allocation->x;
       child_allocation.y += allocation->y;
 
@@ -1081,6 +1119,30 @@
       i++;
       l = l->next;
     }
+  if (tasklist->priv->needScroller)
+  {
+    if (tasklist->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
+    {
+      child_allocation.x = allocation->x + allocation->width - SCROLLER_WIDTH;
+      child_allocation.y = allocation->y + (allocation->height - SCROLLER_HEIGHT) / 2;
+      child_allocation.width = SCROLLER_WIDTH;
+      child_allocation.height = SCROLLER_HEIGHT;
+    }
+    else
+    {
+      child_allocation.x = allocation->x + (allocation->width - SCROLLER_WIDTH) / 2;
+      child_allocation.y = allocation->y + allocation->height - SCROLLER_HEIGHT;
+      child_allocation.width = SCROLLER_WIDTH;
+      child_allocation.height = SCROLLER_HEIGHT;
+    }
+    gtk_widget_size_allocate (tasklist->priv->Scroller, &child_allocation);
+    gtk_widget_show_all (tasklist->priv->Scroller);
+    gtk_widget_set_child_visible (tasklist->priv->Scroller, TRUE);
+  }
+  else
+  {
+    gtk_widget_hide_all (tasklist->priv->Scroller);
+  }
   g_list_free (visible_tasks);
 
   /* Update icon geometries. */
@@ -1089,13 +1151,13 @@
   GTK_WIDGET_CLASS (tasklist_parent_class)->size_allocate (widget, allocation);
 }
 
+
 static void
 wnck_tasklist_realize (GtkWidget *widget)
 {
   WnckTasklist *tasklist;
 
   tasklist = WNCK_TASKLIST (widget);  
-
 #ifdef HAVE_STARTUP_NOTIFICATION
   tasklist->priv->sn_context =
     sn_monitor_context_new (_wnck_screen_get_sn_display (tasklist->priv->screen),
@@ -1160,6 +1222,7 @@
       
       (* callback) (task->button, callback_data);
     }
+  (* callback) (tasklist->priv->Scroller, callback_data);
 }
 
 static void
@@ -1413,7 +1476,7 @@
   GList *l;
   WnckTask *app_task;
   WnckTask *win_task;
-
+  gint i=0;
   wnck_tasklist_free_tasks (tasklist);
   
   windows = wnck_screen_get_windows (tasklist->priv->screen);
@@ -1426,6 +1489,7 @@
       if (wnck_tasklist_include_window (tasklist, win))
 	{
 	  win_task = wnck_task_new_from_window (tasklist, win);
+          win_task->order = i++;
 	  tasklist->priv->windows = g_list_prepend (tasklist->priv->windows, win_task);
 	  g_hash_table_insert (tasklist->priv->win_hash, win, win_task);
 	  
@@ -1438,6 +1502,7 @@
 	  if (app_task == NULL)
 	    {
 	      app_task = wnck_task_new_from_application (tasklist, app);
+              app_task->order = i++;
 	      gtk_widget_set_parent (app_task->button, GTK_WIDGET (tasklist));
 	      gtk_widget_show (app_task->button);
 	      
@@ -2430,14 +2495,15 @@
 }
 
 static gint
-wnck_task_compare (gconstpointer  a,
+wnck_task_application_sort_compare (gconstpointer  a,
 		   gconstpointer  b)
 {
+
   WnckTask *task1 = WNCK_TASK (a);
   WnckTask *task2 = WNCK_TASK (b);
   gulong xid1_1, xid1_2;
   gulong xid2_1, xid2_2;
-  
+
   xid1_1 = xid1_2 = xid2_1 = xid2_2 = 0;   /* silence compiler */
   
   switch (task1->type)
@@ -2467,7 +2533,7 @@
       xid2_1 = xid2_2 = G_MAXULONG;
       break;
     }
-      
+
   if ((xid1_1 < xid2_1) || ((xid1_1 == xid2_1) && (xid1_2 < xid2_2)))
     return -1;
   else if ((xid1_1 == xid2_1) && (xid1_2 == xid2_2))
@@ -2476,6 +2542,42 @@
     return 1;
 }
 
+static gint
+wnck_task_dont_sort_compare (gconstpointer  a,
+		   gconstpointer  b)
+{
+
+  WnckTask *task1 = WNCK_TASK (a);
+  WnckTask *task2 = WNCK_TASK (b);
+
+  if (task1->type == WNCK_TASK_STARTUP_SEQUENCE)
+    task1->order = G_MAXULONG;
+
+  if (task2->type == WNCK_TASK_STARTUP_SEQUENCE)
+    task2->order = G_MAXULONG;
+
+  if (task1->order < task2->order)
+    return -1;
+  else if (task1->order == task2->order)
+    return 0;
+  else 
+    return 1;
+}
+
+static gint
+wnck_task_compare (gconstpointer  a,
+		   gconstpointer  b)
+{
+
+  WnckTask *task = WNCK_TASK (a);
+  WnckTasklist *tasklist = WNCK_TASKLIST (task->tasklist);
+
+  if (tasklist->priv->sorting_type == WNCK_TASKLIST_DONT_SORT)
+    return wnck_task_dont_sort_compare(a,b);
+  if (tasklist->priv->sorting_type == WNCK_TASKLIST_APPLICATION_SORT)
+    return wnck_task_application_sort_compare(a,b);
+  return 0;
+}
 static void
 remove_startup_sequences_for_window (WnckTasklist *tasklist,
                                      WnckWindow   *window)
diff -r -u -N libwnck-2.4.0.1/libwnck/tasklist.h libwnck-2.4.0.1.topatch/libwnck/tasklist.h
--- libwnck-2.4.0.1/libwnck/tasklist.h	2002-11-30 22:55:43.000000000 -0500
+++ libwnck-2.4.0.1.topatch/libwnck/tasklist.h	2003-11-08 21:20:11.000000000 -0500
@@ -56,26 +56,38 @@
   WNCK_TASKLIST_ALWAYS_GROUP,
 } WnckTasklistGroupingType;
 
+typedef enum {
+  WNCK_TASKLIST_DONT_SORT,
+  WNCK_TASKLIST_APPLICATION_SORT,
+} WnckTasklistSortingType;
+
 GType wnck_tasklist_get_type (void) G_GNUC_CONST;
 
 GtkWidget *wnck_tasklist_new (WnckScreen *screen);
 void       wnck_tasklist_set_screen (WnckTasklist *tasklist,
 				     WnckScreen   *screen);
-const int *wnck_tasklist_get_size_hint_list (WnckTasklist  *tasklist,
-					      int           *n_elements);
-
 void wnck_tasklist_set_grouping (WnckTasklist             *tasklist,
 				 WnckTasklistGroupingType  grouping);
 void wnck_tasklist_set_switch_workspace_on_unminimize (WnckTasklist  *tasklist,
 						       gboolean       switch_workspace_on_unminimize);
-void wnck_tasklist_set_grouping_limit (WnckTasklist *tasklist,
-				       gint          limit);
 void wnck_tasklist_set_include_all_workspaces (WnckTasklist *tasklist,
 					       gboolean      include_all_workspaces);
+void wnck_tasklist_set_sorting_type (WnckTasklist            *tasklist,
+				     WnckTasklistSortingType sorting_type);
+void wnck_tasklist_set_orientation (WnckTasklist            *tasklist,
+				    GtkOrientation orientation);
+
+
 void wnck_tasklist_set_minimum_width (WnckTasklist *tasklist, gint size);
 gint wnck_tasklist_get_minimum_width (WnckTasklist *tasklist);
 void wnck_tasklist_set_minimum_height (WnckTasklist *tasklist, gint size);
 gint wnck_tasklist_get_minimum_height (WnckTasklist *tasklist);
+void wnck_tasklist_set_minimum_buttons_width (WnckTasklist *tasklist, gint size);
+gint wnck_tasklist_get_minimum_buttons_width (WnckTasklist *tasklist);
+void wnck_tasklist_set_maximum_buttons_width (WnckTasklist *tasklist, gint size);
+gint wnck_tasklist_get_maximum_buttons_width (WnckTasklist *tasklist);
+
+
 
 typedef GdkPixbuf* (*WnckLoadIconFunction) (const char   *icon_name,
                                             int           size,
