Index: src/display.c
===================================================================
--- src/display.c	(revision 3081)
+++ src/display.c	(working copy)
@@ -333,7 +333,8 @@ meta_display_open (void)
     "_NET_DESKTOP_VIEWPORT",
     "_METACITY_VERSION",
     "_NET_WM_VISIBLE_NAME",
-    "_NET_WM_VISIBLE_ICON_NAME"
+    "_NET_WM_VISIBLE_ICON_NAME",
+    "VMWARE_FULLSCREEN_MONITORS"
   };
   Atom atoms[G_N_ELEMENTS(atom_names)];
   
@@ -492,6 +493,7 @@ meta_display_open (void)
   display->atom_metacity_version = atoms[91];
   display->atom_net_wm_visible_name = atoms[92];
   display->atom_net_wm_visible_icon_name = atoms[93];
+  display->atom_vmware_fullscreen_monitors = atoms[94];
 
   display->prop_hooks = NULL;
   meta_display_init_window_prop_hooks (display);
Index: src/display.h
===================================================================
--- src/display.h	(revision 3081)
+++ src/display.h	(working copy)
@@ -180,6 +180,7 @@ struct _MetaDisplay
   Atom atom_metacity_version;
   Atom atom_net_wm_visible_name;
   Atom atom_net_wm_visible_icon_name;
+  Atom atom_vmware_fullscreen_monitors;
 
   /* This is the actual window from focus events,
    * not the one we last set
Index: src/screen.c
===================================================================
--- src/screen.c	(revision 3081)
+++ src/screen.c	(working copy)
@@ -89,7 +89,7 @@ set_wm_check_hint (MetaScreen *screen)
 static int
 set_supported_hint (MetaScreen *screen)
 {
-#define N_SUPPORTED 58
+#define N_SUPPORTED 59
   Atom atoms[N_SUPPORTED];
   
   atoms[0] = screen->display->atom_net_wm_name;
@@ -150,8 +150,9 @@ set_supported_hint (MetaScreen *screen)
   atoms[55] = screen->display->atom_net_wm_state_demands_attention;
   atoms[56] = screen->display->atom_net_desktop_geometry;
   atoms[57] = screen->display->atom_net_desktop_viewport;
-  //atoms[58] = screen->display->atom_net_restack_window;
-  //atoms[59] = screen->display->atom_net_moveresize_window;
+  atoms[58] = screen->display->atom_vmware_fullscreen_monitors;
+  //atoms[59] = screen->display->atom_net_restack_window;
+  //atoms[60] = screen->display->atom_net_moveresize_window;
   
   XChangeProperty (screen->display->xdisplay, screen->xroot,
                    screen->display->atom_net_supported,
Index: src/constraints.c
===================================================================
--- src/constraints.c	(revision 3081)
+++ src/constraints.c	(working copy)
@@ -752,7 +752,12 @@ constrain_fullscreen (MetaWindow        
   /* Determine whether constraint applies; exit if it doesn't */
   if (!window->fullscreen)
     return TRUE;
-  xinerama = info->entire_xinerama;
+
+  if (window->fullscreen_rect.width)
+    xinerama = window->fullscreen_rect;
+  else
+    xinerama = info->entire_xinerama;
+
   get_size_limits (window, info->fgeom, FALSE, &min_size, &max_size);
   too_big =   !meta_rectangle_could_fit_rect (&xinerama, &min_size);
   too_small = !meta_rectangle_could_fit_rect (&max_size, &xinerama);
