Blob Blame History Raw
From 0826616da1dacf29e3e08dae6d2ffe4116e5bdff Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Thu, 16 Jul 2015 15:07:38 +0200
Subject: [PATCH 1/2] barrier: Guard against X errors

---
 src/backends/x11/meta-barrier-x11.c | 22 +++++++++++++++-------
 1 file changed, 15 insertions(+), 7 deletions(-)

diff --git a/src/backends/x11/meta-barrier-x11.c b/src/backends/x11/meta-barrier-x11.c
index 054e5cdc6..1fc3fd8cc 100644
--- a/src/backends/x11/meta-barrier-x11.c
+++ b/src/backends/x11/meta-barrier-x11.c
@@ -38,6 +38,7 @@
 #include <X11/extensions/XInput2.h>
 #include <X11/extensions/Xfixes.h>
 #include <meta/barrier.h>
+#include <meta/errors.h>
 #include "backends/x11/meta-barrier-x11.h"
 #include "display-private.h"
 
@@ -107,6 +108,7 @@ meta_barrier_impl_x11_new (MetaBarrier *barrier)
   MetaDisplay *display = barrier->priv->display;
   Display *dpy;
   Window root;
+  PointerBarrier xbarrier;
   unsigned int allowed_motion_dirs;
 
   if (display == NULL)
@@ -119,18 +121,24 @@ meta_barrier_impl_x11_new (MetaBarrier *barrier)
   priv = meta_barrier_impl_x11_get_instance_private (self);
   priv->barrier = barrier;
 
+  meta_error_trap_push (display);
   dpy = display->xdisplay;
   root = DefaultRootWindow (dpy);
 
   allowed_motion_dirs =
     meta_border_get_allows_directions (&barrier->priv->border);
-  priv->xbarrier = XFixesCreatePointerBarrier (dpy, root,
-                                               barrier->priv->border.line.a.x,
-                                               barrier->priv->border.line.a.y,
-                                               barrier->priv->border.line.b.x,
-                                               barrier->priv->border.line.b.y,
-                                               allowed_motion_dirs,
-                                               0, NULL);
+  xbarrier = XFixesCreatePointerBarrier (dpy, root,
+                                         barrier->priv->border.line.a.x,
+                                         barrier->priv->border.line.a.y,
+                                         barrier->priv->border.line.b.x,
+                                         barrier->priv->border.line.b.y,
+                                         allowed_motion_dirs,
+                                         0, NULL);
+
+  if (meta_error_trap_pop_with_return (display) != Success)
+    return NULL;
+
+  priv->xbarrier = xbarrier;
 
   g_hash_table_insert (display->xids, &priv->xbarrier, barrier);
 
-- 
2.12.0


From 2da829399dc79b5c51ca55ab6e633c4a4769c15a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Thu, 16 Jul 2015 15:12:55 +0200
Subject: [PATCH 2/2] Do not crash when starting up with no monitor connected

Some parts of Mutter currently assume there's always a monitor connected
to the screen. This assumption can be incorrect - e.g. a desktop
computer can be powered on and a monitor only plugged in after the
desktop session - or the GDM login - has already been reached.

Fix the various places that assume so, making the code robust to the
above use case.

Based on an initial patch by Cosimo Cecchi.
---
 src/backends/x11/meta-monitor-manager-xrandr.c |  4 +-
 src/compositor/meta-window-actor.c             |  2 +-
 src/core/constraints.c                         | 71 +++++++++++++++-----------
 src/core/place.c                               |  4 ++
 src/core/screen.c                              | 10 +++-
 src/core/window.c                              | 57 ++++++++++++++-------
 src/core/workspace.c                           |  3 ++
 src/x11/window-x11.c                           |  3 +-
 8 files changed, 100 insertions(+), 54 deletions(-)

