[mutter] Move workspace related code from MetaDisplay to MetaWorkspaceManager



commit 81c1c70c0a4e52e67bfd14dbb40f8740cadb3195
Author: Armin Krezović <krezovic armin gmail com>
Date:   Sun Aug 27 21:02:40 2017 +0200

    Move workspace related code from MetaDisplay to MetaWorkspaceManager
    
    https://bugzilla.gnome.org/show_bug.cgi?id=759538

 src/core/constraints.c                    |   8 +-
 src/core/core.c                           |  20 +-
 src/core/display-private.h                |  52 --
 src/core/display.c                        | 769 +----------------------------
 src/core/edge-resistance.c                |   8 +-
 src/core/keybindings.c                    |  34 +-
 src/core/meta-workspace-manager-private.h |  45 ++
 src/core/meta-workspace-manager.c         | 786 ++++++++++++++++++++++++++++++
 src/core/stack.c                          |  25 +-
 src/core/window.c                         | 109 +++--
 src/core/workspace-private.h              |   3 +-
 src/core/workspace.c                      |  81 +--
 src/meta/display.h                        |  24 -
 src/meta/meta-workspace-manager.h         |  22 +
 src/x11/events.c                          |  19 +-
 src/x11/meta-x11-display.c                |  68 +--
 src/x11/window-props.c                    |   5 +-
 src/x11/window-x11.c                      |  11 +-
 18 files changed, 1093 insertions(+), 996 deletions(-)
---
diff --git a/src/core/constraints.c b/src/core/constraints.c
index d90e7230c..f84ef7d61 100644
--- a/src/core/constraints.c
+++ b/src/core/constraints.c
@@ -24,6 +24,7 @@
 #include <config.h>
 #include "boxes-private.h"
 #include "constraints.h"
+#include "meta-workspace-manager-private.h"
 #include "workspace-private.h"
 #include "place.h"
 #include <meta/prefs.h>
@@ -412,7 +413,7 @@ setup_constraint_info (ConstraintInfo      *info,
                             &info->entire_monitor);
     }
 
-  cur_workspace = window->display->active_workspace;
+  cur_workspace = window->display->workspace_manager->active_workspace;
   info->usable_screen_region   =
     meta_workspace_get_onscreen_region (cur_workspace);
   info->usable_monitor_region =
