From 9604fb36121d40a7440e3dea49f907f426146e71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Thu, 16 Jul 2015 15:07:38 +0200 Subject: [PATCH 1/2] barrier: Guard against X errors --- src/core/barrier.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/core/barrier.c b/src/core/barrier.c index b869d2e..1d372e9 100644 --- a/src/core/barrier.c +++ b/src/core/barrier.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "display-private.h" #include "mutter-enum-types.h" #include "core.h" @@ -183,6 +184,7 @@ meta_barrier_constructed (GObject *object) MetaBarrierPrivate *priv = barrier->priv; Display *dpy; Window root; + PointerBarrier xbarrier; g_return_if_fail (priv->x1 == priv->x2 || priv->y1 == priv->y2); @@ -192,13 +194,18 @@ meta_barrier_constructed (GObject *object) return; } + meta_error_trap_push (priv->display); dpy = priv->display->xdisplay; root = DefaultRootWindow (dpy); - priv->xbarrier = XFixesCreatePointerBarrier (dpy, root, - priv->x1, priv->y1, - priv->x2, priv->y2, - priv->directions, 0, NULL); + xbarrier = XFixesCreatePointerBarrier (dpy, root, + priv->x1, priv->y1, + priv->x2, priv->y2, + priv->directions, 0, NULL); + if (meta_error_trap_pop_with_return (priv->display) != Success) + return NULL; + + priv->xbarrier = xbarrier; /* Take a ref that we'll release when the XID dies inside destroy(), * so that the object stays alive and doesn't get GC'd. */ -- 2.5.0 From 4485e49f3f7d1232b7bd3c312f26117f5827e816 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= 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/compositor.c | 3 +- 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 | 62 ++++++++++++++-------- src/core/workspace.c | 3 ++ src/x11/window-x11.c | 3 +- 9 files changed, 105 insertions(+), 57 deletions(-) diff --git a/src/backends/x11/meta-monitor-manager-xrandr.c b/src/backends/x11/meta-monitor-manager-xrandr.c index 2c6d65e..3abe413 100644 --- a/src/backends/x11/meta-monitor-manager-xrandr.c +++ b/src/backends/x11/meta-monitor-manager-xrandr.c @@ -866,7 +866,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/compositor.c b/src/compositor/compositor.c index 250d489..8bf469f 100644 --- a/src/compositor/compositor.c +++ b/src/compositor/compositor.c @@ -1105,7 +1105,8 @@ static gboolean meta_repaint_func (gpointer data) { MetaCompositor *compositor = data; - pre_paint_windows (compositor); + if (meta_screen_get_n_monitors (compositor->display->screen) > 0) + pre_paint_windows (compositor); return TRUE; } diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c index 3d6fab1..476abbf 100644 --- a/src/compositor/meta-window-actor.c +++ b/src/compositor/meta-window-actor.c @@ -956,7 +956,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 9f5f127..1cff417 100644 --- a/src/core/constraints.c +++ b/src/core/constraints.c @@ -29,6 +29,7 @@ #include #include +#include #include #if 0 @@ -331,6 +332,8 @@ setup_constraint_info (ConstraintInfo *info, const MetaMonitorInfo *monitor_info; MetaWorkspace *cur_workspace; + memset (info, 0, sizeof (ConstraintInfo)); + info->orig = *orig; info->current = *new; @@ -376,40 +379,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" @@ -478,14 +484,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 56befbd..7f21556 100644 --- a/src/core/place.c +++ b/src/core/place.c @@ -746,6 +746,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; @@ -791,6 +793,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 b26137e..6eaf04f 100644 --- a/src/core/screen.c +++ b/src/core/screen.c @@ -385,7 +385,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 @@ -1410,6 +1413,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]; @@ -1463,7 +1469,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 0bc85d8..694a11e 100644 --- a/src/core/window.c +++ b/src/core/window.c @@ -962,7 +962,8 @@ _meta_window_shared_new (MetaDisplay *display, window->compositor_private = NULL; window->monitor = meta_screen_get_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; @@ -1130,7 +1131,8 @@ _meta_window_shared_new (MetaDisplay *display, meta_window_update_struts (window); } - g_signal_emit_by_name (window->screen, "window-entered-monitor", window->monitor->number, window); + if (window->monitor) + g_signal_emit_by_name (window->screen, "window-entered-monitor", window->monitor->number, window); /* Must add window to stack before doing move/resize, since the * window might have fullscreen size (i.e. should have been @@ -2225,7 +2227,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) { @@ -2622,7 +2627,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)); @@ -2802,6 +2807,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; @@ -2825,7 +2833,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; } /** @@ -2978,7 +2986,10 @@ meta_window_unmaximize_internal (MetaWindow *window, MetaRectangle work_area; MetaRectangle old_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_rect); meta_topic (META_DEBUG_WINDOW_OPS, @@ -3069,7 +3080,7 @@ meta_window_unmaximize_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); } @@ -3476,7 +3487,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 * @@ -3506,14 +3517,14 @@ meta_window_update_for_monitors_changed (MetaWindow *window) if (window->type == META_WINDOW_DESKTOP) return; - if (window->override_redirect) + old = window->monitor; + + if (!old || window->screen->n_monitor_infos == 0 || window->override_redirect) { 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); @@ -3568,7 +3579,8 @@ meta_window_update_monitor (MetaWindow *window, if (old) g_signal_emit_by_name (window->screen, "window-left-monitor", old->number, window); - g_signal_emit_by_name (window->screen, "window-entered-monitor", window->monitor->number, window); + if (window->monitor) + g_signal_emit_by_name (window->screen, "window-entered-monitor", window->monitor->number, window); /* If we're changing monitors, we need to update the has_maximize_func flag, * as the working area has changed. */ @@ -3602,7 +3614,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; @@ -3696,13 +3708,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_IS_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_IS_MOVE_ACTION && flags & META_IS_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) { @@ -3808,7 +3822,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, @@ -6198,9 +6212,17 @@ meta_window_get_work_area_current_monitor (MetaWindow *window, monitor = meta_screen_get_monitor_for_window (window->screen, window); - meta_window_get_work_area_for_monitor (window, - monitor->number, - area); + if (monitor) + { + meta_window_get_work_area_for_monitor (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 f275c00..d4077d7 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 1e2580c..879f229 100644 --- a/src/x11/window-x11.c +++ b/src/x11/window-x11.c @@ -1990,7 +1990,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.5.0