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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulian Eisel <julian@blender.org>2020-06-05 14:09:31 +0300
committerJulian Eisel <julian@blender.org>2020-06-05 14:09:31 +0300
commit920a58d9b6d667894cf166cbbd25e4c2fbd238ea (patch)
tree7ca5a9da640753b5e070c439ac3bdd14dfad92cf /source/blender/windowmanager
parentc94b6209861ca7cc3985b53474feed7d94c0221a (diff)
parenta1d55bdd530390e58c51abe9707b8d3b0ae3e861 (diff)
Merge branch 'master' into wm-drag-drop-rewritewm-drag-drop-rewrite
Diffstat (limited to 'source/blender/windowmanager')
-rw-r--r--source/blender/windowmanager/CMakeLists.txt20
-rw-r--r--source/blender/windowmanager/WM_api.h38
-rw-r--r--source/blender/windowmanager/WM_keymap.h10
-rw-r--r--source/blender/windowmanager/WM_toolsystem.h8
-rw-r--r--source/blender/windowmanager/WM_types.h18
-rw-r--r--source/blender/windowmanager/gizmo/WM_gizmo_api.h2
-rw-r--r--source/blender/windowmanager/gizmo/WM_gizmo_types.h21
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c48
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo_group_type.c2
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c72
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo_type.c12
-rw-r--r--source/blender/windowmanager/intern/wm.c32
-rw-r--r--source/blender/windowmanager/intern/wm_cursors.c20
-rw-r--r--source/blender/windowmanager/intern/wm_draw.c192
-rw-r--r--source/blender/windowmanager/intern/wm_event_query.c10
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c402
-rw-r--r--source/blender/windowmanager/intern/wm_files.c346
-rw-r--r--source/blender/windowmanager/intern/wm_files_link.c2
-rw-r--r--source/blender/windowmanager/intern/wm_gesture.c22
-rw-r--r--source/blender/windowmanager/intern/wm_gesture_ops.c16
-rw-r--r--source/blender/windowmanager/intern/wm_init_exit.c27
-rw-r--r--source/blender/windowmanager/intern/wm_jobs.c6
-rw-r--r--source/blender/windowmanager/intern/wm_keymap.c30
-rw-r--r--source/blender/windowmanager/intern/wm_keymap_utils.c3
-rw-r--r--source/blender/windowmanager/intern/wm_menu_type.c4
-rw-r--r--source/blender/windowmanager/intern/wm_operator_type.c8
-rw-r--r--source/blender/windowmanager/intern/wm_operator_utils.c8
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c143
-rw-r--r--source/blender/windowmanager/intern/wm_playanim.c14
-rw-r--r--source/blender/windowmanager/intern/wm_splash_screen.c332
-rw-r--r--source/blender/windowmanager/intern/wm_surface.c2
-rw-r--r--source/blender/windowmanager/intern/wm_toolsystem.c126
-rw-r--r--source/blender/windowmanager/intern/wm_tooltip.c16
-rw-r--r--source/blender/windowmanager/intern/wm_uilist_type.c4
-rw-r--r--source/blender/windowmanager/intern/wm_window.c249
-rw-r--r--source/blender/windowmanager/intern/wm_xr.c765
-rw-r--r--source/blender/windowmanager/message_bus/intern/wm_message_bus.c11
-rw-r--r--source/blender/windowmanager/wm.h11
-rw-r--r--source/blender/windowmanager/wm_draw.h2
-rw-r--r--source/blender/windowmanager/wm_event_system.h5
-rw-r--r--source/blender/windowmanager/wm_event_types.h1
-rw-r--r--source/blender/windowmanager/wm_files.h2
-rw-r--r--source/blender/windowmanager/wm_surface.h2
-rw-r--r--source/blender/windowmanager/wm_window.h12
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr.c168
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr_draw.c162
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr_intern.h96
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr_session.c430
-rw-r--r--source/blender/windowmanager/xr/wm_xr.h35
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(&region->winrct, &event->x)) {
winrect = &region->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(&region->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(&region->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[] = {
&region->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(&gt->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