[Bf-blender-cvs] [80a46955d82] blender-v3.0-release: Fix T92501: Crash when dragging material assets over 3D View regions

Julian Eisel noreply at git.blender.org
Thu Nov 4 12:25:23 CET 2021


Commit: 80a46955d8212f01b77215ab12d479d934e305f4
Author: Julian Eisel
Date:   Thu Nov 4 12:10:58 2021 +0100
Branches: blender-v3.0-release
https://developer.blender.org/rB80a46955d8212f01b77215ab12d479d934e305f4

Fix T92501: Crash when dragging material assets over 3D View regions

Issue was that the context used for dropbox handling and polling didn't
match the one used for drawing the dropbox and generating the tooltip
text (which would determine the material slot under the cursor,
requiring context). The mismatch would happen with overlapping regions.

Actually, this patch includes two fixes, each fixing the crash itself:
* Store the context from handling & polling and restore it for drawing.
* Correct the hovered region lookup for drawing to account for overlayed
  regions.

Note that to properly set up context for drawing, we should also account
for the operator context, which isn't done here, see
https://developer.blender.org/T92501#1247581.

===================================================================

M	source/blender/editors/include/ED_screen.h
M	source/blender/editors/interface/interface_dropboxes.cc
M	source/blender/editors/screen/area_query.c
M	source/blender/windowmanager/WM_types.h
M	source/blender/windowmanager/intern/wm_dragdrop.c

===================================================================

diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h
index 08b6c02a8d0..ef3ff7874df 100644
--- a/source/blender/editors/include/ED_screen.h
+++ b/source/blender/editors/include/ED_screen.h
@@ -439,6 +439,7 @@ bool ED_region_panel_category_gutter_calc_rect(const ARegion *region, rcti *r_re
 bool ED_region_panel_category_gutter_isect_xy(const ARegion *region, const int event_xy[2]);
 
 bool ED_region_contains_xy(const struct ARegion *region, const int event_xy[2]);
+ARegion *ED_area_find_region_xy_visual(const ScrArea *area, int regiontype, const int event_xy[2]);
 
 /* interface_region_hud.c */
 struct ARegionType *ED_area_type_hud(int space_type);
diff --git a/source/blender/editors/interface/interface_dropboxes.cc b/source/blender/editors/interface/interface_dropboxes.cc
index 81a1354cbe7..369efa7c52e 100644
--- a/source/blender/editors/interface/interface_dropboxes.cc
+++ b/source/blender/editors/interface/interface_dropboxes.cc
@@ -39,12 +39,12 @@ static bool ui_tree_view_drop_poll(bContext *C, wmDrag *drag, const wmEvent *eve
     return false;
   }
 
-  if (drag->free_disabled_info) {
-    MEM_SAFE_FREE(drag->disabled_info);
+  if (drag->drop_state.free_disabled_info) {
+    MEM_SAFE_FREE(drag->drop_state.disabled_info);
   }
 
-  drag->free_disabled_info = false;
-  return UI_tree_view_item_can_drop(hovered_tree_item, drag, &drag->disabled_info);
+  drag->drop_state.free_disabled_info = false;
+  return UI_tree_view_item_can_drop(hovered_tree_item, drag, &drag->drop_state.disabled_info);
 }
 
 static char *ui_tree_view_drop_tooltip(bContext *C,
diff --git a/source/blender/editors/screen/area_query.c b/source/blender/editors/screen/area_query.c
index fd4f3964398..30e744ca174 100644
--- a/source/blender/editors/screen/area_query.c
+++ b/source/blender/editors/screen/area_query.c
@@ -140,6 +140,10 @@ bool ED_region_overlap_isect_xy_with_margin(const ARegion *region,
           ED_region_overlap_isect_y_with_margin(region, event_xy[1], margin));
 }
 
+/**
+ * \note: This may return true for multiple overlapping regions. If it matters, check overlapped
+ *        regions first (#ARegion.overlap).
+ */
 bool ED_region_contains_xy(const ARegion *region, const int event_xy[2])
 {
   /* Only use the margin when inside the region. */
@@ -188,3 +192,44 @@ bool ED_region_contains_xy(const ARegion *region, const int event_xy[2])
   }
   return false;
 }
