Index: ChangeLog
===================================================================
RCS file: /export/cvs/gnome-2.0/libwnck/ChangeLog,v
retrieving revision 1.224
diff -p -u -5 -r1.224 ChangeLog
--- ChangeLog   2004/01/06 06:38:32     1.224
+++ ChangeLog   2004/01/21 10:41:27
@@ -1,5 +1,31 @@
+2004-01-21  Leena Gunda  <leena.gunda@wipro.com>
+
+       * libwnck/window-action-menu.c:
+       (wnck_create_window_action_menu): Add "Move to Workspace Left/
+       Right/Up/Down" menu item.
+       (item_activated_callback): Implement code to move the window to
+       the workspace at left/right/up/down.
+
+        * libwnck/screen.h:
+        Added the WnckWorkspaceLayout structure and WnckMotionDirection.
+
+       *libwnck/screen.c:
+       (wnck_screen_get_workspace_index): Get the index of the 
+       workspace.
+       (wnck_screen_get_workspace_neighbor): Get the neighbor of the 
+       workspace in specified direction.
+       (_wnck_screen_process_property_notify): If the workspace layout 
+       has changed, call the idle handler to update the screen info.
+       (wnck_screen_calc_workspace_layout): calculates the workspace
+       layout. 
+       (wnck_screen_free_workspace_layout): free the layout grid.
+       (update_workspace_layout): idle handler to update the screen 
+       info. if the layout has changed.
+       The code to calculate the workspace layout is copied from
+       metacity sources. Fixes bug #96087
+
 2004-01-06  Leena Gunda  <leena.gunda@wipro.com>
 
        * libwnck/window-action-menu.c:
        (wnck_create_window_action_menu): Add the "Move to Workspace"
        submenu to the actions menu.

Index: libwnck/screen.c
===================================================================
RCS file: /export/cvs/gnome-2.0/libwnck/libwnck/screen.c,v
retrieving revision 1.24
diff -p -u -5 -r1.24 screen.c
--- libwnck/screen.c	2003/11/22 23:49:12	1.24
+++ libwnck/screen.c	2004/01/21 10:04:01
@@ -31,10 +31,26 @@
 #include <gdk/gdk.h>
 #include <gdk/gdkx.h>
 #include <string.h>
 #include <stdlib.h>
 
+#define _NET_WM_ORIENTATION_HORZ 0
+#define _NET_WM_ORIENTATION_VERT 1
+
+#define _NET_WM_TOPLEFT     0
+#define _NET_WM_TOPRIGHT    1
+#define _NET_WM_BOTTOMRIGHT 2
+#define _NET_WM_BOTTOMLEFT  3
+
+typedef enum
+{
+  SCREEN_TOPLEFT,
+  SCREEN_TOPRIGHT,
+  SCREEN_BOTTOMLEFT,
+  SCREEN_BOTTOMRIGHT
+} ScreenCorner;
+
 static WnckScreen** screens = NULL;
 
 struct _WnckScreenPrivate
 {
   int number;
@@ -59,18 +75,24 @@ struct _WnckScreenPrivate
   SnDisplay *sn_display;
 #endif
   
   guint showing_desktop : 1;
   
+  guint vertical_workspaces : 1;
+  ScreenCorner starting_corner;
+  gint rows_of_workspaces;
+  gint columns_of_workspaces;  
+
   /* if you add flags, be sure to set them
    * when we create the screen so we get an initial update
    */
   guint need_update_stack_list : 1;
   guint need_update_workspace_list : 1;
   guint need_update_viewport_settings : 1;
   guint need_update_active_workspace : 1;
   guint need_update_active_window : 1;
+  guint need_update_workspace_layout : 1;
   guint need_update_workspace_names : 1;
   guint need_update_bg_pixmap : 1;
   guint need_update_showing_desktop : 1;
 };
 
