From 80a46955d8212f01b77215ab12d479d934e305f4 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Thu, 4 Nov 2021 12:10:58 +0100 Subject: 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. --- source/blender/editors/include/ED_screen.h | 1 + .../editors/interface/interface_dropboxes.cc | 8 ++-- source/blender/editors/screen/area_query.c | 45 ++++++++++++++++++++++ 3 files changed, 50 insertions(+), 4 deletions(-) (limited to 'source/blender/editors') 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; +} -- cgit v1.2.3