Index: constraints.c
===================================================================
RCS file: /cvs/gnome/metacity/src/constraints.c,v
retrieving revision 1.8
diff -p -u -r1.8 constraints.c
--- constraints.c	2 May 2003 07:31:59 -0000	1.8
+++ constraints.c	7 Jun 2003 21:24:01 -0000
@@ -21,6 +21,8 @@
 
 #include <config.h>
 #include "constraints.h"
+#include "window.h"
+#include "workspace.h"
 #include "place.h"
 
 /* The way this code works was suggested by Owen Taylor.
@@ -301,7 +303,7 @@ static const Constraint constraint_deskt
  * behavior, but not doing that for now.
  *
  * Top resize works the same as left resize. Right/bottom resize don't have a limit
- * because the constraint is designed to keep the top right corner of the
+ * because the constraint is designed to keep the top left corner of the
  * window or its titlebar on the screen, and right/bottom resize will never move that
  * area. Center resize is almost like left/top but dx has the opposite sign
  * and new_width = orig_width + 2dx.
@@ -352,26 +354,141 @@ get_outermost_onscreen_positions (MetaWi
                                   int                  *topmost_y,
                                   int                  *bottommost_y)
 {
-  if (leftmost_x)
-    *leftmost_x = info->nw_x  - orig->width +
-      MIN (TITLEBAR_LENGTH_ONSCREEN, orig->width);
+  GList *workspaces = meta_window_get_workspaces (window);
+  GList *tmp = workspaces;
+  GSList *stmp;
+
+  /* to handle struts, we get the list of workspaces for the window
+   * and traverse all the struts in each of the cached strut lists for
+   * the workspaces.  Note that because the workarea has already been
+   * computed, these strut lists should already be up to date.  No
+   * memory allocation should take place in this function for
+   * performance.
+   */
 
+  if (leftmost_x)
+    {
+      *leftmost_x = info->nw_x;
+      while (tmp)
+        {
+          stmp = ((MetaWorkspace*) tmp->data)->left_struts;
+          while (stmp)
+            {
+              MetaRectangle *rect = (MetaRectangle*) stmp->data;
+              /* the strut only matters if the title bar is
+               * overlapping the strut rect.
+               */
+              if (((orig->y - info->fgeom.top_height >= rect->y) &&
+                   (orig->y - info->fgeom.top_height <= rect->y + rect->height)) ||
+                  ((orig->y >= rect->y) &&
+                   (orig->y <= rect->y + rect->height)))
+                {
+                  *leftmost_x = MAX (*leftmost_x, rect->width);
+                }
+              
+              stmp = stmp->next;
+            }
+          
+          tmp = tmp->next;
+        }
+      
+      *leftmost_x = *leftmost_x - orig->width +
+        MIN (TITLEBAR_LENGTH_ONSCREEN, orig->width);
+    }
+  
+  tmp = workspaces;
   if (rightmost_x)
-    *rightmost_x = info->se_x - MIN (TITLEBAR_LENGTH_ONSCREEN, orig->width);
+    {
+      *rightmost_x = info->se_x;
+      while (tmp)
+        {
+          stmp = ((MetaWorkspace*) tmp->data)->right_struts;
+          while (stmp)
+            {
+              MetaRectangle *rect = (MetaRectangle*) stmp->data;
+              /* the strut only matters if the title bar is
+               * overlapping the strut rect.
+               */
+              if (((orig->y - info->fgeom.top_height >= rect->y) &&
+                   (orig->y - info->fgeom.top_height <= rect->y + rect->height)) ||
+                  ((orig->y >= rect->y) &&
+                   (orig->y <= rect->y + rect->height)))
+                {
+                  *rightmost_x = MIN (*rightmost_x, rect->x);
+                }
+              
+              stmp = stmp->next;
+            }
+          
+          tmp = tmp->next;
+        }
+      
+      *rightmost_x = *rightmost_x - MIN (TITLEBAR_LENGTH_ONSCREEN, orig->width);
+    }
 
+  tmp = workspaces;
   if (topmost_y)
-    *topmost_y = info->nw_y + info->fgeom.top_height;
+    {
+      *topmost_y = info->nw_y;
+      while (tmp)
+        {
+          stmp = ((MetaWorkspace*) tmp->data)->top_struts;
+          while (stmp)
+            {
+              MetaRectangle *rect = (MetaRectangle*) stmp->data;
+              /* here the strut matters if the titlebar is overlapping
+               * the window by too much -- need
+               * TITLEBAR_LENGTH_ONSCREEN sticking out on either the
+               * right or the left
+               */
+              if ((orig->x + TITLEBAR_LENGTH_ONSCREEN >= rect->x) &&
+                  (orig->x + orig->width - TITLEBAR_LENGTH_ONSCREEN <= rect->x + rect->width))
+                {
+                  *topmost_y = MAX (*topmost_y, rect->height);
+                }
+              
+              stmp = stmp->next;
+            }
+          
+          tmp = tmp->next;
+        }
+      
+      *topmost_y = *topmost_y + info->fgeom.top_height;
+    }
 