Index: src/window.c
===================================================================
--- src/window.c	(revision 3081)
+++ src/window.c	(working copy)
@@ -424,6 +424,7 @@ meta_window_new_with_attrs (MetaDisplay 
   /* And this is our unmaximized size */
   window->saved_rect = window->rect;
   window->user_rect = window->rect;
+  memset(&window->fullscreen_rect, 0, sizeof (MetaRectangle));
   
   window->depth = attrs->depth;
   window->xvisual = attrs->visual;
@@ -2509,6 +2510,57 @@ meta_window_unmake_fullscreen (MetaWindo
 }
 
 void
+meta_window_update_fullscreen_rect (MetaWindow *window)
+{
+  gulong *monitors = NULL;
+  int nitems;
+
+  /* The fullscreen constraint will take the current xinerama region if
+   * width is 0.  If a list of monitors exists, this gives a starting point
+   * for building the region.
+   */
+  window->fullscreen_rect.width = 0;
+
+  /* This property specifies a list of monitors that the window wishes to be
+   * fullscreened onto.  If more than one monitor is specified, the (bounding
+   * boxed) union of their screen regions is used.
+   */
+  if (meta_prop_get_cardinal_list (window->display,
+                                   window->xwindow,
+                                   window->display->atom_vmware_fullscreen_monitors,
+                                   &monitors, &nitems) &&
+      nitems > 0)
+    {
+      int i, j;
+      for (i = 0; i < window->screen->n_xinerama_infos; i++) {
+        for (j = 0; j < nitems; j++) {
+          if (monitors[j] == window->screen->xinerama_infos[i].number) {
+            if (window->fullscreen_rect.width == 0)
+              {
+                window->fullscreen_rect = window->screen->xinerama_infos[i].rect;
+              }
+            else
+              {
+                meta_rectangle_union (&window->fullscreen_rect,
+                                      &window->screen->xinerama_infos[i].rect,
+                                      &window->fullscreen_rect);
+              }
+          }
+        }
+      }
+
+      meta_XFree (monitors);
+    }
+
+  if (window->fullscreen)
+    {
+      /* move_resize with new constraints
+       */
+      meta_window_queue_move_resize (window);
+    }
+}
+
+void
 meta_window_shade (MetaWindow  *window,
                    guint32      timestamp)
 {
@@ -5234,6 +5286,10 @@ process_property_notify (MetaWindow     
       meta_window_reload_property (window,
                                    window->display->atom_net_wm_user_time);
     }
+  else if (event->atom == window->display->atom_vmware_fullscreen_monitors)
+    {
+      meta_window_update_fullscreen_rect (window);
+    }
 
   return TRUE;
 }
Index: src/window.h
===================================================================
--- src/window.h	(revision 3081)
+++ src/window.h	(working copy)
@@ -136,6 +136,12 @@ struct _MetaWindow
 
   /* Whether we're fullscreen */
   guint fullscreen : 1;
+
+  /* Area to cover when in fullscreen mode.  If VMWARE_FULLSCREEN_MONITORS
+   * exists on the window, this is a union of those monitors.  If not, this
+   * is the single monitor which the window's origin is on.
+   */
+  MetaRectangle fullscreen_rect;
   
   /* Whether we're trying to constrain the window to be fully onscreen */
   guint require_fully_onscreen : 1;
@@ -418,6 +424,7 @@ void        meta_window_activate_with_wo
 void        meta_window_make_fullscreen_internal (MetaWindow    *window);
 void        meta_window_make_fullscreen    (MetaWindow  *window);
 void        meta_window_unmake_fullscreen  (MetaWindow  *window);
+void        meta_window_update_fullscreen_rect (MetaWindow *window);
 
 /* args to move are window pos, not frame pos */
 void        meta_window_move               (MetaWindow  *window,
Index: src/boxes.c
===================================================================
--- src/boxes.c	(revision 3081)
+++ src/boxes.c	(working copy)
@@ -198,6 +198,34 @@ meta_rectangle_equal (const MetaRectangl
           (src1->height == src2->height));
 }
 
+void
+meta_rectangle_union (MetaRectangle *rect1,
+                      MetaRectangle *rect2,
+                      MetaRectangle *dest)
+{
+  int dest_x, dest_y;
+  int dest_w, dest_h;
+
+  dest_x = rect1->x;
+  dest_y = rect1->y;
+  dest_w = rect1->width;
+  dest_h = rect1->height;
+
+  if (rect2->x < dest_x)
+    dest_x = rect2->x;
+  if (rect2->y < dest_y)
+    dest_y = rect2->y;
+  if (rect2->x + rect2->width > dest_x + dest_w)
+    dest_w = rect2->x + rect2->width - dest_x;
+  if (rect2->y + rect2->height > dest_y + dest_h)
+    dest_h = rect2->y + rect2->height - dest_y;
+
+  dest->x = dest_x;
+  dest->y = dest_y;
+  dest->width = dest_w;
+  dest->height = dest_h;
+}
+
 gboolean
 meta_rectangle_overlap (const MetaRectangle *rect1,
                         const MetaRectangle *rect2)
Index: src/boxes.h
===================================================================
--- src/boxes.h	(revision 3081)
+++ src/boxes.h	(working copy)
@@ -96,6 +96,11 @@ gboolean meta_rectangle_intersect       
 gboolean meta_rectangle_equal           (const MetaRectangle *src1,
                                          const MetaRectangle *src2);
 
+/* Find the bounding box of the union of two rectangles */
+void meta_rectangle_union               (MetaRectangle       *rect1,
+                                         MetaRectangle       *rect2,
+                                         MetaRectangle       *dest);
+
 /* overlap is similar to intersect but doesn't provide location of
  * intersection information.
  */
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 3081)
+++ ChangeLog	(working copy)
@@ -1,3 +1,33 @@
+2007-03-03  David Trowbridge  <trowbrds@gmail.com>
+
+	This change adds a new, experimental hint for fullscreen windows to
+	allow them to request that the fullscreen window appear on certain (or
+	multiple) monitors.  This property is a CARDINAL list of screen
+	numbers, which correspond to the screen IDs given to us by the
+	Xinerama extension.
+
+	If more than one monitor is requested, the window manager takes the
+	bounding box of the union of the screen areas.  If this hint is unset
+	and a window requests fullscreen, it will behave exactly as before.
+
+	* src/display.c (meta_display_open): Add atom for fullscreen-monitors
+	hint.
+	* src/display.h: Ditto.
+	* src/boxes.c: Add meta_rectangle_union.
+	* src/boxes.h: Ditto.
+	* src/window.h: Add storage for fullscreen rect.
+	* src/window.c (meta_window_new_with_attrs): Zero out
+	window->fullscreen_rect during initialization.
+	(meta_window_update_fullscreen_rect): Add code to interpret
+	fullscreen-monitors hint by computing the bounding box of the relevant
+	xinerama screens and storing it inside MetaWindow.  This is used
+	during constraint evaluation.
+	(process_property_notify): Call meta_window_update_fullscreen_rect
+	when the fullscreen monitors property has changed on a window.
+	* src/constraints.c (constrain_fullscreen): Use computed fullscreen
+	bounding box if it exists.
+	* src/screen.c (set_supported_hint): Mark the hint as supported.
+
 2007-02-20  Kjartan Maraas  <kmaraas@gnome.org>
 
 	* Makefile.am: Add MAINTAINERS to EXTRA_DIST so others