+
+/**
+ * Similar to #BKE_area_find_region_xy() but when \a event_xy intersects an overlapping region,
+ * this returns the region that is visually under the cursor. E.g. when over the
+ * transparent part of the region, it returns the region underneath.
+ *
+ * The overlapping region is determined using the #ED_region_contains_xy() query.
+ */
+ARegion *ED_area_find_region_xy_visual(const ScrArea *area,
+                                       const int regiontype,
+                                       const int event_xy[2])
+{
+  if (!area) {
+    return NULL;
+  }
+
+  /* Check overlapped regions first. */
+  LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
+    if (!region->overlap) {
+      continue;
+    }
+    if (ELEM(regiontype, RGN_TYPE_ANY, region->regiontype)) {
+      if (ED_region_contains_xy(region, event_xy)) {
+        return region;
+      }
+    }
+  }
+  /* Now non-overlapping ones. */
+  LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
+    if (region->overlap) {
+      continue;
+    }
+    if (ELEM(regiontype, RGN_TYPE_ANY, region->regiontype)) {
+      if (ED_region_contains_xy(region, event_xy)) {
+        return region;
+      }
+    }
+  }
+
+  return NULL;
+}
diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h
index 9f427a90353..27c8aa532f2 100644
--- a/source/blender/windowmanager/WM_types.h
+++ b/source/blender/windowmanager/WM_types.h
@@ -1030,6 +1030,27 @@ typedef char *(*WMDropboxTooltipFunc)(struct bContext *,
                                       const int xy[2],
                                       struct wmDropBox *drop);
 