+  tmp = workspaces;
   if (bottommost_y)
     {
+      *bottommost_y = info->se_y;
+      while (tmp)
+        {
+          stmp = ((MetaWorkspace*) tmp->data)->bottom_struts;
+          while (stmp)
+            {
+              MetaRectangle *rect = (MetaRectangle*) stmp->data;
+              /* here the strut matters if the titlebar is overlapping
+               * the window by too much -- need
+               * TITLEBAR_LENGTH_ONSCREEN sticking out on either the
+               * right or the left
+               */
+              if ((orig->x + TITLEBAR_LENGTH_ONSCREEN >= rect->x) &&
+                  (orig->x + orig->width - TITLEBAR_LENGTH_ONSCREEN <= rect->x + rect->width))
+                {
+                  *bottommost_y = MIN (*bottommost_y, rect->y);
+                }
+              
+              stmp = stmp->next;
+            }
+          
+          tmp = tmp->next;
+        }
+      
       /* If no frame, keep random TITLEBAR_LENGTH_ONSCREEN pixels on the
        * screen.
        */
-      if (window->frame)
-        *bottommost_y = info->se_y;
-      else
-        *bottommost_y = info->se_y -
-	  MIN (TITLEBAR_LENGTH_ONSCREEN, orig->height);
+      if (!window->frame)
+        *bottommost_y = *bottommost_y -
+          MIN (TITLEBAR_LENGTH_ONSCREEN, orig->height);
     }
 }
 
