Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/metacity/ChangeLog,v
retrieving revision 1.624
diff -u -p -u -r1.624 ChangeLog
--- ChangeLog	23 Feb 2003 05:18:31 -0000	1.624
+++ ChangeLog	23 Feb 2003 17:08:05 -0000
@@ -1,3 +1,34 @@
+2003-02-23  Havoc Pennington  <hp@pobox.com>
+
+	Patch from Rob Adams addresses #95014 (placement issues), 
+	makes first fit algorithm "center tile", adds most code 
+	for per-xinerama workspaces (#86682) but disables it for now.
+	
+	* src/workspace.c (meta_workspace_get_work_area_for_xinerama)
+	(meta_workspace_get_work_area_all_xineramas): new xinerama
+	functions, maintain workspace->work_areas with a different 
+	work area for each xinerama. However for now all the work 
+	areas are the same, because haven't quite figured out how 
+	_NET_WM_STRUT is supposed to work
+
+	* src/window.c: adapt to new meta_window_* xinerama APIs
+	(meta_window_get_work_area_current_xinerama): new xinerama 
+	API
+	(meta_window_get_work_area_for_xinerama): new xinerama API
+	(constrain_position): be a bit more clever about which xinerama's
+	work area we choose to use.
+
+	* src/stack.c: adapt to new Xinerama API
+
+	* src/screen.c (reload_xinerama_infos): invalidate all work areas
+	(meta_screen_get_xinerama_for_rect): new function
+	(meta_screen_window_intersects_xinerama): new function
+
+	* src/place.c (find_first_fit): change to use 
+	"center tiling" (center a screen full of tiled windows, 
+	rather than aligning them top left). Adapt to new 
+	xinerama functions.
+
 2003-02-22  Rob Adams <robadams@ucla.edu>
 
 	* src/metacity.schemas.in: change toggle_maximized to
Index: src/place.c
===================================================================
RCS file: /cvs/gnome/metacity/src/place.c,v
retrieving revision 1.29
diff -u -p -u -r1.29 place.c
--- src/place.c	2 Oct 2002 02:42:24 -0000	1.29
+++ src/place.c	23 Feb 2003 17:08:05 -0000
@@ -2,6 +2,8 @@
 
 /* 
  * Copyright (C) 2001 Havoc Pennington
+ * Copyright (C) 2002, 2003 Red Hat, Inc.
+ * Copyright (C) 2003 Rob Adams
  * 
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -120,13 +122,13 @@ find_next_cascade (MetaWindow *window,
    * cascade_x, cascade_y are the target position
    * of NW corner of window frame.
    */
-  
-  /* FIXME this is bogus because we get the current xinerama
-   * for the window based on its position, but we haven't
-   * placed it yet.
+
+  /* FIXME should use xinerama with mouse pointer
+   * (or better, xinerama where window was launched
+   * determined via startup notification)
    */
-  meta_window_get_work_area (window, TRUE, &work_area);
-  
+  meta_window_get_work_area_for_xinerama (window, 0, &work_area);
+
   cascade_x = MAX (0, work_area.x);
   cascade_y = MAX (0, work_area.y);
   
@@ -363,14 +365,36 @@ topmost_cmp (gconstpointer a, gconstpoin
     return 0;
 }
 
+static void
+center_tile_rect_in_area (MetaRectangle *rect,
+                          MetaRectangle *work_area)
+{
+  int fluff;
+
+  /* The point here is to tile a window such that "extra"
+   * space is equal on either side (i.e. so a full screen
+   * of windows tiled this way would center the windows
+   * as a group)
+   */
+  
+  fluff = (work_area->width % rect->width) / 2;
+  rect->x = work_area->x + fluff;
+  fluff = (work_area->height % rect->height) / 3;
+  rect->y = work_area->y + fluff;
+}
+
 static gboolean
-fit_rect_in_xinerama (MetaScreen    *screen,
+fit_rect_in_xinerama (MetaWindow    *window,
                       MetaRectangle *rect)
 {
   int i;
   int best_index;
   int best_overlap;
+  MetaScreen *screen;
+  MetaRectangle work_area;
   const MetaXineramaScreenInfo *xsi;
+
+  screen = window->screen;
   
   /* Find xinerama with best fit, then
    * shift rect to be entirely within it.
@@ -409,17 +433,17 @@ fit_rect_in_xinerama (MetaScreen    *scr
   /* some overlap had to be better than -1 */
   g_assert (best_index >= 0);
 
-  xsi = &screen->xinerama_infos[best_index];
+  meta_window_get_work_area_for_xinerama (window, best_index, &work_area);
   
-  if (rect->x < xsi->x_origin)
-    rect->x = xsi->x_origin;
-  if (rect->y < xsi->y_origin)
-    rect->y = xsi->y_origin;
-
-  /* Now return whether we are entirely within the xinerama screen */
-  return
-    ((rect->x + rect->width) < (xsi->x_origin + xsi->width)) &&
-    ((rect->y + rect->height) < (xsi->y_origin + xsi->height));
+  if ((rect->x < work_area.x) || (rect->y < work_area.y) ||
+      (rect->x >= work_area.x + work_area.width) ||
+      (rect->y >= work_area.y + work_area.height))
+    center_tile_rect_in_area (rect, &work_area);
+
+  /* Now return whether we are entirely within the work area */
+  return 
+    ((rect->x + rect->width) < (work_area.x + work_area.width)) &&
+    ((rect->y + rect->height) < (work_area.y + work_area.height));
 }
 
 /* Find the leftmost, then topmost, empty area on the workspace
@@ -446,12 +470,12 @@ find_first_fit (MetaWindow *window,
    * the bottom of each existing window, and then to the right
    * of each existing window, aligned with the left/top of the
    * existing window in each of those cases.
-   */
-  
+   */  
   int retval;
   GList *sorted;
   GList *tmp;
   MetaRectangle rect;
+  MetaRectangle work_area;
   int i;
   
   retval = FALSE;
@@ -466,11 +490,16 @@ find_first_fit (MetaWindow *window,
       rect.height += fgeom->top_height + fgeom->bottom_height;
     }
 
-  /* Try origin of first Xinerama */
-  rect.x = window->screen->xinerama_infos[0].x_origin;
-  rect.y = window->screen->xinerama_infos[0].y_origin;
+  /* Try center-tiling on first xinerama */
+  /* FIXME should use xinerama with mouse pointer
+   * (or better, xinerama where window was launched
+   * determined via startup notification)
+   */
+  meta_window_get_work_area_for_xinerama (window, 0, &work_area);
+
+  center_tile_rect_in_area (&rect, &work_area);
 
-  if (fit_rect_in_xinerama (window->screen, &rect) &&
+  if (fit_rect_in_xinerama (window, &rect) &&
       !rectangle_overlaps_some_window (&rect, windows))
     {
       *new_x = rect.x;
@@ -497,13 +526,13 @@ find_first_fit (MetaWindow *window,
     {
       MetaWindow *w = tmp->data;
       MetaRectangle outer_rect;
-      
-      meta_window_get_outer_rect (w, &outer_rect);
 
+      meta_window_get_outer_rect (w, &outer_rect);
+      
       rect.x = outer_rect.x;
       rect.y = outer_rect.y + outer_rect.height;
       
-      if (fit_rect_in_xinerama (window->screen, &rect) &&
+      if (fit_rect_in_xinerama (window, &rect) &&
           !rectangle_overlaps_some_window (&rect, sorted))
         {
           *new_x = rect.x;
@@ -513,12 +542,12 @@ find_first_fit (MetaWindow *window,
               *new_x += fgeom->left_width;
               *new_y += fgeom->top_height;
             }
-
+          
           retval = TRUE;
-
+          
           goto out;
         }
-      
+
       tmp = tmp->next;
     }
 
@@ -531,13 +560,13 @@ find_first_fit (MetaWindow *window,
     {
       MetaWindow *w = tmp->data;
       MetaRectangle outer_rect;
-      
+     
       meta_window_get_outer_rect (w, &outer_rect);
-
+     
       rect.x = outer_rect.x + outer_rect.width;
       rect.y = outer_rect.y;
-      
-      if (fit_rect_in_xinerama (window->screen, &rect) &&
+     
+      if (fit_rect_in_xinerama (window, &rect) &&
           !rectangle_overlaps_some_window (&rect, sorted))
         {
           *new_x = rect.x;
@@ -547,23 +576,24 @@ find_first_fit (MetaWindow *window,
               *new_x += fgeom->left_width;
               *new_y += fgeom->top_height;
             }
-
+         
           retval = TRUE;
-
+         
           goto out;
-        }      
-      
+        }
+
       tmp = tmp->next;
-    }  
+    }
 
-  /* Origin of each Xinerama screen which isn't the first */
+  /* Try center-tile on each Xinerama screen which isn't the first */
   i = 1;
   while (i < window->screen->n_xinerama_infos)
     {
-      rect.x = window->screen->xinerama_infos[i].x_origin;
-      rect.y = window->screen->xinerama_infos[i].y_origin;
-      
-      if (fit_rect_in_xinerama (window->screen, &rect) &&
+      meta_window_get_work_area_for_xinerama (window, i, &work_area);
+
+      center_tile_rect_in_area (&rect, &work_area);
+
+      if (fit_rect_in_xinerama (window, &rect) &&
           !rectangle_overlaps_some_window (&rect, windows))
         {
           *new_x = rect.x;
@@ -578,6 +608,7 @@ find_first_fit (MetaWindow *window,
           
           goto out;
         }
+      
       ++i;
     }
   
@@ -602,17 +633,18 @@ constrain_placement (MetaWindow        *
   int nw_x, nw_y;
   int offscreen_w, offscreen_h;
   MetaRectangle outer_rect;
-  
+
   meta_window_get_outer_rect (window, &outer_rect);
-  
+
   /* FIXME this is bogus because we get the current xinerama
    * for the window based on its position, but we haven't
    * placed it yet.
    */
-  meta_window_get_work_area (window, TRUE, &work_area);
+  meta_window_get_work_area_current_xinerama (window, &work_area);
 
   nw_x = work_area.x;
   nw_y = work_area.y;
+
   if (window->frame)
     {
       nw_x += fgeom->left_width;
@@ -849,6 +881,7 @@ meta_window_place (MetaWindow        *wi
   constrain_placement (window, fgeom, x, y, &x, &y);
 
  done_no_constraints:
+
   *new_x = x;
   *new_y = y;
 }
@@ -946,13 +979,11 @@ get_vertical_edges (MetaWindow *window,
   edges = g_new (int, n_edges);
 
   /* workspace/screen edges */
-  meta_window_get_work_area (window, FALSE, &work_area);
+  meta_window_get_work_area_current_xinerama (window, &work_area);
 
   edges[i] = work_area.x;
   ++i;
-  edges[i] =
-    work_area.x +
-    work_area.width;
+  edges[i] = work_area.x + work_area.width;
   ++i;
   edges[i] = 0;
   ++i;
@@ -1019,13 +1050,11 @@ get_horizontal_edges (MetaWindow *window
   edges = g_new (int, n_edges);
 
   /* workspace/screen edges */
-  meta_window_get_work_area (window, FALSE, &work_area);
+  meta_window_get_work_area_current_xinerama (window, &work_area);
   
   edges[i] = work_area.y;
   ++i;
-  edges[i] =
-    work_area.y +
-    work_area.height;
+  edges[i] = work_area.y + work_area.height;
   ++i;
   edges[i] = 0;
   ++i;
Index: src/screen.c
===================================================================
RCS file: /cvs/gnome/metacity/src/screen.c,v
retrieving revision 1.102
diff -u -p -u -r1.102 screen.c
--- src/screen.c	14 Feb 2003 07:03:46 -0000	1.102
+++ src/screen.c	23 Feb 2003 17:08:05 -0000
@@ -5,6 +5,7 @@
  * Copyright (C) 2002, 2003 Red Hat Inc.
  * Some ICCCM manager selection code derived from fvwm2,
  * Copyright (C) 2001 Dominik Vogt, Matthias Clasen, and fvwm2 team
+ * Copyright (C) 2003 Rob Adams
  * 
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -352,6 +353,20 @@ reload_xinerama_infos (MetaScreen *scree
 
   g_assert (screen->n_xinerama_infos > 0);
   g_assert (screen->xinerama_infos != NULL);
+
+  {
+    GList *tmp;
+
+    tmp = screen->workspaces;
+    while (tmp != NULL)
+      {
+        MetaWorkspace *space = tmp->data;
+
+        meta_workspace_invalidate_work_area (space);
+        
+        tmp = tmp->next;
+      }
+  }
 }
 
 MetaScreen*
@@ -1283,18 +1298,15 @@ meta_screen_focus_default_window (MetaSc
 }
 
 const MetaXineramaScreenInfo*
-meta_screen_get_xinerama_for_window (MetaScreen *screen,
-				     MetaWindow *window)
+meta_screen_get_xinerama_for_rect (MetaScreen    *screen,
+				   MetaRectangle *rect)
 {
   int i;
   int best_xinerama, xinerama_score;
-  MetaRectangle window_rect;
 
   if (screen->n_xinerama_infos == 1)
     return &screen->xinerama_infos[0];
-  
-  meta_window_get_outer_rect (window, &window_rect);
-  
+
   best_xinerama = 0;
   xinerama_score = 0;
 
@@ -1308,7 +1320,7 @@ meta_screen_get_xinerama_for_window (Met
       screen_info.width = screen->xinerama_infos[i].width;
       screen_info.height = screen->xinerama_infos[i].height;
       
-      if (meta_rectangle_intersect (&screen_info, &window_rect, &dest))
+      if (meta_rectangle_intersect (&screen_info, rect, &dest))
         {
           if (dest.width * dest.height > xinerama_score)
             {
@@ -1316,7 +1328,7 @@ meta_screen_get_xinerama_for_window (Met
               best_xinerama = i;
             }
         }
-
+      
       ++i;
     }
 
@@ -1324,11 +1336,43 @@ meta_screen_get_xinerama_for_window (Met
 }
 
 const MetaXineramaScreenInfo*
+meta_screen_get_xinerama_for_window (MetaScreen *screen,
+				     MetaWindow *window)
+{
+  MetaRectangle window_rect;
+  
+  meta_window_get_outer_rect (window, &window_rect);
+
+  return meta_screen_get_xinerama_for_rect (screen, &window_rect);
+}
+
+gboolean
+meta_screen_window_intersects_xinerama (MetaScreen *screen,
+                                        MetaWindow *window,
+                                        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))
+    return TRUE;
+
+  return FALSE;
+}
+
+const MetaXineramaScreenInfo*
 meta_screen_get_current_xinerama (MetaScreen *screen)
 {
   if (screen->n_xinerama_infos == 1)
     return &screen->xinerama_infos[0];
-
+  
   /* Sadly, we have to do it this way. Yuck.
    */
   
@@ -1357,9 +1401,11 @@ meta_screen_get_current_xinerama (MetaSc
       while (i < screen->n_xinerama_infos)
         {
           if ((root_x_return >= screen->xinerama_infos[i].x_origin &&
-               root_x_return < (screen->xinerama_infos[i].x_origin + screen->xinerama_infos[i].width) &&
+               root_x_return < (screen->xinerama_infos[i].x_origin + 
+                                screen->xinerama_infos[i].width) &&
                root_y_return >= screen->xinerama_infos[i].y_origin &&
-               root_y_return < (screen->xinerama_infos[i].y_origin + screen->xinerama_infos[i].height)))
+               root_y_return < (screen->xinerama_infos[i].y_origin + 
+                                screen->xinerama_infos[i].height)))
           {
             screen->last_xinerama_index = i;
             break;
@@ -1594,7 +1640,7 @@ set_work_area_hint (MetaScreen *screen)
 
       if (workspace->screen == screen)
         {
-          meta_workspace_get_work_area (workspace, &area);
+          meta_workspace_get_work_area_all_xineramas (workspace, &area);
           tmp[0] = area.x;
           tmp[1] = area.y;
           tmp[2] = area.width;
Index: src/screen.h
===================================================================
RCS file: /cvs/gnome/metacity/src/screen.h,v
retrieving revision 1.46
diff -u -p -u -r1.46 screen.h
--- src/screen.h	28 Jan 2003 15:07:43 -0000	1.46
+++ src/screen.h	23 Feb 2003 17:08:05 -0000
@@ -133,9 +133,17 @@ void          meta_screen_focus_mouse_wi
 void          meta_screen_focus_default_window (MetaScreen                 *screen,
                                                 MetaWindow                 *not_this_one);
 
-const MetaXineramaScreenInfo* meta_screen_get_current_xinerama (MetaScreen *screen);
-const MetaXineramaScreenInfo* meta_screen_get_xinerama_for_window (MetaScreen *screen,
-								   MetaWindow *window);
+
+const MetaXineramaScreenInfo* meta_screen_get_current_xinerama    (MetaScreen    *screen);
+const MetaXineramaScreenInfo* meta_screen_get_xinerama_for_rect   (MetaScreen    *screen,
+                                                                   MetaRectangle *rect);
+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);
 
 void          meta_screen_update_workspace_layout (MetaScreen             *screen);
 void          meta_screen_update_workspace_names  (MetaScreen             *screen);
Index: src/stack.c
===================================================================
RCS file: /cvs/gnome/metacity/src/stack.c,v
retrieving revision 1.62
diff -u -p -u -r1.62 stack.c
--- src/stack.c	21 Feb 2003 17:51:48 -0000	1.62
+++ src/stack.c	23 Feb 2003 17:08:06 -0000
@@ -2,7 +2,7 @@
 
 /* 
  * Copyright (C) 2001 Havoc Pennington
- * Copyright (C) 2002 Red Hat, Inc.
+ * Copyright (C) 2002, 2003 Red Hat, Inc.
  * 
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -191,9 +191,9 @@ window_is_fullscreen_size (MetaWindow *w
        */
       MetaRectangle workarea;
       
-      meta_window_get_work_area (window, FALSE, &workarea);
+      meta_window_get_work_area_current_xinerama (window, &workarea);
       if (window->rect.x <= workarea.x &&
-          window->rect.y <= workarea.y) 
+          window->rect.y <= workarea.y)
         return TRUE;
     }
   
@@ -205,7 +205,7 @@ window_is_fullscreen_size (MetaWindow *w
         {
           MetaRectangle workarea;
           
-          meta_window_get_work_area (window, TRUE, &workarea);
+          meta_window_get_work_area_current_xinerama (window, &workarea);
           if (window->rect.x <= workarea.x &&
               window->rect.y <= workarea.y) 
             return TRUE;
Index: src/window.c
===================================================================
RCS file: /cvs/gnome/metacity/src/window.c,v
retrieving revision 1.265
diff -u -p -u -r1.265 window.c
--- src/window.c	23 Feb 2003 04:56:11 -0000	1.265
+++ src/window.c	23 Feb 2003 17:08:07 -0000
@@ -2,7 +2,8 @@
 
 /* 
  * Copyright (C) 2001 Havoc Pennington, Anders Carlsson
- * Copyright (C) 2002 Red Hat, Inc.
+ * Copyright (C) 2002, 2003 Red Hat, Inc.
+ * Copyright (C) 2003 Rob Adams
  * 
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
@@ -668,9 +669,12 @@ meta_window_new (MetaDisplay *display,
     {
       MetaRectangle workarea;
       MetaRectangle outer;
-      
-      meta_window_get_work_area (window, TRUE, &workarea);      
 
+      if (!window->placed)
+        meta_warning ("Metacity issue: using position-based current xinerama prior to placement\n");
+
+      meta_window_get_work_area_current_xinerama (window, &workarea);      
+    
       meta_window_get_outer_rect (window, &outer);
       
       if (outer.width >= workarea.width &&
@@ -2181,7 +2185,7 @@ meta_window_move_resize_internal (MetaWi
   
   /* We don't need it in the idle queue anymore. */
   meta_window_unqueue_move_resize (window);  
-  
+
   {
     int oldx, oldy;
     meta_window_get_position (window, &oldx, &oldy);
@@ -2702,7 +2706,7 @@ meta_window_fill_horizontal (MetaWindow 
   w = window->rect.width;
   h = window->rect.height;
   
-  meta_window_get_work_area (window, TRUE, &work_area);
+  meta_window_get_work_area_current_xinerama (window, &work_area);
   
   x = work_area.x;
   w = work_area.width;
@@ -2730,7 +2734,7 @@ meta_window_fill_vertical (MetaWindow  *
   w = window->rect.width;
   h = window->rect.height;
 
-  meta_window_get_work_area (window, TRUE, &work_area);
+  meta_window_get_work_area_current_xinerama (window, &work_area);
 
   y = work_area.y;
   h = work_area.height;
@@ -5674,7 +5678,7 @@ constrain_size (MetaWindow *window,
     {
       MetaRectangle work_area;
       
-      meta_window_get_work_area (window, TRUE, &work_area);
+      meta_window_get_work_area_current_xinerama (window, &work_area);
       
       fullw = work_area.width;
       fullh = work_area.height;
@@ -5823,9 +5827,15 @@ constrain_position (MetaWindow        *w
     }
   else if (window->maximized)
     {
+      const MetaXineramaScreenInfo* xsi;
       MetaRectangle work_area;
-      
-      meta_window_get_work_area (window, TRUE, &work_area);
+
+      xsi = meta_screen_get_xinerama_for_rect (window->screen, 
+					       &window->saved_rect);
+
+      meta_window_get_work_area_for_xinerama (window, 
+					      xsi->number, 
+					      &work_area);
       
       x = work_area.x;
       y = work_area.y;
@@ -5848,8 +5858,25 @@ constrain_position (MetaWindow        *w
       int se_x, se_y;
       int offscreen_w, offscreen_h;
       MetaRectangle work_area;
+      MetaRectangle window_area;
+      const MetaXineramaScreenInfo* xsi;
+
+      /* this is the rect for the window if it were where we're moving
+       * it now
+       */
+      meta_window_get_outer_rect (window, &window_area);
+      window_area.x = x;
+      window_area.y = y;
+      if (fgeom)
+	{
+	  window_area.x -= fgeom->left_width;
+	  window_area.y -= fgeom->top_height;
+	}
       
-      meta_window_get_work_area (window, FALSE, &work_area);
+      xsi = meta_screen_get_xinerama_for_rect (window->screen, &window_area);
+      meta_window_get_work_area_for_xinerama (window, 
+					      xsi->number, 
+					      &work_area);
       
       /* (FIXME instead of TITLEBAR_LENGTH_ONSCREEN, get the actual
        * size of the menu control?).
@@ -5936,7 +5963,7 @@ constrain_position (MetaWindow        *w
           nw_y = se_y;
           se_y = tmp;
         }
-      
+
       /* Clamp window to the given positions.
        * Do the SE clamp first, so that the NW clamp has precedence
        * and we don't tend to lose the titlebar for too-large
@@ -5951,7 +5978,7 @@ constrain_position (MetaWindow        *w
         x = nw_x;
       if (y < nw_y)
         y = nw_y;
-      
+
 #undef TITLEBAR_LENGTH_ONSCREEN
     }
   
@@ -6568,63 +6595,87 @@ meta_window_set_gravity (MetaWindow *win
   meta_error_trap_pop (window->display, FALSE);
 }
 
-void
-meta_window_get_work_area (MetaWindow    *window,
-                           gboolean       for_current_xinerama,
-                           MetaRectangle *area)
+static void
+get_work_area (MetaWindow    *window,
+               MetaRectangle *area,
+               int            which_xinerama)
 {
   MetaRectangle space_area;
-  GList *tmp;
-  
+  GList *tmp;  
   int left_strut;
   int right_strut;
   int top_strut;
   int bottom_strut;  
-
-  if (for_current_xinerama)
-    {
-      const MetaXineramaScreenInfo *xinerama;
-      
-      xinerama = meta_screen_get_xinerama_for_window (window->screen,
-                                                      window);
-      
-      left_strut = xinerama->x_origin;
-      right_strut = window->screen->width - xinerama->width - xinerama->x_origin;
-      top_strut = xinerama->y_origin;
-      bottom_strut = window->screen->height - xinerama->height - xinerama->y_origin;
-    }
-  else
-    {
-      left_strut = 0;
-      right_strut = 0;
-      top_strut = 0;
-      bottom_strut = 0;
-    }
-      
-  tmp = meta_window_get_workspaces (window);
+  int xinerama_origin_x;
+  int xinerama_origin_y;
+  int xinerama_width;
+  int xinerama_height;
+  
+  g_assert (which_xinerama >= 0);
+
+  xinerama_origin_x = window->screen->xinerama_infos[which_xinerama].x_origin;
+  xinerama_origin_y = window->screen->xinerama_infos[which_xinerama].y_origin;
+  xinerama_width = window->screen->xinerama_infos[which_xinerama].width;
+  xinerama_height = window->screen->xinerama_infos[which_xinerama].height;
+  
+  left_strut = 0;
+  right_strut = 0;
+  top_strut = 0;
+  bottom_strut = 0;
   
+  tmp = meta_window_get_workspaces (window);  
   while (tmp != NULL)
     {
-      meta_workspace_get_work_area (tmp->data, &space_area);
+      meta_workspace_get_work_area_for_xinerama (tmp->data,
+                                                 which_xinerama,
+                                                 &space_area);
 
-      left_strut = MAX (left_strut, space_area.x);
+      left_strut = MAX (left_strut, space_area.x - xinerama_origin_x);
       right_strut = MAX (right_strut,
-                         (window->screen->width - space_area.x - space_area.width));
-      top_strut = MAX (top_strut, space_area.y);
+			 (xinerama_width - 
+			  (space_area.x - xinerama_origin_x) - 
+			  space_area.width));
+      top_strut = MAX (top_strut, space_area.y - xinerama_origin_y);
       bottom_strut = MAX (bottom_strut,
-                          (window->screen->height - space_area.y - space_area.height));      
-      
+			  (xinerama_height - 
+			   (space_area.y - xinerama_origin_y) - 
+			   space_area.height));      
       tmp = tmp->next;
     }
   
-  area->x = left_strut;
-  area->y = top_strut;
-  area->width = window->screen->width - left_strut - right_strut;
-  area->height = window->screen->height - top_strut - bottom_strut;
+  area->x = xinerama_origin_x + left_strut;
+  area->y = xinerama_origin_y + top_strut;
+  area->width = xinerama_width - left_strut - right_strut;
+  area->height = xinerama_height - top_strut - bottom_strut;
 
   meta_topic (META_DEBUG_WORKAREA,
               "Window %s has work area %d,%d %d x %d\n",
               window->desc, area->x, area->y, area->width, area->height);
+}
+
+void
+meta_window_get_work_area_current_xinerama (MetaWindow    *window,
+					    MetaRectangle *area)
+{
+  const MetaXineramaScreenInfo *xinerama = NULL;
+  xinerama = meta_screen_get_xinerama_for_window (window->screen,
+						  window);
+
+  meta_window_get_work_area_for_xinerama (window,
+                                          xinerama->number,
+                                          area);
+}
+
+void
+meta_window_get_work_area_for_xinerama (MetaWindow    *window,
+					int            which_xinerama,
+					MetaRectangle *area)
+{
+  g_return_if_fail (which_xinerama >= 0);
+  
+  get_work_area (window,
+                 area,
+                 which_xinerama);
 }
 
 gboolean
Index: src/window.h
===================================================================
RCS file: /cvs/gnome/metacity/src/window.h,v
retrieving revision 1.82
diff -u -p -u -r1.82 window.h
--- src/window.h	5 Jan 2003 07:51:02 -0000	1.82
+++ src/window.h	23 Feb 2003 17:08:07 -0000
@@ -413,10 +413,12 @@ void meta_window_handle_mouse_grab_op_ev
 gboolean meta_window_visible_on_workspace (MetaWindow    *window,
                                            MetaWorkspace *workspace);
 
-/* Get minimum work area for all workspaces we're on */
-void meta_window_get_work_area (MetaWindow    *window,
-                                gboolean       for_current_xinerama,
-                                MetaRectangle *area);
+void meta_window_get_work_area_current_xinerama (MetaWindow    *window,
+                                                 MetaRectangle *area);
+void meta_window_get_work_area_for_xinerama     (MetaWindow    *window,
+                                                 int            which_xinerama,
+                                                 MetaRectangle *area);
+
 
 gboolean meta_window_same_application (MetaWindow *window,
                                        MetaWindow *other_window);
Index: src/workspace.c
===================================================================
RCS file: /cvs/gnome/metacity/src/workspace.c,v
retrieving revision 1.41
diff -u -p -u -r1.41 workspace.c
--- src/workspace.c	22 Jan 2003 04:54:04 -0000	1.41
+++ src/workspace.c	23 Feb 2003 17:08:07 -0000
@@ -42,11 +42,12 @@ meta_workspace_new (MetaScreen *screen)
     g_list_append (workspace->screen->workspaces, workspace);
   workspace->windows = NULL;
 
-  workspace->work_area.x = 0;
-  workspace->work_area.y = 0;
-  workspace->work_area.width = screen->width;
-  workspace->work_area.height = screen->height;
-  workspace->work_area_invalid = TRUE;
+  workspace->work_areas = NULL;
+  workspace->work_areas_invalid = TRUE;
+  workspace->all_work_areas.x = 0;
+  workspace->all_work_areas.y = 0;
+  workspace->all_work_areas.width = 0;
+  workspace->all_work_areas.height = 0;
   
   return workspace;
 }
@@ -84,6 +85,7 @@ meta_workspace_free (MetaWorkspace *work
   workspace->screen->workspaces =
     g_list_remove (workspace->screen->workspaces, workspace);
   
+  g_free (workspace->work_areas);
   g_free (workspace);
 
   /* don't bother to reset names, pagers can just ignore
@@ -304,7 +306,7 @@ meta_workspace_invalidate_work_area (Met
   GList *tmp;
   GList *windows;
   
-  if (workspace->work_area_invalid)
+  if (workspace->work_areas_invalid)
     {
       meta_topic (META_DEBUG_WORKAREA,
                   "Work area for workspace %d is already invalid\n",
@@ -315,8 +317,11 @@ meta_workspace_invalidate_work_area (Met
   meta_topic (META_DEBUG_WORKAREA,
               "Invalidating work area for workspace %d\n",
               meta_workspace_index (workspace));
+
+  g_free (workspace->work_areas);
+  workspace->work_areas = NULL;
   
-  workspace->work_area_invalid = TRUE;
+  workspace->work_areas_invalid = TRUE;
 
   /* redo the size/position constraints on all windows */
   windows = meta_workspace_list_windows (workspace);
@@ -335,81 +340,201 @@ meta_workspace_invalidate_work_area (Met
   meta_screen_queue_workarea_recalc (workspace->screen);
 }
 
-void
-meta_workspace_get_work_area (MetaWorkspace *workspace,
-                              MetaRectangle *area)
-{  
-  if (workspace->work_area_invalid)
-    {
-      int left_strut = 0;
-      int right_strut = 0;
-      int top_strut = 0;
-      int bottom_strut = 0;
-      GList *tmp;
-      GList *windows;
+static void
+ensure_work_areas_validated (MetaWorkspace *workspace)
+{
+  int left_strut = 0;
+  int right_strut = 0;
+  int top_strut = 0;
+  int bottom_strut = 0;
+  int all_left_strut = 0;
+  int all_right_strut = 0;
+  int all_top_strut = 0;
+  int all_bottom_strut = 0;
+  int i;
+  GList *tmp;
+  GList *windows;
+
+  if (!workspace->work_areas_invalid)
+    return;
+      
+  windows = meta_workspace_list_windows (workspace);
+
+  g_free (workspace->work_areas);
+  workspace->work_areas = g_new (MetaRectangle,
+                                 workspace->screen->n_xinerama_infos);
+      
+  i = 0;
+  while (i < workspace->screen->n_xinerama_infos)
+    {
+      left_strut = 0;
+      right_strut = 0;
+      top_strut = 0;
+      bottom_strut = 0;
 
-      windows = meta_workspace_list_windows (workspace);
       tmp = windows;
       while (tmp != NULL)
         {
           MetaWindow *w = tmp->data;
 
-          if (w->has_struts)
+          if (w->has_struts && 
+              (meta_screen_window_intersects_xinerama (w->screen, w, i)))
             {
               meta_topic (META_DEBUG_WORKAREA,
-                          "Merging win %s with %d %d %d %d with %d %d %d %d\n",
+                          "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,
-                          left_strut, right_strut, top_strut, bottom_strut);
-              left_strut = MAX (left_strut, w->left_strut);
+                          w->left_strut, w->right_strut, 
+                          w->top_strut, w->bottom_strut,
+                          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);
-              top_strut = MAX (top_strut, w->top_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);
             }
           
           tmp = tmp->next;
         }
 
-      g_list_free (windows);
-
       /* Some paranoid robustness */
 #define MIN_SANE_AREA 100
       
-      if ((left_strut + right_strut) > (workspace->screen->width - MIN_SANE_AREA))
+      if ((left_strut + right_strut) > 
+          (workspace->screen->xinerama_infos[i].width - MIN_SANE_AREA))
         {
           meta_topic (META_DEBUG_WORKAREA,
-                      "Making left/right struts %d %d sane\n",
-                      left_strut, right_strut);
-          left_strut = (workspace->screen->width - MIN_SANE_AREA) / 2;
+                      "Making left/right struts %d %d sane xinerama %d\n",
+                      left_strut, right_strut, i);
+          left_strut = (workspace->screen->xinerama_infos[i].width - 
+                        MIN_SANE_AREA) / 2;
           right_strut = left_strut;
         }
 
-      if ((top_strut + bottom_strut) > (workspace->screen->height - MIN_SANE_AREA))
+      if ((top_strut + bottom_strut) > 
+          (workspace->screen->xinerama_infos[i].height - MIN_SANE_AREA))
         {
           meta_topic (META_DEBUG_WORKAREA,
-                      "Making top/bottom struts %d %d sane\n",
-                      top_strut, bottom_strut);
-          top_strut = (workspace->screen->height - MIN_SANE_AREA) / 2;
+                      "Making top/bottom struts %d %d sane xinerama %d\n",
+                      top_strut, bottom_strut, i);
+          top_strut = (workspace->screen->xinerama_infos[i].height - 
+                       MIN_SANE_AREA) / 2;
           bottom_strut = top_strut;
         }
-      
-      workspace->work_area.x = left_strut;
-      workspace->work_area.y = top_strut;
-      workspace->work_area.width = workspace->screen->width - left_strut - right_strut;
-      workspace->work_area.height = workspace->screen->height - top_strut - bottom_strut;
 
-      workspace->work_area_invalid = FALSE;
+      /* 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 + 
+        workspace->screen->xinerama_infos[i].y_origin;
+      workspace->work_areas[i].width = 
+        workspace->screen->xinerama_infos[i].width - 
+        left_strut - right_strut;
+      workspace->work_areas[i].height = 
+        workspace->screen->xinerama_infos[i].height - 
+        top_strut - bottom_strut;
 
       meta_topic (META_DEBUG_WORKAREA,
-                  "Computed work area for workspace %d: %d,%d %d x %d\n",
+                  "Computed [unused] work area for workspace %d "
+                  "xinerama %d: %d,%d %d x %d\n",
                   meta_workspace_index (workspace),
-                  workspace->work_area.x,
-                  workspace->work_area.y,
-                  workspace->work_area.width,
-                  workspace->work_area.height);
+                  i,
+                  workspace->work_areas[i].x,
+                  workspace->work_areas[i].y,
+                  workspace->work_areas[i].width,
+                  workspace->work_areas[i].height);
+
+      ++i;
     }
 
-  *area = workspace->work_area;
+  g_list_free (windows);
+
+  if ((all_left_strut + all_right_strut) > 
+      (workspace->screen->width - MIN_SANE_AREA))
+    {
+      meta_topic (META_DEBUG_WORKAREA,
+                  "Making screen-wide left/right struts %d %d sane\n",
+                  all_left_strut, all_right_strut);
+      all_left_strut = (workspace->screen->width - MIN_SANE_AREA) / 2;
+      all_right_strut = all_left_strut;
+    }
+      
+  if ((all_top_strut + all_bottom_strut) > 
+      (workspace->screen->height - MIN_SANE_AREA))
+    {
+      meta_topic (META_DEBUG_WORKAREA,
+                  "Making top/bottom struts %d %d sane\n",
+                  all_top_strut, all_bottom_strut);
+      all_top_strut = (workspace->screen->height - MIN_SANE_AREA) / 2;
+      all_bottom_strut = all_top_strut;
+    }
+      
+  workspace->all_work_areas.x = all_left_strut;
+  workspace->all_work_areas.y = all_top_strut;
+  workspace->all_work_areas.width = 
+    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;
+
+  meta_topic (META_DEBUG_WORKAREA,
+              "Computed work area for workspace %d: %d,%d %d x %d\n",
+              meta_workspace_index (workspace),
+              workspace->all_work_areas.x,
+              workspace->all_work_areas.y,
+              workspace->all_work_areas.width,
+              workspace->all_work_areas.height);    
+}
+
+void
+meta_workspace_get_work_area_for_xinerama (MetaWorkspace *workspace,
+                                           int            which_xinerama,
+                                           MetaRectangle *area)
+{
+  g_assert (which_xinerama >= 0);
+
+  ensure_work_areas_validated (workspace);
+  g_assert (which_xinerama < workspace->screen->n_xinerama_infos);
+  
+  *area = workspace->work_areas[which_xinerama];
+}
+
+void
+meta_workspace_get_work_area_all_xineramas (MetaWorkspace *workspace,
+                                            MetaRectangle *area)
+{
+  ensure_work_areas_validated (workspace);
+  
+  *area = workspace->all_work_areas;
 }
 
 #ifdef WITH_VERBOSE_MODE
Index: src/workspace.h
===================================================================
RCS file: /cvs/gnome/metacity/src/workspace.h,v
retrieving revision 1.13
diff -u -p -u -r1.13 workspace.h
--- src/workspace.h	3 Nov 2002 19:06:39 -0000	1.13
+++ src/workspace.h	23 Feb 2003 17:08:07 -0000
@@ -40,9 +40,11 @@ struct _MetaWorkspace
   MetaScreen *screen;
   
   GList *windows;
+
+  MetaRectangle all_work_areas;
   
-  MetaRectangle work_area;
-  guint work_area_invalid : 1;
+  MetaRectangle *work_areas;
+  guint work_areas_invalid : 1;
 };
 
 MetaWorkspace* meta_workspace_new           (MetaScreen    *screen);
@@ -61,8 +63,16 @@ int            meta_workspace_index     
 GList*         meta_workspace_list_windows  (MetaWorkspace *workspace);
 
 void meta_workspace_invalidate_work_area (MetaWorkspace *workspace);
-void meta_workspace_get_work_area        (MetaWorkspace *workspace,
-                                          MetaRectangle *area);
+
+
+void meta_workspace_get_work_area_for_xinerama  (MetaWorkspace *workspace,
+                                                 int            which_xinerama,
+                                                 MetaRectangle *area);
+void meta_workspace_get_work_area_all_xineramas (MetaWorkspace *workspace,
+                                                 MetaRectangle *area);
+
+
+
 
 
 MetaWorkspace* meta_workspace_get_neighbor (MetaWorkspace      *workspace,
