Index: ChangeLog
===================================================================
RCS file: /export/cvs/head/libwnck/ChangeLog,v
retrieving revision 1.353
diff -p -u -5 -r1.353 ChangeLog
--- ChangeLog	22 Aug 2005 08:57:40 -0000	1.353
+++ ChangeLog	2 Sep 2005 12:01:13 -0000
@@ -1,5 +1,44 @@
+2005-09-02  Srirama Sharma  <srirama.sharma@wipro.com>
+
+	* libwnck/screen.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 and WnckMotionDirection structure.
+
+	* libwnck/window-action-menu.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): calculate 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 taken from
+	metacity sources.
+	(make_check_menu_item): create a check menu item with the given
+	mnemonic text.
+	(update_menu_state): replace the Roll up/Unroll menu item with
+	On Top check menu item.
+
+	* libwnck/window.[ch] :
+	(wnck_window_make_above): Put the window on top of all window.
+	(wnck_window_is_above): check whether the window is above all
+	other window.
+	(wnck_window_unmake_above): if the window is on top then uncheck
+	the menu item.
+	This patch is union of patches given by leena and christian along
+	with some minor modifications.
+
 2005-08-22  Vincent Untz  <vuntz@gnome.org>
 
 	* configure.in: post-release bump to 2.12.0
 
 ==================== 2.11.92 ====================
Index: libwnck/screen.h
===================================================================
RCS file: /export/cvs/head/libwnck/libwnck/screen.h,v
retrieving revision 1.15
diff -p -u -5 -r1.15 screen.h
--- libwnck/screen.h	16 Aug 2004 03:15:30 -0000	1.15
+++ libwnck/screen.h	2 Sep 2005 12:01:13 -0000
@@ -108,17 +108,42 @@ 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);
 WnckWindow*    wnck_screen_get_previously_active_window (WnckScreen *screen);
 GList*         wnck_screen_get_windows              (WnckScreen *screen);
 GList*         wnck_screen_get_windows_stacked      (WnckScreen *screen);
@@ -141,10 +166,15 @@ int            wnck_screen_try_set_works
                                                      int         current_token,
                                                      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/screen.c
===================================================================
RCS file: /export/cvs/head/libwnck/libwnck/screen.c,v
retrieving revision 1.27
diff -p -u -5 -r1.27 screen.c
--- libwnck/screen.c	19 Jul 2005 02:03:32 -0000	1.27
+++ libwnck/screen.c	2 Sep 2005 12:01:13 -0000
@@ -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;
@@ -68,18 +84,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;
 };
 
@@ -108,10 +130,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);              
@@ -390,10 +413,15 @@ wnck_screen_construct (WnckScreen *scree
   screen->priv->xroot = RootWindow (gdk_display, number);
   screen->priv->xscreen = ScreenOfDisplay (gdk_display, number);
   screen->priv->number = number;
   screen->priv->window_order = 0;
 
+  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
@@ -406,10 +434,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);
@@ -523,10 +552,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,
@@ -541,10 +591,58 @@ 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,
@@ -742,10 +840,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);
     }
@@ -761,10 +865,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;
@@ -1406,10 +1717,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;
@@ -1512,10 +1910,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/window-action-menu.c
===================================================================
RCS file: /export/cvs/head/libwnck/libwnck/window-action-menu.c,v
retrieving revision 1.17
diff -p -u -5 -r1.17 window-action-menu.c
--- libwnck/window-action-menu.c	20 Feb 2005 23:30:35 -0000	1.17
+++ libwnck/window-action-menu.c	2 Sep 2005 12:01:13 -0000
@@ -28,14 +28,18 @@
 typedef enum
 {
   CLOSE,
   MINIMIZE,
   MAXIMIZE,
-  SHADE,
+  ABOVE,
   MOVE,
   RESIZE,
   PIN,
+  LEFT,
+  RIGHT,
+  UP,
+  DOWN,
   MOVE_TO_WORKSPACE
 } WindowAction;
 
 typedef struct _ActionMenuData ActionMenuData;
 
