Index: tasklist.c
===================================================================
--- libwnck/tasklist.c	(révision 1379)
+++ libwnck/tasklist.c	(copie de travail)
@@ -35,6 +35,7 @@
 #include "workspace.h"
 #include "xutils.h"
 #include "private.h"
+#include "obox.h"

 /**
  * SECTION:tasklist
@@ -118,6 +119,7 @@ struct _WnckTask
   GtkWidget *button;
   GtkWidget *image;
   GtkWidget *label;
+  GtkWidget *obox;

   WnckTaskType type;

@@ -198,6 +200,9 @@ struct _WnckTasklistPrivate
   GHashTable *class_group_hash;
   GHashTable *win_hash;

+  gboolean vertical_mode;
+  gboolean rotated;
+
   gint max_button_width;
   gint max_button_height;

@@ -677,6 +682,9 @@ wnck_tasklist_init (WnckTasklist *taskli
   tasklist->priv->class_group_hash = g_hash_table_new (NULL, NULL);
   tasklist->priv->win_hash = g_hash_table_new (NULL, NULL);

+  tasklist->priv->vertical_mode = FALSE;
+  tasklist->priv->rotated = FALSE;
+
   tasklist->priv->max_button_width = 0;
   tasklist->priv->max_button_height = 0;

@@ -1000,6 +1008,31 @@ wnck_tasklist_set_include_all_workspaces
 }

 /**
+ * wnck_tasklist_set_vertical_mode:
+ * @tasklist: a #WnckTasklist.
+ * @vertical_mode: whether to put @tasklist in vertical mode.
+ *
+ * Activates or deactivates the vertical mode of @tasklist according to
+ * @vertical_mode. The vertical mode is a specific mode for #WnckTasklist
+ * widgets, to be used when they are on vertical panels, for example. The task
+ * buttons will be rotated if there is not enough space for them to be
+ * horizontal, and the size hints will return a value for the height instead of
+ * the width.
+ */
+void
+wnck_tasklist_set_vertical_mode (WnckTasklist *tasklist,
+                                 gboolean      vertical_mode)
+{
+  g_return_if_fail (WNCK_IS_TASKLIST (tasklist));
+
+  if (tasklist->priv->vertical_mode == vertical_mode)
+    return;
+
+  tasklist->priv->vertical_mode = vertical_mode;
+  gtk_widget_queue_resize (GTK_WIDGET (tasklist));
+}
+
+/**
  * wnck_tasklist_set_grouping_limit:
  * @tasklist: a #WnckTasklist.
  * @limit: a size in pixels.
@@ -1231,28 +1264,48 @@ wnck_task_get_highest_scored (GList
   return g_list_remove (ungrouped_class_groups, best_task);
 }

-static int
-wnck_tasklist_get_button_size (GtkWidget *widget)
+/* This function returns value that are valid for an horizontal button.
+ * If the button gets rotated, returned values should be swapped */
+static void
+wnck_tasklist_get_button_size (GtkWidget *widget,
+                               int       *width,
+                               int       *height)
 {
   PangoContext *context;
   PangoFontMetrics *metrics;
-  gint char_width;
-  gint text_width;
-  gint width;
+  int ascent;
+  int descent;
+  int char_width;
+  int text_width;
+  int focus_width = 0;
+  int focus_pad = 0;
+  int thickness;

   gtk_widget_ensure_style (widget);

   context = gtk_widget_get_pango_context (widget);
   metrics = pango_context_get_metrics (context, widget->style->font_desc,
                                        pango_context_get_language (context));
+  ascent  = pango_font_metrics_get_ascent  (metrics);
+  descent = pango_font_metrics_get_descent (metrics);
   char_width = pango_font_metrics_get_approximate_char_width (metrics);
   pango_font_metrics_unref (metrics);
+
   text_width = PANGO_PIXELS (TASKLIST_TEXT_MAX_WIDTH * char_width);

-  width = text_width + 2 * TASKLIST_BUTTON_PADDING
-	  + MINI_ICON_SIZE + 2 * TASKLIST_BUTTON_PADDING;
+  gtk_widget_style_get (widget,
+                        "focus-line-width", &focus_width,
+                        "focus-padding", &focus_pad,
+                        NULL);
+
+  thickness = MAX (widget->style->ythickness, widget->style->xthickness);
+
+  thickness *= 10;
+
+  *width = text_width + 2 * TASKLIST_BUTTON_PADDING
+           + MINI_ICON_SIZE + 2 * TASKLIST_BUTTON_PADDING
+           + 2 * (focus_width + focus_pad + thickness);

-  return width;
+  *height = MAX (MINI_ICON_SIZE, PANGO_PIXELS (ascent + descent))
+            + 2 * (focus_width + focus_pad + thickness);
 }

 static void