@@ -1023,12 +1140,24 @@ update_position_limits (MetaWindow      
   int nw_x, nw_y;
   int se_x, se_y;
 
-  nw_x = info->work_area_screen.x;
-  nw_y = info->work_area_screen.y;
+  if (window->maximized)
+    {
+      nw_x = MIN(info->work_area_xinerama.x, info->work_area_screen.x);
+      nw_y = MIN(info->work_area_xinerama.y, info->work_area_screen.y);
 
-  /* find bottom-right corner of workarea */
-  se_x = info->work_area_screen.x + info->work_area_screen.width;
-  se_y = info->work_area_screen.y + info->work_area_screen.height;
+      /* find bottom-right corner of workarea */
+      se_x = MAX(info->work_area_xinerama.x + info->work_area_xinerama.width,
+                 info->work_area_screen.x + info->work_area_screen.width);
+      se_y = MAX(info->work_area_xinerama.y + info->work_area_xinerama.height,
+                 info->work_area_screen.y + info->work_area_screen.height);
+    }
+  else
+    {
+      nw_x = 0;
+      nw_y = 0;
+      se_x = window->screen->width;
+      se_y = window->screen->height;
+   }
 
   /* If we have a micro-screen or huge frames maybe nw/se got
    * swapped
@@ -1119,14 +1248,22 @@ meta_window_constrain (MetaWindow       
       !window->maximized &&
       !window->fullscreen)
     {
-      int x, y;
+      MetaRectangle placed_rect = current;
 
       meta_window_place (window, orig_fgeom, current.x, current.y,
-                         &x, &y);
+                         &placed_rect.x, &placed_rect.y);
+
+      /* xinerama may have changed, so update xinerama information */
+      info.xinerama = meta_screen_get_xinerama_for_rect (window->screen,
+							 &placed_rect);
+      meta_window_get_work_area_for_xinerama (window,
+                                              info.xinerama->number,
+                                              &info.work_area_xinerama);
+      update_position_limits (window, &info);
 
       constrain_move (window, &info, &current,
-                      x - current.x,
-                      y - current.y,
+                      placed_rect.x - current.x,
+                      placed_rect.y - current.y,
                       new);
       current = *new;
 
Index: display.c
===================================================================
RCS file: /cvs/gnome/metacity/src/display.c,v
retrieving revision 1.187
diff -p -u -r1.187 display.c
--- display.c	30 May 2003 20:24:00 -0000	1.187
+++ display.c	7 Jun 2003 21:24:04 -0000
@@ -232,6 +232,7 @@ meta_display_open (const char *name)
     "_NET_ACTIVE_WINDOW",
     "_METACITY_RESTART_MESSAGE",    
     "_NET_WM_STRUT",
+    "_NET_WM_STRUT_PARTIAL",
     "_WIN_HINTS",
     "_METACITY_RELOAD_THEME_MESSAGE",
     "_METACITY_SET_KEYBINDINGS_MESSAGE",
@@ -379,45 +380,46 @@ meta_display_open (const char *name)
   display->atom_net_active_window = atoms[43];
   display->atom_metacity_restart_message = atoms[44];
   display->atom_net_wm_strut = atoms[45];
-  display->atom_win_hints = atoms[46];
-  display->atom_metacity_reload_theme_message = atoms[47];
-  display->atom_metacity_set_keybindings_message = atoms[48];
-  display->atom_net_wm_state_hidden = atoms[49];
-  display->atom_net_wm_window_type_utility = atoms[50];
-  display->atom_net_wm_window_type_splash = atoms[51];
-  display->atom_net_wm_state_fullscreen = atoms[52];
-  display->atom_net_wm_ping = atoms[53];
-  display->atom_net_wm_pid = atoms[54];
-  display->atom_wm_client_machine = atoms[55];
-  display->atom_net_workarea = atoms[56];
-  display->atom_net_showing_desktop = atoms[57];
-  display->atom_net_desktop_layout = atoms[58];
-  display->atom_manager = atoms[59];
-  display->atom_targets = atoms[60];
-  display->atom_multiple = atoms[61];
-  display->atom_timestamp = atoms[62];
-  display->atom_version = atoms[63];
-  display->atom_atom_pair = atoms[64];
-  display->atom_net_desktop_names = atoms[65];
-  display->atom_net_wm_allowed_actions = atoms[66];
-  display->atom_net_wm_action_move = atoms[67];
-  display->atom_net_wm_action_resize = atoms[68];
-  display->atom_net_wm_action_shade = atoms[69];
-  display->atom_net_wm_action_stick = atoms[70];
-  display->atom_net_wm_action_maximize_horz = atoms[71];
-  display->atom_net_wm_action_maximize_vert = atoms[72];
-  display->atom_net_wm_action_change_desktop = atoms[73];
-  display->atom_net_wm_action_close = atoms[74];
-  display->atom_net_wm_state_above = atoms[75];
-  display->atom_net_wm_state_below = atoms[76];
-  display->atom_net_startup_id = atoms[77];
-  display->atom_metacity_toggle_verbose = atoms[78];
-  display->atom_metacity_update_counter = atoms[79];
-  display->atom_sync_counter = atoms[80];
-  display->atom_gnome_panel_action = atoms[81];
-  display->atom_gnome_panel_action_main_menu = atoms[82];
-  display->atom_gnome_panel_action_run_dialog = atoms[83];
-  display->atom_metacity_sentinel = atoms[84];
+  display->atom_net_wm_strut_partial = atoms[46];
+  display->atom_win_hints = atoms[47];
+  display->atom_metacity_reload_theme_message = atoms[48];
+  display->atom_metacity_set_keybindings_message = atoms[49];
+  display->atom_net_wm_state_hidden = atoms[50];
+  display->atom_net_wm_window_type_utility = atoms[51];
+  display->atom_net_wm_window_type_splash = atoms[52];
+  display->atom_net_wm_state_fullscreen = atoms[53];
+  display->atom_net_wm_ping = atoms[54];
+  display->atom_net_wm_pid = atoms[55];
+  display->atom_wm_client_machine = atoms[56];
+  display->atom_net_workarea = atoms[57];
+  display->atom_net_showing_desktop = atoms[58];
+  display->atom_net_desktop_layout = atoms[59];
+  display->atom_manager = atoms[60];
+  display->atom_targets = atoms[61];
+  display->atom_multiple = atoms[62];
+  display->atom_timestamp = atoms[63];
+  display->atom_version = atoms[64];
+  display->atom_atom_pair = atoms[65];
+  display->atom_net_desktop_names = atoms[66];
+  display->atom_net_wm_allowed_actions = atoms[67];
+  display->atom_net_wm_action_move = atoms[68];
+  display->atom_net_wm_action_resize = atoms[69];
+  display->atom_net_wm_action_shade = atoms[70];
+  display->atom_net_wm_action_stick = atoms[71];
+  display->atom_net_wm_action_maximize_horz = atoms[72];
+  display->atom_net_wm_action_maximize_vert = atoms[73];
+  display->atom_net_wm_action_change_desktop = atoms[74];
+  display->atom_net_wm_action_close = atoms[75];
+  display->atom_net_wm_state_above = atoms[76];
+  display->atom_net_wm_state_below = atoms[77];
+  display->atom_net_startup_id = atoms[78];
+  display->atom_metacity_toggle_verbose = atoms[79];
+  display->atom_metacity_update_counter = atoms[80];
+  display->atom_sync_counter = atoms[81];
+  display->atom_gnome_panel_action = atoms[82];
+  display->atom_gnome_panel_action_main_menu = atoms[83];
+  display->atom_gnome_panel_action_run_dialog = atoms[84];
+  display->atom_metacity_sentinel = atoms[85];
   
   display->prop_hooks = NULL;
   meta_display_init_window_prop_hooks (display);
@@ -3672,6 +3674,16 @@ meta_rectangle_intersect (MetaRectangle 
     }
 
   return return_val;
+}
+
+gboolean
+meta_rectangle_equal (MetaRectangle *src1,
+                      MetaRectangle *src2)
+{
+  return ((src1->x == src2->x) &&
+          (src1->y == src2->y) &&
+          (src1->width == src2->width) &&
+          (src1->height == src2->height));
 }
 
 static MetaScreen*
Index: display.h
===================================================================
RCS file: /cvs/gnome/metacity/src/display.h,v
retrieving revision 1.103
diff -p -u -r1.103 display.h
--- display.h	30 May 2003 20:24:00 -0000	1.103
+++ display.h	7 Jun 2003 21:24:06 -0000
@@ -134,6 +134,7 @@ struct _MetaDisplay
   Atom atom_net_active_window;
   Atom atom_metacity_restart_message;
   Atom atom_net_wm_strut;
+  Atom atom_net_wm_strut_partial;
   Atom atom_win_hints;
   Atom atom_metacity_reload_theme_message;
   Atom atom_metacity_set_keybindings_message;