@@ -99,10 +121,11 @@ static void wnck_screen_finalize    (GOb
 static void update_client_list        (WnckScreen      *screen);
 static void update_workspace_list     (WnckScreen      *screen);
 static void update_viewport_settings  (WnckScreen      *screen);
 static void update_active_workspace   (WnckScreen      *screen);
 static void update_active_window      (WnckScreen      *screen);
+static void update_workspace_layout   (WnckScreen      *screen);
 static void update_workspace_names    (WnckScreen      *screen);
 static void update_showing_desktop    (WnckScreen      *screen);
 
 static void queue_update            (WnckScreen      *screen);
 static void unqueue_update          (WnckScreen      *screen);              
@@ -379,10 +402,15 @@ wnck_screen_construct (WnckScreen *scree
   /* Create the initial state of the screen. */
   screen->priv->xroot = RootWindow (gdk_display, number);
   screen->priv->xscreen = ScreenOfDisplay (gdk_display, number);
   screen->priv->number = number;
 
+  screen->priv->rows_of_workspaces = 1;
+  screen->priv->columns_of_workspaces = -1;
+  screen->priv->vertical_workspaces = FALSE;
+  screen->priv->starting_corner = SCREEN_TOPLEFT;
+
 #ifdef HAVE_STARTUP_NOTIFICATION
   screen->priv->sn_display = sn_display_new (gdk_display,
                                              sn_error_trap_push,
                                              sn_error_trap_pop);
 #endif
@@ -395,10 +423,11 @@ wnck_screen_construct (WnckScreen *scree
   screen->priv->need_update_workspace_list = TRUE;
   screen->priv->need_update_stack_list = TRUE;
   screen->priv->need_update_viewport_settings = TRUE;
   screen->priv->need_update_active_workspace = TRUE;
   screen->priv->need_update_active_window = TRUE;
+  screen->priv->need_update_workspace_layout = TRUE;
   screen->priv->need_update_workspace_names = TRUE;
   screen->priv->need_update_bg_pixmap = TRUE;
   screen->priv->need_update_showing_desktop = TRUE;
   
   queue_update (screen);
@@ -512,10 +541,31 @@ wnck_screen_get_workspace (WnckScreen *s
     return NULL;
   
   return WNCK_WORKSPACE (list->data);
 }
 
+int
+wnck_screen_get_workspace_index (WnckScreen    *screen,
+				 WnckWorkspace *workspace)
+{
+  GList *tmp;
+  int i;
+
+  i = 0;
+  tmp = screen->priv->workspaces;
+  while (tmp != NULL)
+    {
+      if (tmp->data == workspace)
+        return i;
+
+      ++i;
+
+      tmp = tmp->next;
+    }
+  return -1; /* compiler warnings */
+}
+
 /**
  * wnck_screen_get_active_workspace:
  * @screen: a #WnckScreen 
  * 
  * Gets the active workspace. May return %NULL sometimes,
@@ -530,10 +580,59 @@ wnck_screen_get_active_workspace (WnckSc
   g_return_val_if_fail (WNCK_IS_SCREEN (screen), NULL);
 
   return screen->priv->active_workspace;
 }
 
+WnckWorkspace*
+wnck_screen_get_workspace_neighbor (WnckScreen         *screen,
+				    WnckWorkspace      *workspace,
+				    WnckMotionDirection direction)
+{
+  WnckWorkspaceLayout layout;
+  int i, current_space, num_workspaces;
+
+  current_space = wnck_screen_get_workspace_index (screen, workspace);
+  num_workspaces = wnck_screen_get_workspace_count (screen);
+
+  wnck_screen_calc_workspace_layout (screen, num_workspaces,
+                                     current_space, &layout);
+
+  switch (direction)
+    {
+    case WNCK_MOTION_LEFT:
+      layout.current_col -= 1;
+      break;
+    case WNCK_MOTION_RIGHT:
+      layout.current_col += 1;
+      break;
+    case WNCK_MOTION_UP:
+      layout.current_row -= 1;
+      break;
+    case WNCK_MOTION_DOWN:
+      layout.current_row += 1;
+      break;
+    }
+
+  if (layout.current_col < 0)
+    layout.current_col = 0;
+  if (layout.current_col >= layout.cols)
+    layout.current_col = layout.cols - 1;
+  if (layout.current_row < 0)
+    layout.current_row = 0;
+  if (layout.current_row >= layout.rows)
+    layout.current_row = layout.rows - 1;
+
+  i = layout.grid[layout.current_row * layout.cols + layout.current_col];
+
+  if (i < 0)
+    i = current_space;
+
+  wnck_screen_free_workspace_layout (&layout);
+  return wnck_screen_get_workspace (screen, i);
+}
+
+
 /**
  * wnck_screen_get_active_window:
  * @screen: a #WnckScreen
  * 
  * Gets the active window. May return %NULL sometimes,
@@ -713,10 +812,16 @@ _wnck_screen_process_property_notify (Wn
     {
       screen->priv->need_update_workspace_list = TRUE;
       queue_update (screen);
     }
   else if (xevent->xproperty.atom ==
+	   _wnck_atom_get ("_NET_DESKTOP_LAYOUT"))
+    {
+      screen->priv->need_update_workspace_layout = TRUE;
+      queue_update (screen);
+    }
+  else if (xevent->xproperty.atom ==
            _wnck_atom_get ("_NET_DESKTOP_NAMES"))
     {
       screen->priv->need_update_workspace_names = TRUE;
       queue_update (screen);
     }
@@ -732,10 +837,217 @@ _wnck_screen_process_property_notify (Wn
       screen->priv->need_update_showing_desktop = TRUE;
       queue_update (screen);
     }
 }
 
+void
+wnck_screen_calc_workspace_layout (WnckScreen          *screen,
+				   int                  num_workspaces,
+				   int                  current_space,
+				   WnckWorkspaceLayout *layout)
+{
+  int rows, cols;
+  int grid_area;
+  int *grid;
+  int i, r, c;
+  int current_row, current_col;
+
+  rows = screen->priv->rows_of_workspaces;
+  cols = screen->priv->columns_of_workspaces;
+
+  if (rows <= 0 && cols <= 0)
+    cols = num_workspaces;
+
+  if (rows <= 0)
+    rows = num_workspaces / cols + ((num_workspaces % cols) > 0 ? 1 : 0);
+  if (cols <= 0)
+    cols = num_workspaces / rows + ((num_workspaces % rows) > 0 ? 1 : 0);
+
+  /* paranoia */
+  if (rows < 1)
+    rows = 1;
+  if (cols < 1)
+    cols = 1;
+
+  g_assert (rows != 0 && cols != 0);
+
+  grid_area = rows * cols;
+
+  grid = g_new (int, grid_area);
+
+  current_row = -1;
+  current_col = -1;
+  i = 0;
+
+  switch (screen->priv->starting_corner)
+    {
+    case SCREEN_TOPLEFT:
+      if (screen->priv->vertical_workspaces)
+        {
+          c = 0;
+          while (c < cols)
+            {
+              r = 0;
+              while (r < rows)
+                {
+                  grid[r*cols+c] = i;
+                  ++i;
+                  ++r;
+                }
+              ++c;
+            }
+        }
+      else
+        {
+          r = 0;
+          while (r < rows)
+            {
+              c = 0;
+              while (c < cols)
+                {
+                  grid[r*cols+c] = i;
+                  ++i;
+                  ++c;
+                }
+              ++r;
+            }
+        }
+      break;
+    case SCREEN_TOPRIGHT:
+      if (screen->priv->vertical_workspaces)
+        {
+          c = cols - 1;
+          while (c >= 0)
+            {
+              r = 0;
+              while (r < rows)
+                {
+                  grid[r*cols+c] = i;
+                  ++i;
+                  ++r;
+                }
+              --c;
+            }
+        }
+      else
+        {
+          r = 0;
+          while (r < rows)
+            {
+              c = cols - 1;
+              while (c >= 0)
+                {
+                  grid[r*cols+c] = i;
+                  ++i;
+                  --c;
+                }
+              ++r;
+            }
+        }
+      break;
+    case SCREEN_BOTTOMLEFT:
+      if (screen->priv->vertical_workspaces)
+        {
+          c = 0;
+          while (c < cols)
+            {
+              r = rows - 1;
+              while (r >= 0)
+                {
+                  grid[r*cols+c] = i;
+                  ++i;
+                  --r;
+                }
+              ++c;
+            }
+        }
+      else
+        {
+          r = rows - 1;
+          while (r >= 0)
+            {
+              c = 0;
+              while (c < cols)
+                {
+                  grid[r*cols+c] = i;
+                  ++i;
+                  ++c;
+                }
+              --r;
+            }
+        }
+      break;
+    case SCREEN_BOTTOMRIGHT:
+      if (screen->priv->vertical_workspaces)
+        {
+          c = cols - 1;
+          while (c >= 0)
+            {
+              r = rows - 1;
+              while (r >= 0)
+                {
+                  grid[r*cols+c] = i;
+                  ++i;
+                  --r;
+                }
+              --c;
+            }
+        }
+      else
+        {
+          r = rows - 1;
+          while (r >= 0)
+            {
+              c = cols - 1;
+              while (c >= 0)
+                {
+                  grid[r*cols+c] = i;
+                  ++i;
+                  --c;
+                }
+              --r;
+            }
+        }
+      break;
+    } 
+
+  current_row = 0;
+  current_col = 0;
+  r = 0;
+  while (r < rows)
+    {
+      c = 0;
+      while (c < cols)
+        {
+          if (grid[r*cols+c] == current_space)
+            {
+              current_row = r;
+              current_col = c;
+            }
+          else if (grid[r*cols+c] >= num_workspaces)
+            {
+              /* flag nonexistent spaces with -1 */
+              grid[r*cols+c] = -1;
+            }
+          ++c;
+        }
+      ++r;
+    }
+  layout->rows = rows;
+  layout->cols = cols;
+  layout->grid = grid;
+  layout->grid_area = grid_area;
+  layout->current_row = current_row;
+  layout->current_col = current_col;
+}
+
+void
+wnck_screen_free_workspace_layout (WnckWorkspaceLayout *layout)
+{
+  g_free (layout->grid);
+}
+
 static gboolean
 lists_equal (GList *a,
              GList *b)
 {
   GList *a_iter;
@@ -1367,10 +1679,97 @@ update_active_window (WnckScreen *screen
 
   emit_active_window_changed (screen);
 }
 
 static void
+update_workspace_layout (WnckScreen *screen)
+{
+  gulong *list;
+  int n_items;
+
+  list = NULL;
+  n_items = 0;
+
+  if (!screen->priv->need_update_workspace_layout)
+    return;
+
+  screen->priv->need_update_workspace_layout = FALSE;
+
+  if (_wnck_get_cardinal_list (screen->priv->xroot,
+			       _wnck_atom_get ("_NET_DESKTOP_LAYOUT"),
+			       &list, 
+			       &n_items))
+  {
+      if (n_items == 3 || n_items == 4)
+        {
+          int cols, rows;
+
+          switch (list[0])
+            {
+            case _NET_WM_ORIENTATION_HORZ:
+              screen->priv->vertical_workspaces = FALSE;
+              break;
+            case _NET_WM_ORIENTATION_VERT:
+              screen->priv->vertical_workspaces = TRUE;
+              break;
+            default:
+              g_warning ("Someone set a weird orientation in _NET_DESKTOP_LAYOUT\n");
+              break;
+            }
+
+          cols = list[1];
+          rows = list[2];
+
+          if (rows <= 0 && cols <= 0)
+            {
+              g_warning ("Columns = %d rows = %d in _NET_DESKTOP_LAYOUT makes no sense\n", rows, cols);
+            }
+          else
+            {
+              if (rows > 0)
+                screen->priv->rows_of_workspaces = rows;
+              else
+                screen->priv->rows_of_workspaces = -1;
+
+              if (cols > 0)
+                screen->priv->columns_of_workspaces = cols;
+              else
+                screen->priv->columns_of_workspaces = -1;
+            }
+          if (n_items == 4)
+            {
+              switch (list[3])
+                {
+                  case _NET_WM_TOPLEFT:
+                    screen->priv->starting_corner = SCREEN_TOPLEFT;
+                    break;
+                  case _NET_WM_TOPRIGHT:
+                    screen->priv->starting_corner = SCREEN_TOPRIGHT;
+                    break;
+                  case _NET_WM_BOTTOMRIGHT:
+                    screen->priv->starting_corner = SCREEN_BOTTOMRIGHT;
+                    break;
+                  case _NET_WM_BOTTOMLEFT:
+                    screen->priv->starting_corner = SCREEN_BOTTOMLEFT;
+                    break;
+                  default:
+                    g_warning ("Someone set a weird starting corner in _NET_DESKTOP_LAYOUT\n");
+                    break;
+                }
+            }
+          else
+           screen->priv->starting_corner = SCREEN_TOPLEFT;
+        }
+      else
+        {
+          g_warning ("Someone set _NET_DESKTOP_LAYOUT to %d integers instead of 4 (3 is accepted for backwards compat)\n", n_items);
+        }
+      g_free (list);
+    }
+}
+
+static void
 update_workspace_names (WnckScreen *screen)
 {
   char **names;
   int i;
   GList *tmp;
@@ -1473,10 +1872,11 @@ do_update_now (WnckScreen *screen)
 
   /* Then note any smaller-scale changes */
   update_active_workspace (screen);
   update_viewport_settings (screen);
   update_active_window (screen);
+  update_workspace_layout (screen);
   update_workspace_names (screen);
   update_showing_desktop (screen);
   
   update_bg_pixmap (screen);
 }
Index: libwnck/screen.h
===================================================================
RCS file: /export/cvs/gnome-2.0/libwnck/libwnck/screen.h,v
retrieving revision 1.14
diff -p -u -5 -r1.14 screen.h
--- libwnck/screen.h	2003/11/22 23:49:12	1.14
+++ libwnck/screen.h	2004/01/21 10:04:01
@@ -108,17 +108,43 @@ struct _WnckScreenClass
   void (* pad7) (void);
   void (* pad8) (void);
 #endif
 };
 
+typedef struct WnckWorkspaceLayout WnckWorkspaceLayout;
+
+struct WnckWorkspaceLayout
+{
+  int rows;
+  int cols;
+  int *grid;
+  int grid_area;
+  int current_row;
+  int current_col;
+};
+
+typedef enum
+{
+  WNCK_MOTION_UP = -1,
+  WNCK_MOTION_DOWN = -2,
+  WNCK_MOTION_LEFT = -3,
+  WNCK_MOTION_RIGHT = -4
+} WnckMotionDirection;
+
 GType wnck_screen_get_type (void) G_GNUC_CONST;
 
 WnckScreen*    wnck_screen_get_default              (void);
 WnckScreen*    wnck_screen_get                      (int         index);
 WnckScreen*    wnck_screen_get_for_root             (gulong      root_window_id);
 WnckWorkspace* wnck_screen_get_workspace            (WnckScreen *screen,
                                                      int         workspace);
+int	        wnck_screen_get_workspace_index      (WnckScreen    *screen,
+						      WnckWorkspace *workspace);
+WnckWorkspace* wnck_screen_get_workspace_neighbor   (WnckScreen         *screen,
+						     WnckWorkspace      *workspace,
+						     WnckMotionDirection direction);
+
 WnckWorkspace* wnck_screen_get_active_workspace     (WnckScreen *screen);
 WnckWindow*    wnck_screen_get_active_window        (WnckScreen *screen);
 GList*         wnck_screen_get_windows              (WnckScreen *screen);
 GList*         wnck_screen_get_windows_stacked      (WnckScreen *screen);
 void           wnck_screen_force_update             (WnckScreen *screen);
@@ -141,9 +167,14 @@ int            wnck_screen_try_set_works
                                                      int         rows,
                                                      int         columns);
 void           wnck_screen_release_workspace_layout (WnckScreen *screen,
                                                      int         current_token);
 
+void 	        wnck_screen_calc_workspace_layout    (WnckScreen          *screen,
+                                        	      int                  num_workspaces,
+                                        	      int                  current_space,
+                                        	      WnckWorkspaceLayout *layout);
+void 	        wnck_screen_free_workspace_layout (WnckWorkspaceLayout *layout);
 
 G_END_DECLS
 
 #endif /* WNCK_SCREEN_H */
Index: libwnck/window-action-menu.c
===================================================================
RCS file: /export/cvs/gnome-2.0/libwnck/libwnck/window-action-menu.c,v
retrieving revision 1.11
diff -p -u -5 -r1.11 window-action-menu.c
--- libwnck/window-action-menu.c	2004/01/06 06:38:34	1.11
+++ libwnck/window-action-menu.c	2004/01/21 10:04:01
@@ -32,10 +32,14 @@ typedef enum
   MAXIMIZE,
   SHADE,
   MOVE,
   RESIZE,
   PIN,
+  LEFT,
+  RIGHT,
+  UP,
+  DOWN,
   MOVE_TO_WORKSPACE
 } WindowAction;
 
 typedef struct _ActionMenuData ActionMenuData;
 