@@ -1260,41 +1313,45 @@ wnck_tasklist_size_request  (GtkWidget
                              GtkRequisition *requisition)
 {
   WnckTasklist *tasklist;
-  GtkRequisition child_req;
   GtkAllocation  fake_allocation;
   int max_height = 1;
   int max_width = 1;
-  /* int u_width, u_height; */
+  int grouping_limit;
+  gboolean vertical_orientation;
   GList *l;
+
+  /* for size hints */
+  int *n_rows_or_cols; /* this points to n_cols in horizontal mode,
+                          and n_rows in vertical mode. The size hints depends
+                          on the number of rows in vertical mode. */
+  int last_n_rows_or_cols;
+  int max_size_for_button;
+  int min_size_for_button;
   GArray *array;
   GList *ungrouped_class_groups;
   int n_windows;
   int n_startup_sequences;
   int n_rows;
-  int n_cols, last_n_cols;
+  int n_cols;
   int n_grouped_buttons;
   gboolean score_set;
   int val;
   WnckTask *class_group_task;
   int lowest_range;
-  int grouping_limit;

   tasklist = WNCK_TASKLIST (widget);

-  /* Calculate max needed height and width of the buttons */
+  /* we need to request the size of the buttons to get the labels properly
+   * aligned. FIXME: why? */
 #define GET_MAX_WIDTH_HEIGHT_FROM_BUTTONS(list)                 \
   l = list;                                                     \
   while (l != NULL)                                             \
     {                                                           \
+      GtkRequisition child_req;                                 \
       WnckTask *task = WNCK_TASK (l->data);                     \
                                                                 \
       gtk_widget_size_request (task->button, &child_req);       \
                                                                 \
-      max_height = MAX (child_req.height,                       \
-			max_height);                            \
-      max_width = MAX (child_req.width,                         \
-		       max_width);                              \
-                                                                \
       l = l->next;                                              \
     }

@@ -1302,17 +1359,47 @@ wnck_tasklist_size_request  (GtkWidget
   GET_MAX_WIDTH_HEIGHT_FROM_BUTTONS (tasklist->priv->class_groups)
   GET_MAX_WIDTH_HEIGHT_FROM_BUTTONS (tasklist->priv->startup_sequences)

-  /* Note that the fact that we nearly don't care about the width/height
-   * requested by the buttons makes it possible to hide/show the label/image
-   * in wnck_task_size_allocated(). If we really cared about those, this
-   * wouldn't work since our call to gtk_widget_size_request() does not take
-   * into account the hidden widgets.
-   */
-  tasklist->priv->max_button_width = wnck_tasklist_get_button_size (widget);
+  wnck_tasklist_get_button_size (widget, &max_width, &max_height);
+
+  grouping_limit = MIN (tasklist->priv->grouping_limit, max_width);
+
+  tasklist->priv->max_button_width = max_width;
   tasklist->priv->max_button_height = max_height;

-  fake_allocation.width = GTK_WIDGET (tasklist)->allocation.width;
-  fake_allocation.height = GTK_WIDGET (tasklist)->allocation.height;
+  /* if we're in vertical mode, the width will most often not change, so we
+   * can assume the current width is okay */
+  if (tasklist->priv->vertical_mode &&
+      GTK_WIDGET (tasklist)->allocation.width < grouping_limit)
+    vertical_orientation = TRUE;
+  else
+    vertical_orientation = FALSE;
+
+  /* changing orientation is just rotating everything */
+  if (!tasklist->priv->vertical_mode || vertical_orientation)
+    {
+      n_rows_or_cols = &n_cols;
+      min_size_for_button = grouping_limit;
+      max_size_for_button = tasklist->priv->max_button_width;
+    }
+  else
+    {
+      n_rows_or_cols = &n_rows;
+      min_size_for_button = max_height;
+      max_size_for_button = max_height;
+    }
+
+  if (!vertical_orientation)
+    {
+      fake_allocation.width = GTK_WIDGET (tasklist)->allocation.width;
+      fake_allocation.height = GTK_WIDGET (tasklist)->allocation.height;
+    }
+  else
+    {
+      /* swap width and height, since changing orientation means just rotating
+       * everything */
+      fake_allocation.width = GTK_WIDGET (tasklist)->allocation.height;
+      fake_allocation.height = GTK_WIDGET (tasklist)->allocation.width;
+    }

   array = g_array_new (FALSE, FALSE, sizeof (int));

@@ -1324,26 +1411,32 @@ wnck_tasklist_size_request  (GtkWidget
   ungrouped_class_groups = g_list_copy (tasklist->priv->class_groups);
   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);
+  if (!tasklist->priv->vertical_mode || vertical_orientation)
+     {
+       wnck_tasklist_layout (&fake_allocation,
+				tasklist->priv->max_button_width,
+				tasklist->priv->max_button_height,
+				n_windows + n_startup_sequences,
+				&n_cols, &n_rows);
+     }
+  else
+    {
+      /* We want all tasks in one high column. */
+      n_cols = 1;
+      n_rows = n_windows + n_startup_sequences;
+    }

-  last_n_cols = G_MAXINT;
+  last_n_rows_or_cols = G_MAXINT;
   lowest_range = G_MAXINT;
   if (tasklist->priv->grouping != WNCK_TASKLIST_ALWAYS_GROUP)
     {
-      val = n_cols * tasklist->priv->max_button_width;
+      val = *n_rows_or_cols * max_size_for_button;
       g_array_insert_val (array, array->len, val);
-      val = n_cols * grouping_limit;
+      val = *n_rows_or_cols * min_size_for_button;
       g_array_insert_val (array, array->len, val);

-      last_n_cols = n_cols;
+      last_n_rows_or_cols = *n_rows_or_cols;
       lowest_range = val;
     }

@@ -1365,27 +1449,28 @@ wnck_tasklist_size_request  (GtkWidget
                tasklist->priv->max_button_height,
                n_startup_sequences + n_windows - n_grouped_buttons,
                &n_cols, &n_rows);
-      if (n_cols != last_n_cols &&
+      if (*n_rows_or_cols != last_n_rows_or_cols &&
      (tasklist->priv->grouping == WNCK_TASKLIST_AUTO_GROUP ||
       ungrouped_class_groups == NULL))
    {
-	  val = n_cols * tasklist->priv->max_button_width;
+	  val = *n_rows_or_cols * max_size_for_button;
+
      if (val >= lowest_range)
        { /* Overlaps old range */
               g_assert (array->len > 0);
-	      lowest_range = n_cols * grouping_limit;
+	      lowest_range = *n_rows_or_cols * min_size_for_button;
               g_array_index(array, int, array->len-1) = lowest_range;
        }
      else
        {
          /* Full new range */
          g_array_insert_val (array, array->len, val);
-	      val = n_cols * grouping_limit;
+	      val = *n_rows_or_cols * min_size_for_button;
          g_array_insert_val (array, array->len, val);
          lowest_range = val;
        }

-	  last_n_cols = n_cols;
+	  last_n_rows_or_cols = *n_rows_or_cols;
    }
     }

@@ -1408,8 +1493,16 @@ wnck_tasklist_size_request  (GtkWidget

   tasklist->priv->size_hints = (int *)g_array_free (array, FALSE);

-  requisition->width = tasklist->priv->size_hints[0];
-  requisition->height = fake_allocation.height;
+  if (!tasklist->priv->vertical_mode)
+    {
+      requisition->width = tasklist->priv->size_hints[0];
+      requisition->height = n_rows * tasklist->priv->max_button_height;
+    }
+  else
+  {
+      requisition->width = fake_allocation.width;
+      requisition->height = tasklist->priv->size_hints[0];
+  }
 }

 /**
@@ -1444,17 +1537,29 @@ wnck_task_size_allocated (GtkWidget
                           gpointer       data)
 {
   WnckTask *task = WNCK_TASK (data);
-  int       min_image_width;
+  int       min_image_size;
+  int       size;

-  min_image_width = MINI_ICON_SIZE +
-                    2 * widget->style->xthickness +
-                    2 * TASKLIST_BUTTON_PADDING;
+  if (!task->tasklist->priv->rotated)
+    {
+      size = allocation->width;
+      min_image_size = MINI_ICON_SIZE +
+                       2 * widget->style->xthickness +
+                       2 * TASKLIST_BUTTON_PADDING;
+    }
+  else
+    {
+      size = allocation->height;
+      min_image_size = MINI_ICON_SIZE +
+                       2 * widget->style->ythickness +
+                       2 * TASKLIST_BUTTON_PADDING;
+    }

-  if ((allocation->width < min_image_width + 2 * TASKLIST_BUTTON_PADDING) &&
-      (allocation->width >= min_image_width)) {
+  if ((size < min_image_size + 2 * TASKLIST_BUTTON_PADDING) &&
+      (size >= min_image_size)) {
     gtk_widget_show (task->image);
     gtk_widget_hide (task->label);
-  } else if (allocation->width < min_image_width) {
+  } else if (size < min_image_size) {
     gtk_widget_hide (task->image);
     gtk_widget_show (task->label);
   } else {
@@ -1467,6 +1572,7 @@ static void
 wnck_tasklist_size_allocate (GtkWidget      *widget,
                              GtkAllocation  *allocation)
 {
+  GtkAllocation maybe_rotated_allocation;
   GtkAllocation child_allocation;
   WnckTasklist *tasklist;
   WnckTask *class_group_task;
@@ -1485,6 +1591,7 @@ wnck_tasklist_size_allocate (GtkWidget
   GList *visible_tasks = NULL;
   GList *windows_sorted = NULL;
   int grouping_limit;
+  gdouble angle;

   tasklist = WNCK_TASKLIST (widget);

@@ -1497,8 +1604,45 @@ wnck_tasklist_size_allocate (GtkWidget
   grouping_limit = MIN (tasklist->priv->grouping_limit,
            tasklist->priv->max_button_width);

+  //FIXME: initial size is wrong in vertical mode
+  if (GTK_WIDGET_REALIZED (widget) &&
+      tasklist->priv->vertical_mode && allocation->width < grouping_limit)
+    {
+      GdkScreen *screen;
+      int xpos;
+      int ypos;
+
+      tasklist->priv->rotated = TRUE;
+
+      gdk_window_get_origin (widget->window, &xpos, &ypos);
+
+      //FIXME: is not updated when panel changes from right to left
+      screen = _wnck_screen_get_gdk_screen (tasklist->priv->screen);
+      if (xpos + (allocation->x + allocation->width) / 2
+          < gdk_screen_get_width (screen) / 2)
+        angle = 90;
+      else
+        angle = 270;
+    }
+  else
+    {
+      tasklist->priv->rotated = FALSE;
+      angle = 0;
+    }
+
+  if (!tasklist->priv->rotated)
+    {
+      maybe_rotated_allocation.width = allocation->width;
+      maybe_rotated_allocation.height = allocation->height;
+    }
+  else
+    {
+      maybe_rotated_allocation.width = allocation->height;
+      maybe_rotated_allocation.height = allocation->width;
+    }
+
   /* Try ungrouped mode */
-  button_width = wnck_tasklist_layout (allocation,
+  button_width = wnck_tasklist_layout (&maybe_rotated_allocation,
                       tasklist->priv->max_button_width,
                       tasklist->priv->max_button_height,
                       n_startup_sequences + n_windows,
@@ -1532,8 +1676,8 @@ wnck_tasklist_size_allocate (GtkWidget
        {
          win_task = WNCK_TASK (l->data);

-	      gtk_widget_set_child_visible (GTK_WIDGET (win_task->button), FALSE);
-
+	      gtk_widget_set_child_visible (GTK_WIDGET (win_task->button),
+                                            FALSE);
               cleanup_screenshots (win_task);

          l = l->next;
@@ -1541,13 +1685,14 @@ wnck_tasklist_size_allocate (GtkWidget
    }
       else
    {
-	  visible_tasks = g_list_prepend (visible_tasks, class_group_task->windows->data);
-	  gtk_widget_set_child_visible (GTK_WIDGET (class_group_task->button), FALSE);
-
+	  visible_tasks = g_list_prepend (visible_tasks,
+                                          class_group_task->windows->data);
+	  gtk_widget_set_child_visible (GTK_WIDGET (class_group_task->button),
+                                        FALSE);
           cleanup_screenshots (class_group_task);
         }

-      button_width = wnck_tasklist_layout (allocation,
+      button_width = wnck_tasklist_layout (&maybe_rotated_allocation,
                       tasklist->priv->max_button_width,
                       tasklist->priv->max_button_height,
                       n_startup_sequences + n_windows - n_grouped_buttons,
@@ -1560,34 +1705,45 @@ wnck_tasklist_size_allocate (GtkWidget
     {
       class_group_task = WNCK_TASK (l->data);

-      visible_tasks = g_list_concat (visible_tasks, g_list_copy (class_group_task->windows));
-      gtk_widget_set_child_visible (GTK_WIDGET (class_group_task->button), FALSE);
-
+      visible_tasks = g_list_concat (visible_tasks,
+                                     g_list_copy (class_group_task->windows));
+      gtk_widget_set_child_visible (GTK_WIDGET (class_group_task->button),
+                                    FALSE);
       cleanup_screenshots (class_group_task);

       l = l->next;
     }

   /* Add all windows that are ungrouped because they don't belong to any class
    * group */
   l = tasklist->priv->windows_without_class_group;
   while (l != NULL)
     {
       WnckTask *task;

       task = WNCK_TASK (l->data);
       visible_tasks = g_list_append (visible_tasks, task);

       l = l->next;
     }

   /* Add all startup sequences */
-  visible_tasks = g_list_concat (visible_tasks, g_list_copy (tasklist->priv->startup_sequences));
+  visible_tasks = g_list_concat (visible_tasks,
+                                 g_list_copy (tasklist->priv->startup_sequences));

   /* Sort */
   visible_tasks = g_list_sort (visible_tasks, wnck_task_compare);

   /* Allocate children */
+  if (tasklist->priv->rotated)
+    {
+      int buf;
+
+      buf = n_rows;
+      n_rows = n_cols;
+      n_cols = buf;
+    }
+
   l = visible_tasks;
   i = 0;
   total_width = tasklist->priv->max_button_width * n_cols;
@@ -1586,12 +1742,40 @@ wnck_tasklist_size_allocate (GtkWidget
   while (l != NULL)
     {
       WnckTask *task = WNCK_TASK (l->data);
-      int row = i % n_rows;
-      int col = i / n_rows;
+      int row;
+      int col;
+
+      if (!tasklist->priv->rotated)
+        {
+          row = i % n_rows;
+          col = i / n_rows;
+        }
+      else
+        {
+          row = i % n_cols;
+          col = i / n_cols;
+        }

       if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
         col = n_cols - col - 1;

+      if (angle == 270)
+        {
+          int buf;
+
+          buf = row;
+          row = col;
+          col = n_cols - buf - 1;
+        }
+      else if (angle == 90)
+        {
+          int buf;
+
+          buf = row;
+          row = n_rows - col - 1;
+          col = buf;
+        }
+
       child_allocation.x = total_width*col / n_cols;
       child_allocation.y = allocation->height*row / n_rows;
       child_allocation.width = total_width*(col + 1) / n_cols - child_allocation.x;
@@ -1602,6 +1786,29 @@ wnck_tasklist_size_allocate (GtkWidget
       gtk_widget_size_allocate (task->button, &child_allocation);
       gtk_widget_set_child_visible (GTK_WIDGET (task->button), TRUE);

+      wnck_obox_set_orientation (WNCK_OBOX (task->obox),
+                                 tasklist->priv->rotated ?
+                                   GTK_ORIENTATION_VERTICAL :
+                                   GTK_ORIENTATION_HORIZONTAL);
+      //FIXME: this is wrong for japanese!
+      wnck_obox_set_reverse_order (WNCK_OBOX (task->obox), angle == 90);
+      if (angle == 0)
+        {
+          gtk_label_set_ellipsize (GTK_LABEL (task->label),
+                                   PANGO_ELLIPSIZE_END);
+          gtk_misc_set_alignment (GTK_MISC (task->label), 0.0, 0.5);
+        }
+      else
+        {
+          //FIXME: This is a workaround because GTK+ is not nice with us and
+          //doesn't accept rotated + ellipsized text.
+          gtk_label_set_ellipsize (GTK_LABEL (task->label),
+                                   PANGO_ELLIPSIZE_NONE);
+          gtk_misc_set_alignment (GTK_MISC (task->label), 0.5,
+                                            angle == 90 ? 1.0 : 0.0);
+        }
+      gtk_label_set_angle (GTK_LABEL (task->label), angle);
+
       if (task->type != WNCK_TASK_STARTUP_SEQUENCE)
         {
           GList *ll;
@@ -2605,7 +2812,8 @@ wnck_task_position_menu (GtkMenu   *menu
             gboolean  *push_in,
             gpointer   user_data)
 {
-  GtkWidget *widget = GTK_WIDGET (user_data);
+  WnckTask *task = WNCK_TASK (user_data);
+  GtkWidget *widget = task->button;
   GtkRequisition requisition;
   gint menu_xpos;
   gint menu_ypos;
@@ -2619,7 +2827,7 @@ wnck_task_position_menu (GtkMenu   *menu
   menu_xpos += widget->allocation.x;
   menu_ypos += widget->allocation.y;

-  if (menu_ypos >  gdk_screen_height () / 2)
+  if (menu_ypos > gdk_screen_get_height (_wnck_screen_get_gdk_screen (task->tasklist->priv->screen)) / 2)
     menu_ypos -= requisition.height;
   else
     menu_ypos += widget->allocation.height;
@@ -3007,7 +3215,7 @@ wnck_task_popup_menu (WnckTask *task,
   gtk_widget_show (menu);
   gtk_menu_popup (GTK_MENU (menu),
          NULL, NULL,
-		  wnck_task_position_menu, task->button,
+		  wnck_task_position_menu, task,
          1, gtk_get_current_event_time ());
 }

@@ -3613,7 +3821,7 @@ wnck_task_button_press_event (GtkWidget
           gtk_widget_show (task->action_menu);
           gtk_menu_popup (GTK_MENU (task->action_menu),
                           NULL, NULL,
-                          wnck_task_position_menu, task->button,
+                          wnck_task_position_menu, task,
                           event->button,
                           gtk_get_current_event_time ());

@@ -3638,7 +3846,6 @@ wnck_task_expose (GtkWidget        *widg
 static void
 wnck_task_create_widgets (WnckTask *task, GtkReliefStyle relief)
 {
-  GtkWidget *hbox;
   GdkPixbuf *pixbuf;
   char *text;
   static GQuark disable_sound_quark = 0;
@@ -3678,7 +3885,7 @@ wnck_task_create_widgets (WnckTask *task
     gtk_drag_dest_set (GTK_WIDGET (task->button), 0,
                        NULL, 0, GDK_ACTION_DEFAULT);

-  hbox = gtk_hbox_new (FALSE, 0);
+  task->obox = wnck_obox_new ();

   pixbuf = wnck_task_get_icon (task);
   if (pixbuf)
@@ -3705,13 +3912,13 @@ wnck_task_create_widgets (WnckTask *task

   gtk_widget_show (task->label);

-  gtk_box_pack_start (GTK_BOX (hbox), task->image, FALSE, FALSE,
+  gtk_box_pack_start (GTK_BOX (task->obox), task->image, FALSE, FALSE,
              TASKLIST_BUTTON_PADDING);
-  gtk_box_pack_start (GTK_BOX (hbox), task->label, TRUE, TRUE,
+  gtk_box_pack_start (GTK_BOX (task->obox), task->label, TRUE, TRUE,
              TASKLIST_BUTTON_PADDING);

-  gtk_container_add (GTK_CONTAINER (task->button), hbox);
-  gtk_widget_show (hbox);
+  gtk_container_add (GTK_CONTAINER (task->button), task->obox);
+  gtk_widget_show (task->obox);
   g_free (text);

   text = wnck_task_get_text (task, FALSE, FALSE);
Index: tasklist.h
===================================================================
--- libwnck/tasklist.h	(révision 1378)
+++ libwnck/tasklist.h	(copie de travail)
@@ -98,6 +98,9 @@ void wnck_tasklist_set_include_all_works
                           gboolean      include_all_workspaces);
 void wnck_tasklist_set_button_relief (WnckTasklist *tasklist,
                                       GtkReliefStyle relief);
+void wnck_tasklist_set_vertical_mode (WnckTasklist *tasklist,
+                                      gboolean      vertical_mode);
+
 #ifndef WNCK_DISABLE_DEPRECATED
 void wnck_tasklist_set_minimum_width (WnckTasklist *tasklist, gint size);
 gint wnck_tasklist_get_minimum_width (WnckTasklist *tasklist);
Index: obox.c
===================================================================
--- libwnck/obox.c	(révision 0)
+++ libwnck/obox.c	(révision 0)
@@ -0,0 +1,151 @@
+/* OBox Copyright (C) 2002 Red Hat Inc. based on GtkHBox */
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#include "obox.h"
+
+#include <gtk/gtkhbox.h>
+#include <gtk/gtkvbox.h>
+
+static void wnck_obox_size_request  (GtkWidget       *widget,
+				     GtkRequisition  *requisition);
+static void wnck_obox_size_allocate (GtkWidget       *widget,
+				     GtkAllocation   *allocation);
+
+
+G_DEFINE_TYPE (WnckOBox, wnck_obox, GTK_TYPE_BOX)
+
+static void
+wnck_obox_class_init (WnckOBoxClass *class)
+{
+  GtkWidgetClass *widget_class;
+
+  widget_class = (GtkWidgetClass*) class;
+
+  widget_class->size_request = wnck_obox_size_request;
+  widget_class->size_allocate = wnck_obox_size_allocate;
+}
+
+static void
+wnck_obox_init (WnckOBox *obox)
+{
+  obox->orientation = GTK_ORIENTATION_HORIZONTAL;
+  obox->reverse_order = FALSE;
+}
+
+GtkWidget*
+wnck_obox_new (void)
+{
+  WnckOBox *obox;
+
+  obox = g_object_new (WNCK_TYPE_OBOX, NULL);
+
+  return GTK_WIDGET (obox);
+}
+
+static GtkWidgetClass*
+get_class (WnckOBox *obox)
+{
+  GtkWidgetClass *klass;
+
+  switch (obox->orientation)
+    {
+    case GTK_ORIENTATION_HORIZONTAL:
+      klass = GTK_WIDGET_CLASS (gtk_type_class (GTK_TYPE_HBOX));
+      break;
+    case GTK_ORIENTATION_VERTICAL:
+      klass = GTK_WIDGET_CLASS (gtk_type_class (GTK_TYPE_VBOX));
+      break;
+    default:
+      g_assert_not_reached ();
+      klass = NULL;
+      break;
+    }
+
+  return klass;
+}
+
+static void
+wnck_obox_size_request (GtkWidget      *widget,
+		        GtkRequisition *requisition)
+{
+  GtkWidgetClass *klass;
+  WnckOBox *obox;
+
+  obox = WNCK_OBOX (widget);
+
+  klass = get_class (obox);
+
+  klass->size_request (widget, requisition);
+}
+
+static void
+wnck_obox_size_allocate (GtkWidget     *widget,
+		         GtkAllocation *allocation)
+{
+  GtkWidgetClass *klass;
+  WnckOBox *obox;
+
+  obox = WNCK_OBOX (widget);
+
+  klass = get_class (obox);
+
+  klass->size_allocate (widget, allocation);
+}
+
+void
+wnck_obox_set_orientation (WnckOBox         *obox,
+                           GtkOrientation  orientation)
+{
+  g_return_if_fail (WNCK_IS_OBOX (obox));
+
+  if (obox->orientation == orientation)
+    return;
+
+  g_print ("new orientation: %d\n", orientation);
+  obox->orientation = orientation;
+
+  gtk_widget_queue_resize (GTK_WIDGET (obox));
+}
+
+void
+wnck_obox_set_reverse_order (WnckOBox *obox,
+                             gboolean  reverse_order)
+{
+  GtkBox *box;
+
+  g_return_if_fail (WNCK_IS_OBOX (obox));
+
+  if (obox->reverse_order == reverse_order)
+    return;
+
+  g_print ("reverse order: %d\n", reverse_order);
+  obox->reverse_order = reverse_order;
+  box = GTK_BOX (obox);
+  box->children = g_list_reverse (box->children);
+
+  gtk_widget_queue_resize (GTK_WIDGET (obox));
+}
Index: obox.h
===================================================================
--- libwnck/obox.h	(révision 0)
+++ libwnck/obox.h	(révision 0)
@@ -0,0 +1,75 @@
+/* OBox Copyright (C) 2002 Red Hat Inc. based on GtkHBox */
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ */
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#ifndef __WNCK_OBOX_H__
+#define __WNCK_OBOX_H__
+
+#include <gtk/gtkbox.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+#define WNCK_TYPE_OBOX            (wnck_obox_get_type ())
+#define WNCK_OBOX(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), WNCK_TYPE_OBOX, WnckOBox))
+#define WNCK_OBOX_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), WNCK_TYPE_OBOX, WnckOBoxClass))
+#define WNCK_IS_OBOX(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), WNCK_TYPE_OBOX))
+#define WNCK_IS_OBOX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), WNCK_TYPE_OBOX))
+#define WNCK_OBOX_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), WNCK_TYPE_OBOX, WnckOBoxClass))
+
+
+typedef struct _WnckOBox       WnckOBox;
+typedef struct _WnckOBoxClass  WnckOBoxClass;
+
+struct _WnckOBox
+{
+  GtkBox box;
+
+  GtkOrientation orientation;
+  gboolean       reverse_order;
+};
+
+struct _WnckOBoxClass
+{
+  GtkBoxClass parent_class;
+};
+
+
+GType	   wnck_obox_get_type (void) G_GNUC_CONST;
+GtkWidget* wnck_obox_new      (void);
+
+void wnck_obox_set_orientation (WnckOBox       *obox,
+                                GtkOrientation  orientation);
+void wnck_obox_set_reverse_order (WnckOBox *obox,
+                                  gboolean  reverse_order);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __WNCK_OBOX_H__ */
Index: Makefile.am
===================================================================
--- libwnck/Makefile.am	(révision 1377)
+++ libwnck/Makefile.am	(copie de travail)
@@ -44,6 +44,8 @@ libwnck_1_la_SOURCES= 		\
    application.c		\
    class-group.c		\
    inlinepixbufs.h		\
+	obox.c			\
+	obox.h			\
    pager.c			\
    private.h		\
    screen.c		\
