diff options
author | Julian Eisel <julian@blender.org> | 2020-06-05 14:09:31 +0300 |
---|---|---|
committer | Julian Eisel <julian@blender.org> | 2020-06-05 14:09:31 +0300 |
commit | 920a58d9b6d667894cf166cbbd25e4c2fbd238ea (patch) | |
tree | 7ca5a9da640753b5e070c439ac3bdd14dfad92cf /source/blender/windowmanager | |
parent | c94b6209861ca7cc3985b53474feed7d94c0221a (diff) | |
parent | a1d55bdd530390e58c51abe9707b8d3b0ae3e861 (diff) |
Merge branch 'master' into wm-drag-drop-rewritewm-drag-drop-rewrite
Diffstat (limited to 'source/blender/windowmanager')
49 files changed, 2190 insertions, 1777 deletions
diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt index a1b67216f1a..7c749c60168 100644 --- a/source/blender/windowmanager/CMakeLists.txt +++ b/source/blender/windowmanager/CMakeLists.txt @@ -153,8 +153,8 @@ endif() if(WITH_HEADLESS) add_definitions(-DWITH_HEADLESS) -elseif(WITH_X11) - add_definitions(-DWITH_X11) +elseif(WITH_GHOST_X11) + add_definitions(-DWITH_GHOST_X11) endif() if(WITH_PYTHON) @@ -168,10 +168,6 @@ if(WITH_BUILDINFO) add_definitions(-DWITH_BUILDINFO) endif() -if(WITH_OPENSUBDIV) - add_definitions(-DWITH_OPENSUBDIV) -endif() - if(WITH_INPUT_NDOF) add_definitions(-DWITH_INPUT_NDOF) endif() @@ -191,8 +187,18 @@ endif() if(WITH_XR_OPENXR) add_definitions(-DWITH_XR_OPENXR) + + list(APPEND INC + xr + ) + list(APPEND SRC - intern/wm_xr.c + xr/intern/wm_xr.c + xr/intern/wm_xr_draw.c + xr/intern/wm_xr_session.c + + xr/wm_xr.h + xr/intern/wm_xr_intern.h ) endif() diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index cc8b1bb4882..a886d1440d9 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -64,6 +64,7 @@ struct wmJob; struct wmOperator; struct wmOperatorType; struct wmPaintCursor; +struct wmTabletData; struct wmDragData; struct wmDropTarget; struct wmDropTargetFinder; @@ -106,6 +107,17 @@ void WM_reinit_gizmomap_all(struct Main *bmain); void WM_script_tag_reload(void); +bool WM_window_find_under_cursor(const wmWindowManager *wm, + const wmWindow *win_ignore, + const wmWindow *win, + const int mval[2], + wmWindow **r_win, + int r_mval[2]); +void WM_window_pixel_sample_read(const wmWindowManager *wm, + const wmWindow *win, + const int pos[2], + float r_col[3]); + uint *WM_window_pixels_read(struct wmWindowManager *wm, struct wmWindow *win, int r_size[2]); int WM_window_pixels_x(const struct wmWindow *win); @@ -157,10 +169,6 @@ void *WM_opengl_context_create(void); void WM_opengl_context_dispose(void *context); void WM_opengl_context_activate(void *context); void WM_opengl_context_release(void *context); -#ifdef WIN32 -void *WM_directx_context_create(void); -void WM_directx_context_dispose(void *context); -#endif struct wmWindow *WM_window_open(struct bContext *C, const struct rcti *rect); struct wmWindow *WM_window_open_temp(struct bContext *C, @@ -193,7 +201,7 @@ void WM_lib_reload(struct Library *lib, struct bContext *C, struct ReportList *r /* mouse cursors */ void WM_cursor_set(struct wmWindow *win, int curs); -bool WM_cursor_set_from_tool(struct wmWindow *win, const ScrArea *sa, const ARegion *region); +bool WM_cursor_set_from_tool(struct wmWindow *win, const ScrArea *area, const ARegion *region); void WM_cursor_modal_set(struct wmWindow *win, int curs); void WM_cursor_modal_restore(struct wmWindow *win); void WM_cursor_wait(bool val); @@ -202,14 +210,13 @@ void WM_cursor_grab_disable(struct wmWindow *win, const int mouse_ungrab_xy[2]); void WM_cursor_time(struct wmWindow *win, int nr); struct wmPaintCursor *WM_paint_cursor_activate( - struct wmWindowManager *wm, short space_type, short region_type, bool (*poll)(struct bContext *C), void (*draw)(struct bContext *C, int, int, void *customdata), void *customdata); -bool WM_paint_cursor_end(struct wmWindowManager *wm, struct wmPaintCursor *handle); +bool WM_paint_cursor_end(struct wmPaintCursor *handle); void WM_paint_cursor_tag_redraw(struct wmWindow *win, struct ARegion *region); void WM_cursor_warp(struct wmWindow *win, int x, int y); @@ -621,7 +628,7 @@ int WM_gesture_lasso_modal(struct bContext *C, struct wmOperator *op, const stru void WM_gesture_lasso_cancel(struct bContext *C, struct wmOperator *op); const int (*WM_gesture_lasso_path_to_array(struct bContext *C, struct wmOperator *op, - int *mcords_tot))[2]; + int *mcoords_len))[2]; int WM_gesture_straightline_invoke(struct bContext *C, struct wmOperator *op, const struct wmEvent *event); @@ -841,7 +848,7 @@ void WM_draw_region_viewport_bind(struct ARegion *region); void WM_draw_region_viewport_unbind(struct ARegion *region); /* Region drawing */ -void WM_draw_region_free(struct ARegion *region); +void WM_draw_region_free(struct ARegion *region, bool hide); struct GPUViewport *WM_draw_region_get_viewport(struct ARegion *region); struct GPUViewport *WM_draw_region_get_bound_viewport(struct ARegion *region); @@ -853,6 +860,8 @@ bool write_crash_blend(void); /* Lock the interface for any communication */ void WM_set_locked_interface(struct wmWindowManager *wm, bool lock); +void WM_event_tablet_data_default_set(struct wmTabletData *tablet_data); + /* For testing only 'G_FLAG_EVENT_SIMULATE' */ struct wmEvent *WM_event_add_simulate(struct wmWindow *win, const struct wmEvent *event_to_add); @@ -862,7 +871,7 @@ const char *WM_window_cursor_keymap_status_get(const struct wmWindow *win, void WM_window_cursor_keymap_status_refresh(struct bContext *C, struct wmWindow *win); void WM_window_status_area_tag_redraw(struct wmWindow *win); -struct ScrArea *WM_window_status_area_find(struct wmWindow *win, struct bScreen *sc); +struct ScrArea *WM_window_status_area_find(struct wmWindow *win, struct bScreen *screen); bool WM_window_modal_keymap_status_draw(struct bContext *C, struct wmWindow *win, struct uiLayout *layout); @@ -909,18 +918,18 @@ typedef struct ARegion *(*wmTooltipInitFn)(struct bContext *C, void WM_tooltip_immediate_init(struct bContext *C, struct wmWindow *win, - struct ScrArea *sa, + struct ScrArea *area, struct ARegion *region, wmTooltipInitFn init); void WM_tooltip_timer_init_ex(struct bContext *C, struct wmWindow *win, - struct ScrArea *sa, + struct ScrArea *area, struct ARegion *region, wmTooltipInitFn init, double delay); void WM_tooltip_timer_init(struct bContext *C, struct wmWindow *win, - struct ScrArea *sa, + struct ScrArea *area, struct ARegion *region, wmTooltipInitFn init); void WM_tooltip_timer_clear(struct bContext *C, struct wmWindow *win); @@ -935,11 +944,14 @@ void WM_generic_callback_free(struct wmGenericCallback *callback); void WM_generic_user_data_free(struct wmGenericUserData *user_data); +bool WM_region_use_viewport(struct ScrArea *area, struct ARegion *region); + #ifdef WITH_XR_OPENXR /* wm_xr.c */ bool WM_xr_session_exists(const wmXrData *xr); bool WM_xr_session_is_ready(const wmXrData *xr); struct wmXrSessionState *WM_xr_session_state_handle_get(const wmXrData *xr); +void WM_xr_session_base_pose_reset(wmXrData *xr); bool WM_xr_session_state_viewer_pose_location_get(const wmXrData *xr, float r_location[3]); bool WM_xr_session_state_viewer_pose_rotation_get(const wmXrData *xr, float r_rotation[4]); bool WM_xr_session_state_viewer_pose_matrix_info_get(const wmXrData *xr, diff --git a/source/blender/windowmanager/WM_keymap.h b/source/blender/windowmanager/WM_keymap.h index 2cf71dcf165..53a3fd5ebda 100644 --- a/source/blender/windowmanager/WM_keymap.h +++ b/source/blender/windowmanager/WM_keymap.h @@ -82,7 +82,7 @@ wmKeyMap *WM_keymap_find_all_spaceid_or_empty(struct wmWindowManager *wm, const char *idname, int spaceid, int regionid); -wmKeyMap *WM_keymap_active(struct wmWindowManager *wm, struct wmKeyMap *keymap); +wmKeyMap *WM_keymap_active(const struct wmWindowManager *wm, struct wmKeyMap *keymap); bool WM_keymap_remove(struct wmKeyConfig *keyconfig, struct wmKeyMap *keymap); bool WM_keymap_poll(struct bContext *C, struct wmKeyMap *keymap); @@ -135,10 +135,10 @@ char *WM_modalkeymap_operator_items_to_string_buf(struct wmOperatorType *ot, int *r_available_len, char **r_result); -wmKeyMap *WM_modalkeymap_add(struct wmKeyConfig *keyconf, - const char *idname, - const struct EnumPropertyItem *items); -wmKeyMap *WM_modalkeymap_get(struct wmKeyConfig *keyconf, const char *idname); +wmKeyMap *WM_modalkeymap_ensure(struct wmKeyConfig *keyconf, + const char *idname, + const struct EnumPropertyItem *items); +wmKeyMap *WM_modalkeymap_find(struct wmKeyConfig *keyconf, const char *idname); wmKeyMapItem *WM_modalkeymap_add_item( struct wmKeyMap *km, int type, int val, int modifier, int keymodifier, int value); wmKeyMapItem *WM_modalkeymap_add_item_str( diff --git a/source/blender/windowmanager/WM_toolsystem.h b/source/blender/windowmanager/WM_toolsystem.h index 36cb5be7547..163f37be974 100644 --- a/source/blender/windowmanager/WM_toolsystem.h +++ b/source/blender/windowmanager/WM_toolsystem.h @@ -87,17 +87,17 @@ void WM_toolsystem_ref_sync_from_context(struct Main *bmain, void WM_toolsystem_init(struct bContext *C); int WM_toolsystem_mode_from_spacetype(struct ViewLayer *view_layer, - struct ScrArea *sa, + struct ScrArea *area, int space_type); bool WM_toolsystem_key_from_context(struct ViewLayer *view_layer, - struct ScrArea *sa, + struct ScrArea *area, bToolKey *tkey); void WM_toolsystem_update_from_context_view3d(struct bContext *C); void WM_toolsystem_update_from_context(struct bContext *C, struct WorkSpace *workspace, struct ViewLayer *view_layer, - struct ScrArea *sa); + struct ScrArea *area); bool WM_toolsystem_active_tool_is_brush(const struct bContext *C); @@ -134,7 +134,7 @@ void WM_toolsystem_refresh_active(struct bContext *C); void WM_toolsystem_refresh_screen_area(struct WorkSpace *workspace, struct ViewLayer *view_layer, - struct ScrArea *sa); + struct ScrArea *area); void WM_toolsystem_refresh_screen_all(struct Main *bmain); #ifdef __cplusplus diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index b5f633d688d..48bd9ed9638 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -81,7 +81,7 @@ * ScrArea's store a list of space data (SpaceLinks), each of unique type. * The first one is the displayed in the UI, others are added as needed. * - * +----------------------------+ <-- sa->spacedata.first; + * +----------------------------+ <-- area->spacedata.first; * | | * | |---+ <-- other inactive SpaceLink's stored. * | | | @@ -99,8 +99,8 @@ * * A common way to get the space from the ScrArea: * \code{.c} - * if (sa->spacetype == SPACE_VIEW3D) { - * View3D *v3d = sa->spacedata.first; + * if (area->spacetype == SPACE_VIEW3D) { + * View3D *v3d = area->spacedata.first; * ... * } * \endcode @@ -109,10 +109,6 @@ #ifndef __WM_TYPES_H__ #define __WM_TYPES_H__ -#ifdef __cplusplus -extern "C" { -#endif - struct ID; struct ImBuf; struct bContext; @@ -133,6 +129,10 @@ struct wmWindowManager; /* Include external gizmo API's */ #include "gizmo/WM_gizmo_api.h" +#ifdef __cplusplus +extern "C" { +#endif + typedef struct wmGenericUserData { void *data; /** When NULL, use #MEM_freeN. */ @@ -310,7 +310,7 @@ typedef struct wmNotifier { #define ND_HISTORY (4 << 16) #define ND_JOB (5 << 16) #define ND_UNDO (6 << 16) -#define ND_XR_DATA_CHANGED (7 << 17) +#define ND_XR_DATA_CHANGED (7 << 16) /* NC_SCREEN */ #define ND_LAYOUTBROWSE (1 << 16) @@ -760,7 +760,7 @@ typedef struct wmOperatorType { bool (*pyop_poll)(struct bContext *, struct wmOperatorType *ot) ATTR_WARN_UNUSED_RESULT; /** RNA integration */ - ExtensionRNA ext; + ExtensionRNA rna_ext; /** Flag last for padding */ short flag; diff --git a/source/blender/windowmanager/gizmo/WM_gizmo_api.h b/source/blender/windowmanager/gizmo/WM_gizmo_api.h index 44c1804aa4d..07a3f0445bb 100644 --- a/source/blender/windowmanager/gizmo/WM_gizmo_api.h +++ b/source/blender/windowmanager/gizmo/WM_gizmo_api.h @@ -373,7 +373,7 @@ void WM_gizmo_group_type_unlink_delayed(const char *idname); void WM_gizmo_group_unlink_delayed_ptr_from_space(struct wmGizmoGroupType *gzgt, struct wmGizmoMapType *gzmap_type, - struct ScrArea *sa); + struct ScrArea *area); /* Has the result of unlinking and linking (re-initializes gizmo's). */ void WM_gizmo_group_type_reinit_ptr_ex(struct Main *bmain, diff --git a/source/blender/windowmanager/gizmo/WM_gizmo_types.h b/source/blender/windowmanager/gizmo/WM_gizmo_types.h index d2953a56749..346ed131c59 100644 --- a/source/blender/windowmanager/gizmo/WM_gizmo_types.h +++ b/source/blender/windowmanager/gizmo/WM_gizmo_types.h @@ -67,28 +67,33 @@ typedef enum eWM_GizmoFlag { WM_GIZMO_DRAW_VALUE = (1 << 2), WM_GIZMO_HIDDEN = (1 << 3), WM_GIZMO_HIDDEN_SELECT = (1 << 4), + /** Ignore the key-map for this gizmo. */ + WM_GIZMO_HIDDEN_KEYMAP = (1 << 5), /** * When set 'scale_final' value also scales the offset. * Use when offset is to avoid screen-space overlap instead of absolute positioning. */ - WM_GIZMO_DRAW_OFFSET_SCALE = (1 << 5), + WM_GIZMO_DRAW_OFFSET_SCALE = (1 << 6), /** * User should still use 'scale_final' for any handles and UI elements. * This simply skips scale when calculating the final matrix. * Needed when the gizmo needs to align with the interface underneath it. */ - WM_GIZMO_DRAW_NO_SCALE = (1 << 6), + WM_GIZMO_DRAW_NO_SCALE = (1 << 7), /** * Hide the cursor and lock it's position while interacting with this gizmo. */ - WM_GIZMO_MOVE_CURSOR = (1 << 7), + WM_GIZMO_MOVE_CURSOR = (1 << 8), /** Don't write into the depth buffer when selecting. */ - WM_GIZMO_SELECT_BACKGROUND = (1 << 8), + WM_GIZMO_SELECT_BACKGROUND = (1 << 9), /** Use the active tools operator properties when running as an operator. */ - WM_GIZMO_OPERATOR_TOOL_INIT = (1 << 9), + WM_GIZMO_OPERATOR_TOOL_INIT = (1 << 10), /** Don't pass through events to other handlers * (allows click/drag not to have it's events stolen by press events in other keymaps). */ - WM_GIZMO_EVENT_HANDLE_ALL = (1 << 10), + WM_GIZMO_EVENT_HANDLE_ALL = (1 << 11), + + /** Don't use tool-tips for this gizmo (can be distracting). */ + WM_GIZMO_NO_TOOLTIP = (1 << 12), } eWM_GizmoFlag; /** @@ -381,7 +386,7 @@ typedef struct wmGizmoType { struct StructRNA *srna; /** RNA integration. */ - ExtensionRNA ext; + ExtensionRNA rna_ext; ListBase target_property_defs; int target_property_defs_len; @@ -436,7 +441,7 @@ typedef struct wmGizmoGroupType { struct StructRNA *srna; /** RNA integration. */ - ExtensionRNA ext; + ExtensionRNA rna_ext; eWM_GizmoFlagGroupTypeFlag flag; diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c index ef270533855..67f30f0d7ee 100644 --- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c +++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c @@ -222,7 +222,7 @@ wmGizmo *wm_gizmogroup_find_intersected_gizmo(wmWindowManager *wm, { int gzgroup_keymap_uses_modifier = -1; - for (wmGizmo *gz = gzgroup->gizmos.first; gz; gz = gz->next) { + LISTBASE_FOREACH (wmGizmo *, gz, &gzgroup->gizmos) { if (gz->type->test_select && (gz->flag & (WM_GIZMO_HIDDEN | WM_GIZMO_HIDDEN_SELECT)) == 0) { if (!wm_gizmo_keymap_uses_event_modifier( @@ -298,10 +298,10 @@ void WM_gizmo_group_remove_by_tool(bContext *C, const bToolRef *tref) { wmGizmoMapType *gzmap_type = WM_gizmomaptype_find(&gzgt->gzmap_params); - for (bScreen *sc = bmain->screens.first; sc; sc = sc->id.next) { - for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) { - if (sa->runtime.tool == tref) { - for (ARegion *region = sa->regionbase.first; region; region = region->next) { + for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) { + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + if (area->runtime.tool == tref) { + LISTBASE_FOREACH (ARegion *, region, &area->regionbase) { wmGizmoMap *gzmap = region->gizmo_map; if (gzmap && gzmap->type == gzmap_type) { wmGizmoGroup *gzgroup, *gzgroup_next; @@ -337,7 +337,7 @@ bool wm_gizmogroup_is_visible_in_drawstep(const wmGizmoGroup *gzgroup, bool wm_gizmogroup_is_any_selected(const wmGizmoGroup *gzgroup) { if (gzgroup->type->flag & WM_GIZMOGROUPTYPE_SELECT) { - for (const wmGizmo *gz = gzgroup->gizmos.first; gz; gz = gz->next) { + LISTBASE_FOREACH (const wmGizmo *, gz, &gzgroup->gizmos) { if (gz->state & WM_GIZMO_STATE_SELECT) { return true; } @@ -665,14 +665,14 @@ wmKeyMap *wm_gizmogroup_tweak_modal_keymap(wmKeyConfig *kc) }; STRNCPY(name, "Generic Gizmo Tweak Modal Map"); - keymap = WM_modalkeymap_get(kc, name); + keymap = WM_modalkeymap_find(kc, name); /* this function is called for each spacetype, only needs to add map once */ if (keymap && keymap->modal_items) { return NULL; } - keymap = WM_modalkeymap_add(kc, name, modal_items); + keymap = WM_modalkeymap_ensure(kc, name, modal_items); /* items for modal map */ WM_modalkeymap_add_item(keymap, EVT_ESCKEY, KM_PRESS, KM_ANY, 0, TWEAK_MODAL_CANCEL); @@ -850,8 +850,7 @@ struct wmGizmoGroupTypeRef *WM_gizmomaptype_group_find_ptr(struct wmGizmoMapType const wmGizmoGroupType *gzgt) { /* could use hash lookups as operator types do, for now simple search. */ - for (wmGizmoGroupTypeRef *gzgt_ref = gzmap_type->grouptype_refs.first; gzgt_ref; - gzgt_ref = gzgt_ref->next) { + LISTBASE_FOREACH (wmGizmoGroupTypeRef *, gzgt_ref, &gzmap_type->grouptype_refs) { if (gzgt_ref->type == gzgt) { return gzgt_ref; } @@ -863,8 +862,7 @@ struct wmGizmoGroupTypeRef *WM_gizmomaptype_group_find(struct wmGizmoMapType *gz const char *idname) { /* could use hash lookups as operator types do, for now simple search. */ - for (wmGizmoGroupTypeRef *gzgt_ref = gzmap_type->grouptype_refs.first; gzgt_ref; - gzgt_ref = gzgt_ref->next) { + LISTBASE_FOREACH (wmGizmoGroupTypeRef *, gzgt_ref, &gzmap_type->grouptype_refs) { if (STREQ(idname, gzgt_ref->type->idname)) { return gzgt_ref; } @@ -908,11 +906,11 @@ void WM_gizmomaptype_group_init_runtime(const Main *bmain, } /* now create a gizmo for all existing areas */ - for (bScreen *sc = bmain->screens.first; sc; sc = sc->id.next) { - for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) { - for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) { - ListBase *lb = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase; - for (ARegion *region = lb->first; region; region = region->next) { + for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) { + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) { + ListBase *lb = (sl == area->spacedata.first) ? &area->regionbase : &sl->regionbase; + LISTBASE_FOREACH (ARegion *, region, lb) { wmGizmoMap *gzmap = region->gizmo_map; if (gzmap && gzmap->type == gzmap_type) { WM_gizmomaptype_group_init_runtime_with_region(gzmap_type, gzgt, region); @@ -963,11 +961,11 @@ void WM_gizmomaptype_group_unlink(bContext *C, const wmGizmoGroupType *gzgt) { /* Free instances. */ - for (bScreen *sc = bmain->screens.first; sc; sc = sc->id.next) { - for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) { - for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) { - ListBase *lb = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase; - for (ARegion *region = lb->first; region; region = region->next) { + for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) { + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) { + ListBase *lb = (sl == area->spacedata.first) ? &area->regionbase : &sl->regionbase; + LISTBASE_FOREACH (ARegion *, region, lb) { wmGizmoMap *gzmap = region->gizmo_map; if (gzmap && gzmap->type == gzmap_type) { wmGizmoGroup *gzgroup, *gzgroup_next; @@ -1132,12 +1130,12 @@ void WM_gizmo_group_type_unlink_delayed(const char *idname) void WM_gizmo_group_unlink_delayed_ptr_from_space(wmGizmoGroupType *gzgt, wmGizmoMapType *gzmap_type, - ScrArea *sa) + ScrArea *area) { - for (ARegion *region = sa->regionbase.first; region; region = region->next) { + LISTBASE_FOREACH (ARegion *, region, &area->regionbase) { wmGizmoMap *gzmap = region->gizmo_map; if (gzmap && gzmap->type == gzmap_type) { - for (wmGizmoGroup *gzgroup = gzmap->groups.first; gzgroup; gzgroup = gzgroup->next) { + LISTBASE_FOREACH (wmGizmoGroup *, gzgroup, &gzmap->groups) { if (gzgroup->type == gzgt) { WM_gizmo_group_tag_remove(gzgroup); } diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_group_type.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_group_type.c index 560d73ec220..f594ced6b66 100644 --- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_group_type.c +++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_group_type.c @@ -144,7 +144,7 @@ wmGizmoGroupTypeRef *WM_gizmogrouptype_append_and_link(wmGizmoMapType *gzmap_typ */ static void gizmogrouptype_free(wmGizmoGroupType *gzgt) { - if (gzgt->ext.srna) { /* python gizmo group, allocs own string */ + if (gzgt->rna_ext.srna) { /* python gizmo group, allocs own string */ MEM_freeN((void *)gzgt->idname); } diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c index 286afe42158..6ed6c485e89 100644 --- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c +++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c @@ -171,8 +171,7 @@ static wmGizmoMap *wm_gizmomap_new_from_type_ex(struct wmGizmoMapType *gzmap_typ /* create all gizmo-groups for this gizmo-map. We may create an empty one * too in anticipation of gizmos from operators etc */ - for (wmGizmoGroupTypeRef *gzgt_ref = gzmap_type->grouptype_refs.first; gzgt_ref; - gzgt_ref = gzgt_ref->next) { + LISTBASE_FOREACH (wmGizmoGroupTypeRef *, gzgt_ref, &gzmap_type->grouptype_refs) { wm_gizmogroup_new_from_type(gzmap, gzgt_ref->type); } @@ -231,7 +230,7 @@ wmGizmoGroup *WM_gizmomap_group_find(struct wmGizmoMap *gzmap, const char *idnam wmGizmoGroup *WM_gizmomap_group_find_ptr(struct wmGizmoMap *gzmap, const struct wmGizmoGroupType *gzgt) { - for (wmGizmoGroup *gzgroup = gzmap->groups.first; gzgroup; gzgroup = gzgroup->next) { + LISTBASE_FOREACH (wmGizmoGroup *, gzgroup, &gzmap->groups) { if (gzgroup->type == gzgt) { return gzgroup; } @@ -290,9 +289,9 @@ static GHash *WM_gizmomap_gizmo_hash_new(const bContext *C, GHash *hash = BLI_ghash_ptr_new(__func__); /* collect gizmos */ - for (wmGizmoGroup *gzgroup = gzmap->groups.first; gzgroup; gzgroup = gzgroup->next) { + LISTBASE_FOREACH (wmGizmoGroup *, gzgroup, &gzmap->groups) { if (WM_gizmo_group_type_poll(C, gzgroup->type)) { - for (wmGizmo *gz = gzgroup->gizmos.first; gz; gz = gz->next) { + LISTBASE_FOREACH (wmGizmo *, gz, &gzgroup->gizmos) { if (((flag_exclude == 0) || ((gz->flag & flag_exclude) == 0)) && (!poll || poll(gz, data))) { BLI_ghash_insert(hash, gz, gz); @@ -335,7 +334,7 @@ void WM_gizmomap_tag_refresh(wmGizmoMap *gzmap) bool WM_gizmomap_tag_delay_refresh_for_tweak_check(wmGizmoMap *gzmap) { - for (wmGizmoGroup *gzgroup = gzmap->groups.first; gzgroup; gzgroup = gzgroup->next) { + LISTBASE_FOREACH (wmGizmoGroup *, gzgroup, &gzmap->groups) { if (gzgroup->hide.delay_refresh_for_tweak) { return true; } @@ -403,7 +402,7 @@ static void gizmomap_prepare_drawing(wmGizmoMap *gzmap, const bool do_refresh = gzmap->update_flag[drawstep] & GIZMOMAP_IS_REFRESH_CALLBACK; gzmap->update_flag[drawstep] &= ~GIZMOMAP_IS_REFRESH_CALLBACK; - for (wmGizmoGroup *gzgroup = gzmap->groups.first; gzgroup; gzgroup = gzgroup->next) { + LISTBASE_FOREACH (wmGizmoGroup *, gzgroup, &gzmap->groups) { /* check group visibility - drawstep first to avoid unnecessary call of group poll callback */ if (!wm_gizmogroup_is_visible_in_drawstep(gzgroup, drawstep) || !WM_gizmo_group_type_poll(C, gzgroup->type)) { @@ -430,7 +429,7 @@ static void gizmomap_prepare_drawing(wmGizmoMap *gzmap, gzgroup->type->draw_prepare(C, gzgroup); } - for (wmGizmo *gz = gzgroup->gizmos.first; gz; gz = gz->next) { + LISTBASE_FOREACH (wmGizmo *, gz, &gzgroup->gizmos) { gizmo_prepare_drawing(gzmap, gz, C, draw_gizmos, drawstep); } } @@ -577,9 +576,9 @@ static int gizmo_find_intersected_3d_intern(wmGizmo **visible_gizmos, const int hotspot) { const wmWindowManager *wm = CTX_wm_manager(C); - ScrArea *sa = CTX_wm_area(C); + ScrArea *area = CTX_wm_area(C); ARegion *region = CTX_wm_region(C); - View3D *v3d = sa->spacedata.first; + View3D *v3d = area->spacedata.first; Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); rcti rect; /* Almost certainly overkill, but allow for many custom gizmos. */ @@ -751,7 +750,7 @@ wmGizmo *wm_gizmomap_highlight_find(wmGizmoMap *gzmap, const int event_modifier = WM_event_modifier_flag(event); - for (wmGizmoGroup *gzgroup = gzmap->groups.first; gzgroup; gzgroup = gzgroup->next) { + LISTBASE_FOREACH (wmGizmoGroup *, gzgroup, &gzmap->groups) { /* If it were important we could initialize here, * but this only happens when events are handled before drawing, @@ -966,22 +965,22 @@ void wm_gizmomap_handler_context_op(bContext *C, wmEventHandler_Op *handler) bScreen *screen = CTX_wm_screen(C); if (screen) { - ScrArea *sa; + ScrArea *area; - for (sa = screen->areabase.first; sa; sa = sa->next) { - if (sa == handler->context.area) { + for (area = screen->areabase.first; area; area = area->next) { + if (area == handler->context.area) { break; } } - if (sa == NULL) { + if (area == NULL) { /* when changing screen layouts with running modal handlers (like render display), this * is not an error to print */ printf("internal error: modal gizmo-map handler has invalid area\n"); } else { ARegion *region; - CTX_wm_area_set(C, sa); - for (region = sa->regionbase.first; region; region = region->next) { + CTX_wm_area_set(C, area); + for (region = area->regionbase.first; region; region = region->next) { if (region == handler->context.region) { break; } @@ -1165,12 +1164,12 @@ void WM_gizmomap_message_subscribe(bContext *C, ARegion *region, struct wmMsgBus *mbus) { - for (wmGizmoGroup *gzgroup = gzmap->groups.first; gzgroup; gzgroup = gzgroup->next) { + LISTBASE_FOREACH (wmGizmoGroup *, gzgroup, &gzmap->groups) { if ((gzgroup->hide.any != 0) || (gzgroup->init_flag & WM_GIZMOGROUP_INIT_SETUP) == 0 || !WM_gizmo_group_type_poll(C, gzgroup->type)) { continue; } - for (wmGizmo *gz = gzgroup->gizmos.first; gz; gz = gz->next) { + LISTBASE_FOREACH (wmGizmo *, gz, &gzgroup->gizmos) { if (gz->flag & WM_GIZMO_HIDDEN) { continue; } @@ -1220,8 +1219,7 @@ struct ARegion *WM_gizmomap_tooltip_init(struct bContext *C, wmGizmoMapType *WM_gizmomaptype_find(const struct wmGizmoMapType_Params *gzmap_params) { - for (wmGizmoMapType *gzmap_type = gizmomaptypes.first; gzmap_type; - gzmap_type = gzmap_type->next) { + LISTBASE_FOREACH (wmGizmoMapType *, gzmap_type, &gizmomaptypes) { if (gzmap_type->spaceid == gzmap_params->spaceid && gzmap_type->regionid == gzmap_params->regionid) { return gzmap_type; @@ -1269,10 +1267,8 @@ void wm_gizmos_keymap(wmKeyConfig *keyconf) /* we add this item-less keymap once and use it to group gizmo-group keymaps into it */ WM_keymap_ensure(keyconf, "Gizmos", 0, 0); - for (wmGizmoMapType *gzmap_type = gizmomaptypes.first; gzmap_type; - gzmap_type = gzmap_type->next) { - for (wmGizmoGroupTypeRef *gzgt_ref = gzmap_type->grouptype_refs.first; gzgt_ref; - gzgt_ref = gzgt_ref->next) { + LISTBASE_FOREACH (wmGizmoMapType *, gzmap_type, &gizmomaptypes) { + LISTBASE_FOREACH (wmGizmoGroupTypeRef *, gzgt_ref, &gzmap_type->grouptype_refs) { wm_gizmogrouptype_setup_keymap(gzgt_ref->type, keyconf); } } @@ -1328,8 +1324,7 @@ void WM_gizmoconfig_update(struct Main *bmain) } if (wm_gzmap_type_update_flag & WM_GIZMOMAPTYPE_GLOBAL_UPDATE_REMOVE) { - for (wmGizmoMapType *gzmap_type = gizmomaptypes.first; gzmap_type; - gzmap_type = gzmap_type->next) { + LISTBASE_FOREACH (wmGizmoMapType *, gzmap_type, &gizmomaptypes) { if (gzmap_type->type_update_flag & WM_GIZMOMAPTYPE_GLOBAL_UPDATE_REMOVE) { gzmap_type->type_update_flag &= ~WM_GIZMOMAPTYPE_UPDATE_REMOVE; for (wmGizmoGroupTypeRef *gzgt_ref = gzmap_type->grouptype_refs.first, *gzgt_ref_next; @@ -1348,13 +1343,11 @@ void WM_gizmoconfig_update(struct Main *bmain) } if (wm_gzmap_type_update_flag & WM_GIZMOMAPTYPE_GLOBAL_UPDATE_INIT) { - for (wmGizmoMapType *gzmap_type = gizmomaptypes.first; gzmap_type; - gzmap_type = gzmap_type->next) { + LISTBASE_FOREACH (wmGizmoMapType *, gzmap_type, &gizmomaptypes) { const uchar type_update_all = WM_GIZMOMAPTYPE_UPDATE_INIT | WM_GIZMOMAPTYPE_KEYMAP_INIT; if (gzmap_type->type_update_flag & type_update_all) { gzmap_type->type_update_flag &= ~type_update_all; - for (wmGizmoGroupTypeRef *gzgt_ref = gzmap_type->grouptype_refs.first; gzgt_ref; - gzgt_ref = gzgt_ref->next) { + LISTBASE_FOREACH (wmGizmoGroupTypeRef *, gzgt_ref, &gzmap_type->grouptype_refs) { if (gzgt_ref->type->type_update_flag & WM_GIZMOMAPTYPE_KEYMAP_INIT) { WM_gizmomaptype_group_init_runtime_keymap(bmain, gzgt_ref->type); gzgt_ref->type->type_update_flag &= ~WM_GIZMOMAPTYPE_KEYMAP_INIT; @@ -1373,10 +1366,11 @@ void WM_gizmoconfig_update(struct Main *bmain) if (wm_gzmap_type_update_flag & WM_GIZMOTYPE_GLOBAL_UPDATE_REMOVE) { for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) { - for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { - for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) { - ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase; - for (ARegion *region = regionbase->first; region; region = region->next) { + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) { + ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase : + &sl->regionbase; + LISTBASE_FOREACH (ARegion *, region, regionbase) { wmGizmoMap *gzmap = region->gizmo_map; if (gzmap != NULL && gzmap->tag_remove_group) { gzmap->tag_remove_group = false; @@ -1410,10 +1404,10 @@ void WM_gizmoconfig_update(struct Main *bmain) void WM_reinit_gizmomap_all(Main *bmain) { for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) { - for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { - for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) { - ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase; - for (ARegion *region = regionbase->first; region; region = region->next) { + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) { + ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase : &sl->regionbase; + LISTBASE_FOREACH (ARegion *, region, regionbase) { wmGizmoMap *gzmap = region->gizmo_map; if ((gzmap != NULL) && (gzmap->is_init == false)) { WM_gizmomap_reinit(gzmap); diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_type.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_type.c index 93f3a04978f..3956ff8fd36 100644 --- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_type.c +++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_type.c @@ -120,7 +120,7 @@ void WM_gizmotype_append_ptr(void (*gtfunc)(struct wmGizmoType *, void *), void */ static void gizmotype_free(wmGizmoType *gzt) { - if (gzt->ext.srna) { /* python gizmo, allocs own string */ + if (gzt->rna_ext.srna) { /* python gizmo, allocs own string */ MEM_freeN((void *)gzt->idname); } @@ -134,11 +134,11 @@ static void gizmotype_free(wmGizmoType *gzt) static void gizmotype_unlink(bContext *C, Main *bmain, wmGizmoType *gzt) { /* Free instances. */ - for (bScreen *sc = bmain->screens.first; sc; sc = sc->id.next) { - for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) { - for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) { - ListBase *lb = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase; - for (ARegion *region = lb->first; region; region = region->next) { + for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) { + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) { + ListBase *lb = (sl == area->spacedata.first) ? &area->regionbase : &sl->regionbase; + LISTBASE_FOREACH (ARegion *, region, lb) { wmGizmoMap *gzmap = region->gizmo_map; if (gzmap) { wmGizmoGroup *gzgroup; diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c index 0c74debf2d2..6edf0f9edfd 100644 --- a/source/blender/windowmanager/intern/wm.c +++ b/source/blender/windowmanager/intern/wm.c @@ -44,8 +44,10 @@ #include "BKE_idprop.h" #include "BKE_idtype.h" #include "BKE_lib_id.h" +#include "BKE_lib_query.h" #include "BKE_main.h" #include "BKE_report.h" +#include "BKE_screen.h" #include "BKE_workspace.h" #include "WM_api.h" @@ -55,6 +57,9 @@ #include "wm_draw.h" #include "wm_event_system.h" #include "wm_window.h" +#ifdef WITH_XR_OPENXR +# include "wm_xr.h" +#endif #include "BKE_undo_system.h" #include "ED_screen.h" @@ -70,6 +75,28 @@ static void window_manager_free_data(ID *id) wm_close_and_free(NULL, (wmWindowManager *)id); } +static void window_manager_foreach_id(ID *id, LibraryForeachIDData *data) +{ + wmWindowManager *wm = (wmWindowManager *)id; + + LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { + BKE_LIB_FOREACHID_PROCESS(data, win->scene, IDWALK_CB_USER_ONE); + + /* This pointer can be NULL during old files reading, better be safe than sorry. */ + if (win->workspace_hook != NULL) { + ID *workspace = (ID *)BKE_workspace_active_get(win->workspace_hook); + BKE_LIB_FOREACHID_PROCESS_ID(data, workspace, IDWALK_CB_NOP); + /* allow callback to set a different workspace */ + BKE_workspace_active_set(win->workspace_hook, (WorkSpace *)workspace); + } + if (BKE_lib_query_foreachid_process_flags_get(data) & IDWALK_INCLUDE_UI) { + LISTBASE_FOREACH (ScrArea *, area, &win->global_areas.areabase) { + BKE_screen_foreach_id_screen_area(data, area); + } + } + } +} + IDTypeInfo IDType_ID_WM = { .id_code = ID_WM, .id_filter = 0, @@ -84,6 +111,7 @@ IDTypeInfo IDType_ID_WM = { .copy_data = NULL, .free_data = window_manager_free_data, .make_local = NULL, + .foreach_id = window_manager_foreach_id, }; #define MAX_OP_REGISTERED 32 @@ -356,11 +384,11 @@ void wm_add_default(Main *bmain, bContext *C) WorkSpaceLayout *layout = BKE_workspace_layout_find_global(bmain, screen, &workspace); CTX_wm_manager_set(C, wm); - win = wm_window_new(bmain, wm, NULL); + win = wm_window_new(bmain, wm, NULL, false); win->scene = CTX_data_scene(C); STRNCPY(win->view_layer_name, CTX_data_view_layer(C)->name); BKE_workspace_active_set(win->workspace_hook, workspace); - BKE_workspace_hook_layout_for_workspace_set(win->workspace_hook, workspace, layout); + BKE_workspace_active_layout_set(win->workspace_hook, workspace, layout); screen->winid = win->winid; wm->winactive = win; diff --git a/source/blender/windowmanager/intern/wm_cursors.c b/source/blender/windowmanager/intern/wm_cursors.c index aa80064fae7..2af68956923 100644 --- a/source/blender/windowmanager/intern/wm_cursors.c +++ b/source/blender/windowmanager/intern/wm_cursors.c @@ -145,6 +145,16 @@ void WM_cursor_set(wmWindow *win, int curs) return; /* Can't set custom cursor before Window init */ } + if (curs == WM_CURSOR_DEFAULT && win->modalcursor) { + curs = win->modalcursor; + } + + if (win->cursor == curs) { + return; /* Cursor is already set */ + } + + win->cursor = curs; + if (curs == WM_CURSOR_NONE) { GHOST_SetCursorVisibility(win->ghostwin, 0); return; @@ -152,12 +162,6 @@ void WM_cursor_set(wmWindow *win, int curs) GHOST_SetCursorVisibility(win->ghostwin, 1); - if (curs == WM_CURSOR_DEFAULT && win->modalcursor) { - curs = win->modalcursor; - } - - win->cursor = curs; - if (curs < 0 || curs >= WM_CURSOR_NUM) { BLI_assert(!"Invalid cursor number"); return; @@ -183,13 +187,13 @@ void WM_cursor_set(wmWindow *win, int curs) } } -bool WM_cursor_set_from_tool(struct wmWindow *win, const ScrArea *sa, const ARegion *region) +bool WM_cursor_set_from_tool(struct wmWindow *win, const ScrArea *area, const ARegion *region) { if (region && (region->regiontype != RGN_TYPE_WINDOW)) { return false; } - bToolRef_Runtime *tref_rt = (sa && sa->runtime.tool) ? sa->runtime.tool->runtime : NULL; + bToolRef_Runtime *tref_rt = (area && area->runtime.tool) ? area->runtime.tool->runtime : NULL; if (tref_rt && tref_rt->cursor != WM_CURSOR_DEFAULT) { if (win->modalcursor == 0) { WM_cursor_set(win, tref_rt->cursor); diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c index 6e1c815dbca..730c5b3b0c2 100644 --- a/source/blender/windowmanager/intern/wm_draw.c +++ b/source/blender/windowmanager/intern/wm_draw.c @@ -73,19 +73,28 @@ # include "BKE_subsurf.h" #endif -/* ******************* paint cursor *************** */ +/* -------------------------------------------------------------------- */ +/** \name Draw Paint Cursor + * \{ */ -static void wm_paintcursor_draw(bContext *C, ScrArea *sa, ARegion *region) +static void wm_paintcursor_draw(bContext *C, ScrArea *area, ARegion *region) { wmWindowManager *wm = CTX_wm_manager(C); wmWindow *win = CTX_wm_window(C); bScreen *screen = WM_window_get_active_screen(win); wmPaintCursor *pc; + /* Don't draw paint cursors with locked interface. Painting is not possible + * then, and cursor drawing can use scene data that another thread may be + * modifying. */ + if (wm->is_interface_locked) { + return; + } + if (region->visible && region == screen->active_region) { for (pc = wm->paintcursors.first; pc; pc = pc->next) { - if ((pc->space_type != SPACE_TYPE_ANY) && (sa->spacetype != pc->space_type)) { + if ((pc->space_type != SPACE_TYPE_ANY) && (area->spacetype != pc->space_type)) { continue; } @@ -116,8 +125,14 @@ static void wm_paintcursor_draw(bContext *C, ScrArea *sa, ARegion *region) } } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Internal Utilities + * \{ */ + static bool wm_draw_region_stereo_set(Main *bmain, - ScrArea *sa, + ScrArea *area, ARegion *region, eStereoViews sview) { @@ -127,10 +142,10 @@ static bool wm_draw_region_stereo_set(Main *bmain, return false; } - switch (sa->spacetype) { + switch (area->spacetype) { case SPACE_IMAGE: { if (region->regiontype == RGN_TYPE_WINDOW) { - SpaceImage *sima = sa->spacedata.first; + SpaceImage *sima = area->spacedata.first; sima->iuser.multiview_eye = sview; return true; } @@ -138,7 +153,7 @@ static bool wm_draw_region_stereo_set(Main *bmain, } case SPACE_VIEW3D: { if (region->regiontype == RGN_TYPE_WINDOW) { - View3D *v3d = sa->spacedata.first; + View3D *v3d = area->spacedata.first; if (v3d->camera && v3d->camera->type == OB_CAMERA) { RegionView3D *rv3d = region->regiondata; RenderEngine *engine = rv3d->render_engine; @@ -159,7 +174,7 @@ static bool wm_draw_region_stereo_set(Main *bmain, } case SPACE_NODE: { if (region->regiontype == RGN_TYPE_WINDOW) { - SpaceNode *snode = sa->spacedata.first; + SpaceNode *snode = area->spacedata.first; if ((snode->flag & SNODE_BACKDRAW) && ED_node_is_compositor(snode)) { Image *ima = BKE_image_ensure_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node"); ima->eye = sview; @@ -169,7 +184,7 @@ static bool wm_draw_region_stereo_set(Main *bmain, break; } case SPACE_SEQ: { - SpaceSeq *sseq = sa->spacedata.first; + SpaceSeq *sseq = area->spacedata.first; sseq->multiview_eye = sview; if (region->regiontype == RGN_TYPE_PREVIEW) { @@ -184,17 +199,15 @@ static bool wm_draw_region_stereo_set(Main *bmain, return false; } -/* ********************* drawing ****************** */ - -static void wm_area_mark_invalid_backbuf(ScrArea *sa) +static void wm_area_mark_invalid_backbuf(ScrArea *area) { - if (sa->spacetype == SPACE_VIEW3D) { - ((View3D *)sa->spacedata.first)->flag |= V3D_INVALID_BACKBUF; + if (area->spacetype == SPACE_VIEW3D) { + ((View3D *)area->spacedata.first)->flag |= V3D_INVALID_BACKBUF; } } static void wm_region_test_gizmo_do_draw(bContext *C, - ScrArea *sa, + ScrArea *area, ARegion *region, bool tag_redraw) { @@ -203,13 +216,12 @@ static void wm_region_test_gizmo_do_draw(bContext *C, } wmGizmoMap *gzmap = region->gizmo_map; - for (wmGizmoGroup *gzgroup = WM_gizmomap_group_list(gzmap)->first; gzgroup; - gzgroup = gzgroup->next) { + LISTBASE_FOREACH (wmGizmoGroup *, gzgroup, WM_gizmomap_group_list(gzmap)) { if (tag_redraw && (gzgroup->type->flag & WM_GIZMOGROUPTYPE_VR_REDRAWS)) { - ScrArea *ctx_sa = CTX_wm_area(C); - ARegion *ctx_ar = CTX_wm_region(C); + ScrArea *ctx_area = CTX_wm_area(C); + ARegion *ctx_region = CTX_wm_region(C); - CTX_wm_area_set(C, sa); + CTX_wm_area_set(C, area); CTX_wm_region_set(C, region); if (WM_gizmo_group_type_poll(C, gzgroup->type)) { @@ -217,11 +229,11 @@ static void wm_region_test_gizmo_do_draw(bContext *C, } /* Reset. */ - CTX_wm_area_set(C, ctx_sa); - CTX_wm_region_set(C, ctx_ar); + CTX_wm_area_set(C, ctx_area); + CTX_wm_region_set(C, ctx_region); } - for (wmGizmo *gz = gzgroup->gizmos.first; gz; gz = gz->next) { + LISTBASE_FOREACH (wmGizmo *, gz, &gzgroup->gizmos) { if (gz->do_draw) { if (tag_redraw) { ED_region_tag_redraw_editor_overlays(region); @@ -234,17 +246,17 @@ static void wm_region_test_gizmo_do_draw(bContext *C, static void wm_region_test_render_do_draw(const Scene *scene, struct Depsgraph *depsgraph, - ScrArea *sa, + ScrArea *area, ARegion *region) { /* tag region for redraw from render engine preview running inside of it */ - if (sa->spacetype == SPACE_VIEW3D && region->regiontype == RGN_TYPE_WINDOW) { + if (area->spacetype == SPACE_VIEW3D && region->regiontype == RGN_TYPE_WINDOW) { RegionView3D *rv3d = region->regiondata; RenderEngine *engine = rv3d->render_engine; GPUViewport *viewport = WM_draw_region_get_viewport(region); if (engine && (engine->flag & RE_ENGINE_DO_DRAW)) { - View3D *v3d = sa->spacedata.first; + View3D *v3d = area->spacedata.first; rcti border_rect; /* do partial redraw when possible */ @@ -281,13 +293,18 @@ static bool wm_region_use_viewport_by_type(short space_type, short region_type) return (ELEM(space_type, SPACE_VIEW3D, SPACE_IMAGE) && region_type == RGN_TYPE_WINDOW); } -static bool wm_region_use_viewport(ScrArea *sa, ARegion *region) +bool WM_region_use_viewport(ScrArea *area, ARegion *region) { - return wm_region_use_viewport_by_type(sa->spacetype, region->regiontype); + return wm_region_use_viewport_by_type(area->spacetype, region->regiontype); } -/********************** draw all **************************/ -/* - reference method, draw all each time */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Window Drawing (Draw All) + * + * Reference method, draw all each time. + * \{ */ typedef struct WindowDrawCB { struct WindowDrawCB *next, *prev; @@ -312,7 +329,7 @@ void *WM_draw_cb_activate(wmWindow *win, void WM_draw_cb_exit(wmWindow *win, void *handle) { - for (WindowDrawCB *wdc = win->drawcalls.first; wdc; wdc = wdc->next) { + LISTBASE_FOREACH (WindowDrawCB *, wdc, &win->drawcalls) { if (wdc == (WindowDrawCB *)handle) { BLI_remlink(&win->drawcalls, wdc); MEM_freeN(wdc); @@ -323,17 +340,21 @@ void WM_draw_cb_exit(wmWindow *win, void *handle) static void wm_draw_callbacks(wmWindow *win) { - for (WindowDrawCB *wdc = win->drawcalls.first; wdc; wdc = wdc->next) { + LISTBASE_FOREACH (WindowDrawCB *, wdc, &win->drawcalls) { wdc->draw(win, wdc->customdata); } } -/************************* Region drawing. ******************************** +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Region Drawing * - * Each region draws into its own framebuffer, which is then blit on the + * Each region draws into its own frame-buffer, which is then blit on the * window draw buffer. This helps with fast redrawing if only some regions * change. It also means we can share a single context for multiple windows, - * so that for example VAOs can be shared between windows. */ + * so that for example VAOs can be shared between windows. + * \{ */ static void wm_draw_region_buffer_free(ARegion *region) { @@ -553,13 +574,13 @@ void wm_draw_region_blend(ARegion *region, int view, bool blend) alpha = 1.0f; } - glUniform1i(GPU_shader_get_uniform_ensure(shader, "image"), 0); - glUniform4f(GPU_shader_get_uniform_ensure(shader, "rect_icon"), + glUniform1i(GPU_shader_get_uniform(shader, "image"), 0); + glUniform4f(GPU_shader_get_uniform(shader, "rect_icon"), rect_tex.xmin, rect_tex.ymin, rect_tex.xmax, rect_tex.ymax); - glUniform4f(GPU_shader_get_uniform_ensure(shader, "rect_geom"), + glUniform4f(GPU_shader_get_uniform(shader, "rect_geom"), rect_geo.xmin, rect_geo.ymin, rect_geo.xmax, @@ -604,12 +625,11 @@ static void wm_draw_window_offscreen(bContext *C, wmWindow *win, bool stereo) bScreen *screen = WM_window_get_active_screen(win); /* Draw screen areas into own frame buffer. */ - ED_screen_areas_iter(win, screen, sa) - { - CTX_wm_area_set(C, sa); + ED_screen_areas_iter (win, screen, area) { + CTX_wm_area_set(C, area); /* Compute UI layouts for dynamically size regions. */ - for (ARegion *region = sa->regionbase.first; region; region = region->next) { + LISTBASE_FOREACH (ARegion *, region, &area->regionbase) { /* Dynamic region may have been flagged as too small because their size on init is 0. * ARegion.visible is false then, as expected. The layout should still be created then, so * the region size can be updated (it may turn out to be not too small then). */ @@ -625,22 +645,22 @@ static void wm_draw_window_offscreen(bContext *C, wmWindow *win, bool stereo) } } - ED_area_update_region_sizes(wm, win, sa); + ED_area_update_region_sizes(wm, win, area); - if (sa->flag & AREA_FLAG_ACTIVE_TOOL_UPDATE) { - if ((1 << sa->spacetype) & WM_TOOLSYSTEM_SPACE_MASK) { - WM_toolsystem_update_from_context(C, CTX_wm_workspace(C), CTX_data_view_layer(C), sa); + if (area->flag & AREA_FLAG_ACTIVE_TOOL_UPDATE) { + if ((1 << area->spacetype) & WM_TOOLSYSTEM_SPACE_MASK) { + WM_toolsystem_update_from_context(C, CTX_wm_workspace(C), CTX_data_view_layer(C), area); } - sa->flag &= ~AREA_FLAG_ACTIVE_TOOL_UPDATE; + area->flag &= ~AREA_FLAG_ACTIVE_TOOL_UPDATE; } /* Then do actual drawing of regions. */ - for (ARegion *region = sa->regionbase.first; region; region = region->next) { + LISTBASE_FOREACH (ARegion *, region, &area->regionbase) { if (region->visible && region->do_draw) { CTX_wm_region_set(C, region); - bool use_viewport = wm_region_use_viewport(sa, region); + bool use_viewport = WM_region_use_viewport(area, region); - if (stereo && wm_draw_region_stereo_set(bmain, sa, region, STEREO_LEFT_ID)) { + if (stereo && wm_draw_region_stereo_set(bmain, area, region, STEREO_LEFT_ID)) { wm_draw_region_buffer_create(region, true, use_viewport); for (int view = 0; view < 2; view++) { @@ -650,7 +670,7 @@ static void wm_draw_window_offscreen(bContext *C, wmWindow *win, bool stereo) } else { sview = STEREO_RIGHT_ID; - wm_draw_region_stereo_set(bmain, sa, region, sview); + wm_draw_region_stereo_set(bmain, area, region, sview); } wm_draw_region_bind(region, view); @@ -674,12 +694,12 @@ static void wm_draw_window_offscreen(bContext *C, wmWindow *win, bool stereo) } } - wm_area_mark_invalid_backbuf(sa); + wm_area_mark_invalid_backbuf(area); CTX_wm_area_set(C, NULL); } /* Draw menus into their own framebuffer. */ - for (ARegion *region = screen->regionbase.first; region; region = region->next) { + LISTBASE_FOREACH (ARegion *, region, &screen->regionbase) { if (region->visible) { CTX_wm_menu_set(C, region); @@ -720,9 +740,8 @@ static void wm_draw_window_onscreen(bContext *C, wmWindow *win, int view) #endif /* Blit non-overlapping area regions. */ - ED_screen_areas_iter(win, screen, sa) - { - for (ARegion *region = sa->regionbase.first; region; region = region->next) { + ED_screen_areas_iter (win, screen, area) { + LISTBASE_FOREACH (ARegion *, region, &area->regionbase) { if (region->visible && region->overlap == false) { /* Blit from offscreen buffer. */ wm_draw_region_blit(region, view); @@ -732,15 +751,14 @@ static void wm_draw_window_onscreen(bContext *C, wmWindow *win, int view) /* Draw paint cursors. */ if (wm->paintcursors.first) { - ED_screen_areas_iter(win, screen, sa) - { - for (ARegion *region = sa->regionbase.first; region; region = region->next) { + ED_screen_areas_iter (win, screen, area) { + LISTBASE_FOREACH (ARegion *, region, &area->regionbase) { if (region->visible && region == screen->active_region) { - CTX_wm_area_set(C, sa); + CTX_wm_area_set(C, area); CTX_wm_region_set(C, region); /* make region ready for draw, scissor, pixelspace */ - wm_paintcursor_draw(C, sa, region); + wm_paintcursor_draw(C, area, region); CTX_wm_region_set(C, NULL); CTX_wm_area_set(C, NULL); @@ -752,9 +770,8 @@ static void wm_draw_window_onscreen(bContext *C, wmWindow *win, int view) } /* Blend in overlapping area regions */ - ED_screen_areas_iter(win, screen, sa) - { - for (ARegion *region = sa->regionbase.first; region; region = region->next) { + ED_screen_areas_iter (win, screen, area) { + LISTBASE_FOREACH (ARegion *, region, &area->regionbase) { if (region->visible && region->overlap) { wm_draw_region_blend(region, 0, true); } @@ -766,7 +783,7 @@ static void wm_draw_window_onscreen(bContext *C, wmWindow *win, int view) wm_draw_callbacks(win); /* Blend in floating regions (menus). */ - for (ARegion *region = screen->regionbase.first; region; region = region->next) { + LISTBASE_FOREACH (ARegion *, region, &screen->regionbase) { if (region->visible) { wm_draw_region_blend(region, 0, true); } @@ -831,6 +848,7 @@ static void wm_draw_window(bContext *C, wmWindow *win) glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, GPU_texture_opengl_bindcode(texture)); + wmWindowViewport(win); if (win->stereo3d_format->display_mode == S3D_DISPLAY_SIDEBYSIDE) { wm_stereo3d_draw_sidebyside(win, view); } @@ -866,7 +884,11 @@ static void wm_draw_surface(bContext *C, wmSurface *surface) wm_surface_clear_drawable(); } -/****************** main update call **********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Main Update Call + * \{ */ /* quick test to prevent changing window drawable */ static bool wm_draw_update_test_window(Main *bmain, bContext *C, wmWindow *win) @@ -889,13 +911,12 @@ static bool wm_draw_update_test_window(Main *bmain, bContext *C, wmWindow *win) } } - ED_screen_areas_iter(win, screen, sa) - { - for (region = sa->regionbase.first; region; region = region->next) { - wm_region_test_gizmo_do_draw(C, sa, region, true); - wm_region_test_render_do_draw(scene, depsgraph, sa, region); + ED_screen_areas_iter (win, screen, area) { + for (region = area->regionbase.first; region; region = region->next) { + wm_region_test_gizmo_do_draw(C, area, region, true); + wm_region_test_render_do_draw(scene, depsgraph, area, region); #ifdef WITH_XR_OPENXR - wm_region_test_xr_do_draw(wm, sa, region); + wm_region_test_xr_do_draw(wm, area, region); #endif if (region->visible && region->do_draw) { @@ -937,10 +958,9 @@ static void wm_draw_update_clear_window(bContext *C, wmWindow *win) { bScreen *screen = WM_window_get_active_screen(win); - ED_screen_areas_iter(win, screen, sa) - { - for (ARegion *region = sa->regionbase.first; region; region = region->next) { - wm_region_test_gizmo_do_draw(C, sa, region, false); + ED_screen_areas_iter (win, screen, area) { + LISTBASE_FOREACH (ARegion *, region, &area->regionbase) { + wm_region_test_gizmo_do_draw(C, area, region, false); } } @@ -963,10 +983,6 @@ void wm_draw_update(bContext *C) wmWindowManager *wm = CTX_wm_manager(C); wmWindow *win; -#ifdef WITH_OPENSUBDIV - BKE_subsurf_free_unused_buffers(); -#endif - GPU_free_unused_buffers(bmain); for (win = wm->windows.first; win; win = win->next) { @@ -1012,16 +1028,18 @@ void wm_draw_region_clear(wmWindow *win, ARegion *UNUSED(region)) screen->do_draw = true; } -void WM_draw_region_free(ARegion *region) +void WM_draw_region_free(ARegion *region, bool hide) { wm_draw_region_buffer_free(region); - region->visible = 0; + if (hide) { + region->visible = 0; + } } -void wm_draw_region_test(bContext *C, ScrArea *sa, ARegion *region) +void wm_draw_region_test(bContext *C, ScrArea *area, ARegion *region) { /* Function for redraw timer benchmark. */ - bool use_viewport = wm_region_use_viewport(sa, region); + bool use_viewport = WM_region_use_viewport(area, region); wm_draw_region_buffer_create(region, false, use_viewport); wm_draw_region_bind(region, 0); ED_region_do_draw(C, region); @@ -1033,15 +1051,17 @@ void WM_redraw_windows(bContext *C) { wmWindow *win_prev = CTX_wm_window(C); ScrArea *area_prev = CTX_wm_area(C); - ARegion *ar_prev = CTX_wm_region(C); + ARegion *region_prev = CTX_wm_region(C); wm_draw_update(C); CTX_wm_window_set(C, win_prev); CTX_wm_area_set(C, area_prev); - CTX_wm_region_set(C, ar_prev); + CTX_wm_region_set(C, region_prev); } +/** \} */ + /* -------------------------------------------------------------------- */ /** \name Region Viewport Drawing * diff --git a/source/blender/windowmanager/intern/wm_event_query.c b/source/blender/windowmanager/intern/wm_event_query.c index 5b1c7680adc..381c06983a8 100644 --- a/source/blender/windowmanager/intern/wm_event_query.c +++ b/source/blender/windowmanager/intern/wm_event_query.c @@ -61,18 +61,28 @@ void WM_event_print(const wmEvent *event) const char *unknown = "UNKNOWN"; const char *type_id = unknown; const char *val_id = unknown; + const char *prev_type_id = unknown; + const char *prev_val_id = unknown; RNA_enum_identifier(rna_enum_event_type_items, event->type, &type_id); RNA_enum_identifier(rna_enum_event_value_items, event->val, &val_id); + RNA_enum_identifier(rna_enum_event_type_items, event->prevtype, &prev_type_id); + RNA_enum_identifier(rna_enum_event_value_items, event->prevval, &prev_val_id); + printf( "wmEvent type:%d / %s, val:%d / %s,\n" + " prev_type:%d / %s, prev_val:%d / %s,\n" " shift:%d, ctrl:%d, alt:%d, oskey:%d, keymodifier:%d, is_repeat:%d,\n" " mouse:(%d,%d), ascii:'%c', utf8:'%.*s', pointer:%p\n", event->type, type_id, event->val, val_id, + event->prevtype, + prev_type_id, + event->prevval, + prev_val_id, event->shift, event->ctrl, event->alt, diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 0957a5c52a0..9a90e73af39 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -1,4 +1,4 @@ -/* +/* * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 @@ -197,7 +197,7 @@ void wm_event_init_from_window(wmWindow *win, wmEvent *event) static bool wm_test_duplicate_notifier(const wmWindowManager *wm, uint type, void *reference) { - for (wmNotifier *note = wm->queue.first; note; note = note->next) { + LISTBASE_FOREACH (wmNotifier *, note, &wm->queue) { if ((note->category | note->data | note->subtype | note->action) == type && note->reference == reference) { return 1; @@ -290,16 +290,16 @@ void WM_main_remove_notifier_reference(const void *reference) void WM_main_remap_editor_id_reference(ID *old_id, ID *new_id) { Main *bmain = G_MAIN; - bScreen *sc; + bScreen *screen; - for (sc = bmain->screens.first; sc; sc = sc->id.next) { - ScrArea *sa; + for (screen = bmain->screens.first; screen; screen = screen->id.next) { + ScrArea *area; - for (sa = sc->areabase.first; sa; sa = sa->next) { + for (area = screen->areabase.first; area; area = area->next) { SpaceLink *sl; - for (sl = sa->spacedata.first; sl; sl = sl->next) { - ED_spacedata_id_remap(sa, sl, old_id, new_id); + for (sl = area->spacedata.first; sl; sl = sl->next) { + ED_spacedata_id_remap(area, sl, old_id, new_id); } } } @@ -334,14 +334,14 @@ void wm_event_do_depsgraph(bContext *C, bool is_after_open_file) } /* Combine datamasks so 1 win doesn't disable UV's in another [#26448]. */ CustomData_MeshMasks win_combine_v3d_datamask = {0}; - for (wmWindow *win = wm->windows.first; win; win = win->next) { + LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { const Scene *scene = WM_window_get_active_scene(win); const bScreen *screen = WM_window_get_active_screen(win); ED_view3d_screen_datamask(C, scene, screen, &win_combine_v3d_datamask); } /* Update all the dependency graphs of visible view layers. */ - for (wmWindow *win = wm->windows.first; win; win = win->next) { + LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { Scene *scene = WM_window_get_active_scene(win); ViewLayer *view_layer = WM_window_get_active_view_layer(win); Main *bmain = CTX_data_main(C); @@ -374,15 +374,15 @@ void wm_event_do_refresh_wm_and_depsgraph(bContext *C) { wmWindowManager *wm = CTX_wm_manager(C); /* cached: editor refresh callbacks now, they get context */ - for (wmWindow *win = wm->windows.first; win; win = win->next) { + LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { const bScreen *screen = WM_window_get_active_screen(win); - ScrArea *sa; + ScrArea *area; CTX_wm_window_set(C, win); - for (sa = screen->areabase.first; sa; sa = sa->next) { - if (sa->do_refresh) { - CTX_wm_area_set(C, sa); - ED_area_do_refresh(C, sa); + for (area = screen->areabase.first; area; area = area->next) { + if (area->do_refresh) { + CTX_wm_area_set(C, area); + ED_area_do_refresh(C, area); } } } @@ -529,11 +529,10 @@ void wm_event_do_notifiers(bContext *C) ED_region_do_listen(win, NULL, region, note, scene); } - ED_screen_areas_iter(win, screen, sa) - { - ED_area_do_listen(win, sa, note, scene); - for (region = sa->regionbase.first; region; region = region->next) { - ED_region_do_listen(win, sa, region, note, scene); + ED_screen_areas_iter (win, screen, area) { + ED_area_do_listen(win, area, note, scene); + for (region = area->regionbase.first; region; region = region->next) { + ED_region_do_listen(win, area, region, note, scene); } } } @@ -608,6 +607,12 @@ static int wm_handler_ui_call(bContext *C, } } + /* Don't block file-select events. Those are triggered by a separate file browser window. + * See T75292. */ + if (event->type == EVT_FILESELECT) { + return WM_UI_HANDLER_CONTINUE; + } + /* we set context to where ui handler came from */ if (handler->context.area) { CTX_wm_area_set(C, handler->context.area); @@ -646,11 +651,11 @@ static int wm_handler_ui_call(bContext *C, return WM_HANDLER_CONTINUE; } -static void wm_handler_ui_cancel(bContext *C) +void wm_event_handler_ui_cancel_ex(bContext *C, + wmWindow *win, + ARegion *region, + bool reactivate_button) { - wmWindow *win = CTX_wm_window(C); - ARegion *region = CTX_wm_region(C); - if (!region) { return; } @@ -662,11 +667,19 @@ static void wm_handler_ui_cancel(bContext *C) wmEvent event; wm_event_init_from_window(win, &event); event.type = EVT_BUT_CANCEL; + event.val = reactivate_button ? 0 : 1; handler->handle_fn(C, &event, handler->user_data); } } } +static void wm_event_handler_ui_cancel(bContext *C) +{ + wmWindow *win = CTX_wm_window(C); + ARegion *region = CTX_wm_region(C); + wm_event_handler_ui_cancel_ex(C, win, region, true); +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -827,11 +840,11 @@ bool WM_operator_check_ui_empty(wmOperatorType *ot) */ void WM_operator_region_active_win_set(bContext *C) { - ScrArea *sa = CTX_wm_area(C); - if (sa) { + ScrArea *area = CTX_wm_area(C); + if (area) { ARegion *region = CTX_wm_region(C); if (region && region->regiontype == RGN_TYPE_WINDOW) { - sa->region_active_win = BLI_findindex(&sa->regionbase, region); + area->region_active_win = BLI_findindex(&area->regionbase, region); } } } @@ -844,7 +857,7 @@ static void wm_operator_reports(bContext *C, wmOperator *op, int retval, bool ca /* FIXME, temp setting window, see other call to UI_popup_menu_reports for why */ wmWindow *win_prev = CTX_wm_window(C); ScrArea *area_prev = CTX_wm_area(C); - ARegion *ar_prev = CTX_wm_region(C); + ARegion *region_prev = CTX_wm_region(C); if (win_prev == NULL) { CTX_wm_window_set(C, CTX_wm_manager(C)->windows.first); @@ -854,7 +867,7 @@ static void wm_operator_reports(bContext *C, wmOperator *op, int retval, bool ca CTX_wm_window_set(C, win_prev); CTX_wm_area_set(C, area_prev); - CTX_wm_region_set(C, ar_prev); + CTX_wm_region_set(C, region_prev); } } @@ -875,6 +888,10 @@ static void wm_operator_reports(bContext *C, wmOperator *op, int retval, bool ca } } + /* Refresh Info Editor with reports immediately, even if op returned OPERATOR_CANCELLED. */ + if ((retval & OPERATOR_CANCELLED) && !BLI_listbase_is_empty(&op->reports->list)) { + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_INFO_REPORT, NULL); + } /* if the caller owns them, handle this */ wm_add_reports(op->reports); } @@ -949,9 +966,9 @@ static void wm_operator_finished(bContext *C, wmOperator *op, const bool repeat, if (hud_status != NOP) { if (hud_status == SET) { - ScrArea *sa = CTX_wm_area(C); - if (sa) { - ED_area_type_hud_ensure(C, sa); + ScrArea *area = CTX_wm_area(C); + if (area) { + ED_area_type_hud_ensure(C, area); } } else if (hud_status == CLEAR) { @@ -1336,7 +1353,7 @@ static int wm_operator_invoke(bContext *C, if (wrap) { const rcti *winrect = NULL; ARegion *region = CTX_wm_region(C); - ScrArea *sa = CTX_wm_area(C); + ScrArea *area = CTX_wm_area(C); /* Wrap only in X for header. */ if (region && @@ -1348,8 +1365,8 @@ static int wm_operator_invoke(bContext *C, BLI_rcti_isect_pt_v(®ion->winrct, &event->x)) { winrect = ®ion->winrct; } - else if (sa && BLI_rcti_isect_pt_v(&sa->totrct, &event->x)) { - winrect = &sa->totrct; + else if (area && BLI_rcti_isect_pt_v(&area->totrct, &event->x)) { + winrect = &area->totrct; } if (winrect) { @@ -1367,7 +1384,7 @@ static int wm_operator_invoke(bContext *C, * while dragging the view or worse, that stay there permanently * after the modal operator has swallowed all events and passed * none to the UI handler */ - wm_handler_ui_cancel(C); + wm_event_handler_ui_cancel(C); } else { WM_operator_free(op); @@ -1654,17 +1671,16 @@ static void wm_handler_op_context(bContext *C, wmEventHandler_Op *handler, const CTX_wm_area_set(C, NULL); } else { - ScrArea *sa = NULL; + ScrArea *area = NULL; - ED_screen_areas_iter(win, screen, sa_iter) - { - if (sa_iter == handler->context.area) { - sa = sa_iter; + ED_screen_areas_iter (win, screen, area_iter) { + if (area_iter == handler->context.area) { + area = area_iter; break; } } - if (sa == NULL) { + if (area == NULL) { /* when changing screen layouts with running modal handlers (like render display), this * is not an error to print */ if (handler->op == NULL) { @@ -1676,10 +1692,10 @@ static void wm_handler_op_context(bContext *C, wmEventHandler_Op *handler, const else { ARegion *region; wmOperator *op = handler->op ? (handler->op->opm ? handler->op->opm : handler->op) : NULL; - CTX_wm_area_set(C, sa); + CTX_wm_area_set(C, area); if (op && (op->flag & OP_IS_MODAL_CURSOR_REGION)) { - region = BKE_area_find_region_xy(sa, handler->context.region_type, event->x, event->y); + region = BKE_area_find_region_xy(area, handler->context.region_type, event->x, event->y); if (region) { handler->context.region = region; } @@ -1689,7 +1705,7 @@ static void wm_handler_op_context(bContext *C, wmEventHandler_Op *handler, const } if (region == NULL) { - for (region = sa->regionbase.first; region; region = region->next) { + for (region = area->regionbase.first; region; region = region->next) { if (region == handler->context.region) { break; } @@ -1868,7 +1884,7 @@ static wmKeyMapItem *wm_eventmatch_modal_keymap_items(const wmKeyMap *keymap, wmOperator *op, const wmEvent *event) { - for (wmKeyMapItem *kmi = keymap->items.first; kmi; kmi = kmi->next) { + LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) { /* Should already be handled by #wm_user_modal_keymap_set_items. */ BLI_assert(kmi->propvalue_str[0] == '\0'); if (wm_eventmatch(event, kmi)) { @@ -2217,19 +2233,19 @@ static int wm_handler_fileselect_do(bContext *C, } else { wmWindow *temp_win; - ScrArea *ctx_sa = CTX_wm_area(C); + ScrArea *ctx_area = CTX_wm_area(C); for (temp_win = wm->windows.first; temp_win; temp_win = temp_win->next) { bScreen *screen = WM_window_get_active_screen(temp_win); - ScrArea *file_sa = screen->areabase.first; + ScrArea *file_area = screen->areabase.first; - if (screen->temp && (file_sa->spacetype == SPACE_FILE)) { + if (screen->temp && (file_area->spacetype == SPACE_FILE)) { int win_size[2]; bool is_maximized; ED_fileselect_window_params_get(temp_win, win_size, &is_maximized); - ED_fileselect_params_to_userdef(file_sa->spacedata.first, win_size, is_maximized); + ED_fileselect_params_to_userdef(file_area->spacedata.first, win_size, is_maximized); - if (BLI_listbase_is_single(&file_sa->spacedata)) { + if (BLI_listbase_is_single(&file_area->spacedata)) { BLI_assert(ctx_win != temp_win); wm_window_close(C, wm, temp_win); @@ -2245,20 +2261,20 @@ static int wm_handler_fileselect_do(bContext *C, handler->context.win = NULL; } } - else if (file_sa->full) { - ED_screen_full_prevspace(C, file_sa); + else if (file_area->full) { + ED_screen_full_prevspace(C, file_area); } else { - ED_area_prevspace(C, file_sa); + ED_area_prevspace(C, file_area); } break; } } - if (!temp_win && ctx_sa->full) { - ED_fileselect_params_to_userdef(ctx_sa->spacedata.first, NULL, false); - ED_screen_full_prevspace(C, ctx_sa); + if (!temp_win && ctx_area->full) { + ED_fileselect_params_to_userdef(ctx_area->spacedata.first, NULL, false); + ED_screen_full_prevspace(C, ctx_area); } } @@ -2297,7 +2313,7 @@ static int wm_handler_fileselect_do(bContext *C, * it can be removed without breaking anything but then no linking errors - campbell */ wmWindow *win_prev = CTX_wm_window(C); ScrArea *area_prev = CTX_wm_area(C); - ARegion *ar_prev = CTX_wm_region(C); + ARegion *region_prev = CTX_wm_region(C); if (win_prev == NULL) { CTX_wm_window_set(C, CTX_wm_manager(C)->windows.first); @@ -2315,7 +2331,7 @@ static int wm_handler_fileselect_do(bContext *C, CTX_wm_window_set(C, win_prev); CTX_wm_area_set(C, area_prev); - CTX_wm_region_set(C, ar_prev); + CTX_wm_region_set(C, region_prev); } /* for WM_operator_pystring only, custom report handling is done above */ @@ -2379,21 +2395,23 @@ static int wm_action_not_handled(int action) return action == WM_HANDLER_CONTINUE || action == (WM_HANDLER_BREAK | WM_HANDLER_MODAL); } -static int wm_event_inside_rect(wmEvent *event, rcti *rect) +static bool wm_event_inside_rect(const wmEvent *event, const rcti *rect) { - if (wm_event_always_pass(event)) - return 1; - if (BLI_rcti_isect_pt_v(rect, &event->x)) - return 1; - return 0; + if (wm_event_always_pass(event)) { + return true; + } + if (BLI_rcti_isect_pt_v(rect, &event->x)) { + return true; + } + return false; } -static bool wm_event_inside_region(const wmEvent *event, const ARegion *ar) +static bool wm_event_inside_region(const wmEvent *event, const ARegion *region) { if (wm_event_always_pass(event)) { return true; } - return ED_region_contains_xy(ar, &event->x); + return ED_region_contains_xy(region, &event->x); } static ScrArea *area_event_inside(bContext *C, const int xy[2]) @@ -2402,10 +2420,10 @@ static ScrArea *area_event_inside(bContext *C, const int xy[2]) bScreen *screen = CTX_wm_screen(C); if (screen) { - ED_screen_areas_iter(win, screen, sa) - { - if (BLI_rcti_isect_pt_v(&sa->totrct, xy)) - return sa; + ED_screen_areas_iter (win, screen, area) { + if (BLI_rcti_isect_pt_v(&area->totrct, xy)) { + return area; + } } } return NULL; @@ -2415,12 +2433,15 @@ static ARegion *region_event_inside(bContext *C, const int xy[2]) { bScreen *screen = CTX_wm_screen(C); ScrArea *area = CTX_wm_area(C); - ARegion *ar; + ARegion *region; - if (screen && area) - for (ar = area->regionbase.first; ar; ar = ar->next) - if (BLI_rcti_isect_pt_v(&ar->winrct, xy)) - return ar; + if (screen && area) { + for (region = area->regionbase.first; region; region = region->next) { + if (BLI_rcti_isect_pt_v(®ion->winrct, xy)) { + return region; + } + } + } return NULL; } @@ -2451,7 +2472,7 @@ static int wm_handlers_do_keymap_with_keymap_handler( PRINT("pass\n"); - for (wmKeyMapItem *kmi = keymap->items.first; kmi; kmi = kmi->next) { + LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) { if (wm_eventmatch(event, kmi)) { struct wmEventHandler_KeymapPost keymap_post = handler->post; @@ -2565,10 +2586,11 @@ static int wm_handlers_do_gizmo_handler(bContext *C, wmGizmo *gz = wm_gizmomap_highlight_get(gzmap); /* Needed so UI blocks over gizmos don't let events fall through to the gizmos, - * noticeable for the node editor - where dragging on a node should move it, see: T73212. */ + * noticeable for the node editor - where dragging on a node should move it, see: T73212. + * note we still allow for starting the gizmo drag outside, then travel 'inside' the node */ if (region->type->clip_gizmo_events_by_ui) { if (UI_region_block_find_mouse_over(region, &event->x, true)) { - if (gz != NULL) { + if (gz != NULL && event->type != EVT_GIZMO_UPDATE) { WM_tooltip_clear(C, CTX_wm_window(C)); wm_gizmomap_highlight_set(gzmap, C, NULL, 0); } @@ -2623,7 +2645,7 @@ static int wm_handlers_do_gizmo_handler(bContext *C, if (wm_gizmomap_highlight_set(gzmap, C, gz, part)) { if (gz != NULL) { - if (U.flag & USER_TOOLTIPS) { + if ((U.flag & USER_TOOLTIPS) && (gz->flag & WM_GIZMO_NO_TOOLTIP) == 0) { WM_tooltip_timer_init(C, CTX_wm_window(C), area, region, WM_gizmomap_tooltip_init); } } @@ -2635,7 +2657,7 @@ static int wm_handlers_do_gizmo_handler(bContext *C, if (handle_keymap) { /* Handle highlight gizmo. */ - if (gz != NULL) { + if ((gz != NULL) && (gz->flag & WM_GIZMO_HIDDEN_KEYMAP) == 0) { bool keymap_poll = false; wmGizmoGroup *gzgroup = gz->parent_gzgroup; wmKeyMap *keymap = WM_keymap_active(wm, gz->keymap ? gz->keymap : gzgroup->type->keymap); @@ -2656,7 +2678,7 @@ static int wm_handlers_do_gizmo_handler(bContext *C, event_test_tweak.type = EVT_TWEAK_L + (event->type - LEFTMOUSE); event_test_tweak.val = KM_ANY; - for (wmKeyMapItem *kmi = keymap->items.first; kmi; kmi = kmi->next) { + LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) { if ((kmi->flag & KMI_INACTIVE) == 0) { if (wm_eventmatch(&event_test_click, kmi) || wm_eventmatch(&event_test_click_drag, kmi) || @@ -2681,7 +2703,7 @@ static int wm_handlers_do_gizmo_handler(bContext *C, if ((action & WM_HANDLER_BREAK) == 0) { if (WM_gizmomap_is_any_selected(gzmap)) { const ListBase *groups = WM_gizmomap_group_list(gzmap); - for (wmGizmoGroup *gzgroup = groups->first; gzgroup; gzgroup = gzgroup->next) { + LISTBASE_FOREACH (wmGizmoGroup *, gzgroup, groups) { if (wm_gizmogroup_is_any_selected(gzgroup)) { wmKeyMap *keymap = WM_keymap_active(wm, gzgroup->type->keymap); action |= wm_handlers_do_keymap_with_gizmo_handler( @@ -2708,6 +2730,12 @@ static int wm_handlers_do_gizmo_handler(bContext *C, return action; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Handle Single Event (All Handler Types) + * \{ */ + static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers) { const bool do_debug_handler = @@ -2993,7 +3021,7 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers) else { wmWindow *win = CTX_wm_window(C); if (win) { - if (ISKEYMODIFIER(win->eventstate->prevtype)) { + if (ISKEYMODIFIER(win->eventstate->type)) { win->eventstate->check_click = 0; } } @@ -3003,6 +3031,14 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers) return action; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Event Queue Utilities + * + * Utilities used by #wm_event_do_handlers. + * \{ */ + static void wm_paintcursor_tag(bContext *C, wmPaintCursor *pc, ARegion *region) { if (region) { @@ -3030,14 +3066,14 @@ static void wm_paintcursor_test(bContext *C, const wmEvent *event) /* if previous position was not in current region, we have to set a temp new context */ if (region == NULL || !BLI_rcti_isect_pt_v(®ion->winrct, &event->prevx)) { - ScrArea *sa = CTX_wm_area(C); + ScrArea *area = CTX_wm_area(C); CTX_wm_area_set(C, area_event_inside(C, &event->prevx)); CTX_wm_region_set(C, region_event_inside(C, &event->prevx)); wm_paintcursor_tag(C, wm->paintcursors.first, CTX_wm_region(C)); - CTX_wm_area_set(C, sa); + CTX_wm_area_set(C, area); CTX_wm_region_set(C, region); } } @@ -3084,6 +3120,33 @@ static bool wm_event_pie_filter(wmWindow *win, const wmEvent *event) } } +/** + * Account for the special case when events are being handled and a file is loaded. + * In this case event handling exits early, however when "Load UI" is disabled + * the even will still be in #wmWindow.queue. + * + * Without this it's possible to continuously handle the same event, see: T76484. + */ +static void wm_event_free_and_remove_from_queue_if_valid(wmEvent *event) +{ + LISTBASE_FOREACH (wmWindowManager *, wm, &G_MAIN->wm) { + LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { + if (BLI_remlink_safe(&win->queue, event)) { + wm_event_free(event); + return; + } + } + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Main Event Queue (Every Window) + * + * Handle events for all windows, run from the #WM_main event loop. + * \{ */ + /* called in main loop */ /* goes over entire hierarchy: events -> window -> screen -> area -> region */ void wm_event_do_handlers(bContext *C) @@ -3144,9 +3207,9 @@ void wm_event_do_handlers(bContext *C) } if (is_playing_sound == 0) { - const float time = BKE_sound_sync_scene(scene_eval); + const double time = BKE_sound_sync_scene(scene_eval); if (isfinite(time)) { - int ncfra = time * (float)FPS + 0.5f; + int ncfra = time * FPS + 0.5; if (ncfra != scene->r.cfra) { scene->r.cfra = ncfra; ED_update_for_newframe(CTX_data_main(C), depsgraph); @@ -3206,6 +3269,7 @@ void wm_event_do_handlers(bContext *C) /* fileread case */ if (CTX_wm_window(C) == NULL) { + wm_event_free_and_remove_from_queue_if_valid(event); return; } @@ -3241,8 +3305,7 @@ void wm_event_do_handlers(bContext *C) } #endif - ED_screen_areas_iter(win, screen, sa) - { + ED_screen_areas_iter (win, screen, area) { /* after restoring a screen from SCREENMAXIMIZED we have to wait * with the screen handling till the region coordinates are updated */ if (screen->skip_handling == true) { @@ -3252,15 +3315,15 @@ void wm_event_do_handlers(bContext *C) } /* update azones if needed - done here because it needs to be independent from redraws */ - if (sa->flag & AREA_FLAG_ACTIONZONES_UPDATE) { - ED_area_azones_update(sa, &event->x); + if (area->flag & AREA_FLAG_ACTIONZONES_UPDATE) { + ED_area_azones_update(area, &event->x); } - if (wm_event_inside_rect(event, &sa->totrct)) { - CTX_wm_area_set(C, sa); + if (wm_event_inside_rect(event, &area->totrct)) { + CTX_wm_area_set(C, area); if ((action & WM_HANDLER_BREAK) == 0) { - for (region = sa->regionbase.first; region; region = region->next) { + for (region = area->regionbase.first; region; region = region->next) { if (wm_event_inside_region(event, region)) { CTX_wm_region_set(C, region); @@ -3278,6 +3341,7 @@ void wm_event_do_handlers(bContext *C) /* fileread case (python), [#29489] */ if (CTX_wm_window(C) == NULL) { + wm_event_free_and_remove_from_queue_if_valid(event); return; } @@ -3292,7 +3356,7 @@ void wm_event_do_handlers(bContext *C) if ((action & WM_HANDLER_BREAK) == 0) { wm_region_mouse_co(C, event); /* only invalidates event->mval in this case */ - action |= wm_handlers_do(C, event, &sa->handlers); + action |= wm_handlers_do(C, event, &area->handlers); } CTX_wm_area_set(C, NULL); @@ -3312,6 +3376,7 @@ void wm_event_do_handlers(bContext *C) /* fileread case */ if (CTX_wm_window(C) == NULL) { + wm_event_free_and_remove_from_queue_if_valid(event); return; } } @@ -3388,19 +3453,13 @@ void WM_event_add_fileselect(bContext *C, wmOperator *op) wmWindowManager *wm = CTX_wm_manager(C); wmWindow *win = CTX_wm_window(C); const bool is_temp_screen = WM_window_is_temp_screen(win); - const bool opens_window = (U.filebrowser_display_type == USER_TEMP_SPACE_DISPLAY_WINDOW); - /* Don't add the file handler to the temporary window if one is opened, or else it owns the - * handlers for itself, causing dangling pointers once it's destructed through a handler. It has - * a parent which should hold the handlers itself. */ - ListBase *modalhandlers = (is_temp_screen && opens_window) ? &win->parent->modalhandlers : - &win->modalhandlers; /* Close any popups, like when opening a file browser from the splash. */ - UI_popup_handlers_remove_all(C, modalhandlers); + UI_popup_handlers_remove_all(C, &win->modalhandlers); if (!is_temp_screen) { /* only allow 1 file selector open per window */ - LISTBASE_FOREACH_MUTABLE (wmEventHandler *, handler_base, modalhandlers) { + LISTBASE_FOREACH_MUTABLE (wmEventHandler *, handler_base, &win->modalhandlers) { if (handler_base->type == WM_HANDLER_TYPE_OP) { wmEventHandler_Op *handler = (wmEventHandler_Op *)handler_base; if (handler->is_fileselect == false) { @@ -3410,13 +3469,12 @@ void WM_event_add_fileselect(bContext *C, wmOperator *op) bool cancel_handler = true; /* find the area with the file selector for this handler */ - ED_screen_areas_iter(win, screen, sa) - { - if (sa->spacetype == SPACE_FILE) { - SpaceFile *sfile = sa->spacedata.first; + ED_screen_areas_iter (win, screen, area) { + if (area->spacetype == SPACE_FILE) { + SpaceFile *sfile = area->spacedata.first; if (sfile->op == handler->op) { - CTX_wm_area_set(C, sa); + CTX_wm_area_set(C, area); wm_handler_fileselect_do(C, &win->modalhandlers, handler, EVT_FILESELECT_CANCEL); cancel_handler = false; break; @@ -3442,7 +3500,7 @@ void WM_event_add_fileselect(bContext *C, wmOperator *op) handler->context.area = CTX_wm_area(C); handler->context.region = CTX_wm_region(C); - BLI_addhead(modalhandlers, handler); + BLI_addhead(&win->modalhandlers, handler); /* check props once before invoking if check is available * ensures initial properties are valid */ @@ -3577,9 +3635,9 @@ wmEventHandler_Keymap *WM_event_add_keymap_handler(ListBase *handlers, wmKeyMap wmKeyMap *WM_event_get_keymap_from_toolsystem_fallback(wmWindowManager *wm, wmEventHandler_Keymap *handler) { - ScrArea *sa = handler->dynamic.user_data; + ScrArea *area = handler->dynamic.user_data; handler->keymap_tool = NULL; - bToolRef_Runtime *tref_rt = sa->runtime.tool ? sa->runtime.tool->runtime : NULL; + bToolRef_Runtime *tref_rt = area->runtime.tool ? area->runtime.tool->runtime : NULL; if (tref_rt && tref_rt->keymap_fallback[0]) { const char *keymap_id = NULL; @@ -3587,7 +3645,7 @@ wmKeyMap *WM_event_get_keymap_from_toolsystem_fallback(wmWindowManager *wm, if (tref_rt->gizmo_group[0] != '\0' && tref_rt->keymap_fallback[0] != '\n') { wmGizmoMap *gzmap = NULL; wmGizmoGroup *gzgroup = NULL; - for (ARegion *region = sa->regionbase.first; region; region = region->next) { + LISTBASE_FOREACH (ARegion *, region, &area->regionbase) { if (region->gizmo_map != NULL) { gzmap = region->gizmo_map; gzgroup = WM_gizmomap_group_find(gzmap, tref_rt->gizmo_group); @@ -3611,15 +3669,15 @@ wmKeyMap *WM_event_get_keymap_from_toolsystem_fallback(wmWindowManager *wm, if (keymap_id && keymap_id[0]) { wmKeyMap *km = WM_keymap_list_find_spaceid_or_empty( - &wm->userconf->keymaps, keymap_id, sa->spacetype, RGN_TYPE_WINDOW); + &wm->userconf->keymaps, keymap_id, area->spacetype, RGN_TYPE_WINDOW); /* We shouldn't use keymaps from unrelated spaces. */ if (km != NULL) { - handler->keymap_tool = sa->runtime.tool; + handler->keymap_tool = area->runtime.tool; return km; } else { printf( - "Keymap: '%s' not found for tool '%s'\n", tref_rt->keymap, sa->runtime.tool->idname); + "Keymap: '%s' not found for tool '%s'\n", tref_rt->keymap, area->runtime.tool->idname); } } } @@ -3628,22 +3686,22 @@ wmKeyMap *WM_event_get_keymap_from_toolsystem_fallback(wmWindowManager *wm, wmKeyMap *WM_event_get_keymap_from_toolsystem(wmWindowManager *wm, wmEventHandler_Keymap *handler) { - ScrArea *sa = handler->dynamic.user_data; + ScrArea *area = handler->dynamic.user_data; handler->keymap_tool = NULL; - bToolRef_Runtime *tref_rt = sa->runtime.tool ? sa->runtime.tool->runtime : NULL; + bToolRef_Runtime *tref_rt = area->runtime.tool ? area->runtime.tool->runtime : NULL; if (tref_rt && tref_rt->keymap[0]) { const char *keymap_id = tref_rt->keymap; { wmKeyMap *km = WM_keymap_list_find_spaceid_or_empty( - &wm->userconf->keymaps, keymap_id, sa->spacetype, RGN_TYPE_WINDOW); + &wm->userconf->keymaps, keymap_id, area->spacetype, RGN_TYPE_WINDOW); /* We shouldn't use keymaps from unrelated spaces. */ if (km != NULL) { - handler->keymap_tool = sa->runtime.tool; + handler->keymap_tool = area->runtime.tool; return km; } else { printf( - "Keymap: '%s' not found for tool '%s'\n", tref_rt->keymap, sa->runtime.tool->idname); + "Keymap: '%s' not found for tool '%s'\n", tref_rt->keymap, area->runtime.tool->idname); } } } @@ -4109,6 +4167,19 @@ static void wm_eventemulation(wmEvent *event, bool test_only) } } +static const wmTabletData wm_event_tablet_data_default = { + .active = EVT_TABLET_NONE, + .pressure = 1.0f, + .x_tilt = 0.0f, + .y_tilt = 0.0f, + .is_motion_absolute = false, +}; + +void WM_event_tablet_data_default_set(wmTabletData *tablet_data) +{ + *tablet_data = wm_event_tablet_data_default; +} + void wm_tablet_data_from_ghost(const GHOST_TabletData *tablet_data, wmTabletData *wmtab) { if ((tablet_data != NULL) && tablet_data->Active != GHOST_kTabletModeNone) { @@ -4121,11 +4192,7 @@ void wm_tablet_data_from_ghost(const GHOST_TabletData *tablet_data, wmTabletData // printf("%s: using tablet %.5f\n", __func__, wmtab->pressure); } else { - wmtab->active = EVT_TABLET_NONE; - wmtab->pressure = 1.0f; - wmtab->x_tilt = 0.0f; - wmtab->y_tilt = 0.0f; - wmtab->is_motion_absolute = false; + *wmtab = wm_event_tablet_data_default; // printf("%s: not using tablet\n", __func__); } } @@ -4162,7 +4229,7 @@ static void attach_ndof_data(wmEvent *event, const GHOST_TEventNDOFMotionData *g /* imperfect but probably usable... draw/enable drags to other windows */ static wmWindow *wm_event_cursor_other_windows(wmWindowManager *wm, wmWindow *win, wmEvent *event) { - int mx = event->x, my = event->y; + int mval[2] = {event->x, event->y}; if (wm->windows.first == wm->windows.last) { return NULL; @@ -4171,7 +4238,8 @@ static wmWindow *wm_event_cursor_other_windows(wmWindowManager *wm, wmWindow *wi /* in order to use window size and mouse position (pixels), we have to use a WM function */ /* check if outside, include top window bar... */ - if (mx < 0 || my < 0 || mx > WM_window_pixels_x(win) || my > WM_window_pixels_y(win) + 30) { + if (mval[0] < 0 || mval[1] < 0 || mval[0] > WM_window_pixels_x(win) || + mval[1] > WM_window_pixels_y(win) + 30) { wmWindow *owin; wmEventHandler *handler; @@ -4184,25 +4252,10 @@ static wmWindow *wm_event_cursor_other_windows(wmWindowManager *wm, wmWindow *wi } } - /* to desktop space */ - mx += (int)(U.pixelsize * win->posx); - my += (int)(U.pixelsize * win->posy); - - /* check other windows to see if it has mouse inside */ - for (owin = wm->windows.first; owin; owin = owin->next) { - - if (owin != win) { - int posx = (int)(U.pixelsize * owin->posx); - int posy = (int)(U.pixelsize * owin->posy); - - if (mx - posx >= 0 && owin->posy >= 0 && mx - posx <= WM_window_pixels_x(owin) && - my - posy <= WM_window_pixels_y(owin)) { - event->x = mx - (int)(U.pixelsize * owin->posx); - event->y = my - (int)(U.pixelsize * owin->posy); - - return owin; - } - } + if (WM_window_find_under_cursor(wm, win, win, mval, &owin, mval)) { + event->x = mval[0]; + event->y = mval[1]; + return owin; } } return NULL; @@ -4739,7 +4792,7 @@ wmKeyMap *WM_event_get_keymap_from_handler(wmWindowManager *wm, wmEventHandler_K wmKeyMapItem *WM_event_match_keymap_item(bContext *C, wmKeyMap *keymap, const wmEvent *event) { - for (wmKeyMapItem *kmi = keymap->items.first; kmi; kmi = kmi->next) { + LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) { if (wm_eventmatch(event, kmi)) { wmOperatorType *ot = WM_operatortype_find(kmi->idname, 0); if (WM_operator_poll_context(C, ot, WM_OP_INVOKE_DEFAULT)) { @@ -4845,30 +4898,30 @@ ScrArea *WM_window_status_area_find(wmWindow *win, bScreen *screen) if (screen->state == SCREENFULL) { return NULL; } - ScrArea *sa_statusbar = NULL; - for (ScrArea *sa = win->global_areas.areabase.first; sa; sa = sa->next) { - if (sa->spacetype == SPACE_STATUSBAR) { - sa_statusbar = sa; + ScrArea *area_statusbar = NULL; + LISTBASE_FOREACH (ScrArea *, area, &win->global_areas.areabase) { + if (area->spacetype == SPACE_STATUSBAR) { + area_statusbar = area; break; } } - return sa_statusbar; + return area_statusbar; } void WM_window_status_area_tag_redraw(wmWindow *win) { - bScreen *sc = WM_window_get_active_screen(win); - ScrArea *sa = WM_window_status_area_find(win, sc); - if (sa != NULL) { - ED_area_tag_redraw(sa); + bScreen *screen = WM_window_get_active_screen(win); + ScrArea *area = WM_window_status_area_find(win, screen); + if (area != NULL) { + ED_area_tag_redraw(area); } } void WM_window_cursor_keymap_status_refresh(bContext *C, wmWindow *win) { bScreen *screen = WM_window_get_active_screen(win); - ScrArea *sa_statusbar = WM_window_status_area_find(win, screen); - if (sa_statusbar == NULL) { + ScrArea *area_statusbar = WM_window_status_area_find(win, screen); + if (area_statusbar == NULL) { MEM_SAFE_FREE(win->cursor_keymap_status); return; } @@ -4895,20 +4948,19 @@ void WM_window_cursor_keymap_status_refresh(bContext *C, wmWindow *win) return; } - ScrArea *sa = NULL; - ED_screen_areas_iter(win, screen, sa_iter) - { - if (BLI_findindex(&sa_iter->regionbase, region) != -1) { - sa = sa_iter; + ScrArea *area = NULL; + ED_screen_areas_iter (win, screen, area_iter) { + if (BLI_findindex(&area_iter->regionbase, region) != -1) { + area = area_iter; break; } } - if (sa == NULL) { + if (area == NULL) { return; } /* Keep as-is. */ - if (ELEM(sa->spacetype, SPACE_STATUSBAR, SPACE_TOPBAR)) { + if (ELEM(area->spacetype, SPACE_STATUSBAR, SPACE_TOPBAR)) { return; } if (ELEM(region->regiontype, @@ -4921,23 +4973,23 @@ void WM_window_cursor_keymap_status_refresh(bContext *C, wmWindow *win) } /* Fallback to window. */ if (ELEM(region->regiontype, RGN_TYPE_TOOLS, RGN_TYPE_TOOL_PROPS)) { - region = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW); + region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW); } /* Detect changes to the state. */ { bToolRef *tref = NULL; if ((region->regiontype == RGN_TYPE_WINDOW) && - ((1 << sa->spacetype) & WM_TOOLSYSTEM_SPACE_MASK)) { + ((1 << area->spacetype) & WM_TOOLSYSTEM_SPACE_MASK)) { ViewLayer *view_layer = WM_window_get_active_view_layer(win); WorkSpace *workspace = WM_window_get_active_workspace(win); const bToolKey tkey = { - .space_type = sa->spacetype, - .mode = WM_toolsystem_mode_from_spacetype(view_layer, sa, sa->spacetype), + .space_type = area->spacetype, + .mode = WM_toolsystem_mode_from_spacetype(view_layer, area, area->spacetype), }; tref = WM_toolsystem_ref_find(workspace, &tkey); } - wm_event_cursor_store(&cd->state, win->eventstate, sa->spacetype, region->regiontype, tref); + wm_event_cursor_store(&cd->state, win->eventstate, area->spacetype, region->regiontype, tref); if (memcmp(&cd->state, &cd_prev.state, sizeof(cd->state)) == 0) { return; } @@ -4969,12 +5021,12 @@ void WM_window_cursor_keymap_status_refresh(bContext *C, wmWindow *win) } CTX_wm_window_set(C, win); - CTX_wm_area_set(C, sa); + CTX_wm_area_set(C, area); CTX_wm_region_set(C, region); ListBase *handlers[] = { ®ion->handlers, - &sa->handlers, + &area->handlers, &win->handlers, }; @@ -5004,7 +5056,7 @@ void WM_window_cursor_keymap_status_refresh(bContext *C, wmWindow *win) } if (memcmp(&cd_prev.text, &cd->text, sizeof(cd_prev.text)) != 0) { - ED_area_tag_redraw(sa_statusbar); + ED_area_tag_redraw(area_statusbar); } CTX_wm_window_set(C, NULL); diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index 3f4d082f9f7..ed1b29d61ce 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -141,11 +141,37 @@ static void wm_history_file_free(RecentFile *recent); static void wm_history_file_update(void); static void wm_history_file_write(void); -/* To be able to read files without windows closing, opening, moving +/* -------------------------------------------------------------------- */ +/** \name Misc Utility Functions + * \{ */ + +void WM_file_tag_modified(void) +{ + wmWindowManager *wm = G_MAIN->wm.first; + if (wm->file_saved) { + wm->file_saved = 0; + /* notifier that data changed, for save-over warning or header */ + WM_main_add_notifier(NC_WM | ND_DATACHANGED, NULL); + } +} + +bool wm_file_or_image_is_modified(const Main *bmain, const wmWindowManager *wm) +{ + return !wm->file_saved || ED_image_should_save_modified(bmain); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Window Matching for File Reading + * \{ */ + +/** + * To be able to read files without windows closing, opening, moving * we try to prepare for worst case: * - active window gets active screen from file * - restoring the screens from non-active windows - * Best case is all screens match, in that case they get assigned to proper window + * Best case is all screens match, in that case they get assigned to proper window. */ static void wm_window_match_init(bContext *C, ListBase *wmlist) { @@ -236,7 +262,7 @@ static void wm_window_match_keep_current_wm(const bContext *C, /* when loading without UI, no matching needed */ if (load_ui && (screen = CTX_wm_screen(C))) { - for (wmWindow *win = wm->windows.first; win; win = win->next) { + LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { WorkSpace *workspace; BKE_workspace_layout_find_global(bmain, screen, &workspace); @@ -294,8 +320,8 @@ static void wm_window_match_replace_by_file_wm(bContext *C, wm_window_clear_drawable(oldwm); /* only first wm in list has ghostwins */ - for (wmWindow *win = wm->windows.first; win; win = win->next) { - for (wmWindow *oldwin = oldwm->windows.first; oldwin; oldwin = oldwin->next) { + LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { + LISTBASE_FOREACH (wmWindow *, oldwin, &oldwm->windows) { if (oldwin->winid == win->winid) { has_match = true; @@ -355,6 +381,12 @@ static void wm_window_match_do(bContext *C, } } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Preferences Initialization & Versioning + * \{ */ + /* in case UserDef was read, we re-initialize all, and do versioning */ static void wm_init_userdef(Main *bmain) { @@ -375,6 +407,9 @@ static void wm_init_userdef(Main *bmain) /* update tempdir from user preferences */ BKE_tempdir_init(U.tempdir); + + /* Update tablet API preference. */ + WM_init_tablet_api(); } /* return codes */ @@ -386,6 +421,15 @@ static void wm_init_userdef(Main *bmain) # define BKE_READ_EXOTIC_OK_OTHER 1 /* other supported formats */ #endif +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Read Exotic File Formats + * + * Currently only supports '.blend' files, + * we could support registering other file formats and their loaders. + * \{ */ + /* intended to check for non-blender formats but for now it only reads blends */ static int wm_read_exotic(const char *name) { @@ -438,6 +482,12 @@ static int wm_read_exotic(const char *name) return retval; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Read Blend-File Shared Utilities + * \{ */ + void WM_file_autoexec_init(const char *filepath) { if (G.f & G_FLAG_SCRIPT_OVERRIDE_PREF) { @@ -483,6 +533,24 @@ void wm_file_read_report(bContext *C, Main *bmain) /** * Logic shared between #WM_file_read & #wm_homefile_read, + * call before loading a file. + * \note In the case of #WM_file_read the file may fail to load. + * Change here shouldn't cause user-visible changes in that case. + */ +static void wm_file_read_pre(bContext *C, bool use_data, bool UNUSED(use_userdef)) +{ + if (use_data) { + BKE_callback_exec_null(CTX_data_main(C), BKE_CB_EVT_LOAD_PRE); + BLI_timer_on_file_load(); + } + + /* Always do this as both startup and preferences may have loaded in many font's + * at a different zoom level to the file being loaded. */ + UI_view2d_zoom_cache_reset(); +} + +/** + * Logic shared between #WM_file_read & #wm_homefile_read, * updates to make after reading a file. */ static void wm_file_read_post(bContext *C, @@ -507,12 +575,16 @@ static void wm_file_read_post(bContext *C, if (is_startup_file) { /* possible python hasn't been initialized */ if (CTX_py_init_get(C)) { - if (reset_app_template) { + bool reset_all = use_userdef; + if (use_userdef || reset_app_template) { /* Only run when we have a template path found. */ if (BKE_appdir_app_template_any()) { BPY_execute_string( C, (const char *[]){"bl_app_template_utils", NULL}, "bl_app_template_utils.reset()"); + reset_all = true; } + } + if (reset_all) { /* sync addons, these may have changed from the defaults */ BPY_execute_string(C, (const char *[]){"addon_utils", NULL}, "addon_utils.reset_all()"); } @@ -598,24 +670,27 @@ static void wm_file_read_post(bContext *C, } } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Read Main Blend-File API + * \{ */ + bool WM_file_read(bContext *C, const char *filepath, ReportList *reports) { /* assume automated tasks with background, don't write recent file list */ const bool do_history = (G.background == false) && (CTX_wm_manager(C)->op_undo_depth == 0); bool success = false; + const bool use_data = true; + const bool use_userdef = false; + /* so we can get the error message */ errno = 0; WM_cursor_wait(1); - BKE_callback_exec_null(CTX_data_main(C), BKE_CB_EVT_LOAD_PRE); - BLI_timer_on_file_load(); - - UI_view2d_zoom_cache_reset(); - - /* Reset session-wise ID UUID counter. */ - BKE_lib_libblock_session_uuid_reset(); + wm_file_read_pre(C, use_data, use_userdef); /* first try to append data from exotic file formats... */ /* it throws error box when file doesn't exist and returns -1 */ @@ -675,8 +750,6 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports) } } - const bool use_data = true; - const bool use_userdef = false; wm_file_read_post(C, false, false, use_data, use_userdef, false); } #if 0 @@ -746,6 +819,12 @@ const char *WM_init_state_app_template_get(void) return wm_init_state_app_template.override ? wm_init_state_app_template.app_template : NULL; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Read Startup & Preferences Blend-File API + * \{ */ + /** * Called on startup, (context entirely filled with NULLs) * or called for 'New File' both startup.blend and userpref.blend are checked. @@ -802,6 +881,23 @@ void wm_homefile_read(bContext *C, * or use app-template startup.blend which the user hasn't saved. */ bool is_factory_startup = true; + const char *app_template = NULL; + bool update_defaults = false; + + if (filepath_startup_override != NULL) { + /* pass */ + } + else if (app_template_override) { + /* This may be clearing the current template by setting to an empty string. */ + app_template = app_template_override; + } + else if (!use_factory_settings && U.app_template[0]) { + app_template = U.app_template; + } + + const bool reset_app_template = ((!app_template && U.app_template[0]) || + (app_template && !STREQ(app_template, U.app_template))); + /* options exclude eachother */ BLI_assert((use_factory_settings && filepath_startup_override) == 0); @@ -809,18 +905,30 @@ void wm_homefile_read(bContext *C, SET_FLAG_FROM_TEST(G.f, (U.flag & USER_SCRIPT_AUTOEXEC_DISABLE) == 0, G_FLAG_SCRIPT_AUTOEXEC); } - if (use_data) { - BKE_callback_exec_null(CTX_data_main(C), BKE_CB_EVT_LOAD_PRE); - BLI_timer_on_file_load(); + if (use_userdef || reset_app_template) { +#ifdef WITH_PYTHON + /* This only runs once Blender has already started. */ + if (CTX_py_init_get(C)) { + /* This is restored by 'wm_file_read_post', disable before loading any preferences + * so an add-on can read their own preferences when un-registering, + * and use new preferences if/when re-registering, see T67577. + * + * Note that this fits into 'wm_file_read_pre' function but gets messy + * since we need to know if 'reset_app_template' is true. */ + BPY_execute_string(C, (const char *[]){"addon_utils", NULL}, "addon_utils.disable_all()"); + } +#endif /* WITH_PYTHON */ + } + wm_file_read_pre(C, use_data, use_userdef); + + if (use_data) { G.relbase_valid = 0; /* put aside screens to match with persistent windows later */ wm_window_match_init(C, &wmbase); } - UI_view2d_zoom_cache_reset(); - filepath_startup[0] = '\0'; filepath_userdef[0] = '\0'; app_template_system[0] = '\0'; @@ -861,28 +969,6 @@ void wm_homefile_read(bContext *C, } } - const char *app_template = NULL; - bool update_defaults = false; - bool reset_app_template = false; - - if (filepath_startup_override != NULL) { - /* pass */ - } - else if (app_template_override) { - /* This may be clearing the current template by setting to an empty string. */ - app_template = app_template_override; - } - else if (!use_factory_settings && U.app_template[0]) { - app_template = U.app_template; - } - - if ((!app_template && U.app_template[0]) || - (app_template && !STREQ(app_template, U.app_template))) { - /* Always load UI when switching to another template. */ - G.fileflags &= ~G_FILE_NO_UI; - reset_app_template = true; - } - if ((app_template != NULL) && (app_template[0] != '\0')) { if (!BKE_appdir_app_template_id_search( app_template, app_template_system, sizeof(app_template_system))) { @@ -923,9 +1009,6 @@ void wm_homefile_read(bContext *C, } } - /* Reset session-wise ID UUID counter. */ - BKE_lib_libblock_session_uuid_reset(); - if (!use_factory_settings || (filepath_startup[0] != '\0')) { if (BLI_access(filepath_startup, R_OK) == 0) { success = BKE_blendfile_read(C, @@ -953,20 +1036,20 @@ void wm_homefile_read(bContext *C, } } + if (use_userdef) { + if ((skip_flags & BLO_READ_SKIP_USERDEF) == 0) { + UserDef *userdef_default = BKE_blendfile_userdef_from_defaults(); + BKE_blender_userdef_data_set_and_free(userdef_default); + skip_flags |= BLO_READ_SKIP_USERDEF; + } + } + if (success == false && filepath_startup_override && reports) { /* We can not return from here because wm is already reset */ BKE_reportf(reports, RPT_ERROR, "Could not read '%s'", filepath_startup_override); } if (success == false) { - if (use_userdef) { - if ((skip_flags & BLO_READ_SKIP_USERDEF) == 0) { - UserDef *userdef_default = BKE_blendfile_userdef_from_defaults(); - BKE_blender_userdef_data_set_and_free(userdef_default); - skip_flags |= BLO_READ_SKIP_USERDEF; - } - } - success = BKE_blendfile_read_from_memory(C, datatoc_startup_blend, datatoc_startup_blend_size, @@ -1031,6 +1114,11 @@ void wm_homefile_read(bContext *C, * Screws up autosaves otherwise can remove this eventually, * only in a 2.53 and older, now its not written. */ G.fileflags &= ~G_FILE_RELATIVE_REMAP; + + if (reset_app_template) { + /* Always load UI when switching to another template. */ + G.fileflags &= ~G_FILE_NO_UI; + } } bmain = CTX_data_main(C); @@ -1038,7 +1126,6 @@ void wm_homefile_read(bContext *C, if (use_userdef) { /* check userdef before open window, keymaps etc */ wm_init_userdef(bmain); - reset_app_template = true; } if (use_data) { @@ -1047,8 +1134,8 @@ void wm_homefile_read(bContext *C, } if (use_userdef) { - /* Clear keymaps because the current default keymap may have been initialized - * from user preferences, which have been reset. */ + /* Clear keymaps because the current default keymap may have been initialized + * from user preferences, which have been reset. */ for (wmWindowManager *wm = bmain->wm.first; wm; wm = wm->id.next) { if (wm->defaultconf) { wm->defaultconf->flag &= ~KEYCONF_INIT_DEFAULT; @@ -1073,7 +1160,7 @@ void wm_homefile_read(bContext *C, } /* -------------------------------------------------------------------- */ -/** \name WM History File API +/** \name Blend-File History API * \{ */ void wm_history_file_read(void) @@ -1202,7 +1289,7 @@ static void wm_history_file_update(void) /** \} */ /* -------------------------------------------------------------------- */ -/** \name Save Main .blend File (internal) +/** \name Save Main Blend-File (internal) * \{ */ /* screen can be NULL */ @@ -1215,11 +1302,12 @@ static ImBuf *blend_file_thumb(const bContext *C, ImBuf *ibuf; BlendThumbnail *thumb; wmWindowManager *wm = CTX_wm_manager(C); + const float pixelsize_old = U.pixelsize; wmWindow *windrawable_old = wm->windrawable; char err_out[256] = "unknown"; /* screen if no camera found */ - ScrArea *sa = NULL; + ScrArea *area = NULL; ARegion *region = NULL; View3D *v3d = NULL; @@ -1235,10 +1323,10 @@ static ImBuf *blend_file_thumb(const bContext *C, } if ((scene->camera == NULL) && (screen != NULL)) { - sa = BKE_screen_find_big_area(screen, SPACE_VIEW3D, 0); - region = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW); + area = BKE_screen_find_big_area(screen, SPACE_VIEW3D, 0); + region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW); if (region) { - v3d = sa->spacedata.first; + v3d = area->spacedata.first; } } @@ -1249,6 +1337,10 @@ static ImBuf *blend_file_thumb(const bContext *C, /* gets scaled to BLEN_THUMB_SIZE */ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + /* Note that with scaling, this ends up being 0.5, + * as it's a thumbnail, we don't need object centers and friends to be 1:1 size. */ + U.pixelsize = 1.0f; + if (scene->camera) { ibuf = ED_view3d_draw_offscreen_imbuf_simple(depsgraph, scene, @@ -1279,6 +1371,8 @@ static ImBuf *blend_file_thumb(const bContext *C, err_out); } + U.pixelsize = pixelsize_old; + /* Reset to old drawable. */ if (windrawable_old) { wm_window_make_drawable(wm, windrawable_old); @@ -1433,6 +1527,9 @@ static bool wm_file_write(bContext *C, const char *filepath, int fileflags, Repo ibuf_thumb = IMB_thumb_create(filepath, THB_LARGE, THB_SOURCE_BLEND, ibuf_thumb); } + /* Without this there is no feedback the file was saved. */ + BKE_reportf(reports, RPT_INFO, "Saved \"%s\"", BLI_path_basename(filepath)); + /* Success. */ ok = true; } @@ -1507,7 +1604,7 @@ void wm_autosave_timer(Main *bmain, wmWindowManager *wm, wmTimer *UNUSED(wt)) WM_event_remove_timer(wm, NULL, wm->autosavetimer); /* if a modal operator is running, don't autosave, but try again in 10 seconds */ - for (wmWindow *win = wm->windows.first; win; win = win->next) { + LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { LISTBASE_FOREACH (wmEventHandler *, handler_base, &win->modalhandlers) { if (handler_base->type == WM_HANDLER_TYPE_OP) { wmEventHandler_Op *handler = (wmEventHandler_Op *)handler_base; @@ -1532,7 +1629,7 @@ void wm_autosave_timer(Main *bmain, wmWindowManager *wm, wmTimer *UNUSED(wt)) } } else { - /* save as regular blend file */ + /* Save as regular blend file. */ int fileflags = G.fileflags & ~(G_FILE_COMPRESS | G_FILE_HISTORY); ED_editors_flush_edits(bmain); @@ -1616,18 +1713,8 @@ void wm_open_init_use_scripts(wmOperator *op, bool use_prefs) /** \} */ -void WM_file_tag_modified(void) -{ - wmWindowManager *wm = G_MAIN->wm.first; - if (wm->file_saved) { - wm->file_saved = 0; - /* notifier that data changed, for save-over warning or header */ - WM_main_add_notifier(NC_WM | ND_DATACHANGED, NULL); - } -} - /* -------------------------------------------------------------------- */ -/** \name Preferences/startup save & load. +/** \name Startup File Save Operator * \{ */ /** @@ -1665,7 +1752,7 @@ static int wm_homefile_write_exec(bContext *C, wmOperator *op) ED_editors_flush_edits(bmain); - /* force save as regular blend file */ + /* Force save as regular blend file. */ fileflags = G.fileflags & ~(G_FILE_COMPRESS | G_FILE_HISTORY); if (BLO_write_file(bmain, filepath, fileflags, op->reports, NULL) == 0) { @@ -1692,48 +1779,11 @@ void WM_OT_save_homefile(wmOperatorType *ot) ot->exec = wm_homefile_write_exec; } -static int wm_userpref_autoexec_add_exec(bContext *UNUSED(C), wmOperator *UNUSED(op)) -{ - bPathCompare *path_cmp = MEM_callocN(sizeof(bPathCompare), "bPathCompare"); - BLI_addtail(&U.autoexec_paths, path_cmp); - U.runtime.is_dirty = true; - return OPERATOR_FINISHED; -} - -void WM_OT_userpref_autoexec_path_add(wmOperatorType *ot) -{ - ot->name = "Add Autoexec Path"; - ot->idname = "WM_OT_userpref_autoexec_path_add"; - ot->description = "Add path to exclude from autoexecution"; - - ot->exec = wm_userpref_autoexec_add_exec; - - ot->flag = OPTYPE_INTERNAL; -} - -static int wm_userpref_autoexec_remove_exec(bContext *UNUSED(C), wmOperator *op) -{ - const int index = RNA_int_get(op->ptr, "index"); - bPathCompare *path_cmp = BLI_findlink(&U.autoexec_paths, index); - if (path_cmp) { - BLI_freelinkN(&U.autoexec_paths, path_cmp); - U.runtime.is_dirty = true; - } - return OPERATOR_FINISHED; -} - -void WM_OT_userpref_autoexec_path_remove(wmOperatorType *ot) -{ - ot->name = "Remove Autoexec Path"; - ot->idname = "WM_OT_userpref_autoexec_path_remove"; - ot->description = "Remove path to exclude from autoexecution"; - - ot->exec = wm_userpref_autoexec_remove_exec; - - ot->flag = OPTYPE_INTERNAL; +/** \} */ - RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, 1000); -} +/* -------------------------------------------------------------------- */ +/** \name Write Preferences Operator + * \{ */ /* Only save the prefs block. operator entry */ static int wm_userpref_write_exec(bContext *C, wmOperator *op) @@ -1758,6 +1808,12 @@ void WM_OT_save_userpref(wmOperatorType *ot) ot->exec = wm_userpref_write_exec; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Read Preferences Operator + * \{ */ + /** * When reading preferences, there are some exceptions for values which are reset. */ @@ -1821,10 +1877,6 @@ static void wm_userpref_update_when_changed(bContext *C, rna_struct_update_when_changed(C, bmain, &ptr_a, &ptr_b); -#ifdef WITH_PYTHON - BPY_execute_string(C, (const char *[]){"addon_utils", NULL}, "addon_utils.reset_all()"); -#endif - WM_reinit_gizmomap_all(bmain); WM_keyconfig_reload(C); @@ -1890,6 +1942,12 @@ void WM_OT_read_factory_userpref(wmOperatorType *ot) ot->exec = wm_userpref_read_exec; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Read File History Operator + * \{ */ + static int wm_history_file_read_exec(bContext *UNUSED(C), wmOperator *UNUSED(op)) { ED_file_read_bookmarks(); @@ -1910,6 +1968,14 @@ void WM_OT_read_history(wmOperatorType *ot) ot->flag = OPTYPE_INTERNAL; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Read Startup & Preferences Operator + * + * Both #WM_OT_read_homefile & #WM_OT_read_factory_settings. + * \{ */ + static int wm_homefile_read_exec(bContext *C, wmOperator *op) { const bool use_factory_settings = (STREQ(op->type->idname, "WM_OT_read_factory_settings")); @@ -1953,9 +2019,11 @@ static int wm_homefile_read_exec(bContext *C, wmOperator *op) RNA_property_string_get(op->ptr, prop_app_template, app_template_buf); app_template = app_template_buf; - /* Always load preferences when switching templates with own preferences. */ - use_userdef = BKE_appdir_app_template_has_userpref(app_template) || - BKE_appdir_app_template_has_userpref(U.app_template); + if (!use_factory_settings) { + /* Always load preferences when switching templates with own preferences. */ + use_userdef = BKE_appdir_app_template_has_userpref(app_template) || + BKE_appdir_app_template_has_userpref(U.app_template); + } /* Turn override off, since we're explicitly loading a different app-template. */ WM_init_state_app_template_set(NULL); @@ -2298,7 +2366,7 @@ static bool wm_open_mainfile_check(bContext *UNUSED(C), wmOperator *op) RNA_string_get(op->ptr, "filepath", path); /* get the dir */ - lslash = (char *)BLI_last_slash(path); + lslash = (char *)BLI_path_slash_rfind(path); if (lslash) { *(lslash + 1) = '\0'; } @@ -2433,7 +2501,7 @@ void WM_OT_revert_mainfile(wmOperatorType *ot) /** \} */ /* -------------------------------------------------------------------- */ -/** \name Recover last session & auto-save. +/** \name Recover Last Session Operator * \{ */ void WM_recover_last_session(bContext *C, ReportList *reports) @@ -2477,6 +2545,12 @@ void WM_OT_recover_last_session(wmOperatorType *ot) ot->exec = wm_recover_last_session_exec; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Auto-Save Main .blend File Operator + * \{ */ + static int wm_recover_auto_save_exec(bContext *C, wmOperator *op) { char filepath[FILE_MAX]; @@ -2531,12 +2605,14 @@ void WM_OT_recover_auto_save(wmOperatorType *ot) /* -------------------------------------------------------------------- */ /** \name Save Main .blend File Operator + * + * Both #WM_OT_save_as_mainfile & #WM_OT_save_mainfile. * \{ */ static void wm_filepath_default(char *filepath) { if (G.save_over == false) { - BLI_ensure_filename(filepath, FILE_MAX, "untitled.blend"); + BLI_path_filename_ensure(filepath, FILE_MAX, "untitled.blend"); } } @@ -2715,8 +2791,6 @@ static int wm_save_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *U RNA_string_get(op->ptr, "filepath", path); ret = wm_save_as_mainfile_exec(C, op); - /* Without this there is no feedback the file was saved. */ - BKE_reportf(op->reports, RPT_INFO, "Saved \"%s\"", BLI_path_basename(path)); } else { WM_event_add_fileselect(C, op); @@ -2759,7 +2833,7 @@ void WM_OT_save_mainfile(wmOperatorType *ot) /** \} */ /* -------------------------------------------------------------------- */ -/** \name Auto-execution of scripts warning popup +/** \name Auto Script Execution Warning Dialog * \{ */ static void wm_block_autorun_warning_ignore(bContext *C, void *arg_block, void *UNUSED(arg)) @@ -2961,8 +3035,11 @@ void wm_test_autorun_warning(bContext *C) } } -/* Close File Dialog - *************************************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Close File Dialog + * \{ */ static char save_images_when_file_is_closed = true; @@ -3228,9 +3305,4 @@ void wm_close_file_dialog(bContext *C, wmGenericCallback *post_action) } } -bool wm_file_or_image_is_modified(const Main *bmain, const wmWindowManager *wm) -{ - return !wm->file_saved || ED_image_should_save_modified(bmain); -} - /** \} */ diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c index 5acc8a5fbc6..da4e4160724 100644 --- a/source/blender/windowmanager/intern/wm_files_link.c +++ b/source/blender/windowmanager/intern/wm_files_link.c @@ -104,7 +104,7 @@ static int wm_link_append_invoke(bContext *C, wmOperator *op, const wmEvent *UNU else if (G.relbase_valid) { char path[FILE_MAX]; BLI_strncpy(path, BKE_main_blendfile_path_from_global(), sizeof(path)); - BLI_parent_dir(path); + BLI_path_parent_dir(path); RNA_string_set(op->ptr, "filepath", path); } } diff --git a/source/blender/windowmanager/intern/wm_gesture.c b/source/blender/windowmanager/intern/wm_gesture.c index 71ae44297e7..6b2a74138c9 100644 --- a/source/blender/windowmanager/intern/wm_gesture.c +++ b/source/blender/windowmanager/intern/wm_gesture.c @@ -320,24 +320,24 @@ static void draw_filled_lasso_px_cb(int x, int x_end, int y, void *user_data) static void draw_filled_lasso(wmGesture *gt) { const short *lasso = (short *)gt->customdata; - const int tot = gt->points; - int(*moves)[2] = MEM_mallocN(sizeof(*moves) * (tot + 1), __func__); + const int mcoords_len = gt->points; + int(*mcoords)[2] = MEM_mallocN(sizeof(*mcoords) * (mcoords_len + 1), __func__); int i; rcti rect; float red[4] = {1.0f, 0.0f, 0.0f, 0.0f}; - for (i = 0; i < tot; i++, lasso += 2) { - moves[i][0] = lasso[0]; - moves[i][1] = lasso[1]; + for (i = 0; i < mcoords_len; i++, lasso += 2) { + mcoords[i][0] = lasso[0]; + mcoords[i][1] = lasso[1]; } - BLI_lasso_boundbox(&rect, (const int(*)[2])moves, tot); + BLI_lasso_boundbox(&rect, (const int(*)[2])mcoords, mcoords_len); BLI_rcti_translate(&rect, gt->winrct.xmin, gt->winrct.ymin); BLI_rcti_isect(>->winrct, &rect, &rect); BLI_rcti_translate(&rect, -gt->winrct.xmin, -gt->winrct.ymin); - /* highly unlikely this will fail, but could crash if (tot == 0) */ + /* Highly unlikely this will fail, but could crash if (mcoords_len == 0). */ if (BLI_rcti_is_empty(&rect) == false) { const int w = BLI_rcti_size_x(&rect); const int h = BLI_rcti_size_y(&rect); @@ -348,8 +348,8 @@ static void draw_filled_lasso(wmGesture *gt) rect.ymin, rect.xmax, rect.ymax, - (const int(*)[2])moves, - tot, + (const int(*)[2])mcoords, + mcoords_len, draw_filled_lasso_px_cb, &lasso_fill_data); @@ -365,7 +365,7 @@ static void draw_filled_lasso(wmGesture *gt) IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR); GPU_shader_bind(state.shader); GPU_shader_uniform_vector( - state.shader, GPU_shader_get_uniform_ensure(state.shader, "shuffle"), 4, 1, red); + state.shader, GPU_shader_get_uniform(state.shader, "shuffle"), 4, 1, red); immDrawPixelsTex(&state, rect.xmin, @@ -390,7 +390,7 @@ static void draw_filled_lasso(wmGesture *gt) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } - MEM_freeN(moves); + MEM_freeN(mcoords); } static void wm_gesture_draw_lasso(wmGesture *gt, bool filled) diff --git a/source/blender/windowmanager/intern/wm_gesture_ops.c b/source/blender/windowmanager/intern/wm_gesture_ops.c index 11beb7d2fd5..9fb368a02b4 100644 --- a/source/blender/windowmanager/intern/wm_gesture_ops.c +++ b/source/blender/windowmanager/intern/wm_gesture_ops.c @@ -718,10 +718,10 @@ void WM_gesture_lines_cancel(bContext *C, wmOperator *op) */ const int (*WM_gesture_lasso_path_to_array(bContext *UNUSED(C), wmOperator *op, - int *mcords_tot))[2] + int *r_mcoords_len))[2] { PropertyRNA *prop = RNA_struct_find_property(op->ptr, "path"); - int(*mcords)[2] = NULL; + int(*mcoords)[2] = NULL; BLI_assert(prop != NULL); if (prop) { @@ -729,26 +729,26 @@ const int (*WM_gesture_lasso_path_to_array(bContext *UNUSED(C), if (len) { int i = 0; - mcords = MEM_mallocN(sizeof(int) * 2 * len, __func__); + mcoords = MEM_mallocN(sizeof(int[2]) * len, __func__); RNA_PROP_BEGIN (op->ptr, itemptr, prop) { float loc[2]; RNA_float_get_array(&itemptr, "loc", loc); - mcords[i][0] = (int)loc[0]; - mcords[i][1] = (int)loc[1]; + mcoords[i][0] = (int)loc[0]; + mcoords[i][1] = (int)loc[1]; i++; } RNA_PROP_END; } - *mcords_tot = len; + *r_mcoords_len = len; } else { - *mcords_tot = 0; + *r_mcoords_len = 0; } /* cast for 'const' */ - return (const int(*)[2])mcords; + return mcoords; } #if 0 diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index 8293504d068..c4fccddc869 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -44,6 +44,7 @@ #include "BLI_listbase.h" #include "BLI_path_util.h" #include "BLI_string.h" +#include "BLI_task.h" #include "BLI_threads.h" #include "BLI_timer.h" #include "BLI_utildefines.h" @@ -124,6 +125,8 @@ #include "GPU_material.h" #include "BKE_sound.h" +#include "BKE_subdiv.h" + #include "COM_compositor.h" #include "DEG_depsgraph.h" @@ -131,10 +134,6 @@ #include "DRW_engine.h" -#ifdef WITH_OPENSUBDIV -# include "BKE_subsurf.h" -#endif - CLG_LOGREF_DECLARE_GLOBAL(WM_LOG_OPERATORS, "wm.operator"); CLG_LOGREF_DECLARE_GLOBAL(WM_LOG_HANDLERS, "wm.handler"); CLG_LOGREF_DECLARE_GLOBAL(WM_LOG_EVENTS, "wm.event"); @@ -188,17 +187,16 @@ void WM_init_opengl(Main *bmain) GPU_init(); GPU_set_mipmap(bmain, true); GPU_set_linear_mipmap(true); - GPU_set_anisotropic(bmain, U.anisotropic_filter); + GPU_set_anisotropic(U.anisotropic_filter); GPU_pass_cache_init(); -#ifdef WITH_OPENSUBDIV - BKE_subsurf_osd_init(); -#endif + BKE_subdiv_init(); + opengl_is_init = true; } -static void sound_jack_sync_callback(Main *bmain, int mode, float time) +static void sound_jack_sync_callback(Main *bmain, int mode, double time) { /* Ugly: Blender doesn't like it when the animation is played back during rendering. */ if (G.is_rendering) { @@ -217,10 +215,10 @@ static void sound_jack_sync_callback(Main *bmain, int mode, float time) if (depsgraph == NULL) { continue; } - BKE_sound_lock_scene(scene); + BKE_sound_lock(); Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); BKE_sound_jack_scene_update(scene_eval, mode, time); - BKE_sound_unlock_scene(scene); + BKE_sound_unlock(); } } @@ -574,11 +572,9 @@ void WM_exit_ex(bContext *C, const bool do_python) COM_deinitialize(); #endif - if (opengl_is_init) { -#ifdef WITH_OPENSUBDIV - BKE_subsurf_osd_cleanup(); -#endif + BKE_subdiv_exit(); + if (opengl_is_init) { GPU_free_unused_buffers(G_MAIN); } @@ -647,6 +643,7 @@ void WM_exit_ex(bContext *C, const bool do_python) DNA_sdna_current_free(); BLI_threadapi_exit(); + BLI_task_scheduler_exit(); /* No need to call this early, rather do it late so that other * pieces of Blender using sound may exit cleanly, see also T50676. */ diff --git a/source/blender/windowmanager/intern/wm_jobs.c b/source/blender/windowmanager/intern/wm_jobs.c index 33ea6dc54cc..c10f03f3dab 100644 --- a/source/blender/windowmanager/intern/wm_jobs.c +++ b/source/blender/windowmanager/intern/wm_jobs.c @@ -35,6 +35,7 @@ #include "BKE_context.h" #include "BKE_global.h" +#include "BKE_sequencer.h" #include "WM_api.h" #include "WM_types.h" @@ -254,7 +255,7 @@ static void wm_jobs_update_progress_bars(wmWindowManager *wm) float total_progress = 0.f; float jobs_progress = 0; - for (wmJob *wm_job = wm->jobs.first; wm_job; wm_job = wm_job->next) { + LISTBASE_FOREACH (wmJob *, wm_job, &wm->jobs) { if (wm_job->threads.first && !wm_job->ready) { if (wm_job->flag & WM_JOB_PROGRESS) { /* accumulate global progress for running jobs */ @@ -558,6 +559,9 @@ void WM_jobs_kill_all(wmWindowManager *wm) while ((wm_job = wm->jobs.first)) { wm_jobs_kill_job(wm, wm_job); } + + /* This job will be automatically restarted */ + BKE_sequencer_prefetch_stop_all(); } /* wait until every job ended, except for one owner (used in undo to keep screen job alive) */ diff --git a/source/blender/windowmanager/intern/wm_keymap.c b/source/blender/windowmanager/intern/wm_keymap.c index ab4888d4d31..d7102a1e8af 100644 --- a/source/blender/windowmanager/intern/wm_keymap.c +++ b/source/blender/windowmanager/intern/wm_keymap.c @@ -278,7 +278,7 @@ wmKeyConfig *WM_keyconfig_new(wmWindowManager *wm, const char *idname, bool user if (keyconf == wm->defaultconf) { /* For default configuration, we need to keep keymap * modal items and poll functions intact. */ - for (wmKeyMap *km = keyconf->keymaps.first; km; km = km->next) { + LISTBASE_FOREACH (wmKeyMap *, km, &keyconf->keymaps) { WM_keymap_clear(km); } } @@ -328,7 +328,7 @@ bool WM_keyconfig_remove(wmWindowManager *wm, wmKeyConfig *keyconf) void WM_keyconfig_clear(wmKeyConfig *keyconf) { - for (wmKeyMap *km = keyconf->keymaps.first; km; km = km->next) { + LISTBASE_FOREACH (wmKeyMap *, km, &keyconf->keymaps) { WM_keymap_clear(km); } @@ -911,9 +911,9 @@ wmKeyMap *WM_keymap_find_all_spaceid_or_empty(wmWindowManager *wm, * and filter the keys before sending to #wmOperatorType.modal callback. * \{ */ -wmKeyMap *WM_modalkeymap_add(wmKeyConfig *keyconf, - const char *idname, - const EnumPropertyItem *items) +wmKeyMap *WM_modalkeymap_ensure(wmKeyConfig *keyconf, + const char *idname, + const EnumPropertyItem *items) { wmKeyMap *km = WM_keymap_ensure(keyconf, idname, 0, 0); km->flag |= KEYMAP_MODAL; @@ -937,7 +937,7 @@ wmKeyMap *WM_modalkeymap_add(wmKeyConfig *keyconf, return km; } -wmKeyMap *WM_modalkeymap_get(wmKeyConfig *keyconf, const char *idname) +wmKeyMap *WM_modalkeymap_find(wmKeyConfig *keyconf, const char *idname) { wmKeyMap *km; @@ -1329,7 +1329,7 @@ static wmKeyMapItem *wm_keymap_item_find_in_keymap(wmKeyMap *keymap, const bool is_strict, const struct wmKeyMapItemFind_Params *params) { - for (wmKeyMapItem *kmi = keymap->items.first; kmi; kmi = kmi->next) { + LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) { /* skip disabled keymap items [T38447] */ if (kmi->flag & KMI_INACTIVE) { continue; @@ -1449,7 +1449,7 @@ static wmKeyMapItem *wm_keymap_item_find_props(const bContext *C, wmKeyMap **r_keymap) { wmWindow *win = CTX_wm_window(C); - ScrArea *sa = CTX_wm_area(C); + ScrArea *area = CTX_wm_area(C); ARegion *region = CTX_wm_region(C); wmKeyMapItem *found = NULL; @@ -1463,16 +1463,16 @@ static wmKeyMapItem *wm_keymap_item_find_props(const bContext *C, } } - if (sa && found == NULL) { + if (area && found == NULL) { found = wm_keymap_item_find_handlers( - C, &sa->handlers, opname, opcontext, properties, is_strict, params, r_keymap); + C, &area->handlers, opname, opcontext, properties, is_strict, params, r_keymap); } if (found == NULL) { if (ELEM(opcontext, WM_OP_EXEC_REGION_WIN, WM_OP_INVOKE_REGION_WIN)) { - if (sa) { + if (area) { if (!(region && region->regiontype == RGN_TYPE_WINDOW)) { - region = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW); + region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW); } if (region) { @@ -1483,7 +1483,7 @@ static wmKeyMapItem *wm_keymap_item_find_props(const bContext *C, } else if (ELEM(opcontext, WM_OP_EXEC_REGION_CHANNELS, WM_OP_INVOKE_REGION_CHANNELS)) { if (!(region && region->regiontype == RGN_TYPE_CHANNELS)) { - region = BKE_area_find_region_type(sa, RGN_TYPE_CHANNELS); + region = BKE_area_find_region_type(area, RGN_TYPE_CHANNELS); } if (region) { @@ -1493,7 +1493,7 @@ static wmKeyMapItem *wm_keymap_item_find_props(const bContext *C, } else if (ELEM(opcontext, WM_OP_EXEC_REGION_PREVIEW, WM_OP_INVOKE_REGION_PREVIEW)) { if (!(region && region->regiontype == RGN_TYPE_PREVIEW)) { - region = BKE_area_find_region_type(sa, RGN_TYPE_PREVIEW); + region = BKE_area_find_region_type(area, RGN_TYPE_PREVIEW); } if (region) { @@ -1936,7 +1936,7 @@ void WM_keyconfig_update(wmWindowManager *wm) * During event handling this function is called to get the keymap from the final configuration. * \{ */ -wmKeyMap *WM_keymap_active(wmWindowManager *wm, wmKeyMap *keymap) +wmKeyMap *WM_keymap_active(const wmWindowManager *wm, wmKeyMap *keymap) { wmKeyMap *km; diff --git a/source/blender/windowmanager/intern/wm_keymap_utils.c b/source/blender/windowmanager/intern/wm_keymap_utils.c index 307ad444ffd..5ab36b15666 100644 --- a/source/blender/windowmanager/intern/wm_keymap_utils.c +++ b/source/blender/windowmanager/intern/wm_keymap_utils.c @@ -27,6 +27,7 @@ #include "DNA_userdef_types.h" #include "DNA_windowmanager_types.h" +#include "BLI_listbase.h" #include "BLI_utildefines.h" #include "BKE_context.h" @@ -485,7 +486,7 @@ static bool wm_keymap_item_uses_modifier(wmKeyMapItem *kmi, const int event_modi bool WM_keymap_uses_event_modifier(wmKeyMap *keymap, const int event_modifier) { - for (wmKeyMapItem *kmi = keymap->items.first; kmi; kmi = kmi->next) { + LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) { if ((kmi->flag & KMI_INACTIVE) == 0) { if (wm_keymap_item_uses_modifier(kmi, event_modifier)) { return true; diff --git a/source/blender/windowmanager/intern/wm_menu_type.c b/source/blender/windowmanager/intern/wm_menu_type.c index 28dd1984bf0..c4491423d82 100644 --- a/source/blender/windowmanager/intern/wm_menu_type.c +++ b/source/blender/windowmanager/intern/wm_menu_type.c @@ -87,8 +87,8 @@ void WM_menutype_free(void) GHASH_ITER (gh_iter, menutypes_hash) { MenuType *mt = BLI_ghashIterator_getValue(&gh_iter); - if (mt->ext.free) { - mt->ext.free(mt->ext.data); + if (mt->rna_ext.free) { + mt->rna_ext.free(mt->rna_ext.data); } } diff --git a/source/blender/windowmanager/intern/wm_operator_type.c b/source/blender/windowmanager/intern/wm_operator_type.c index 015f2b0448d..650d5bbe015 100644 --- a/source/blender/windowmanager/intern/wm_operator_type.c +++ b/source/blender/windowmanager/intern/wm_operator_type.c @@ -199,7 +199,7 @@ static void operatortype_ghash_free_cb(wmOperatorType *ot) wm_operatortype_free_macro(ot); } - if (ot->ext.srna) { + if (ot->rna_ext.srna) { /* python operator, allocs own string */ MEM_freeN((void *)ot->idname); } @@ -507,9 +507,9 @@ wmOperatorType *WM_operatortype_append_macro(const char *idname, RNA_def_struct_ui_text(ot->srna, ot->name, ot->description); RNA_def_struct_identifier(&BLENDER_RNA, ot->srna, ot->idname); - /* Use i18n context from ext.srna if possible (py operators). */ - i18n_context = ot->ext.srna ? RNA_struct_translation_context(ot->ext.srna) : - BLT_I18NCONTEXT_OPERATOR_DEFAULT; + /* Use i18n context from rna_ext.srna if possible (py operators). */ + i18n_context = ot->rna_ext.srna ? RNA_struct_translation_context(ot->rna_ext.srna) : + BLT_I18NCONTEXT_OPERATOR_DEFAULT; RNA_def_struct_translation_context(ot->srna, i18n_context); ot->translation_context = i18n_context; diff --git a/source/blender/windowmanager/intern/wm_operator_utils.c b/source/blender/windowmanager/intern/wm_operator_utils.c index 4a786329e1a..81b597f7484 100644 --- a/source/blender/windowmanager/intern/wm_operator_utils.c +++ b/source/blender/windowmanager/intern/wm_operator_utils.c @@ -62,7 +62,7 @@ typedef struct ValueInteraction { float range[2]; struct { - ScrArea *sa; + ScrArea *area; ARegion *region; } context_vars; } ValueInteraction; @@ -74,7 +74,7 @@ static void interactive_value_init(bContext *C, const float range[2]) { - inter->context_vars.sa = CTX_wm_area(C); + inter->context_vars.area = CTX_wm_area(C); inter->context_vars.region = CTX_wm_region(C); inter->init.mval[0] = event->mval[0]; @@ -97,7 +97,7 @@ static void interactive_value_init_from_property( static void interactive_value_exit(ValueInteraction *inter) { - ED_area_status_text(inter->context_vars.sa, NULL); + ED_area_status_text(inter->context_vars.area, NULL); } static bool interactive_value_update(ValueInteraction *inter, @@ -128,7 +128,7 @@ static bool interactive_value_update(ValueInteraction *inter, /* set the property for the operator and call its modal function */ char str[64]; SNPRINTF(str, "%.4f", value_final); - ED_area_status_text(inter->context_vars.sa, str); + ED_area_status_text(inter->context_vars.area, str); } inter->prev.prop_value = value_final; diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index 853da714f76..f99f47bc3ad 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -103,9 +103,13 @@ #include "wm.h" #include "wm_draw.h" +#include "wm_event_system.h" #include "wm_event_types.h" #include "wm_files.h" #include "wm_window.h" +#ifdef WITH_XR_OPENXR +# include "wm_xr.h" +#endif #define UNDOCUMENTED_OPERATOR_TIP N_("(undocumented operator)") @@ -769,7 +773,7 @@ bool WM_operator_last_properties_init(wmOperator *op) bool changed = false; if (op->type->last_properties) { changed |= operator_last_properties_init_impl(op, op->type->last_properties); - for (wmOperator *opm = op->macro.first; opm; opm = opm->next) { + LISTBASE_FOREACH (wmOperator *, opm, &op->macro) { IDProperty *idp_src = IDP_GetPropertyFromGroup(op->type->last_properties, opm->idname); if (idp_src) { changed |= operator_last_properties_init_impl(opm, idp_src); @@ -792,7 +796,7 @@ bool WM_operator_last_properties_store(wmOperator *op) } if (op->macro.first != NULL) { - for (wmOperator *opm = op->macro.first; opm; opm = opm->next) { + LISTBASE_FOREACH (wmOperator *, opm, &op->macro) { if (opm->properties) { if (op->type->last_properties == NULL) { op->type->last_properties = IDP_New( @@ -1345,17 +1349,8 @@ static uiBlock *wm_block_create_redo(bContext *C, ARegion *region, void *arg_op) } uiLayout *col = uiLayoutColumn(layout, false); - - if (op->type->flag & OPTYPE_MACRO) { - for (op = op->macro.first; op; op = op->next) { - uiTemplateOperatorPropertyButs( - C, col, op, UI_BUT_LABEL_ALIGN_NONE, UI_TEMPLATE_OP_PROPS_SHOW_TITLE); - } - } - else { - uiTemplateOperatorPropertyButs( - C, col, op, UI_BUT_LABEL_ALIGN_NONE, UI_TEMPLATE_OP_PROPS_SHOW_TITLE); - } + uiTemplateOperatorPropertyButs( + C, col, op, UI_BUT_LABEL_ALIGN_NONE, UI_TEMPLATE_OP_PROPS_SHOW_TITLE); UI_block_bounds_set_popup(block, 6 * U.dpi_fac, NULL); @@ -1767,13 +1762,13 @@ static int wm_search_menu_invoke(bContext *C, wmOperator *op, const wmEvent *eve /* Exception for launching via spacebar */ if (event->type == EVT_SPACEKEY) { bool ok = true; - ScrArea *sa = CTX_wm_area(C); - if (sa) { - if (sa->spacetype == SPACE_CONSOLE) { + ScrArea *area = CTX_wm_area(C); + if (area) { + if (area->spacetype == SPACE_CONSOLE) { /* So we can use the shortcut in the console. */ ok = false; } - else if (sa->spacetype == SPACE_TEXT) { + else if (area->spacetype == SPACE_TEXT) { /* So we can use the spacebar in the text editor. */ ok = false; } @@ -1790,13 +1785,12 @@ static int wm_search_menu_invoke(bContext *C, wmOperator *op, const wmEvent *eve } } - PropertyRNA *prop = op->type->prop; int search_type; - if (RNA_property_is_set(op->ptr, prop)) { - search_type = RNA_property_enum_get(op->ptr, prop); + if (STREQ(op->type->idname, "WM_OT_search_menu")) { + search_type = SEARCH_TYPE_MENU; } else { - search_type = U.experimental.use_menu_search ? SEARCH_TYPE_MENU : SEARCH_TYPE_OPERATOR; + search_type = SEARCH_TYPE_OPERATOR; } static struct SearchPopupInit_Data data; @@ -1805,7 +1799,7 @@ static int wm_search_menu_invoke(bContext *C, wmOperator *op, const wmEvent *eve .size = {UI_searchbox_size_x() * 2, UI_searchbox_size_y()}, }; - UI_popup_block_invoke(C, wm_block_search_menu, &data, NULL); + UI_popup_block_invoke_ex(C, wm_block_search_menu, &data, NULL, false); return OPERATOR_INTERFACE; } @@ -1814,20 +1808,22 @@ static void WM_OT_search_menu(wmOperatorType *ot) { ot->name = "Search Menu"; ot->idname = "WM_OT_search_menu"; - ot->description = "Pop-up a search menu over all available operators in current context"; + ot->description = "Pop-up a search over all menus in the current context"; ot->invoke = wm_search_menu_invoke; ot->exec = wm_search_menu_exec; ot->poll = WM_operator_winactive; +} - static const EnumPropertyItem search_type_items[] = { - {SEARCH_TYPE_OPERATOR, "OPERATOR", 0, "Operator", "Search all operators"}, - {SEARCH_TYPE_MENU, "MENU", 0, "Menu", "Search active menu items"}, - {0, NULL, 0, NULL, NULL}, - }; +static void WM_OT_search_operator(wmOperatorType *ot) +{ + ot->name = "Search Operator"; + ot->idname = "WM_OT_search_operator"; + ot->description = "Pop-up a search over all available operators in current context"; - /* properties */ - ot->prop = RNA_def_enum(ot->srna, "type", search_type_items, SEARCH_TYPE_OPERATOR, "Type", ""); + ot->invoke = wm_search_menu_invoke; + ot->exec = wm_search_menu_exec; + ot->poll = WM_operator_winactive; } static int wm_call_menu_exec(bContext *C, wmOperator *op) @@ -2063,13 +2059,14 @@ static void WM_OT_console_toggle(wmOperatorType *ot) * * \{ */ -wmPaintCursor *WM_paint_cursor_activate(wmWindowManager *wm, - short space_type, +wmPaintCursor *WM_paint_cursor_activate(short space_type, short region_type, bool (*poll)(bContext *C), wmPaintCursorDraw draw, void *customdata) { + wmWindowManager *wm = G_MAIN->wm.first; + wmPaintCursor *pc = MEM_callocN(sizeof(wmPaintCursor), "paint cursor"); BLI_addtail(&wm->paintcursors, pc); @@ -2084,11 +2081,10 @@ wmPaintCursor *WM_paint_cursor_activate(wmWindowManager *wm, return pc; } -bool WM_paint_cursor_end(wmWindowManager *wm, wmPaintCursor *handle) +bool WM_paint_cursor_end(wmPaintCursor *handle) { - wmPaintCursor *pc; - - for (pc = wm->paintcursors.first; pc; pc = pc->next) { + wmWindowManager *wm = G_MAIN->wm.first; + for (wmPaintCursor *pc = wm->paintcursors.first; pc; pc = pc->next) { if (pc == (wmPaintCursor *)handle) { BLI_remlink(&wm->paintcursors, pc); MEM_freeN(pc); @@ -2135,7 +2131,7 @@ static void radial_control_update_header(wmOperator *op, bContext *C) { RadialControl *rc = op->customdata; char msg[UI_MAX_DRAW_STR]; - ScrArea *sa = CTX_wm_area(C); + ScrArea *area = CTX_wm_area(C); Scene *scene = CTX_data_scene(C); if (hasNumInput(&rc->num_input)) { @@ -2172,7 +2168,7 @@ static void radial_control_update_header(wmOperator *op, bContext *C) } } - ED_area_status_text(sa, msg); + ED_area_status_text(area, msg); } static void radial_control_set_initial_mouse(RadialControl *rc, const wmEvent *event) @@ -2763,7 +2759,7 @@ static int radial_control_invoke(bContext *C, wmOperator *op, const wmEvent *eve /* add radial control paint cursor */ rc->cursor = WM_paint_cursor_activate( - wm, SPACE_TYPE_ANY, RGN_TYPE_ANY, op->type->poll, radial_control_paint_cursor, rc); + SPACE_TYPE_ANY, RGN_TYPE_ANY, op->type->poll, radial_control_paint_cursor, rc); WM_event_add_modal_handler(C, op); @@ -2788,16 +2784,16 @@ static void radial_control_cancel(bContext *C, wmOperator *op) { RadialControl *rc = op->customdata; wmWindowManager *wm = CTX_wm_manager(C); - ScrArea *sa = CTX_wm_area(C); + ScrArea *area = CTX_wm_area(C); if (rc->dial) { MEM_freeN(rc->dial); rc->dial = NULL; } - ED_area_status_text(sa, NULL); + ED_area_status_text(area, NULL); - WM_paint_cursor_end(wm, rc->cursor); + WM_paint_cursor_end(rc->cursor); /* restore original paint cursors */ wm->paintcursors = rc->orig_paintcursors; @@ -3139,11 +3135,11 @@ static void WM_OT_radial_control(wmOperatorType *ot) static void redraw_timer_window_swap(bContext *C) { wmWindow *win = CTX_wm_window(C); - ScrArea *sa; + ScrArea *area; CTX_wm_menu_set(C, NULL); - for (sa = CTX_wm_screen(C)->areabase.first; sa; sa = sa->next) { - ED_area_tag_redraw(sa); + for (area = CTX_wm_screen(C)->areabase.first; area; area = area->next) { + ED_area_tag_redraw(area); } wm_draw_update(C); @@ -3176,14 +3172,14 @@ static void redraw_timer_step(bContext *C, Scene *scene, struct Depsgraph *depsgraph, wmWindow *win, - ScrArea *sa, + ScrArea *area, ARegion *region, const int type, const int cfra) { if (type == eRTDrawRegion) { if (region) { - wm_draw_region_test(C, sa, region); + wm_draw_region_test(C, area, region); } } else if (type == eRTDrawRegionSwap) { @@ -3196,25 +3192,26 @@ static void redraw_timer_step(bContext *C, } else if (type == eRTDrawWindow) { bScreen *screen = WM_window_get_active_screen(win); - ScrArea *sa_iter; + ScrArea *area_iter; CTX_wm_menu_set(C, NULL); - for (sa_iter = screen->areabase.first; sa_iter; sa_iter = sa_iter->next) { - ARegion *ar_iter; - CTX_wm_area_set(C, sa_iter); + for (area_iter = screen->areabase.first; area_iter; area_iter = area_iter->next) { + ARegion *region_iter; + CTX_wm_area_set(C, area_iter); - for (ar_iter = sa_iter->regionbase.first; ar_iter; ar_iter = ar_iter->next) { - if (ar_iter->visible) { - CTX_wm_region_set(C, ar_iter); - wm_draw_region_test(C, sa_iter, ar_iter); + for (region_iter = area_iter->regionbase.first; region_iter; + region_iter = region_iter->next) { + if (region_iter->visible) { + CTX_wm_region_set(C, region_iter); + wm_draw_region_test(C, area_iter, region_iter); } } } CTX_wm_window_set(C, win); /* XXX context manipulation warning! */ - CTX_wm_area_set(C, sa); + CTX_wm_area_set(C, area); CTX_wm_region_set(C, region); } else if (type == eRTDrawWindowSwap) { @@ -3240,8 +3237,12 @@ static void redraw_timer_step(bContext *C, } } else { /* eRTUndo */ + /* Undo and redo, including depsgraph update since that can be a + * significant part of the cost. */ ED_undo_pop(C); + wm_event_do_refresh_wm_and_depsgraph(C); ED_undo_redo(C); + wm_event_do_refresh_wm_and_depsgraph(C); } } @@ -3250,7 +3251,7 @@ static int redraw_timer_exec(bContext *C, wmOperator *op) Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); wmWindow *win = CTX_wm_window(C); - ScrArea *sa = CTX_wm_area(C); + ScrArea *area = CTX_wm_area(C); ARegion *region = CTX_wm_region(C); wmWindowManager *wm = CTX_wm_manager(C); double time_start, time_delta; @@ -3272,7 +3273,7 @@ static int redraw_timer_exec(bContext *C, wmOperator *op) wm_window_make_drawable(wm, win); for (a = 0; a < iter; a++) { - redraw_timer_step(C, bmain, scene, depsgraph, win, sa, region, type, cfra); + redraw_timer_step(C, bmain, scene, depsgraph, win, area, region, type, cfra); iter_steps += 1; if (time_limit != 0.0) { @@ -3688,8 +3689,8 @@ static void wm_xr_session_update_screen(Main *bmain, const wmXrData *xr_data) const bool session_exists = WM_xr_session_exists(xr_data); for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) { - for (ScrArea *area = screen->areabase.first; area; area = area->next) { - for (SpaceLink *slink = area->spacedata.first; slink; slink = slink->next) { + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + LISTBASE_FOREACH (SpaceLink *, slink, &area->spacedata) { if (slink->spacetype == SPACE_VIEW3D) { View3D *v3d = (View3D *)slink; @@ -3711,6 +3712,8 @@ static void wm_xr_session_update_screen(Main *bmain, const wmXrData *xr_data) } } } + + WM_main_add_notifier(NC_WM | ND_XR_DATA_CHANGED, NULL); } static void wm_xr_session_update_screen_on_exit_cb(const wmXrData *xr_data) @@ -3775,8 +3778,6 @@ void wm_operatortypes_register(void) WM_operatortype_append(WM_OT_save_userpref); WM_operatortype_append(WM_OT_read_userpref); WM_operatortype_append(WM_OT_read_factory_userpref); - WM_operatortype_append(WM_OT_userpref_autoexec_path_add); - WM_operatortype_append(WM_OT_userpref_autoexec_path_remove); WM_operatortype_append(WM_OT_window_fullscreen_toggle); WM_operatortype_append(WM_OT_quit_blender); WM_operatortype_append(WM_OT_open_mainfile); @@ -3794,7 +3795,9 @@ void wm_operatortypes_register(void) WM_operatortype_append(WM_OT_debug_menu); WM_operatortype_append(WM_OT_operator_defaults); WM_operatortype_append(WM_OT_splash); + WM_operatortype_append(WM_OT_splash_about); WM_operatortype_append(WM_OT_search_menu); + WM_operatortype_append(WM_OT_search_operator); WM_operatortype_append(WM_OT_call_menu); WM_operatortype_append(WM_OT_call_menu_pie); WM_operatortype_append(WM_OT_call_panel); @@ -3833,14 +3836,14 @@ static void gesture_circle_modal_keymap(wmKeyConfig *keyconf) }; /* WARNING - name is incorrect, use for non-3d views */ - wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "View3D Gesture Circle"); + wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "View3D Gesture Circle"); /* this function is called for each spacetype, only needs to add map once */ if (keymap && keymap->modal_items) { return; } - keymap = WM_modalkeymap_add(keyconf, "View3D Gesture Circle", modal_items); + keymap = WM_modalkeymap_ensure(keyconf, "View3D Gesture Circle", modal_items); /* assign map to operators */ WM_modalkeymap_assign(keymap, "VIEW3D_OT_select_circle"); @@ -3863,14 +3866,14 @@ static void gesture_straightline_modal_keymap(wmKeyConfig *keyconf) {0, NULL, 0, NULL, NULL}, }; - wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "Gesture Straight Line"); + wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "Gesture Straight Line"); /* this function is called for each spacetype, only needs to add map once */ if (keymap && keymap->modal_items) { return; } - keymap = WM_modalkeymap_add(keyconf, "Gesture Straight Line", modal_items); + keymap = WM_modalkeymap_ensure(keyconf, "Gesture Straight Line", modal_items); /* assign map to operators */ WM_modalkeymap_assign(keymap, "IMAGE_OT_sample_line"); @@ -3889,14 +3892,14 @@ static void gesture_box_modal_keymap(wmKeyConfig *keyconf) {0, NULL, 0, NULL, NULL}, }; - wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "Gesture Box"); + wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "Gesture Box"); /* this function is called for each spacetype, only needs to add map once */ if (keymap && keymap->modal_items) { return; } - keymap = WM_modalkeymap_add(keyconf, "Gesture Box", modal_items); + keymap = WM_modalkeymap_ensure(keyconf, "Gesture Box", modal_items); /* assign map to operators */ WM_modalkeymap_assign(keymap, "ACTION_OT_select_box"); @@ -3940,14 +3943,14 @@ static void gesture_zoom_border_modal_keymap(wmKeyConfig *keyconf) {0, NULL, 0, NULL, NULL}, }; - wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "Gesture Zoom Border"); + wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "Gesture Zoom Border"); /* this function is called for each spacetype, only needs to add map once */ if (keymap && keymap->modal_items) { return; } - keymap = WM_modalkeymap_add(keyconf, "Gesture Zoom Border", modal_items); + keymap = WM_modalkeymap_ensure(keyconf, "Gesture Zoom Border", modal_items); /* assign map to operators */ WM_modalkeymap_assign(keymap, "VIEW2D_OT_zoom_border"); diff --git a/source/blender/windowmanager/intern/wm_playanim.c b/source/blender/windowmanager/intern/wm_playanim.c index 8a872010ecc..948e8d9fb74 100644 --- a/source/blender/windowmanager/intern/wm_playanim.c +++ b/source/blender/windowmanager/intern/wm_playanim.c @@ -317,7 +317,13 @@ static void playanim_toscreen( GPU_blend(true); glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - imm_draw_box_checker_2d(offs_x, offs_y, offs_x + span_x, offs_y + span_y); + imm_draw_box_checker_2d_ex(offs_x, + offs_y, + offs_x + span_x, + offs_y + span_y, + (const float[4]){0.15, 0.15, 0.15, 1.0}, + (const float[4]){0.20, 0.20, 0.20, 1.0}, + 8); } IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR); @@ -429,7 +435,8 @@ static void build_pict_list_ex( } fp_decoded; BLI_strncpy(filepath, first, sizeof(filepath)); - fp_framenr = BLI_stringdec(filepath, fp_decoded.head, fp_decoded.tail, &fp_decoded.digits); + fp_framenr = BLI_path_sequence_decode( + filepath, fp_decoded.head, fp_decoded.tail, &fp_decoded.digits); pupdate_time(); ptottime = 1.0; @@ -522,7 +529,8 @@ static void build_pict_list_ex( /* create a new filepath each time */ fp_framenr += fstep; - BLI_stringenc(filepath, fp_decoded.head, fp_decoded.tail, fp_decoded.digits, fp_framenr); + BLI_path_sequence_encode( + filepath, fp_decoded.head, fp_decoded.tail, fp_decoded.digits, fp_framenr); while ((hasevent = GHOST_ProcessEvents(g_WS.ghost_system, 0))) { GHOST_DispatchEvents(g_WS.ghost_system); diff --git a/source/blender/windowmanager/intern/wm_splash_screen.c b/source/blender/windowmanager/intern/wm_splash_screen.c index 9c7ed52b0f9..b75609fd28f 100644 --- a/source/blender/windowmanager/intern/wm_splash_screen.c +++ b/source/blender/windowmanager/intern/wm_splash_screen.c @@ -40,6 +40,7 @@ #include "DNA_windowmanager_types.h" #include "BLI_blenlib.h" +#include "BLI_math.h" #include "BLI_utildefines.h" #include "BKE_appdir.h" @@ -47,6 +48,8 @@ #include "BKE_context.h" #include "BKE_screen.h" +#include "BLT_translation.h" + #include "BLF_api.h" #include "IMB_imbuf.h" @@ -55,202 +58,137 @@ #include "ED_screen.h" #include "UI_interface.h" +#include "UI_interface_icons.h" +#include "UI_resources.h" #include "WM_api.h" #include "WM_types.h" #include "wm.h" -static void wm_block_splash_close(bContext *C, void *arg_block, void *UNUSED(arg)) +static void wm_block_close(bContext *C, void *arg_block, void *UNUSED(arg)) { wmWindow *win = CTX_wm_window(C); UI_popup_block_close(C, win, arg_block); } -static uiBlock *wm_block_create_splash(bContext *C, ARegion *region, void *arg_unused); - static void wm_block_splash_refreshmenu(bContext *C, void *UNUSED(arg_block), void *UNUSED(arg)) { - ARegion *ar_menu = CTX_wm_menu(C); - ED_region_tag_refresh_ui(ar_menu); + ARegion *region_menu = CTX_wm_menu(C); + ED_region_tag_refresh_ui(region_menu); } -static void wm_block_splash_add_label(uiBlock *block, const char *label, int x, int *y) +static void wm_block_splash_add_label(uiBlock *block, const char *label, int x, int y) { if (!(label && label[0])) { return; } - const uiStyle *style = UI_style_get(); - - BLF_size(style->widgetlabel.uifont_id, style->widgetlabel.points, U.pixelsize * U.dpi); - int label_width = BLF_width(style->widgetlabel.uifont_id, label, strlen(label)); - label_width = label_width + U.widget_unit; - UI_block_emboss_set(block, UI_EMBOSS_NONE); - uiBut *but = uiDefBut(block, - UI_BTYPE_LABEL, - 0, - label, - x - label_width, - *y, - label_width, - UI_UNIT_Y, - NULL, - 0, - 0, - 0, - 0, - NULL); + uiBut *but = uiDefBut( + block, UI_BTYPE_LABEL, 0, label, 0, y, x, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL); + UI_but_drawflag_disable(but, UI_BUT_TEXT_LEFT); + UI_but_drawflag_enable(but, UI_BUT_TEXT_RIGHT); /* 1 = UI_SELECT, internal flag to draw in white. */ UI_but_flag_enable(but, 1); UI_block_emboss_set(block, UI_EMBOSS); - *y -= 12 * U.dpi_fac; } -static void wm_block_splash_add_labels(uiBlock *block, int x, int y) +#ifndef WITH_HEADLESS +static void wm_block_splash_image_roundcorners_add(ImBuf *ibuf) { - /* Version number. */ - const char *version_cycle = NULL; - bool show_build_info = true; - - if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "alpha")) { - version_cycle = " Alpha"; - } - else if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "beta")) { - version_cycle = " Beta"; - } - else if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "rc")) { - version_cycle = " Release Candidate"; - show_build_info = false; - } - else if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "release")) { - version_cycle = STRINGIFY(BLENDER_VERSION_CHAR); - show_build_info = false; - } - - const char *version_cycle_number = ""; - if (strlen(STRINGIFY(BLENDER_VERSION_CYCLE_NUMBER))) { - version_cycle_number = " " STRINGIFY(BLENDER_VERSION_CYCLE_NUMBER); - } - - char version_buf[256] = "\0"; - BLI_snprintf(version_buf, - sizeof(version_buf), - "v %d.%d%s%s", - BLENDER_VERSION / 100, - BLENDER_VERSION % 100, - version_cycle, - version_cycle_number); - - wm_block_splash_add_label(block, version_buf, x, &y); - -#ifdef WITH_BUILDINFO - if (show_build_info) { - extern unsigned long build_commit_timestamp; - extern char build_hash[], build_commit_date[], build_commit_time[], build_branch[]; - - /* Date, hidden for builds made from tag. */ - if (build_commit_timestamp != 0) { - char date_buf[256] = "\0"; - BLI_snprintf( - date_buf, sizeof(date_buf), "Date: %s %s", build_commit_date, build_commit_time); - wm_block_splash_add_label(block, date_buf, x, &y); - } - - /* Hash. */ - char hash_buf[256] = "\0"; - BLI_snprintf(hash_buf, sizeof(hash_buf), "Hash: %s", build_hash); - wm_block_splash_add_label(block, hash_buf, x, &y); - - /* Branch. */ - if (!STREQ(build_branch, "master")) { - char branch_buf[256] = "\0"; - BLI_snprintf(branch_buf, sizeof(branch_buf), "Branch: %s", build_branch); - - wm_block_splash_add_label(block, branch_buf, x, &y); + uchar *rct = (uchar *)ibuf->rect; + + if (rct) { + bTheme *btheme = UI_GetTheme(); + const float roundness = btheme->tui.wcol_menu_back.roundness * U.dpi_fac; + const int size = roundness * 20; + + if (size < ibuf->x && size < ibuf->y) { + /* Y-axis initial offset. */ + rct += 4 * (ibuf->y - size) * ibuf->x; + + for (int y = 0; y < size; y++) { + for (int x = 0; x < size; x++, rct += 4) { + const float pixel = 1.0 / size; + const float u = pixel * x; + const float v = pixel * y; + const float distance = sqrt(u * u + v * v); + + /* Pointer offset to the alpha value of pixel. */ + /* Note, the left corner is flipped in the X-axis. */ + const int offset_l = 4 * (size - x - x - 1) + 3; + const int offset_r = 4 * (ibuf->x - size) + 3; + + if (distance > 1.0) { + rct[offset_l] = 0; + rct[offset_r] = 0; + } + else { + /* Create a single pixel wide transition for anti-aliasing. + * Invert the distance and map its range [0, 1] to [0, pixel]. */ + const float fac = (1.0 - distance) * size; + + if (fac > 1.0) { + continue; + } + + const uchar alpha = unit_float_to_uchar_clamp(fac); + rct[offset_l] = alpha; + rct[offset_r] = alpha; + } + } + + /* X-axis offset to the next row. */ + rct += 4 * (ibuf->x - size); + } } } -#else - UNUSED_VARS(show_build_info); -#endif /* WITH_BUILDINFO */ } +#endif /* WITH_HEADLESS */ -static ImBuf *wm_block_splash_image(int r_unit_size[2]) +static ImBuf *wm_block_splash_image(int width, int *r_height) { #ifndef WITH_HEADLESS extern char datatoc_splash_png[]; extern int datatoc_splash_png_size; - extern char datatoc_splash_2x_png[]; - extern int datatoc_splash_2x_png_size; - const bool is_2x = U.dpi_fac > 1.0; - const int imb_scale = is_2x ? 2 : 1; - - /* We could allow this to be variable, - * for now don't since allowing it might create layout issues. - * - * Only check width because splashes sometimes change height - * and we don't want to break app-templates. */ - const int x_expect = 501 * imb_scale; ImBuf *ibuf = NULL; + int height = 0; if (U.app_template[0] != '\0') { char splash_filepath[FILE_MAX]; char template_directory[FILE_MAX]; if (BKE_appdir_app_template_id_search( U.app_template, template_directory, sizeof(template_directory))) { - BLI_join_dirfile(splash_filepath, - sizeof(splash_filepath), - template_directory, - is_2x ? "splash_2x.png" : "splash.png"); + BLI_join_dirfile(splash_filepath, sizeof(splash_filepath), template_directory, "splash.png"); ibuf = IMB_loadiffname(splash_filepath, IB_rect, NULL); - - /* We could skip this check, see comment about 'x_expect' above. */ - if (ibuf && ibuf->x != x_expect) { - CLOG_ERROR(WM_LOG_OPERATORS, - "Splash expected %d width found %d, ignoring: %s\n", - x_expect, - ibuf->x, - splash_filepath); - IMB_freeImBuf(ibuf); - ibuf = NULL; - } } } if (ibuf == NULL) { - const uchar *splash_data; - size_t splash_data_size; + const uchar *splash_data = (const uchar *)datatoc_splash_png; + size_t splash_data_size = datatoc_splash_png_size; + ibuf = IMB_ibImageFromMemory(splash_data, splash_data_size, IB_rect, NULL, "<splash screen>"); + } - if (is_2x) { - splash_data = (const uchar *)datatoc_splash_2x_png; - splash_data_size = datatoc_splash_2x_png_size; - } - else { - splash_data = (const uchar *)datatoc_splash_png; - splash_data_size = datatoc_splash_png_size; + if (ibuf) { + height = (width * ibuf->y) / ibuf->x; + if (width != ibuf->x || height != ibuf->y) { + IMB_scaleImBuf(ibuf, width, height); } - ibuf = IMB_ibImageFromMemory(splash_data, splash_data_size, IB_rect, NULL, "<splash screen>"); - - BLI_assert(ibuf->x == x_expect); + wm_block_splash_image_roundcorners_add(ibuf); + IMB_premultiply_alpha(ibuf); } - if (is_2x) { - r_unit_size[0] = ibuf->x / 2; - r_unit_size[1] = ibuf->y / 2; - } - else { - r_unit_size[0] = ibuf->x; - r_unit_size[1] = ibuf->y; - } + *r_height = height; return ibuf; #else - UNUSED_VARS(r_unit_size); + UNUSED_VARS(width, r_height); return NULL; #endif } @@ -269,23 +207,20 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *region, void *UNUSE UI_block_flag_enable(block, UI_BLOCK_LOOP | UI_BLOCK_KEEP_OPEN | UI_BLOCK_NO_WIN_CLIP); UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP); - /* Size before dpi scaling (halved for hi-dpi image). */ - int ibuf_unit_size[2]; - ImBuf *ibuf = wm_block_splash_image(ibuf_unit_size); - but = uiDefButImage(block, - ibuf, - 0, - 0.5f * U.widget_unit, - U.dpi_fac * ibuf_unit_size[0], - U.dpi_fac * ibuf_unit_size[1], - NULL); - UI_but_func_set(but, wm_block_splash_close, block, NULL); - UI_block_func_set(block, wm_block_splash_refreshmenu, block, NULL); + int splash_width = 500.0f * U.dpi_fac; + int splash_height; + + /* Would be nice to support caching this, so it only has to be re-read (and likely resized) on + * first draw or if the image changed. */ + ImBuf *ibuf = wm_block_splash_image(splash_width, &splash_height); - int x = U.dpi_fac * (ibuf_unit_size[0] + 1); - int y = U.dpi_fac * (ibuf_unit_size[1] - 13); + but = uiDefButImage(block, ibuf, 0, 0.5f * U.widget_unit, splash_width, splash_height, NULL); + + UI_but_func_set(but, wm_block_close, block, NULL); + UI_block_func_set(block, wm_block_splash_refreshmenu, block, NULL); - wm_block_splash_add_labels(block, x, y); + wm_block_splash_add_label( + block, BKE_blender_version_string(), splash_width, splash_height - 13.0 * U.dpi_fac); const int layout_margin_x = U.dpi_fac * 26; uiLayout *layout = UI_block_layout(block, @@ -293,7 +228,7 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *region, void *UNUSE UI_LAYOUT_PANEL, layout_margin_x, 0, - (U.dpi_fac * ibuf_unit_size[0]) - (layout_margin_x * 2), + splash_width - (layout_margin_x * 2), U.dpi_fac * 110, 0, style); @@ -324,3 +259,92 @@ void WM_OT_splash(wmOperatorType *ot) ot->invoke = wm_splash_invoke; ot->poll = WM_operator_winactive; } + +static uiBlock *wm_block_create_about(bContext *C, ARegion *region, void *UNUSED(arg)) +{ + uiBlock *block; + const uiStyle *style = UI_style_get_dpi(); + const int dialog_width = U.widget_unit * 24; + const short logo_size = 128 * U.dpi_fac; + + /* Calculate icon column factor. */ + const float split_factor = (float)logo_size / (float)(dialog_width - style->columnspace); + + block = UI_block_begin(C, region, "about", UI_EMBOSS); + + UI_block_flag_enable( + block, UI_BLOCK_KEEP_OPEN | UI_BLOCK_LOOP | UI_BLOCK_NO_WIN_CLIP | UI_BLOCK_NUMSELECT); + UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP); + UI_block_emboss_set(block, UI_EMBOSS); + + uiLayout *block_layout = UI_block_layout( + block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, dialog_width, 0, 0, style); + + /* Split layout to put Blender logo on left side. */ + uiLayout *split_block = uiLayoutSplit(block_layout, split_factor, false); + + /* Blender Logo. */ + uiLayout *layout = uiLayoutColumn(split_block, false); + uiDefButAlert(block, ALERT_ICON_BLENDER, 0, 0, 0, logo_size); + + /* The rest of the content on the right. */ + layout = uiLayoutColumn(split_block, false); + + uiLayoutSetScaleY(layout, 0.7f); + + uiItemS_ex(layout, 1.0f); + + /* Title. */ + uiItemL_ex(layout, "Blender", ICON_NONE, true, false); + + /* Version. */ + uiItemL(layout, BKE_blender_version_string(), ICON_NONE); + + uiItemS_ex(layout, 3.0f); + +#ifdef WITH_BUILDINFO + + extern char build_hash[], build_commit_date[], build_commit_time[], build_branch[]; + + char str_buf[256] = "\0"; + BLI_snprintf(str_buf, sizeof(str_buf), "Date: %s %s", build_commit_date, build_commit_time); + uiItemL(layout, str_buf, ICON_NONE); + + BLI_snprintf(str_buf, sizeof(str_buf), "Hash: %s", build_hash); + uiItemL(layout, str_buf, ICON_NONE); + + BLI_snprintf(str_buf, sizeof(str_buf), "Branch: %s", build_branch); + uiItemL(layout, str_buf, ICON_NONE); + +#endif /* WITH_BUILDINFO */ + + uiItemS_ex(layout, 1.5f); + + MenuType *mt = WM_menutype_find("WM_MT_splash_about", true); + if (mt) { + UI_menutype_draw(C, mt, layout); + } + + uiItemS_ex(layout, 2.0f); + + UI_block_bounds_set_centered(block, 14 * U.dpi_fac); + + return block; +} + +static int wm_about_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event)) +{ + UI_popup_block_invoke(C, wm_block_create_about, NULL, NULL); + + return OPERATOR_FINISHED; +} + +void WM_OT_splash_about(wmOperatorType *ot) +{ + ot->name = "About Blender"; + ot->idname = "WM_OT_splash_about"; + ot->description = "Open a window with information about Blender"; + + ot->invoke = wm_about_invoke; + ot->poll = WM_operator_winactive; +} diff --git a/source/blender/windowmanager/intern/wm_surface.c b/source/blender/windowmanager/intern/wm_surface.c index 043b584bbbd..e8850693d69 100644 --- a/source/blender/windowmanager/intern/wm_surface.c +++ b/source/blender/windowmanager/intern/wm_surface.c @@ -45,7 +45,7 @@ static wmSurface *g_drawable = NULL; void wm_surfaces_iter(bContext *C, void (*cb)(bContext *C, wmSurface *)) { - for (wmSurface *surf = global_surface_list.first; surf; surf = surf->next) { + LISTBASE_FOREACH (wmSurface *, surf, &global_surface_list) { cb(C, surf); } } diff --git a/source/blender/windowmanager/intern/wm_toolsystem.c b/source/blender/windowmanager/intern/wm_toolsystem.c index 551250ec747..72969f34162 100644 --- a/source/blender/windowmanager/intern/wm_toolsystem.c +++ b/source/blender/windowmanager/intern/wm_toolsystem.c @@ -72,18 +72,18 @@ struct bToolRef *WM_toolsystem_ref_from_context(struct bContext *C) { WorkSpace *workspace = CTX_wm_workspace(C); ViewLayer *view_layer = CTX_data_view_layer(C); - ScrArea *sa = CTX_wm_area(C); - if ((sa == NULL) || ((1 << sa->spacetype) & WM_TOOLSYSTEM_SPACE_MASK) == 0) { + ScrArea *area = CTX_wm_area(C); + if ((area == NULL) || ((1 << area->spacetype) & WM_TOOLSYSTEM_SPACE_MASK) == 0) { return NULL; } const bToolKey tkey = { - .space_type = sa->spacetype, - .mode = WM_toolsystem_mode_from_spacetype(view_layer, sa, sa->spacetype), + .space_type = area->spacetype, + .mode = WM_toolsystem_mode_from_spacetype(view_layer, area, area->spacetype), }; bToolRef *tref = WM_toolsystem_ref_find(workspace, &tkey); - /* We could return 'sa->runtime.tool' in this case. */ - if (sa->runtime.is_tool_set) { - BLI_assert(tref == sa->runtime.tool); + /* We could return 'area->runtime.tool' in this case. */ + if (area->runtime.is_tool_set) { + BLI_assert(tref == area->runtime.tool); } return tref; } @@ -178,7 +178,7 @@ static void toolsystem_ref_link(bContext *C, WorkSpace *workspace, bToolRef *tre if (i != -1) { const int value = items[i].value; wmWindowManager *wm = bmain->wm.first; - for (wmWindow *win = wm->windows.first; win; win = win->next) { + LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { if (workspace == WM_window_get_active_workspace(win)) { Scene *scene = WM_window_get_active_scene(win); ToolSettings *ts = scene->toolsettings; @@ -197,7 +197,7 @@ static void toolsystem_ref_link(bContext *C, WorkSpace *workspace, bToolRef *tre if (i != -1) { const int slot_index = items[i].value; wmWindowManager *wm = bmain->wm.first; - for (wmWindow *win = wm->windows.first; win; win = win->next) { + LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { if (workspace == WM_window_get_active_workspace(win)) { Scene *scene = WM_window_get_active_scene(win); BKE_paint_ensure_from_paintmode(scene, paint_mode); @@ -279,15 +279,15 @@ void WM_toolsystem_reinit_all(struct bContext *C, wmWindow *win) { bScreen *screen = WM_window_get_active_screen(win); ViewLayer *view_layer = WM_window_get_active_view_layer(win); - for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { - if (((1 << sa->spacetype) & WM_TOOLSYSTEM_SPACE_MASK) == 0) { + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + if (((1 << area->spacetype) & WM_TOOLSYSTEM_SPACE_MASK) == 0) { continue; } WorkSpace *workspace = WM_window_get_active_workspace(win); const bToolKey tkey = { - .space_type = sa->spacetype, - .mode = WM_toolsystem_mode_from_spacetype(view_layer, sa, sa->spacetype), + .space_type = area->spacetype, + .mode = WM_toolsystem_mode_from_spacetype(view_layer, area, area->spacetype), }; bToolRef *tref = WM_toolsystem_ref_find(workspace, &tkey); if (tref) { @@ -372,7 +372,7 @@ void WM_toolsystem_ref_sync_from_context(Main *bmain, WorkSpace *workspace, bToo return; } wmWindowManager *wm = bmain->wm.first; - for (wmWindow *win = wm->windows.first; win; win = win->next) { + LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { if (workspace != WM_window_get_active_workspace(win)) { continue; } @@ -450,12 +450,12 @@ static bool toolsystem_key_ensure_check(const bToolKey *tkey) return false; } -int WM_toolsystem_mode_from_spacetype(ViewLayer *view_layer, ScrArea *sa, int spacetype) +int WM_toolsystem_mode_from_spacetype(ViewLayer *view_layer, ScrArea *area, int spacetype) { int mode = -1; switch (spacetype) { case SPACE_VIEW3D: { - /* 'sa' may be NULL in this case. */ + /* 'area' may be NULL in this case. */ Object *obact = OBACT(view_layer); if (obact != NULL) { Object *obedit = OBEDIT_FROM_OBACT(obact); @@ -467,7 +467,7 @@ int WM_toolsystem_mode_from_spacetype(ViewLayer *view_layer, ScrArea *sa, int sp break; } case SPACE_IMAGE: { - SpaceImage *sima = sa->spacedata.first; + SpaceImage *sima = area->spacedata.first; mode = sima->mode; break; } @@ -476,7 +476,7 @@ int WM_toolsystem_mode_from_spacetype(ViewLayer *view_layer, ScrArea *sa, int sp break; } case SPACE_SEQ: { - SpaceSeq *sseq = sa->spacedata.first; + SpaceSeq *sseq = area->spacedata.first; mode = sseq->view; break; } @@ -484,14 +484,14 @@ int WM_toolsystem_mode_from_spacetype(ViewLayer *view_layer, ScrArea *sa, int sp return mode; } -bool WM_toolsystem_key_from_context(ViewLayer *view_layer, ScrArea *sa, bToolKey *tkey) +bool WM_toolsystem_key_from_context(ViewLayer *view_layer, ScrArea *area, bToolKey *tkey) { int space_type = SPACE_EMPTY; int mode = -1; - if (sa != NULL) { - space_type = sa->spacetype; - mode = WM_toolsystem_mode_from_spacetype(view_layer, sa, space_type); + if (area != NULL) { + space_type = area->spacetype; + mode = WM_toolsystem_mode_from_spacetype(view_layer, area, space_type); } if (mode != -1) { @@ -514,24 +514,24 @@ void WM_toolsystem_refresh_active(bContext *C) { Main *bmain = CTX_data_main(C); for (wmWindowManager *wm = bmain->wm.first; wm; wm = wm->id.next) { - for (wmWindow *win = wm->windows.first; win; win = win->next) { + LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { WorkSpace *workspace = WM_window_get_active_workspace(win); bScreen *screen = WM_window_get_active_screen(win); ViewLayer *view_layer = WM_window_get_active_view_layer(win); /* Could skip loop for modes that don't depend on space type. */ int space_type_mask_handled = 0; - for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { /* Don't change the space type of the active tool, only update it's mode. */ - const int space_type_mask = (1 << sa->spacetype); + const int space_type_mask = (1 << area->spacetype); if ((space_type_mask & WM_TOOLSYSTEM_SPACE_MASK) && ((space_type_mask_handled & space_type_mask) == 0)) { space_type_mask_handled |= space_type_mask; const bToolKey tkey = { - .space_type = sa->spacetype, - .mode = WM_toolsystem_mode_from_spacetype(view_layer, sa, sa->spacetype), + .space_type = area->spacetype, + .mode = WM_toolsystem_mode_from_spacetype(view_layer, area, area->spacetype), }; bToolRef *tref = WM_toolsystem_ref_find(workspace, &tkey); - if (tref != sa->runtime.tool) { + if (tref != area->runtime.tool) { toolsystem_reinit_ensure_toolref(C, workspace, &tkey, NULL); } } @@ -547,22 +547,22 @@ void WM_toolsystem_refresh_active(bContext *C) /* Refresh to ensure data is initialized. * This is needed because undo can load a state which no longer has the underlying DNA data * needed for the tool (un-initialized paint-slots for eg), see: T64339. */ - for (bToolRef *tref = workspace->tools.first; tref; tref = tref->next) { + LISTBASE_FOREACH (bToolRef *, tref, &workspace->tools) { toolsystem_refresh_ref(C, workspace, tref); } } } } -void WM_toolsystem_refresh_screen_area(WorkSpace *workspace, ViewLayer *view_layer, ScrArea *sa) +void WM_toolsystem_refresh_screen_area(WorkSpace *workspace, ViewLayer *view_layer, ScrArea *area) { - sa->runtime.tool = NULL; - sa->runtime.is_tool_set = true; - const int mode = WM_toolsystem_mode_from_spacetype(view_layer, sa, sa->spacetype); - for (bToolRef *tref = workspace->tools.first; tref; tref = tref->next) { - if (tref->space_type == sa->spacetype) { + area->runtime.tool = NULL; + area->runtime.is_tool_set = true; + const int mode = WM_toolsystem_mode_from_spacetype(view_layer, area, area->spacetype); + LISTBASE_FOREACH (bToolRef *, tref, &workspace->tools) { + if (tref->space_type == area->spacetype) { if (tref->mode == mode) { - sa->runtime.tool = tref; + area->runtime.tool = tref; break; } } @@ -573,19 +573,19 @@ void WM_toolsystem_refresh_screen_all(Main *bmain) { /* Update all ScrArea's tools */ for (wmWindowManager *wm = bmain->wm.first; wm; wm = wm->id.next) { - for (wmWindow *win = wm->windows.first; win; win = win->next) { + LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { WorkSpace *workspace = WM_window_get_active_workspace(win); bool space_type_has_tools[SPACE_TYPE_LAST + 1] = {0}; - for (bToolRef *tref = workspace->tools.first; tref; tref = tref->next) { + LISTBASE_FOREACH (bToolRef *, tref, &workspace->tools) { space_type_has_tools[tref->space_type] = true; } bScreen *screen = WM_window_get_active_screen(win); ViewLayer *view_layer = WM_window_get_active_view_layer(win); - for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { - sa->runtime.tool = NULL; - sa->runtime.is_tool_set = true; - if (space_type_has_tools[sa->spacetype]) { - WM_toolsystem_refresh_screen_area(workspace, view_layer, sa); + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + area->runtime.tool = NULL; + area->runtime.is_tool_set = true; + if (space_type_has_tools[area->spacetype]) { + WM_toolsystem_refresh_screen_area(workspace, view_layer, area); } } } @@ -598,16 +598,16 @@ static void toolsystem_refresh_screen_from_active_tool(Main *bmain, { /* Update all ScrArea's tools */ for (wmWindowManager *wm = bmain->wm.first; wm; wm = wm->id.next) { - for (wmWindow *win = wm->windows.first; win; win = win->next) { + LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { if (workspace == WM_window_get_active_workspace(win)) { bScreen *screen = WM_window_get_active_screen(win); ViewLayer *view_layer = WM_window_get_active_view_layer(win); - for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { - if (sa->spacetype == tref->space_type) { - int mode = WM_toolsystem_mode_from_spacetype(view_layer, sa, sa->spacetype); + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + if (area->spacetype == tref->space_type) { + int mode = WM_toolsystem_mode_from_spacetype(view_layer, area, area->spacetype); if (mode == tref->mode) { - sa->runtime.tool = tref; - sa->runtime.is_tool_set = true; + area->runtime.tool = tref; + area->runtime.is_tool_set = true; } } } @@ -649,9 +649,9 @@ bToolRef *WM_toolsystem_ref_set_by_id_ex( bToolRef *WM_toolsystem_ref_set_by_id(bContext *C, const char *name) { ViewLayer *view_layer = CTX_data_view_layer(C); - ScrArea *sa = CTX_wm_area(C); + ScrArea *area = CTX_wm_area(C); bToolKey tkey; - if (WM_toolsystem_key_from_context(view_layer, sa, &tkey)) { + if (WM_toolsystem_key_from_context(view_layer, area, &tkey)) { WorkSpace *workspace = CTX_wm_workspace(C); return WM_toolsystem_ref_set_by_id_ex(C, workspace, &tkey, name, false); } @@ -707,7 +707,7 @@ static const char *toolsystem_default_tool(const bToolKey *tkey) case SEQ_VIEW_SEQUENCE: return "builtin.select"; case SEQ_VIEW_PREVIEW: - return "builtin.annotate"; + return "builtin.sample"; case SEQ_VIEW_SEQUENCE_PREVIEW: return "builtin.select"; } @@ -759,9 +759,9 @@ void WM_toolsystem_update_from_context_view3d(bContext *C) if (!BLI_listbase_is_single(&wm->windows)) { wmWindow *win_prev = CTX_wm_window(C); ScrArea *area_prev = CTX_wm_area(C); - ARegion *ar_prev = CTX_wm_region(C); + ARegion *region_prev = CTX_wm_region(C); - for (wmWindow *win = wm->windows.first; win; win = win->next) { + LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { if (win != win_prev) { WorkSpace *workspace_iter = WM_window_get_active_workspace(win); if (workspace_iter != workspace) { @@ -772,7 +772,7 @@ void WM_toolsystem_update_from_context_view3d(bContext *C) CTX_wm_window_set(C, win_prev); CTX_wm_area_set(C, area_prev); - CTX_wm_region_set(C, ar_prev); + CTX_wm_region_set(C, region_prev); } } } @@ -782,11 +782,11 @@ void WM_toolsystem_update_from_context_view3d(bContext *C) void WM_toolsystem_update_from_context(bContext *C, WorkSpace *workspace, ViewLayer *view_layer, - ScrArea *sa) + ScrArea *area) { const bToolKey tkey = { - .space_type = sa->spacetype, - .mode = WM_toolsystem_mode_from_spacetype(view_layer, sa, sa->spacetype), + .space_type = area->spacetype, + .mode = WM_toolsystem_mode_from_spacetype(view_layer, area, area->spacetype), }; if (toolsystem_key_ensure_check(&tkey)) { toolsystem_reinit_ensure_toolref(C, workspace, &tkey, NULL); @@ -807,13 +807,13 @@ void WM_toolsystem_do_msg_notify_tag_refresh(bContext *C, wmMsgSubscribeKey *UNUSED(msg_key), wmMsgSubscribeValue *msg_val) { - ScrArea *sa = msg_val->user_data; + ScrArea *area = msg_val->user_data; Main *bmain = CTX_data_main(C); wmWindow *win = ((wmWindowManager *)bmain->wm.first)->windows.first; if (win->next != NULL) { do { bScreen *screen = WM_window_get_active_screen(win); - if (BLI_findindex(&screen->areabase, sa) != -1) { + if (BLI_findindex(&screen->areabase, area) != -1) { break; } } while ((win = win->next)); @@ -823,11 +823,11 @@ void WM_toolsystem_do_msg_notify_tag_refresh(bContext *C, ViewLayer *view_layer = WM_window_get_active_view_layer(win); const bToolKey tkey = { - .space_type = sa->spacetype, - .mode = WM_toolsystem_mode_from_spacetype(view_layer, sa, sa->spacetype), + .space_type = area->spacetype, + .mode = WM_toolsystem_mode_from_spacetype(view_layer, area, area->spacetype), }; WM_toolsystem_refresh(C, workspace, &tkey); - WM_toolsystem_refresh_screen_area(workspace, view_layer, sa); + WM_toolsystem_refresh_screen_area(workspace, view_layer, area); } IDProperty *WM_toolsystem_ref_properties_ensure_idprops(bToolRef *tref) diff --git a/source/blender/windowmanager/intern/wm_tooltip.c b/source/blender/windowmanager/intern/wm_tooltip.c index da2afda5e24..a9f0e01cfb5 100644 --- a/source/blender/windowmanager/intern/wm_tooltip.c +++ b/source/blender/windowmanager/intern/wm_tooltip.c @@ -43,7 +43,7 @@ double WM_tooltip_time_closed(void) } void WM_tooltip_immediate_init( - bContext *C, wmWindow *win, ScrArea *sa, ARegion *region, wmTooltipInitFn init) + bContext *C, wmWindow *win, ScrArea *area, ARegion *region, wmTooltipInitFn init) { WM_tooltip_timer_clear(C, win); @@ -51,14 +51,14 @@ void WM_tooltip_immediate_init( if (screen->tool_tip == NULL) { screen->tool_tip = MEM_callocN(sizeof(*screen->tool_tip), __func__); } - screen->tool_tip->area_from = sa; + screen->tool_tip->area_from = area; screen->tool_tip->region_from = region; screen->tool_tip->init = init; WM_tooltip_init(C, win); } void WM_tooltip_timer_init_ex( - bContext *C, wmWindow *win, ScrArea *sa, ARegion *region, wmTooltipInitFn init, double delay) + bContext *C, wmWindow *win, ScrArea *area, ARegion *region, wmTooltipInitFn init, double delay) { WM_tooltip_timer_clear(C, win); @@ -67,16 +67,16 @@ void WM_tooltip_timer_init_ex( if (screen->tool_tip == NULL) { screen->tool_tip = MEM_callocN(sizeof(*screen->tool_tip), __func__); } - screen->tool_tip->area_from = sa; + screen->tool_tip->area_from = area; screen->tool_tip->region_from = region; screen->tool_tip->timer = WM_event_add_timer(wm, win, TIMER, delay); screen->tool_tip->init = init; } void WM_tooltip_timer_init( - bContext *C, wmWindow *win, ScrArea *sa, ARegion *region, wmTooltipInitFn init) + bContext *C, wmWindow *win, ScrArea *area, ARegion *region, wmTooltipInitFn init) { - WM_tooltip_timer_init_ex(C, win, sa, region, init, UI_TOOLTIP_DELAY); + WM_tooltip_timer_init_ex(C, win, area, region, init, UI_TOOLTIP_DELAY); } void WM_tooltip_timer_clear(bContext *C, wmWindow *win) @@ -119,7 +119,7 @@ void WM_tooltip_init(bContext *C, wmWindow *win) { ScrArea *area_prev = CTX_wm_area(C); - ARegion *ar_prev = CTX_wm_region(C); + ARegion *region_prev = CTX_wm_region(C); CTX_wm_area_set(C, screen->tool_tip->area_from); CTX_wm_region_set(C, screen->tool_tip->region_from); screen->tool_tip->region = screen->tool_tip->init(C, @@ -128,7 +128,7 @@ void WM_tooltip_init(bContext *C, wmWindow *win) &pass_delay, &screen->tool_tip->exit_on_event); CTX_wm_area_set(C, area_prev); - CTX_wm_region_set(C, ar_prev); + CTX_wm_region_set(C, region_prev); } copy_v2_v2_int(screen->tool_tip->event_xy, &win->eventstate->x); diff --git a/source/blender/windowmanager/intern/wm_uilist_type.c b/source/blender/windowmanager/intern/wm_uilist_type.c index f886e01f5a3..801043a56d1 100644 --- a/source/blender/windowmanager/intern/wm_uilist_type.c +++ b/source/blender/windowmanager/intern/wm_uilist_type.c @@ -82,8 +82,8 @@ void WM_uilisttype_free(void) GHASH_ITER (gh_iter, uilisttypes_hash) { uiListType *ult = BLI_ghashIterator_getValue(&gh_iter); - if (ult->ext.free) { - ult->ext.free(ult->ext.data); + if (ult->rna_ext.free) { + ult->rna_ext.free(ult->rna_ext.data); } } diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index 0f96500b8b3..05a84f6acaa 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -65,6 +65,9 @@ #include "wm_platform_support.h" #include "wm_window.h" #include "wm_window_private.h" +#ifdef WITH_XR_OPENXR +# include "wm_xr.h" +#endif #include "ED_anim_api.h" #include "ED_fileselect.h" @@ -81,11 +84,11 @@ #include "GPU_batch.h" #include "GPU_batch_presets.h" #include "GPU_context.h" -#include "GPU_draw.h" #include "GPU_framebuffer.h" #include "GPU_immediate.h" #include "GPU_init_exit.h" #include "GPU_platform.h" +#include "GPU_state.h" #include "UI_resources.h" @@ -283,14 +286,15 @@ static int find_free_winid(wmWindowManager *wm) } /* don't change context itself */ -wmWindow *wm_window_new(const Main *bmain, wmWindowManager *wm, wmWindow *parent) +wmWindow *wm_window_new(const Main *bmain, wmWindowManager *wm, wmWindow *parent, bool dialog) { wmWindow *win = MEM_callocN(sizeof(wmWindow), "window"); BLI_addtail(&wm->windows, win); win->winid = find_free_winid(wm); - win->parent = (parent && parent->parent) ? parent->parent : parent; + /* Dialogs may have a child window as parent. Otherwise, a child must not be a parent too. */ + win->parent = (!dialog && parent && parent->parent) ? parent->parent : parent; win->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Stereo 3D Format (window)"); win->workspace_hook = BKE_workspace_instance_hook_create(bmain); @@ -304,8 +308,9 @@ wmWindow *wm_window_copy(Main *bmain, const bool duplicate_layout, const bool child) { + const bool is_dialog = GHOST_IsDialogWindow(win_src->ghostwin); wmWindow *win_parent = (child) ? win_src : win_src->parent; - wmWindow *win_dst = wm_window_new(bmain, wm, win_parent); + wmWindow *win_dst = wm_window_new(bmain, wm, win_parent, is_dialog); WorkSpace *workspace = WM_window_get_active_workspace(win_src); WorkSpaceLayout *layout_old = WM_window_get_active_layout(win_src); WorkSpaceLayout *layout_new; @@ -321,7 +326,7 @@ wmWindow *wm_window_copy(Main *bmain, layout_new = duplicate_layout ? ED_workspace_layout_duplicate(bmain, workspace, layout_old, win_dst) : layout_old; - BKE_workspace_hook_layout_for_workspace_set(win_dst->workspace_hook, workspace, layout_new); + BKE_workspace_active_layout_set(win_dst->workspace_hook, workspace, layout_new); *win_dst->stereo3d_format = *win_src->stereo3d_format; @@ -414,7 +419,6 @@ void wm_quit_with_optional_confirmation_prompt(bContext *C, wmWindow *win) void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win) { wmWindow *win_other; - const bool is_dialog = (G.background == false) ? GHOST_IsDialogWindow(win->ghostwin) : false; /* First check if there is another main window remaining. */ for (win_other = wm->windows.first; win_other; win_other = win_other->next) { @@ -428,20 +432,11 @@ void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win) return; } - /* Close child windows and bring windows back to front that dialogs have pushed behind the main - * window. */ - for (wmWindow *iter_win = wm->windows.first; iter_win; iter_win = iter_win->next) { + /* Close child windows */ + LISTBASE_FOREACH_MUTABLE (wmWindow *, iter_win, &wm->windows) { if (iter_win->parent == win) { wm_window_close(C, wm, iter_win); } - else { - if (G.background == false) { - if (is_dialog && iter_win != win && iter_win->parent && - (GHOST_GetWindowState(iter_win->ghostwin) != GHOST_kWindowStateMinimized)) { - wm_window_raise(iter_win); - } - } - } } bScreen *screen = WM_window_get_active_screen(win); @@ -761,22 +756,9 @@ void wm_window_ghostwindows_ensure(wmWindowManager *wm) * in practice the window manager will likely move to the correct monitor */ wm_init_state.start_x = 0; wm_init_state.start_y = 0; - -#ifdef WITH_X11 /* X11 */ - /* X11, don't start maximized because we can't figure out the dimensions - * of a single display yet if there are multiple, due to lack of Xinerama - * handling in GHOST. */ - wm_init_state.size_x = min_ii(wm_init_state.size_x, WM_WIN_INIT_SIZE_X); - wm_init_state.size_y = min_ii(wm_init_state.size_y, WM_WIN_INIT_SIZE_Y); - /* pad */ - wm_init_state.start_x = WM_WIN_INIT_PAD; - wm_init_state.start_y = WM_WIN_INIT_PAD; - wm_init_state.size_x -= WM_WIN_INIT_PAD * 2; - wm_init_state.size_y -= WM_WIN_INIT_PAD * 2; -#endif } - for (wmWindow *win = wm->windows.first; win; win = win->next) { + LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { wm_window_ghostwindow_ensure(wm, win, false); } } @@ -799,6 +781,36 @@ void wm_window_ghostwindows_remove_invalid(bContext *C, wmWindowManager *wm) } } +/* Update window size and position based on data from GHOST window. */ +static bool wm_window_update_size_position(wmWindow *win) +{ + GHOST_RectangleHandle client_rect; + int l, t, r, b, scr_w, scr_h; + int sizex, sizey, posx, posy; + + client_rect = GHOST_GetClientBounds(win->ghostwin); + GHOST_GetRectangle(client_rect, &l, &t, &r, &b); + + GHOST_DisposeRectangle(client_rect); + + wm_get_desktopsize(&scr_w, &scr_h); + sizex = r - l; + sizey = b - t; + posx = l; + posy = scr_h - t - win->sizey; + + if (win->sizex != sizex || win->sizey != sizey || win->posx != posx || win->posy != posy) { + win->sizex = sizex; + win->sizey = sizey; + win->posx = posx; + win->posy = posy; + return true; + } + else { + return false; + } +} + /** * new window, no screen yet, but we open ghostwindow for it, * also gets the window level handlers @@ -809,7 +821,7 @@ wmWindow *WM_window_open(bContext *C, const rcti *rect) { wmWindowManager *wm = CTX_wm_manager(C); wmWindow *win_prev = CTX_wm_window(C); - wmWindow *win = wm_window_new(CTX_data_main(C), wm, win_prev); + wmWindow *win = wm_window_new(CTX_data_main(C), wm, win_prev, false); win->posx = rect->xmin; win->posy = rect->ymin; @@ -849,7 +861,7 @@ wmWindow *WM_window_open_temp(bContext *C, wmWindow *win_prev = CTX_wm_window(C); wmWindow *win; bScreen *screen; - ScrArea *sa; + ScrArea *area; Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); @@ -880,7 +892,7 @@ wmWindow *WM_window_open_temp(bContext *C, /* add new window? */ if (win == NULL) { - win = wm_window_new(bmain, wm, win_prev); + win = wm_window_new(bmain, wm, win_prev, dialog); win->posx = rect.xmin; win->posy = rect.ymin; @@ -915,7 +927,8 @@ wmWindow *WM_window_open_temp(bContext *C, /* make window active, and validate/resize */ CTX_wm_window_set(C, win); - if (!win->ghostwin) { + const bool new_window = (win->ghostwin == NULL); + if (new_window) { wm_window_ghostwindow_ensure(wm, win, dialog); } WM_check(C); @@ -927,18 +940,25 @@ wmWindow *WM_window_open_temp(bContext *C, */ /* ensure it shows the right spacetype editor */ - sa = screen->areabase.first; - CTX_wm_area_set(C, sa); + area = screen->areabase.first; + CTX_wm_area_set(C, area); - ED_area_newspace(C, sa, space_type, false); + ED_area_newspace(C, area, space_type, false); ED_screen_change(C, screen); - ED_screen_refresh(wm, win); /* test scale */ - if (win->ghostwin) { + if (!new_window) { + /* Set size in GHOST window and then update size and position from GHOST, + * in case they where changed by GHOST to fit the monitor/screen. */ wm_window_set_size(win, win->sizex, win->sizey); - wm_window_raise(win); + wm_window_update_size_position(win); + } + /* Refresh screen dimensions, after the effective window size is known. */ + ED_screen_refresh(wm, win); + + if (win->ghostwin) { + wm_window_raise(win); GHOST_SetTitle(win->ghostwin, title); return win; } @@ -1346,21 +1366,6 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr /* win32: gives undefined window size when minimized */ if (state != GHOST_kWindowStateMinimized) { - GHOST_RectangleHandle client_rect; - int l, t, r, b, scr_w, scr_h; - int sizex, sizey, posx, posy; - - client_rect = GHOST_GetClientBounds(win->ghostwin); - GHOST_GetRectangle(client_rect, &l, &t, &r, &b); - - GHOST_DisposeRectangle(client_rect); - - wm_get_desktopsize(&scr_w, &scr_h); - sizex = r - l; - sizey = b - t; - posx = l; - posy = scr_h - t - win->sizey; - /* * Ghost sometimes send size or move events when the window hasn't changed. * One case of this is using compiz on linux. To alleviate the problem @@ -1369,15 +1374,9 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr * It might be good to eventually do that at Ghost level, but that is for * another time. */ - if (win->sizex != sizex || win->sizey != sizey || win->posx != posx || - win->posy != posy) { + if (wm_window_update_size_position(win)) { const bScreen *screen = WM_window_get_active_screen(win); - win->sizex = sizex; - win->sizey = sizey; - win->posx = posx; - win->posy = posy; - /* debug prints */ if (G.debug & G_DEBUG_EVENTS) { const char *state_str; @@ -1659,8 +1658,6 @@ void wm_ghost_init(bContext *C) } GHOST_UseWindowFocus(wm_init_state.window_focus); - - WM_init_tablet_api(); } } @@ -1970,6 +1967,90 @@ bool wm_window_get_swap_interval(wmWindow *win, int *intervalOut) /** \} */ /* -------------------------------------------------------------------- */ +/** \name Find Window Utility + * + * \{ */ +static void wm_window_desktop_pos_get(const wmWindow *win, + const int screen_pos[2], + int r_desk_pos[2]) +{ + /* To desktop space. */ + r_desk_pos[0] = screen_pos[0] + (int)(U.pixelsize * win->posx); + r_desk_pos[1] = screen_pos[1] + (int)(U.pixelsize * win->posy); +} + +static void wm_window_screen_pos_get(const wmWindow *win, + const int desktop_pos[2], + int r_scr_pos[2]) +{ + /* To window space. */ + r_scr_pos[0] = desktop_pos[0] - (int)(U.pixelsize * win->posx); + r_scr_pos[1] = desktop_pos[1] - (int)(U.pixelsize * win->posy); +} + +bool WM_window_find_under_cursor(const wmWindowManager *wm, + const wmWindow *win_ignore, + const wmWindow *win, + const int mval[2], + wmWindow **r_win, + int r_mval[2]) +{ + int desk_pos[2]; + wm_window_desktop_pos_get(win, mval, desk_pos); + + /* TODO: This should follow the order of the activated windows. + * The current solution is imperfect but usable in most cases. */ + LISTBASE_FOREACH (wmWindow *, win_iter, &wm->windows) { + if (win_iter == win_ignore) { + continue; + } + + if (win_iter->windowstate == GHOST_kWindowStateMinimized) { + continue; + } + + int scr_pos[2]; + wm_window_screen_pos_get(win_iter, desk_pos, scr_pos); + + if (scr_pos[0] >= 0 && win_iter->posy >= 0 && scr_pos[0] <= WM_window_pixels_x(win_iter) && + scr_pos[1] <= WM_window_pixels_y(win_iter)) { + + *r_win = win_iter; + copy_v2_v2_int(r_mval, scr_pos); + return true; + } + } + + return false; +} + +void WM_window_pixel_sample_read(const wmWindowManager *wm, + const wmWindow *win, + const int pos[2], + float r_col[3]) +{ + bool setup_context = wm->windrawable != win; + + if (setup_context) { + GHOST_ActivateWindowDrawingContext(win->ghostwin); + GPU_context_active_set(win->gpuctx); + } + + glReadBuffer(GL_FRONT); + glReadPixels(pos[0], pos[1], 1, 1, GL_RGB, GL_FLOAT, r_col); + glReadBuffer(GL_BACK); + + if (setup_context) { + if (wm->windrawable) { + GHOST_ActivateWindowDrawingContext(wm->windrawable->ghostwin); + GPU_context_active_set(wm->windrawable->gpuctx); + } + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Window Screen Shot Utility * * Include here since it can involve low level buffer switching. @@ -2152,8 +2233,7 @@ void WM_window_screen_rect_calc(const wmWindow *win, rcti *r_rect) screen_rect = window_rect; /* Subtract global areas from screen rectangle. */ - for (ScrArea *global_area = win->global_areas.areabase.first; global_area; - global_area = global_area->next) { + LISTBASE_FOREACH (ScrArea *, global_area, &win->global_areas.areabase) { int height = ED_area_global_size_y(global_area) - 1; if (global_area->global->flag & GLOBAL_AREA_IS_HIDDEN) { @@ -2201,7 +2281,7 @@ bool WM_window_is_maximized(const wmWindow *win) */ void WM_windows_scene_data_sync(const ListBase *win_lb, Scene *scene) { - for (wmWindow *win = win_lb->first; win; win = win->next) { + LISTBASE_FOREACH (wmWindow *, win, win_lb) { if (WM_window_get_active_scene(win) == scene) { ED_workspace_scene_data_sync(win->workspace_hook, scene); } @@ -2210,7 +2290,7 @@ void WM_windows_scene_data_sync(const ListBase *win_lb, Scene *scene) Scene *WM_windows_scene_get_from_screen(const wmWindowManager *wm, const bScreen *screen) { - for (wmWindow *win = wm->windows.first; win; win = win->next) { + LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { if (WM_window_get_active_screen(win) == screen) { return WM_window_get_active_scene(win); } @@ -2221,7 +2301,7 @@ Scene *WM_windows_scene_get_from_screen(const wmWindowManager *wm, const bScreen WorkSpace *WM_windows_workspace_get_from_screen(const wmWindowManager *wm, const bScreen *screen) { - for (wmWindow *win = wm->windows.first; win; win = win->next) { + LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { if (WM_window_get_active_screen(win) == screen) { return WM_window_get_active_workspace(win); } @@ -2249,7 +2329,7 @@ void WM_window_set_active_scene(Main *bmain, bContext *C, wmWindow *win, Scene * changed = true; } - for (wmWindow *win_child = wm->windows.first; win_child; win_child = win_child->next) { + LISTBASE_FOREACH (wmWindow *, win_child, &wm->windows) { if (win_child->parent == win_parent && win_child->scene != scene) { ED_screen_scene_change(C, win_child, scene); changed = true; @@ -2295,7 +2375,7 @@ void WM_window_set_active_view_layer(wmWindow *win, ViewLayer *view_layer) wmWindow *win_parent = (win->parent) ? win->parent : win; /* Set view layer in parent and child windows. */ - for (wmWindow *win_iter = wm->windows.first; win_iter; win_iter = win_iter->next) { + LISTBASE_FOREACH (wmWindow *, win_iter, &wm->windows) { if ((win_iter == win_parent) || (win_iter->parent == win_parent)) { STRNCPY(win_iter->view_layer_name, view_layer->name); bScreen *screen = BKE_workspace_active_screen_get(win_iter->workspace_hook); @@ -2327,7 +2407,7 @@ void WM_window_set_active_workspace(bContext *C, wmWindow *win, WorkSpace *works ED_workspace_change(workspace, C, wm, win); - for (wmWindow *win_child = wm->windows.first; win_child; win_child = win_child->next) { + LISTBASE_FOREACH (wmWindow *, win_child, &wm->windows) { if (win_child->parent == win_parent) { bScreen *screen = WM_window_get_active_screen(win_child); /* Don't change temporary screens, they only serve a single purpose. */ @@ -2346,7 +2426,7 @@ WorkSpaceLayout *WM_window_get_active_layout(const wmWindow *win) } void WM_window_set_active_layout(wmWindow *win, WorkSpace *workspace, WorkSpaceLayout *layout) { - BKE_workspace_hook_layout_for_workspace_set(win->workspace_hook, workspace, layout); + BKE_workspace_active_layout_set(win->workspace_hook, workspace, layout); } /** @@ -2441,24 +2521,3 @@ void WM_ghost_show_message_box(const char *title, GHOST_ShowMessageBox(g_system, title, message, help_label, continue_label, link, dialog_options); } /** \} */ - -#ifdef WIN32 -/* -------------------------------------------------------------------- */ -/** \name Direct DirectX Context Management - * \{ */ - -void *WM_directx_context_create(void) -{ - BLI_assert(GPU_framebuffer_active_get() == NULL); - return GHOST_CreateDirectXContext(g_system); -} - -void WM_directx_context_dispose(void *context) -{ - BLI_assert(GPU_framebuffer_active_get() == NULL); - GHOST_DisposeDirectXContext(g_system, context); -} - -/** \} */ - -#endif diff --git a/source/blender/windowmanager/intern/wm_xr.c b/source/blender/windowmanager/intern/wm_xr.c deleted file mode 100644 index 7422fc97f04..00000000000 --- a/source/blender/windowmanager/intern/wm_xr.c +++ /dev/null @@ -1,765 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** \file - * \ingroup wm - * - * \name Window-Manager XR API - * - * Implements Blender specific functionality for the GHOST_Xr API. - */ - -#include "BKE_context.h" -#include "BKE_global.h" -#include "BKE_idprop.h" -#include "BKE_main.h" -#include "BKE_object.h" -#include "BKE_report.h" -#include "BKE_screen.h" - -#include "BLI_ghash.h" -#include "BLI_math_geom.h" -#include "BLI_math_matrix.h" - -#include "CLG_log.h" - -#include "DNA_camera_types.h" -#include "DNA_object_types.h" -#include "DNA_scene_types.h" -#include "DNA_view3d_types.h" -#include "DNA_xr_types.h" - -#include "DRW_engine.h" - -#include "ED_view3d.h" -#include "ED_view3d_offscreen.h" - -#include "GHOST_C-api.h" - -#include "GPU_context.h" -#include "GPU_draw.h" -#include "GPU_matrix.h" -#include "GPU_viewport.h" - -#include "MEM_guardedalloc.h" - -#include "UI_interface.h" - -#include "WM_api.h" -#include "WM_types.h" - -#include "wm.h" -#include "wm_surface.h" -#include "wm_window.h" - -struct wmXrRuntimeData *wm_xr_runtime_data_create(void); -void wm_xr_runtime_data_free(struct wmXrRuntimeData **runtime); -void wm_xr_draw_view(const GHOST_XrDrawViewInfo *, void *); -void *wm_xr_session_gpu_binding_context_create(GHOST_TXrGraphicsBinding); -void wm_xr_session_gpu_binding_context_destroy(GHOST_TXrGraphicsBinding, GHOST_ContextHandle); -wmSurface *wm_xr_session_surface_create(wmWindowManager *, unsigned int); -void wm_xr_pose_to_viewmat(const GHOST_XrPose *pose, float r_viewmat[4][4]); - -/* -------------------------------------------------------------------- */ - -typedef struct wmXrSessionState { - bool is_started; - - /** Last known viewer pose (centroid of eyes, in world space) stored for queries. */ - GHOST_XrPose viewer_pose; - /** The last known view matrix, calculated from above's viewer pose. */ - float viewer_viewmat[4][4]; - float focal_len; - - /** Copy of XrSessionSettings.flag created on the last draw call, stored to detect changes. */ - int prev_settings_flag; - /** Copy of wmXrDrawData.eye_position_ofs. */ - float prev_eye_position_ofs[3]; - - bool is_view_data_set; -} wmXrSessionState; - -typedef struct wmXrRuntimeData { - GHOST_XrContextHandle context; - - /* Although this struct is internal, RNA gets a handle to this for state information queries. */ - wmXrSessionState session_state; - wmXrSessionExitFn exit_fn; -} wmXrRuntimeData; - -typedef struct wmXrDrawData { - /** The pose (location + rotation) to which eye deltas will be applied to when drawing (world - * space). With positional tracking enabled, it should be the same as the base pose, when - * disabled it also contains a location delta from the moment the option was toggled. */ - GHOST_XrPose base_pose; - float eye_position_ofs[3]; /* Local/view space. */ -} wmXrDrawData; - -typedef struct { - GHOST_TXrGraphicsBinding gpu_binding_type; - GPUOffScreen *offscreen; - GPUViewport *viewport; - - GHOST_ContextHandle secondary_ghost_ctx; -} wmXrSurfaceData; - -typedef struct { - wmWindowManager *wm; -} wmXrErrorHandlerData; - -/* -------------------------------------------------------------------- */ - -static wmSurface *g_xr_surface = NULL; -static CLG_LogRef LOG = {"wm.xr"}; - -/* -------------------------------------------------------------------- */ -/** \name XR-Context - * - * All XR functionality is accessed through a #GHOST_XrContext handle. - * The lifetime of this context also determines the lifetime of the OpenXR instance, which is the - * representation of the OpenXR runtime connection within the application. - * - * \{ */ - -static void wm_xr_error_handler(const GHOST_XrError *error) -{ - wmXrErrorHandlerData *handler_data = error->customdata; - wmWindowManager *wm = handler_data->wm; - - BKE_reports_clear(&wm->reports); - WM_report(RPT_ERROR, error->user_message); - WM_report_banner_show(); - - if (wm->xr.runtime) { - /* Just play safe and destroy the entire runtime data, including context. */ - wm_xr_runtime_data_free(&wm->xr.runtime); - } -} - -bool wm_xr_init(wmWindowManager *wm) -{ - if (wm->xr.runtime && wm->xr.runtime->context) { - return true; - } - static wmXrErrorHandlerData error_customdata; - - /* Set up error handling */ - error_customdata.wm = wm; - GHOST_XrErrorHandler(wm_xr_error_handler, &error_customdata); - - { - const GHOST_TXrGraphicsBinding gpu_bindings_candidates[] = { - GHOST_kXrGraphicsOpenGL, -#ifdef WIN32 - GHOST_kXrGraphicsD3D11, -#endif - }; - GHOST_XrContextCreateInfo create_info = { - .gpu_binding_candidates = gpu_bindings_candidates, - .gpu_binding_candidates_count = ARRAY_SIZE(gpu_bindings_candidates), - }; - GHOST_XrContextHandle context; - - if (G.debug & G_DEBUG_XR) { - create_info.context_flag |= GHOST_kXrContextDebug; - } - if (G.debug & G_DEBUG_XR_TIME) { - create_info.context_flag |= GHOST_kXrContextDebugTime; - } - - if (!(context = GHOST_XrContextCreate(&create_info))) { - return false; - } - - /* Set up context callbacks */ - GHOST_XrGraphicsContextBindFuncs(context, - wm_xr_session_gpu_binding_context_create, - wm_xr_session_gpu_binding_context_destroy); - GHOST_XrDrawViewFunc(context, wm_xr_draw_view); - - if (!wm->xr.runtime) { - wm->xr.runtime = wm_xr_runtime_data_create(); - wm->xr.runtime->context = context; - } - } - BLI_assert(wm->xr.runtime && wm->xr.runtime->context); - - return true; -} - -void wm_xr_exit(wmWindowManager *wm) -{ - if (wm->xr.runtime != NULL) { - wm_xr_runtime_data_free(&wm->xr.runtime); - } - if (wm->xr.session_settings.shading.prop) { - IDP_FreeProperty(wm->xr.session_settings.shading.prop); - wm->xr.session_settings.shading.prop = NULL; - } -} - -bool wm_xr_events_handle(wmWindowManager *wm) -{ - if (wm->xr.runtime && wm->xr.runtime->context) { - return GHOST_XrEventsHandle(wm->xr.runtime->context); - } - return false; -} - -/** \} */ /* XR-Context */ - -/* -------------------------------------------------------------------- */ -/** \name XR Runtime Data - * - * \{ */ - -wmXrRuntimeData *wm_xr_runtime_data_create(void) -{ - wmXrRuntimeData *runtime = MEM_callocN(sizeof(*runtime), __func__); - return runtime; -} - -void wm_xr_runtime_data_free(wmXrRuntimeData **runtime) -{ - /* Note that this function may be called twice, because of an indirect recursion: If a session is - * running while WM-XR calls this function, calling GHOST_XrContextDestroy() will call this - * again, because it's also set as the session exit callback. So NULL-check and NULL everything - * that is freed here. */ - - /* We free all runtime XR data here, so if the context is still alive, destroy it. */ - if ((*runtime)->context != NULL) { - GHOST_XrContextHandle context = (*runtime)->context; - /* Prevent recursive GHOST_XrContextDestroy() call by NULL'ing the context pointer before the - * first call, see comment above. */ - (*runtime)->context = NULL; - GHOST_XrContextDestroy(context); - } - MEM_SAFE_FREE(*runtime); -} - -static void wm_xr_base_pose_calc(const Scene *scene, - const XrSessionSettings *settings, - GHOST_XrPose *r_base_pose) -{ - const Object *base_pose_object = ((settings->base_pose_type == XR_BASE_POSE_OBJECT) && - settings->base_pose_object) ? - settings->base_pose_object : - scene->camera; - - if (settings->base_pose_type == XR_BASE_POSE_CUSTOM) { - float tmp_quatx[4], tmp_quatz[4]; - - copy_v3_v3(r_base_pose->position, settings->base_pose_location); - axis_angle_to_quat_single(tmp_quatx, 'X', M_PI_2); - axis_angle_to_quat_single(tmp_quatz, 'Z', settings->base_pose_angle); - mul_qt_qtqt(r_base_pose->orientation_quat, tmp_quatz, tmp_quatx); - } - else if (base_pose_object) { - float tmp_quat[4]; - float tmp_eul[3]; - - mat4_to_loc_quat(r_base_pose->position, tmp_quat, base_pose_object->obmat); - - /* Only use rotation around Z-axis to align view with floor. */ - quat_to_eul(tmp_eul, tmp_quat); - tmp_eul[0] = M_PI_2; - tmp_eul[1] = 0; - eul_to_quat(r_base_pose->orientation_quat, tmp_eul); - } - else { - copy_v3_fl(r_base_pose->position, 0.0f); - axis_angle_to_quat_single(r_base_pose->orientation_quat, 'X', M_PI_2); - } -} - -static void wm_xr_draw_data_populate(const wmXrSessionState *state, - const GHOST_XrDrawViewInfo *draw_view, - const XrSessionSettings *settings, - const Scene *scene, - wmXrDrawData *r_draw_data) -{ - const bool position_tracking_toggled = ((state->prev_settings_flag & - XR_SESSION_USE_POSITION_TRACKING) != - (settings->flag & XR_SESSION_USE_POSITION_TRACKING)); - const bool use_position_tracking = settings->flag & XR_SESSION_USE_POSITION_TRACKING; - - memset(r_draw_data, 0, sizeof(*r_draw_data)); - - wm_xr_base_pose_calc(scene, settings, &r_draw_data->base_pose); - - /* Set the eye position offset, it's used to offset the base pose when changing positional - * tracking. */ - if (!state->is_view_data_set) { - /* Always use the exact base pose with no offset when starting the session. */ - copy_v3_fl(r_draw_data->eye_position_ofs, 0.0f); - } - else if (position_tracking_toggled) { - if (use_position_tracking) { - copy_v3_fl(r_draw_data->eye_position_ofs, 0.0f); - } - else { - /* Store the current local offset (local pose) so that we can apply that to the eyes. This - * way the eyes stay exactly where they are when disabling positional tracking. */ - copy_v3_v3(r_draw_data->eye_position_ofs, draw_view->local_pose.position); - } - } - else if (!use_position_tracking) { - /* Keep previous offset when positional tracking is disabled. */ - copy_v3_v3(r_draw_data->eye_position_ofs, state->prev_eye_position_ofs); - } -} - -/** - * Update information that is only stored for external state queries. E.g. for Python API to - * request the current (as in, last known) viewer pose. - */ -static void wm_xr_session_state_update(wmXrSessionState *state, - const GHOST_XrDrawViewInfo *draw_view, - const XrSessionSettings *settings, - const wmXrDrawData *draw_data) -{ - GHOST_XrPose viewer_pose; - const bool use_position_tracking = settings->flag & XR_SESSION_USE_POSITION_TRACKING; - - mul_qt_qtqt(viewer_pose.orientation_quat, - draw_data->base_pose.orientation_quat, - draw_view->local_pose.orientation_quat); - copy_v3_v3(viewer_pose.position, draw_data->base_pose.position); - /* The local pose and the eye pose (which is copied from an earlier local pose) both are view - * space, so Y-up. In this case we need them in regular Z-up. */ - viewer_pose.position[0] += draw_data->eye_position_ofs[0]; - viewer_pose.position[1] -= draw_data->eye_position_ofs[2]; - viewer_pose.position[2] += draw_data->eye_position_ofs[1]; - if (use_position_tracking) { - viewer_pose.position[0] += draw_view->local_pose.position[0]; - viewer_pose.position[1] -= draw_view->local_pose.position[2]; - viewer_pose.position[2] += draw_view->local_pose.position[1]; - } - - copy_v3_v3(state->viewer_pose.position, viewer_pose.position); - copy_qt_qt(state->viewer_pose.orientation_quat, viewer_pose.orientation_quat); - wm_xr_pose_to_viewmat(&viewer_pose, state->viewer_viewmat); - /* No idea why, but multiplying by two seems to make it match the VR view more. */ - state->focal_len = 2.0f * - fov_to_focallength(draw_view->fov.angle_right - draw_view->fov.angle_left, - DEFAULT_SENSOR_WIDTH); - - copy_v3_v3(state->prev_eye_position_ofs, draw_data->eye_position_ofs); - state->prev_settings_flag = settings->flag; - state->is_view_data_set = true; -} - -wmXrSessionState *WM_xr_session_state_handle_get(const wmXrData *xr) -{ - return xr->runtime ? &xr->runtime->session_state : NULL; -} - -bool WM_xr_session_state_viewer_pose_location_get(const wmXrData *xr, float r_location[3]) -{ - if (!WM_xr_session_is_ready(xr) || !xr->runtime->session_state.is_view_data_set) { - zero_v3(r_location); - return false; - } - - copy_v3_v3(r_location, xr->runtime->session_state.viewer_pose.position); - return true; -} - -bool WM_xr_session_state_viewer_pose_rotation_get(const wmXrData *xr, float r_rotation[4]) -{ - if (!WM_xr_session_is_ready(xr) || !xr->runtime->session_state.is_view_data_set) { - unit_qt(r_rotation); - return false; - } - - copy_v4_v4(r_rotation, xr->runtime->session_state.viewer_pose.orientation_quat); - return true; -} - -bool WM_xr_session_state_viewer_pose_matrix_info_get(const wmXrData *xr, - float r_viewmat[4][4], - float *r_focal_len) -{ - if (!WM_xr_session_is_ready(xr) || !xr->runtime->session_state.is_view_data_set) { - unit_m4(r_viewmat); - *r_focal_len = 0.0f; - return false; - } - - copy_m4_m4(r_viewmat, xr->runtime->session_state.viewer_viewmat); - *r_focal_len = xr->runtime->session_state.focal_len; - - return true; -} - -/** \} */ /* XR Runtime Data */ - -/* -------------------------------------------------------------------- */ -/** \name XR-Session - * - * \{ */ - -void *wm_xr_session_gpu_binding_context_create(GHOST_TXrGraphicsBinding graphics_binding) -{ - wmSurface *surface = wm_xr_session_surface_create(G_MAIN->wm.first, graphics_binding); - wmXrSurfaceData *data = surface->customdata; - - wm_surface_add(surface); - - /* Some regions may need to redraw with updated session state after the session is entirely up - * and running. */ - WM_main_add_notifier(NC_WM | ND_XR_DATA_CHANGED, NULL); - - return data->secondary_ghost_ctx ? data->secondary_ghost_ctx : surface->ghost_ctx; -} - -void wm_xr_session_gpu_binding_context_destroy(GHOST_TXrGraphicsBinding UNUSED(graphics_lib), - GHOST_ContextHandle UNUSED(context)) -{ - if (g_xr_surface) { /* Might have been freed already */ - wm_surface_remove(g_xr_surface); - } - - wm_window_reset_drawable(); - - /* Some regions may need to redraw with updated session state after the session is entirely - * stopped. */ - WM_main_add_notifier(NC_WM | ND_XR_DATA_CHANGED, NULL); -} - -static void wm_xr_session_exit_cb(void *customdata) -{ - wmXrData *xr_data = customdata; - - xr_data->runtime->session_state.is_started = false; - if (xr_data->runtime->exit_fn) { - xr_data->runtime->exit_fn(xr_data); - } - - /* Free the entire runtime data (including session state and context), to play safe. */ - wm_xr_runtime_data_free(&xr_data->runtime); -} - -static void wm_xr_session_begin_info_create(wmXrData *xr_data, - GHOST_XrSessionBeginInfo *r_begin_info) -{ - /* WM-XR exit function, does some own stuff and calls callback passed to wm_xr_session_toggle(), - * to allow external code to execute its own session-exit logic. */ - r_begin_info->exit_fn = wm_xr_session_exit_cb; - r_begin_info->exit_customdata = xr_data; -} - -void wm_xr_session_toggle(wmWindowManager *wm, wmXrSessionExitFn session_exit_fn) -{ - wmXrData *xr_data = &wm->xr; - - if (WM_xr_session_exists(xr_data)) { - GHOST_XrSessionEnd(xr_data->runtime->context); - } - else { - GHOST_XrSessionBeginInfo begin_info; - - xr_data->runtime->session_state.is_started = true; - xr_data->runtime->exit_fn = session_exit_fn; - - wm_xr_session_begin_info_create(xr_data, &begin_info); - GHOST_XrSessionStart(xr_data->runtime->context, &begin_info); - } -} - -/** - * Check if the XR-Session was triggered. - * If an error happened while trying to start a session, this returns false too. - */ -bool WM_xr_session_exists(const wmXrData *xr) -{ - return xr->runtime && xr->runtime->context && xr->runtime->session_state.is_started; -} - -/** - * Check if the session is running, according to the OpenXR definition. - */ -bool WM_xr_session_is_ready(const wmXrData *xr) -{ - return WM_xr_session_exists(xr) && GHOST_XrSessionIsRunning(xr->runtime->context); -} - -/** \} */ /* XR-Session */ - -/* -------------------------------------------------------------------- */ -/** \name XR-Session Surface - * - * A wmSurface is used to manage drawing of the VR viewport. It's created and destroyed with the - * session. - * - * \{ */ - -/** - * \brief Call Ghost-XR to draw a frame - * - * Draw callback for the XR-session surface. It's expected to be called on each main loop iteration - * and tells Ghost-XR to submit a new frame by drawing its views. Note that for drawing each view, - * #wm_xr_draw_view() will be called through Ghost-XR (see GHOST_XrDrawViewFunc()). - */ -static void wm_xr_session_surface_draw(bContext *C) -{ - wmXrSurfaceData *surface_data = g_xr_surface->customdata; - wmWindowManager *wm = CTX_wm_manager(C); - - if (!GHOST_XrSessionIsRunning(wm->xr.runtime->context)) { - return; - } - DRW_xr_drawing_begin(); - GHOST_XrSessionDrawViews(wm->xr.runtime->context, C); - GPU_offscreen_unbind(surface_data->offscreen, false); - DRW_xr_drawing_end(); -} - -static void wm_xr_session_free_data(wmSurface *surface) -{ - wmXrSurfaceData *data = surface->customdata; - - if (data->secondary_ghost_ctx) { -#ifdef WIN32 - if (data->gpu_binding_type == GHOST_kXrGraphicsD3D11) { - WM_directx_context_dispose(data->secondary_ghost_ctx); - } -#endif - } - if (data->viewport) { - GPU_viewport_free(data->viewport); - } - if (data->offscreen) { - GPU_offscreen_free(data->offscreen); - } - - MEM_freeN(surface->customdata); - - g_xr_surface = NULL; -} - -static bool wm_xr_session_surface_offscreen_ensure(const GHOST_XrDrawViewInfo *draw_view) -{ - wmXrSurfaceData *surface_data = g_xr_surface->customdata; - const bool size_changed = surface_data->offscreen && - (GPU_offscreen_width(surface_data->offscreen) != draw_view->width) && - (GPU_offscreen_height(surface_data->offscreen) != draw_view->height); - char err_out[256] = "unknown"; - bool failure = false; - - if (surface_data->offscreen) { - BLI_assert(surface_data->viewport); - - if (!size_changed) { - return true; - } - GPU_viewport_free(surface_data->viewport); - GPU_offscreen_free(surface_data->offscreen); - } - - if (!(surface_data->offscreen = GPU_offscreen_create( - draw_view->width, draw_view->height, 0, true, false, err_out))) { - failure = true; - } - - if (failure) { - /* Pass. */ - } - else if (!(surface_data->viewport = GPU_viewport_create())) { - GPU_offscreen_free(surface_data->offscreen); - failure = true; - } - - if (failure) { - CLOG_ERROR(&LOG, "Failed to get buffer, %s\n", err_out); - return false; - } - - return true; -} - -wmSurface *wm_xr_session_surface_create(wmWindowManager *UNUSED(wm), unsigned int gpu_binding_type) -{ - if (g_xr_surface) { - BLI_assert(false); - return g_xr_surface; - } - - wmSurface *surface = MEM_callocN(sizeof(*surface), __func__); - wmXrSurfaceData *data = MEM_callocN(sizeof(*data), "XrSurfaceData"); - -#ifndef WIN32 - BLI_assert(gpu_binding_type == GHOST_kXrGraphicsOpenGL); -#endif - - surface->draw = wm_xr_session_surface_draw; - surface->free_data = wm_xr_session_free_data; - - data->gpu_binding_type = gpu_binding_type; - surface->customdata = data; - - surface->ghost_ctx = DRW_xr_opengl_context_get(); - - switch (gpu_binding_type) { - case GHOST_kXrGraphicsOpenGL: - break; -#ifdef WIN32 - case GHOST_kXrGraphicsD3D11: - data->secondary_ghost_ctx = WM_directx_context_create(); - break; -#endif - } - - surface->gpu_ctx = DRW_xr_gpu_context_get(); - - g_xr_surface = surface; - - return surface; -} - -/** \} */ /* XR-Session Surface */ - -/* -------------------------------------------------------------------- */ -/** \name XR Drawing - * - * \{ */ - -void wm_xr_pose_to_viewmat(const GHOST_XrPose *pose, float r_viewmat[4][4]) -{ - float iquat[4]; - invert_qt_qt_normalized(iquat, pose->orientation_quat); - quat_to_mat4(r_viewmat, iquat); - translate_m4(r_viewmat, -pose->position[0], -pose->position[1], -pose->position[2]); -} - -static void wm_xr_draw_matrices_create(const wmXrDrawData *draw_data, - const GHOST_XrDrawViewInfo *draw_view, - const XrSessionSettings *session_settings, - float r_view_mat[4][4], - float r_proj_mat[4][4]) -{ - GHOST_XrPose eye_pose; - - copy_qt_qt(eye_pose.orientation_quat, draw_view->eye_pose.orientation_quat); - copy_v3_v3(eye_pose.position, draw_view->eye_pose.position); - add_v3_v3(eye_pose.position, draw_data->eye_position_ofs); - if ((session_settings->flag & XR_SESSION_USE_POSITION_TRACKING) == 0) { - sub_v3_v3(eye_pose.position, draw_view->local_pose.position); - } - - perspective_m4_fov(r_proj_mat, - draw_view->fov.angle_left, - draw_view->fov.angle_right, - draw_view->fov.angle_up, - draw_view->fov.angle_down, - session_settings->clip_start, - session_settings->clip_end); - - float eye_mat[4][4]; - float base_mat[4][4]; - - wm_xr_pose_to_viewmat(&eye_pose, eye_mat); - /* Calculate the base pose matrix (in world space!). */ - wm_xr_pose_to_viewmat(&draw_data->base_pose, base_mat); - - mul_m4_m4m4(r_view_mat, eye_mat, base_mat); -} - -static void wm_xr_draw_viewport_buffers_to_active_framebuffer( - const wmXrSurfaceData *surface_data, const GHOST_XrDrawViewInfo *draw_view) -{ - const bool is_upside_down = surface_data->secondary_ghost_ctx && - GHOST_isUpsideDownContext(surface_data->secondary_ghost_ctx); - rcti rect = {.xmin = 0, .ymin = 0, .xmax = draw_view->width - 1, .ymax = draw_view->height - 1}; - - wmViewport(&rect); - - /* For upside down contexts, draw with inverted y-values. */ - if (is_upside_down) { - SWAP(int, rect.ymin, rect.ymax); - } - GPU_viewport_draw_to_screen_ex(surface_data->viewport, 0, &rect, draw_view->expects_srgb_buffer); -} - -/** - * \brief Draw a viewport for a single eye. - * - * This is the main viewport drawing function for VR sessions. It's assigned to Ghost-XR as a - * callback (see GHOST_XrDrawViewFunc()) and executed for each view (read: eye). - */ -void wm_xr_draw_view(const GHOST_XrDrawViewInfo *draw_view, void *customdata) -{ - bContext *C = customdata; - wmWindowManager *wm = CTX_wm_manager(C); - wmXrSurfaceData *surface_data = g_xr_surface->customdata; - wmXrSessionState *session_state = &wm->xr.runtime->session_state; - XrSessionSettings *settings = &wm->xr.session_settings; - wmXrDrawData draw_data; - Scene *scene = CTX_data_scene(C); - - const int display_flags = V3D_OFSDRAW_OVERRIDE_SCENE_SETTINGS | settings->draw_flags; - - float viewmat[4][4], winmat[4][4]; - - BLI_assert(WM_xr_session_is_ready(&wm->xr)); - - wm_xr_draw_data_populate(session_state, draw_view, settings, scene, &draw_data); - wm_xr_draw_matrices_create(&draw_data, draw_view, settings, viewmat, winmat); - wm_xr_session_state_update(session_state, draw_view, settings, &draw_data); - - if (!wm_xr_session_surface_offscreen_ensure(draw_view)) { - return; - } - - /* In case a framebuffer is still bound from drawing the last eye. */ - GPU_framebuffer_restore(); - /* Some systems have drawing glitches without this. */ - GPU_clear(GPU_DEPTH_BIT); - - /* Draws the view into the surface_data->viewport's framebuffers */ - ED_view3d_draw_offscreen_simple(CTX_data_ensure_evaluated_depsgraph(C), - scene, - &wm->xr.session_settings.shading, - wm->xr.session_settings.shading.type, - draw_view->width, - draw_view->height, - display_flags, - viewmat, - winmat, - settings->clip_start, - settings->clip_end, - false, - true, - true, - NULL, - false, - surface_data->offscreen, - surface_data->viewport); - - /* The draw-manager uses both GPUOffscreen and GPUViewport to manage frame and texture buffers. A - * call to GPU_viewport_draw_to_screen() is still needed to get the final result from the - * viewport buffers composited together and potentially color managed for display on screen. - * It needs a bound frame-buffer to draw into, for which we simply reuse the GPUOffscreen one. - * - * In a next step, Ghost-XR will use the the currently bound frame-buffer to retrieve the image - * to be submitted to the OpenXR swap-chain. So do not un-bind the offscreen yet! */ - - GPU_offscreen_bind(surface_data->offscreen, false); - - wm_xr_draw_viewport_buffers_to_active_framebuffer(surface_data, draw_view); -} - -/** \} */ /* XR Drawing */ diff --git a/source/blender/windowmanager/message_bus/intern/wm_message_bus.c b/source/blender/windowmanager/message_bus/intern/wm_message_bus.c index fd5237a70a5..86a106462c3 100644 --- a/source/blender/windowmanager/message_bus/intern/wm_message_bus.c +++ b/source/blender/windowmanager/message_bus/intern/wm_message_bus.c @@ -111,7 +111,7 @@ void WM_msgbus_clear_by_owner(struct wmMsgBus *mbus, void *owner) void WM_msg_dump(struct wmMsgBus *mbus, const char *info_str) { printf(">>>> %s\n", info_str); - for (wmMsgSubscribeKey *key = mbus->messages.first; key; key = key->next) { + LISTBASE_FOREACH (wmMsgSubscribeKey *, key, &mbus->messages) { const wmMsg *msg = wm_msg_subscribe_value_msg_cast(key); const wmMsgTypeInfo *info = &wm_msg_types[msg->type]; info->repr(stdout, key); @@ -131,8 +131,8 @@ void WM_msgbus_handle(struct wmMsgBus *mbus, struct bContext *C) } // uint a = 0, b = 0; - for (wmMsgSubscribeKey *key = mbus->messages.first; key; key = key->next) { - for (wmMsgSubscribeValueLink *msg_lnk = key->values.first; msg_lnk; msg_lnk = msg_lnk->next) { + LISTBASE_FOREACH (wmMsgSubscribeKey *, key, &mbus->messages) { + LISTBASE_FOREACH (wmMsgSubscribeValueLink *, msg_lnk, &key->values) { if (msg_lnk->params.tag) { msg_lnk->params.notify(C, key, &msg_lnk->params); msg_lnk->params.tag = false; @@ -175,7 +175,7 @@ wmMsgSubscribeKey *WM_msg_subscribe_with_key(struct wmMsgBus *mbus, } else { key = *r_key; - for (wmMsgSubscribeValueLink *msg_lnk = key->values.first; msg_lnk; msg_lnk = msg_lnk->next) { + LISTBASE_FOREACH (wmMsgSubscribeValueLink *, msg_lnk, &key->values) { if ((msg_lnk->params.notify == msg_val_params->notify) && (msg_lnk->params.owner == msg_val_params->owner) && (msg_lnk->params.user_data == msg_val_params->user_data)) { @@ -198,8 +198,7 @@ void WM_msg_publish_with_key(struct wmMsgBus *mbus, wmMsgSubscribeKey *msg_key) msg_key, BLI_listbase_count(&msg_key->values)); - for (wmMsgSubscribeValueLink *msg_lnk = msg_key->values.first; msg_lnk; - msg_lnk = msg_lnk->next) { + LISTBASE_FOREACH (wmMsgSubscribeValueLink *, msg_lnk, &msg_key->values) { if (false) { /* make an option? */ msg_lnk->params.notify(NULL, msg_key, &msg_lnk->params); } diff --git a/source/blender/windowmanager/wm.h b/source/blender/windowmanager/wm.h index 97403a0315a..16aa5cb44db 100644 --- a/source/blender/windowmanager/wm.h +++ b/source/blender/windowmanager/wm.h @@ -80,6 +80,7 @@ void wm_autosave_location(char *filepath); /* wm_splash_screen.c */ void WM_OT_splash(wmOperatorType *ot); +void WM_OT_splash_about(wmOperatorType *ot); /* wm_stereo.c */ void wm_stereo3d_draw_sidebyside(wmWindow *win, int view); @@ -96,14 +97,4 @@ void wm_stereo3d_set_cancel(bContext *C, wmOperator *op); void wm_open_init_load_ui(wmOperator *op, bool use_prefs); void wm_open_init_use_scripts(wmOperator *op, bool use_prefs); -#ifdef WITH_XR_OPENXR -typedef void (*wmXrSessionExitFn)(const wmXrData *xr_data); - -/* wm_xr.c */ -bool wm_xr_init(wmWindowManager *wm); -void wm_xr_exit(wmWindowManager *wm); -void wm_xr_session_toggle(wmWindowManager *wm, wmXrSessionExitFn session_exit_fn); -bool wm_xr_events_handle(wmWindowManager *wm); #endif - -#endif /* __WM_H__ */ diff --git a/source/blender/windowmanager/wm_draw.h b/source/blender/windowmanager/wm_draw.h index b19fdf97569..ff2fc25333a 100644 --- a/source/blender/windowmanager/wm_draw.h +++ b/source/blender/windowmanager/wm_draw.h @@ -46,7 +46,7 @@ struct wmWindow; void wm_draw_update(struct bContext *C); void wm_draw_region_clear(struct wmWindow *win, struct ARegion *region); void wm_draw_region_blend(struct ARegion *region, int view, bool blend); -void wm_draw_region_test(struct bContext *C, struct ScrArea *sa, struct ARegion *region); +void wm_draw_region_test(struct bContext *C, struct ScrArea *area, struct ARegion *region); struct GPUTexture *wm_draw_region_texture(struct ARegion *region, int view); diff --git a/source/blender/windowmanager/wm_event_system.h b/source/blender/windowmanager/wm_event_system.h index 95d3820cf96..b837cafd30a 100644 --- a/source/blender/windowmanager/wm_event_system.h +++ b/source/blender/windowmanager/wm_event_system.h @@ -149,6 +149,11 @@ void wm_event_do_depsgraph(bContext *C, bool is_after_open_file); void wm_event_do_refresh_wm_and_depsgraph(bContext *C); void wm_event_do_notifiers(bContext *C); +void wm_event_handler_ui_cancel_ex(bContext *C, + wmWindow *win, + ARegion *region, + bool reactivate_button); + /* wm_event_query.c */ float wm_pressure_curve(float raw_pressure); void wm_tablet_data_from_ghost(const struct GHOST_TabletData *tablet_data, wmTabletData *wmtab); diff --git a/source/blender/windowmanager/wm_event_types.h b/source/blender/windowmanager/wm_event_types.h index f16056cc91e..ffed86abfe7 100644 --- a/source/blender/windowmanager/wm_event_types.h +++ b/source/blender/windowmanager/wm_event_types.h @@ -333,6 +333,7 @@ enum { EVT_BUT_OPEN = 0x5021, /* 20513 */ EVT_MODAL_MAP = 0x5022, /* 20514 */ EVT_DROP = 0x5023, /* 20515 */ + /* When value is 0, re-activate, when 1, don't re-activate the button under the cursor. */ EVT_BUT_CANCEL = 0x5024, /* 20516 */ /* could become gizmo callback */ diff --git a/source/blender/windowmanager/wm_files.h b/source/blender/windowmanager/wm_files.h index e081742b904..42eab35cdb9 100644 --- a/source/blender/windowmanager/wm_files.h +++ b/source/blender/windowmanager/wm_files.h @@ -45,8 +45,6 @@ void wm_close_file_dialog(bContext *C, struct wmGenericCallback *post_action); bool wm_file_or_image_is_modified(const Main *bmain, const wmWindowManager *wm); void WM_OT_save_homefile(struct wmOperatorType *ot); -void WM_OT_userpref_autoexec_path_add(struct wmOperatorType *ot); -void WM_OT_userpref_autoexec_path_remove(struct wmOperatorType *ot); void WM_OT_save_userpref(struct wmOperatorType *ot); void WM_OT_read_userpref(struct wmOperatorType *ot); void WM_OT_read_factory_userpref(struct wmOperatorType *ot); diff --git a/source/blender/windowmanager/wm_surface.h b/source/blender/windowmanager/wm_surface.h index 98d67c55619..e1b00ae1ade 100644 --- a/source/blender/windowmanager/wm_surface.h +++ b/source/blender/windowmanager/wm_surface.h @@ -46,7 +46,7 @@ void wm_surface_remove(wmSurface *surface); void wm_surfaces_free(void); /* Utils */ -void wm_surfaces_iter(struct bContext *C, void (*cb)(bContext *, wmSurface *)); +void wm_surfaces_iter(struct bContext *C, void (*cb)(struct bContext *, wmSurface *)); /* Drawing */ void wm_surface_make_drawable(wmSurface *surface); diff --git a/source/blender/windowmanager/wm_window.h b/source/blender/windowmanager/wm_window.h index ce9d79b8e59..5ca5711b4f2 100644 --- a/source/blender/windowmanager/wm_window.h +++ b/source/blender/windowmanager/wm_window.h @@ -33,7 +33,10 @@ void wm_ghost_exit(void); void wm_get_screensize(int *r_width, int *r_height); void wm_get_desktopsize(int *r_width, int *r_height); -wmWindow *wm_window_new(const struct Main *bmain, wmWindowManager *wm, wmWindow *parent); +wmWindow *wm_window_new(const struct Main *bmain, + wmWindowManager *wm, + wmWindow *parent, + bool dialog); wmWindow *wm_window_copy(struct Main *bmain, wmWindowManager *wm, wmWindow *win_src, @@ -82,11 +85,4 @@ int wm_window_new_main_exec(bContext *C, struct wmOperator *op); void wm_test_autorun_warning(bContext *C); -/* Initial (unmaximized) size to start with for - * systems that can't find it for themselves (X11). - * Clamped by real desktop limits */ -#define WM_WIN_INIT_SIZE_X 1800 -#define WM_WIN_INIT_SIZE_Y 1000 -#define WM_WIN_INIT_PAD 40 - #endif /* __WM_WINDOW_H__ */ diff --git a/source/blender/windowmanager/xr/intern/wm_xr.c b/source/blender/windowmanager/xr/intern/wm_xr.c new file mode 100644 index 00000000000..90f30809136 --- /dev/null +++ b/source/blender/windowmanager/xr/intern/wm_xr.c @@ -0,0 +1,168 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup wm + * + * All XR functionality is accessed through a #GHOST_XrContext handle. + * The lifetime of this context also determines the lifetime of the OpenXR instance, which is the + * representation of the OpenXR runtime connection within the application. + */ + +#include "BKE_global.h" +#include "BKE_idprop.h" +#include "BKE_report.h" + +#include "DNA_scene_types.h" +#include "DNA_windowmanager_types.h" + +#include "DEG_depsgraph.h" + +#include "MEM_guardedalloc.h" + +#include "GHOST_C-api.h" + +#include "WM_api.h" + +#include "wm_surface.h" +#include "wm_xr_intern.h" + +typedef struct { + wmWindowManager *wm; +} wmXrErrorHandlerData; + +/* -------------------------------------------------------------------- */ + +static void wm_xr_error_handler(const GHOST_XrError *error) +{ + wmXrErrorHandlerData *handler_data = error->customdata; + wmWindowManager *wm = handler_data->wm; + + BKE_reports_clear(&wm->reports); + WM_report(RPT_ERROR, error->user_message); + WM_report_banner_show(); + + if (wm->xr.runtime) { + /* Just play safe and destroy the entire runtime data, including context. */ + wm_xr_runtime_data_free(&wm->xr.runtime); + } +} + +bool wm_xr_init(wmWindowManager *wm) +{ + if (wm->xr.runtime && wm->xr.runtime->context) { + return true; + } + static wmXrErrorHandlerData error_customdata; + + /* Set up error handling */ + error_customdata.wm = wm; + GHOST_XrErrorHandler(wm_xr_error_handler, &error_customdata); + + { + const GHOST_TXrGraphicsBinding gpu_bindings_candidates[] = { + GHOST_kXrGraphicsOpenGL, +#ifdef WIN32 + GHOST_kXrGraphicsD3D11, +#endif + }; + GHOST_XrContextCreateInfo create_info = { + .gpu_binding_candidates = gpu_bindings_candidates, + .gpu_binding_candidates_count = ARRAY_SIZE(gpu_bindings_candidates), + }; + GHOST_XrContextHandle context; + + if (G.debug & G_DEBUG_XR) { + create_info.context_flag |= GHOST_kXrContextDebug; + } + if (G.debug & G_DEBUG_XR_TIME) { + create_info.context_flag |= GHOST_kXrContextDebugTime; + } + + if (!(context = GHOST_XrContextCreate(&create_info))) { + return false; + } + + /* Set up context callbacks */ + GHOST_XrGraphicsContextBindFuncs(context, + wm_xr_session_gpu_binding_context_create, + wm_xr_session_gpu_binding_context_destroy); + GHOST_XrDrawViewFunc(context, wm_xr_draw_view); + + if (!wm->xr.runtime) { + wm->xr.runtime = wm_xr_runtime_data_create(); + wm->xr.runtime->context = context; + } + } + BLI_assert(wm->xr.runtime && wm->xr.runtime->context); + + return true; +} + +void wm_xr_exit(wmWindowManager *wm) +{ + if (wm->xr.runtime != NULL) { + wm_xr_runtime_data_free(&wm->xr.runtime); + } + if (wm->xr.session_settings.shading.prop) { + IDP_FreeProperty(wm->xr.session_settings.shading.prop); + wm->xr.session_settings.shading.prop = NULL; + } +} + +bool wm_xr_events_handle(wmWindowManager *wm) +{ + if (wm->xr.runtime && wm->xr.runtime->context) { + GHOST_XrEventsHandle(wm->xr.runtime->context); + + /* wm_window_process_events() uses the return value to determine if it can put the main thread + * to sleep for some milliseconds. We never want that to happen while the VR session runs on + * the main thread. So always return true. */ + return true; + } + return false; +} + +/* -------------------------------------------------------------------- */ +/** \name XR Runtime Data + * + * \{ */ + +wmXrRuntimeData *wm_xr_runtime_data_create(void) +{ + wmXrRuntimeData *runtime = MEM_callocN(sizeof(*runtime), __func__); + return runtime; +} + +void wm_xr_runtime_data_free(wmXrRuntimeData **runtime) +{ + /* Note that this function may be called twice, because of an indirect recursion: If a session is + * running while WM-XR calls this function, calling GHOST_XrContextDestroy() will call this + * again, because it's also set as the session exit callback. So NULL-check and NULL everything + * that is freed here. */ + + /* We free all runtime XR data here, so if the context is still alive, destroy it. */ + if ((*runtime)->context != NULL) { + GHOST_XrContextHandle context = (*runtime)->context; + /* Prevent recursive GHOST_XrContextDestroy() call by NULL'ing the context pointer before the + * first call, see comment above. */ + (*runtime)->context = NULL; + GHOST_XrContextDestroy(context); + } + MEM_SAFE_FREE(*runtime); +} + +/** \} */ /* XR Runtime Data */ diff --git a/source/blender/windowmanager/xr/intern/wm_xr_draw.c b/source/blender/windowmanager/xr/intern/wm_xr_draw.c new file mode 100644 index 00000000000..684e59eb8b2 --- /dev/null +++ b/source/blender/windowmanager/xr/intern/wm_xr_draw.c @@ -0,0 +1,162 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup wm + * + * \name Window-Manager XR Drawing + * + * Implements Blender specific drawing functionality for use with the Ghost-XR API. + */ + +#include <string.h> + +#include "BLI_math.h" + +#include "ED_view3d_offscreen.h" + +#include "GHOST_C-api.h" + +#include "GPU_viewport.h" + +#include "WM_api.h" + +#include "wm_surface.h" +#include "wm_xr_intern.h" + +void wm_xr_pose_to_viewmat(const GHOST_XrPose *pose, float r_viewmat[4][4]) +{ + float iquat[4]; + invert_qt_qt_normalized(iquat, pose->orientation_quat); + quat_to_mat4(r_viewmat, iquat); + translate_m4(r_viewmat, -pose->position[0], -pose->position[1], -pose->position[2]); +} + +static void wm_xr_draw_matrices_create(const wmXrDrawData *draw_data, + const GHOST_XrDrawViewInfo *draw_view, + const XrSessionSettings *session_settings, + float r_view_mat[4][4], + float r_proj_mat[4][4]) +{ + GHOST_XrPose eye_pose; + + copy_qt_qt(eye_pose.orientation_quat, draw_view->eye_pose.orientation_quat); + copy_v3_v3(eye_pose.position, draw_view->eye_pose.position); + add_v3_v3(eye_pose.position, draw_data->eye_position_ofs); + if ((session_settings->flag & XR_SESSION_USE_POSITION_TRACKING) == 0) { + sub_v3_v3(eye_pose.position, draw_view->local_pose.position); + } + + perspective_m4_fov(r_proj_mat, + draw_view->fov.angle_left, + draw_view->fov.angle_right, + draw_view->fov.angle_up, + draw_view->fov.angle_down, + session_settings->clip_start, + session_settings->clip_end); + + float eye_mat[4][4]; + float base_mat[4][4]; + + wm_xr_pose_to_viewmat(&eye_pose, eye_mat); + /* Calculate the base pose matrix (in world space!). */ + wm_xr_pose_to_viewmat(&draw_data->base_pose, base_mat); + + mul_m4_m4m4(r_view_mat, eye_mat, base_mat); +} + +static void wm_xr_draw_viewport_buffers_to_active_framebuffer( + const wmXrRuntimeData *runtime_data, + const wmXrSurfaceData *surface_data, + const GHOST_XrDrawViewInfo *draw_view) +{ + const bool is_upside_down = GHOST_XrSessionNeedsUpsideDownDrawing(runtime_data->context); + rcti rect = {.xmin = 0, .ymin = 0, .xmax = draw_view->width - 1, .ymax = draw_view->height - 1}; + + wmViewport(&rect); + + /* For upside down contexts, draw with inverted y-values. */ + if (is_upside_down) { + SWAP(int, rect.ymin, rect.ymax); + } + GPU_viewport_draw_to_screen_ex(surface_data->viewport, 0, &rect, draw_view->expects_srgb_buffer); +} + +/** + * \brief Draw a viewport for a single eye. + * + * This is the main viewport drawing function for VR sessions. It's assigned to Ghost-XR as a + * callback (see GHOST_XrDrawViewFunc()) and executed for each view (read: eye). + */ +void wm_xr_draw_view(const GHOST_XrDrawViewInfo *draw_view, void *customdata) +{ + wmXrDrawData *draw_data = customdata; + wmXrData *xr_data = draw_data->xr_data; + wmXrSurfaceData *surface_data = draw_data->surface_data; + wmXrSessionState *session_state = &xr_data->runtime->session_state; + XrSessionSettings *settings = &xr_data->session_settings; + + const int display_flags = V3D_OFSDRAW_OVERRIDE_SCENE_SETTINGS | settings->draw_flags; + + float viewmat[4][4], winmat[4][4]; + + BLI_assert(WM_xr_session_is_ready(xr_data)); + + wm_xr_session_draw_data_update(session_state, settings, draw_view, draw_data); + wm_xr_draw_matrices_create(draw_data, draw_view, settings, viewmat, winmat); + wm_xr_session_state_update(settings, draw_data, draw_view, session_state); + + if (!wm_xr_session_surface_offscreen_ensure(surface_data, draw_view)) { + return; + } + + /* In case a framebuffer is still bound from drawing the last eye. */ + GPU_framebuffer_restore(); + /* Some systems have drawing glitches without this. */ + GPU_clear(GPU_DEPTH_BIT); + + /* Draws the view into the surface_data->viewport's framebuffers */ + ED_view3d_draw_offscreen_simple(draw_data->depsgraph, + draw_data->scene, + &settings->shading, + settings->shading.type, + draw_view->width, + draw_view->height, + display_flags, + viewmat, + winmat, + settings->clip_start, + settings->clip_end, + false, + true, + true, + NULL, + false, + surface_data->offscreen, + surface_data->viewport); + + /* The draw-manager uses both GPUOffscreen and GPUViewport to manage frame and texture buffers. A + * call to GPU_viewport_draw_to_screen() is still needed to get the final result from the + * viewport buffers composited together and potentially color managed for display on screen. + * It needs a bound frame-buffer to draw into, for which we simply reuse the GPUOffscreen one. + * + * In a next step, Ghost-XR will use the currently bound frame-buffer to retrieve the image + * to be submitted to the OpenXR swap-chain. So do not un-bind the off-screen yet! */ + + GPU_offscreen_bind(surface_data->offscreen, false); + + wm_xr_draw_viewport_buffers_to_active_framebuffer(xr_data->runtime, surface_data, draw_view); +} diff --git a/source/blender/windowmanager/xr/intern/wm_xr_intern.h b/source/blender/windowmanager/xr/intern/wm_xr_intern.h new file mode 100644 index 00000000000..9b7e9a15948 --- /dev/null +++ b/source/blender/windowmanager/xr/intern/wm_xr_intern.h @@ -0,0 +1,96 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup wm + */ + +#ifndef __WM_XR_INTERN_H__ +#define __WM_XR_INTERN_H__ + +#include "CLG_log.h" + +#include "wm_xr.h" + +typedef struct wmXrSessionState { + bool is_started; + + /** Last known viewer pose (centroid of eyes, in world space) stored for queries. */ + GHOST_XrPose viewer_pose; + /** The last known view matrix, calculated from above's viewer pose. */ + float viewer_viewmat[4][4]; + float focal_len; + + /** Copy of XrSessionSettings.base_pose_ data to detect changes that need + * resetting to base pose. */ + char prev_base_pose_type; /* eXRSessionBasePoseType */ + Object *prev_base_pose_object; + /** Copy of XrSessionSettings.flag created on the last draw call, stored to detect changes. */ + int prev_settings_flag; + /** Copy of wmXrDrawData.eye_position_ofs. */ + float prev_eye_position_ofs[3]; + + bool force_reset_to_base_pose; + bool is_view_data_set; +} wmXrSessionState; + +typedef struct wmXrRuntimeData { + GHOST_XrContextHandle context; + + /* Although this struct is internal, RNA gets a handle to this for state information queries. */ + wmXrSessionState session_state; + wmXrSessionExitFn exit_fn; +} wmXrRuntimeData; + +typedef struct { + struct GPUOffScreen *offscreen; + struct GPUViewport *viewport; +} wmXrSurfaceData; + +typedef struct wmXrDrawData { + struct Scene *scene; + struct Depsgraph *depsgraph; + + wmXrData *xr_data; + wmXrSurfaceData *surface_data; + + /** The pose (location + rotation) to which eye deltas will be applied to when drawing (world + * space). With positional tracking enabled, it should be the same as the base pose, when + * disabled it also contains a location delta from the moment the option was toggled. */ + GHOST_XrPose base_pose; + float eye_position_ofs[3]; /* Local/view space. */ +} wmXrDrawData; + +wmXrRuntimeData *wm_xr_runtime_data_create(void); +void wm_xr_runtime_data_free(wmXrRuntimeData **runtime); + +void wm_xr_session_draw_data_update(const wmXrSessionState *state, + const XrSessionSettings *settings, + const GHOST_XrDrawViewInfo *draw_view, + wmXrDrawData *draw_data); +void wm_xr_session_state_update(const XrSessionSettings *settings, + const wmXrDrawData *draw_data, + const GHOST_XrDrawViewInfo *draw_view, + wmXrSessionState *state); +bool wm_xr_session_surface_offscreen_ensure(wmXrSurfaceData *surface_data, + const GHOST_XrDrawViewInfo *draw_view); +void *wm_xr_session_gpu_binding_context_create(void); +void wm_xr_session_gpu_binding_context_destroy(GHOST_ContextHandle context); + +void wm_xr_pose_to_viewmat(const GHOST_XrPose *pose, float r_viewmat[4][4]); +void wm_xr_draw_view(const GHOST_XrDrawViewInfo *draw_view, void *customdata); + +#endif diff --git a/source/blender/windowmanager/xr/intern/wm_xr_session.c b/source/blender/windowmanager/xr/intern/wm_xr_session.c new file mode 100644 index 00000000000..e9ff38c5a92 --- /dev/null +++ b/source/blender/windowmanager/xr/intern/wm_xr_session.c @@ -0,0 +1,430 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup wm + */ + +#include "BKE_context.h" + +#include "BLI_math.h" + +#include "DEG_depsgraph.h" + +#include "DNA_camera_types.h" + +#include "DRW_engine.h" + +#include "GHOST_C-api.h" + +#include "GPU_viewport.h" + +#include "MEM_guardedalloc.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "wm_surface.h" +#include "wm_window.h" +#include "wm_xr_intern.h" + +wmSurface *g_xr_surface = NULL; +CLG_LogRef LOG = {"wm.xr"}; + +/* -------------------------------------------------------------------- */ + +static void wm_xr_session_exit_cb(void *customdata) +{ + wmXrData *xr_data = customdata; + + xr_data->runtime->session_state.is_started = false; + if (xr_data->runtime->exit_fn) { + xr_data->runtime->exit_fn(xr_data); + } + + /* Free the entire runtime data (including session state and context), to play safe. */ + wm_xr_runtime_data_free(&xr_data->runtime); +} + +static void wm_xr_session_begin_info_create(wmXrData *xr_data, + GHOST_XrSessionBeginInfo *r_begin_info) +{ + /* WM-XR exit function, does some own stuff and calls callback passed to wm_xr_session_toggle(), + * to allow external code to execute its own session-exit logic. */ + r_begin_info->exit_fn = wm_xr_session_exit_cb; + r_begin_info->exit_customdata = xr_data; +} + +void wm_xr_session_toggle(wmWindowManager *wm, wmXrSessionExitFn session_exit_fn) +{ + wmXrData *xr_data = &wm->xr; + + if (WM_xr_session_exists(xr_data)) { + GHOST_XrSessionEnd(xr_data->runtime->context); + } + else { + GHOST_XrSessionBeginInfo begin_info; + + xr_data->runtime->session_state.is_started = true; + xr_data->runtime->exit_fn = session_exit_fn; + + wm_xr_session_begin_info_create(xr_data, &begin_info); + GHOST_XrSessionStart(xr_data->runtime->context, &begin_info); + } +} + +/** + * Check if the XR-Session was triggered. + * If an error happened while trying to start a session, this returns false too. + */ +bool WM_xr_session_exists(const wmXrData *xr) +{ + return xr->runtime && xr->runtime->context && xr->runtime->session_state.is_started; +} + +void WM_xr_session_base_pose_reset(wmXrData *xr) +{ + xr->runtime->session_state.force_reset_to_base_pose = true; +} + +/** + * Check if the session is running, according to the OpenXR definition. + */ +bool WM_xr_session_is_ready(const wmXrData *xr) +{ + return WM_xr_session_exists(xr) && GHOST_XrSessionIsRunning(xr->runtime->context); +} + +static void wm_xr_session_base_pose_calc(const Scene *scene, + const XrSessionSettings *settings, + GHOST_XrPose *r_base_pose) +{ + const Object *base_pose_object = ((settings->base_pose_type == XR_BASE_POSE_OBJECT) && + settings->base_pose_object) ? + settings->base_pose_object : + scene->camera; + + if (settings->base_pose_type == XR_BASE_POSE_CUSTOM) { + float tmp_quatx[4], tmp_quatz[4]; + + copy_v3_v3(r_base_pose->position, settings->base_pose_location); + axis_angle_to_quat_single(tmp_quatx, 'X', M_PI_2); + axis_angle_to_quat_single(tmp_quatz, 'Z', settings->base_pose_angle); + mul_qt_qtqt(r_base_pose->orientation_quat, tmp_quatz, tmp_quatx); + } + else if (base_pose_object) { + float tmp_quat[4]; + float tmp_eul[3]; + + mat4_to_loc_quat(r_base_pose->position, tmp_quat, base_pose_object->obmat); + + /* Only use rotation around Z-axis to align view with floor. */ + quat_to_eul(tmp_eul, tmp_quat); + tmp_eul[0] = M_PI_2; + tmp_eul[1] = 0; + eul_to_quat(r_base_pose->orientation_quat, tmp_eul); + } + else { + copy_v3_fl(r_base_pose->position, 0.0f); + axis_angle_to_quat_single(r_base_pose->orientation_quat, 'X', M_PI_2); + } +} + +static void wm_xr_session_draw_data_populate(wmXrData *xr_data, + Scene *scene, + Depsgraph *depsgraph, + wmXrDrawData *r_draw_data) +{ + const XrSessionSettings *settings = &xr_data->session_settings; + + memset(r_draw_data, 0, sizeof(*r_draw_data)); + r_draw_data->scene = scene; + r_draw_data->depsgraph = depsgraph; + r_draw_data->xr_data = xr_data; + r_draw_data->surface_data = g_xr_surface->customdata; + + wm_xr_session_base_pose_calc(r_draw_data->scene, settings, &r_draw_data->base_pose); +} + +static bool wm_xr_session_draw_data_needs_reset_to_base_pose(const wmXrSessionState *state, + const XrSessionSettings *settings) +{ + if (state->force_reset_to_base_pose) { + return true; + } + return ((settings->flag & XR_SESSION_USE_POSITION_TRACKING) == 0) && + ((state->prev_base_pose_type != settings->base_pose_type) || + (state->prev_base_pose_object != settings->base_pose_object)); +} + +void wm_xr_session_draw_data_update(const wmXrSessionState *state, + const XrSessionSettings *settings, + const GHOST_XrDrawViewInfo *draw_view, + wmXrDrawData *draw_data) +{ + const bool position_tracking_toggled = ((state->prev_settings_flag & + XR_SESSION_USE_POSITION_TRACKING) != + (settings->flag & XR_SESSION_USE_POSITION_TRACKING)); + const bool use_position_tracking = settings->flag & XR_SESSION_USE_POSITION_TRACKING; + + /* Set the eye position offset, it's used to offset the base pose when changing positional + * tracking. */ + if (!state->is_view_data_set || + wm_xr_session_draw_data_needs_reset_to_base_pose(state, settings)) { + /* Always use the exact base pose with no offset when starting the session. */ + copy_v3_fl(draw_data->eye_position_ofs, 0.0f); + } + else if (position_tracking_toggled) { + if (use_position_tracking) { + copy_v3_fl(draw_data->eye_position_ofs, 0.0f); + } + else { + /* Store the current local offset (local pose) so that we can apply that to the eyes. This + * way the eyes stay exactly where they are when disabling positional tracking. */ + copy_v3_v3(draw_data->eye_position_ofs, draw_view->local_pose.position); + } + } + else if (!use_position_tracking) { + /* Keep previous offset when positional tracking is disabled. */ + copy_v3_v3(draw_data->eye_position_ofs, state->prev_eye_position_ofs); + } +} + +/** + * Update information that is only stored for external state queries. E.g. for Python API to + * request the current (as in, last known) viewer pose. + */ +void wm_xr_session_state_update(const XrSessionSettings *settings, + const wmXrDrawData *draw_data, + const GHOST_XrDrawViewInfo *draw_view, + wmXrSessionState *state) +{ + GHOST_XrPose viewer_pose; + const bool use_position_tracking = settings->flag & XR_SESSION_USE_POSITION_TRACKING; + + mul_qt_qtqt(viewer_pose.orientation_quat, + draw_data->base_pose.orientation_quat, + draw_view->local_pose.orientation_quat); + copy_v3_v3(viewer_pose.position, draw_data->base_pose.position); + /* The local pose and the eye pose (which is copied from an earlier local pose) both are view + * space, so Y-up. In this case we need them in regular Z-up. */ + viewer_pose.position[0] += draw_data->eye_position_ofs[0]; + viewer_pose.position[1] -= draw_data->eye_position_ofs[2]; + viewer_pose.position[2] += draw_data->eye_position_ofs[1]; + if (use_position_tracking) { + viewer_pose.position[0] += draw_view->local_pose.position[0]; + viewer_pose.position[1] -= draw_view->local_pose.position[2]; + viewer_pose.position[2] += draw_view->local_pose.position[1]; + } + + copy_v3_v3(state->viewer_pose.position, viewer_pose.position); + copy_qt_qt(state->viewer_pose.orientation_quat, viewer_pose.orientation_quat); + wm_xr_pose_to_viewmat(&viewer_pose, state->viewer_viewmat); + /* No idea why, but multiplying by two seems to make it match the VR view more. */ + state->focal_len = 2.0f * + fov_to_focallength(draw_view->fov.angle_right - draw_view->fov.angle_left, + DEFAULT_SENSOR_WIDTH); + + copy_v3_v3(state->prev_eye_position_ofs, draw_data->eye_position_ofs); + state->prev_settings_flag = settings->flag; + state->prev_base_pose_type = settings->base_pose_type; + state->prev_base_pose_object = settings->base_pose_object; + state->is_view_data_set = true; +} + +wmXrSessionState *WM_xr_session_state_handle_get(const wmXrData *xr) +{ + return xr->runtime ? &xr->runtime->session_state : NULL; +} + +bool WM_xr_session_state_viewer_pose_location_get(const wmXrData *xr, float r_location[3]) +{ + if (!WM_xr_session_is_ready(xr) || !xr->runtime->session_state.is_view_data_set) { + zero_v3(r_location); + return false; + } + + copy_v3_v3(r_location, xr->runtime->session_state.viewer_pose.position); + return true; +} + +bool WM_xr_session_state_viewer_pose_rotation_get(const wmXrData *xr, float r_rotation[4]) +{ + if (!WM_xr_session_is_ready(xr) || !xr->runtime->session_state.is_view_data_set) { + unit_qt(r_rotation); + return false; + } + + copy_v4_v4(r_rotation, xr->runtime->session_state.viewer_pose.orientation_quat); + return true; +} + +bool WM_xr_session_state_viewer_pose_matrix_info_get(const wmXrData *xr, + float r_viewmat[4][4], + float *r_focal_len) +{ + if (!WM_xr_session_is_ready(xr) || !xr->runtime->session_state.is_view_data_set) { + unit_m4(r_viewmat); + *r_focal_len = 0.0f; + return false; + } + + copy_m4_m4(r_viewmat, xr->runtime->session_state.viewer_viewmat); + *r_focal_len = xr->runtime->session_state.focal_len; + + return true; +} + +/* -------------------------------------------------------------------- */ +/** \name XR-Session Surface + * + * A wmSurface is used to manage drawing of the VR viewport. It's created and destroyed with the + * session. + * + * \{ */ + +/** + * \brief Call Ghost-XR to draw a frame + * + * Draw callback for the XR-session surface. It's expected to be called on each main loop iteration + * and tells Ghost-XR to submit a new frame by drawing its views. Note that for drawing each view, + * #wm_xr_draw_view() will be called through Ghost-XR (see GHOST_XrDrawViewFunc()). + */ +static void wm_xr_session_surface_draw(bContext *C) +{ + wmXrSurfaceData *surface_data = g_xr_surface->customdata; + wmWindowManager *wm = CTX_wm_manager(C); + wmXrDrawData draw_data; + + if (!GHOST_XrSessionIsRunning(wm->xr.runtime->context)) { + return; + } + wm_xr_session_draw_data_populate( + &wm->xr, CTX_data_scene(C), CTX_data_ensure_evaluated_depsgraph(C), &draw_data); + + DRW_xr_drawing_begin(); + + GHOST_XrSessionDrawViews(wm->xr.runtime->context, &draw_data); + + GPU_offscreen_unbind(surface_data->offscreen, false); + DRW_xr_drawing_end(); +} + +bool wm_xr_session_surface_offscreen_ensure(wmXrSurfaceData *surface_data, + const GHOST_XrDrawViewInfo *draw_view) +{ + const bool size_changed = surface_data->offscreen && + (GPU_offscreen_width(surface_data->offscreen) != draw_view->width) && + (GPU_offscreen_height(surface_data->offscreen) != draw_view->height); + char err_out[256] = "unknown"; + bool failure = false; + + if (surface_data->offscreen) { + BLI_assert(surface_data->viewport); + + if (!size_changed) { + return true; + } + GPU_viewport_free(surface_data->viewport); + GPU_offscreen_free(surface_data->offscreen); + } + + if (!(surface_data->offscreen = GPU_offscreen_create( + draw_view->width, draw_view->height, 0, true, false, err_out))) { + failure = true; + } + + if (failure) { + /* Pass. */ + } + else if (!(surface_data->viewport = GPU_viewport_create())) { + GPU_offscreen_free(surface_data->offscreen); + failure = true; + } + + if (failure) { + CLOG_ERROR(&LOG, "Failed to get buffer, %s\n", err_out); + return false; + } + + return true; +} + +static void wm_xr_session_surface_free_data(wmSurface *surface) +{ + wmXrSurfaceData *data = surface->customdata; + + if (data->viewport) { + GPU_viewport_free(data->viewport); + } + if (data->offscreen) { + GPU_offscreen_free(data->offscreen); + } + + MEM_freeN(surface->customdata); + + g_xr_surface = NULL; +} + +static wmSurface *wm_xr_session_surface_create(void) +{ + if (g_xr_surface) { + BLI_assert(false); + return g_xr_surface; + } + + wmSurface *surface = MEM_callocN(sizeof(*surface), __func__); + wmXrSurfaceData *data = MEM_callocN(sizeof(*data), "XrSurfaceData"); + + surface->draw = wm_xr_session_surface_draw; + surface->free_data = wm_xr_session_surface_free_data; + surface->ghost_ctx = DRW_xr_opengl_context_get(); + surface->gpu_ctx = DRW_xr_gpu_context_get(); + + surface->customdata = data; + + g_xr_surface = surface; + + return surface; +} + +void *wm_xr_session_gpu_binding_context_create(void) +{ + wmSurface *surface = wm_xr_session_surface_create(); + + wm_surface_add(surface); + + /* Some regions may need to redraw with updated session state after the session is entirely up + * and running. */ + WM_main_add_notifier(NC_WM | ND_XR_DATA_CHANGED, NULL); + + return surface->ghost_ctx; +} + +void wm_xr_session_gpu_binding_context_destroy(GHOST_ContextHandle UNUSED(context)) +{ + if (g_xr_surface) { /* Might have been freed already */ + wm_surface_remove(g_xr_surface); + } + + wm_window_reset_drawable(); + + /* Some regions may need to redraw with updated session state after the session is entirely + * stopped. */ + WM_main_add_notifier(NC_WM | ND_XR_DATA_CHANGED, NULL); +} + +/** \} */ /* XR-Session Surface */ diff --git a/source/blender/windowmanager/xr/wm_xr.h b/source/blender/windowmanager/xr/wm_xr.h new file mode 100644 index 00000000000..33f79bc75b2 --- /dev/null +++ b/source/blender/windowmanager/xr/wm_xr.h @@ -0,0 +1,35 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup wm + */ + +#ifndef __WM_XR_H__ +#define __WM_XR_H__ + +struct wmWindowManager; +struct wmXrData; + +typedef void (*wmXrSessionExitFn)(const wmXrData *xr_data); + +/* wm_xr.c */ +bool wm_xr_init(wmWindowManager *wm); +void wm_xr_exit(wmWindowManager *wm); +void wm_xr_session_toggle(wmWindowManager *wm, wmXrSessionExitFn session_exit_fn); +bool wm_xr_events_handle(wmWindowManager *wm); + +#endif |