+typedef struct wmDragActiveDropState {
+  /** Informs which dropbox is activated with the drag item.
+   * When this value changes, the #draw_activate and #draw_deactivate dropbox callbacks are
+   * triggered.
+   */
+  struct wmDropBox *active_dropbox;
+
+  /** If `active_dropbox` is set, the area it successfully polled in. To restore the context of it
+   * as needed. */
+  struct ScrArea *area_from;
+  /** If `active_dropbox` is set, the region it successfully polled in. To restore the context of
+   * it as needed. */
+  struct ARegion *region_from;
+
+  /** Text to show when a dropbox poll succeeds (so the dropbox itself is available) but the
+   * operator poll fails. Typically the message the operator set with
+   * CTX_wm_operator_poll_msg_set(). */
+  const char *disabled_info;
+  bool free_disabled_info;
+} wmDragActiveDropState;
+
 typedef struct wmDrag {
   struct wmDrag *next, *prev;
 
@@ -1045,15 +1066,7 @@ typedef struct wmDrag {
   float scale;
   int sx, sy;
 
-  /** Informs which dropbox is activated with the drag item.
-   * When this value changes, the #draw_activate and #draw_deactivate dropbox callbacks are
-   * triggered.
-   */
-  struct wmDropBox *active_dropbox;
-  /* Text to show when the operator poll fails. Typically the message the
-   * operator set with CTX_wm_operator_poll_msg_set(). */
-  const char *disabled_info;
-  bool free_disabled_info;
+  wmDragActiveDropState drop_state;
 
   unsigned int flags;
 
diff --git a/source/blender/windowmanager/intern/wm_dragdrop.c b/source/blender/windowmanager/intern/wm_dragdrop.c
index 37a101cc31d..85378ffd7c7 100644
--- a/source/blender/windowmanager/intern/wm_dragdrop.c
+++ b/source/blender/windowmanager/intern/wm_dragdrop.c
@@ -51,6 +51,7 @@
 #include "BLO_readfile.h"
 
 #include "ED_asset.h"
+#include "ED_screen.h"
 
 #include "GPU_shader.h"
 #include "GPU_state.h"
@@ -217,7 +218,7 @@ void wm_drags_exit(wmWindowManager *wm, wmWindow *win)
 {
   bool any_active = false;
   LISTBASE_FOREACH (const wmDrag *, drag, &wm->drags) {
-    if (drag->active_dropbox) {
+    if (drag->drop_state.active_dropbox) {
       any_active = true;
       break;
     }
@@ -260,14 +261,14 @@ void WM_drag_data_free(int dragtype, void *poin)
 
 void WM_drag_free(wmDrag *drag)
 {
-  if (drag->active_dropbox && drag->active_dropbox->draw_deactivate) {
-    drag->active_dropbox->draw_deactivate(drag->active_dropbox, drag);
+  if (drag->drop_state.active_dropbox && drag->drop_state.active_dropbox->draw_deactivate) {
+    drag->drop_state.active_dropbox->draw_deactivate(drag->drop_state.active_dropbox, drag);
   }
   if (drag->flags & WM_DRAG_FREE_DATA) {
     WM_drag_data_free(drag->type, drag->poin);
   }
-  if (drag->free_disabled_info) {
-    MEM_SAFE_FREE(drag->disabled_info);
+  if (drag->drop_state.free_disabled_info) {
+    MEM_SAFE_FREE(drag->drop_state.disabled_info);
   }
   BLI_freelistN(&drag->ids);
   LISTBASE_FOREACH_MUTABLE (wmDragAssetListItem *, asset_item, &drag->asset_items) {
@@ -306,10 +307,10 @@ static wmDropBox *dropbox_active(bContext *C,
                                  wmDrag *drag,
                                  const wmEvent *event)
 {
-  if (drag->free_disabled_info) {
-    MEM_SAFE_FREE(drag->disabled_info);
+  if (drag->drop_state.free_disabled_info) {
+    MEM_SAFE_FREE(drag->drop_state.disabled_info);
   }
-  drag->disabled_info = NULL;
+  drag->drop_state.disabled_info = NULL;
 
   LISTBASE_FOREACH (wmEventHandler *, handler_base, handlers) {
     if (handler_base->type == WM_HANDLER_TYPE_DROPBOX) {
@@ -332,8 +333,8 @@ static wmDropBox *dropbox_active(bContext *C,
           bool free_disabled_info = false;
           const char *disabled_hint = CTX_wm_operator_poll_msg_get(C, &free_disabled_info);
           if (disabled_hint) {
-            drag->disabled_info = disabled_hint;
-            drag->free_disabled_info = free_disabled_info;
+            drag->drop_state.disabled_info = disabled_hint;
+            drag->drop_state.free_disabled_info = free_disabled_info;
           }
         }
       }
@@ -373,7 +374,7 @@ static void wm_drop_update_active(bContext *C, wmDrag *drag, const wmEvent *even
     return;
   }
 
-  wmDropBox *drop_prev = drag->active_dropbox;
+  wmDropBox *drop_prev = drag->drop_state.active_dropbox;
   wmDropBox *drop = wm_dropbox_active(C, drag, event);
   if (drop != drop_prev) {
     if (drop_prev && drop_prev->draw_deactivate) {
@@ -383,7 +384,9 @@ static void wm_drop_update_active(bContext *C, wmDrag *drag, const wmEvent *even
     if (drop && drop->draw_activate) {
       drop->draw_activate(drop, drag);
     }
-    drag->active_dropbox = drop;
+    drag->drop_state.active_dropbox = drop;
+    drag->drop_state.area_from = drop ? CTX_wm_area(C) : NULL;
+    drag->drop_state.region_from = drop ? CTX_wm_region(C) : NULL;
   }
 }
 
@@ -408,7 +411,7 @@ void wm_drags_check_ops(bContext *C, const wmEvent *event)
   LISTBASE_FOREACH (wmDrag *, drag, &wm->drags) {
     wm_drop_update_active(C, drag, event);
 
-    if (drag->active_dropbox) {
+    if (drag->drop_state.active_dropbox) {
       any_active = true;
     }
   }
@@ -819,14 +822,14 @@ static void wm_drag_draw_tooltip(bContext *C, wmWindow *win, wmDrag *drag, const
   int iconsize = UI_DPI_ICON_SIZE;
   int padding = 4 * UI_DPI_FAC;
 
-  const char *tooltip = NULL;
-  bool free_tooltip = false;
-  if (drag->active_dropbox) {
-    tooltip = dropbox_tooltip(C, drag, xy, drag->active_dropbox);
-    free_tooltip = true;
+  char *tooltip = NULL;
+  if (drag->drop_state.active_dropbox) {
+    tooltip = dropbox_tooltip(C, drag, xy, drag->drop_state.active_dropbox);
   }
 
-  if (!tooltip && !drag->disabled_info) {
+  const bool has_disabled_info = drag->drop_state.disabled_info &&
+                                 drag->drop_state.disabled_info[0];
+  if (!tooltip && !has_disabled_info) {
     return;
   }
 
@@ -855,12 +858,10 @@ static void wm_drag_draw_tooltip(bContext *C, wmWindow *win, wmDrag *drag, const
 
   if (tooltip) {
     wm_drop_operator_draw(tooltip, x, y);
-    if (free_tooltip) {
-      MEM_freeN((void *)tooltip);
-    }
+    MEM_freeN(tooltip);
   }
-  else if

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list