diff --git a/src/backends/x11/meta-monitor-manager-xrandr.c b/src/backends/x11/meta-monitor-manager-xrandr.c
index b0a77dadb..b82120af9 100644
--- a/src/backends/x11/meta-monitor-manager-xrandr.c
+++ b/src/backends/x11/meta-monitor-manager-xrandr.c
@@ -1141,7 +1141,9 @@ meta_monitor_manager_xrandr_apply_configuration (MetaMonitorManager *manager,
       crtc->current_mode = NULL;
     }
 
-  g_assert (width > 0 && height > 0);
+  if (width == 0 || height == 0)
+    return;
+
   /* The 'physical size' of an X screen is meaningless if that screen
    * can consist of many monitors. So just pick a size that make the
    * dpi 96.
diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c
index 9395caac5..fb29ca1c9 100644
--- a/src/compositor/meta-window-actor.c
+++ b/src/compositor/meta-window-actor.c
@@ -959,7 +959,7 @@ queue_send_frame_messages_timeout (MetaWindowActor *self)
   outputs = meta_monitor_manager_get_outputs (monitor_manager, &n_outputs);
   for (i = 0; i < n_outputs; i++)
     {
-      if (outputs[i].winsys_id == window->monitor->winsys_id && outputs[i].crtc)
+      if (window->monitor && outputs[i].winsys_id == window->monitor->winsys_id && outputs[i].crtc)
         {
           refresh_rate = outputs[i].crtc->current_mode->refresh_rate;
           break;
diff --git a/src/core/constraints.c b/src/core/constraints.c
index 67b52c994..3d1701e88 100644
--- a/src/core/constraints.c
+++ b/src/core/constraints.c
@@ -29,6 +29,7 @@
 #include <meta/prefs.h>
 
 #include <stdlib.h>
+#include <string.h>
 #include <math.h>
 
 #if 0
@@ -337,6 +338,8 @@ setup_constraint_info (ConstraintInfo      *info,
   const MetaMonitorInfo *monitor_info;
   MetaWorkspace *cur_workspace;
 
+  memset (info, 0, sizeof (ConstraintInfo));
+
   info->orig    = *orig;
   info->current = *new;
 
@@ -382,40 +385,43 @@ setup_constraint_info (ConstraintInfo      *info,
   if (!info->is_user_action)
     info->fixed_directions = FIXED_DIRECTION_NONE;
 
+  cur_workspace = window->screen->active_workspace;
   monitor_info =
     meta_screen_get_monitor_for_rect (window->screen, &info->current);
-  meta_window_get_work_area_for_monitor (window,
-                                         monitor_info->number,
-                                         &info->work_area_monitor);
 
-  if (!window->fullscreen || window->fullscreen_monitors[0] == -1)
+  if (monitor_info)
     {
-      info->entire_monitor = monitor_info->rect;
-    }
-  else
-    {
-      int i = 0;
-      long monitor;
+      meta_window_get_work_area_for_monitor (window,
+                                             monitor_info->number,
+                                             &info->work_area_monitor);
 
-      monitor = window->fullscreen_monitors[i];
-      info->entire_monitor =
-        window->screen->monitor_infos[monitor].rect;
-      for (i = 1; i <= 3; i++)
+      if (!window->fullscreen || window->fullscreen_monitors[0] == -1)
+        {
+          info->entire_monitor = monitor_info->rect;
+        }
+      else
         {
+          int i = 0;
+          long monitor;
+
           monitor = window->fullscreen_monitors[i];
-          meta_rectangle_union (&info->entire_monitor,
-                                &window->screen->monitor_infos[monitor].rect,
-                                &info->entire_monitor);
+          info->entire_monitor =
+            window->screen->monitor_infos[monitor].rect;
+          for (i = 1; i <= 3; i++)
+            {
+              monitor = window->fullscreen_monitors[i];
+              meta_rectangle_union (&info->entire_monitor,
+                                    &window->screen->monitor_infos[monitor].rect,
+                                    &info->entire_monitor);
+            }
         }
+      info->usable_screen_region  =
+        meta_workspace_get_onscreen_region (cur_workspace);
+      info->usable_monitor_region =
+        meta_workspace_get_onmonitor_region (cur_workspace,
+                                             monitor_info->number);
     }
 
-  cur_workspace = window->screen->active_workspace;
-  info->usable_screen_region   =
-    meta_workspace_get_onscreen_region (cur_workspace);
-  info->usable_monitor_region =
-    meta_workspace_get_onmonitor_region (cur_workspace,
-                                         monitor_info->number);
-
   /* Log all this information for debugging */
   meta_topic (META_DEBUG_GEOMETRY,
               "Setting up constraint info:\n"
@@ -489,14 +495,17 @@ place_window_if_needed(MetaWindow     *window,
        */
       monitor_info =
         meta_screen_get_monitor_for_rect (window->screen, &placed_rect);
-      info->entire_monitor = monitor_info->rect;
-      meta_window_get_work_area_for_monitor (window,
-                                             monitor_info->number,
-                                             &info->work_area_monitor);
       cur_workspace = window->screen->active_workspace;
-      info->usable_monitor_region =
-        meta_workspace_get_onmonitor_region (cur_workspace,
-                                             monitor_info->number);
+      if (monitor_info)
+        {
+          info->entire_monitor = monitor_info->rect;
+          meta_window_get_work_area_for_monitor (window,
+                                                 monitor_info->number,
+                                                 &info->work_area_monitor);
+          info->usable_monitor_region =
+            meta_workspace_get_onmonitor_region (cur_workspace,
+                                                 monitor_info->number);
+        }
 
       info->current.x = placed_rect.x;
       info->current.y = placed_rect.y;
diff --git a/src/core/place.c b/src/core/place.c
index db71b83ce..0f046f046 100644
--- a/src/core/place.c
+++ b/src/core/place.c
@@ -811,6 +811,8 @@ meta_window_place (MetaWindow        *window,
 
       /* Warning, this function is a round trip! */
       xi = meta_screen_get_current_monitor_info (window->screen);
+      if (!xi)
+        goto done;
 
       w = xi->rect.width;
       h = xi->rect.height;
@@ -856,6 +858,8 @@ meta_window_place (MetaWindow        *window,
 
   /* Warning, this is a round trip! */
   xi = meta_screen_get_current_monitor_info (window->screen);
+  if (!xi)
+    goto done;
 
   /* Maximize windows if they are too big for their work area (bit of
    * a hack here). Assume undecorated windows probably don't intend to
diff --git a/src/core/screen.c b/src/core/screen.c
index b8ac22f76..54a0b0aba 100644
--- a/src/core/screen.c
+++ b/src/core/screen.c
@@ -381,7 +381,10 @@ meta_screen_monitor_index_to_xinerama_index (MetaScreen *screen,
 
   meta_screen_ensure_xinerama_indices (screen);
 
-  return screen->monitor_infos[index].xinerama_index;
+  if (index >= 0 && index < screen->n_monitor_infos)
+    return screen->monitor_infos[index].xinerama_index;
+
+  return -1;
 }
 
 int
@@ -1395,6 +1398,9 @@ meta_screen_get_monitor_for_rect (MetaScreen    *screen,
   int i;
   int best_monitor, monitor_score, rect_area;
 
+  if (screen->n_monitor_infos == 0)
+    return NULL;
+
   if (screen->n_monitor_infos == 1)
     return &screen->monitor_infos[0];
 
@@ -1448,7 +1454,7 @@ meta_screen_get_monitor_index_for_rect (MetaScreen    *screen,
                                         MetaRectangle *rect)
 {
   const MetaMonitorInfo *monitor = meta_screen_get_monitor_for_rect (screen, rect);
-  return monitor->number;
+  return monitor ? monitor->number : -1;
 }
 
 const MetaMonitorInfo *
diff --git a/src/core/window.c b/src/core/window.c
index e3e15cf26..9745b42e0 100644
--- a/src/core/window.c
+++ b/src/core/window.c
@@ -1029,7 +1029,8 @@ _meta_window_shared_new (MetaDisplay         *display,
 
   window->monitor = meta_screen_calculate_monitor_for_window (window->screen,
                                                               window);
-  window->preferred_output_winsys_id = window->monitor->winsys_id;
+  window->preferred_output_winsys_id = window->monitor ? window->monitor->winsys_id
+                                                       : -1;
 
   window->tile_match = NULL;
 
@@ -2280,7 +2281,10 @@ meta_window_show (MetaWindow *window)
       if (meta_prefs_get_auto_maximize() && window->showing_for_first_time && window->has_maximize_func)
         {
           MetaRectangle work_area;
-          meta_window_get_work_area_for_monitor (window, window->monitor->number, &work_area);
+          if (window->monitor)
+            meta_window_get_work_area_for_monitor (window, window->monitor->number, &work_area);
+          else
+            meta_window_get_work_area_current_monitor (window, &work_area);
           /* Automaximize windows that map with a size > MAX_UNMAXIMIZED_WINDOW_AREA of the work area */
           if (window->rect.width * window->rect.height > work_area.width * work_area.height * MAX_UNMAXIMIZED_WINDOW_AREA)
             {
@@ -2677,7 +2681,7 @@ meta_window_maximize_internal (MetaWindow        *window,
   meta_window_recalc_features (window);
   set_net_wm_state (window);
 
-  if (window->monitor->in_fullscreen)
+  if (window->monitor && window->monitor->in_fullscreen)
     meta_screen_queue_check_fullscreen (window->screen);
 
   g_object_freeze_notify (G_OBJECT (window));
@@ -2863,6 +2867,9 @@ meta_window_is_monitor_sized (MetaWindow *window)
   if (meta_window_is_screen_sized (window))
     return TRUE;
 
+  if (!window->monitor)
+    return FALSE;
+
   if (window->override_redirect)
     {
       MetaRectangle window_rect, monitor_rect;
@@ -2886,7 +2893,7 @@ meta_window_is_monitor_sized (MetaWindow *window)
 gboolean
 meta_window_is_on_primary_monitor (MetaWindow *window)
 {
-  return window->monitor->is_primary;
+  return window->monitor ? window->monitor->is_primary : FALSE;
 }
 
 /**
@@ -3027,7 +3034,10 @@ meta_window_unmaximize (MetaWindow        *window,
       MetaRectangle work_area;
       MetaRectangle old_frame_rect, old_buffer_rect;
 
-      meta_window_get_work_area_for_monitor (window, window->monitor->number, &work_area);
+      if (window->monitor)
+        meta_window_get_work_area_for_monitor (window, window->monitor->number, &work_area);
+      else
+        meta_window_get_work_area_current_monitor (window, &work_area);
       meta_window_get_frame_rect (window, &old_frame_rect);
       meta_window_get_buffer_rect (window, &old_buffer_rect);
 
@@ -3123,7 +3133,7 @@ meta_window_unmaximize (MetaWindow        *window,
 
       meta_window_recalc_features (window);
       set_net_wm_state (window);
-      if (!window->monitor->in_fullscreen)
+      if (window->monitor && !window->monitor->in_fullscreen)
         meta_screen_queue_check_fullscreen (window->screen);
     }
 
@@ -3522,7 +3532,7 @@ maybe_move_attached_dialog (MetaWindow *window,
 int
 meta_window_get_monitor (MetaWindow *window)
 {
-  return window->monitor->number;
+  return window->monitor ? window->monitor->number : -1;
 }
 
 static MetaMonitorInfo *
@@ -3549,14 +3559,15 @@ meta_window_update_for_monitors_changed (MetaWindow *window)
 {
   const MetaMonitorInfo *old, *new;
 
-  if (window->override_redirect || window->type == META_WINDOW_DESKTOP)
+  old = window->monitor;
+
+  if (!old || window->screen->n_monitor_infos == 0 ||
+      window->override_redirect || window->type == META_WINDOW_DESKTOP)
     {
       meta_window_update_monitor (window, FALSE);
       return;
     }
 
-  old = window->monitor;
-
   /* Try the preferred output first */
   new = find_monitor_by_winsys_id (window, window->preferred_output_winsys_id);
 
@@ -3643,7 +3654,7 @@ meta_window_move_resize_internal (MetaWindow          *window,
    */
 
   gboolean did_placement;
-  guint old_output_winsys_id;
+  guint old_output_winsys_id, new_output_winsys_id;
   MetaRectangle unconstrained_rect;
   MetaRectangle constrained_rect;
   MetaMoveResizeResultFlags result = 0;
@@ -3737,13 +3748,15 @@ meta_window_move_resize_internal (MetaWindow          *window,
                                               did_placement);
     }
 
-  old_output_winsys_id = window->monitor->winsys_id;
+  old_output_winsys_id = window->monitor ? window->monitor->winsys_id : -1;
 
   meta_window_update_monitor (window, flags & META_MOVE_RESIZE_USER_ACTION);
 
-  if (old_output_winsys_id != window->monitor->winsys_id &&
+  new_output_winsys_id = window->monitor ? window->monitor->winsys_id : -1;
+
+  if (old_output_winsys_id != new_output_winsys_id &&
       flags & META_MOVE_RESIZE_MOVE_ACTION && flags & META_MOVE_RESIZE_USER_ACTION)
-    window->preferred_output_winsys_id = window->monitor->winsys_id;
+    window->preferred_output_winsys_id = new_output_winsys_id;
 
   if ((result & META_MOVE_RESIZE_RESULT_FRAME_SHAPE_CHANGED) && window->frame_bounds)
     {
@@ -3849,7 +3862,7 @@ meta_window_move_to_monitor (MetaWindow  *window,
 {
   MetaRectangle old_area, new_area;
 
-  if (monitor == window->monitor->number)
+  if (!window->monitor || monitor == window->monitor->number)
     return;
 
   meta_window_get_work_area_for_monitor (window,
@@ -6104,9 +6117,17 @@ void
 meta_window_get_work_area_current_monitor (MetaWindow    *window,
                                            MetaRectangle *area)
 {
-  meta_window_get_work_area_for_monitor (window,
-                                         window->monitor->number,
-                                         area);
+  if (window->monitor)
+    {
+      meta_window_get_work_area_for_monitor (window,
+                                             window->monitor->number,
+                                             area);
+    }
+  else if (area)
+    {
+      MetaRectangle empty = { 0, 0, 0, 0 };
+      *area = empty;
+    }
 }
 
 /**
diff --git a/src/core/workspace.c b/src/core/workspace.c
index cfac7dc48..a73ac6bb7 100644
--- a/src/core/workspace.c
+++ b/src/core/workspace.c
@@ -765,6 +765,9 @@ ensure_work_areas_validated (MetaWorkspace *workspace)
   g_assert (workspace->screen_edges == NULL);
   g_assert (workspace->monitor_edges == NULL);
 
+  if (workspace->screen->n_monitor_infos == 0)
+    return;
+
   /* STEP 1: Get the list of struts */
 
   workspace->all_struts = copy_strut_list (workspace->builtin_struts);
diff --git a/src/x11/window-x11.c b/src/x11/window-x11.c
index 376d73c78..9b102e589 100644
--- a/src/x11/window-x11.c
+++ b/src/x11/window-x11.c
@@ -2032,7 +2032,8 @@ meta_window_move_resize_request (MetaWindow *window,
       rect.width = width;
       rect.height = height;
 
-      meta_screen_get_monitor_geometry (window->screen, window->monitor->number, &monitor_rect);
+      if (window->monitor)
+        meta_screen_get_monitor_geometry (window->screen, window->monitor->number, &monitor_rect);
 
       /* Workaround braindead legacy apps that don't know how to
        * fullscreen themselves properly - don't get fooled by
-- 
2.12.0