@@ -43,16 +47,20 @@ struct _ActionMenuData
 {
   WnckWindow *window;
   GtkWidget *menu;
   GtkWidget *minimize_item;
   GtkWidget *maximize_item;
-  GtkWidget *shade_item;
+  GtkWidget *above_item;
   GtkWidget *move_item;
   GtkWidget *resize_item;
   GtkWidget *close_item;
   GtkWidget *workspace_separator;
   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,
@@ -126,15 +134,15 @@ item_activated_callback (GtkWidget *menu
       if (wnck_window_is_maximized (amd->window))
         wnck_window_unmaximize (amd->window);
       else
         wnck_window_maximize (amd->window);
       break;
-    case SHADE:
-      if (wnck_window_is_shaded (amd->window))
-        wnck_window_unshade (amd->window);
+    case ABOVE:
+      if (wnck_window_is_above (amd->window))
+        wnck_window_unmake_above (amd->window);
       else
-        wnck_window_shade (amd->window);
+        wnck_window_make_above (amd->window);
       break;
     case MOVE:
       wnck_window_keyboard_move (amd->window);
       break;
     case RESIZE:
@@ -144,19 +152,57 @@ 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 MOVE_TO_WORKSPACE: {
+    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
 set_item_text (GtkWidget  *mi,
@@ -234,24 +280,21 @@ update_menu_state (ActionMenuData *amd)
       set_item_stock (amd->maximize_item, WNCK_STOCK_MAXIMIZE);
       gtk_widget_set_sensitive (amd->maximize_item,
                                 (actions & WNCK_WINDOW_ACTION_MAXIMIZE) != 0);
     }
 
-  if (wnck_window_is_shaded (amd->window))
-    {
-      set_item_text (amd->shade_item, _("_Unroll"));
-      set_item_stock (amd->shade_item, NULL);
-      gtk_widget_set_sensitive (amd->shade_item,
-                                (actions & WNCK_WINDOW_ACTION_UNSHADE) != 0);
-    }
-  else
-    {
-      set_item_text (amd->shade_item, _("Roll _Up"));
-      set_item_stock (amd->shade_item, NULL);
-      gtk_widget_set_sensitive (amd->shade_item,
-                                (actions & WNCK_WINDOW_ACTION_SHADE) != 0);
-    }
+  g_signal_handlers_block_by_func (G_OBJECT (amd->above_item),
+                                   item_activated_callback,
+                                   GINT_TO_POINTER (ABOVE));
+  gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (amd->above_item),
+                                  wnck_window_is_above (amd->window));
+  g_signal_handlers_unblock_by_func (G_OBJECT (amd->above_item),
+                                     item_activated_callback,
+                                     GINT_TO_POINTER (ABOVE));
+
+  gtk_widget_set_sensitive (amd->above_item,
+                            (actions & WNCK_WINDOW_ACTION_ABOVE) != 0);
 
   if (wnck_window_is_pinned (amd->window))
     {
       set_item_text (amd->pin_item, _("_Only on This Workspace"));
       set_item_stock (amd->pin_item, NULL);
@@ -273,13 +316,32 @@ 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 (!wnck_window_is_pinned (amd->window))
+    {
+      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);
+    }
   if (wnck_screen_get_workspace_count (screen) > 1)
     {
       gtk_widget_show (amd->workspace_separator);
       gtk_widget_show (amd->pin_item);
       gtk_widget_show (amd->workspace_item);
@@ -328,10 +390,30 @@ actions_changed_callback (WnckWindow    
   if (amd)
     queue_update (amd);
 }
 
 static GtkWidget*
+make_check_menu_item (ActionMenuData *amd,
+                      WindowAction    action,
+                      const gchar    *mnemonic_text)
+{
+  GtkWidget *mi;
+
+  mi = gtk_check_menu_item_new_with_mnemonic (mnemonic_text);
+
+  set_data (G_OBJECT (mi), amd);
+
+  g_signal_connect (G_OBJECT (mi), "activate",
+                    G_CALLBACK (item_activated_callback),
+                    GINT_TO_POINTER (action));
+
+  gtk_widget_show (mi);
+
+  return mi;
+}
+
+static GtkWidget*
 make_menu_item (ActionMenuData *amd,
                 WindowAction    action)
 {
   GtkWidget *mi;
   
@@ -443,10 +525,11 @@ wnck_create_window_action_menu (WnckWind
   GtkWidget *menu, *submenu;
   ActionMenuData *amd;
   GtkWidget *separator;
   int num_workspaces, present_workspace, i;
   WnckWorkspace *workspace;
+  WnckWorkspaceLayout layout;
 
   _wnck_stock_icons_init ();
   
   amd = g_new0 (ActionMenuData, 1);
   amd->window = window;
@@ -471,14 +554,15 @@ wnck_create_window_action_menu (WnckWind
   amd->maximize_item = make_menu_item (amd, MAXIMIZE);
   
   gtk_menu_shell_append (GTK_MENU_SHELL (menu),
                          amd->maximize_item);
 
-  amd->shade_item = make_menu_item (amd, SHADE);
+  amd->above_item = make_check_menu_item (amd, ABOVE,
+                                          _("On _Top"));
   
   gtk_menu_shell_append (GTK_MENU_SHELL (menu),
-                         amd->shade_item);
+                         amd->above_item);
 
   amd->move_item = make_menu_item (amd, MOVE);
   gtk_menu_shell_append (GTK_MENU_SHELL (menu),
                          amd->move_item);  
 
@@ -513,28 +597,83 @@ 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);
+  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));
 
-  gtk_menu_shell_append (GTK_MENU_SHELL (menu),
-                         amd->workspace_item);
+  wnck_screen_calc_workspace_layout (wnck_window_get_screen (amd->window),
+                                     num_workspaces,
+                                     present_workspace,
+                                     &layout);
+
+  if (!wnck_window_is_pinned (amd->window))
+    {
+      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;
+
+      if ((layout.current_col < layout.cols - 1) && (layout.current_row * layout.cols + (layout.current_col + 1) < num_workspaces ))
+        {
+          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; 
+
+
+      if ((layout.current_row < layout.rows - 1) && ((layout.current_row + 1) * layout.cols + layout.current_col) < num_workspaces)
+        {
+          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;  
+    }
 
-  num_workspaces = wnck_screen_get_workspace_count (wnck_window_get_screen (amd->window));
   workspace = wnck_window_get_workspace (amd->window);
 
   if (workspace)
     present_workspace = wnck_workspace_get_number (workspace);
   else 
     present_workspace = -1;
 
+  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 *item;
 	
@@ -543,11 +682,11 @@ wnck_create_window_action_menu (WnckWind
 
       item = make_menu_item (amd, MOVE_TO_WORKSPACE);
       g_object_set_data (G_OBJECT (item), "workspace", GINT_TO_POINTER (i));
 
       if (i == present_workspace)
-	gtk_widget_set_sensitive (item, FALSE);
+        gtk_widget_set_sensitive (item, FALSE);
 
       gtk_menu_shell_append (GTK_MENU_SHELL (submenu), item);
       set_item_text (item, label);
       set_item_stock (item, NULL);
 
Index: libwnck/window.h
===================================================================
RCS file: /export/cvs/head/libwnck/libwnck/window.h,v
retrieving revision 1.35
diff -p -u -5 -r1.35 window.h
--- libwnck/window.h	19 Jul 2005 10:18:04 -0000	1.35
+++ libwnck/window.h	2 Sep 2005 12:01:13 -0000
@@ -43,10 +43,11 @@ typedef enum
   WNCK_WINDOW_STATE_STICKY                 = 1 << 6,
   WNCK_WINDOW_STATE_HIDDEN                 = 1 << 7,
   WNCK_WINDOW_STATE_FULLSCREEN             = 1 << 8,
   WNCK_WINDOW_STATE_DEMANDS_ATTENTION      = 1 << 9,
   WNCK_WINDOW_STATE_URGENT                 = 1 << 10,
+  WNCK_WINDOW_STATE_ABOVE                  = 1 << 11
 } WnckWindowState;
 
 typedef enum
 {
   WNCK_WINDOW_ACTION_MOVE                    = 1 << 0,
@@ -63,11 +64,12 @@ typedef enum
   WNCK_WINDOW_ACTION_UNSTICK                 = 1 << 11,
   WNCK_WINDOW_ACTION_MINIMIZE                = 1 << 12,
   WNCK_WINDOW_ACTION_UNMINIMIZE              = 1 << 13,
   WNCK_WINDOW_ACTION_MAXIMIZE                = 1 << 14,
   WNCK_WINDOW_ACTION_UNMAXIMIZE              = 1 << 15,
-  WNCK_WINDOW_ACTION_FULLSCREEN              = 1 << 16
+  WNCK_WINDOW_ACTION_FULLSCREEN              = 1 << 16,
+  WNCK_WINDOW_ACTION_ABOVE                   = 1 << 17
 } WnckWindowActions;
 
 typedef enum
 {
   WNCK_WINDOW_NORMAL,       /* document/app window */
@@ -155,10 +157,11 @@ void           wnck_window_set_window_ty
 gboolean wnck_window_is_minimized              (WnckWindow *window);
 gboolean wnck_window_is_maximized_horizontally (WnckWindow *window);
 gboolean wnck_window_is_maximized_vertically   (WnckWindow *window);
 gboolean wnck_window_is_maximized              (WnckWindow *window);
 gboolean wnck_window_is_shaded                 (WnckWindow *window);
+gboolean wnck_window_is_above                  (WnckWindow *window);
 gboolean wnck_window_is_skip_pager             (WnckWindow *window);
 gboolean wnck_window_is_skip_tasklist          (WnckWindow *window);
 gboolean wnck_window_is_fullscreen             (WnckWindow *window);
 gboolean wnck_window_is_sticky                 (WnckWindow *window);
 gboolean wnck_window_needs_attention           (WnckWindow *window);
@@ -182,10 +185,12 @@ void wnck_window_maximize_horizontally  
 void wnck_window_unmaximize_horizontally (WnckWindow *window);
 void wnck_window_maximize_vertically     (WnckWindow *window);
 void wnck_window_unmaximize_vertically   (WnckWindow *window);
 void wnck_window_shade                   (WnckWindow *window);
 void wnck_window_unshade                 (WnckWindow *window);
+void wnck_window_make_above              (WnckWindow *window);
+void wnck_window_unmake_above            (WnckWindow *window);
 void wnck_window_stick                   (WnckWindow *window);
 void wnck_window_unstick                 (WnckWindow *window);
 void wnck_window_keyboard_move           (WnckWindow *window);
 void wnck_window_keyboard_size           (WnckWindow *window);
 
Index: libwnck/window.c
===================================================================
RCS file: /export/cvs/head/libwnck/libwnck/window.c,v
retrieving revision 1.60
diff -p -u -5 -r1.60 window.c
--- libwnck/window.c	19 Jul 2005 10:18:04 -0000	1.60
+++ libwnck/window.c	2 Sep 2005 12:01:13 -0000
@@ -46,11 +46,12 @@ static GHashTable *window_hash = NULL;
     ((window)->priv->skip_taskbar        << 5) |        \
     ((window)->priv->is_sticky           << 6) |        \
     ((window)->priv->is_hidden           << 7) |        \
     ((window)->priv->is_fullscreen       << 8) |        \
     ((window)->priv->demands_attention   << 9) |        \
-    ((window)->priv->is_urgent           << 10) )
+    ((window)->priv->is_urgent           << 10)|        \
+    ((window)->priv->is_above            << 11))
 
 struct _WnckWindowPrivate
 {
   Window xwindow;
   WnckScreen *screen;
@@ -93,10 +94,11 @@ struct _WnckWindowPrivate
   /* window state */
   guint is_minimized : 1;
   guint is_maximized_horz : 1;
   guint is_maximized_vert : 1;
   guint is_shaded : 1;
+  guint is_above : 1;
   guint skip_pager : 1;
   guint skip_taskbar : 1;
   guint is_sticky : 1;
   guint is_hidden : 1;
   guint is_fullscreen : 1;
@@ -822,10 +824,18 @@ wnck_window_is_shaded                 (W
 
   return window->priv->is_shaded;
 }
 
 gboolean
+wnck_window_is_above                  (WnckWindow *window)
+{
+  g_return_val_if_fail (WNCK_IS_WINDOW (window), FALSE);
+
+  return window->priv->is_above;
+}
+
+gboolean
 wnck_window_is_skip_pager             (WnckWindow *window)
 {
   g_return_val_if_fail (WNCK_IS_WINDOW (window), FALSE);
 
   return window->priv->skip_pager;
@@ -1025,10 +1035,34 @@ wnck_window_unshade                 (Wnc
                       _wnck_atom_get ("_NET_WM_STATE_SHADED"),
                       0);
 }
 
 void
+wnck_window_make_above (WnckWindow *window)
+{
+  g_return_if_fail (WNCK_IS_WINDOW (window));
+
+  _wnck_change_state (WNCK_SCREEN_XSCREEN (window->priv->screen),
+                      window->priv->xwindow,
+                      TRUE,
+                      _wnck_atom_get ("_NET_WM_STATE_ABOVE"),
+                      0);
+}
+
+void
+wnck_window_unmake_above (WnckWindow *window)
+{
+  g_return_if_fail (WNCK_IS_WINDOW (window));
+
+  _wnck_change_state (WNCK_SCREEN_XSCREEN (window->priv->screen),
+                      window->priv->xwindow,
+                      FALSE,
+                      _wnck_atom_get ("_NET_WM_STATE_ABOVE"),
+                      0);
+}
+
+void
 wnck_window_stick                   (WnckWindow *window)
 {
   g_return_if_fail (WNCK_IS_WINDOW (window));
 
   _wnck_change_state (WNCK_SCREEN_XSCREEN (window->priv->screen),
@@ -1771,10 +1805,11 @@ update_state (WnckWindow *window)
     {
       window->priv->is_maximized_horz = FALSE;
       window->priv->is_maximized_vert = FALSE;
       window->priv->is_sticky = FALSE;
       window->priv->is_shaded = FALSE;
+      window->priv->is_above = FALSE;
       window->priv->skip_taskbar = FALSE;
       window->priv->skip_pager = FALSE;
       window->priv->net_wm_state_hidden = FALSE;
       window->priv->demands_attention = FALSE;
       
@@ -1795,10 +1830,12 @@ update_state (WnckWindow *window)
             window->priv->net_wm_state_hidden = TRUE;
           else if (atoms[i] == _wnck_atom_get ("_NET_WM_STATE_STICKY"))
             window->priv->is_sticky = TRUE;
           else if (atoms[i] == _wnck_atom_get ("_NET_WM_STATE_SHADED"))
             window->priv->is_shaded = TRUE;
+          else if (atoms[i] == _wnck_atom_get ("_NET_WM_STATE_ABOVE"))
+            window->priv->is_above = TRUE;
           else if (atoms[i] == _wnck_atom_get ("_NET_WM_STATE_FULLSCREEN"))
             window->priv->is_fullscreen = TRUE;
           else if (atoms[i] == _wnck_atom_get ("_NET_WM_STATE_SKIP_TASKBAR"))
             window->priv->skip_taskbar = TRUE;
           else if (atoms[i] == _wnck_atom_get ("_NET_WM_STATE_SKIP_PAGER"))
@@ -1966,10 +2003,11 @@ update_actions (WnckWindow *window)
     {
       window->priv->actions = 
                 WNCK_WINDOW_ACTION_MOVE                    |
                 WNCK_WINDOW_ACTION_RESIZE                  |
                 WNCK_WINDOW_ACTION_SHADE                   |
+                WNCK_WINDOW_ACTION_ABOVE                   |
                 WNCK_WINDOW_ACTION_STICK                   |
                 WNCK_WINDOW_ACTION_MAXIMIZE_HORIZONTALLY   |
                 WNCK_WINDOW_ACTION_MAXIMIZE_VERTICALLY     |
                 WNCK_WINDOW_ACTION_CHANGE_WORKSPACE        |
                 WNCK_WINDOW_ACTION_CLOSE                   |