@@ -441,6 +442,8 @@ gboolean meta_grab_op_is_resizing (MetaG
 gboolean meta_rectangle_intersect (MetaRectangle *src1,
                                    MetaRectangle *src2,
                                    MetaRectangle *dest);
+gboolean meta_rectangle_equal (MetaRectangle *src1,
+                               MetaRectangle *src2);
 
 void meta_display_devirtualize_modifiers (MetaDisplay        *display,
                                           MetaVirtualModifier modifiers,
Index: screen.c
===================================================================
RCS file: /cvs/gnome/metacity/src/screen.c,v
retrieving revision 1.106
diff -p -u -r1.106 screen.c
--- screen.c	16 May 2003 21:59:07 -0000	1.106
+++ screen.c	7 Jun 2003 21:24:07 -0000
@@ -1479,21 +1479,18 @@ meta_screen_get_natural_xinerama_list (M
 }
 
 gboolean
-meta_screen_window_intersects_xinerama (MetaScreen *screen,
-                                        MetaWindow *window,
-                                        int         which_xinerama)
+meta_screen_rect_intersects_xinerama (MetaScreen    *screen,
+                                      MetaRectangle *rect,
+                                      int            which_xinerama)
 {
-  MetaRectangle window_rect;
   MetaRectangle dest, screen_rect;
   
-  meta_window_get_outer_rect (window, &window_rect);
-  
   screen_rect.x = screen->xinerama_infos[which_xinerama].x_origin;
   screen_rect.y = screen->xinerama_infos[which_xinerama].y_origin;
   screen_rect.width = screen->xinerama_infos[which_xinerama].width;
   screen_rect.height = screen->xinerama_infos[which_xinerama].height;
   
-  if (meta_rectangle_intersect (&screen_rect, &window_rect, &dest))
+  if (meta_rectangle_intersect (&screen_rect, rect, &dest))
     return TRUE;
 
   return FALSE;
Index: screen.h
===================================================================
RCS file: /cvs/gnome/metacity/src/screen.h,v
retrieving revision 1.49
diff -p -u -r1.49 screen.h
--- screen.h	16 May 2003 21:59:08 -0000	1.49
+++ screen.h	7 Jun 2003 21:24:07 -0000
@@ -148,9 +148,9 @@ const MetaXineramaScreenInfo* meta_scree
 const MetaXineramaScreenInfo* meta_screen_get_xinerama_for_window (MetaScreen    *screen,
                                                                    MetaWindow    *window);
 
-gboolean      meta_screen_window_intersects_xinerama (MetaScreen *screen, 
-                                                      MetaWindow *window,
-                                                      int         which_xinerama);
+gboolean      meta_screen_rect_intersects_xinerama (MetaScreen    *screen, 
+                                                    MetaRectangle *window,
+                                                    int            which_xinerama);
 
 const MetaXineramaScreenInfo* meta_screen_get_xinerama_neighbor (MetaScreen *screen,
                                                                  int         which_xinerama,
Index: window.c
===================================================================
RCS file: /cvs/gnome/metacity/src/window.c,v
retrieving revision 1.284
diff -p -u -r1.284 window.c
--- window.c	7 Jun 2003 17:15:33 -0000	1.284
+++ window.c	7 Jun 2003 21:24:13 -0000
@@ -88,8 +88,6 @@ static gboolean process_property_notify 
 static void     meta_window_show          (MetaWindow     *window);
 static void     meta_window_hide          (MetaWindow     *window);
 
-static GList*   meta_window_get_workspaces (MetaWindow    *window);
-
 static void     meta_window_save_rect         (MetaWindow    *window);
 
 static void meta_window_move_resize_internal (MetaWindow         *window,
@@ -490,10 +488,6 @@ meta_window_new (MetaDisplay *display,
 
   window->has_struts = FALSE;
   window->do_not_cover = FALSE;
-  window->left_strut = 0;
-  window->right_strut = 0;
-  window->top_strut = 0;
-  window->bottom_strut = 0;
 
   window->using_net_wm_name = FALSE;
   window->using_net_wm_icon_name = FALSE;
@@ -4213,7 +4207,8 @@ process_property_notify (MetaWindow     
                                         event->atom);
       meta_window_queue_update_icon (window);
     }
-  else if (event->atom == window->display->atom_net_wm_strut)
+  else if ((event->atom == window->display->atom_net_wm_strut) ||
+	   (event->atom == window->display->atom_net_wm_strut_partial))
     {
       meta_verbose ("Property notify on %s for _NET_WM_STRUT\n", window->desc);
       update_struts (window);
@@ -4917,7 +4912,7 @@ meta_window_queue_update_icon (MetaWindo
   update_icon_pending = g_slist_prepend (update_icon_pending, window);
 }
 
-static GList*
+GList*
 meta_window_get_workspaces (MetaWindow *window)
 {
   if (window->on_all_workspaces)
@@ -4947,10 +4942,10 @@ update_struts (MetaWindow *window)
   int nitems;
   gboolean old_has_struts;
   gboolean old_do_not_cover;
-  int old_left;
-  int old_right;
-  int old_top;
-  int old_bottom;
+  MetaRectangle old_left;
+  MetaRectangle old_right;
+  MetaRectangle old_top;
+  MetaRectangle old_bottom;
   
   meta_verbose ("Updating struts for %s\n", window->desc);
   
@@ -4963,55 +4958,109 @@ update_struts (MetaWindow *window)
   
   window->has_struts = FALSE;
   window->do_not_cover = FALSE;
-  window->left_strut = 0;
-  window->right_strut = 0;
-  window->top_strut = 0;
-  window->bottom_strut = 0;
+
+  window->left_strut.width = 0;
+  window->left_strut.x = 0;
+  window->left_strut.y = 0;
+  window->left_strut.height = window->screen->height;
+
+  window->right_strut.width = 0;
+  window->right_strut.x = window->screen->width;
+  window->right_strut.y = 0;
+  window->right_strut.height = window->screen->height;
+
+  window->top_strut.height = 0;
+  window->top_strut.y = 0;
+  window->top_strut.x = 0;
+  window->top_strut.width = window->screen->width;
+
+  window->bottom_strut.height = 0;
+  window->bottom_strut.y = window->screen->height;
+  window->bottom_strut.x = 0;
+  window->bottom_strut.width = window->screen->width;
   
   if (meta_prop_get_cardinal_list (window->display,
                                    window->xwindow,
-                                   window->display->atom_net_wm_strut,
+                                   window->display->atom_net_wm_strut_partial,
                                    &struts, &nitems))
     {
-      if (nitems != 4)
+      if (nitems != 12)
         {
-          meta_verbose ("_NET_WM_STRUT on %s has %d values instead of 4\n",
+          meta_verbose ("_NET_WM_STRUT_PARTIAL on %s has %d values instead of 12\n",
                         window->desc, nitems);
           meta_XFree (struts);
         }
       
       window->has_struts = TRUE;
-      window->left_strut = struts[0];
-      window->right_strut = struts[1];
-      window->top_strut = struts[2];
-      window->bottom_strut = struts[3];
-
-      meta_verbose ("_NET_WM_STRUT struts %d %d %d %d for window %s\n",
-                    window->left_strut, window->right_strut,
-                    window->top_strut, window->bottom_strut,
+      window->left_strut.width = struts[0];
+      window->right_strut.width = struts[1];
+      window->top_strut.height = struts[2];
+      window->bottom_strut.height = struts[3];
+      window->right_strut.x = window->screen->width - window->right_strut.width;
+      window->bottom_strut.y = window->screen->height - window->bottom_strut.height;
+      window->left_strut.y = struts[4];
+      window->left_strut.height = struts[5] - window->left_strut.y;
+      window->right_strut.y = struts[6];
+      window->right_strut.height = struts[7] - window->right_strut.y;
+      window->top_strut.x = struts[8];
+      window->top_strut.width = struts[9] - window->top_strut.x;
+      window->bottom_strut.x = struts[10];
+      window->bottom_strut.width = struts[11] - window->bottom_strut.x;
+
+      meta_verbose ("_NET_WM_STRUT_PARTIAL struts %d %d %d %d for window %s\n",
+                    window->left_strut.width,
+                    window->right_strut.width,
+                    window->top_strut.height,
+                    window->bottom_strut.height,
                     window->desc);
-      
-      if (window->left_strut < 0)
-        window->left_strut = 0;
-      if (window->right_strut < 0)
-        window->right_strut = 0;
-      if (window->top_strut < 0)
-        window->top_strut = 0;
-      if (window->bottom_strut < 0)
-        window->bottom_strut = 0;
-      
-      meta_verbose ("Using _NET_WM_STRUT struts %d %d %d %d for window %s\n",
-                    window->left_strut, window->right_strut,
-                    window->top_strut, window->bottom_strut,
-                    window->desc);
-      
+            
       meta_XFree (struts);
     }
   else
     {
-      meta_verbose ("No _NET_WM_STRUT property for %s\n",
+      meta_verbose ("No _NET_WM_STRUT_PARTIAL property for %s\n",
                     window->desc);
     }
+
+  if (!window->has_struts)
+    {
+      if (meta_prop_get_cardinal_list (window->display,
+                                       window->xwindow,
+                                       window->display->atom_net_wm_strut,
+                                       &struts, &nitems))
+        {
+          if (nitems != 4)
+            {
+              meta_verbose ("_NET_WM_STRUT on %s has %d values instead of 4\n",
+                            window->desc, nitems);
+              meta_XFree (struts);
+            }
+          
+          window->has_struts = TRUE;
+          window->left_strut.width = struts[0];
+          window->right_strut.width = struts[1];
+          window->top_strut.height = struts[2];
+          window->bottom_strut.height = struts[3];
+          window->left_strut.x = 0;
+          window->right_strut.x = window->screen->width - window->right_strut.width;
+          window->top_strut.y = 0;
+          window->bottom_strut.y = window->screen->height - window->bottom_strut.height;
+          
+          meta_verbose ("_NET_WM_STRUT struts %d %d %d %d for window %s\n",
+                        window->left_strut.width,
+                        window->right_strut.width,
+                        window->top_strut.height,
+                        window->bottom_strut.height,
+                        window->desc);
+          
+          meta_XFree (struts);
+        }
+      else
+        {
+          meta_verbose ("No _NET_WM_STRUT property for %s\n",
+                        window->desc);
+        }
+    }
   
   if (!window->has_struts)
     {
@@ -5030,8 +5079,8 @@ update_struts (MetaWindow *window)
               recalc_do_not_cover_struts (window);
 
               meta_verbose ("Using _WIN_HINTS struts %d %d %d %d for window %s\n",
-                            window->left_strut, window->right_strut,
-                            window->top_strut, window->bottom_strut,
+                            window->left_strut.width, window->right_strut.width,
+                            window->top_strut.height, window->bottom_strut.height,
                             window->desc);              
             }
           else
@@ -5048,10 +5097,10 @@ update_struts (MetaWindow *window)
 
   if (old_has_struts != window->has_struts ||
       old_do_not_cover != window->do_not_cover ||
-      old_left != window->left_strut ||
-      old_right != window->right_strut ||
-      old_top != window->top_strut ||
-      old_bottom != window->bottom_strut)
+      !meta_rectangle_equal(&old_left, &window->left_strut) ||
+      !meta_rectangle_equal(&old_right, &window->right_strut) ||
+      !meta_rectangle_equal(&old_top, &window->top_strut) ||
+      !meta_rectangle_equal(&old_bottom, &window->bottom_strut))
     {  
       meta_topic (META_DEBUG_WORKAREA,
                   "Invalidating work areas of window %s due to struts update\n",
@@ -5079,10 +5128,22 @@ recalc_do_not_cover_struts (MetaWindow *
       gboolean on_bottom_edge;
       gboolean on_top_edge;      
 
-      window->left_strut = 0;
-      window->right_strut = 0;
-      window->top_strut = 0;
-      window->bottom_strut = 0;
+      window->left_strut.width = 0;
+      window->right_strut.width = 0;
+      window->top_strut.height = 0;
+      window->bottom_strut.height = 0;
+      window->left_strut.x = 0;
+      window->right_strut.x = window->screen->width;
+      window->top_strut.y = 0;
+      window->bottom_strut.y = window->screen->height;
+      window->left_strut.y = 0;
+      window->left_strut.height = window->screen->height;
+      window->right_strut.y = 0;
+      window->right_strut.height = window->screen->height;
+      window->top_strut.x = 0;
+      window->top_strut.width = window->screen->width;
+      window->bottom_strut.x = 0;
+      window->bottom_strut.width = window->screen->width;
       
       on_left_edge = window->rect.x == 0;
       on_right_edge = (window->rect.x + window->rect.width) ==
@@ -5106,16 +5167,26 @@ recalc_do_not_cover_struts (MetaWindow *
       if (horizontal)
         {
           if (on_top_edge)
-            window->top_strut = window->rect.height;
+	    {
+	      window->top_strut.height = window->rect.height;
+	    }
           else if (on_bottom_edge)
-            window->bottom_strut = window->rect.height;
+	    {
+	      window->bottom_strut.height = window->rect.height;
+	      window->bottom_strut.y = window->screen->height - window->bottom_strut.height;
+	    }
         }
       else
         {
           if (on_left_edge)
-            window->left_strut = window->rect.width;
+	    {
+	      window->left_strut.width = window->rect.width;
+	    }
           else if (on_right_edge)
-            window->right_strut = window->rect.width;
+	    {
+	      window->right_strut.width = window->rect.width;
+	      window->right_strut.x = window->screen->width - window->right_strut.width;
+	    }
         }
     }
 }
Index: window.h
===================================================================
RCS file: /cvs/gnome/metacity/src/window.h,v
retrieving revision 1.89
diff -p -u -r1.89 window.h
--- window.h	4 Jun 2003 19:15:46 -0000	1.89
+++ window.h	7 Jun 2003 21:24:13 -0000
@@ -270,10 +270,10 @@ struct _MetaWindow
   XSizeHints size_hints;
 
   /* struts */
-  int left_strut;
-  int right_strut;
-  int top_strut;
-  int bottom_strut;
+  MetaRectangle left_strut;
+  MetaRectangle right_strut;
+  MetaRectangle top_strut;
+  MetaRectangle bottom_strut;
   
   /* Managed by stack.c */
   MetaStackLayer layer;
@@ -415,6 +415,8 @@ void meta_window_set_gravity (MetaWindow
 
 void meta_window_handle_mouse_grab_op_event (MetaWindow *window,
                                              XEvent     *event);
+
+GList* meta_window_get_workspaces (MetaWindow *window);
 
 gboolean meta_window_visible_on_workspace (MetaWindow    *window,
                                            MetaWorkspace *workspace);
Index: workspace.c
===================================================================
RCS file: /cvs/gnome/metacity/src/workspace.c,v
retrieving revision 1.43
diff -p -u -r1.43 workspace.c
--- workspace.c	30 May 2003 20:24:00 -0000	1.43
+++ workspace.c	7 Jun 2003 21:24:14 -0000
@@ -48,6 +48,11 @@ meta_workspace_new (MetaScreen *screen)
   workspace->all_work_areas.y = 0;
   workspace->all_work_areas.width = 0;
   workspace->all_work_areas.height = 0;
+
+  workspace->left_struts = NULL;
+  workspace->right_struts = NULL;
+  workspace->top_struts = NULL;
+  workspace->bottom_struts = NULL;
   
   return workspace;
 }
@@ -86,6 +91,12 @@ meta_workspace_free (MetaWorkspace *work
     g_list_remove (workspace->screen->workspaces, workspace);
   
   g_free (workspace->work_areas);
+
+  g_slist_free (workspace->left_struts);
+  g_slist_free (workspace->right_struts);
+  g_slist_free (workspace->top_struts);
+  g_slist_free (workspace->bottom_struts);
+
   g_free (workspace);
 
   /* don't bother to reset names, pagers can just ignore
@@ -375,6 +386,15 @@ ensure_work_areas_validated (MetaWorkspa
   if (!workspace->work_areas_invalid)
     return;
       
+  g_slist_free (workspace->left_struts);
+  workspace->left_struts = NULL;
+  g_slist_free (workspace->right_struts);
+  workspace->right_struts = NULL;
+  g_slist_free (workspace->top_struts);
+  workspace->top_struts = NULL;
+  g_slist_free (workspace->bottom_struts);
+  workspace->bottom_struts = NULL;
+
   windows = meta_workspace_list_windows (workspace);
 
   g_free (workspace->work_areas);
@@ -394,33 +414,76 @@ ensure_work_areas_validated (MetaWorkspa
         {
           MetaWindow *w = tmp->data;
 
-          if (w->has_struts && 
-              (meta_screen_window_intersects_xinerama (w->screen, w, i)))
+          if (w->has_struts)
             {
               meta_topic (META_DEBUG_WORKAREA,
                           "Merging win %s with %d %d %d %d "
                           "with %d %d %d %d\n",
                           w->desc,
-                          w->left_strut, w->right_strut, 
-                          w->top_strut, w->bottom_strut,
+                          w->left_strut.width, w->right_strut.width, 
+                          w->top_strut.height, w->bottom_strut.height,
                           left_strut, right_strut, 
                           top_strut, bottom_strut);
 
-              left_strut = MAX (left_strut, 
-                                w->left_strut - 
-                                workspace->screen->xinerama_infos[i].x_origin);
-              all_left_strut = MAX (all_left_strut, w->left_strut);
-
-              right_strut = MAX (right_strut, w->right_strut);
-              all_right_strut = MAX (all_right_strut, w->right_strut);
-
-              top_strut = MAX (top_strut,
-                               w->top_strut - 
-                               workspace->screen->xinerama_infos[i].y_origin);
-              all_top_strut = MAX (all_top_strut, w->top_strut);
-
-              bottom_strut = MAX (bottom_strut, w->bottom_strut);
-              all_bottom_strut = MAX (all_bottom_strut, w->bottom_strut);
+              if ((i == 0) && (w->left_strut.width > 0))
+                {
+                  workspace->left_struts = g_slist_prepend (workspace->left_struts,
+                                                            &w->left_strut);
+                }
+
+              if (meta_screen_rect_intersects_xinerama (w->screen,
+                                                        &w->left_strut,
+                                                        i))
+                {
+                  left_strut = MAX (left_strut, 
+                                    w->left_strut.width - 
+                                    workspace->screen->xinerama_infos[i].x_origin);
+                  all_left_strut = MAX (all_left_strut, w->left_strut.width);
+                }
+
+              if ((i == 0) && (w->right_strut.width > 0))
+                {
+                  workspace->right_struts = g_slist_prepend (workspace->right_struts,
+							     &w->right_strut);
+                }
+
+              if (meta_screen_rect_intersects_xinerama (w->screen,
+                                                        &w->right_strut,
+                                                        i))
+                {
+                  right_strut = MAX (right_strut, w->right_strut.width);
+                  all_right_strut = MAX (all_right_strut, w->right_strut.width);
+                }
+
+              if ((i == 0) && (w->top_strut.height > 0))
+                {
+                  workspace->top_struts = g_slist_prepend (workspace->top_struts,
+                                                           &w->top_strut);
+                }
+
+              if (meta_screen_rect_intersects_xinerama (w->screen,
+                                                        &w->top_strut,
+                                                        i))
+                {
+                  top_strut = MAX (top_strut,
+                                   w->top_strut.height - 
+                                   workspace->screen->xinerama_infos[i].y_origin);
+                  all_top_strut = MAX (all_top_strut, w->top_strut.height);
+                }
+
+              if ((i == 0) && (w->bottom_strut.height > 0))
+                {
+                  workspace->bottom_struts = g_slist_prepend (workspace->bottom_struts,
+                                                              &w->bottom_strut);
+                }
+
+              if (meta_screen_rect_intersects_xinerama (w->screen,
+                                                        &w->bottom_strut,
+                                                        i))
+                {
+                  bottom_strut = MAX (bottom_strut, w->bottom_strut.height);
+                  all_bottom_strut = MAX (all_bottom_strut, w->bottom_strut.height);
+                }
             }
           
           tmp = tmp->next;
@@ -451,10 +514,6 @@ ensure_work_areas_validated (MetaWorkspa
           bottom_strut = top_strut;
         }
 
-      /* FIXME even if we take struts to apply only to xineramas
-       * that the strut-specifying window overlaps, is it right
-       * to make the struts *relative to* the xinerama?
-       */
       workspace->work_areas[i].x = 
         left_strut + workspace->screen->xinerama_infos[i].x_origin;
       workspace->work_areas[i].y = top_strut + 
@@ -467,7 +526,7 @@ ensure_work_areas_validated (MetaWorkspa
         top_strut - bottom_strut;
 
       meta_topic (META_DEBUG_WORKAREA,
-                  "Computed [unused] work area for workspace %d "
+                  "Computed work area for workspace %d "
                   "xinerama %d: %d,%d %d x %d\n",
                   meta_workspace_index (workspace),
                   i,
@@ -507,19 +566,6 @@ ensure_work_areas_validated (MetaWorkspa
     workspace->screen->width - all_left_strut - all_right_strut;
   workspace->all_work_areas.height = 
     workspace->screen->height - all_top_strut - all_bottom_strut;
-
-  /* FIXME Here we disable all the per-xinerama work done earlier,
-   * because we don't have a spec for how it should work yet.
-   * If we do rely on which windows overlap what, work areas
-   * will need to be invalidated when we change a strut-setting
-   * window's size/position in move_resize_internal
-   */
-  i = 0;
-  while (i < workspace->screen->n_xinerama_infos)
-    {
-      workspace->work_areas[i] = workspace->all_work_areas;
-      ++i;
-    }
   
   workspace->work_areas_invalid = FALSE;
 
Index: workspace.h
===================================================================
RCS file: /cvs/gnome/metacity/src/workspace.h,v
retrieving revision 1.15
diff -p -u -r1.15 workspace.h
--- workspace.h	30 May 2003 20:24:00 -0000	1.15
+++ workspace.h	7 Jun 2003 21:24:14 -0000
@@ -42,8 +42,11 @@ struct _MetaWorkspace
   GList *windows;
 
   MetaRectangle all_work_areas;
-  
   MetaRectangle *work_areas;
+  GSList *left_struts;
+  GSList *right_struts;
+  GSList *top_struts;
+  GSList *bottom_struts;
   guint work_areas_invalid : 1;
 };
 
Index: tools/metacity-window-demo.c
===================================================================
RCS file: /cvs/gnome/metacity/src/tools/metacity-window-demo.c,v
retrieving revision 1.14
diff -p -u -r1.14 metacity-window-demo.c
--- tools/metacity-window-demo.c	18 Oct 2002 06:05:09 -0000	1.14
+++ tools/metacity-window-demo.c	7 Jun 2003 21:24:15 -0000
@@ -33,19 +33,27 @@ set_gdk_window_struts (GdkWindow *window
                        int        top,
                        int        bottom)
 {
-  long vals[4];
+  long vals[12];
   
   vals[0] = left;
   vals[1] = right;
   vals[2] = top;
   vals[3] = bottom;
-  
+  vals[4] = 200;
+  vals[5] = 600;
+  vals[6] = 200;
+  vals[7] = 600;
+  vals[8] = 200;
+  vals[9] = 800;
+  vals[10] = 200;
+  vals[11] = 800;
+
   XChangeProperty (GDK_WINDOW_XDISPLAY (window),
                    GDK_WINDOW_XWINDOW (window),
                    XInternAtom (GDK_WINDOW_XDISPLAY (window),
-                                "_NET_WM_STRUT", False),
+                                "_NET_WM_STRUT_PARTIAL", False),
                    XA_CARDINAL, 32, PropModeReplace,
-                   (guchar *)vals, 4);
+                   (guchar *)vals, 12);
 }
 
 static void
@@ -583,26 +591,26 @@ make_dock (int type)
   switch (type)
     {
     case DOCK_LEFT:
-      gtk_widget_set_size_request (window, DOCK_SIZE, gdk_screen_height ());
-      gtk_window_move (GTK_WINDOW (window), 0, 0);
+      gtk_widget_set_size_request (window, DOCK_SIZE, 400);
+      gtk_window_move (GTK_WINDOW (window), 0, 200);
       set_gtk_window_struts (window, DOCK_SIZE, 0, 0, 0);
       gtk_window_set_title (GTK_WINDOW (window), "LeftDock");
       break;
     case DOCK_RIGHT:      
-      gtk_widget_set_size_request (window, DOCK_SIZE, gdk_screen_height ());
-      gtk_window_move (GTK_WINDOW (window), gdk_screen_width () - DOCK_SIZE, 0);
+      gtk_widget_set_size_request (window, DOCK_SIZE, 400);
+      gtk_window_move (GTK_WINDOW (window), gdk_screen_width () - DOCK_SIZE, 200);
       set_gtk_window_struts (window, 0, DOCK_SIZE, 0, 0);
       gtk_window_set_title (GTK_WINDOW (window), "RightDock");
       break;
     case DOCK_TOP:
-      gtk_widget_set_size_request (window, gdk_screen_width (), DOCK_SIZE);
-      gtk_window_move (GTK_WINDOW (window), 0, 0);
+      gtk_widget_set_size_request (window, 600, DOCK_SIZE);
+      gtk_window_move (GTK_WINDOW (window), 200, 0);
       set_gtk_window_struts (window, 0, 0, DOCK_SIZE, 0);
       gtk_window_set_title (GTK_WINDOW (window), "TopDock");
       break;
     case DOCK_BOTTOM:
-      gtk_widget_set_size_request (window, gdk_screen_width (), DOCK_SIZE);
-      gtk_window_move (GTK_WINDOW (window), 0, gdk_screen_height () - DOCK_SIZE);
+      gtk_widget_set_size_request (window, 600, DOCK_SIZE);
+      gtk_window_move (GTK_WINDOW (window), 200, gdk_screen_height () - DOCK_SIZE);
       set_gtk_window_struts (window, 0, 0, 0, DOCK_SIZE);
       gtk_window_set_title (GTK_WINDOW (window), "BottomDock");
       break;