@@ -48,10 +52,14 @@ struct _ActionMenuData
   GtkWidget *shade_item;
   GtkWidget *move_item;
   GtkWidget *resize_item;
   GtkWidget *close_item;
   GtkWidget *pin_item;
+  GtkWidget *left_item;
+  GtkWidget *right_item;
+  GtkWidget *up_item;
+  GtkWidget *down_item;
   GtkWidget *workspace_item;
   guint idle_handler;
 };
 
 static void object_weak_notify (gpointer data,
@@ -140,18 +148,51 @@ item_activated_callback (GtkWidget *menu
       if (wnck_window_is_pinned (amd->window))
         wnck_window_unpin (amd->window);
       else
         wnck_window_pin (amd->window);
       break;
+    case LEFT: {
+	WnckWorkspace *workspace;
+        workspace = wnck_screen_get_workspace_neighbor (wnck_window_get_screen (amd->window),
+	  				  	        wnck_window_get_workspace (amd->window), 
+						        WNCK_MOTION_LEFT);
+	wnck_window_move_to_workspace (amd->window, workspace);
+	break;
+    } 
+    case RIGHT: {
+        WnckWorkspace *workspace;
+        workspace = wnck_screen_get_workspace_neighbor (wnck_window_get_screen ( amd->window),
+                                                        wnck_window_get_workspace (amd->window),
+                                                        WNCK_MOTION_RIGHT);
+        wnck_window_move_to_workspace (amd->window, workspace);
+	break;
+    }
+    case UP: {
+        WnckWorkspace *workspace;
+        workspace = wnck_screen_get_workspace_neighbor (wnck_window_get_screen (amd->window),
+                                                        wnck_window_get_workspace (amd->window),
+                                                        WNCK_MOTION_UP);
+        wnck_window_move_to_workspace (amd->window, workspace);
+	break;
+    }
+    case DOWN: {
+        WnckWorkspace *workspace;
+        workspace = wnck_screen_get_workspace_neighbor (wnck_window_get_screen (amd->window),
+                                                        wnck_window_get_workspace (amd->window),
+                                                        WNCK_MOTION_DOWN);
+        wnck_window_move_to_workspace (amd->window, workspace);
+	break;
+    }
     case MOVE_TO_WORKSPACE: {
         int workspace_index;
 
         workspace_index = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (menu_item), "workspace"));
 
         wnck_window_move_to_workspace (amd->window,
                                        wnck_screen_get_workspace (wnck_window_get_screen (amd->window),
                                        workspace_index));
+	break;
        }
     }
 }
 
 static void
