Index: src/workspace.c
===================================================================
--- src/workspace.c	(revision 3142)
+++ src/workspace.c	(working copy)
@@ -493,17 +493,10 @@ meta_workspace_invalidate_work_area (Met
 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;
+  GList         *windows;
+  GList         *tmp;
+  MetaRectangle  work_area;
+  int            i;  /* C89 absolutely sucks... */
 
   if (!workspace->work_areas_invalid)
     return;
@@ -513,183 +506,22 @@ ensure_work_areas_validated (MetaWorkspa
   g_assert (workspace->screen_region == NULL);
   g_assert (workspace->screen_edges == NULL);
   g_assert (workspace->xinerama_edges == NULL);
-  
-  windows = meta_workspace_list_windows (workspace);
 
-  g_free (workspace->work_area_xinerama);
-  workspace->work_area_xinerama = g_new (MetaRectangle,
-                                         workspace->screen->n_xinerama_infos);
-      
-  i = 0;
-  while (i < workspace->screen->n_xinerama_infos)
+  /* STEP 1: Get the list of struts */  
+  windows = meta_workspace_list_windows (workspace);
+  for (tmp = windows; tmp != NULL; tmp = tmp->next)
     {
-      left_strut = 0;
-      right_strut = 0;
-      top_strut = 0;
-      bottom_strut = 0;
-
-      tmp = windows;
-      while (tmp != NULL)
-        {
-          MetaWindow *w = tmp->data;
+      MetaWindow *win = tmp->data;
+      GSList *s_iter;
 
-          if (w->struts)
-            {
-              meta_topic (META_DEBUG_WORKAREA,
-                          "Merging win %s with %d %d %d %d "
-                          "with %d %d %d %d\n",
-                          w->desc,
-                          w->struts->left.width, w->struts->right.width, 
-                          w->struts->top.height, w->struts->bottom.height,
-                          left_strut, right_strut, 
-                          top_strut, bottom_strut);
-
-              if ((i == 0) && (w->struts->left.width > 0))
-                {
-                  workspace->all_struts = g_slist_prepend (workspace->all_struts,
-                                                           &w->struts->left);
-                }
-
-              if (meta_rectangle_overlap (&w->screen->xinerama_infos[i].rect,
-                                          &w->struts->left))
-                {
-                  left_strut = MAX (left_strut, 
-                                    w->struts->left.width - 
-                                    workspace->screen->xinerama_infos[i].rect.x);
-                  all_left_strut = MAX (all_left_strut, w->struts->left.width);
-                }
-
-              if ((i == 0) && (w->struts->right.width > 0))
-                {
-                  workspace->all_struts = g_slist_prepend (workspace->all_struts,
-                                                           &w->struts->right);
-                }
-
-              if (meta_rectangle_overlap (&w->screen->xinerama_infos[i].rect,
-                                          &w->struts->right))
-                {
-                  right_strut = MAX (right_strut, w->struts->right.width - 
-                                     workspace->screen->rect.width + 
-                                     workspace->screen->xinerama_infos[i].rect.width +
-                                     workspace->screen->xinerama_infos[i].rect.x);
-                  all_right_strut = MAX (all_right_strut, w->struts->right.width);
-                }
-
-              if ((i == 0) && (w->struts->top.height > 0))
-                {
-                  workspace->all_struts = g_slist_prepend (workspace->all_struts,
-                                                           &w->struts->top);
-                }
-
-              if (meta_rectangle_overlap (&w->screen->xinerama_infos[i].rect,
-                                          &w->struts->top))
-                {
-                  top_strut = MAX (top_strut,
-                                   w->struts->top.height - 
-                                   workspace->screen->xinerama_infos[i].rect.y);
-                  all_top_strut = MAX (all_top_strut, w->struts->top.height);
-                }
-
-              if ((i == 0) && (w->struts->bottom.height > 0))
-                {
-                  workspace->all_struts = g_slist_prepend (workspace->all_struts,
-                                                           &w->struts->bottom);
-                }
-
-              if (meta_rectangle_overlap (&w->screen->xinerama_infos[i].rect,
-                                          &w->struts->bottom))
-                {
-                  bottom_strut = MAX (bottom_strut, w->struts->bottom.height - 
-                                      workspace->screen->rect.height + 
-                                      workspace->screen->xinerama_infos[i].rect.height +
-                                      workspace->screen->xinerama_infos[i].rect.y);
-                  all_bottom_strut = MAX (all_bottom_strut, w->struts->bottom.height);
-                }
-            }
-          
-          tmp = tmp->next;
-        }
-
-      /* Some paranoid robustness */
-#define MIN_SANE_AREA 100
-      
-      if ((left_strut + right_strut) > 
-          (workspace->screen->xinerama_infos[i].rect.width - MIN_SANE_AREA))
-        {
-          meta_topic (META_DEBUG_WORKAREA,
-                      "Making left/right struts %d %d sane xinerama %d\n",
-                      left_strut, right_strut, i);
-          left_strut = (workspace->screen->xinerama_infos[i].rect.width - 
-                        MIN_SANE_AREA) / 2;
-          right_strut = left_strut;
-        }
-
-      if ((top_strut + bottom_strut) > 
-          (workspace->screen->xinerama_infos[i].rect.height - MIN_SANE_AREA))
-        {
-          meta_topic (META_DEBUG_WORKAREA,
-                      "Making top/bottom struts %d %d sane xinerama %d\n",
-                      top_strut, bottom_strut, i);
-          top_strut = (workspace->screen->xinerama_infos[i].rect.height - 
-                       MIN_SANE_AREA) / 2;
-          bottom_strut = top_strut;
-        }
-
-      workspace->work_area_xinerama[i].x = 
-        left_strut + workspace->screen->xinerama_infos[i].rect.x;
-      workspace->work_area_xinerama[i].y = top_strut + 
-        workspace->screen->xinerama_infos[i].rect.y;
-      workspace->work_area_xinerama[i].width = 
-        workspace->screen->xinerama_infos[i].rect.width - 
-        left_strut - right_strut;
-      workspace->work_area_xinerama[i].height = 
-        workspace->screen->xinerama_infos[i].rect.height - 
-        top_strut - bottom_strut;
-
-      meta_topic (META_DEBUG_WORKAREA,
-                  "Computed work area for workspace %d "
-                  "xinerama %d: %d,%d %d x %d\n",
-                  meta_workspace_index (workspace),
-                  i,
-                  workspace->work_area_xinerama[i].x,
-                  workspace->work_area_xinerama[i].y,
-                  workspace->work_area_xinerama[i].width,
-                  workspace->work_area_xinerama[i].height);
-
-      ++i;
+      for (s_iter = win->struts; s_iter != NULL; s_iter = s_iter->next)
+        workspace->all_struts = g_slist_prepend (workspace->all_struts,
+                                                 s_iter->data);
     }
-
   g_list_free (windows);
 
-  if ((all_left_strut + all_right_strut) > 
-      (workspace->screen->rect.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->rect.width - MIN_SANE_AREA) / 2;
-      all_right_strut = all_left_strut;
-    }
-      
-  if ((all_top_strut + all_bottom_strut) > 
-      (workspace->screen->rect.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->rect.height - MIN_SANE_AREA) / 2;
-      all_bottom_strut = all_top_strut;
-    }
-      
-  workspace->work_area_screen.x = all_left_strut;
-  workspace->work_area_screen.y = all_top_strut;
-  workspace->work_area_screen.width = 
-    workspace->screen->rect.width - all_left_strut - all_right_strut;
-  workspace->work_area_screen.height = 
-    workspace->screen->rect.height - all_top_strut - all_bottom_strut;
-
-  /* Now cache the spanning rects for the onscreen and
-   * on-single-xinerama regions
+  /* STEP 2: Get the maximal/spanning rects for the onscreen and
+   *         on-single-xinerama regions
    */  
   g_assert (workspace->xinerama_region == NULL);
   g_assert (workspace->screen_region   == NULL);
@@ -707,13 +539,97 @@ ensure_work_areas_validated (MetaWorkspa
     meta_rectangle_get_minimal_spanning_set_for_region (
       &workspace->screen->rect,
       workspace->all_struts);
-  /* Since get_minimal_spanning_set_for_region() doesn't do the
-   * MIN_SANE_AREA thing, manually account for it.  Note that it's okay if
-   * get_minimal_spanning_set_for_region() returns a very small region--all
-   * we really need here is a 1x1 region that corresponds to somewhere on
-   * the monitor for the partially onscreen constraint.  If we don't get
-   * anything, though, we use work_area_screen just for convenience.
+
+  /* STEP 3: Get the work areas (region-to-maximize-to) for the screen and
+   *         xineramas.
    */
+  work_area = workspace->screen->rect;  /* start with the screen */
+  if (workspace->screen_region == NULL)
+    work_area = meta_rect (0, 0, -1, -1);
+  else
+    meta_rectangle_clip_to_region (workspace->screen_region,
+                                   FIXED_DIRECTION_NONE,
+                                   &work_area);
+
+  /* Lots of paranoia checks, forcing work_area_screen to be sane */
+#define MIN_SANE_AREA 100
+  if (work_area.width < MIN_SANE_AREA)
+    {
+      meta_warning ("struts occupy an unusually large percentage of the screen; "
+                    "available remaining width = %d < %d",
+                    work_area.width, MIN_SANE_AREA);
+      if (work_area.width < 1)
+        {
+          work_area.x = (workspace->screen->rect.width - MIN_SANE_AREA)/2;
+          work_area.width = MIN_SANE_AREA;
+        }
+      else
+        {
+          int amount = (MIN_SANE_AREA - work_area.width)/2;
+          work_area.x     -=   amount;
+          work_area.width += 2*amount;
+        }
+    }
+  if (work_area.height < MIN_SANE_AREA)
+    {
+      meta_warning ("struts occupy an unusually large percentage of the screen; "
+                    "available remaining height = %d < %d",
+                    work_area.height, MIN_SANE_AREA);
+      if (work_area.height < 1)
+        {
+          work_area.y = (workspace->screen->rect.height - MIN_SANE_AREA)/2;
+          work_area.height = MIN_SANE_AREA;
+        }
+      else
+        {
+          int amount = (MIN_SANE_AREA - work_area.height)/2;
+          work_area.y      -=   amount;
+          work_area.height += 2*amount;
+        }
+    }
+  workspace->work_area_screen = work_area;
+  meta_topic (META_DEBUG_WORKAREA,
+              "Computed work area for workspace %d: %d,%d %d x %d\n",
+              meta_workspace_index (workspace),
+              workspace->work_area_screen.x,
+              workspace->work_area_screen.y,
+              workspace->work_area_screen.width,
+              workspace->work_area_screen.height);    
+
+  /* Now find the work areas for each xinerama */
+  g_free (workspace->work_area_xinerama);
+  workspace->work_area_xinerama = g_new (MetaRectangle,
+                                         workspace->screen->n_xinerama_infos);
+
+  for (i = 0; i < workspace->screen->n_xinerama_infos; i++)
+    {
+      work_area = workspace->screen->xinerama_infos[i].rect;
+
+      if (workspace->xinerama_region[i] == NULL)
+        /* FIXME: constraints.c untested with this, but it might be nice for
+         * a screen reader or magnifier.
+         */
+        work_area = meta_rect (work_area.x, work_area.y, -1, -1);
+      else
+        meta_rectangle_clip_to_region (workspace->xinerama_region[i],
+                                       FIXED_DIRECTION_NONE,
+                                       &work_area);
+
+      workspace->work_area_xinerama[i] = work_area;
+      meta_topic (META_DEBUG_WORKAREA,
+                  "Computed work area for workspace %d "
+                  "xinerama %d: %d,%d %d x %d\n",
+                  meta_workspace_index (workspace),
+                  i,
+                  workspace->work_area_xinerama[i].x,
+                  workspace->work_area_xinerama[i].y,
+                  workspace->work_area_xinerama[i].width,
+                  workspace->work_area_xinerama[i].height);
+    }
+
+  /* STEP 4: Make sure the screen_region is nonempty (separate from step 2
+   *         since it relies on step 3).
+   */  
   if (workspace->screen_region == NULL)
     {
       MetaRectangle *nonempty_region;
@@ -722,7 +638,7 @@ ensure_work_areas_validated (MetaWorkspa
       workspace->screen_region = g_list_prepend (NULL, nonempty_region);
     }
 
-  /* Now cache the screen and xinerama edges for edge resistance and snapping */
+  /* STEP 5: Cache screen and xinerama edges for edge resistance and snapping */
   g_assert (workspace->screen_edges    == NULL);
   g_assert (workspace->xinerama_edges  == NULL);
   workspace->screen_edges =
@@ -736,17 +652,8 @@ ensure_work_areas_validated (MetaWorkspa
                                                        workspace->all_struts);
   g_list_free (tmp);
 
-
   /* We're all done, YAAY!  Record that everything has been validated. */
   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->work_area_screen.x,
-              workspace->work_area_screen.y,
-              workspace->work_area_screen.width,
-              workspace->work_area_screen.height);    
 }
 
 void
Index: src/util.c
===================================================================
--- src/util.c	(revision 3142)
+++ src/util.c	(working copy)
@@ -199,6 +199,15 @@ utf8_fputs (const char *str,
   return retval;
 }
 
+void
+meta_free_gslist_and_elements (GSList *list_to_deep_free)
+{
+  g_slist_foreach (list_to_deep_free,
+                   (void (*)(gpointer,gpointer))&g_free, /* ew, for ugly */
+                   NULL);
+  g_slist_free (list_to_deep_free);
+}
+
 #ifdef WITH_VERBOSE_MODE
 void
 meta_debug_spew_real (const char *format, ...)
Index: src/util.h
===================================================================
--- src/util.h	(revision 3142)
+++ src/util.h	(working copy)
@@ -95,6 +95,8 @@ const char* meta_gravity_to_string (int 
 
 char* meta_g_utf8_strndup (const gchar *src, gsize n);
 
+void  meta_free_gslist_and_elements (GSList *list_to_deep_free);
+
 /* To disable verbose mode, we make these functions into no-ops */
 #ifdef WITH_VERBOSE_MODE
 
Index: src/edge-resistance.c
===================================================================
--- src/edge-resistance.c	(revision 3142)
+++ src/edge-resistance.c	(working copy)
@@ -300,9 +300,9 @@ movement_towards_edge (MetaDirection sid
     case META_DIRECTION_RIGHT:
     case META_DIRECTION_BOTTOM:
       return increment > 0;
+    default:
+      g_assert_not_reached ();
     }
-
-  g_assert_not_reached ();
 }
 
 static gboolean
Index: src/testboxes.c
===================================================================
--- src/testboxes.c	(revision 3142)
+++ src/testboxes.c	(working copy)
@@ -58,6 +58,17 @@ new_meta_rect (int x, int y, int width, 
   return temporary;
 }
 
+static MetaStrut*
+new_meta_strut (int x, int y, int width, int height, int side)
+{
+  MetaStrut* temporary;
+  temporary = g_new (MetaStrut, 1);
+  temporary->rect = meta_rect(x, y, width, height);
+  temporary->side = side;
+
+  return temporary;
+}
+
 static MetaEdge*
 new_screen_edge (int x, int y, int width, int height, int side_type)
 {
@@ -228,9 +239,10 @@ free_strut_list (GSList *struts)
 static GSList*
 get_strut_list (int which)
 {
-  GSList *struts;
+  GSList *ans;
+  MetaDirection wc = 0; /* wc == who cares? ;-) */
 
-  struts = NULL;
+  ans = NULL;
 
   g_assert (which >=0 && which <= 6);
   switch (which)
@@ -238,36 +250,36 @@ get_strut_list (int which)
     case 0:
       break;
     case 1:
-      struts = g_slist_prepend (struts, new_meta_rect (   0,    0, 1600,   20));
-      struts = g_slist_prepend (struts, new_meta_rect ( 400, 1160, 1600,   40));
+      ans = g_slist_prepend (ans, new_meta_strut (   0,    0, 1600,   20, wc));
+      ans = g_slist_prepend (ans, new_meta_strut ( 400, 1160, 1600,   40, wc));
       break;
     case 2:
-      struts = g_slist_prepend (struts, new_meta_rect (   0,    0, 1600,   20));
-      struts = g_slist_prepend (struts, new_meta_rect ( 800, 1100,  400,  100));
-      struts = g_slist_prepend (struts, new_meta_rect ( 300, 1150,  150,   50));
+      ans = g_slist_prepend (ans, new_meta_strut (   0,    0, 1600,   20, wc));
+      ans = g_slist_prepend (ans, new_meta_strut ( 800, 1100,  400,  100, wc));
+      ans = g_slist_prepend (ans, new_meta_strut ( 300, 1150,  150,   50, wc));
       break;
     case 3:
-      struts = g_slist_prepend (struts, new_meta_rect (   0,    0, 1600,   20));
-      struts = g_slist_prepend (struts, new_meta_rect ( 800, 1100,  400,  100));
-      struts = g_slist_prepend (struts, new_meta_rect ( 300, 1150,   80,   50));
-      struts = g_slist_prepend (struts, new_meta_rect ( 700,  525,  200,  150));
+      ans = g_slist_prepend (ans, new_meta_strut (   0,    0, 1600,   20, wc));
+      ans = g_slist_prepend (ans, new_meta_strut ( 800, 1100,  400,  100, wc));
+      ans = g_slist_prepend (ans, new_meta_strut ( 300, 1150,   80,   50, wc));
+      ans = g_slist_prepend (ans, new_meta_strut ( 700,  525,  200,  150, wc));
       break;
     case 4:
-      struts = g_slist_prepend (struts, new_meta_rect (   0,    0,  800, 1200));
-      struts = g_slist_prepend (struts, new_meta_rect ( 800,    0, 1600,   20));
+      ans = g_slist_prepend (ans, new_meta_strut (   0,    0,  800, 1200, wc));
+      ans = g_slist_prepend (ans, new_meta_strut ( 800,    0, 1600,   20, wc));
       break;
     case 5:
-      struts = g_slist_prepend (struts, new_meta_rect ( 800,    0, 1600,   20));
-      struts = g_slist_prepend (struts, new_meta_rect (   0,    0,  800, 1200));
-      struts = g_slist_prepend (struts, new_meta_rect ( 800,   10,  800, 1200));
+      ans = g_slist_prepend (ans, new_meta_strut ( 800,    0, 1600,   20, wc));
+      ans = g_slist_prepend (ans, new_meta_strut (   0,    0,  800, 1200, wc));
+      ans = g_slist_prepend (ans, new_meta_strut ( 800,   10,  800, 1200, wc));
       break;
     case 6:
-      struts = g_slist_prepend (struts, new_meta_rect (   0,    0, 1600,   40));
-      struts = g_slist_prepend (struts, new_meta_rect (   0,    0, 1600,   20));
+      ans = g_slist_prepend (ans, new_meta_strut (   0,    0, 1600,   40, wc));
+      ans = g_slist_prepend (ans, new_meta_strut (   0,    0, 1600,   20, wc));
       break;
     }
 
-  return struts;
+  return ans;
 }
 
 static GList*
Index: src/constraints.c
===================================================================
--- src/constraints.c	(revision 3142)
+++ src/constraints.c	(working copy)
@@ -365,7 +365,7 @@ setup_constraint_info (ConstraintInfo   
    * and (b) ignored it for aspect ratio windows -- at least in those
    * cases where both directions do actually change size.
    */
-  info->fixed_directions = 0;
+  info->fixed_directions = FIXED_DIRECTION_NONE;
   /* If x directions don't change but either y direction does */
   if ( orig->x == new->x && orig->x + orig->width  == new->x + new->width   &&
       (orig->y != new->y || orig->y + orig->height != new->y + new->height))
@@ -385,7 +385,7 @@ setup_constraint_info (ConstraintInfo   
    * aren't explicit user interaction, though, so just clear it out.
    */
   if (!info->is_user_action)
-    info->fixed_directions = 0;
+    info->fixed_directions = FIXED_DIRECTION_NONE;
 
   xinerama_info =
     meta_screen_get_xinerama_for_rect (window->screen, &info->current);
@@ -441,7 +441,7 @@ setup_constraint_info (ConstraintInfo   
                 "Freakin' Invalid Stupid",
               (info->is_user_action) ? "true" : "false",
               meta_gravity_to_string (info->resize_gravity),
-              (info->fixed_directions == 0) ? "None" :
+              (info->fixed_directions == FIXED_DIRECTION_NONE) ? "None" :
                 (info->fixed_directions == FIXED_DIRECTION_X) ? "X fixed" :
                 (info->fixed_directions == FIXED_DIRECTION_Y) ? "Y fixed" :
                 "Freakin' Invalid Stupid",
@@ -500,7 +500,7 @@ place_window_if_needed(MetaWindow     *w
       /* Since we just barely placed the window, there's no reason to
        * consider any of the directions fixed.
        */
-      info->fixed_directions = 0;
+      info->fixed_directions = FIXED_DIRECTION_NONE;
     }
 
   if (window->placed || did_placement)
@@ -691,7 +691,8 @@ constrain_maximization (MetaWindow      
                         ConstraintPriority  priority,
                         gboolean            check_only)
 {
-  MetaRectangle min_size, max_size, work_area;
+  MetaRectangle target_size;
+  MetaRectangle min_size, max_size;
   gboolean hminbad, vminbad;
   gboolean horiz_equal, vert_equal;
   gboolean constraint_already_satisfied;
@@ -703,20 +704,51 @@ constrain_maximization (MetaWindow      
   if (!window->maximized_horizontally && !window->maximized_vertically)
     return TRUE;
 
-  work_area = info->work_area_xinerama;
-  unextend_by_frame (&work_area, info->fgeom);
-  get_size_limits (window, info->fgeom, FALSE, &min_size, &max_size);
+  /* Calculate target_size = maximized size of (window + frame) */
+  if (window->maximized_horizontally && window->maximized_vertically)
+    target_size = info->work_area_xinerama;
+  else
+    {
+      /* Amount of maximization possible in a single direction depends
+       * on which struts could occlude the window given its current
+       * position.  For example, a vertical partial strut on the right
+       * is only relevant for a horizontally maximized window when the
+       * window is at a vertical position where it could be occluded
+       * by that partial strut.
+       */
+      MetaDirection  direction;
+      GSList        *active_workspace_struts;
+
+      if (window->maximized_horizontally)
+        direction = META_DIRECTION_HORIZONTAL;
+      else
+        direction = META_DIRECTION_VERTICAL;
+      active_workspace_struts = window->screen->active_workspace->all_struts;
+
+      target_size = info->current;
+      extend_by_frame (&target_size, info->fgeom);
+      meta_rectangle_expand_to_avoiding_struts (&target_size,
+                                                &info->entire_xinerama,
+                                                direction,
+                                                active_workspace_struts);
+   }
+  /* Now make target_size = maximized size of client window */
+  unextend_by_frame (&target_size, info->fgeom);
 
-  hminbad = work_area.width < min_size.width && window->maximized_horizontally;
-  vminbad = work_area.height < min_size.height && window->maximized_vertically;
+  /* Check min size constraints; max size constraints are ignored for maximized
+   * windows, as per bug 327543.
+   */
+  get_size_limits (window, info->fgeom, FALSE, &min_size, &max_size);
+  hminbad = target_size.width < min_size.width && window->maximized_horizontally;
+  vminbad = target_size.height < min_size.height && window->maximized_vertically;
   if (hminbad || vminbad)
     return TRUE;
 
   /* Determine whether constraint is already satisfied; exit if it is */
-  horiz_equal = work_area.x      == info->current.x &&
-                work_area.width  == info->current.width;
-  vert_equal  = work_area.y      == info->current.y &&
-                work_area.height == info->current.height;
+  horiz_equal = target_size.x      == info->current.x &&
+                target_size.width  == info->current.width;
+  vert_equal  = target_size.y      == info->current.y &&
+                target_size.height == info->current.height;
   constraint_already_satisfied =
     (horiz_equal || !window->maximized_horizontally) &&
     (vert_equal  || !window->maximized_vertically);
@@ -726,13 +758,13 @@ constrain_maximization (MetaWindow      
   /*** Enforce constraint ***/
   if (window->maximized_horizontally)
     {
-      info->current.x      = work_area.x;
-      info->current.width  = work_area.width;
+      info->current.x      = target_size.x;
+      info->current.width  = target_size.width;
     }
   if (window->maximized_vertically)
     {
-      info->current.y      = work_area.y;
-      info->current.height = work_area.height;
+      info->current.y      = target_size.y;
+      info->current.height = target_size.height;
     }
   return TRUE;
 }
Index: src/window.c
===================================================================
--- src/window.c	(revision 3142)
+++ src/window.c	(working copy)
@@ -5675,86 +5675,74 @@ invalidate_work_areas (MetaWindow *windo
 void
 meta_window_update_struts (MetaWindow *window)
 {
+  GSList *old_struts;
+  GSList *new_struts;
+  GSList *old_iter, *new_iter;
   gulong *struts = NULL;
   int nitems;
-  gboolean old_has_struts;
-  gboolean new_has_struts;
-
-  MetaRectangle old_left;
-  MetaRectangle old_right;
-  MetaRectangle old_top;
-  MetaRectangle old_bottom;
-
-  MetaRectangle new_left;
-  MetaRectangle new_right;
-  MetaRectangle new_top;
-  MetaRectangle new_bottom;
+  gboolean changed;
 
   meta_verbose ("Updating struts for %s\n", window->desc);
-  
-  if (window->struts)
-    {
-      old_has_struts = TRUE;
-      old_left = window->struts->left;
-      old_right = window->struts->right;
-      old_top = window->struts->top;
-      old_bottom = window->struts->bottom;
-    }
-  else
-    {
-      old_has_struts = FALSE;
-    }
 
-  new_has_struts = FALSE;
-  new_left = window->screen->rect;
-  new_left.width = 0;
+  old_struts = window->struts;
+  new_struts = NULL; 
 
-  new_right = window->screen->rect;
-  new_right.width = 0;
-  new_right.x = window->screen->rect.width;
-
-  new_top = window->screen->rect;
-  new_top.height = 0;
-
-  new_bottom = window->screen->rect;
-  new_bottom.height = 0;
-  new_bottom.y = window->screen->rect.height;
-  
   if (meta_prop_get_cardinal_list (window->display,
                                    window->xwindow,
                                    window->display->atom_net_wm_strut_partial,
                                    &struts, &nitems))
     {
       if (nitems != 12)
-        {
-          meta_verbose ("_NET_WM_STRUT_PARTIAL on %s has %d values instead of 12\n",
-                        window->desc, nitems);
-        }
+        meta_verbose ("_NET_WM_STRUT_PARTIAL on %s has %d values instead "
+                      "of 12\n",
+                      window->desc, nitems);
       else
         {
-          new_has_struts = TRUE;
-          new_left.width = (int) struts[0];
-          new_right.width = (int) struts[1];
-          new_top.height = (int)struts[2];
-          new_bottom.height = (int)struts[3];
-          new_right.x  = window->screen->rect.width  - new_right.width;
-          new_bottom.y = window->screen->rect.height - new_bottom.height;
-          new_left.y = struts[4];
-          new_left.height = struts[5] - new_left.y + 1;
-          new_right.y = struts[6];
-          new_right.height = struts[7] - new_right.y + 1;
-          new_top.x = struts[8];
-          new_top.width = struts[9] - new_top.x + 1;
-          new_bottom.x = struts[10];
-          new_bottom.width = struts[11] - new_bottom.x + 1;
-          
-          meta_verbose ("_NET_WM_STRUT_PARTIAL struts %d %d %d %d for window %s\n",
-                        new_left.width,
-                        new_right.width,
-                        new_top.height,
-                        new_bottom.height,
+          /* Pull out the strut info for each side in the hint */
+          int i;
+          for (i=0; i<4; i++)
+            {
+              MetaStrut *temp;
+              int thickness, strut_begin, strut_end;
+
+              thickness = struts[i];
+              if (thickness == 0)
+                continue;
+              strut_begin = struts[4+(i*2)];
+              strut_end   = struts[4+(i*2)+1];
+
+              temp = g_new (MetaStrut, 1);
+              temp->side = 1 << i; // See MetaDirection def.  Matches nicely, eh?
+              temp->rect = window->screen->rect;
+              switch (temp->side)
+                {
+                case META_SIDE_RIGHT:
+                  temp->rect.x = BOX_RIGHT(temp->rect) - thickness;
+                  /* Intentionally fall through without breaking */
+                case META_SIDE_LEFT:
+                  temp->rect.width  = thickness;
+                  temp->rect.y      = strut_begin;
+                  temp->rect.height = strut_end - strut_begin + 1;
+                  break;
+                case META_SIDE_BOTTOM:
+                  temp->rect.y = BOX_BOTTOM(temp->rect) - thickness;
+                  /* Intentionally fall through without breaking */
+                case META_SIDE_TOP:
+                  temp->rect.height = thickness;
+                  temp->rect.x      = strut_begin;
+                  temp->rect.width  = strut_end - strut_begin + 1;
+                  break;
+                default:
+                  g_assert_not_reached ();
+                }
+
+              new_struts = g_slist_prepend (new_struts, temp);
+            }
+
+          meta_verbose ("_NET_WM_STRUT_PARTIAL struts %lu %lu %lu %lu for "
+                        "window %s\n",
+                        struts[0], struts[1], struts[2], struts[3], 
                         window->desc);
-          
         }
       meta_XFree (struts);
     }
@@ -5764,67 +5752,86 @@ meta_window_update_struts (MetaWindow *w
                     window->desc);
     }
 
-  if (!new_has_struts)
+  if (!new_struts &&
+      meta_prop_get_cardinal_list (window->display,
+                                   window->xwindow,
+                                   window->display->atom_net_wm_strut,
+                                   &struts, &nitems))
     {
-      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);
+      else
         {
-          if (nitems != 4)
+          /* Pull out the strut info for each side in the hint */
+          int i;
+          for (i=0; i<4; i++)
             {
-              meta_verbose ("_NET_WM_STRUT on %s has %d values instead of 4\n",
-                            window->desc, nitems);
+              MetaStrut *temp;
+              int thickness;
+
+              thickness = struts[i];
+              if (thickness == 0)
+                continue;
+
+              temp = g_new (MetaStrut, 1);
+              temp->side = 1 << i;
+              temp->rect = window->screen->rect;
+              switch (temp->side)
+                {
+                case META_SIDE_RIGHT:
+                  temp->rect.x = BOX_RIGHT(temp->rect) - thickness;
+                  /* Intentionally fall through without breaking */
+                case META_SIDE_LEFT:
+                  temp->rect.width  = thickness;
+                  break;
+                case META_SIDE_BOTTOM:
+                  temp->rect.y = BOX_BOTTOM(temp->rect) - thickness;
+                  /* Intentionally fall through without breaking */
+                case META_SIDE_TOP:
+                  temp->rect.height = thickness;
+                  break;
+                default:
+                  g_assert_not_reached ();
+                }
+
+              new_struts = g_slist_prepend (new_struts, temp);
             }
-          else
-            {
-              new_has_struts = TRUE;
-              new_left.width = (int) struts[0];
-              new_right.width = (int) struts[1];
-              new_top.height = (int)struts[2];
-              new_bottom.height = (int)struts[3];
-              new_right.x  = window->screen->rect.width  - new_right.width;
-              new_bottom.y = window->screen->rect.height - new_bottom.height;
               
-              meta_verbose ("_NET_WM_STRUT struts %d %d %d %d for window %s\n",
-                            new_left.width,
-                            new_right.width,
-                            new_top.height,
-                            new_bottom.height,
-                            window->desc);
-              
-            }
-          meta_XFree (struts);
-        }
-      else
-        {
-          meta_verbose ("No _NET_WM_STRUT property for %s\n",
+          meta_verbose ("_NET_WM_STRUT struts %lu %lu %lu %lu for window %s\n",
+                        struts[0], struts[1], struts[2], struts[3], 
                         window->desc);
         }
+      meta_XFree (struts);
+    }
+  else if (!new_struts)
+    {
+      meta_verbose ("No _NET_WM_STRUT property for %s\n",
+                    window->desc);
     }
  
-  if (old_has_struts != new_has_struts ||
-      (new_has_struts && old_has_struts &&
-       (!meta_rectangle_equal(&old_left, &new_left) ||
-        !meta_rectangle_equal(&old_right, &new_right) ||
-        !meta_rectangle_equal(&old_top, &new_top) ||
-        !meta_rectangle_equal(&old_bottom, &new_bottom))))
+  /* Determine whether old_struts and new_struts are the same */
+  old_iter = old_struts;
+  new_iter = new_struts;
+  while (old_iter && new_iter)
+    {
+      MetaStrut *old_strut = (MetaStrut*) old_iter->data;
+      MetaStrut *new_strut = (MetaStrut*) new_iter->data;
+
+      if (old_strut->side != new_strut->side ||
+          !meta_rectangle_equal (&old_strut->rect, &new_strut->rect))
+        break;
+
+      old_iter = old_iter->next;
+      new_iter = new_iter->next;
+    }
+  changed = (old_iter != NULL || new_iter != NULL);
+
+  /* Update appropriately */
+  meta_free_gslist_and_elements (old_struts);
+  window->struts = new_struts;
+  if (changed)
     {
-      if (new_has_struts)
-        {
-          if (!window->struts)
-            window->struts = g_new (MetaStruts, 1);
-              
-          window->struts->left = new_left;
-          window->struts->right = new_right;
-          window->struts->top = new_top;
-          window->struts->bottom = new_bottom;
-        }
-      else
-        {
-          g_free (window->struts);
-          window->struts = NULL;
-        }
       meta_topic (META_DEBUG_WORKAREA,
                   "Invalidating work areas of window %s due to struts update\n",
                   window->desc);
Index: src/window.h
===================================================================
--- src/window.h	(revision 3142)
+++ src/window.h	(working copy)
@@ -36,7 +36,6 @@
 #include <gdk-pixbuf/gdk-pixbuf.h>
 
 typedef struct _MetaGroup MetaGroup;
-typedef struct _MetaStruts MetaStruts;
 
 typedef gboolean (*MetaWindowForeachFunc) (MetaWindow *window,
                                            void       *data);
@@ -67,15 +66,6 @@ typedef enum {
   META_CLIENT_TYPE_MAX_RECOGNIZED = 2
 } MetaClientType;
 
-struct _MetaStruts
-{
-  /* struts */
-  MetaRectangle left;
-  MetaRectangle right;
-  MetaRectangle top;
-  MetaRectangle bottom;
-};
-
 struct _MetaWindow
 {
   MetaDisplay *display;
@@ -276,7 +266,7 @@ struct _MetaWindow
   guint calc_placement : 1;
 
   /* Note: can be NULL */
-  MetaStruts *struts;
+  GSList *struts;
 
   /* Transient parent is a root window */
   guint transient_parent_is_root_window : 1;
Index: src/boxes.c
===================================================================
--- src/boxes.c	(revision 3142)
+++ src/boxes.c	(working copy)
@@ -547,10 +547,10 @@ meta_rectangle_get_minimal_spanning_set_
   ret = g_list_prepend (NULL, temp_rect);
 
   strut_iter = all_struts;
-  while (strut_iter)
+  for (strut_iter = all_struts; strut_iter; strut_iter = strut_iter->next)
     {
       GList *rect_iter; 
-      MetaRectangle *strut = (MetaRectangle*) strut_iter->data;
+      MetaRectangle *strut_rect = &((MetaStrut*)strut_iter->data)->rect;
 
       tmp_list = ret;
       ret = NULL;
@@ -558,45 +558,45 @@ meta_rectangle_get_minimal_spanning_set_
       while (rect_iter)
         {
           MetaRectangle *rect = (MetaRectangle*) rect_iter->data;
-          if (!meta_rectangle_overlap (rect, strut))
+          if (!meta_rectangle_overlap (rect, strut_rect))
             ret = g_list_prepend (ret, rect);
           else
             {
               /* If there is area in rect left of strut */
-              if (rect->x < strut->x)
+              if (BOX_LEFT (*rect) < BOX_LEFT (*strut_rect))
                 {
                   temp_rect = g_new (MetaRectangle, 1);
                   *temp_rect = *rect;
-                  temp_rect->width = strut->x - rect->x;
+                  temp_rect->width = BOX_LEFT (*strut_rect) - BOX_LEFT (*rect);
                   ret = g_list_prepend (ret, temp_rect);
                 }
               /* If there is area in rect right of strut */
-              if (rect->x + rect->width > strut->x + strut->width)
+              if (BOX_RIGHT (*rect) > BOX_RIGHT (*strut_rect))
                 {
                   int new_x;
                   temp_rect = g_new (MetaRectangle, 1);
                   *temp_rect = *rect;
-                  new_x = strut->x + strut->width;
-                  temp_rect->width = rect->x + rect->width - new_x;
+                  new_x = BOX_RIGHT (*strut_rect);
+                  temp_rect->width = BOX_RIGHT(*rect) - new_x;
                   temp_rect->x = new_x;
                   ret = g_list_prepend (ret, temp_rect);
                 }
               /* If there is area in rect above strut */
-              if (rect->y < strut->y)
+              if (BOX_TOP (*rect) < BOX_TOP (*strut_rect))
                 {
                   temp_rect = g_new (MetaRectangle, 1);
                   *temp_rect = *rect;
-                  temp_rect->height = strut->y - rect->y;
+                  temp_rect->height = BOX_TOP (*strut_rect) - BOX_TOP (*rect);
                   ret = g_list_prepend (ret, temp_rect);
                 }
               /* If there is area in rect below strut */
-              if (rect->y + rect->height > strut->y + strut->height)
+              if (BOX_BOTTOM (*rect) > BOX_BOTTOM (*strut_rect))
                 {
                   int new_y;
                   temp_rect = g_new (MetaRectangle, 1);
                   *temp_rect = *rect;
-                  new_y = strut->y + strut->height;
-                  temp_rect->height = rect->y + rect->height - new_y;
+                  new_y = BOX_BOTTOM (*strut_rect);
+                  temp_rect->height = BOX_BOTTOM (*rect) - new_y;
                   temp_rect->y = new_y;
                   ret = g_list_prepend (ret, temp_rect);
                 }
@@ -605,7 +605,6 @@ meta_rectangle_get_minimal_spanning_set_
           rect_iter = rect_iter->next;
         }
       g_list_free (tmp_list);
-      strut_iter = strut_iter->next;
     }
 
   /* Sort by maximal area, just because I feel like it... */
@@ -663,6 +662,76 @@ meta_rectangle_expand_region_conditional
 }
 
 void
+meta_rectangle_expand_to_avoiding_struts (MetaRectangle       *rect,
+                                          const MetaRectangle *expand_to,
+                                          const MetaDirection  direction,
+                                          const GSList        *all_struts)
+{
+  const GSList *strut_iter;
+
+  /* If someone wants this function to handle more fine-grained
+   * direction expanding in the future (e.g. only left, or fully
+   * horizontal plus upward), feel free.  But I'm hard-coding for both
+   * horizontal directions (exclusive-)or both vertical directions.
+   */
+  g_assert ((direction == META_DIRECTION_HORIZONTAL) ^
+            (direction == META_DIRECTION_VERTICAL  ));
+ 
+  if (direction == META_DIRECTION_HORIZONTAL)
+    {
+      rect->x      = expand_to->x;
+      rect->width  = expand_to->width;
+    }
+  else
+    {
+      rect->y      = expand_to->y;
+      rect->height = expand_to->height;
+    }
+
+ 
+  /* Run over all struts */
+  for (strut_iter = all_struts; strut_iter; strut_iter = strut_iter->next)
+    {
+      MetaStrut *strut = (MetaStrut*) strut_iter->data;
+ 
+      /* Skip struts that don't overlap */
+      if (!meta_rectangle_overlap (&strut->rect, rect))
+        continue;
+
+      if (direction == META_DIRECTION_HORIZONTAL)
+        {
+          if (strut->side == META_SIDE_LEFT)
+            {
+              int offset = BOX_RIGHT(strut->rect) - BOX_LEFT(*rect);
+              rect->x     += offset;
+              rect->width -= offset;
+            }
+          else if (strut->side == META_SIDE_RIGHT)
+            {
+              int offset = BOX_RIGHT (*rect) - BOX_LEFT(strut->rect);
+              rect->width -= offset;
+            }
+          /* else ignore the strut */
+        }
+      else /* direction == META_DIRECTION_VERTICAL */
+        {
+          if (strut->side == META_SIDE_TOP)
+            {
+              int offset = BOX_BOTTOM(strut->rect) - BOX_TOP(*rect);
+              rect->y      += offset;
+              rect->height -= offset;
+            }
+          else if (strut->side == META_SIDE_BOTTOM)
+            {
+              int offset = BOX_BOTTOM(*rect) - BOX_TOP(strut->rect);
+              rect->height -= offset;
+            }
+          /* else ignore the strut */
+        }
+    } /* end loop over struts */
+} /* end meta_rectangle_expand_to_avoiding_struts */
+
+void
 meta_rectangle_free_list_and_elements (GList *filled_list)
 {
   g_list_foreach (filled_list, 
@@ -1075,9 +1144,9 @@ meta_rectangle_edge_aligns (const MetaRe
     case META_DIRECTION_BOTTOM:
       return BOX_LEFT (*rect)      <= BOX_RIGHT (edge->rect) &&
              BOX_LEFT (edge->rect) <= BOX_RIGHT (*rect);
+    default:
+      g_assert_not_reached ();
     }
-
-  g_assert_not_reached ();
 }
 
 static GList*
@@ -1161,27 +1230,27 @@ replace_rect_with_list (GList *old_eleme
 }
 
 /* Make a copy of the strut list, make sure that copy only contains parts
- * of the old_struts that intersect with the rection rect, and then do some
+ * of the old_struts that intersect with the region rect, and then do some
  * magic to make all the new struts disjoint (okay, we we break up struts
  * that aren't disjoint in a way that the overlapping part is only included
  * once, so it's not really magic...).
  */
 static GList*
-get_disjoint_strut_list_in_region (const GSList        *old_struts,
-                                   const MetaRectangle *region)
+get_disjoint_strut_rect_list_in_region (const GSList        *old_struts,
+                                        const MetaRectangle *region)
 {
-  GList *struts;
+  GList *strut_rects;
   GList *tmp;
 
   /* First, copy the list */
-  struts = NULL;
+  strut_rects = NULL;
   while (old_struts)
     {
-      MetaRectangle *cur = old_struts->data;
+      MetaRectangle *cur = &((MetaStrut*)old_struts->data)->rect;
       MetaRectangle *copy = g_new (MetaRectangle, 1);
       *copy = *cur;
       if (meta_rectangle_intersect (copy, region, copy))
-        struts = g_list_prepend (struts, copy);
+        strut_rects = g_list_prepend (strut_rects, copy);
       else
         g_free (copy);
 
@@ -1191,7 +1260,7 @@ get_disjoint_strut_list_in_region (const
   /* Now, loop over the list and check for intersections, fixing things up
    * where they do intersect.
    */
-  tmp = struts;
+  tmp = strut_rects;
   while (tmp)
     {
       GList *compare;
@@ -1218,10 +1287,10 @@ get_disjoint_strut_list_in_region (const
               cur_leftover = g_list_prepend (cur_leftover, overlap_allocated);
 
               /* Fix up tmp, compare, and cur -- maybe struts too */
-              if (struts == tmp)
+              if (strut_rects == tmp)
                 {
-                  struts = replace_rect_with_list (tmp, cur_leftover);
-                  tmp = struts;
+                  strut_rects = replace_rect_with_list (tmp, cur_leftover);
+                  tmp = strut_rects;
                 }
               else
                 tmp   = replace_rect_with_list (tmp,     cur_leftover);
@@ -1239,7 +1308,7 @@ get_disjoint_strut_list_in_region (const
       tmp = tmp->next;
     }
 
-  return struts;
+  return strut_rects;
 }
 
 gint
@@ -1347,7 +1416,7 @@ rectangle_and_edge_intersection (const M
   /* Find out if the intersection is empty; have to do it this way since
    * edges have a thickness of 0
    */
-  if ((result->width < 0 || result->height < 0) ||
+  if ((result->width <  0 || result->height <  0) ||
       (result->width == 0 && result->height == 0))
     {
       result->width = 0;
@@ -1397,6 +1466,8 @@ rectangle_and_edge_intersection (const M
           else
             *handle_type = 0;
           break;
+        default:
+          g_assert_not_reached ();
         }
     }
   return intersect;
@@ -1503,23 +1574,25 @@ split_edge (GList *cur_list, 
           cur_list = g_list_prepend (cur_list, temp_edge);
         }
       break;
+    default:
+      g_assert_not_reached ();
     }
 
   return cur_list;
 }
 
 /* Split up edge and remove preliminary edges from strut_edges depending on
- * if and how strut and edge intersect.
+ * if and how rect and edge intersect.
  */
 static void
-fix_up_edges (MetaRectangle *strut,        MetaEdge *edge, 
+fix_up_edges (MetaRectangle *rect,         MetaEdge *edge, 
               GList         **strut_edges, GList    **edge_splits,
               gboolean      *edge_needs_removal)
 {
   MetaEdge overlap;
   int      handle_type;
 
-  if (!rectangle_and_edge_intersection (strut, edge, &overlap, &handle_type))
+  if (!rectangle_and_edge_intersection (rect, edge, &overlap, &handle_type))
     return;
 
   if (handle_type == 0 || handle_type == 1)
@@ -1628,9 +1701,9 @@ meta_rectangle_find_onscreen_edges (cons
                                     const GSList        *all_struts)
 {
   GList        *ret;
-  GList        *fixed_struts;
+  GList        *fixed_strut_rects;
   GList        *edge_iter; 
-  const GList  *strut_iter;
+  const GList  *strut_rect_iter;
 
   /* The algorithm is basically as follows:
    *   Make sure the struts are disjoint
@@ -1648,18 +1721,19 @@ meta_rectangle_find_onscreen_edges (cons
    */
 
   /* Make sure the struts are disjoint */
-  fixed_struts = get_disjoint_strut_list_in_region (all_struts, basic_rect);
+  fixed_strut_rects =
+    get_disjoint_strut_rect_list_in_region (all_struts, basic_rect);
 
   /* Start off the list with the edges of basic_rect */
   ret = add_edges (NULL, basic_rect, TRUE);
 
-  strut_iter = fixed_struts;
-  while (strut_iter)
+  strut_rect_iter = fixed_strut_rects;
+  while (strut_rect_iter)
     {
-      MetaRectangle *strut = (MetaRectangle*) strut_iter->data;
+      MetaRectangle *strut_rect = (MetaRectangle*) strut_rect_iter->data;
 
       /* Get the new possible edges we may need to add from the strut */
-      GList *new_strut_edges = add_edges (NULL, strut, FALSE);
+      GList *new_strut_edges = add_edges (NULL, strut_rect, FALSE);
 
       edge_iter = ret;
       while (edge_iter)
@@ -1668,7 +1742,7 @@ meta_rectangle_find_onscreen_edges (cons
           GList *splits_of_cur_edge = NULL;
           gboolean edge_needs_removal = FALSE;
 
-          fix_up_edges (strut,            cur_edge, 
+          fix_up_edges (strut_rect,       cur_edge, 
                         &new_strut_edges, &splits_of_cur_edge,
                         &edge_needs_removal);
 
@@ -1692,14 +1766,14 @@ meta_rectangle_find_onscreen_edges (cons
         }
 
       ret = g_list_concat (new_strut_edges, ret);
-      strut_iter = strut_iter->next;
+      strut_rect_iter = strut_rect_iter->next;
     }
 
   /* Sort the list */
   ret = g_list_sort (ret, meta_rectangle_edge_cmp);
 
   /* Free the fixed struts list */
-  meta_rectangle_free_list_and_elements (fixed_struts);
+  meta_rectangle_free_list_and_elements (fixed_strut_rects);
 
   return ret;
 }
@@ -1716,6 +1790,7 @@ meta_rectangle_find_nonintersected_xiner
    */
   GList *ret;
   const GList  *cur;
+  GSList *temp_rects;
 
   /* Initialize the return list to be empty */
   ret = NULL;
@@ -1823,8 +1898,13 @@ meta_rectangle_find_nonintersected_xiner
       cur = cur->next;
     }
 
+  temp_rects = NULL;
+  for (; all_struts; all_struts = all_struts->next)
+    temp_rects = g_slist_prepend (temp_rects,
+                                  &((MetaStrut*)all_struts->data)->rect);
   ret = meta_rectangle_remove_intersections_with_boxes_from_edges (ret, 
-                                                                   all_struts);
+                                                                   temp_rects);
+  g_slist_free (temp_rects);
 
   /* Sort the list */
   ret = g_list_sort (ret, meta_rectangle_edge_cmp);
Index: src/boxes.h
===================================================================
--- src/boxes.h	(revision 3142)
+++ src/boxes.h	(working copy)
@@ -28,7 +28,6 @@
 #include "common.h"
 
 typedef struct _MetaRectangle MetaRectangle;
-
 struct _MetaRectangle
 {
   int x;
@@ -37,6 +36,13 @@ struct _MetaRectangle
   int height;
 };
 
+typedef struct _MetaStrut MetaStrut;
+struct _MetaStrut
+{
+  MetaRectangle rect;
+  MetaDirection side;
+};
+
 #define BOX_LEFT(box)    ((box).x)                /* Leftmost pixel of rect */
 #define BOX_RIGHT(box)   ((box).x + (box).width)  /* One pixel past right   */
 #define BOX_TOP(box)     ((box).y)                /* Topmost pixel of rect  */
@@ -44,8 +50,9 @@ struct _MetaRectangle
 
 typedef enum
 {
-  FIXED_DIRECTION_X = 1 << 0,
-  FIXED_DIRECTION_Y = 1 << 1,
+  FIXED_DIRECTION_NONE = 0,
+  FIXED_DIRECTION_X    = 1 << 0,
+  FIXED_DIRECTION_Y    = 1 << 1,
 } FixedDirections;
 
 typedef enum
@@ -166,6 +173,16 @@ GList*   meta_rectangle_expand_region_co
                                          const int            min_x,
                                          const int            min_y);
 
+/* Expand rect in direction to the size of expand_to, and then clip out any
+ * overlapping struts oriented orthognal to the expansion direction.  (Think
+ * horizontal or vertical maximization)
+ */
+void     meta_rectangle_expand_to_avoiding_struts (
+                                         MetaRectangle       *rect,
+                                         const MetaRectangle *expand_to,
+                                         const MetaDirection  direction,
+                                         const GSList        *all_struts);
+
 /* Free the list created by
  *   meta_rectangle_get_minimal_spanning_set_for_region()
  * or
Index: src/common.h
===================================================================
--- src/common.h	(revision 3142)
+++ src/common.h	(working copy)
@@ -216,12 +216,24 @@ typedef enum
  */
 typedef enum
 {
-  META_DIRECTION_LEFT      = 1 << 0,
-  META_DIRECTION_RIGHT     = 1 << 1,
-  META_DIRECTION_TOP       = 1 << 2,
-  META_DIRECTION_BOTTOM    = 1 << 3,
-  META_DIRECTION_UP        = 1 << 2, /* Alternate name for TOP */
-  META_DIRECTION_DOWN      = 1 << 3  /* Alternate name for BOTTOM */
+  META_DIRECTION_LEFT       = 1 << 0,
+  META_DIRECTION_RIGHT      = 1 << 1,
+  META_DIRECTION_TOP        = 1 << 2,
+  META_DIRECTION_BOTTOM     = 1 << 3,
+
+  /* Some aliases for making code more readable for various circumstances. */
+  META_DIRECTION_UP         = META_DIRECTION_TOP,
+  META_DIRECTION_DOWN       = META_DIRECTION_BOTTOM,
+
+  /* A few more definitions using aliases */
+  META_DIRECTION_HORIZONTAL = META_DIRECTION_LEFT | META_DIRECTION_RIGHT,
+  META_DIRECTION_VERTICAL   = META_DIRECTION_UP   | META_DIRECTION_DOWN,
+
+  /* And a few more aliases */
+  META_SIDE_LEFT            = META_DIRECTION_LEFT,
+  META_SIDE_RIGHT           = META_DIRECTION_RIGHT,
+  META_SIDE_TOP             = META_DIRECTION_TOP,
+  META_SIDE_BOTTOM          = META_DIRECTION_BOTTOM
 } MetaDirection;
 
 /* Function a window button can have.  Note, you can't add stuff here
