Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulian Eisel <julian@blender.org>2021-11-04 14:10:58 +0300
committerJulian Eisel <julian@blender.org>2021-11-04 14:20:37 +0300
commit80a46955d8212f01b77215ab12d479d934e305f4 (patch)
tree538ddd4b47c195df8006456c046d6dce6bad1a20 /source/blender/windowmanager
parentbfb664b65de2c71ee3d85760ee5dcf83a7c9aa23 (diff)
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.
Diffstat (limited to 'source/blender/windowmanager')
-rw-r--r--source/blender/windowmanager/WM_types.h31
-rw-r--r--source/blender/windowmanager/intern/wm_dragdrop.c77
2 files changed, 66 insertions, 42 deletions
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 (drag->disabled_info) {
- wm_drop_redalert_draw(drag->disabled_info, x, y);
+ else if (has_disabled_info) {
+ wm_drop_redalert_draw(drag->drop_state.disabled_info, x, y);
}
}
@@ -905,22 +906,32 @@ void wm_drags_draw(bContext *C, wmWindow *win)
}
bScreen *screen = CTX_wm_screen(C);
+ /* To start with, use the area and region under the mouse cursor, just like event handling. The
+ * operator context may still override it. */
ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, UNPACK2(xy));
- ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_ANY, UNPACK2(xy));
- if (region) {
- BLI_assert(!CTX_wm_area(C) && !CTX_wm_region(C));
- CTX_wm_area_set(C, area);
- CTX_wm_region_set(C, region);
- }
+ ARegion *region = ED_area_find_region_xy_visual(area, RGN_TYPE_ANY, xy);
+ /* Will be overridden and unset eventually. */
+ BLI_assert(!CTX_wm_area(C) && !CTX_wm_region(C));
wmWindowManager *wm = CTX_wm_manager(C);
/* Should we support multi-line drag draws? Maybe not, more types mixed won't work well. */
GPU_blend(GPU_BLEND_ALPHA);
LISTBASE_FOREACH (wmDrag *, drag, &wm->drags) {
- if (drag->active_dropbox && drag->active_dropbox->draw) {
- drag->active_dropbox->draw(C, win, drag, xy);
- continue;
+ if (drag->drop_state.active_dropbox) {
+ CTX_wm_area_set(C, drag->drop_state.area_from);
+ CTX_wm_region_set(C, drag->drop_state.region_from);
+
+ /* Drawing should be allowed to assume the context from handling and polling (that's why we
+ * restore it above). */
+ if (drag->drop_state.active_dropbox->draw) {
+ drag->drop_state.active_dropbox->draw(C, win, drag, xy);
+ continue;
+ }
+ }
+ else if (region) {
+ CTX_wm_area_set(C, area);
+ CTX_wm_region_set(C, region);
}
wm_drag_draw_default(C, win, drag, xy);