@@ -499,7 +500,7 @@ place_window_if_needed(MetaWindow     *window,
       meta_window_get_work_area_for_logical_monitor (window,
                                                      logical_monitor,
                                                      &info->work_area_monitor);
-      cur_workspace = window->display->active_workspace;
+      cur_workspace = window->display->workspace_manager->active_workspace;
       info->usable_monitor_region =
         meta_workspace_get_onmonitor_region (cur_workspace, logical_monitor);
 
@@ -926,6 +927,7 @@ constrain_maximization (MetaWindow         *window,
                         ConstraintPriority  priority,
                         gboolean            check_only)
 {
+  MetaWorkspaceManager *workspace_manager = window->display->workspace_manager;
   MetaRectangle target_size;
   MetaRectangle min_size, max_size;
   gboolean hminbad, vminbad;
@@ -965,7 +967,7 @@ constrain_maximization (MetaWindow         *window,
         direction = META_DIRECTION_HORIZONTAL;
       else
         direction = META_DIRECTION_VERTICAL;
-      active_workspace_struts = window->display->active_workspace->all_struts;
+      active_workspace_struts = workspace_manager->active_workspace->all_struts;
 
       target_size = info->current;
       meta_rectangle_expand_to_avoiding_struts (&target_size,
diff --git a/src/core/core.c b/src/core/core.c
index 8aeebe505..7b7f1300a 100644
--- a/src/core/core.c
+++ b/src/core/core.c
@@ -24,6 +24,7 @@
 #include <config.h>
 #include "core.h"
 #include "frame.h"
+#include "meta-workspace-manager-private.h"
 #include "workspace-private.h"
 #include <meta/prefs.h>
 #include <meta/meta-x11-errors.h>
@@ -77,6 +78,8 @@ static gboolean
 lower_window_and_transients (MetaWindow *window,
                              gpointer   data)
 {
+  MetaWorkspaceManager *workspace_manager = window->display->workspace_manager;
+
   meta_window_lower (window);
 
   meta_window_foreach_transient (window, lower_window_and_transients, NULL);
@@ -87,22 +90,22 @@ lower_window_and_transients (MetaWindow *window,
        * Do extra sanity checks to avoid possible race conditions.
        * (Borrowed from window.c.)
        */
-      if (window->display->active_workspace &&
+      if (workspace_manager->active_workspace &&
           meta_window_located_on_workspace (window,
-                                            window->display->active_workspace))
+                                            workspace_manager->active_workspace))
         {
           GList* link;
-          link = g_list_find (window->display->active_workspace->mru_list,
+          link = g_list_find (workspace_manager->active_workspace->mru_list,
                               window);
           g_assert (link);
 
-          window->display->active_workspace->mru_list =
-            g_list_remove_link (window->display->active_workspace->mru_list,
+          workspace_manager->active_workspace->mru_list =
+            g_list_remove_link (workspace_manager->active_workspace->mru_list,
                                 link);
           g_list_free (link);
 
-          window->display->active_workspace->mru_list =
-            g_list_append (window->display->active_workspace->mru_list,
+          workspace_manager->active_workspace->mru_list =
+            g_list_append (workspace_manager->active_workspace->mru_list,
                            window);
         }
     }
@@ -116,6 +119,7 @@ meta_core_user_lower_and_unfocus (Display *xdisplay,
                                   guint32  timestamp)
 {
   MetaWindow *window = get_window (xdisplay, frame_xwindow);
+  MetaWorkspaceManager *workspace_manager = window->display->workspace_manager;
 
   lower_window_and_transients (window, NULL);
 
@@ -123,7 +127,7 @@ meta_core_user_lower_and_unfocus (Display *xdisplay,
   * the focus window, assume that's always the case. (Typically,
   * this will be invoked via keyboard action or by a mouse action;
   * in either case the window or a modal child will have been focused.) */
-  meta_workspace_focus_default_window (window->display->active_workspace,
+  meta_workspace_focus_default_window (workspace_manager->active_workspace,
                                        NULL,
                                        timestamp);
 }
diff --git a/src/core/display-private.h b/src/core/display-private.h
index 769dbb134..c87e0b39b 100644
--- a/src/core/display-private.h
+++ b/src/core/display-private.h
@@ -242,16 +242,6 @@ struct _MetaDisplay
   guint work_area_later;
   guint check_fullscreen_later;
 
-  MetaWorkspace *active_workspace;
-
-  GList *workspaces;
-
-  int rows_of_workspaces;
-  int columns_of_workspaces;
-  MetaDisplayCorner starting_corner;
-  guint vertical_workspaces : 1;
-  guint workspace_layout_overridden : 1;
-
   MetaBell *bell;
   MetaWorkspaceManager *workspace_manager;
 };
@@ -442,46 +432,4 @@ void meta_display_queue_check_fullscreen (MetaDisplay *display);
 MetaWindow *meta_display_get_pointer_window (MetaDisplay *display,
                                              MetaWindow  *not_this_one);
 
-void meta_display_init_workspaces         (MetaDisplay *display);
-void meta_display_update_workspace_layout (MetaDisplay       *display,
-                                           MetaDisplayCorner  starting_corner,
-                                           gboolean           vertical_layout,
-                                           int                n_rows,
-                                           int                n_columns);
-
-typedef struct MetaWorkspaceLayout MetaWorkspaceLayout;
-
-struct MetaWorkspaceLayout
-{
-  int rows;
-  int cols;
-  int *grid;
-  int grid_area;
-  int current_row;
-  int current_col;
-};
-
-void meta_display_calc_workspace_layout (MetaDisplay         *display,
-                                         int                  num_workspaces,
-                                         int                  current_space,
-                                         MetaWorkspaceLayout *layout);
-void meta_display_free_workspace_layout (MetaWorkspaceLayout *layout);
-
-void meta_display_minimize_all_on_active_workspace_except (MetaDisplay *display,
-                                                           MetaWindow *keep);
-
-/* Show/hide the desktop (temporarily hide all windows) */
-void     meta_display_show_desktop        (MetaDisplay *display,
-                                           guint32      timestamp);
-void     meta_display_unshow_desktop      (MetaDisplay *display);
-
-void     meta_display_workspace_switched (MetaDisplay        *display,
-                                          int                 from,
-                                          int                 to,
-                                          MetaMotionDirection direction);
-
-void meta_display_update_num_workspaces (MetaDisplay *display,
-                                         guint32      timestamp,
-                                         int          new_num);
-
 #endif
diff --git a/src/core/display.c b/src/core/display.c
index 97d23f80d..f5cefb4e9 100644
--- a/src/core/display.c
+++ b/src/core/display.c
@@ -154,8 +154,7 @@ enum
 enum {
   PROP_0,
 
-  PROP_FOCUS_WINDOW,
-  PROP_N_WORKSPACES
+  PROP_FOCUS_WINDOW
 };
 
 static guint display_signals [LAST_SIGNAL] = { 0 };
@@ -190,9 +189,6 @@ meta_display_get_property(GObject         *object,
     case PROP_FOCUS_WINDOW:
       g_value_set_object (value, display->focus_window);
       break;
-    case PROP_N_WORKSPACES:
-      g_value_set_int (value, meta_display_get_n_workspaces (display));
-      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -536,14 +532,6 @@ meta_display_class_init (MetaDisplayClass *klass)
                                                         META_TYPE_WINDOW,
                                                         G_PARAM_READABLE));
 
-  g_object_class_install_property (object_class,
-                                   PROP_N_WORKSPACES,
-                                   g_param_spec_int ("n-workspaces",
-                                                     "N Workspaces",
-                                                     "Number of workspaces",
-                                                     1, G_MAXINT, 1,
-                                                     G_PARAM_READABLE));
-
 }
 
 
@@ -688,18 +676,6 @@ on_startup_notification_changed (MetaStartupNotification *sn,
   g_signal_emit_by_name (display, "startup-sequence-changed", sequence);
 }
 
-static void
-reload_logical_monitors (MetaDisplay *display)
-{
-  GList *l;
-
-  for (l = display->workspaces; l != NULL; l = l->next)
-    {
-      MetaWorkspace *space = l->data;
-      meta_workspace_invalidate_work_area (space);
-    }
-}
-
 /**
  * meta_display_open:
  *
@@ -762,13 +738,6 @@ meta_display_open (void)
   display->grab_tile_mode = META_TILE_NONE;
   display->grab_tile_monitor_number = -1;
 
-  display->active_workspace = NULL;
-  display->workspaces = NULL;
-  display->rows_of_workspaces = 1;
-  display->columns_of_workspaces = -1;
-  display->vertical_workspaces = FALSE;
-  display->starting_corner = META_DISPLAY_TOPLEFT;
-
   display->grab_edge_resistance_data = NULL;
 
   meta_display_init_keys (display);
@@ -793,25 +762,6 @@ meta_display_open (void)
 
   display->workspace_manager = meta_workspace_manager_new (display);
 
-  /* This is the default layout extracted from default
-   * variable values in update_num_workspaces ()
-   * This can be overriden using _NET_DESKTOP_LAYOUT in
-   * meta_x11_display_new (), if it's specified */
-  meta_display_update_workspace_layout (display,
-                                        META_DISPLAY_TOPLEFT,
-                                        FALSE,
-                                        -1,
-                                         1);
-
-  /* There must be at least one workspace at all times,
-   * so create that required workspace.
-   */
-  meta_workspace_new (display);
-
-  meta_display_init_workspaces (display);
-
-  reload_logical_monitors (display);
-
   display->startup_notification = meta_startup_notification_get (display);
   g_signal_connect (display->startup_notification, "changed",
                     G_CALLBACK (on_startup_notification_changed), display);
@@ -2564,18 +2514,6 @@ prefs_changed_callback (MetaPreference pref,
     {
       meta_display_reload_cursor (display);
     }
-  else if ((pref == META_PREF_NUM_WORKSPACES ||
-            pref == META_PREF_DYNAMIC_WORKSPACES) &&
-            !meta_prefs_get_dynamic_workspaces ())
-    {
-      /* GSettings doesn't provide timestamps, but luckily update_num_workspaces
-       * often doesn't need it...
-       */
-      guint32 timestamp =
-        meta_display_get_current_time_roundtrip (display);
-      int new_num = meta_prefs_get_num_workspaces ();
-      meta_display_update_num_workspaces (display, timestamp, new_num);
-    }
 }
 
 void
@@ -3082,7 +3020,7 @@ on_monitors_changed_internal (MetaMonitorManager *monitor_manager,
   MetaBackend *backend;
   MetaCursorRenderer *cursor_renderer;
 
-  reload_logical_monitors (display);
+  meta_workspace_manager_reload_work_areas (display->workspace_manager);
 
   /* Fix up monitor for all windows on this display */
   meta_display_foreach_window (display, META_LIST_INCLUDE_OVERRIDE_REDIRECT,
@@ -3665,6 +3603,7 @@ MetaWindow *
 meta_display_get_pointer_window (MetaDisplay *display,
                                  MetaWindow  *not_this_one)
 {
+  MetaWorkspaceManager *workspace_manager = display->workspace_manager;
   MetaBackend *backend = meta_get_backend ();
   MetaCursorTracker *cursor_tracker = meta_backend_get_cursor_tracker (backend);
   MetaWindow *window;
@@ -3677,718 +3616,24 @@ meta_display_get_pointer_window (MetaDisplay *display,
   meta_cursor_tracker_get_pointer (cursor_tracker, &x, &y, NULL);
 
   window = meta_stack_get_default_focus_window_at_point (display->stack,
-                                                         display->active_workspace,
+                                                         workspace_manager->active_workspace,
                                                          not_this_one,
                                                          x, y);
 
   return window;
 }
 
-void
-meta_display_init_workspaces (MetaDisplay *display)
-{
-  int num;
-
-  g_return_if_fail (META_IS_DISPLAY (display));
-
-  if (meta_prefs_get_dynamic_workspaces ())
-    /* This will be properly updated using _NET_NUMBER_OF_DESKTOPS
-     * (if set) in meta_x11_display_new () */
-    num = 1;
-  else
-    num = meta_prefs_get_num_workspaces ();
-
-  meta_display_update_num_workspaces (display, META_CURRENT_TIME, num);
-
-  meta_workspace_activate (display->workspaces->data, META_CURRENT_TIME);
-}
-
-int
-meta_display_get_n_workspaces (MetaDisplay *display)
-{
-  return g_list_length (display->workspaces);
-}
-
-/**
- * meta_display_get_workspace_by_index:
- * @display: a #MetaDisplay
- * @index: index of one of the display's workspaces
- *
- * Gets the workspace object for one of a display's workspaces given the workspace
- * index. It's valid to call this function with an out-of-range index and it
- * will robustly return %NULL.
- *
- * Return value: (transfer none): the workspace object with specified index, or %NULL
- *   if the index is out of range.
- */
-MetaWorkspace *
-meta_display_get_workspace_by_index (MetaDisplay  *display,
-                                     int           idx)
-{
-  return g_list_nth_data (display->workspaces, idx);
-}
-
-void
-meta_display_remove_workspace (MetaDisplay   *display,
-                               MetaWorkspace *workspace,
-                               guint32        timestamp)
-{
-  GList *l;
-  GList *next;
-  MetaWorkspace *neighbour = NULL;
-  int index;
-  gboolean active_index_changed;
-  int new_num;
-
-  l = g_list_find (display->workspaces, workspace);
-  if (!l)
-    return;
-
-  next = l->next;
-
-  if (l->prev)
-    neighbour = l->prev->data;
-  else if (l->next)
-    neighbour = l->next->data;
-  else
-    {
-      /* Cannot remove the only workspace! */
-      return;
-    }
-
-  meta_workspace_relocate_windows (workspace, neighbour);
-
-  if (workspace == display->active_workspace)
-    meta_workspace_activate (neighbour, timestamp);
-
-  /* To emit the signal after removing the workspace */
-  index = meta_workspace_index (workspace);
-  active_index_changed = index < meta_display_get_active_workspace_index (display);
-
-  /* This also removes the workspace from the displays list */
-  meta_workspace_remove (workspace);
-
-  new_num = g_list_length (display->workspaces);
-
-  if (!meta_prefs_get_dynamic_workspaces ())
-    meta_prefs_set_num_workspaces (new_num);
-
-  /* If deleting a workspace before the current workspace, the active
-   * workspace index changes, so we need to update that hint */
-  if (active_index_changed)
-    g_signal_emit (display, display_signals[ACTIVE_WORKSPACE_CHANGED], 0, NULL);
-
-  for (l = next; l; l = l->next)
-    {
-      MetaWorkspace *w = l->data;
-
-      meta_workspace_index_changed (w);
-    }
-
-  meta_display_queue_workarea_recalc (display);
-
-  g_signal_emit (display, display_signals[WORKSPACE_REMOVED], 0, index);
-  g_object_notify (G_OBJECT (display), "n-workspaces");
-}
-
-/**
- * meta_display_append_new_workspace:
- * @display: a #MetaDisplay
- * @activate: %TRUE if the workspace should be switched to after creation
- * @timestamp: if switching to a new workspace, timestamp to be used when
- *   focusing a window on the new workspace. (Doesn't hurt to pass a valid
- *   timestamp when available even if not switching workspaces.)
- *
- * Append a new workspace to the display and (optionally) switch to that
- * display.
- *
- * Return value: (transfer none): the newly appended workspace.
- */
-MetaWorkspace *
-meta_display_append_new_workspace (MetaDisplay *display,
-                                   gboolean     activate,
-                                   guint32      timestamp)
-{
-  MetaWorkspace *w;
-  int new_num;
-
-  /* This also adds the workspace to the display list */
-  w = meta_workspace_new (display);
-
-  if (!w)
-    return NULL;
-
-  if (activate)
-    meta_workspace_activate (w, timestamp);
-
-  new_num = g_list_length (display->workspaces);
-
-  if (!meta_prefs_get_dynamic_workspaces ())
-    meta_prefs_set_num_workspaces (new_num);
-
-  meta_display_queue_workarea_recalc (display);
-
-  g_signal_emit (display, display_signals[WORKSPACE_ADDED],
-                 0, meta_workspace_index (w));
-  g_object_notify (G_OBJECT (display), "n-workspaces");
-
-  return w;
-}
-
-void
-meta_display_update_num_workspaces (MetaDisplay *display,
-                                    guint32      timestamp,
-                                    int          new_num)
-{
-  int old_num;
-  GList *l;
-  int i = 0;
-  GList *extras = NULL;
-  MetaWorkspace *last_remaining = NULL;
-  gboolean need_change_space = FALSE;
-
-  g_assert (new_num > 0);
-
-  if (g_list_length (display->workspaces) == (guint) new_num)
-    return;
-
-  for (l = display->workspaces; l != NULL; l = l->next)
-    {
-      MetaWorkspace *w = l->data;
-
-      if (i >= new_num)
-        extras = g_list_prepend (extras, w);
-      else
-        last_remaining = w;
-
-      ++i;
-    }
-  old_num = i;
-
-  g_assert (last_remaining);
-
-  /* Get rid of the extra workspaces by moving all their windows
-   * to last_remaining, then activating last_remaining if
-   * one of the removed workspaces was active. This will be a bit
-   * wacky if the config tool for changing number of workspaces
-   * is on a removed workspace ;-)
-   */
-  for (l = extras; l != NULL; l = l->next)
-    {
-      MetaWorkspace *w = l->data;
-
-      meta_workspace_relocate_windows (w, last_remaining);
-
-      if (w == display->active_workspace)
-        need_change_space = TRUE;
-    }
-
-  if (need_change_space)
-    meta_workspace_activate (last_remaining, timestamp);
-
-  /* Should now be safe to free the workspaces */
-  for (l = extras; l != NULL; l = l->next)
-    {
-      MetaWorkspace *w = l->data;
-
-      meta_workspace_remove (w);
-    }
-
-  g_list_free (extras);
-
-  for (i = old_num; i < new_num; i++)
-    meta_workspace_new (display);
-
-  meta_display_queue_workarea_recalc (display);
-
-  for (i = old_num; i < new_num; i++)
-    g_signal_emit (display, display_signals[WORKSPACE_ADDED], 0, i);
-
-  g_object_notify (G_OBJECT (display), "n-workspaces");
-}
-
-void
-meta_display_update_workspace_layout (MetaDisplay      *display,
-                                      MetaDisplayCorner starting_corner,
-                                      gboolean          vertical_layout,
-                                      int               n_rows,
-                                      int               n_columns)
-{
-  g_return_if_fail (META_IS_DISPLAY (display));
-  g_return_if_fail (n_rows > 0 || n_columns > 0);
-  g_return_if_fail (n_rows != 0 && n_columns != 0);
-
-  if (display->workspace_layout_overridden)
-    return;
-
-  display->vertical_workspaces = vertical_layout != FALSE;
-  display->starting_corner = starting_corner;
-  display->rows_of_workspaces = n_rows;
-  display->columns_of_workspaces = n_columns;
-
-  meta_verbose ("Workspace layout rows = %d cols = %d orientation = %d starting corner = %u\n",
-                display->rows_of_workspaces,
-                display->columns_of_workspaces,
-                display->vertical_workspaces,
-                display->starting_corner);
-}
-
-/**
- * meta_display_override_workspace_layout:
- * @display: a #MetaDisplay
- * @starting_corner: the corner at which the first workspace is found
- * @vertical_layout: if %TRUE the workspaces are laid out in columns rather than rows
- * @n_rows: number of rows of workspaces, or -1 to determine the number of rows from
- *   @n_columns and the total number of workspaces
- * @n_columns: number of columns of workspaces, or -1 to determine the number of columns from
- *   @n_rows and the total number of workspaces
- *
- * Explicitly set the layout of workspaces. Once this has been called, the contents of the
- * _NET_DESKTOP_LAYOUT property on the root window are completely ignored.
- */
-void
-meta_display_override_workspace_layout (MetaDisplay       *display,
-                                        MetaDisplayCorner  starting_corner,
-                                        gboolean           vertical_layout,
-                                        int                n_rows,
-                                        int                n_columns)
-{
-  meta_display_update_workspace_layout (display,
-                                        starting_corner,
-                                        vertical_layout,
-                                        n_rows,
-                                        n_columns);
-
-  display->workspace_layout_overridden = TRUE;
-}
-
-#ifdef WITH_VERBOSE_MODE
-static const char *
-meta_display_corner_to_string (MetaDisplayCorner corner)
-{
-  switch (corner)
-    {
-    case META_DISPLAY_TOPLEFT:
-      return "TopLeft";
-    case META_DISPLAY_TOPRIGHT:
-      return "TopRight";
-    case META_DISPLAY_BOTTOMLEFT:
-      return "BottomLeft";
-    case META_DISPLAY_BOTTOMRIGHT:
-      return "BottomRight";
-    }
-
-  return "Unknown";
-}
-#endif /* WITH_VERBOSE_MODE */
-
-void
-meta_display_calc_workspace_layout (MetaDisplay         *display,
-                                    int                  num_workspaces,
-                                    int                  current_space,
-                                    MetaWorkspaceLayout *layout)
-{
-  int rows, cols;
-  int grid_area;
-  int *grid;
-  int i, r, c;
-  int current_row, current_col;
-
-  rows = display->rows_of_workspaces;
-  cols = display->columns_of_workspaces;
-  if (rows <= 0 && cols <= 0)
-    cols = num_workspaces;
-
-  if (rows <= 0)
-    rows = num_workspaces / cols + ((num_workspaces % cols) > 0 ? 1 : 0);
-  if (cols <= 0)
-    cols = num_workspaces / rows + ((num_workspaces % rows) > 0 ? 1 : 0);
-
-  /* paranoia */
-  if (rows < 1)
-    rows = 1;
-  if (cols < 1)
-    cols = 1;
-
-  g_assert (rows != 0 && cols != 0);
-
-  grid_area = rows * cols;
-
-  meta_verbose ("Getting layout rows = %d cols = %d current = %d "
-                "num_spaces = %d vertical = %s corner = %s\n",
-                rows, cols, current_space, num_workspaces,
-                display->vertical_workspaces ? "(true)" : "(false)",
-                meta_display_corner_to_string (display->starting_corner));
-
-  /* ok, we want to setup the distances in the workspace array to go
-   * in each direction. Remember, there are many ways that a workspace
-   * array can be setup.
-   * see http://www.freedesktop.org/standards/wm-spec/1.2/html/x109.html
-   * and look at the _NET_DESKTOP_LAYOUT section for details.
-   * For instance:
-   */
-  /* starting_corner = META_DISPLAY_TOPLEFT
-   *  vertical_workspaces = 0                 vertical_workspaces=1
-   *       1234                                    1357
-   *       5678                                    2468
-   *
-   * starting_corner = META_DISPLAY_TOPRIGHT
-   *  vertical_workspaces = 0                 vertical_workspaces=1
-   *       4321                                    7531
-   *       8765                                    8642
-   *
-   * starting_corner = META_DISPLAY_BOTTOMLEFT
-   *  vertical_workspaces = 0                 vertical_workspaces=1
-   *       5678                                    2468
-   *       1234                                    1357
-   *
-   * starting_corner = META_DISPLAY_BOTTOMRIGHT
-   *  vertical_workspaces = 0                 vertical_workspaces=1
-   *       8765                                    8642
-   *       4321                                    7531
-   *
-   */
-  /* keep in mind that we could have a ragged layout, e.g. the "8"
-   * in the above grids could be missing
-   */
-
-
-  grid = g_new (int, grid_area);
-
-  current_row = -1;
-  current_col = -1;
-  i = 0;
-
-  switch (display->starting_corner)
-    {
-    case META_DISPLAY_TOPLEFT:
-      if (display->vertical_workspaces)
-        {
-          c = 0;
-          while (c < cols)
-            {
-              r = 0;
-              while (r < rows)
-                {
-                  grid[r*cols+c] = i;
-                  ++i;
-                  ++r;
-                }
-              ++c;
-            }
-        }
-      else
-        {
-          r = 0;
-          while (r < rows)
-            {
-              c = 0;
-              while (c < cols)
-                {
-                  grid[r*cols+c] = i;
-                  ++i;
-                  ++c;
-                }
-              ++r;
-            }
-        }
-      break;
-    case META_DISPLAY_TOPRIGHT:
-      if (display->vertical_workspaces)
-        {
-          c = cols - 1;
-          while (c >= 0)
-            {
-              r = 0;
-              while (r < rows)
-                {
-                  grid[r*cols+c] = i;
-                  ++i;
-                  ++r;
-                }
-              --c;
-            }
-        }
-      else
-        {
-          r = 0;
-          while (r < rows)
-            {
-              c = cols - 1;
-              while (c >= 0)
-                {
-                  grid[r*cols+c] = i;
-                  ++i;
-                  --c;
-                }
-              ++r;
-            }
-        }
-      break;
-    case META_DISPLAY_BOTTOMLEFT:
-      if (display->vertical_workspaces)
-        {
-          c = 0;
-          while (c < cols)
-            {
-              r = rows - 1;
-              while (r >= 0)
-                {
-                  grid[r*cols+c] = i;
-                  ++i;
-                  --r;
-                }
-              ++c;
-            }
-        }
-      else
-        {
-          r = rows - 1;
-          while (r >= 0)
-            {
-              c = 0;
-              while (c < cols)
-                {
-                  grid[r*cols+c] = i;
-                  ++i;
-                  ++c;
-                }
-              --r;
-            }
-        }
-      break;
-    case META_DISPLAY_BOTTOMRIGHT:
-      if (display->vertical_workspaces)
-        {
-          c = cols - 1;
-          while (c >= 0)
-            {
-              r = rows - 1;
-              while (r >= 0)
-                {
-                  grid[r*cols+c] = i;
-                  ++i;
-                  --r;
-                }
-              --c;
-            }
-        }
-      else
-        {
-          r = rows - 1;
-          while (r >= 0)
-            {
-              c = cols - 1;
-              while (c >= 0)
-                {
-                  grid[r*cols+c] = i;
-                  ++i;
-                  --c;
-                }
-              --r;
-            }
-        }
-      break;
-    }
-
-  if (i != grid_area)
-    meta_bug ("did not fill in the whole workspace grid in %s (%d filled)\n",
-              G_STRFUNC, i);
-
-  current_row = 0;
-  current_col = 0;
-  r = 0;
-  while (r < rows)
-    {
-      c = 0;
-      while (c < cols)
-        {
-          if (grid[r*cols+c] == current_space)
-            {
-              current_row = r;
-              current_col = c;
-            }
-          else if (grid[r*cols+c] >= num_workspaces)
-            {
-              /* flag nonexistent spaces with -1 */
-              grid[r*cols+c] = -1;
-            }
-          ++c;
-        }
-      ++r;
-    }
-
-  layout->rows = rows;
-  layout->cols = cols;
-  layout->grid = grid;
-  layout->grid_area = grid_area;
-  layout->current_row = current_row;
-  layout->current_col = current_col;
-
-#ifdef WITH_VERBOSE_MODE
-  if (meta_is_verbose ())
-    {
-      r = 0;
-      while (r < layout->rows)
-        {
-          meta_verbose (" ");
-          meta_push_no_msg_prefix ();
-          c = 0;
-          while (c < layout->cols)
-            {
-              if (r == layout->current_row &&
-                  c == layout->current_col)
-                meta_verbose ("*%2d ", layout->grid[r*layout->cols+c]);
-              else
-                meta_verbose ("%3d ", layout->grid[r*layout->cols+c]);
-              ++c;
-            }
-          meta_verbose ("\n");
-          meta_pop_no_msg_prefix ();
-          ++r;
-        }
-    }
-#endif /* WITH_VERBOSE_MODE */
-}
-
-void
-meta_display_free_workspace_layout (MetaWorkspaceLayout *layout)
-{
-  g_free (layout->grid);
-}
-
-static void
-queue_windows_showing (MetaDisplay *display)
-{
-  GSList *windows, *l;
-
-  /* Must operate on all windows on display instead of just on the
-   * active_workspace's window list, because the active_workspace's
-   * window list may not contain the on_all_workspace windows.
-   */
-  windows = meta_display_list_windows (display, META_LIST_DEFAULT);
-
-  for (l = windows; l != NULL; l = l->next)
-    {
-      MetaWindow *w = l->data;
-      meta_window_queue (w, META_QUEUE_CALC_SHOWING);
-    }
-
-  g_slist_free (windows);
-}
-
-void
-meta_display_minimize_all_on_active_workspace_except (MetaDisplay *display,
-                                                      MetaWindow  *keep)
-{
-  GList *l;
-
-  for (l = display->active_workspace->windows; l != NULL; l = l->next)
-    {
-      MetaWindow *w = l->data;
-
-      if (w->has_minimize_func && w != keep)
-       meta_window_minimize (w);
-    }
-}
-
-void
-meta_display_show_desktop (MetaDisplay *display,
-                           guint32      timestamp)
-{
-  GList *l;
-
-  if (display->active_workspace->showing_desktop)
-    return;
-
-  display->active_workspace->showing_desktop = TRUE;
-
-  queue_windows_showing (display);
-
-  /* Focus the most recently used META_WINDOW_DESKTOP window, if there is one;
-   * see bug 159257.
-   */
-  for (l = display->active_workspace->mru_list; l != NULL; l = l->next)
-    {
-      MetaWindow *w = l->data;
-
-      if (w->type == META_WINDOW_DESKTOP)
-        {
-          meta_window_focus (w, timestamp);
-          break;
-        }
-    }
-
-  g_signal_emit (display, display_signals[SHOWING_DESKTOP_CHANGED], 0, NULL);
-}
-
-void
-meta_display_unshow_desktop (MetaDisplay *display)
-{
-  if (!display->active_workspace->showing_desktop)
-    return;
-
-  display->active_workspace->showing_desktop = FALSE;
-
-  queue_windows_showing (display);
-
-  g_signal_emit (display, display_signals[SHOWING_DESKTOP_CHANGED], 0, NULL);
-}
-
-/**
- * meta_display_get_workspaces: (skip)
- * @display: a #MetaDisplay
- *
- * Returns: (transfer none) (element-type Meta.Workspace): The workspaces for @display
- */
-GList *
-meta_display_get_workspaces (MetaDisplay *display)
-{
-  return display->workspaces;
-}
-
-int
-meta_display_get_active_workspace_index (MetaDisplay *display)
-{
-  MetaWorkspace *active = display->active_workspace;
-
-  if (!active)
-    return -1;
-
-  return meta_workspace_index (active);
-}
-
-/**
- * meta_display_get_active_workspace:
- * @display: A #MetaDisplay
- *
- * Returns: (transfer none): The current workspace
- */
-MetaWorkspace *
-meta_display_get_active_workspace (MetaDisplay *display)
-{
-  return display->active_workspace;
-}
-
 void
 meta_display_focus_default_window (MetaDisplay *display,
                                    guint32      timestamp)
 {
-  meta_workspace_focus_default_window (display->active_workspace,
+  MetaWorkspaceManager *workspace_manager = display->workspace_manager;
+
+  meta_workspace_focus_default_window (workspace_manager->active_workspace,
                                        NULL,
                                        timestamp);
 }
 
-void
-meta_display_workspace_switched (MetaDisplay        *display,
-                                 int                 from,
-                                 int                 to,
-                                 MetaMotionDirection direction)
-{
-  g_signal_emit (display, display_signals[WORKSPACE_SWITCHED], 0,
-                 from, to, direction);
-}
-
 MetaWorkspaceManager *
 meta_display_get_workspace_manager (MetaDisplay *display)
 {
diff --git a/src/core/edge-resistance.c b/src/core/edge-resistance.c
index 245e6ae52..963b365d9 100644
--- a/src/core/edge-resistance.c
+++ b/src/core/edge-resistance.c
@@ -23,6 +23,7 @@
 #include "edge-resistance.h"
 #include "boxes-private.h"
 #include "display-private.h"
+#include "meta-workspace-manager-private.h"
 #include "workspace-private.h"
 
 /* A simple macro for whether a given window's edges are potentially
@@ -999,6 +1000,7 @@ compute_resistance_and_snapping_edges (MetaDisplay *display)
    * in the layer that we are working on
    */
   GSList *rem_windows, *rem_win_stacking;
+  MetaWorkspaceManager *workspace_manager = display->workspace_manager;
 
   g_assert (display->grab_window != NULL);
   meta_topic (META_DEBUG_WINDOW_OPS,
@@ -1010,7 +1012,7 @@ compute_resistance_and_snapping_edges (MetaDisplay *display)
    */
   stacked_windows =
     meta_stack_list_windows (display->stack,
-                             display->active_workspace);
+                             workspace_manager->active_workspace);
 
   /*
    * 2nd: we need to separate that stacked list into a list of windows that
@@ -1172,8 +1174,8 @@ compute_resistance_and_snapping_edges (MetaDisplay *display)
    */
   cache_edges (display,
                edges,
-               display->active_workspace->monitor_edges,
-               display->active_workspace->screen_edges);
+               workspace_manager->active_workspace->monitor_edges,
+               workspace_manager->active_workspace->screen_edges);
   g_list_free (edges);
 
   /*
diff --git a/src/core/keybindings.c b/src/core/keybindings.c
index ebce5396f..3152c8058 100644
--- a/src/core/keybindings.c
+++ b/src/core/keybindings.c
@@ -29,6 +29,7 @@
 
 #include <config.h>
 #include "keybindings-private.h"
+#include "meta-workspace-manager-private.h"
 #include "workspace-private.h"
 #include <meta/compositor.h>
 #include <meta/meta-x11-errors.h>
@@ -2733,8 +2734,9 @@ handle_switch_to_last_workspace (MetaDisplay     *display,
                                  MetaKeyBinding *binding,
                                  gpointer        dummy)
 {
-    gint target = meta_display_get_n_workspaces(display) - 1;
-    MetaWorkspace *workspace = meta_display_get_workspace_by_index (display, target);
+    MetaWorkspaceManager *workspace_manager = display->workspace_manager;
+    gint target = meta_workspace_manager_get_n_workspaces (workspace_manager) - 1;
+    MetaWorkspace *workspace = meta_workspace_manager_get_workspace_by_index (workspace_manager, target);
     meta_workspace_activate (workspace, event->time);
 }
 
@@ -2746,6 +2748,7 @@ handle_switch_to_workspace (MetaDisplay     *display,
                             gpointer         dummy)
 {
   gint which = binding->handler->data;
+  MetaWorkspaceManager *workspace_manager = display->workspace_manager;
   MetaWorkspace *workspace;
 
   if (which < 0)
@@ -2754,12 +2757,12 @@ handle_switch_to_workspace (MetaDisplay     *display,
        * current workspace.
        */
 
-      workspace = meta_workspace_get_neighbor (display->active_workspace,
+      workspace = meta_workspace_get_neighbor (workspace_manager->active_workspace,
                                                which);
     }
   else
     {
-      workspace = meta_display_get_workspace_by_index (display, which);
+      workspace = meta_workspace_manager_get_workspace_by_index (workspace_manager, which);
     }
 
   if (workspace)
@@ -2982,15 +2985,17 @@ handle_show_desktop (MetaDisplay     *display,
                      MetaKeyBinding  *binding,
                      gpointer         dummy)
 {
-  if (display->active_workspace->showing_desktop)
+  MetaWorkspaceManager *workspace_manager = display->workspace_manager;
+
+  if (workspace_manager->active_workspace->showing_desktop)
     {
-      meta_display_unshow_desktop (display);
-      meta_workspace_focus_default_window (display->active_workspace,
+      meta_workspace_manager_unshow_desktop (workspace_manager);
+      meta_workspace_focus_default_window (workspace_manager->active_workspace,
                                            NULL,
                                            event->time);
     }
   else
-    meta_display_show_desktop (display, event->time);
+    meta_workspace_manager_show_desktop (workspace_manager, event->time);
 }
 
 static void
@@ -3077,6 +3082,7 @@ do_choose_window (MetaDisplay     *display,
                   MetaKeyBinding  *binding,
                   gboolean         backward)
 {
+  MetaWorkspaceManager *workspace_manager = display->workspace_manager;
   MetaTabList type = binding->handler->data;
   MetaWindow *window;
 
@@ -3085,7 +3091,7 @@ do_choose_window (MetaDisplay     *display,
 
   window = meta_display_get_tab_next (display,
                                       type,
-                                      display->active_workspace,
+                                      workspace_manager->active_workspace,
                                       NULL,
                                       backward);
 
@@ -3299,14 +3305,15 @@ handle_move_to_workspace_last (MetaDisplay     *display,
                                MetaKeyBinding  *binding,
                                gpointer         dummy)
 {
+  MetaWorkspaceManager *workspace_manager = display->workspace_manager;
   gint which;
   MetaWorkspace *workspace;
 
   if (window->always_sticky)
     return;
 
-  which = meta_display_get_n_workspaces (display) - 1;
-  workspace = meta_display_get_workspace_by_index (display, which);
+  which = meta_workspace_manager_get_n_workspaces (workspace_manager) - 1;
+  workspace = meta_workspace_manager_get_workspace_by_index (workspace_manager, which);
   meta_window_change_workspace (window, workspace);
 }
 
@@ -3318,6 +3325,7 @@ handle_move_to_workspace  (MetaDisplay     *display,
                            MetaKeyBinding  *binding,
                            gpointer         dummy)
 {
+  MetaWorkspaceManager *workspace_manager = display->workspace_manager;
   gint which = binding->handler->data;
   gboolean flip = (which < 0);
   MetaWorkspace *workspace;
@@ -3336,12 +3344,12 @@ handle_move_to_workspace  (MetaDisplay     *display,
   workspace = NULL;
   if (flip)
     {
-      workspace = meta_workspace_get_neighbor (display->active_workspace,
+      workspace = meta_workspace_get_neighbor (workspace_manager->active_workspace,
                                                which);
     }
   else
     {
-      workspace = meta_display_get_workspace_by_index (display, which);
+      workspace = meta_workspace_manager_get_workspace_by_index (workspace_manager, which);
     }
 
   if (workspace)
diff --git a/src/core/meta-workspace-manager-private.h b/src/core/meta-workspace-manager-private.h
index 1dafa5039..261c4d47c 100644
--- a/src/core/meta-workspace-manager-private.h
+++ b/src/core/meta-workspace-manager-private.h
@@ -48,4 +48,49 @@ struct _MetaWorkspaceManager
 
 MetaWorkspaceManager *meta_workspace_manager_new (MetaDisplay *display);
 
+void meta_workspace_manager_init_workspaces         (MetaWorkspaceManager *workspace_manager);
+void meta_workspace_manager_update_workspace_layout (MetaWorkspaceManager *workspace_manager,
+                                                     MetaDisplayCorner     starting_corner,
+                                                     gboolean              vertical_layout,
+                                                     int                   n_rows,
+                                                     int                   n_columns);
+
+void meta_workspace_manager_reload_work_areas (MetaWorkspaceManager *workspace_manager);
+
+typedef struct MetaWorkspaceLayout MetaWorkspaceLayout;
+
+struct MetaWorkspaceLayout
+{
+  int rows;
+  int cols;
+  int *grid;
+  int grid_area;
+  int current_row;
+  int current_col;
+};
+
+void meta_workspace_manager_calc_workspace_layout (MetaWorkspaceManager *workspace_manager,
+                                                   int                   num_workspaces,
+                                                   int                   current_space,
+                                                   MetaWorkspaceLayout  *layout);
+
+void meta_workspace_manager_free_workspace_layout (MetaWorkspaceLayout *layout);
+
+void meta_workspace_manager_minimize_all_on_active_workspace_except (MetaWorkspaceManager *workspace_manager,
+                                                                     MetaWindow           *keep);
+
+/* Show/hide the desktop (temporarily hide all windows) */
+void meta_workspace_manager_show_desktop   (MetaWorkspaceManager *workspace_manager,
+                                            guint32               timestamp);
+void meta_workspace_manager_unshow_desktop (MetaWorkspaceManager *workspace_manager);
+
+void meta_workspace_manager_workspace_switched (MetaWorkspaceManager *workspace_manager,
+                                                int                   from,
+                                                int                   to,
+                                                MetaMotionDirection   direction);
+
+void meta_workspace_manager_update_num_workspaces (MetaWorkspaceManager *workspace_manager,
+                                                   guint32               timestamp,
+                                                   int                   new_num);
+
 #endif /* META_WORKSPACE_MANAGER_PRIVATE_H */
diff --git a/src/core/meta-workspace-manager.c b/src/core/meta-workspace-manager.c
index 0521337e1..2670f4938 100644
--- a/src/core/meta-workspace-manager.c
+++ b/src/core/meta-workspace-manager.c
@@ -28,7 +28,12 @@
 #include <string.h>
 #include <unistd.h>
 
+#include "core/window-private.h"
+#include "core/workspace-private.h"
+
 #include "meta/meta-enum-types.h"
+#include "meta/prefs.h"
+#include "meta/util.h"
 
 G_DEFINE_TYPE (MetaWorkspaceManager, meta_workspace_manager, G_TYPE_OBJECT)
 
@@ -50,6 +55,9 @@ enum {
 
 static guint workspace_manager_signals [LAST_SIGNAL] = { 0 };
 
+static void prefs_changed_callback (MetaPreference pref,
+                                    gpointer       data);
+
 static void
 meta_workspace_manager_get_property (GObject    *object,
                                      guint       prop_id,
@@ -83,6 +91,16 @@ meta_workspace_manager_set_property (GObject      *object,
     }
 }
 
+static void
+meta_workspace_manager_finalize (GObject *object)
+{
+  MetaWorkspaceManager *workspace_manager = META_WORKSPACE_MANAGER (object);
+
+  meta_prefs_remove_listener (prefs_changed_callback, workspace_manager);
+
+  G_OBJECT_CLASS (meta_workspace_manager_parent_class)->finalize (object);
+}
+
 static void
 meta_workspace_manager_class_init (MetaWorkspaceManagerClass *klass)
 {
@@ -91,6 +109,8 @@ meta_workspace_manager_class_init (MetaWorkspaceManagerClass *klass)
   object_class->get_property = meta_workspace_manager_get_property;
   object_class->set_property = meta_workspace_manager_set_property;
 
+  object_class->finalize = meta_workspace_manager_finalize;
+
   workspace_manager_signals[WORKSPACE_ADDED] =
     g_signal_new ("workspace-added",
                   G_TYPE_FROM_CLASS (klass),
@@ -133,6 +153,14 @@ meta_workspace_manager_class_init (MetaWorkspaceManagerClass *klass)
                   G_SIGNAL_RUN_LAST,
                   0, NULL, NULL, NULL,
                   G_TYPE_NONE, 0);
+
+  g_object_class_install_property (object_class,
+                                   PROP_N_WORKSPACES,
+                                   g_param_spec_int ("n-workspaces",
+                                                     "N Workspaces",
+                                                     "Number of workspaces",
+                                                     1, G_MAXINT, 1,
+                                                     G_PARAM_READABLE));
 }
 
 static void
@@ -140,6 +168,19 @@ meta_workspace_manager_init (MetaWorkspaceManager *workspace_manager)
 {
 }
 
+void
+meta_workspace_manager_reload_work_areas (MetaWorkspaceManager *workspace_manager)
+{
+  GList *l;
+
+  for (l = workspace_manager->workspaces; l; l = l->next)
+    {
+      MetaWorkspace *workspace = l->data;
+
+      meta_workspace_invalidate_work_area (workspace);
+    }
+}
+
 MetaWorkspaceManager *
 meta_workspace_manager_new (MetaDisplay *display)
 {
@@ -155,11 +196,756 @@ meta_workspace_manager_new (MetaDisplay *display)
   workspace_manager->vertical_workspaces = FALSE;
   workspace_manager->starting_corner = META_DISPLAY_TOPLEFT;
 
+  /* This is the default layout extracted from default
+   * variable values in update_num_workspaces ()
+   * This can be overriden using _NET_DESKTOP_LAYOUT in
+   * meta_x11_display_new (), if it's specified */
+  meta_workspace_manager_update_workspace_layout (workspace_manager,
+                                                  META_DISPLAY_TOPLEFT,
+                                                  FALSE,
+                                                  -1,
+                                                  1);
+
+  /* There must be at least one workspace at all times,
+   * so create that required workspace.
+   */
+  meta_workspace_new (workspace_manager);
+
+  meta_workspace_manager_init_workspaces (workspace_manager);
+
+  meta_prefs_add_listener (prefs_changed_callback, workspace_manager);
+
   return workspace_manager;
 }
 
+void
+meta_workspace_manager_init_workspaces (MetaWorkspaceManager *workspace_manager)
+{
+  int num;
+
+  g_return_if_fail (META_IS_WORKSPACE_MANAGER (workspace_manager));
+
+  if (meta_prefs_get_dynamic_workspaces ())
+    /* This will be properly updated using _NET_NUMBER_OF_DESKTOPS
+     * (if set) in meta_x11_display_new () */
+    num = 1;
+  else
+    num = meta_prefs_get_num_workspaces ();
+
+  meta_workspace_manager_update_num_workspaces (workspace_manager, META_CURRENT_TIME, num);
+
+  meta_workspace_activate (workspace_manager->workspaces->data, META_CURRENT_TIME);
+
+  meta_workspace_manager_reload_work_areas (workspace_manager);
+}
+
 int
 meta_workspace_manager_get_n_workspaces (MetaWorkspaceManager *workspace_manager)
 {
   return g_list_length (workspace_manager->workspaces);
 }
+
+/**
+ * meta_workspace_manager_get_workspace_by_index:
+ * @workspace_manager: a #MetaWorkspaceManager
+ * @index: index of one of the display's workspaces
+ *
+ * Gets the workspace object for one of a workspace manager's workspaces given the workspace
+ * index. It's valid to call this function with an out-of-range index and it
+ * will robustly return %NULL.
+ *
+ * Return value: (transfer none): the workspace object with specified index, or %NULL
+ *   if the index is out of range.
+ */
+MetaWorkspace *
+meta_workspace_manager_get_workspace_by_index (MetaWorkspaceManager *workspace_manager,
+                                               int                   idx)
+{
+  return g_list_nth_data (workspace_manager->workspaces, idx);
+}
+
+void
+meta_workspace_manager_remove_workspace (MetaWorkspaceManager *workspace_manager,
+                                         MetaWorkspace        *workspace,
+                                         guint32               timestamp)
+{
+  GList *l;
+  GList *next;
+  MetaWorkspace *neighbour = NULL;
+  int index;
+  int active_index;
+  gboolean active_index_changed;
+  int new_num;
+
+  l = g_list_find (workspace_manager->workspaces, workspace);
+  if (!l)
+    return;
+
+  next = l->next;
+
+  if (l->prev)
+    neighbour = l->prev->data;
+  else if (l->next)
+    neighbour = l->next->data;
+  else
+    {
+      /* Cannot remove the only workspace! */
+      return;
+    }
+
+  meta_workspace_relocate_windows (workspace, neighbour);
+
+  if (workspace == workspace_manager->active_workspace)
+    meta_workspace_activate (neighbour, timestamp);
+
+  /* To emit the signal after removing the workspace */
+  index = meta_workspace_index (workspace);
+  active_index = meta_workspace_manager_get_active_workspace_index (workspace_manager);
+  active_index_changed = index < active_index;
+
+  /* This also removes the workspace from the displays list */
+  meta_workspace_remove (workspace);
+
+  new_num = g_list_length (workspace_manager->workspaces);
+
+  if (!meta_prefs_get_dynamic_workspaces ())
+    meta_prefs_set_num_workspaces (new_num);
+
+  /* If deleting a workspace before the current workspace, the active
+   * workspace index changes, so we need to update that hint */
+  if (active_index_changed)
+    g_signal_emit (workspace_manager,
+                   workspace_manager_signals[ACTIVE_WORKSPACE_CHANGED],
+                   0, NULL);
+
+  for (l = next; l; l = l->next)
+    {
+      MetaWorkspace *w = l->data;
+      meta_workspace_index_changed (w);
+    }
+
+  meta_display_queue_workarea_recalc (workspace_manager->display);
+
+  g_signal_emit (workspace_manager,
+                 workspace_manager_signals[WORKSPACE_REMOVED],
+                 0, index);
+  g_object_notify (G_OBJECT (workspace_manager), "n-workspaces");
+}
+
+/**
+ * meta_workspace_manager_append_new_workspace:
+ * @workspace_manager: a #MetaWorkspaceManager
+ * @activate: %TRUE if the workspace should be switched to after creation
+ * @timestamp: if switching to a new workspace, timestamp to be used when
+ *   focusing a window on the new workspace. (Doesn't hurt to pass a valid
+ *   timestamp when available even if not switching workspaces.)
+ *
+ * Append a new workspace to the workspace manager and (optionally) switch to that
+ * display.
+ *
+ * Return value: (transfer none): the newly appended workspace.
+ */
+MetaWorkspace *
+meta_workspace_manager_append_new_workspace (MetaWorkspaceManager *workspace_manager,
+                                             gboolean              activate,
+                                             guint32               timestamp)
+{
+  MetaWorkspace *w;
+  int new_num;
+
+  /* This also adds the workspace to the workspace manager list */
+  w = meta_workspace_new (workspace_manager);
+
+  if (!w)
+    return NULL;
+
+  if (activate)
+    meta_workspace_activate (w, timestamp);
+
+  new_num = g_list_length (workspace_manager->workspaces);
+
+  if (!meta_prefs_get_dynamic_workspaces ())
+    meta_prefs_set_num_workspaces (new_num);
+
+  meta_display_queue_workarea_recalc (workspace_manager->display);
+
+  g_signal_emit (workspace_manager, workspace_manager_signals[WORKSPACE_ADDED],
+                 0, meta_workspace_index (w));
+  g_object_notify (G_OBJECT (workspace_manager), "n-workspaces");
+
+  return w;
+}
+
+void
+meta_workspace_manager_update_num_workspaces (MetaWorkspaceManager *workspace_manager,
+                                              guint32               timestamp,
+                                              int                   new_num)
+{
+  int old_num;
+  GList *l;
+  int i = 0;
+  GList *extras = NULL;
+  MetaWorkspace *last_remaining = NULL;
+  gboolean need_change_space = FALSE;
+
+  g_assert (new_num > 0);
+
+  if (g_list_length (workspace_manager->workspaces) == (guint) new_num)
+    return;
+
+  for (l = workspace_manager->workspaces; l; l = l->next)
+    {
+      MetaWorkspace *w = l->data;
+
+      if (i >= new_num)
+        extras = g_list_prepend (extras, w);
+      else
+        last_remaining = w;
+
+      ++i;
+    }
+  old_num = i;
+
+  g_assert (last_remaining);
+
+  /* Get rid of the extra workspaces by moving all their windows
+   * to last_remaining, then activating last_remaining if
+   * one of the removed workspaces was active. This will be a bit
+   * wacky if the config tool for changing number of workspaces
+   * is on a removed workspace ;-)
+   */
+  for (l = extras; l; l = l->next)
+    {
+      MetaWorkspace *w = l->data;
+
+      meta_workspace_relocate_windows (w, last_remaining);
+
+      if (w == workspace_manager->active_workspace)
+        need_change_space = TRUE;
+    }
+
+  if (need_change_space)
+    meta_workspace_activate (last_remaining, timestamp);
+
+  /* Should now be safe to free the workspaces */
+  for (l = extras; l; l = l->next)
+    {
+      MetaWorkspace *w = l->data;
+
+      meta_workspace_remove (w);
+    }
+
+  g_list_free (extras);
+
+  for (i = old_num; i < new_num; i++)
+    meta_workspace_new (workspace_manager);
+
+  meta_display_queue_workarea_recalc (workspace_manager->display);
+
+  for (i = old_num; i < new_num; i++)
+    g_signal_emit (workspace_manager,
+                   workspace_manager_signals[WORKSPACE_ADDED],
+                   0, i);
+
+  g_object_notify (G_OBJECT (workspace_manager), "n-workspaces");
+}
+
+void
+meta_workspace_manager_update_workspace_layout (MetaWorkspaceManager *workspace_manager,
+                                                MetaDisplayCorner     starting_corner,
+                                                gboolean              vertical_layout,
+                                                int                   n_rows,
+                                                int                   n_columns)
+{
+  g_return_if_fail (META_IS_WORKSPACE_MANAGER (workspace_manager));
+  g_return_if_fail (n_rows > 0 || n_columns > 0);
+  g_return_if_fail (n_rows != 0 && n_columns != 0);
+
+  if (workspace_manager->workspace_layout_overridden)
+    return;
+
+  workspace_manager->vertical_workspaces = vertical_layout != FALSE;
+  workspace_manager->starting_corner = starting_corner;
+  workspace_manager->rows_of_workspaces = n_rows;
+  workspace_manager->columns_of_workspaces = n_columns;
+
+  meta_verbose ("Workspace layout rows = %d cols = %d orientation = %d starting corner = %u\n",
+                workspace_manager->rows_of_workspaces,
+                workspace_manager->columns_of_workspaces,
+                workspace_manager->vertical_workspaces,
+                workspace_manager->starting_corner);
+}
+
+/**
+ * meta_workspace_manager_override_workspace_layout:
+ * @workspace_manager: a #MetaWorkspaceManager
+ * @starting_corner: the corner at which the first workspace is found
+ * @vertical_layout: if %TRUE the workspaces are laid out in columns rather than rows
+ * @n_rows: number of rows of workspaces, or -1 to determine the number of rows from
+ *   @n_columns and the total number of workspaces
+ * @n_columns: number of columns of workspaces, or -1 to determine the number of columns from
+ *   @n_rows and the total number of workspaces
+ *
+ * Explicitly set the layout of workspaces. Once this has been called, the contents of the
+ * _NET_DESKTOP_LAYOUT property on the root window are completely ignored.
+ */
+void
+meta_workspace_manager_override_workspace_layout (MetaWorkspaceManager *workspace_manager,
+                                                  MetaDisplayCorner     starting_corner,
+                                                  gboolean              vertical_layout,
+                                                  int                   n_rows,
+                                                  int                   n_columns)
+{
+  meta_workspace_manager_update_workspace_layout (workspace_manager,
+                                                  starting_corner,
+                                                  vertical_layout,
+                                                  n_rows,
+                                                  n_columns);
+
+  workspace_manager->workspace_layout_overridden = TRUE;
+}
+
+#ifdef WITH_VERBOSE_MODE
+static const char *
+meta_workspace_manager_corner_to_string (MetaDisplayCorner corner)
+{
+  switch (corner)
+    {
+    case META_DISPLAY_TOPLEFT:
+      return "TopLeft";
+    case META_DISPLAY_TOPRIGHT:
+      return "TopRight";
+    case META_DISPLAY_BOTTOMLEFT:
+      return "BottomLeft";
+    case META_DISPLAY_BOTTOMRIGHT:
+      return "BottomRight";
+    }
+
+  return "Unknown";
+}
+#endif /* WITH_VERBOSE_MODE */
+
+void
+meta_workspace_manager_calc_workspace_layout (MetaWorkspaceManager *workspace_manager,
+                                              int                   num_workspaces,
+                                              int                   current_space,
+                                              MetaWorkspaceLayout  *layout)
+{
+  int rows, cols;
+  int grid_area;
+  int *grid;
+  int i, r, c;
+  int current_row, current_col;
+
+  rows = workspace_manager->rows_of_workspaces;
+  cols = workspace_manager->columns_of_workspaces;
+  if (rows <= 0 && cols <= 0)
+    cols = num_workspaces;
+
+  if (rows <= 0)
+    rows = num_workspaces / cols + ((num_workspaces % cols) > 0 ? 1 : 0);
+  if (cols <= 0)
+    cols = num_workspaces / rows + ((num_workspaces % rows) > 0 ? 1 : 0);
+
+  /* paranoia */
+  if (rows < 1)
+    rows = 1;
+  if (cols < 1)
+    cols = 1;
+
+  g_assert (rows != 0 && cols != 0);
+
+  grid_area = rows * cols;
+
+  meta_verbose ("Getting layout rows = %d cols = %d current = %d "
+                "num_spaces = %d vertical = %s corner = %s\n",
+                rows, cols, current_space, num_workspaces,
+                workspace_manager->vertical_workspaces ? "(true)" : "(false)",
+                meta_workspace_manager_corner_to_string (workspace_manager->starting_corner));
+
+  /* ok, we want to setup the distances in the workspace array to go
+   * in each direction. Remember, there are many ways that a workspace
+   * array can be setup.
+   * see http://www.freedesktop.org/standards/wm-spec/1.2/html/x109.html
+   * and look at the _NET_DESKTOP_LAYOUT section for details.
+   * For instance:
+   */
+  /* starting_corner = META_DISPLAY_TOPLEFT
+   *  vertical_workspaces = 0                 vertical_workspaces=1
+   *       1234                                    1357
+   *       5678                                    2468
+   *
+   * starting_corner = META_DISPLAY_TOPRIGHT
+   *  vertical_workspaces = 0                 vertical_workspaces=1
+   *       4321                                    7531
+   *       8765                                    8642
+   *
+   * starting_corner = META_DISPLAY_BOTTOMLEFT
+   *  vertical_workspaces = 0                 vertical_workspaces=1
+   *       5678                                    2468
+   *       1234                                    1357
+   *
+   * starting_corner = META_DISPLAY_BOTTOMRIGHT
+   *  vertical_workspaces = 0                 vertical_workspaces=1
+   *       8765                                    8642
+   *       4321                                    7531
+   *
+   */
+  /* keep in mind that we could have a ragged layout, e.g. the "8"
+   * in the above grids could be missing
+   */
+
+
+  grid = g_new (int, grid_area);
+
+  current_row = -1;
+  current_col = -1;
+  i = 0;
+
+  switch (workspace_manager->starting_corner)
+    {
+    case META_DISPLAY_TOPLEFT:
+      if (workspace_manager->vertical_workspaces)
+        {
+          c = 0;
+          while (c < cols)
+            {
+              r = 0;
+              while (r < rows)
+                {
+                  grid[r*cols+c] = i;
+                  ++i;
+                  ++r;
+                }
+              ++c;
+            }
+        }
+      else
+        {
+          r = 0;
+          while (r < rows)
+            {
+              c = 0;
+              while (c < cols)
+                {
+                  grid[r*cols+c] = i;
+                  ++i;
+                  ++c;
+                }
+              ++r;
+            }
+        }
+      break;
+    case META_DISPLAY_TOPRIGHT:
+      if (workspace_manager->vertical_workspaces)
+        {
+          c = cols - 1;
+          while (c >= 0)
+            {
+              r = 0;
+              while (r < rows)
+                {
+                  grid[r*cols+c] = i;
+                  ++i;
+                  ++r;
+                }
+              --c;
+            }
+        }
+      else
+        {
+          r = 0;
+          while (r < rows)
+            {
+              c = cols - 1;
+              while (c >= 0)
+                {
+                  grid[r*cols+c] = i;
+                  ++i;
+                  --c;
+                }
+              ++r;
+            }
+        }
+      break;
+    case META_DISPLAY_BOTTOMLEFT:
+      if (workspace_manager->vertical_workspaces)
+        {
+          c = 0;
+          while (c < cols)
+            {
+              r = rows - 1;
+              while (r >= 0)
+                {
+                  grid[r*cols+c] = i;
+                  ++i;
+                  --r;
+                }
+              ++c;
+            }
+        }
+      else
+        {
+          r = rows - 1;
+          while (r >= 0)
+            {
+              c = 0;
+              while (c < cols)
+                {
+                  grid[r*cols+c] = i;
+                  ++i;
+                  ++c;
+                }
+              --r;
+            }
+        }
+      break;
+    case META_DISPLAY_BOTTOMRIGHT:
+      if (workspace_manager->vertical_workspaces)
+        {
+          c = cols - 1;
+          while (c >= 0)
+            {
+              r = rows - 1;
+              while (r >= 0)
+                {
+                  grid[r*cols+c] = i;
+                  ++i;
+                  --r;
+                }
+              --c;
+            }
+        }
+      else
+        {
+          r = rows - 1;
+          while (r >= 0)
+            {
+              c = cols - 1;
+              while (c >= 0)
+                {
+                  grid[r*cols+c] = i;
+                  ++i;
+                  --c;
+                }
+              --r;
+            }
+        }
+      break;
+    }
+
+  if (i != grid_area)
+    meta_bug ("did not fill in the whole workspace grid in %s (%d filled)\n",
+              G_STRFUNC, i);
+
+  current_row = 0;
+  current_col = 0;
+  r = 0;
+  while (r < rows)
+    {
+      c = 0;
+      while (c < cols)
+        {
+          if (grid[r*cols+c] == current_space)
+            {
+              current_row = r;
+              current_col = c;
+            }
+          else if (grid[r*cols+c] >= num_workspaces)
+            {
+              /* flag nonexistent spaces with -1 */
+              grid[r*cols+c] = -1;
+            }
+          ++c;
+        }
+      ++r;
+    }
+
+  layout->rows = rows;
+  layout->cols = cols;
+  layout->grid = grid;
+  layout->grid_area = grid_area;
+  layout->current_row = current_row;
+  layout->current_col = current_col;
+
+#ifdef WITH_VERBOSE_MODE
+  if (meta_is_verbose ())
+    {
+      r = 0;
+      while (r < layout->rows)
+        {
+          meta_verbose (" ");
+          meta_push_no_msg_prefix ();
+          c = 0;
+          while (c < layout->cols)
+            {
+              if (r == layout->current_row &&
+                  c == layout->current_col)
+                meta_verbose ("*%2d ", layout->grid[r*layout->cols+c]);
+              else
+                meta_verbose ("%3d ", layout->grid[r*layout->cols+c]);
+              ++c;
+            }
+          meta_verbose ("\n");
+          meta_pop_no_msg_prefix ();
+          ++r;
+        }
+    }
+#endif /* WITH_VERBOSE_MODE */
+}
+
+void
+meta_workspace_manager_free_workspace_layout (MetaWorkspaceLayout *layout)
+{
+  g_free (layout->grid);
+}
+
+static void
+queue_windows_showing (MetaWorkspaceManager *workspace_manager)
+{
+  GSList *windows, *l;
+
+  /* Must operate on all windows on display instead of just on the
+   * active_workspace's window list, because the active_workspace's
+   * window list may not contain the on_all_workspace windows.
+   */
+  windows = meta_display_list_windows (workspace_manager->display, META_LIST_DEFAULT);
+
+  for (l = windows; l; l = l->next)
+    {
+      MetaWindow *w = l->data;
+
+      meta_window_queue (w, META_QUEUE_CALC_SHOWING);
+    }
+
+  g_slist_free (windows);
+}
+
+void
+meta_workspace_manager_minimize_all_on_active_workspace_except (MetaWorkspaceManager *workspace_manager,
+                                                                MetaWindow           *keep)
+{
+  GList *l;
+
+  for (l = workspace_manager->active_workspace->windows; l; l = l->next)
+    {
+      MetaWindow *w = l->data;
+
+      if (w->has_minimize_func && w != keep)
+        meta_window_minimize (w);
+    }
+}
+
+void
+meta_workspace_manager_show_desktop (MetaWorkspaceManager *workspace_manager,
+                                     guint32               timestamp)
+{
+  GList *l;
+
+  if (workspace_manager->active_workspace->showing_desktop)
+    return;
+
+  workspace_manager->active_workspace->showing_desktop = TRUE;
+
+  queue_windows_showing (workspace_manager);
+
+  /* Focus the most recently used META_WINDOW_DESKTOP window, if there is one;
+   * see bug 159257.
+   */
+  for (l = workspace_manager->active_workspace->mru_list; l; l = l->next)
+    {
+      MetaWindow *w = l->data;
+
+      if (w->type == META_WINDOW_DESKTOP)
+        {
+          meta_window_focus (w, timestamp);
+          break;
+        }
+    }
+
+  g_signal_emit (workspace_manager,
+                 workspace_manager_signals[SHOWING_DESKTOP_CHANGED],
+                 0, NULL);
+}
+
+void
+meta_workspace_manager_unshow_desktop (MetaWorkspaceManager *workspace_manager)
+{
+  if (!workspace_manager->active_workspace->showing_desktop)
+    return;
+
+  workspace_manager->active_workspace->showing_desktop = FALSE;
+
+  queue_windows_showing (workspace_manager);
+
+  g_signal_emit (workspace_manager,
+                 workspace_manager_signals[SHOWING_DESKTOP_CHANGED],
+                 0, NULL);
+}
+
+/**
+ * meta_workspace_manager_get_workspaces: (skip)
+ * @workspace_manager: a #MetaWorkspaceManager
+ *
+ * Returns: (transfer none) (element-type Meta.Workspace): The workspaces for @display
+ */
+GList *
+meta_workspace_manager_get_workspaces (MetaWorkspaceManager *workspace_manager)
+{
+  return workspace_manager->workspaces;
+}
+
+int
+meta_workspace_manager_get_active_workspace_index (MetaWorkspaceManager *workspace_manager)
+{
+  MetaWorkspace *active = workspace_manager->active_workspace;
+
+  if (!active)
+    return -1;
+
+  return meta_workspace_index (active);
+}
+
+/**
+ * meta_workspace_manager_get_active_workspace:
+ * @workspace_manager: A #MetaWorkspaceManager
+ *
+ * Returns: (transfer none): The current workspace
+ */
+MetaWorkspace *
+meta_workspace_manager_get_active_workspace (MetaWorkspaceManager *workspace_manager)
+{
+  return workspace_manager->active_workspace;
+}
+
+void 
+meta_workspace_manager_workspace_switched (MetaWorkspaceManager *workspace_manager,
+                                           int                   from,
+                                           int                   to,
+                                           MetaMotionDirection   direction)
+{
+  g_signal_emit (workspace_manager,
+                 workspace_manager_signals[WORKSPACE_SWITCHED], 0,
+                 from, to, direction);
+}
+
+static void
+prefs_changed_callback (MetaPreference pref,
+                        gpointer       data)
+{
+  MetaWorkspaceManager *workspace_manager = data;
+
+  if ((pref == META_PREF_NUM_WORKSPACES ||
+       pref == META_PREF_DYNAMIC_WORKSPACES) &&
+      !meta_prefs_get_dynamic_workspaces ())
+    {
+      guint32 timestamp;
+      int new_num;
+
+      timestamp =
+        meta_display_get_current_time_roundtrip (workspace_manager->display);
+      new_num = meta_prefs_get_num_workspaces ();
+      meta_workspace_manager_update_num_workspaces (workspace_manager,
+                                                    timestamp, new_num);
+    }
+}
diff --git a/src/core/stack.c b/src/core/stack.c
index a7484c5d2..c00e86c76 100644
--- a/src/core/stack.c
+++ b/src/core/stack.c
@@ -27,6 +27,7 @@
 
 #include <config.h>
 #include "stack.h"
+#include "meta-workspace-manager-private.h"
 #include "window-private.h"
 #include <meta/meta-x11-errors.h>
 #include "frame.h"
@@ -101,6 +102,8 @@ void
 meta_stack_add (MetaStack  *stack,
                 MetaWindow *window)
 {
+  MetaWorkspaceManager *workspace_manager = window->display->workspace_manager;
+
   g_return_if_fail (meta_window_is_stackable (window));
 
   meta_topic (META_DEBUG_STACK, "Adding window %s to the stack\n", window->desc);
@@ -117,13 +120,15 @@ meta_stack_add (MetaStack  *stack,
               window->desc, window->stack_position);
 
   stack_sync_to_xserver (stack);
-  meta_stack_update_window_tile_matches (stack, window->display->active_workspace);
+  meta_stack_update_window_tile_matches (stack, workspace_manager->active_workspace);
 }
 
 void
 meta_stack_remove (MetaStack  *stack,
                    MetaWindow *window)
 {
+  MetaWorkspaceManager *workspace_manager = window->display->workspace_manager;
+
   meta_topic (META_DEBUG_STACK, "Removing window %s from the stack\n", window->desc);
 
   /* Set window to top position, so removing it will not leave gaps
@@ -153,27 +158,29 @@ meta_stack_remove (MetaStack  *stack,
     }
 
   stack_sync_to_xserver (stack);
-  meta_stack_update_window_tile_matches (stack, window->display->active_workspace);
+  meta_stack_update_window_tile_matches (stack, workspace_manager->active_workspace);
 }
 
 void
 meta_stack_update_layer (MetaStack  *stack,
                          MetaWindow *window)
 {
+  MetaWorkspaceManager *workspace_manager = window->display->workspace_manager;
   stack->need_relayer = TRUE;
 
   stack_sync_to_xserver (stack);
-  meta_stack_update_window_tile_matches (stack, window->display->active_workspace);
+  meta_stack_update_window_tile_matches (stack, workspace_manager->active_workspace);
 }
 
 void
 meta_stack_update_transient (MetaStack  *stack,
                              MetaWindow *window)
 {
+  MetaWorkspaceManager *workspace_manager = window->display->workspace_manager;
   stack->need_constrain = TRUE;
 
   stack_sync_to_xserver (stack);
-  meta_stack_update_window_tile_matches (stack, window->display->active_workspace);
+  meta_stack_update_window_tile_matches (stack, workspace_manager->active_workspace);
 }
 
 /* raise/lower within a layer */
@@ -181,6 +188,7 @@ void
 meta_stack_raise (MetaStack  *stack,
                   MetaWindow *window)
 {
+  MetaWorkspaceManager *workspace_manager = window->display->workspace_manager;
   GList *l;
   int max_stack_position = window->stack_position;
   MetaWorkspace *workspace;
@@ -202,13 +210,14 @@ meta_stack_raise (MetaStack  *stack,
   meta_window_set_stack_position_no_sync (window, max_stack_position);
 
   stack_sync_to_xserver (stack);
-  meta_stack_update_window_tile_matches (stack, window->display->active_workspace);
+  meta_stack_update_window_tile_matches (stack, workspace_manager->active_workspace);
 }
 
 void
 meta_stack_lower (MetaStack  *stack,
                   MetaWindow *window)
 {
+  MetaWorkspaceManager *workspace_manager = window->display->workspace_manager;
   GList *l;
   int min_stack_position = window->stack_position;
   MetaWorkspace *workspace;
@@ -230,7 +239,7 @@ meta_stack_lower (MetaStack  *stack,
   meta_window_set_stack_position_no_sync (window, min_stack_position);
 
   stack_sync_to_xserver (stack);
-  meta_stack_update_window_tile_matches (stack, window->display->active_workspace);
+  meta_stack_update_window_tile_matches (stack, workspace_manager->active_workspace);
 }
 
 void
@@ -1457,8 +1466,10 @@ void
 meta_window_set_stack_position (MetaWindow *window,
                                 int         position)
 {
+  MetaWorkspaceManager *workspace_manager = window->display->workspace_manager;
+
   meta_window_set_stack_position_no_sync (window, position);
   stack_sync_to_xserver (window->display->stack);
   meta_stack_update_window_tile_matches (window->display->stack,
-                                         window->display->active_workspace);
+                                         workspace_manager->active_workspace);
 }
diff --git a/src/core/window.c b/src/core/window.c
index 3335c9bdf..3322ffb0f 100644
--- a/src/core/window.c
+++ b/src/core/window.c
@@ -33,6 +33,7 @@
 #include "util-private.h"
 #include "frame.h"
 #include <meta/meta-x11-errors.h>
+#include "meta-workspace-manager-private.h"
 #include "workspace-private.h"
 #include "stack.h"
 #include "keybindings-private.h"
@@ -687,9 +688,10 @@ is_desktop_or_dock_foreach (MetaWindow *window,
 static void
 maybe_leave_show_desktop_mode (MetaWindow *window)
 {
+  MetaWorkspaceManager *workspace_manager = window->display->workspace_manager;
   gboolean is_desktop_or_dock;
 
-  if (!window->display->active_workspace->showing_desktop)
+  if (!workspace_manager->active_workspace->showing_desktop)
     return;
 
   /* If the window is a transient for the dock or desktop, don't
@@ -706,9 +708,9 @@ maybe_leave_show_desktop_mode (MetaWindow *window)
 
   if (!is_desktop_or_dock)
     {
-      meta_display_minimize_all_on_active_workspace_except (window->display,
-                                                            window);
-      meta_display_unshow_desktop (window->display);
+      meta_workspace_manager_minimize_all_on_active_workspace_except (workspace_manager,
+                                                                      window);
+      meta_workspace_manager_unshow_desktop (workspace_manager);
     }
 }
 
@@ -929,6 +931,7 @@ _meta_window_shared_new (MetaDisplay         *display,
                          MetaCompEffect       effect,
                          XWindowAttributes   *attrs)
 {
+  MetaWorkspaceManager *workspace_manager = display->workspace_manager;
   MetaWindow *window;
 
   g_assert (attrs != NULL);
@@ -1238,8 +1241,8 @@ _meta_window_shared_new (MetaDisplay         *display,
                       "Window %s is initially on space %d\n",
                       window->desc, window->initial_workspace);
 
-          workspace = meta_display_get_workspace_by_index (window->display,
-                                                           window->initial_workspace);
+          workspace = meta_workspace_manager_get_workspace_by_index (workspace_manager,
+                                                                     window->initial_workspace);
         }
 
       set_workspace_state (window, on_all_workspaces, workspace);
@@ -1278,7 +1281,7 @@ _meta_window_shared_new (MetaDisplay         *display,
                       "Putting window %s on active workspace\n",
                       window->desc);
 
-          set_workspace_state (window, FALSE, window->display->active_workspace);
+          set_workspace_state (window, FALSE, workspace_manager->active_workspace);
         }
 
       meta_window_update_struts (window);
@@ -1378,6 +1381,7 @@ void
 meta_window_unmanage (MetaWindow  *window,
                       guint32      timestamp)
 {
+  MetaWorkspaceManager *workspace_manager = window->display->workspace_manager;
   GList *tmp;
 
   meta_verbose ("Unmanaging %s\n", window->desc);
@@ -1464,7 +1468,7 @@ meta_window_unmanage (MetaWindow  *window,
       meta_topic (META_DEBUG_FOCUS,
                   "Focusing default window since we're unmanaging %s\n",
                   window->desc);
-      meta_workspace_focus_default_window (window->display->active_workspace, NULL, timestamp);
+      meta_workspace_focus_default_window (workspace_manager->active_workspace, NULL, timestamp);
     }
   else
     {
@@ -1510,7 +1514,7 @@ meta_window_unmanage (MetaWindow  *window,
   g_assert (window->workspace == NULL);
 
 #ifndef G_DISABLE_CHECKS
-  tmp = window->display->workspaces;
+  tmp = workspace_manager->workspaces;
   while (tmp != NULL)
     {
       MetaWorkspace *workspace = tmp->data;
@@ -1622,6 +1626,7 @@ ancestor_is_minimized (MetaWindow *window)
 gboolean
 meta_window_showing_on_its_workspace (MetaWindow *window)
 {
+  MetaWorkspaceManager *workspace_manager = window->display->workspace_manager;
   gboolean showing;
   gboolean is_desktop_or_dock;
   MetaWorkspace* workspace_of_window;
@@ -1641,7 +1646,7 @@ meta_window_showing_on_its_workspace (MetaWindow *window)
                                 &is_desktop_or_dock);
 
   if (window->on_all_workspaces)
-    workspace_of_window = window->display->active_workspace;
+    workspace_of_window = workspace_manager->active_workspace;
   else if (window->workspace)
     workspace_of_window = window->workspace;
   else /* This only seems to be needed for startup */
@@ -1673,6 +1678,8 @@ meta_window_showing_on_its_workspace (MetaWindow *window)
 gboolean
 meta_window_should_be_showing (MetaWindow  *window)
 {
+  MetaWorkspaceManager *workspace_manager = window->display->workspace_manager;
+
 #ifdef HAVE_WAYLAND
   if (window->client_type == META_WINDOW_CLIENT_TYPE_WAYLAND &&
       !meta_wayland_surface_get_buffer (window->surface))
@@ -1681,7 +1688,7 @@ meta_window_should_be_showing (MetaWindow  *window)
 
   /* Windows should be showing if they're located on the
    * active workspace and they're showing on their own workspace. */
-  return (meta_window_located_on_workspace (window, window->display->active_workspace) &&
+  return (meta_window_located_on_workspace (window, workspace_manager->active_workspace) &&
           meta_window_showing_on_its_workspace (window));
 }
 
@@ -2551,6 +2558,7 @@ meta_window_show (MetaWindow *window)
 static void
 meta_window_hide (MetaWindow *window)
 {
+  MetaWorkspaceManager *workspace_manager = window->display->workspace_manager;
   gboolean did_hide;
 
   meta_topic (META_DEBUG_WINDOW_STATE,
@@ -2621,11 +2629,11 @@ meta_window_hide (MetaWindow *window)
        * We also pass in NULL if we are in the process of hiding all non-desktop
        * windows to avoid unexpected changes to the stacking order.
        */
-      if (my_workspace == window->display->active_workspace &&
+      if (my_workspace == workspace_manager->active_workspace &&
           !my_workspace->showing_desktop)
         not_this_one = window;
 
-      meta_workspace_focus_default_window (window->display->active_workspace,
+      meta_workspace_focus_default_window (workspace_manager->active_workspace,
                                            not_this_one,
                                            timestamp);
     }
@@ -3602,6 +3610,7 @@ meta_window_activate_full (MetaWindow     *window,
                            MetaClientType  source_indication,
                            MetaWorkspace  *workspace)
 {
+  MetaWorkspaceManager *workspace_manager = window->display->workspace_manager;
   gboolean allow_workspace_switch;
   meta_topic (META_DEBUG_FOCUS,
               "_NET_ACTIVE_WINDOW message sent for %s at time %u "
@@ -3630,7 +3639,7 @@ meta_window_activate_full (MetaWindow     *window,
 
   /* Get window on current or given workspace */
   if (workspace == NULL)
-    workspace = window->display->active_workspace;
+    workspace = workspace_manager->active_workspace;
 
   /* For non-transient windows, we just set up a pulsing indicator,
      rather than move windows or workspaces.
@@ -3839,6 +3848,7 @@ void
 meta_window_update_monitor (MetaWindow *window,
                             gboolean    user_op)
 {
+  MetaWorkspaceManager *workspace_manager = window->display->workspace_manager;
   const MetaLogicalMonitor *old;
 
   old = window->monitor;
@@ -3858,8 +3868,8 @@ meta_window_update_monitor (MetaWindow *window,
        */
       if (meta_prefs_get_workspaces_only_on_primary () && user_op &&
           meta_window_is_on_primary_monitor (window)  &&
-          window->display->active_workspace != window->workspace)
-        meta_window_change_workspace (window, window->display->active_workspace);
+          workspace_manager->active_workspace != window->workspace)
+        meta_window_change_workspace (window, workspace_manager->active_workspace);
 
       meta_window_main_monitor_changed (window, old);
 
@@ -3894,6 +3904,7 @@ meta_window_move_resize_internal (MetaWindow          *window,
    * to the client.
    */
 
+  MetaWorkspaceManager *workspace_manager = window->display->workspace_manager;
   gboolean did_placement;
   MetaRectangle unconstrained_rect;
   MetaRectangle constrained_rect;
@@ -4025,7 +4036,7 @@ meta_window_move_resize_internal (MetaWindow          *window,
   meta_window_foreach_transient (window, maybe_move_attached_dialog, NULL);
 
   meta_stack_update_window_tile_matches (window->display->stack,
-                                         window->display->active_workspace);
+                                         workspace_manager->active_workspace);
 }
 
 /**
@@ -4605,6 +4616,7 @@ void
 meta_window_focus (MetaWindow  *window,
                    guint32      timestamp)
 {
+  MetaWorkspaceManager *workspace_manager = window->display->workspace_manager;
   MetaWindow *modal_transient;
 
   g_return_if_fail (!window->override_redirect);
@@ -4631,8 +4643,8 @@ meta_window_focus (MetaWindow  *window,
       meta_topic (META_DEBUG_FOCUS,
                   "%s has %s as a modal transient, so focusing it instead.\n",
                   window->desc, modal_transient->desc);
-      if (!meta_window_located_on_workspace (modal_transient, window->display->active_workspace))
-        meta_window_change_workspace (modal_transient, window->display->active_workspace);
+      if (!meta_window_located_on_workspace (modal_transient, workspace_manager->active_workspace))
+        meta_window_change_workspace (modal_transient, workspace_manager->active_workspace);
       window = modal_transient;
     }
 
@@ -4682,6 +4694,8 @@ set_workspace_state (MetaWindow    *window,
                      gboolean       on_all_workspaces,
                      MetaWorkspace *workspace)
 {
+  MetaWorkspaceManager *workspace_manager = window->display->workspace_manager;
+
   /* If we're on all workspaces, then our new workspace must be NULL. */
   if (on_all_workspaces)
     g_assert (workspace == NULL);
@@ -4703,7 +4717,7 @@ set_workspace_state (MetaWindow    *window,
   else if (window->on_all_workspaces)
     {
       GList *l;
-      for (l = window->display->workspaces; l != NULL; l = l->next)
+      for (l = workspace_manager->workspaces; l != NULL; l = l->next)
         {
           MetaWorkspace *ws = l->data;
           meta_workspace_remove_window (ws, window);
@@ -4718,7 +4732,7 @@ set_workspace_state (MetaWindow    *window,
   else if (window->on_all_workspaces)
     {
       GList *l;
-      for (l = window->display->workspaces; l != NULL; l = l->next)
+      for (l = workspace_manager->workspaces; l != NULL; l = l->next)
         {
           MetaWorkspace *ws = l->data;
           meta_workspace_add_window (ws, window);
@@ -4760,6 +4774,7 @@ should_be_on_all_workspaces (MetaWindow *window)
 void
 meta_window_on_all_workspaces_changed (MetaWindow *window)
 {
+  MetaWorkspaceManager *workspace_manager = window->display->workspace_manager;
   gboolean on_all_workspaces = should_be_on_all_workspaces (window);
 
   if (window->on_all_workspaces == on_all_workspaces)
@@ -4775,7 +4790,7 @@ meta_window_on_all_workspaces_changed (MetaWindow *window)
     {
       /* We're coming out of the sticky state. Put the window on
        * the currently active workspace. */
-      workspace = window->display->active_workspace;
+      workspace = workspace_manager->active_workspace;
     }
 
   set_workspace_state (window, on_all_workspaces, workspace);
@@ -4998,6 +5013,7 @@ meta_window_change_workspace_by_index (MetaWindow *window,
                                        gint        space_index,
                                        gboolean    append)
 {
+  MetaWorkspaceManager *workspace_manager;
   MetaWorkspace *workspace;
   MetaDisplay   *display;
 
@@ -5010,12 +5026,13 @@ meta_window_change_workspace_by_index (MetaWindow *window,
     }
 
   display = window->display;
+  workspace_manager = display->workspace_manager;
 
   workspace =
-    meta_display_get_workspace_by_index (display, space_index);
+    meta_workspace_manager_get_workspace_by_index (workspace_manager, space_index);
 
   if (!workspace && append)
-    workspace = meta_display_append_new_workspace (display, FALSE, META_CURRENT_TIME);
+    workspace = meta_workspace_manager_append_new_workspace (workspace_manager, FALSE, META_CURRENT_TIME);
 
   if (workspace)
     meta_window_change_workspace (window, workspace);
@@ -5115,6 +5132,8 @@ void
 meta_window_set_focused_internal (MetaWindow *window,
                                   gboolean    focused)
 {
+  MetaWorkspaceManager *workspace_manager = window->display->workspace_manager;
+
   if (focused)
     {
       window->has_focus = TRUE;
@@ -5129,22 +5148,22 @@ meta_window_set_focused_internal (MetaWindow *window,
        * list only if the window is actually on the active
        * workspace.
        */
-      if (window->display->active_workspace &&
+      if (workspace_manager->active_workspace &&
           meta_window_located_on_workspace (window,
-                                            window->display->active_workspace))
+                                            workspace_manager->active_workspace))
         {
           GList* link;
-          link = g_list_find (window->display->active_workspace->mru_list,
+          link = g_list_find (workspace_manager->active_workspace->mru_list,
                               window);
           g_assert (link);
 
-          window->display->active_workspace->mru_list =
-            g_list_remove_link (window->display->active_workspace->mru_list,
+          workspace_manager->active_workspace->mru_list =
+            g_list_remove_link (workspace_manager->active_workspace->mru_list,
                                 link);
           g_list_free (link);
 
-          window->display->active_workspace->mru_list =
-            g_list_prepend (window->display->active_workspace->mru_list,
+          workspace_manager->active_workspace->mru_list =
+            g_list_prepend (workspace_manager->active_workspace->mru_list,
                             window);
         }
 
@@ -5387,8 +5406,10 @@ idle_update_icon (gpointer data)
 GList*
 meta_window_get_workspaces (MetaWindow *window)
 {
+  MetaWorkspaceManager *workspace_manager = window->display->workspace_manager;
+
   if (window->on_all_workspaces)
-    return window->display->workspaces;
+    return workspace_manager->workspaces;
   else if (window->workspace != NULL)
     return window->workspace->list_containing_self;
   else if (window->constructing)
@@ -5745,6 +5766,7 @@ meta_window_show_menu_for_rect (MetaWindow         *window,
 void
 meta_window_shove_titlebar_onscreen (MetaWindow *window)
 {
+  MetaWorkspaceManager *workspace_manager = window->display->workspace_manager;
   MetaRectangle  frame_rect;
   GList         *onscreen_region;
   int            horiz_amount, vert_amount;
@@ -5757,7 +5779,7 @@ meta_window_shove_titlebar_onscreen (MetaWindow *window)
 
   /* Get the basic info we need */
   meta_window_get_frame_rect (window, &frame_rect);
-  onscreen_region = window->display->active_workspace->screen_region;
+  onscreen_region = workspace_manager->active_workspace->screen_region;
 
   /* Extend the region (just in case the window is too big to fit on the
    * screen), then shove the window on screen, then return the region to
@@ -5785,6 +5807,7 @@ meta_window_shove_titlebar_onscreen (MetaWindow *window)
 gboolean
 meta_window_titlebar_is_onscreen (MetaWindow *window)
 {
+  MetaWorkspaceManager *workspace_manager = window->display->workspace_manager;
   MetaRectangle  titlebar_rect, frame_rect;
   GList         *onscreen_region;
   gboolean       is_onscreen;
@@ -5809,7 +5832,7 @@ meta_window_titlebar_is_onscreen (MetaWindow *window)
    * them overlaps with the titlebar sufficiently to consider it onscreen.
    */
   is_onscreen = FALSE;
-  onscreen_region = window->display->active_workspace->screen_region;
+  onscreen_region = workspace_manager->active_workspace->screen_region;
   while (onscreen_region)
     {
       MetaRectangle *spanning_rect = onscreen_region->data;
@@ -6882,11 +6905,12 @@ ensure_mru_position_after (MetaWindow *window,
    * map.
    */
 
+  MetaWorkspaceManager *workspace_manager = window->display->workspace_manager;
   GList* active_mru_list;
   GList* window_position;
   GList* after_this_one_position;
 
-  active_mru_list         = window->display->active_workspace->mru_list;
+  active_mru_list         = workspace_manager->active_workspace->mru_list;
   window_position         = g_list_find (active_mru_list, window);
   after_this_one_position = g_list_find (active_mru_list, after_this_one);
 
@@ -6899,12 +6923,12 @@ ensure_mru_position_after (MetaWindow *window,
 
   if (g_list_length (window_position) > g_list_length (after_this_one_position))
     {
-      window->display->active_workspace->mru_list =
-        g_list_delete_link (window->display->active_workspace->mru_list,
+      workspace_manager->active_workspace->mru_list =
+        g_list_delete_link (workspace_manager->active_workspace->mru_list,
                             window_position);
 
-      window->display->active_workspace->mru_list =
-        g_list_insert_before (window->display->active_workspace->mru_list,
+      workspace_manager->active_workspace->mru_list =
+        g_list_insert_before (workspace_manager->active_workspace->mru_list,
                               after_this_one_position->next,
                               window);
     }
@@ -7052,12 +7076,13 @@ meta_window_get_stable_sequence (MetaWindow *window)
 void
 meta_window_set_demands_attention (MetaWindow *window)
 {
+  MetaWorkspaceManager *workspace_manager = window->display->workspace_manager;
   MetaRectangle candidate_rect, other_rect;
   GList *stack = window->display->stack->sorted;
   MetaWindow *other_window;
   gboolean obscured = FALSE;
 
-  MetaWorkspace *workspace = window->display->active_workspace;
+  MetaWorkspace *workspace = workspace_manager->active_workspace;
 
   if (window->wm_state_demands_attention)
     return;
@@ -7243,8 +7268,10 @@ meta_window_get_window_type (MetaWindow *window)
 MetaWorkspace *
 meta_window_get_workspace (MetaWindow *window)
 {
+  MetaWorkspaceManager *workspace_manager = window->display->workspace_manager;
+
   if (window->on_all_workspaces)
-    return window->display->active_workspace;
+    return workspace_manager->active_workspace;
   else
     return window->workspace;
 }
diff --git a/src/core/workspace-private.h b/src/core/workspace-private.h
index f63be9550..35d0e705f 100644
--- a/src/core/workspace-private.h
+++ b/src/core/workspace-private.h
@@ -38,6 +38,7 @@ struct _MetaWorkspace
 {
   GObject parent_instance;
   MetaDisplay *display;
+  MetaWorkspaceManager *manager;
 
   GList *windows;
 
@@ -72,7 +73,7 @@ struct _MetaWorkspaceClass
   GObjectClass parent_class;
 };
 
-MetaWorkspace* meta_workspace_new           (MetaDisplay   *display);
+MetaWorkspace* meta_workspace_new           (MetaWorkspaceManager *workspace_manager);
 void           meta_workspace_remove        (MetaWorkspace *workspace);
 void           meta_workspace_add_window    (MetaWorkspace *workspace,
                                              MetaWindow    *window);
diff --git a/src/core/workspace.c b/src/core/workspace.c
index 6e25a44af..e9b693e0b 100644
--- a/src/core/workspace.c
+++ b/src/core/workspace.c
@@ -36,6 +36,7 @@
 #include "backends/meta-logical-monitor.h"
 #include "x11/meta-x11-display-private.h"
 #include <meta/workspace.h>
+#include "meta-workspace-manager-private.h"
 #include "workspace-private.h"
 #include "boxes-private.h"
 #include <meta/meta-x11-errors.h>
@@ -222,17 +223,20 @@ meta_workspace_init (MetaWorkspace *workspace)
 {
 }
 
-MetaWorkspace*
-meta_workspace_new (MetaDisplay *display)
+MetaWorkspace *
+meta_workspace_new (MetaWorkspaceManager *workspace_manager)
 {
+  MetaDisplay *display = workspace_manager->display;
   MetaWorkspace *workspace;
   GSList *windows, *l;
 
   workspace = g_object_new (META_TYPE_WORKSPACE, NULL);
 
   workspace->display = display;
-  workspace->display->workspaces =
-    g_list_append (workspace->display->workspaces, workspace);
+  workspace->manager = workspace_manager;
+
+  workspace_manager->workspaces =
+    g_list_append (workspace_manager->workspaces, workspace);
   workspace->windows = NULL;
   workspace->mru_list = NULL;
 
@@ -319,12 +323,14 @@ assert_workspace_empty (MetaWorkspace *workspace)
 void
 meta_workspace_remove (MetaWorkspace *workspace)
 {
-  g_return_if_fail (workspace != workspace->display->active_workspace);
+  MetaWorkspaceManager *manager = workspace->display->workspace_manager;
+
+  g_return_if_fail (workspace != manager->active_workspace);
 
   assert_workspace_empty (workspace);
 
-  workspace->display->workspaces =
-    g_list_remove (workspace->display->workspaces, workspace);
+  manager->workspaces =
+    g_list_remove (manager->workspaces, workspace);
 
   meta_workspace_clear_logical_monitor_data (workspace);
 
@@ -439,14 +445,14 @@ workspace_switch_sound(MetaWorkspace *from,
   int i, nw, x, y, fi, ti;
   const char *e;
 
-  nw = meta_display_get_n_workspaces(from->display);
+  nw = meta_workspace_manager_get_n_workspaces (from->manager);
   fi = meta_workspace_index(from);
   ti = meta_workspace_index(to);
 
-  meta_display_calc_workspace_layout(from->display,
-                                     nw,
-                                     fi,
-                                     &layout);
+  meta_workspace_manager_calc_workspace_layout (from->manager,
+                                                nw,
+                                                fi,
+                                                &layout);
 
   for (i = 0; i < nw; i++)
     if (layout.grid[i] == ti)
@@ -489,7 +495,7 @@ workspace_switch_sound(MetaWorkspace *from,
                   NULL);
 
  finish:
-  meta_display_free_workspace_layout (&layout);
+  meta_workspace_manager_free_workspace_layout (&layout);
 #endif /* HAVE_LIBCANBERRA */
 }
 
@@ -519,7 +525,6 @@ meta_workspace_activate_with_focus (MetaWorkspace *workspace,
 {
   MetaWorkspace  *old;
   MetaWindow     *move_window;
-  MetaDisplay    *display;
   MetaCompositor *comp;
   MetaWorkspaceLayout layout1, layout2;
   gint num_workspaces, current_space, new_space;
@@ -528,22 +533,22 @@ meta_workspace_activate_with_focus (MetaWorkspace *workspace,
   meta_verbose ("Activating workspace %d\n",
                 meta_workspace_index (workspace));
 
-  if (workspace->display->active_workspace == workspace)
+  if (workspace->manager->active_workspace == workspace)
     return;
 
   /* Free any cached pointers to the workspaces's edges from
    * a current resize or move operation */
   meta_display_cleanup_edges (workspace->display);
 
-  if (workspace->display->active_workspace)
-    workspace_switch_sound (workspace->display->active_workspace, workspace);
+  if (workspace->manager->active_workspace)
+    workspace_switch_sound (workspace->manager->active_workspace, workspace);
 
   /* Note that old can be NULL; e.g. when starting up */
-  old = workspace->display->active_workspace;
+  old = workspace->manager->active_workspace;
 
-  workspace->display->active_workspace = workspace;
+  workspace->manager->active_workspace = workspace;
 
-  g_signal_emit_by_name (workspace->display, "active-workspace-changed");
+  g_signal_emit_by_name (workspace->manager, "active-workspace-changed");
 
   if (old == NULL)
     return;
@@ -553,7 +558,7 @@ meta_workspace_activate_with_focus (MetaWorkspace *workspace,
    * _net_showing_desktop hint
    */
   if (old->showing_desktop != workspace->showing_desktop)
-    g_signal_emit_by_name (workspace->display, "showing-desktop-changed");
+    g_signal_emit_by_name (workspace->manager, "showing-desktop-changed");
 
   move_window = NULL;
   if (meta_grab_op_is_moving (workspace->display->grab_op))
@@ -578,18 +583,17 @@ meta_workspace_activate_with_focus (MetaWorkspace *workspace,
    /*
     * Notify the compositor that the active workspace is changing.
     */
-   display = workspace->display;
-   comp = meta_display_get_compositor (display);
+   comp = meta_display_get_compositor (workspace->display);
    direction = 0;
 
    current_space = meta_workspace_index (old);
    new_space     = meta_workspace_index (workspace);
-   num_workspaces = meta_display_get_n_workspaces (workspace->display);
-   meta_display_calc_workspace_layout (workspace->display, num_workspaces,
-                                       current_space, &layout1);
+   num_workspaces = meta_workspace_manager_get_n_workspaces (workspace->manager);
+   meta_workspace_manager_calc_workspace_layout (workspace->manager, num_workspaces,
+                                                 current_space, &layout1);
 
-   meta_display_calc_workspace_layout (workspace->display, num_workspaces,
-                                       new_space, &layout2);
+   meta_workspace_manager_calc_workspace_layout (workspace->manager, num_workspaces,
+                                                 new_space, &layout2);
 
    if (meta_get_locale_direction () == META_LOCALE_DIRECTION_RTL)
      {
@@ -626,8 +630,8 @@ meta_workspace_activate_with_focus (MetaWorkspace *workspace,
          direction = META_MOTION_UP_LEFT;
      }
 
-   meta_display_free_workspace_layout (&layout1);
-   meta_display_free_workspace_layout (&layout2);
+   meta_workspace_manager_free_workspace_layout (&layout1);
+   meta_workspace_manager_free_workspace_layout (&layout2);
 
    meta_compositor_switch_workspace (comp, old, workspace, direction);
 
@@ -650,7 +654,8 @@ meta_workspace_activate_with_focus (MetaWorkspace *workspace,
       meta_workspace_focus_default_window (workspace, NULL, timestamp);
     }
 
-   meta_display_workspace_switched (display, current_space, new_space, direction);
+   meta_workspace_manager_workspace_switched (workspace->manager, current_space,
+                                              new_space, direction);
 }
 
 void
@@ -665,7 +670,7 @@ meta_workspace_index (MetaWorkspace *workspace)
 {
   int ret;
 
-  ret = g_list_index (workspace->display->workspaces, workspace);
+  ret = g_list_index (workspace->manager->workspaces, workspace);
 
   if (ret < 0)
     meta_bug ("Workspace does not exist to index!\n");
@@ -738,7 +743,7 @@ meta_workspace_invalidate_work_area (MetaWorkspace *workspace)
 
   /* If we are in the middle of a resize or move operation, we
    * might have cached pointers to the workspace's edges */
-  if (workspace == workspace->display->active_workspace)
+  if (workspace == workspace->manager->active_workspace)
     meta_display_cleanup_edges (workspace->display);
 
   meta_workspace_clear_logical_monitor_data (workspace);
@@ -1204,9 +1209,9 @@ meta_workspace_get_neighbor (MetaWorkspace      *workspace,
   gboolean ltr;
 
   current_space = meta_workspace_index (workspace);
-  num_workspaces = meta_display_get_n_workspaces (workspace->display);
-  meta_display_calc_workspace_layout (workspace->display, num_workspaces,
-                                      current_space, &layout);
+  num_workspaces = meta_workspace_manager_get_n_workspaces (workspace->manager);
+  meta_workspace_manager_calc_workspace_layout (workspace->manager, num_workspaces,
+                                                current_space, &layout);
 
   meta_verbose ("Getting neighbor of %d in direction %s\n",
                 current_space, meta_motion_direction_to_string (direction));
@@ -1251,9 +1256,9 @@ meta_workspace_get_neighbor (MetaWorkspace      *workspace,
   meta_verbose ("Neighbor workspace is %d at row %d col %d\n",
                 i, layout.current_row, layout.current_col);
 
-  meta_display_free_workspace_layout (&layout);
+  meta_workspace_manager_free_workspace_layout (&layout);
 
-  return meta_display_get_workspace_by_index (workspace->display, i);
+  return meta_workspace_manager_get_workspace_by_index (workspace->manager, i);
 }
 
 const char*
diff --git a/src/meta/display.h b/src/meta/display.h
index 6d446a656..a165421b7 100644
--- a/src/meta/display.h
+++ b/src/meta/display.h
@@ -203,24 +203,6 @@ int meta_display_get_monitor_neighbor_index (MetaDisplay         *display,
                                              int                  which_monitor,
                                              MetaDisplayDirection dir);
 
-GList *meta_display_get_workspaces (MetaDisplay *display);
-
-int meta_display_get_n_workspaces (MetaDisplay *display);
-
-MetaWorkspace* meta_display_get_workspace_by_index (MetaDisplay *display,
-                                                   int           index);
-void meta_display_remove_workspace (MetaDisplay   *display,
-                                    MetaWorkspace *workspace,
-                                    guint32        timestamp);
-
-MetaWorkspace *meta_display_append_new_workspace (MetaDisplay *display,
-                                                  gboolean     activate,
-                                                  guint32      timestamp);
-
-int meta_display_get_active_workspace_index (MetaDisplay *display);
-
-MetaWorkspace *meta_display_get_active_workspace (MetaDisplay *display);
-
 void meta_display_focus_default_window (MetaDisplay *display,
                                         guint32      timestamp);
 
@@ -239,12 +221,6 @@ typedef enum
   META_DISPLAY_BOTTOMRIGHT
 } MetaDisplayCorner;
 
-void meta_display_override_workspace_layout (MetaDisplay       *display,
-                                             MetaDisplayCorner starting_corner,
-                                             gboolean          vertical_layout,
-                                             int               n_rows,
-                                             int               n_columns);
-
 MetaWorkspaceManager *meta_display_get_workspace_manager (MetaDisplay *display);
 
 #endif
diff --git a/src/meta/meta-workspace-manager.h b/src/meta/meta-workspace-manager.h
index 29604f244..52b2f0e30 100644
--- a/src/meta/meta-workspace-manager.h
+++ b/src/meta/meta-workspace-manager.h
@@ -32,6 +32,28 @@
 #define META_TYPE_WORKSPACE_MANAGER (meta_workspace_manager_get_type ())
 G_DECLARE_FINAL_TYPE (MetaWorkspaceManager, meta_workspace_manager, META, WORKSPACE_MANAGER, GObject)
 
+GList *meta_workspace_manager_get_workspaces (MetaWorkspaceManager *workspace_manager);
+
 int meta_workspace_manager_get_n_workspaces (MetaWorkspaceManager *workspace_manager);
 
+MetaWorkspace* meta_workspace_manager_get_workspace_by_index (MetaWorkspaceManager *workspace_manager,
+                                                              int                   index);
+
+void meta_workspace_manager_remove_workspace (MetaWorkspaceManager *workspace_manager,
+                                              MetaWorkspace        *workspace,
+                                              guint32               timestamp);
+
+MetaWorkspace *meta_workspace_manager_append_new_workspace (MetaWorkspaceManager *workspace_manager,
+                                                            gboolean              activate,
+                                                            guint32               timestamp);
+
+int meta_workspace_manager_get_active_workspace_index (MetaWorkspaceManager *workspace_manager);
+
+MetaWorkspace *meta_workspace_manager_get_active_workspace (MetaWorkspaceManager *workspace_manager);
+
+void meta_workspace_manager_override_workspace_layout (MetaWorkspaceManager *workspace_manager,
+                                                       MetaDisplayCorner     starting_corner,
+                                                       gboolean              vertical_layout,
+                                                       int                   n_rows,
+                                                       int                   n_columns);
 #endif /* META_WORKSPACE_MANAGER_H */
diff --git a/src/x11/events.c b/src/x11/events.c
index 397df1b27..53e1aa191 100644
--- a/src/x11/events.c
+++ b/src/x11/events.c
@@ -32,6 +32,7 @@
 #include "meta/meta-backend.h"
 #include "bell.h"
 #include "display-private.h"
+#include "meta-workspace-manager-private.h"
 #include "window-private.h"
 #include "workspace-private.h"
 #include "backends/meta-cursor-tracker-private.h"
@@ -844,6 +845,7 @@ handle_input_xevent (MetaX11Display *x11_display,
   Window modified;
   MetaWindow *window;
   MetaDisplay *display = x11_display->display;
+  MetaWorkspaceManager *workspace_manager = display->workspace_manager;
 
   if (input_event == NULL)
     return FALSE;
@@ -912,7 +914,7 @@ handle_input_xevent (MetaX11Display *x11_display,
                           "Focus got set to None, probably due to "
                           "brain-damage in the X protocol (see bug "
                           "125492).  Setting the default focus window.\n");
-              meta_workspace_focus_default_window (display->active_workspace,
+              meta_workspace_focus_default_window (workspace_manager->active_workspace,
                                                    NULL,
                                                    meta_x11_display_get_current_time_roundtrip 
(x11_display));
             }
@@ -924,7 +926,7 @@ handle_input_xevent (MetaX11Display *x11_display,
                           "Focus got set to root window, probably due to "
                           "gnome-session logout dialog usage (see bug "
                           "153220).  Setting the default focus window.\n");
-              meta_workspace_focus_default_window (display->active_workspace,
+              meta_workspace_focus_default_window (workspace_manager->active_workspace,
                                                    NULL,
                                                    meta_x11_display_get_current_time_roundtrip 
(x11_display));
             }
@@ -1197,6 +1199,7 @@ handle_other_xevent (MetaX11Display *x11_display,
                      XEvent         *event)
 {
   MetaDisplay *display = x11_display->display;
+  MetaWorkspaceManager *workspace_manager = display->workspace_manager;
   Window modified;
   MetaWindow *window;
   MetaWindow *property_for_window;
@@ -1398,12 +1401,12 @@ handle_other_xevent (MetaX11Display *x11_display,
       if (window->minimized)
         {
           meta_window_unminimize (window);
-          if (window->workspace != window->display->active_workspace)
+          if (window->workspace != workspace_manager->active_workspace)
             {
               meta_verbose ("Changing workspace due to MapRequest mapped = %d minimized = %d\n",
                             window->mapped, window->minimized);
               meta_window_change_workspace (window,
-                                            window->display->active_workspace);
+                                            workspace_manager->active_workspace);
             }
         }
       break;
@@ -1552,7 +1555,7 @@ handle_other_xevent (MetaX11Display *x11_display,
                                 "specified timestamp of %u\n",
                                 space, time);
 
-                  workspace = meta_display_get_workspace_by_index (display, space);
+                  workspace = meta_workspace_manager_get_workspace_by_index (workspace_manager, space);
 
                   /* Handle clients using the older version of the spec... */
                   if (time == 0 && workspace)
@@ -1593,11 +1596,11 @@ handle_other_xevent (MetaX11Display *x11_display,
                                 showing_desktop ? "show" : "hide");
 
                   if (showing_desktop)
-                    meta_display_show_desktop (display, timestamp);
+                    meta_workspace_manager_show_desktop (workspace_manager, timestamp);
                   else
                     {
-                      meta_display_unshow_desktop (display);
-                      meta_workspace_focus_default_window (display->active_workspace, NULL, timestamp);
+                      meta_workspace_manager_unshow_desktop (workspace_manager);
+                      meta_workspace_focus_default_window (workspace_manager->active_workspace, NULL, 
timestamp);
                     }
                 }
               else if (event->xclient.message_type ==
diff --git a/src/x11/meta-x11-display.c b/src/x11/meta-x11-display.c
index 9c48ae312..76433a4b5 100644
--- a/src/x11/meta-x11-display.c
+++ b/src/x11/meta-x11-display.c
@@ -55,6 +55,7 @@
 #include "backends/meta-logical-monitor.h"
 #include "backends/x11/meta-backend-x11.h"
 #include "core/frame.h"
+#include "core/meta-workspace-manager-private.h"
 #include "core/util-private.h"
 #include "core/workspace-private.h"
 #include "meta/main.h"
@@ -793,8 +794,8 @@ init_event_masks (MetaX11Display *x11_display)
 }
 
 static void
-set_active_workspace_hint (MetaDisplay    *display,
-                           MetaX11Display *x11_display)
+set_active_workspace_hint (MetaWorkspaceManager *workspace_manager,
+                           MetaX11Display       *x11_display)
 {
   unsigned long data[1];
 
@@ -804,10 +805,10 @@ set_active_workspace_hint (MetaDisplay    *display,
    * on restart. By doing this we keep the current
    * desktop on restart.
    */
-  if (display->closing > 0)
+  if (x11_display->display->closing > 0)
     return;
 
-  data[0] = meta_workspace_index (display->active_workspace);
+  data[0] = meta_workspace_index (workspace_manager->active_workspace);
 
   meta_verbose ("Setting _NET_CURRENT_DESKTOP to %lu\n", data[0]);
 
@@ -821,17 +822,17 @@ set_active_workspace_hint (MetaDisplay    *display,
 }
 
 static void
-set_number_of_spaces_hint (MetaDisplay *display,
-                           GParamSpec  *pspec,
-                           gpointer     user_data)
+set_number_of_spaces_hint (MetaWorkspaceManager *workspace_manager,
+                           GParamSpec           *pspec,
+                           gpointer              user_data)
 {
   MetaX11Display *x11_display = user_data;
   unsigned long data[1];
 
-  if (display->closing > 0)
+  if (x11_display->display->closing > 0)
     return;
 
-  data[0] = meta_display_get_n_workspaces (display);
+  data[0] = meta_workspace_manager_get_n_workspaces (workspace_manager);
 
   meta_verbose ("Setting _NET_NUMBER_OF_DESKTOPS to %lu\n", data[0]);
 
@@ -845,12 +846,12 @@ set_number_of_spaces_hint (MetaDisplay *display,
 }
 
 static void
-set_showing_desktop_hint (MetaDisplay    *display,
-                          MetaX11Display *x11_display)
+set_showing_desktop_hint (MetaWorkspaceManager *workspace_manager,
+                          MetaX11Display       *x11_display)
 {
   unsigned long data[1];
 
-  data[0] = display->active_workspace->showing_desktop ? 1 : 0;
+  data[0] = workspace_manager->active_workspace->showing_desktop ? 1 : 0;
 
   meta_x11_error_trap_push (x11_display);
   XChangeProperty (x11_display->xdisplay,
@@ -864,12 +865,15 @@ set_showing_desktop_hint (MetaDisplay    *display,
 static void
 set_workspace_names (MetaX11Display *x11_display)
 {
+  MetaWorkspaceManager *workspace_manager;
   GString *flattened;
   int i;
   int n_spaces;
 
+  workspace_manager = x11_display->display->workspace_manager;
+
   /* flatten to nul-separated list */
-  n_spaces = meta_display_get_n_workspaces (x11_display->display);
+  n_spaces = meta_workspace_manager_get_n_workspaces (workspace_manager);
   flattened = g_string_new ("");
   i = 0;
   while (i < n_spaces)
@@ -903,16 +907,17 @@ static void
 set_work_area_hint (MetaDisplay    *display,
                     MetaX11Display *x11_display)
 {
+  MetaWorkspaceManager *workspace_manager = display->workspace_manager;
   int num_workspaces;
   GList *l;
   unsigned long *data, *tmp;
   MetaRectangle area;
 
-  num_workspaces = meta_display_get_n_workspaces (display);
+  num_workspaces = meta_workspace_manager_get_n_workspaces (workspace_manager);
   data = g_new (unsigned long, num_workspaces * 4);
   tmp = data;
 
-  for (l = display->workspaces; l; l = l->next)
+  for (l = workspace_manager->workspaces; l; l = l->next)
     {
       MetaWorkspace *workspace = l->data;
 
@@ -1252,8 +1257,8 @@ meta_x11_display_new (MetaDisplay *display, GError **error)
                     (int) current_workspace_index);
 
       /* Switch to the _NET_CURRENT_DESKTOP workspace */
-      current_workspace = meta_display_get_workspace_by_index (display,
-                                                               current_workspace_index);
+      current_workspace = meta_workspace_manager_get_workspace_by_index (display->workspace_manager,
+                                                                         current_workspace_index);
 
       if (current_workspace != NULL)
         meta_workspace_activate (current_workspace, timestamp);
@@ -1278,25 +1283,25 @@ meta_x11_display_new (MetaDisplay *display, GError **error)
           meta_XFree (list);
         }
 
-        if (num > meta_display_get_n_workspaces (display))
-          meta_display_update_num_workspaces (display, timestamp, num);
+        if (num > meta_workspace_manager_get_n_workspaces (display->workspace_manager))
+          meta_workspace_manager_update_num_workspaces (display->workspace_manager, timestamp, num);
     }
 
-  set_active_workspace_hint (display, x11_display);
+  set_active_workspace_hint (display->workspace_manager, x11_display);
 
-  g_signal_connect_object (display, "active-workspace-changed",
+  g_signal_connect_object (display->workspace_manager, "active-workspace-changed",
                            G_CALLBACK (set_active_workspace_hint),
                            x11_display, 0);
 
-  set_number_of_spaces_hint (display, NULL, x11_display);
+  set_number_of_spaces_hint (display->workspace_manager, NULL, x11_display);
 
-  g_signal_connect_object (display, "notify::n-workspaces",
+  g_signal_connect_object (display->workspace_manager, "notify::n-workspaces",
                            G_CALLBACK (set_number_of_spaces_hint),
                            x11_display, 0);
 
-  set_showing_desktop_hint (display, x11_display);
+  set_showing_desktop_hint (display->workspace_manager, x11_display);
 
-  g_signal_connect_object (display, "showing-desktop-changed",
+  g_signal_connect_object (display->workspace_manager, "showing-desktop-changed",
                            G_CALLBACK (set_showing_desktop_hint),
                            x11_display, 0);
 
@@ -2013,6 +2018,7 @@ meta_x11_display_update_workspace_names (MetaX11Display *x11_display)
 void
 meta_x11_display_update_workspace_layout (MetaX11Display *x11_display)
 {
+  MetaWorkspaceManager *workspace_manager = x11_display->display->workspace_manager;
   gboolean vertical_layout = FALSE;
   int n_rows = -1;
   int n_columns = 1;
@@ -2020,7 +2026,7 @@ meta_x11_display_update_workspace_layout (MetaX11Display *x11_display)
   uint32_t *list;
   int n_items;
 
-  if (x11_display->display->workspace_layout_overridden)
+  if (workspace_manager->workspace_layout_overridden)
     return;
 
   list = NULL;
@@ -2098,11 +2104,11 @@ meta_x11_display_update_workspace_layout (MetaX11Display *x11_display)
 
       meta_XFree (list);
 
-      meta_display_update_workspace_layout (x11_display->display,
-                                            starting_corner,
-                                            vertical_layout,
-                                            n_rows,
-                                            n_columns);
+      meta_workspace_manager_update_workspace_layout (workspace_manager,
+                                                      starting_corner,
+                                                      vertical_layout,
+                                                      n_rows,
+                                                      n_columns);
     }
 }
 
diff --git a/src/x11/window-props.c b/src/x11/window-props.c
index 946568cb2..d06a89a21 100644
--- a/src/x11/window-props.c
+++ b/src/x11/window-props.c
@@ -49,6 +49,7 @@
 #include <unistd.h>
 #include <string.h>
 #include "util-private.h"
+#include "meta-workspace-manager-private.h"
 
 #ifndef HOST_NAME_MAX
 /* Solaris headers apparently don't define this so do so manually; #326745 */
@@ -1027,6 +1028,7 @@ reload_net_startup_id (MetaWindow    *window,
                        MetaPropValue *value,
                        gboolean       initial)
 {
+  MetaWorkspaceManager *workspace_manager = window->display->workspace_manager;
   guint32 timestamp = window->net_wm_user_time;
   MetaWorkspace *workspace = NULL;
 
@@ -1049,7 +1051,8 @@ reload_net_startup_id (MetaWindow    *window,
         if (window->initial_timestamp_set)
           timestamp = window->initial_timestamp;
         if (window->initial_workspace_set)
-          workspace = meta_display_get_workspace_by_index (window->display, window->initial_workspace);
+          workspace = meta_workspace_manager_get_workspace_by_index (workspace_manager,
+                                                                     window->initial_workspace);
 
         meta_window_activate_with_workspace (window, timestamp, workspace);
       }
diff --git a/src/x11/window-x11.c b/src/x11/window-x11.c
index 267fc3427..2418e6262 100644
--- a/src/x11/window-x11.c
+++ b/src/x11/window-x11.c
@@ -50,6 +50,7 @@
 #include "xprops.h"
 #include "session.h"
 #include "workspace-private.h"
+#include "meta-workspace-manager-private.h"
 
 #include "backends/meta-logical-monitor.h"
 #include "backends/x11/meta-backend-x11.h"
@@ -442,11 +443,12 @@ meta_window_apply_session_info (MetaWindow *window,
       tmp = info->workspace_indices;
       while (tmp != NULL)
         {
+          MetaWorkspaceManager *workspace_manager = window->display->workspace_manager;
           MetaWorkspace *space;
 
           space =
-            meta_display_get_workspace_by_index (window->display,
-                                                 GPOINTER_TO_INT (tmp->data));
+            meta_workspace_manager_get_workspace_by_index (workspace_manager,
+                                                           GPOINTER_TO_INT (tmp->data));
 
           if (space)
             spaces = g_slist_prepend (spaces, space);
@@ -2403,6 +2405,7 @@ meta_window_x11_client_message (MetaWindow *window,
            x11_display->atom__NET_WM_DESKTOP)
     {
       int space;
+      MetaWorkspaceManager *workspace_manager = window->display->workspace_manager;
       MetaWorkspace *workspace;
 
       space = event->xclient.data.l[0];
@@ -2411,8 +2414,8 @@ meta_window_x11_client_message (MetaWindow *window,
                     window->desc, space);
 
       workspace =
-        meta_display_get_workspace_by_index (window->display,
-                                             space);
+        meta_workspace_manager_get_workspace_by_index (workspace_manager,
+                                                       space);
 
       if (workspace)
         meta_window_change_workspace (window, workspace);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]