@@ -267,14 +308,30 @@ update_menu_state (ActionMenuData *amd)
                             (actions & WNCK_WINDOW_ACTION_MOVE) != 0);
 
   gtk_widget_set_sensitive (amd->resize_item,
                             (actions & WNCK_WINDOW_ACTION_RESIZE) != 0);
 
-  gtk_widget_set_sensitive (amd->workspace_item,
-                            (actions & WNCK_WINDOW_ACTION_CHANGE_WORKSPACE) != 0);
+  if (amd->workspace_item)
+      gtk_widget_set_sensitive (amd->workspace_item,
+				(actions & WNCK_WINDOW_ACTION_CHANGE_WORKSPACE) != 0);
+
+  if (amd->left_item)
+      gtk_widget_set_sensitive (amd->left_item,
+				(actions & WNCK_WINDOW_ACTION_CHANGE_WORKSPACE) != 0);
+
+  if (amd->right_item)
+      gtk_widget_set_sensitive (amd->right_item,
+				(actions & WNCK_WINDOW_ACTION_CHANGE_WORKSPACE) != 0);
+
+  if (amd->up_item)
+      gtk_widget_set_sensitive (amd->up_item,
+				(actions & WNCK_WINDOW_ACTION_CHANGE_WORKSPACE) != 0);
+
+  if (amd->down_item)
+      gtk_widget_set_sensitive (amd->down_item,
+				(actions & WNCK_WINDOW_ACTION_CHANGE_WORKSPACE) != 0);
 
