[metacity] Fix crash when struts change during grab operation



commit 1031d4df76f8406a59d1b1a569e18816f2dc0229
Author: Owen W. Taylor <otaylor fishsoup net>
Date:   Tue Feb 9 16:44:16 2010 -0500

    Fix crash when struts change during grab operation
    
    Since meta_workspace_invalidate_work_area() frees the edges
    workspace->screen_edges and workspace->monitor_edges, we must clean up
    our cached edge resistance data when the invalidate_work_area() is
    called on the active workspace, or when the workspace changes.
    
    Make the computation of the edge resistance data lazy so that it
    will be recomputed the next time we try to access it.
    meta_display_compute_resistance_and_snapping_edges() is made
    private to edge-resistance.c
    
    Invaliding the data when active workspace changes also will improve
    correctness for edge resistance when the current workspace changes
    during a grab operation. (Even with this fix we still don't try to
    handle window positions changing during a grab operation; that can't
    cause a crash since, unlike screen and monitor edges, the window edges
    are freshly allocated, it will just cause slight oddness in that
    corner case.)
    
    Root cause tracked down due to much effort by Jon Nettleton.
    https://bugzilla.gnome.org/show_bug.cgi?id=608800 (Mutter)
    https://bugzilla.gnome.org/show_bug.cgi?id=603632 (Metacity)

 src/core/display-private.h |    5 ++---
 src/core/display.c         |   12 ------------
 src/core/edge-resistance.c |   18 ++++++++++++++----
 src/core/workspace.c       |   11 +++++++++++
 4 files changed, 27 insertions(+), 19 deletions(-)
---
diff --git a/src/core/display-private.h b/src/core/display-private.h
index d257426..c9e919e 100644
--- a/src/core/display-private.h
+++ b/src/core/display-private.h
@@ -377,9 +377,8 @@ void meta_display_grab_focus_window_button   (MetaDisplay *display,
 void meta_display_ungrab_focus_window_button (MetaDisplay *display,
                                               MetaWindow  *window);
 
-/* Next two functions are defined in edge-resistance.c */
-void meta_display_compute_resistance_and_snapping_edges (MetaDisplay *display);
-void meta_display_cleanup_edges                         (MetaDisplay *display);
+/* Next function is defined in edge-resistance.c */
+void meta_display_cleanup_edges              (MetaDisplay *display);
 
 /* make a request to ensure the event serial has changed */
 void     meta_display_increment_event_serial (MetaDisplay *display);
diff --git a/src/core/display.c b/src/core/display.c
index 7044557..3c9ca12 100644
--- a/src/core/display.c
+++ b/src/core/display.c
@@ -3658,18 +3658,6 @@ meta_display_begin_grab_op (MetaDisplay *display,
   g_assert (display->grab_window != NULL || display->grab_screen != NULL);
   g_assert (display->grab_op != META_GRAB_OP_NONE);
 
-  /* If this is a move or resize, cache the window edges for
-   * resistance/snapping
-   */
-  if (meta_grab_op_is_resizing (display->grab_op) ||
-      meta_grab_op_is_moving (display->grab_op))
-    {
-      meta_topic (META_DEBUG_WINDOW_OPS,
-                  "Computing edges to resist-movement or snap-to for %s.\n",
-                  window->desc);
-      meta_display_compute_resistance_and_snapping_edges (display);
-    }
-
   /* Save the old stacking */
   if (GRAB_OP_IS_WINDOW_SWITCH (display->grab_op))
     {
diff --git a/src/core/edge-resistance.c b/src/core/edge-resistance.c
index d4b5301..cb54730 100644
--- a/src/core/edge-resistance.c
+++ b/src/core/edge-resistance.c
@@ -61,6 +61,8 @@ struct MetaEdgeResistanceData
   ResistanceDataForAnEdge bottom_data;
 };
 
+static void compute_resistance_and_snapping_edges (MetaDisplay *display);
+
 /* !WARNING!: this function can return invalid indices (namely, either -1 or
  * edges->len); this is by design, but you need to remember this.
  */
@@ -552,7 +554,9 @@ apply_edge_resistance_to_each_side (MetaDisplay         *display,
   gboolean                modified;
   int new_left, new_right, new_top, new_bottom;
 
-  g_assert (display->grab_edge_resistance_data != NULL);
+  if (display->grab_edge_resistance_data == NULL)
+    compute_resistance_and_snapping_edges (display);
+
   edge_data = display->grab_edge_resistance_data;
 
   if (auto_snap)
@@ -673,7 +677,8 @@ meta_display_cleanup_edges (MetaDisplay *display)
   MetaEdgeResistanceData *edge_data = display->grab_edge_resistance_data;
   GHashTable *edges_to_be_freed;
 
-  g_assert (edge_data != NULL);
+  if (edge_data == NULL) /* Not currently cached */
+    return;
 
   /* We first need to clean out any window edges */
   edges_to_be_freed = g_hash_table_new_full (g_direct_hash, g_direct_equal,
@@ -938,8 +943,8 @@ initialize_grab_edge_resistance_data (MetaDisplay *display)
   edge_data->bottom_data.keyboard_buildup = 0;
 }
 
-void
-meta_display_compute_resistance_and_snapping_edges (MetaDisplay *display)
+static void
+compute_resistance_and_snapping_edges (MetaDisplay *display)
 {
   GList *stacked_windows;
   GList *cur_window_iter;
@@ -952,6 +957,11 @@ meta_display_compute_resistance_and_snapping_edges (MetaDisplay *display)
    */
   GSList *rem_windows, *rem_win_stacking;
 
+  g_assert (display->grab_window != NULL);
+  meta_topic (META_DEBUG_WINDOW_OPS,
+              "Computing edges to resist-movement or snap-to for %s.\n",
+              display->grab_window->desc);
+
   /*
    * 1st: Get the list of relevant windows, from bottom to top
    */
diff --git a/src/core/workspace.c b/src/core/workspace.c
index fef2128..9af548b 100644
--- a/src/core/workspace.c
+++ b/src/core/workspace.c
@@ -389,6 +389,11 @@ meta_workspace_activate_with_focus (MetaWorkspace *workspace,
   if (workspace->screen->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->screen->display);
+
   if (workspace->screen->active_workspace)
     workspace_switch_sound(workspace->screen->active_workspace, workspace);
 
@@ -553,6 +558,12 @@ meta_workspace_invalidate_work_area (MetaWorkspace *workspace)
               "Invalidating work area for workspace %d\n",
               meta_workspace_index (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->screen->active_workspace)
+    meta_display_cleanup_edges (workspace->screen->display);
+
   g_free (workspace->work_area_xinerama);
   workspace->work_area_xinerama = NULL;
 


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