-  
   return FALSE;
 }
 
 static void
 queue_update (ActionMenuData *amd)
@@ -424,10 +481,11 @@ wnck_create_window_action_menu (WnckWind
 {
   GtkWidget *menu, *submenu;
   ActionMenuData *amd;
   GtkWidget *separator;
   int num_workspaces, present_workspace, i;
+  WnckWorkspaceLayout layout;
  
   _wnck_stock_icons_init ();
   
   amd = g_new0 (ActionMenuData, 1);
   amd->window = window;
@@ -493,45 +551,99 @@ wnck_create_window_action_menu (WnckWind
 
   amd->pin_item = make_menu_item (amd, PIN);
   gtk_menu_shell_append (GTK_MENU_SHELL (menu),
                          amd->pin_item);
   set_item_stock (amd->pin_item, NULL);
-  
-  amd->workspace_item = gtk_menu_item_new_with_mnemonic (_("Move to Another _Workspace")); 
-  gtk_widget_show (amd->workspace_item);
 
-  submenu = gtk_menu_new ();
-  gtk_menu_item_set_submenu (GTK_MENU_ITEM (amd->workspace_item), 
-			     submenu);
+  if (!wnck_window_is_pinned (amd->window)) {
+      num_workspaces = wnck_screen_get_workspace_count (wnck_window_get_screen (amd->window));
+      present_workspace = wnck_workspace_get_number (wnck_window_get_workspace (amd->window));
+
+      wnck_screen_calc_workspace_layout (wnck_window_get_screen (amd->window),
+		  		         num_workspaces,
+				         present_workspace,
+				         &layout);
+
+      if (layout.current_col > 0) {
+	  amd->left_item = make_menu_item (amd, LEFT);
+	  gtk_menu_shell_append (GTK_MENU_SHELL (menu),
+				 amd->left_item);
+	  set_item_text (amd->left_item, _("Move to Workspace _Left"));
+	  set_item_stock (amd->left_item, NULL);
+      }
+      else 
+	  amd->left_item = NULL;
 
-  gtk_menu_shell_append (GTK_MENU_SHELL (menu),
-                         amd->workspace_item);
+      if (layout.current_col < layout.cols - 1) {
+ 	  amd->right_item = make_menu_item (amd, RIGHT);
+	  gtk_menu_shell_append (GTK_MENU_SHELL (menu),
+          	                 amd->right_item);
+	  set_item_text (amd->right_item, _("Move to Workspace R_ight"));
+	  set_item_stock (amd->right_item, NULL);
+      }
+      else 
+	  amd->right_item = NULL;	
+	
+      if (layout.current_row > 0) {
+	  amd->up_item = make_menu_item (amd, UP);
+	  gtk_menu_shell_append (GTK_MENU_SHELL (menu),
+          	                 amd->up_item);
+	  set_item_text (amd->up_item, _("Move to Workspace _Up"));
+	  set_item_stock (amd->up_item, NULL);
+      }
+      else 
+	  amd->up_item = NULL; 
 
-  num_workspaces = wnck_screen_get_workspace_count (wnck_window_get_screen (amd->window));
-  present_workspace = wnck_workspace_get_number (wnck_window_get_workspace (amd->window));
- 
-  for (i = 0; i < num_workspaces; i++) {
-    char *name,*label;
-    GtkWidget *mi;
+      if (layout.current_row < layout.rows - 1) {
+	  amd->down_item = make_menu_item (amd, DOWN);
+	  gtk_menu_shell_append (GTK_MENU_SHELL (menu),
+          	                 amd->down_item);
+	  set_item_text (amd->down_item, _("Move to Workspace _Down"));
+	  set_item_stock (amd->down_item, NULL);
+      }
+      else 
+	  amd->down_item = NULL;  
+
+      amd->workspace_item = gtk_menu_item_new_with_mnemonic (_("Move to Another _Workspace")); 
+      gtk_widget_show (amd->workspace_item);
+
+      submenu = gtk_menu_new ();
+      gtk_menu_item_set_submenu (GTK_MENU_ITEM (amd->workspace_item), 
+			         submenu);
+
+      gtk_menu_shell_append (GTK_MENU_SHELL (menu),
+                             amd->workspace_item);
+
+      for (i = 0; i < num_workspaces; i++) {
+	  char *name,*label;
+	  GtkWidget *mi;
 	
-    name = get_workspace_name_with_accel (amd->window, i);
-    label = g_strdup_printf (_("%s"), name);
+	  name = get_workspace_name_with_accel (amd->window, i);
+	  label = g_strdup_printf (_("%s"), name);
 
-    mi = make_menu_item (amd, MOVE_TO_WORKSPACE);
-    g_object_set_data (G_OBJECT (mi), "workspace", GINT_TO_POINTER (i));
+	  mi = make_menu_item (amd, MOVE_TO_WORKSPACE);
+	  g_object_set_data (G_OBJECT (mi), "workspace", GINT_TO_POINTER (i));
 
-    if (i == present_workspace)
-	gtk_widget_set_sensitive (mi, FALSE);
+	  if (i == present_workspace)
+	      gtk_widget_set_sensitive (mi, FALSE);
 
-    gtk_menu_shell_append (GTK_MENU_SHELL (submenu), mi);
-    set_item_text (mi, label);
-    set_item_stock (mi, NULL);
-
-    g_free (name);
-    g_free (label);	
-  }	
-		 
+	  gtk_menu_shell_append (GTK_MENU_SHELL (submenu), mi);
+    	  set_item_text (mi, label);
+    	  set_item_stock (mi, NULL);
+
+    	  g_free (name);
+    	  g_free (label);	
+      }	
+  }
+  else {
+      amd->workspace_item = NULL;
+      amd->left_item = NULL;
+      amd->right_item = NULL;
+      amd->up_item = NULL;
+      amd->down_item = NULL;
+  }
+			 
   g_signal_connect_object (G_OBJECT (amd->window), 
                            "state_changed",
                            G_CALLBACK (state_changed_callback),
                            G_OBJECT (menu),
                            0);
