diff options
Diffstat (limited to 'source/blender/windowmanager')
54 files changed, 1312 insertions, 2044 deletions
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index 8d25ece3753..4ffd31a9923 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -84,11 +84,24 @@ typedef struct wmGizmoMap wmGizmoMap; typedef struct wmGizmoMapType wmGizmoMapType; typedef struct wmJob wmJob; -/* general API */ +/* General API. */ + +/** + * Used for setting app-template from the command line: + * - non-empty string: overrides. + * - empty string: override, using no app template. + * - NULL: clears override. + */ void WM_init_state_app_template_set(const char *app_template); const char *WM_init_state_app_template_get(void); +/** + * Called when no ghost system was initialized. + */ void WM_init_state_size_set(int stax, int stay, int sizx, int sizy); +/** + * For border-less and border windows set from command-line. + */ void WM_init_state_fullscreen_set(void); void WM_init_state_normal_set(void); void WM_init_state_maximized_set(void); @@ -97,9 +110,21 @@ void WM_init_window_focus_set(bool do_it); void WM_init_native_pixels(bool do_it); void WM_init_tablet_api(void); +/** + * Initialize Blender and load the startup file & preferences + * (only called once). + */ void WM_init(struct bContext *C, int argc, const char **argv); +/** + * \note doesn't run exit() call #WM_exit() for that. + */ void WM_exit_ex(struct bContext *C, const bool do_python); +/** + * \brief Main exit function to close Blender ordinarily. + * \note Use #wm_exit_schedule_delayed() to close Blender from an operator. + * Might leak memory otherwise. + */ void WM_exit(struct bContext *C) ATTR_NORETURN; void WM_main(struct bContext *C) ATTR_NORETURN; @@ -111,6 +136,10 @@ void WM_init_opengl(void); void WM_check(struct bContext *C); void WM_reinit_gizmomap_all(struct Main *bmain); +/** + * Needed for cases when operators are re-registered + * (when operator type pointers are stored). + */ void WM_script_tag_reload(void); wmWindow *WM_window_find_under_cursor(const wmWindowManager *wm, @@ -125,13 +154,30 @@ void WM_window_pixel_sample_read(const wmWindowManager *wm, uint *WM_window_pixels_read(struct wmWindowManager *wm, struct wmWindow *win, int r_size[2]); +/** + * Support for native pixel size + * + * \note macOS retina opens window in size X, but it has up to 2 x more pixels. + */ int WM_window_pixels_x(const struct wmWindow *win); int WM_window_pixels_y(const struct wmWindow *win); +/** + * Get boundaries usable by all window contents, including global areas. + */ void WM_window_rect_calc(const struct wmWindow *win, struct rcti *r_rect); +/** + * Get boundaries usable by screen-layouts, excluding global areas. + * \note Depends on #U.dpi_fac. Should that be outdated, call #WM_window_set_dpi first. + */ void WM_window_screen_rect_calc(const struct wmWindow *win, struct rcti *r_rect); bool WM_window_is_fullscreen(const struct wmWindow *win); bool WM_window_is_maximized(const struct wmWindow *win); +/** + * Some editor data may need to be synced with scene data (3D View camera and layers). + * This function ensures data is synced for editors + * in visible work-spaces and their visible layouts. + */ void WM_windows_scene_data_sync(const ListBase *win_lb, struct Scene *scene) ATTR_NONNULL(); struct Scene *WM_windows_scene_get_from_screen(const struct wmWindowManager *wm, const struct bScreen *screen) @@ -145,6 +191,9 @@ struct WorkSpace *WM_windows_workspace_get_from_screen(const wmWindowManager *wm struct Scene *WM_window_get_active_scene(const struct wmWindow *win) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT; +/** + * \warning Only call outside of area/region loops. + */ void WM_window_set_active_scene(struct Main *bmain, struct bContext *C, struct wmWindow *win, @@ -159,6 +208,9 @@ struct WorkSpaceLayout *WM_window_get_active_layout(const struct wmWindow *win) void WM_window_set_active_layout(struct wmWindow *win, struct WorkSpace *workspace, struct WorkSpaceLayout *layout) ATTR_NONNULL(1); +/** + * Get the active screen of the active workspace in \a win. + */ struct bScreen *WM_window_get_active_screen(const struct wmWindow *win) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT; void WM_window_set_active_screen(struct wmWindow *win, @@ -185,6 +237,14 @@ typedef enum eWindowAlignment { WIN_ALIGN_PARENT_CENTER, } eWindowAlignment; +/** + * \param space_type: SPACE_VIEW3D, SPACE_INFO, ... (eSpace_Type) + * \param toplevel: Not a child owned by other windows. A peer of main window. + * \param dialog: whether this should be made as a dialog-style window + * \param temp: whether this is considered a short-lived window + * \param alignment: how this window is positioned relative to its parent + * \return the window or NULL in case of failure. + */ struct wmWindow *WM_window_open(struct bContext *C, const char *title, int x, @@ -208,6 +268,10 @@ void WM_autosave_init(struct wmWindowManager *wm); bool WM_recover_last_session(struct bContext *C, struct ReportList *reports); void WM_file_tag_modified(void); +/** + * \note `scene` (and related `view_layer` and `v3d`) pointers may be NULL, + * in which case no instantiation of linked objects, collections etc. will be performed. + */ struct ID *WM_file_link_datablock(struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer, @@ -216,6 +280,10 @@ struct ID *WM_file_link_datablock(struct Main *bmain, const short id_code, const char *id_name, int flag); +/** + * \note `scene` (and related `view_layer` and `v3d`) pointers may be NULL, + * in which case no instantiation of appended objects, collections etc. will be performed. + */ struct ID *WM_file_append_datablock(struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer, @@ -226,14 +294,24 @@ struct ID *WM_file_append_datablock(struct Main *bmain, int flag); void WM_lib_reload(struct Library *lib, struct bContext *C, struct ReportList *reports); -/* mouse cursors */ +/* Mouse cursors. */ + void WM_cursor_set(struct wmWindow *win, int curs); bool WM_cursor_set_from_tool(struct wmWindow *win, const ScrArea *area, const ARegion *region); void WM_cursor_modal_set(struct wmWindow *win, int val); void WM_cursor_modal_restore(struct wmWindow *win); +/** + * To allow usage all over, we do entire WM. + */ void WM_cursor_wait(bool val); +/** + * \param bounds: can be NULL + */ void WM_cursor_grab_enable(struct wmWindow *win, int wrap, bool hide, int bounds[4]); void WM_cursor_grab_disable(struct wmWindow *win, const int mouse_ungrab_xy[2]); +/** + * After this you can call restore too. + */ void WM_cursor_time(struct wmWindow *win, int nr); struct wmPaintCursor *WM_paint_cursor_activate( @@ -249,10 +327,16 @@ void WM_paint_cursor_remove_by_type(struct wmWindowManager *wm, void (*free)(void *)); void WM_paint_cursor_tag_redraw(struct wmWindow *win, struct ARegion *region); +/** + * This function requires access to the GHOST_SystemHandle (g_system). + */ void WM_cursor_warp(struct wmWindow *win, int x, int y); +/** + * Set x, y to values we can actually position the cursor to. + */ void WM_cursor_compatible_xy(wmWindow *win, int *x, int *y); -/* handlers */ +/* Handlers. */ typedef bool (*EventHandlerPoll)(const ARegion *region, const struct wmEvent *event); struct wmEventHandler_Keymap *WM_event_add_keymap_handler(ListBase *handlers, wmKeyMap *keymap); @@ -261,7 +345,9 @@ struct wmEventHandler_Keymap *WM_event_add_keymap_handler_poll(ListBase *handler EventHandlerPoll poll); struct wmEventHandler_Keymap *WM_event_add_keymap_handler_v2d_mask(ListBase *handlers, wmKeyMap *keymap); -/* priority not implemented, it adds in begin */ +/** + * \note Priorities not implemented yet, for time being just insert in begin of list. + */ struct wmEventHandler_Keymap *WM_event_add_keymap_handler_priority(ListBase *handlers, wmKeyMap *keymap, int priority); @@ -319,6 +405,10 @@ struct wmEventHandler_UI *WM_event_add_ui_handler(const struct bContext *C, wmUIHandlerRemoveFunc remove_fn, void *user_data, const char flag); +/** + * \param postpone: Enable for `win->modalhandlers`, + * this is in a running for () loop in wm_handlers_do(). + */ void WM_event_remove_ui_handler(ListBase *handlers, wmUIHandlerFunc handle_fn, wmUIHandlerRemoveFunc remove_fn, @@ -331,13 +421,24 @@ void WM_event_free_ui_handler_all(struct bContext *C, wmUIHandlerRemoveFunc remove_fn); struct wmEventHandler_Op *WM_event_add_modal_handler(struct bContext *C, struct wmOperator *op); +/** + * Modal handlers store a pointer to an area which might be freed while the handler runs. + * Use this function to NULL all handler pointers to \a old_area. + */ void WM_event_modal_handler_area_replace(wmWindow *win, const struct ScrArea *old_area, struct ScrArea *new_area); +/** + * Modal handlers store a pointer to a region which might be freed while the handler runs. + * Use this function to NULL all handler pointers to \a old_region. + */ void WM_event_modal_handler_region_replace(wmWindow *win, const struct ARegion *old_region, struct ARegion *new_region); +/** + * Called on exit or remove area, only here call cancel callback. + */ void WM_event_remove_handlers(struct bContext *C, ListBase *handlers); /* handler flag */ @@ -366,11 +467,20 @@ void WM_event_add_notifier_ex(struct wmWindowManager *wm, void *reference); void WM_event_add_notifier(const struct bContext *C, unsigned int type, void *reference); void WM_main_add_notifier(unsigned int type, void *reference); +/** + * Clear notifiers by reference, Used so listeners don't act on freed data. + */ void WM_main_remove_notifier_reference(const void *reference); void WM_main_remap_editor_id_reference(struct ID *old_id, struct ID *new_id); /* reports */ +/** + * Show the report in the info header. + */ void WM_report_banner_show(void); +/** + * Hide all currently displayed banners and abort their timer. + */ void WM_report_banners_cancel(struct Main *bmain); void WM_report(eReportType type, const char *message); void WM_reportf(eReportType type, const char *format, ...) ATTR_PRINTF_FORMAT(2, 3); @@ -398,44 +508,87 @@ void WM_event_remove_timer(struct wmWindowManager *wm, void WM_event_remove_timer_notifier(struct wmWindowManager *wm, struct wmWindow *win, struct wmTimer *timer); +/** + * To (de)activate running timers temporary. + */ void WM_event_timer_sleep(struct wmWindowManager *wm, struct wmWindow *win, struct wmTimer *timer, bool do_sleep); -/* operator api, default callbacks */ -/* invoke callback, uses enum property named "type" */ +/* Operator API, default callbacks. */ + +/** + * Helper to get select and tweak-transform to work conflict free and as desired. See + * #WM_operator_properties_generic_select() for details. + * + * To be used together with #WM_generic_select_invoke() and + * #WM_operator_properties_generic_select(). + */ int WM_generic_select_modal(struct bContext *C, struct wmOperator *op, const struct wmEvent *event); +/** + * Helper to get select and tweak-transform to work conflict free and as desired. See + * #WM_operator_properties_generic_select() for details. + * + * To be used together with #WM_generic_select_modal() and + * #WM_operator_properties_generic_select(). + */ int WM_generic_select_invoke(struct bContext *C, struct wmOperator *op, const struct wmEvent *event); void WM_operator_view3d_unit_defaults(struct bContext *C, struct wmOperator *op); int WM_operator_smooth_viewtx_get(const struct wmOperator *op); +/** + * Invoke callback, uses enum property named "type". + */ int WM_menu_invoke_ex(struct bContext *C, struct wmOperator *op, wmOperatorCallContext opcontext); int WM_menu_invoke(struct bContext *C, struct wmOperator *op, const struct wmEvent *event); +/** + * Call an existent menu. The menu can be created in C or Python. + */ void WM_menu_name_call(struct bContext *C, const char *menu_name, short context); +/** + * Similar to #WM_enum_search_invoke, but draws previews. Also, this can't + * be used as invoke callback directly since it needs additional info. + */ int WM_enum_search_invoke_previews(struct bContext *C, struct wmOperator *op, short prv_cols, short prv_rows); int WM_enum_search_invoke(struct bContext *C, struct wmOperator *op, const struct wmEvent *event); -/* invoke callback, confirm menu + exec */ +/** + * Invoke callback, confirm menu + exec. + */ int WM_operator_confirm(struct bContext *C, struct wmOperator *op, const struct wmEvent *event); int WM_operator_confirm_or_exec(struct bContext *C, struct wmOperator *op, const struct wmEvent *event); -/* invoke callback, file selector "filepath" unset + exec */ +/** + * Invoke callback, file selector "filepath" unset + exec. + * + * #wmOperatorType.invoke, opens file-select if path property not set, otherwise executes. + */ int WM_operator_filesel(struct bContext *C, struct wmOperator *op, const struct wmEvent *event); bool WM_operator_filesel_ensure_ext_imtype(wmOperator *op, const struct ImageFormatData *im_format); -/* poll callback, context checks */ +/** Callback for #wmOperatorType.poll */ bool WM_operator_winactive(struct bContext *C); -/* invoke callback, exec + redo popup */ +/** + * Invoke callback, exec + redo popup. + * + * Same as #WM_operator_props_popup but don't use operator redo. + * just wraps #WM_operator_props_dialog_popup. + */ int WM_operator_props_popup_confirm(struct bContext *C, struct wmOperator *op, const struct wmEvent *event); +/** + * Same as #WM_operator_props_popup but call the operator first, + * This way - the button values correspond to the result of the operator. + * Without this, first access to a button will make the result jump, see T32452. + */ int WM_operator_props_popup_call(struct bContext *C, struct wmOperator *op, const struct wmEvent *event); @@ -446,6 +599,9 @@ int WM_operator_props_dialog_popup(struct bContext *C, struct wmOperator *op, in int WM_operator_redo_popup(struct bContext *C, struct wmOperator *op); int WM_operator_ui_popup(struct bContext *C, struct wmOperator *op, int width); +/** + * Can't be used as an invoke directly, needs message arg (can be NULL). + */ int WM_operator_confirm_message_ex(struct bContext *C, struct wmOperator *op, const char *title, @@ -454,22 +610,60 @@ int WM_operator_confirm_message_ex(struct bContext *C, const wmOperatorCallContext opcontext); int WM_operator_confirm_message(struct bContext *C, struct wmOperator *op, const char *message); -/* operator api */ +/* Operator API. */ + void WM_operator_free(struct wmOperator *op); void WM_operator_free_all_after(wmWindowManager *wm, struct wmOperator *op); +/** + * Use with extreme care! + * Properties, custom-data etc - must be compatible. + * + * \param op: Operator to assign the type to. + * \param ot: Operator type to assign. + */ void WM_operator_type_set(struct wmOperator *op, struct wmOperatorType *ot); void WM_operator_stack_clear(struct wmWindowManager *wm); +/** + * This function is needed in the case when an addon id disabled + * while a modal operator it defined is running. + */ void WM_operator_handlers_clear(wmWindowManager *wm, struct wmOperatorType *ot); bool WM_operator_poll(struct bContext *C, struct wmOperatorType *ot); bool WM_operator_poll_context(struct bContext *C, struct wmOperatorType *ot, short context); +/** + * For running operators with frozen context (modal handlers, menus). + * + * \param store: Store settings for re-use. + * + * \warning do not use this within an operator to call its self! T29537. + */ int WM_operator_call_ex(struct bContext *C, struct wmOperator *op, const bool store); int WM_operator_call(struct bContext *C, struct wmOperator *op); +/** + * This is intended to be used when an invoke operator wants to call exec on its self + * and is basically like running op->type->exec() directly, no poll checks no freeing, + * since we assume whoever called invoke will take care of that + */ int WM_operator_call_notest(struct bContext *C, struct wmOperator *op); +/** + * Execute this operator again, put here so it can share above code + */ int WM_operator_repeat(struct bContext *C, struct wmOperator *op); int WM_operator_repeat_last(struct bContext *C, struct wmOperator *op); +/** + * \return true if #WM_operator_repeat can run. + * Simple check for now but may become more involved. + * To be sure the operator can run call `WM_operator_poll(C, op->type)` also, since this call + * checks if #WM_operator_repeat() can run at all, not that it WILL run at any time. + */ bool WM_operator_repeat_check(const struct bContext *C, struct wmOperator *op); bool WM_operator_is_repeat(const struct bContext *C, const struct wmOperator *op); + +bool WM_operator_name_poll(struct bContext *C, const char *opstring); +/** + * Invokes operator in context. + */ int WM_operator_name_call_ptr(struct bContext *C, struct wmOperatorType *ot, wmOperatorCallContext context, @@ -482,6 +676,13 @@ int WM_operator_name_call_with_properties(struct bContext *C, const char *opstring, wmOperatorCallContext context, struct IDProperty *properties); +/** + * Similar to #WM_operator_name_call called with #WM_OP_EXEC_DEFAULT context. + * + * - #wmOperatorType is used instead of operator name since python already has the operator type. + * - `poll()` must be called by python before this runs. + * - reports can be passed to this function (so python can report them as exceptions). + */ int WM_operator_call_py(struct bContext *C, struct wmOperatorType *ot, wmOperatorCallContext context, @@ -495,15 +696,30 @@ void WM_operator_name_call_ptr_with_depends_on_cursor(struct bContext *C, PointerRNA *properties, const char *drawstr); -/* Used for keymap and macro items. */ +/** + * Similar to the function above except its uses ID properties used for key-maps and macros. + */ void WM_operator_properties_alloc(struct PointerRNA **ptr, struct IDProperty **properties, const char *opstring); -/* Make props context sensitive or not. */ +/** + * Make props context sensitive or not. + */ void WM_operator_properties_sanitize(struct PointerRNA *ptr, const bool no_context); +/** + * Set all props to their default. + * + * \param do_update: Only update un-initialized props. + * + * \note There's nothing specific to operators here. + * This could be made a general function. + */ bool WM_operator_properties_default(struct PointerRNA *ptr, const bool do_update); +/** + * Remove all props without #PROP_SKIP_SAVE. + */ void WM_operator_properties_reset(struct wmOperator *op); void WM_operator_properties_create(struct PointerRNA *ptr, const char *opstring); void WM_operator_properties_create_ptr(struct PointerRNA *ptr, struct wmOperatorType *ot); @@ -511,18 +727,28 @@ void WM_operator_properties_clear(struct PointerRNA *ptr); void WM_operator_properties_free(struct PointerRNA *ptr); bool WM_operator_check_ui_empty(struct wmOperatorType *ot); +/** + * Return false, if the UI should be disabled. + */ bool WM_operator_check_ui_enabled(const struct bContext *C, const char *idname); IDProperty *WM_operator_last_properties_ensure_idprops(struct wmOperatorType *ot); void WM_operator_last_properties_ensure(struct wmOperatorType *ot, struct PointerRNA *ptr); wmOperator *WM_operator_last_redo(const struct bContext *C); +/** + * Use for drag & drop a path or name with operators invoke() function. + */ ID *WM_operator_drop_load_path(struct bContext *C, struct wmOperator *op, const short idcode); bool WM_operator_last_properties_init(struct wmOperator *op); bool WM_operator_last_properties_store(struct wmOperator *op); /* wm_operator_props.c */ + void WM_operator_properties_confirm_or_exec(struct wmOperatorType *ot); +/** + * Default properties for file-select. + */ void WM_operator_properties_filesel(struct wmOperatorType *ot, int filter, short type, @@ -530,36 +756,91 @@ void WM_operator_properties_filesel(struct wmOperatorType *ot, short flag, short display, short sort); +/** + * Disable using cursor position, + * use when view operators are initialized from buttons. + */ void WM_operator_properties_use_cursor_init(struct wmOperatorType *ot); void WM_operator_properties_border(struct wmOperatorType *ot); void WM_operator_properties_border_to_rcti(struct wmOperator *op, struct rcti *rect); void WM_operator_properties_border_to_rctf(struct wmOperator *op, rctf *rect); +/** + * Use with #WM_gesture_box_invoke + */ void WM_operator_properties_gesture_box_ex(struct wmOperatorType *ot, bool deselect, bool extend); void WM_operator_properties_gesture_box(struct wmOperatorType *ot); void WM_operator_properties_gesture_box_select(struct wmOperatorType *ot); void WM_operator_properties_gesture_box_zoom(struct wmOperatorType *ot); +/** + * Use with #WM_gesture_lasso_invoke + */ void WM_operator_properties_gesture_lasso(struct wmOperatorType *ot); +/** + * Use with #WM_gesture_straightline_invoke + */ void WM_operator_properties_gesture_straightline(struct wmOperatorType *ot, int cursor); +/** + * Use with #WM_gesture_circle_invoke + */ void WM_operator_properties_gesture_circle(struct wmOperatorType *ot); void WM_operator_properties_mouse_select(struct wmOperatorType *ot); void WM_operator_properties_select_all(struct wmOperatorType *ot); void WM_operator_properties_select_action(struct wmOperatorType *ot, int default_action, bool hide_gui); +/** + * Only #SELECT / #DESELECT. + */ void WM_operator_properties_select_action_simple(struct wmOperatorType *ot, int default_action, bool hide_gui); +/** + * Use for all select random operators. + * Adds properties: percent, seed, action. + */ void WM_operator_properties_select_random(struct wmOperatorType *ot); int WM_operator_properties_select_random_seed_increment_get(wmOperator *op); void WM_operator_properties_select_operation(struct wmOperatorType *ot); +/** + * \note Some tools don't support XOR/AND. + */ void WM_operator_properties_select_operation_simple(struct wmOperatorType *ot); void WM_operator_properties_select_walk_direction(struct wmOperatorType *ot); +/** + * Selecting and tweaking items are overlapping operations. Getting both to work without conflicts + * requires special care. See + * https://wiki.blender.org/wiki/Human_Interface_Guidelines/Selection#Select-tweaking for the + * desired behavior. + * + * For default click selection (with no modifier keys held), the select operators can do the + * following: + * - On a mouse press on an unselected item, change selection and finish immediately after. + * This sends an undo push and allows transform to take over should a tweak event be caught now. + * - On a mouse press on a selected item, don't change selection state, but start modal execution + * of the operator. Idea is that we wait with deselecting other items until we know that the + * intention wasn't to tweak (mouse press+drag) all selected items. + * - If a tweak is recognized before the release event happens, cancel the operator, so that + * transform can take over and no undo-push is sent. + * - If the release event occurs rather than a tweak one, deselect all items but the one under the + * cursor, and finish the modal operator. + * + * This utility, together with #WM_generic_select_invoke() and #WM_generic_select_modal() should + * help getting the wanted behavior to work. Most generic logic should be handled in these, so that + * the select operators only have to care for the case dependent handling. + * + * Every select operator has slightly different requirements, e.g. sequencer strip selection + * also needs to account for handle selection. This should be the baseline behavior though. + */ void WM_operator_properties_generic_select(struct wmOperatorType *ot); + struct CheckerIntervalParams { int nth; /* bypass when set to zero */ int skip; int offset; }; +/** + * \param nth_can_disable: Enable if we want to be able to select no interval at all. + */ void WM_operator_properties_checker_interval(struct wmOperatorType *ot, bool nth_can_disable); void WM_operator_properties_checker_interval_from_op(struct wmOperator *op, struct CheckerIntervalParams *op_params); @@ -576,7 +857,17 @@ bool WM_operator_properties_checker_interval_test(const struct CheckerIntervalPa /* Show the properties sidebar by default. */ #define WM_FILESEL_SHOW_PROPS (1 << 5) -/* operator as a python command (resultuing string must be freed) */ +/** + * Operator as a Python command (resulting string must be freed). + * + * Print a string representation of the operator, + * with the arguments that it runs so Python can run it again. + * + * When calling from an existing #wmOperator, better to use simple version: + * `WM_operator_pystring(C, op);` + * + * \note Both \a op and \a opptr may be `NULL` (\a op is only used for macro operators). + */ char *WM_operator_pystring_ex(struct bContext *C, struct wmOperator *op, const bool all_args, @@ -587,16 +878,32 @@ char *WM_operator_pystring(struct bContext *C, struct wmOperator *op, const bool all_args, const bool macro_args); +/** + * \return true if the string was shortened. + */ bool WM_operator_pystring_abbreviate(char *str, int str_len_max); char *WM_prop_pystring_assign(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop, int index); +/** + * Convert: `some.op` -> `SOME_OT_op` or leave as-is. + */ void WM_operator_bl_idname(char *to, const char *from); +/** + * Convert: `SOME_OT_op` -> `some.op` or leave as-is. + */ void WM_operator_py_idname(char *to, const char *from); +/** + * Sanity check to ensure #WM_operator_bl_idname won't fail. + * \returns true when there are no problems with \a idname, otherwise report an error. + */ bool WM_operator_py_idname_ok_or_report(struct ReportList *reports, const char *classname, const char *idname); +/** + * Calculate the path to `ptr` from context `C`, or return NULL if it can't be calculated. + */ char *WM_context_path_resolve_property_full(const struct bContext *C, const PointerRNA *ptr, PropertyRNA *prop, @@ -604,16 +911,46 @@ char *WM_context_path_resolve_property_full(const struct bContext *C, char *WM_context_path_resolve_full(struct bContext *C, const PointerRNA *ptr); /* wm_operator_type.c */ + struct wmOperatorType *WM_operatortype_find(const char *idname, bool quiet); +/** + * \note Caller must free. + */ void WM_operatortype_iter(struct GHashIterator *ghi); void WM_operatortype_append(void (*opfunc)(struct wmOperatorType *)); void WM_operatortype_append_ptr(void (*opfunc)(struct wmOperatorType *, void *), void *userdata); void WM_operatortype_append_macro_ptr(void (*opfunc)(struct wmOperatorType *, void *), void *userdata); +/** + * Called on initialize WM_exit(). + */ void WM_operatortype_remove_ptr(struct wmOperatorType *ot); bool WM_operatortype_remove(const char *idname); +/** + * Remove memory of all previously executed tools. + */ void WM_operatortype_last_properties_clear_all(void); +/** + * Tag all operator-properties of \a ot defined after calling this, until + * the next #WM_operatortype_props_advanced_end call (if available), with + * #OP_PROP_TAG_ADVANCED. Previously defined ones properties not touched. + * + * Calling this multiple times without a call to #WM_operatortype_props_advanced_end, + * all calls after the first one are ignored. Meaning all proprieties defined after the + * first call are tagged as advanced. + * + * This doesn't do the actual tagging, #WM_operatortype_props_advanced_end does which is + * called for all operators during registration (see #wm_operatortype_append__end). + */ void WM_operatortype_props_advanced_begin(struct wmOperatorType *ot); +/** + * Tags all operator-properties of \a ot defined since the first + * #WM_operatortype_props_advanced_begin call, + * or the last #WM_operatortype_props_advanced_end call, with #OP_PROP_TAG_ADVANCED. + * + * \note This is called for all operators during registration (see #wm_operatortype_append__end). + * So it does not need to be explicitly called in operator-type definition. + */ void WM_operatortype_props_advanced_end(struct wmOperatorType *ot); #define WM_operatortype_prop_tag(property, tags) \ @@ -623,6 +960,9 @@ void WM_operatortype_props_advanced_end(struct wmOperatorType *ot); } \ (void)0 +/** + * \note Names have to be static for now. + */ struct wmOperatorType *WM_operatortype_append_macro(const char *idname, const char *name, const char *description, @@ -634,26 +974,57 @@ const char *WM_operatortype_name(struct wmOperatorType *ot, struct PointerRNA *p char *WM_operatortype_description(struct bContext *C, struct wmOperatorType *ot, struct PointerRNA *properties); +/** + * Use when we want a label, preferring the description. + */ char *WM_operatortype_description_or_name(struct bContext *C, struct wmOperatorType *ot, struct PointerRNA *properties); /* wm_operator_utils.c */ + +/** + * Allow an operator with only and execute function to run modally, + * re-doing the action, using vertex coordinate store/restore instead of operator undo. + */ void WM_operator_type_modal_from_exec_for_object_edit_coords(struct wmOperatorType *ot); /* wm_uilist_type.c */ + +/** + * Called on initialize #WM_init() + */ void WM_uilisttype_init(void); struct uiListType *WM_uilisttype_find(const char *idname, bool quiet); bool WM_uilisttype_add(struct uiListType *ult); void WM_uilisttype_remove_ptr(struct Main *bmain, struct uiListType *ult); void WM_uilisttype_free(void); +/** + * The "full" list-ID is an internal name used for storing and identifying a list. It is built like + * this: + * "{uiListType.idname}_{list_id}", whereby "list_id" is an optional parameter passed to + * `UILayout.template_list()`. If it is not set, the full list-ID is just "{uiListType.idname}_". + * + * Note that whenever the Python API refers to the list-ID, it's the short, "non-full" one it + * passed to `UILayout.template_list()`. C code can query that through + * #WM_uilisttype_list_id_get(). + */ void WM_uilisttype_to_full_list_id(const struct uiListType *ult, const char *list_id, char r_full_list_id[]); +/** + * Get the "non-full" list-ID, see #WM_uilisttype_to_full_list_id() for details. + * + * \note Assumes `uiList.list_id` was set using #WM_uilisttype_to_full_list_id()! + */ const char *WM_uilisttype_list_id_get(const struct uiListType *ult, struct uiList *list); /* wm_menu_type.c */ + +/** + * \note Called on initialize #WM_init(). + */ void WM_menutype_init(void); struct MenuType *WM_menutype_find(const char *idname, bool quiet); void WM_menutype_iter(struct GHashIterator *ghi); @@ -663,6 +1034,10 @@ void WM_menutype_free(void); bool WM_menutype_poll(struct bContext *C, struct MenuType *mt); /* wm_panel_type.c */ + +/** + * Called on initialize #WM_init(). + */ void WM_paneltype_init(void); void WM_paneltype_clear(void); struct PanelType *WM_paneltype_find(const char *idname, bool quiet); @@ -690,6 +1065,11 @@ int WM_gesture_lasso_invoke(struct bContext *C, const struct wmEvent *event); int WM_gesture_lasso_modal(struct bContext *C, struct wmOperator *op, const struct wmEvent *event); void WM_gesture_lasso_cancel(struct bContext *C, struct wmOperator *op); +/** + * helper function, we may want to add options for conversion to view space + * + * caller must free. + */ const int (*WM_gesture_lasso_path_to_array(struct bContext *C, struct wmOperator *op, int *mcoords_len))[2]; @@ -697,18 +1077,38 @@ const int (*WM_gesture_lasso_path_to_array(struct bContext *C, int WM_gesture_straightline_invoke(struct bContext *C, struct wmOperator *op, const struct wmEvent *event); +/** + * This invoke callback starts the straight-line gesture with a viewport preview to the right side + * of the line. + */ int WM_gesture_straightline_active_side_invoke(struct bContext *C, struct wmOperator *op, const struct wmEvent *event); +/** + * This modal callback calls exec once per mouse move event while the gesture is active with the + * updated line start and end values, so it can be used for tools that have a real time preview + * (like a gradient updating in real time over the mesh). + */ int WM_gesture_straightline_modal(struct bContext *C, struct wmOperator *op, const struct wmEvent *event); +/** + * This modal one-shot callback only calls exec once after the gesture finishes without any updates + * during the gesture execution. Should be used for operations that are intended to be applied once + * without real time preview (like a trimming tool that only applies the bisect operation once + * after finishing the gesture as the bisect operation is too heavy to be computed in real time for + * a preview). + */ int WM_gesture_straightline_oneshot_modal(struct bContext *C, struct wmOperator *op, const struct wmEvent *event); void WM_gesture_straightline_cancel(struct bContext *C, struct wmOperator *op); /* Gesture manager API */ + +/** + * Context checked on having screen, window and area. + */ struct wmGesture *WM_gesture_new(struct wmWindow *window, const struct ARegion *region, const struct wmEvent *event, @@ -718,15 +1118,34 @@ void WM_gestures_remove(struct wmWindow *win); void WM_gestures_free_all(struct wmWindow *win); bool WM_gesture_is_modal_first(const struct wmGesture *gesture); -/* fileselecting support */ +/* File-selecting support. */ + +/** + * The idea here is to keep a handler alive on window queue, owning the operator. + * The file window can send event to make it execute, thus ensuring + * executing happens outside of lower level queues, with UI refreshed. + * Should also allow multi-window solutions. + */ void WM_event_add_fileselect(struct bContext *C, struct wmOperator *op); void WM_event_fileselect_event(struct wmWindowManager *wm, void *ophandle, int eventval); +/** + * Sets the active region for this space from the context. + * + * \see #BKE_area_find_region_active_win + */ void WM_operator_region_active_win_set(struct bContext *C); +/** + * Only finish + pass through for press events (allowing press-tweak). + */ int WM_operator_flag_only_pass_through_on_press(int retval, const struct wmEvent *event); -/* drag and drop */ +/* Drag and drop. */ + +/** + * Note that the pointer should be valid allocated and not on stack. + */ struct wmDrag *WM_event_start_drag( struct bContext *C, int icon, int type, void *poin, double value, unsigned int flags); void WM_event_drag_image(struct wmDrag *, struct ImBuf *, float scale, int sx, int sy); @@ -748,30 +1167,61 @@ void WM_drag_draw_default_fn(struct bContext *C, struct wmWindow *win, struct wmDrag *drag, const int xy[2]); +/** + * `spaceid` / `regionid` are zero for window drop maps. + */ ListBase *WM_dropboxmap_find(const char *idname, int spaceid, int regionid); /* ID drag and drop */ + +/** + * \param flag_extra: Additional linking flags (from #eFileSel_Params_Flag). + */ ID *WM_drag_asset_id_import(wmDragAsset *asset_drag, int flag_extra); bool WM_drag_asset_will_import_linked(const wmDrag *drag); void WM_drag_add_local_ID(struct wmDrag *drag, struct ID *id, struct ID *from_parent); struct ID *WM_drag_get_local_ID(const struct wmDrag *drag, short idcode); struct ID *WM_drag_get_local_ID_from_event(const struct wmEvent *event, short idcode); +/** + * Check if the drag data is either a local ID or an external ID asset of type \a idcode. + */ bool WM_drag_is_ID_type(const struct wmDrag *drag, int idcode); +/** + * \note: Does not store \a asset in any way, so it's fine to pass a temporary. + */ wmDragAsset *WM_drag_create_asset_data(const struct AssetHandle *asset, struct AssetMetaData *metadata, const char *path, int import_type); struct wmDragAsset *WM_drag_get_asset_data(const struct wmDrag *drag, int idcode); struct AssetMetaData *WM_drag_get_asset_meta_data(const struct wmDrag *drag, int idcode); +/** + * When dragging a local ID, return that. Otherwise, if dragging an asset-handle, link or append + * that depending on what was chosen by the drag-box (currently append only in fact). + * + * Use #WM_drag_free_imported_drag_ID() as cancel callback of the drop-box, so that the asset + * import is rolled back if the drop operator fails. + */ struct ID *WM_drag_get_local_ID_or_import_from_asset(const struct wmDrag *drag, int idcode); +/** + * \brief Free asset ID imported for canceled drop. + * + * If the asset was imported (linked/appended) using #WM_drag_get_local_ID_or_import_from_asset()` + * (typically via a #wmDropBox.copy() callback), we want the ID to be removed again if the drop + * operator cancels. + * This is for use as #wmDropBox.cancel() callback. + */ void WM_drag_free_imported_drag_ID(struct Main *bmain, struct wmDrag *drag, struct wmDropBox *drop); struct wmDragAssetCatalog *WM_drag_get_asset_catalog_data(const struct wmDrag *drag); +/** + * \note: Does not store \a asset in any way, so it's fine to pass a temporary. + */ void WM_drag_add_asset_list_item(wmDrag *drag, const struct bContext *C, const struct AssetLibraryReference *asset_library_ref, @@ -788,6 +1238,10 @@ void wmWindowViewport(struct wmWindow *win); /* OpenGL utilities with safety check */ void wmOrtho2(float x1, float x2, float y1, float y2); /* use for conventions (avoid hard-coded offsets all over) */ + +/** + * Default pixel alignment for regions. + */ void wmOrtho2_region_pixelspace(const struct ARegion *region); void wmOrtho2_pixelspace(const float x, const float y); void wmGetProjectionMatrix(float mat[4][4], const struct rcti *winrct); @@ -834,6 +1288,12 @@ enum { * if having hard coded values is a problem */ }; +/** + * \return current job or adds new job, but doesn't run it. + * + * \note every owner only gets a single job, + * adding a new one will stop running job and when stopped it starts the new one. + */ struct wmJob *WM_jobs_get(struct wmWindowManager *wm, struct wmWindow *win, const void *owner, @@ -841,9 +1301,15 @@ struct wmJob *WM_jobs_get(struct wmWindowManager *wm, int flag, int job_type); +/** + * Returns true if job runs, for UI (progress) indicators. + */ bool WM_jobs_test(const struct wmWindowManager *wm, const void *owner, int job_type); float WM_jobs_progress(const struct wmWindowManager *wm, const void *owner); const char *WM_jobs_name(const struct wmWindowManager *wm, const void *owner); +/** + * Time that job started. + */ double WM_jobs_starttime(const struct wmWindowManager *wm, const void *owner); void *WM_jobs_customdata(struct wmWindowManager *wm, const void *owner); void *WM_jobs_customdata_from_type(struct wmWindowManager *wm, int job_type); @@ -865,12 +1331,28 @@ void WM_jobs_callbacks(struct wmJob *, void (*update)(void *), void (*endjob)(void *)); +/** + * If job running, the same owner gave it a new job. + * if different owner starts existing startjob, it suspends itself + */ void WM_jobs_start(struct wmWindowManager *wm, struct wmJob *); +/** + * Signal job(s) from this owner or callback to stop, timer is required to get handled. + */ void WM_jobs_stop(struct wmWindowManager *wm, const void *owner, void *startjob); +/** + * Actually terminate thread and job timer. + */ void WM_jobs_kill(struct wmWindowManager *wm, void *owner, void (*)(void *, short int *, short int *, float *)); +/** + * Wait until every job ended. + */ void WM_jobs_kill_all(struct wmWindowManager *wm); +/** + * Wait until every job ended, except for one owner (used in undo to keep screen job alive). + */ void WM_jobs_kill_all_except(struct wmWindowManager *wm, const void *owner); void WM_jobs_kill_type(struct wmWindowManager *wm, const void *owner, int job_type); @@ -879,16 +1361,27 @@ bool WM_jobs_has_running(const struct wmWindowManager *wm); void WM_job_main_thread_lock_acquire(struct wmJob *job); void WM_job_main_thread_lock_release(struct wmJob *job); -/* clipboard */ +/* Clipboard. */ + +/** + * Return text from the clipboard. + * + * \note Caller needs to check for valid utf8 if this is a requirement. + */ char *WM_clipboard_text_get(bool selection, int *r_len); +/** + * Convenience function for pasting to areas of Blender which don't support newlines. + */ char *WM_clipboard_text_get_firstline(bool selection, int *r_len); void WM_clipboard_text_set(const char *buf, bool selection); /* progress */ + void WM_progress_set(struct wmWindow *win, float progress); void WM_progress_clear(struct wmWindow *win); /* Draw (for screenshot) */ + void *WM_draw_cb_activate(struct wmWindow *win, void (*draw)(const struct wmWindow *, void *), void *customdata); @@ -900,21 +1393,29 @@ 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, bool hide); struct GPUViewport *WM_draw_region_get_viewport(struct ARegion *region); struct GPUViewport *WM_draw_region_get_bound_viewport(struct ARegion *region); void WM_main_playanim(int argc, const char **argv); -/* debugging only, convenience function to write on crash */ +/** + * Debugging only, convenience function to write on crash. + * Convenient to save a blend file from a debugger. + */ bool write_crash_blend(void); -/* Lock the interface for any communication */ +/** + * 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' */ +/** + * For testing only, see #G_FLAG_EVENT_SIMULATE. + */ struct wmEvent *WM_event_add_simulate(struct wmWindow *win, const struct wmEvent *event_to_add); const char *WM_window_cursor_keymap_status_get(const struct wmWindow *win, @@ -923,28 +1424,60 @@ 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); +/** + * Similar to #BKE_screen_area_map_find_area_xy and related functions, + * use here since the area is stored in the window manager. + */ 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); /* wm_event_query.c */ + +/** + * For debugging only, getting inspecting events manually is tedious. + */ void WM_event_print(const struct wmEvent *event); int WM_event_modifier_flag(const struct wmEvent *event); +/** + * For modal callbacks, check configuration for how to interpret exit with tweaks. + */ bool WM_event_is_modal_tweak_exit(const struct wmEvent *event, int tweak_event); bool WM_event_is_last_mousemove(const struct wmEvent *event); bool WM_event_is_mouse_drag(const struct wmEvent *event); bool WM_event_is_mouse_drag_or_press(const wmEvent *event); +/** + * Detect motion between selection (callers should only use this for selection picking), + * typically mouse press/click events. + * + * \param mval: Region relative coordinates, call with (-1, -1) resets the last cursor location. + * \returns True when there was motion since last called. + * + * NOTE(@campbellbarton): The logic used here isn't foolproof. + * It's possible that users move the cursor past #WM_EVENT_CURSOR_MOTION_THRESHOLD then back to + * a position within the threshold (between mouse clicks). + * In practice users never reported this since the threshold is very small (a few pixels). + * To prevent the unlikely case of values matching from another region, + * changing regions resets this value to (-1, -1). + */ bool WM_cursor_test_motion_and_update(const int mval[2]) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT; int WM_event_drag_threshold(const struct wmEvent *event); bool WM_event_drag_test(const struct wmEvent *event, const int prev_xy[2]); bool WM_event_drag_test_with_delta(const struct wmEvent *event, const int delta[2]); -/* event map */ +/** + * Event map that takes preferences into account. + */ int WM_userdef_event_map(int kmitype); +/** + * Use so we can check if 'wmEvent.type' is released in modal operators. + * + * An alternative would be to add a 'wmEvent.type_nokeymap'... or similar. + */ int WM_userdef_event_type_from_keymap_type(int kmitype); #ifdef WITH_INPUT_NDOF @@ -961,6 +1494,10 @@ void WM_event_ndof_to_quat(const struct wmNDOFMotionData *ndof, float q[4]); bool WM_event_is_xr(const struct wmEvent *event); #endif +/** + * If this is a tablet event, return tablet pressure and set `*pen_flip` + * to 1 if the eraser tool is being used, 0 otherwise. + */ float WM_event_tablet_data(const struct wmEvent *event, int *pen_flip, float tilt[2]); bool WM_event_is_tablet(const struct wmEvent *event); @@ -972,6 +1509,7 @@ bool WM_event_is_ime_switch(const struct wmEvent *event); #endif /* wm_tooltip.c */ + typedef struct ARegion *(*wmTooltipInitFn)(struct bContext *C, struct ARegion *region, int *pass, @@ -1001,6 +1539,7 @@ void WM_tooltip_refresh(struct bContext *C, struct wmWindow *win); double WM_tooltip_time_closed(void); /* wm_utils.c */ + struct wmGenericCallback *WM_generic_callback_steal(struct wmGenericCallback *callback); void WM_generic_callback_free(struct wmGenericCallback *callback); @@ -1010,7 +1549,15 @@ bool WM_region_use_viewport(struct ScrArea *area, struct ARegion *region); #ifdef WITH_XR_OPENXR /* wm_xr_session.c */ + +/** + * 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); +/** + * Check if the session is running, according to the OpenXR definition. + */ bool WM_xr_session_is_ready(const wmXrData *xr); struct wmXrSessionState *WM_xr_session_state_handle_get(const wmXrData *xr); struct ScrArea *WM_xr_session_area_get(const wmXrData *xr); @@ -1043,8 +1590,10 @@ void WM_xr_session_state_navigation_reset(struct wmXrSessionState *state); struct ARegionType *WM_xr_surface_controller_region_type_get(void); /* wm_xr_actions.c */ + /* XR action functions to be called pre-XR session start. * NOTE: The "destroy" functions can also be called post-session start. */ + bool WM_xr_action_set_create(wmXrData *xr, const char *action_set_name); void WM_xr_action_set_destroy(wmXrData *xr, const char *action_set_name); bool WM_xr_action_create(wmXrData *xr, @@ -1078,7 +1627,9 @@ void WM_xr_action_binding_destroy(wmXrData *xr, const char *action_name, const char *profile_path); -/* If action_set_name is NULL, then all action sets will be treated as active. */ +/** + * If action_set_name is NULL, then all action sets will be treated as active. + */ bool WM_xr_active_action_set_set(wmXrData *xr, const char *action_set_name); bool WM_xr_controller_pose_actions_set(wmXrData *xr, @@ -1086,7 +1637,9 @@ bool WM_xr_controller_pose_actions_set(wmXrData *xr, const char *grip_action_name, const char *aim_action_name); -/* XR action functions to be called post-XR session start. */ +/** + * XR action functions to be called post-XR session start. + */ bool WM_xr_action_state_get(const wmXrData *xr, const char *action_set_name, const char *action_name, @@ -1105,9 +1658,13 @@ void WM_xr_haptic_action_stop(wmXrData *xr, const char *subaction_path); /* wm_xr_actionmap.c */ + XrActionMap *WM_xr_actionmap_new(struct wmXrRuntimeData *runtime, const char *name, bool replace_existing); +/** + * Ensure unique name among all action maps. + */ void WM_xr_actionmap_ensure_unique(struct wmXrRuntimeData *runtime, XrActionMap *actionmap); XrActionMap *WM_xr_actionmap_add_copy(struct wmXrRuntimeData *runtime, XrActionMap *am_src); bool WM_xr_actionmap_remove(struct wmXrRuntimeData *runtime, XrActionMap *actionmap); @@ -1123,15 +1680,25 @@ void WM_xr_actionmap_selected_index_set(struct wmXrRuntimeData *runtime, short i XrActionMapItem *WM_xr_actionmap_item_new(XrActionMap *actionmap, const char *name, bool replace_existing); +/** + * Ensure unique name among all action map items. + */ void WM_xr_actionmap_item_ensure_unique(XrActionMap *actionmap, XrActionMapItem *ami); XrActionMapItem *WM_xr_actionmap_item_add_copy(XrActionMap *actionmap, XrActionMapItem *ami_src); bool WM_xr_actionmap_item_remove(XrActionMap *actionmap, XrActionMapItem *ami); XrActionMapItem *WM_xr_actionmap_item_find(XrActionMap *actionmap, const char *name); +/** + * Similar to #wm_xr_actionmap_item_properties_set() + * but checks for the #eXrActionType and #wmOperatorType having changed. + */ void WM_xr_actionmap_item_properties_update_ot(XrActionMapItem *ami); XrActionMapBinding *WM_xr_actionmap_binding_new(XrActionMapItem *ami, const char *name, bool replace_existing); +/** + * Ensure unique name among all action map bindings. + */ void WM_xr_actionmap_binding_ensure_unique(XrActionMapItem *ami, XrActionMapBinding *amb); XrActionMapBinding *WM_xr_actionmap_binding_add_copy(XrActionMapItem *ami, XrActionMapBinding *amb_src); diff --git a/source/blender/windowmanager/WM_keymap.h b/source/blender/windowmanager/WM_keymap.h index 0633ffe55ea..4d1f2d979cb 100644 --- a/source/blender/windowmanager/WM_keymap.h +++ b/source/blender/windowmanager/WM_keymap.h @@ -55,6 +55,9 @@ void WM_keyconfig_update_operatortype(void); void WM_keymap_clear(struct wmKeyMap *keymap); +/** + * Always add item. + */ wmKeyMapItem *WM_keymap_add_item( struct wmKeyMap *keymap, const char *idname, int type, int val, int modifier, int keymodifier); wmKeyMapItem *WM_keymap_add_item_copy(struct wmKeyMap *keymap, wmKeyMapItem *kmi_src); @@ -91,16 +94,30 @@ bool WM_keymap_item_compare(const struct wmKeyMapItem *k1, const struct wmKeyMap /* keymap_utils.c */ -/** Wrappers for #WM_keymap_add_item */ +/* Wrappers for #WM_keymap_add_item */ + +/** + * Menu wrapper for #WM_keymap_add_item. + */ wmKeyMapItem *WM_keymap_add_menu( struct wmKeyMap *keymap, const char *idname, int type, int val, int modifier, int keymodifier); +/** + * Pie-menu wrapper for #WM_keymap_add_item. + */ wmKeyMapItem *WM_keymap_add_menu_pie( struct wmKeyMap *keymap, const char *idname, int type, int val, int modifier, int keymodifier); +/** + * Panel (popover) wrapper for #WM_keymap_add_item. + */ wmKeyMapItem *WM_keymap_add_panel( struct wmKeyMap *keymap, const char *idname, int type, int val, int modifier, int keymodifier); +/** + * Tool wrapper for #WM_keymap_add_item. + */ wmKeyMapItem *WM_keymap_add_tool( struct wmKeyMap *keymap, const char *idname, int type, int val, int modifier, int keymodifier); +/** Useful for mapping numbers to an enum. */ void WM_keymap_add_context_enum_set_items(wmKeyMap *keymap, const struct EnumPropertyItem *items, const char *data_path, @@ -110,6 +127,12 @@ void WM_keymap_add_context_enum_set_items(wmKeyMap *keymap, int keymodifier); wmKeyMap *WM_keymap_guess_from_context(const struct bContext *C); + +/** + * Guess an appropriate key-map from the operator name. + * + * \note Needs to be kept up to date with Key-map and Operator naming. + */ wmKeyMap *WM_keymap_guess_opname(const struct bContext *C, const char *opname); bool WM_keymap_uses_event_modifier(const wmKeyMap *keymap, const int event_modifier); @@ -149,6 +172,9 @@ void WM_modalkeymap_assign(struct wmKeyMap *km, const char *opname); /* Keymap Editor */ void WM_keymap_restore_to_default(struct wmKeyMap *keymap, struct wmWindowManager *wm); +/** + * Properties can be NULL, otherwise the arg passed is used and ownership is given to the `kmi`. + */ void WM_keymap_item_properties_reset(struct wmKeyMapItem *kmi, struct IDProperty *properties); void WM_keymap_item_restore_to_default(wmWindowManager *wm, struct wmKeyMap *keymap, @@ -168,6 +194,10 @@ int WM_keymap_item_raw_to_string(const short shift, const bool compact, char *result, const int result_len); +/** + * \param include_mask, exclude_mask: + * Event types to include/exclude when looking up keys (#eEventType_Mask). + */ wmKeyMapItem *WM_key_event_operator(const struct bContext *C, const char *opname, wmOperatorCallContext opcontext, diff --git a/source/blender/windowmanager/WM_toolsystem.h b/source/blender/windowmanager/WM_toolsystem.h index eb89fca7b56..32b9cf1d7ba 100644 --- a/source/blender/windowmanager/WM_toolsystem.h +++ b/source/blender/windowmanager/WM_toolsystem.h @@ -69,6 +69,9 @@ void WM_toolsystem_unlink(struct bContext *C, struct WorkSpace *workspace, const void WM_toolsystem_refresh(struct bContext *C, struct WorkSpace *workspace, const bToolKey *tkey); void WM_toolsystem_reinit(struct bContext *C, struct WorkSpace *workspace, const bToolKey *tkey); +/** + * Operate on all active tools. + */ void WM_toolsystem_unlink_all(struct bContext *C, struct WorkSpace *workspace); void WM_toolsystem_refresh_all(struct bContext *C, struct WorkSpace *workspace); void WM_toolsystem_reinit_all(struct bContext *C, struct wmWindow *win); @@ -79,6 +82,12 @@ void WM_toolsystem_ref_set_from_runtime(struct bContext *C, const struct bToolRef_Runtime *tref_rt, const char *idname); +/** + * Sync the internal active state of a tool back into the tool system, + * this is needed for active brushes where the real active state is not stored in the tool system. + * + * \see #toolsystem_ref_link + */ void WM_toolsystem_ref_sync_from_context(struct Main *bmain, struct WorkSpace *workspace, struct bToolRef *tref); @@ -98,8 +107,12 @@ void WM_toolsystem_update_from_context(struct bContext *C, struct ViewLayer *view_layer, struct ScrArea *area); +/** + * For paint modes to support non-brush tools. + */ bool WM_toolsystem_active_tool_is_brush(const struct bContext *C); +/** Follow #wmMsgNotifyFn spec. */ void WM_toolsystem_do_msg_notify_tag_refresh(struct bContext *C, struct wmMsgSubscribeKey *msg_key, struct wmMsgSubscribeValue *msg_val); @@ -129,6 +142,14 @@ void WM_toolsystem_ref_properties_init_for_keymap(struct bToolRef *tref, struct PointerRNA *src_ptr, struct wmOperatorType *ot); +/** + * Use to update the active tool (shown in the top bar) in the least disruptive way. + * + * This is a little involved since there may be multiple valid active tools + * depending on the mode and space type. + * + * Used when undoing since the active mode may have changed. + */ void WM_toolsystem_refresh_active(struct bContext *C); void WM_toolsystem_refresh_screen_area(struct WorkSpace *workspace, diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index b8fe3786bde..3d56303a424 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -972,10 +972,10 @@ typedef void (*wmPaintCursorDraw)(struct bContext *C, int, int, void *customdata #define WM_DRAG_DATASTACK 8 #define WM_DRAG_ASSET_CATALOG 9 -typedef enum wmDragFlags { +typedef enum eWM_DragFlags { WM_DRAG_NOP = 0, WM_DRAG_FREE_DATA = 1, -} wmDragFlags; +} eWM_DragFlags; /* NOTE: structs need not exported? */ @@ -1070,7 +1070,7 @@ typedef struct wmDrag { wmDragActiveDropState drop_state; - unsigned int flags; + eWM_DragFlags flags; /** List of wmDragIDs, all are guaranteed to have the same ID type. */ ListBase ids; diff --git a/source/blender/windowmanager/gizmo/WM_gizmo_api.h b/source/blender/windowmanager/gizmo/WM_gizmo_api.h index c7a4b064d0e..497e4f6e5fc 100644 --- a/source/blender/windowmanager/gizmo/WM_gizmo_api.h +++ b/source/blender/windowmanager/gizmo/WM_gizmo_api.h @@ -61,19 +61,42 @@ extern "C" { struct wmGizmo *WM_gizmo_new_ptr(const struct wmGizmoType *gzt, struct wmGizmoGroup *gzgroup, struct PointerRNA *properties); +/** + * \param idname: Must be a valid gizmo type name, + * if you need to check it exists use #WM_gizmo_new_ptr + * because callers of this function don't NULL check the return value. + */ struct wmGizmo *WM_gizmo_new(const char *idname, struct wmGizmoGroup *gzgroup, struct PointerRNA *properties); +/** + * \warning this doesn't check #wmGizmoMap (highlight, selection etc). + * Typical use is when freeing the windowing data, + * where caller can manage clearing selection, highlight... etc. + */ void WM_gizmo_free(struct wmGizmo *gz); +/** + * Free \a gizmo and unlink from \a gizmolist. + * \a gizmolist is allowed to be NULL. + */ void WM_gizmo_unlink(ListBase *gizmolist, struct wmGizmoMap *gzmap, struct wmGizmo *gz, struct bContext *C); +/** + * Remove from selection array without running callbacks. + */ bool WM_gizmo_select_unlink(struct wmGizmoMap *gzmap, struct wmGizmo *gz); bool WM_gizmo_select_set(struct wmGizmoMap *gzmap, struct wmGizmo *gz, bool select); bool WM_gizmo_highlight_set(struct wmGizmoMap *gzmap, struct wmGizmo *gz); +/** + * Special function to run from setup so gizmos start out interactive. + * + * We could do this when linking them, + * but this complicates things since the window update code needs to run first. + */ void WM_gizmo_modal_set_from_setup(struct wmGizmoMap *gzmap, struct bContext *C, struct wmGizmo *gz, @@ -87,17 +110,30 @@ struct PointerRNA *WM_gizmo_operator_set(struct wmGizmo *gz, struct IDProperty *properties); int WM_gizmo_operator_invoke(struct bContext *C, struct wmGizmo *gz, struct wmGizmoOpElem *gzop); -/* callbacks */ +/* Callbacks. */ + void WM_gizmo_set_fn_custom_modal(struct wmGizmo *gz, wmGizmoFnModal fn); void WM_gizmo_set_matrix_location(struct wmGizmo *gz, const float origin[3]); +/** + * #wmGizmo.matrix utility, set the orientation by it's Z axis. + */ void WM_gizmo_set_matrix_rotation_from_z_axis(struct wmGizmo *gz, const float z_axis[3]); +/** + * #wmGizmo.matrix utility, set the orientation by it's Y/Z axis. + */ void WM_gizmo_set_matrix_rotation_from_yz_axis(struct wmGizmo *gz, const float y_axis[3], const float z_axis[3]); void WM_gizmo_set_matrix_offset_location(struct wmGizmo *gz, const float offset[3]); +/** + * #wmGizmo.matrix_offset utility, set the orientation by it's Z axis. + */ void WM_gizmo_set_matrix_offset_rotation_from_z_axis(struct wmGizmo *gz, const float z_axis[3]); +/** + * #wmGizmo.matrix_offset utility, set the orientation by it's Y/Z axis. + */ void WM_gizmo_set_matrix_offset_rotation_from_yz_axis(struct wmGizmo *gz, const float y_axis[3], const float z_axis[3]); @@ -128,14 +164,30 @@ void WM_gizmo_calc_matrix_final_no_offset(const struct wmGizmo *gz, float r_mat[ void WM_gizmo_calc_matrix_final(const struct wmGizmo *gz, float r_mat[4][4]); -/* properties */ +/* Properties. */ + void WM_gizmo_properties_create_ptr(struct PointerRNA *ptr, struct wmGizmoType *gzt); void WM_gizmo_properties_create(struct PointerRNA *ptr, const char *gtstring); +/** + * Similar to #WM_gizmo_properties_create + * except its uses ID properties used for key-maps and macros. + */ void WM_gizmo_properties_alloc(struct PointerRNA **ptr, struct IDProperty **properties, const char *gtstring); void WM_gizmo_properties_sanitize(struct PointerRNA *ptr, const bool no_context); +/** + * Set all props to their default. + * + * \param do_update: Only update un-initialized props. + * + * \note There's nothing specific to gizmos here. + * This could be made a general function. + */ bool WM_gizmo_properties_default(struct PointerRNA *ptr, const bool do_update); +/** + * Remove all props without #PROP_SKIP_SAVE. + */ void WM_gizmo_properties_reset(struct wmGizmo *gz); void WM_gizmo_properties_clear(struct PointerRNA *ptr); void WM_gizmo_properties_free(struct PointerRNA *ptr); @@ -146,7 +198,13 @@ void WM_gizmotype_append(void (*gtfunc)(struct wmGizmoType *)); void WM_gizmotype_append_ptr(void (*gtfunc)(struct wmGizmoType *, void *), void *userdata); bool WM_gizmotype_remove(struct bContext *C, struct Main *bmain, const char *idname); void WM_gizmotype_remove_ptr(struct bContext *C, struct Main *bmain, struct wmGizmoType *gzt); +/** + * Free but don't remove from ghash. + */ void WM_gizmotype_free_ptr(struct wmGizmoType *gzt); +/** + * Caller must free. + */ void WM_gizmotype_iter(struct GHashIterator *ghi); /* wm_gizmo_group_type.c */ @@ -155,8 +213,15 @@ struct wmGizmoGroupType *WM_gizmogrouptype_append(void (*wtfunc)(struct wmGizmoG struct wmGizmoGroupType *WM_gizmogrouptype_append_ptr(void (*wtfunc)(struct wmGizmoGroupType *, void *), void *userdata); +/** + * Caller must free. + */ void WM_gizmogrouptype_iter(struct GHashIterator *ghi); +/** + * Append and insert into a gizmo typemap. + * This is most common for C gizmos which are enabled by default. + */ struct wmGizmoGroupTypeRef *WM_gizmogrouptype_append_and_link( struct wmGizmoMapType *gzmap_type, void (*wtfunc)(struct wmGizmoGroupType *)); @@ -167,6 +232,10 @@ void WM_gizmoconfig_update_tag_group_type_init(struct wmGizmoMapType *gzmap_type struct wmGizmoGroupType *gzgt); void WM_gizmoconfig_update_tag_group_type_remove(struct wmGizmoMapType *gzmap_type, struct wmGizmoGroupType *gzgt); +/** + * Run in case new types have been added (runs often, early exit where possible). + * Follows #WM_keyconfig_update conventions. + */ void WM_gizmoconfig_update(struct Main *bmain); void WM_gizmoconfig_update_tag_group_remove(struct wmGizmoMap *gzmap); @@ -222,7 +291,8 @@ bool WM_gizmo_target_property_float_range_get(const struct wmGizmo *gz, int WM_gizmo_target_property_array_length(const struct wmGizmo *gz, struct wmGizmoProperty *gz_prop); -/* definitions */ +/* Definitions. */ + const struct wmGizmoPropertyType *WM_gizmotype_target_property_find(const struct wmGizmoType *gzt, const char *idname); void WM_gizmotype_target_property_def(struct wmGizmoType *gzt, @@ -230,14 +300,21 @@ void WM_gizmotype_target_property_def(struct wmGizmoType *gzt, int data_type, int array_length); -/* utilities */ +/* Utilities. */ + void WM_gizmo_do_msg_notify_tag_refresh(struct bContext *C, struct wmMsgSubscribeKey *msg_key, struct wmMsgSubscribeValue *msg_val); +/** + * Runs on the "prepare draw" pass, drawing the region clears. + */ void WM_gizmo_target_property_subscribe_all(struct wmGizmo *gz, struct wmMsgBus *mbus, struct ARegion *region); +/** + * Auto-key function if auto-key is enabled. + */ void WM_gizmo_target_property_anim_autokey(struct bContext *C, const struct wmGizmo *gz, struct wmGizmoProperty *gz_prop); @@ -256,6 +333,7 @@ struct wmKeyMap *WM_gizmogroup_setup_keymap_generic_maybe_drag(const struct wmGi struct wmKeyConfig *kc); /* Utility functions (not callbacks). */ + struct wmKeyMap *WM_gizmo_keymap_generic_with_keyconfig(struct wmKeyConfig *kc); struct wmKeyMap *WM_gizmo_keymap_generic(struct wmWindowManager *wm); @@ -268,19 +346,29 @@ struct wmKeyMap *WM_gizmo_keymap_generic_drag(struct wmWindowManager *wm); struct wmKeyMap *WM_gizmo_keymap_generic_click_drag_with_keyconfig(struct wmKeyConfig *kc); struct wmKeyMap *WM_gizmo_keymap_generic_click_drag(struct wmWindowManager *wm); +/** + * Drag or press depending on preference. + */ struct wmKeyMap *WM_gizmo_keymap_generic_maybe_drag_with_keyconfig(struct wmKeyConfig *kc); struct wmKeyMap *WM_gizmo_keymap_generic_maybe_drag(struct wmWindowManager *wm); void WM_gizmogroup_ensure_init(const struct bContext *C, struct wmGizmoGroup *gzgroup); /* Sort utilities for use with 'BLI_listbase_sort'. */ + int WM_gizmo_cmp_temp_fl(const void *gz_a_ptr, const void *gz_b_ptr); int WM_gizmo_cmp_temp_fl_reverse(const void *gz_a_ptr, const void *gz_b_ptr); /* -------------------------------------------------------------------- */ /* wmGizmoMap */ +/** + * Creates a gizmo-map with all registered gizmos for that type + */ struct wmGizmoMap *WM_gizmomap_new_from_type(const struct wmGizmoMapType_Params *gzmap_params); +/** + * Re-create the gizmos (use when changing theme settings). + */ void WM_gizmomap_reinit(struct wmGizmoMap *gzmap); const struct ListBase *WM_gizmomap_group_list(struct wmGizmoMap *gzmap); struct wmGizmoGroup *WM_gizmomap_group_find(struct wmGizmoMap *gzmap, const char *idname); @@ -298,6 +386,12 @@ void WM_gizmomap_draw(struct wmGizmoMap *gzmap, const struct bContext *C, const eWM_GizmoFlagMapDrawStep drawstep); void WM_gizmomap_add_handlers(struct ARegion *region, struct wmGizmoMap *gzmap); +/** + * Select/Deselect all selectable gizmos in \a gzmap. + * \return if selection has changed. + * + * TODO: select all by type. + */ bool WM_gizmomap_select_all(struct bContext *C, struct wmGizmoMap *gzmap, const int action); bool WM_gizmomap_cursor_set(const struct wmGizmoMap *gzmap, struct wmWindow *win); void WM_gizmomap_message_subscribe(const struct bContext *C, @@ -305,6 +399,9 @@ void WM_gizmomap_message_subscribe(const struct bContext *C, struct ARegion *region, struct wmMsgBus *mbus); bool WM_gizmomap_is_any_selected(const struct wmGizmoMap *gzmap); +/** + * \note We could use a callback to define bounds, for now just use matrix location. + */ bool WM_gizmomap_minmax(const struct wmGizmoMap *gzmap, bool use_hidden, bool use_select, @@ -327,6 +424,10 @@ struct wmGizmoGroupTypeRef *WM_gizmomaptype_group_find(struct wmGizmoMapType *gz const char *idname); struct wmGizmoGroupTypeRef *WM_gizmomaptype_group_find_ptr(struct wmGizmoMapType *gzmap_type, const struct wmGizmoGroupType *gzgt); +/** + * Use this for registering gizmos on startup. + * For runtime, use #WM_gizmomaptype_group_link_runtime. + */ struct wmGizmoGroupTypeRef *WM_gizmomaptype_group_link(struct wmGizmoMapType *gzmap_type, const char *idname); struct wmGizmoGroupTypeRef *WM_gizmomaptype_group_link_ptr(struct wmGizmoMapType *gzmap_type, @@ -345,6 +446,9 @@ void WM_gizmomaptype_group_unlink(struct bContext *C, struct wmGizmoMapType *gzmap_type, const struct wmGizmoGroupType *gzgt); +/** + * Unlike #WM_gizmomaptype_group_unlink this doesn't maintain correct state, simply free. + */ void WM_gizmomaptype_group_free(struct wmGizmoGroupTypeRef *gzgt); /* -------------------------------------------------------------------- */ @@ -362,6 +466,9 @@ bool WM_gizmo_group_type_ensure_ptr_ex(struct wmGizmoGroupType *gzgt, bool WM_gizmo_group_type_ensure_ptr(struct wmGizmoGroupType *gzgt); bool WM_gizmo_group_type_ensure(const char *idname); +/** + * Call #WM_gizmo_group_type_free_ptr after to remove & free. + */ void WM_gizmo_group_type_remove_ptr_ex(struct Main *bmain, struct wmGizmoGroupType *gzgt, struct wmGizmoMapType *gzmap_type); @@ -380,7 +487,9 @@ void WM_gizmo_group_unlink_delayed_ptr_from_space(struct wmGizmoGroupType *gzgt, void WM_gizmo_group_type_free_ptr(wmGizmoGroupType *gzgt); bool WM_gizmo_group_type_free(const char *idname); -/* Has the result of unlinking and linking (re-initializes gizmo's). */ +/** + * Has the result of unlinking and linking (re-initializes gizmo's). + */ void WM_gizmo_group_type_reinit_ptr_ex(struct Main *bmain, struct wmGizmoGroupType *gzgt, struct wmGizmoMapType *gzmap_type); @@ -388,6 +497,7 @@ void WM_gizmo_group_type_reinit_ptr(struct Main *bmain, struct wmGizmoGroupType void WM_gizmo_group_type_reinit(struct Main *bmain, const char *idname); /* Utilities */ + bool WM_gizmo_context_check_drawstep(const struct bContext *C, eWM_GizmoFlagMapDrawStep step); void WM_gizmo_group_remove_by_tool(struct bContext *C, @@ -398,6 +508,7 @@ void WM_gizmo_group_remove_by_tool(struct bContext *C, void WM_gizmo_group_tag_remove(struct wmGizmoGroup *gzgroup); /* Wrap Group Type Callbacks. */ + bool WM_gizmo_group_type_poll(const struct bContext *C, const struct wmGizmoGroupType *gzgt); void WM_gizmo_group_refresh(const struct bContext *C, struct wmGizmoGroup *gzgroup); diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo.c index cfedd67b2f0..d4f11c79d46 100644 --- a/source/blender/windowmanager/gizmo/intern/wm_gizmo.c +++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo.c @@ -106,11 +106,6 @@ wmGizmo *WM_gizmo_new_ptr(const wmGizmoType *gzt, wmGizmoGroup *gzgroup, Pointer return gz; } -/** - * \param idname: Must be a valid gizmo type name, - * if you need to check it exists use #WM_gizmo_new_ptr - * because callers of this function don't NULL check the return value. - */ wmGizmo *WM_gizmo_new(const char *idname, wmGizmoGroup *gzgroup, PointerRNA *properties) { const wmGizmoType *gzt = WM_gizmotype_find(idname, false); @@ -143,11 +138,6 @@ static void wm_gizmo_register(wmGizmoGroup *gzgroup, wmGizmo *gz) wm_gizmogroup_gizmo_register(gzgroup, gz); } -/** - * \warning this doesn't check #wmGizmoMap (highlight, selection etc). - * Typical use is when freeing the windowing data, - * where caller can manage clearing selection, highlight... etc. - */ void WM_gizmo_free(wmGizmo *gz) { if (gz->type->free != NULL) { @@ -187,10 +177,6 @@ void WM_gizmo_free(wmGizmo *gz) MEM_freeN(gz); } -/** - * Free \a gizmo and unlink from \a gizmolist. - * \a gizmolist is allowed to be NULL. - */ void WM_gizmo_unlink(ListBase *gizmolist, wmGizmoMap *gzmap, wmGizmo *gz, bContext *C) { if (gz->state & WM_GIZMO_STATE_HIGHLIGHT) { @@ -300,9 +286,6 @@ static void wm_gizmo_set_matrix_rotation_from_yz_axis__internal(float matrix[4][ normalize_v3(matrix[0]); } -/** - * wmGizmo.matrix utils. - */ void WM_gizmo_set_matrix_rotation_from_z_axis(wmGizmo *gz, const float z_axis[3]) { wm_gizmo_set_matrix_rotation_from_z_axis__internal(gz->matrix_basis, z_axis); @@ -318,9 +301,6 @@ void WM_gizmo_set_matrix_location(wmGizmo *gz, const float origin[3]) copy_v3_v3(gz->matrix_basis[3], origin); } -/** - * wmGizmo.matrix_offset utils. - */ void WM_gizmo_set_matrix_offset_rotation_from_z_axis(wmGizmo *gz, const float z_axis[3]) { wm_gizmo_set_matrix_rotation_from_z_axis__internal(gz->matrix_offset, z_axis); @@ -388,12 +368,7 @@ void WM_gizmo_set_fn_custom_modal(struct wmGizmo *gz, wmGizmoFnModal fn) /** \} */ /* -------------------------------------------------------------------- */ -/** - * Add/Remove \a gizmo to selection. - * Reallocates memory for selected gizmos so better not call for selecting multiple ones. - * - * \return if the selection has changed. - */ + bool wm_gizmo_select_set_ex( wmGizmoMap *gzmap, wmGizmo *gz, bool select, bool use_array, bool use_callback) { @@ -429,7 +404,6 @@ bool wm_gizmo_select_set_ex( return changed; } -/* Remove from selection array without running callbacks. */ bool WM_gizmo_select_unlink(wmGizmoMap *gzmap, wmGizmo *gz) { return wm_gizmo_select_set_ex(gzmap, gz, false, true, false); @@ -454,12 +428,6 @@ bool wm_gizmo_select_and_highlight(bContext *C, wmGizmoMap *gzmap, wmGizmo *gz) return false; } -/** - * Special function to run from setup so gizmos start out interactive. - * - * We could do this when linking them, - * but this complicates things since the window update code needs to run first. - */ void WM_gizmo_modal_set_from_setup(struct wmGizmoMap *gzmap, struct bContext *C, struct wmGizmo *gz, @@ -634,8 +602,6 @@ void WM_gizmo_properties_create(PointerRNA *ptr, const char *gtstring) } } -/* similar to the function above except its uses ID properties - * used for keymaps and macros */ void WM_gizmo_properties_alloc(PointerRNA **ptr, IDProperty **properties, const char *gtstring) { if (*properties == NULL) { @@ -680,14 +646,6 @@ void WM_gizmo_properties_sanitize(PointerRNA *ptr, const bool no_context) RNA_STRUCT_END; } -/** - * Set all props to their default. - * - * \param do_update: Only update un-initialized props. - * - * \note There's nothing specific to gizmos here. - * This could be made a general function. - */ bool WM_gizmo_properties_default(PointerRNA *ptr, const bool do_update) { bool changed = false; @@ -715,7 +673,6 @@ bool WM_gizmo_properties_default(PointerRNA *ptr, const bool do_update) return changed; } -/* remove all props without PROP_SKIP_SAVE */ void WM_gizmo_properties_reset(wmGizmo *gz) { if (gz->ptr->data) { diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c index b6d759eb95f..6f10e4f3f0d 100644 --- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c +++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c @@ -63,9 +63,6 @@ /** \name wmGizmoGroup * \{ */ -/** - * Create a new gizmo-group from \a gzgt. - */ wmGizmoGroup *wm_gizmogroup_new_from_type(wmGizmoMap *gzmap, wmGizmoGroupType *gzgt) { wmGizmoGroup *gzgroup = MEM_callocN(sizeof(*gzgroup), "gizmo-group"); @@ -148,9 +145,6 @@ void WM_gizmo_group_tag_remove(wmGizmoGroup *gzgroup) } } -/** - * Add \a gizmo to \a gzgroup and make sure its name is unique within the group. - */ void wm_gizmogroup_gizmo_register(wmGizmoGroup *gzgroup, wmGizmo *gz) { BLI_assert(BLI_findindex(&gzgroup->gizmos, gz) == -1); @@ -234,10 +228,6 @@ wmGizmo *wm_gizmogroup_find_intersected_gizmo(wmWindowManager *wm, return NULL; } -/** - * Adds all gizmos of \a gzgroup that can be selected to the head of \a listbase. - * Added items need freeing! - */ void wm_gizmogroup_intersectable_gizmos_to_list(wmWindowManager *wm, const wmGizmoGroup *gzgroup, const int event_modifier, @@ -345,10 +335,9 @@ bool wm_gizmogroup_is_any_selected(const wmGizmoGroup *gzgroup) /** \} */ /* -------------------------------------------------------------------- */ -/** \name Gizmo operators +/** \name Gizmo Operators * * Basic operators for gizmo interaction with user configurable keymaps. - * * \{ */ static int gizmo_select_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) @@ -641,8 +630,6 @@ void GIZMOGROUP_OT_gizmo_tweak(wmOperatorType *ot) #endif } -/** \} */ - wmKeyMap *wm_gizmogroup_tweak_modal_keymap(wmKeyConfig *keyconf) { wmKeyMap *keymap; @@ -774,11 +761,12 @@ wmKeyMap *WM_gizmogroup_setup_keymap_generic_select(const wmGizmoGroupType *UNUS return WM_gizmogroup_keymap_template_select_ex(kc, "Generic Gizmo Select", ¶ms); } +/** \} */ + /* -------------------------------------------------------------------- */ /** \name wmGizmo (Key-map access) * * Key config version so these can be called from #wmGizmoGroupFnSetupKeymap. - * * \{ */ struct wmKeyMap *WM_gizmo_keymap_generic_with_keyconfig(wmKeyConfig *kc) @@ -821,7 +809,6 @@ struct wmKeyMap *WM_gizmo_keymap_generic_click_drag(wmWindowManager *wm) return WM_gizmo_keymap_generic_click_drag_with_keyconfig(wm->defaultconf); } -/** Drag or press depending on preference. */ struct wmKeyMap *WM_gizmo_keymap_generic_maybe_drag_with_keyconfig(wmKeyConfig *kc) { const char *idname = "Generic Gizmo Maybe Drag"; @@ -862,10 +849,6 @@ struct wmGizmoGroupTypeRef *WM_gizmomaptype_group_find(struct wmGizmoMapType *gz return NULL; } -/** - * Use this for registering gizmos on startup. - * For runtime, use #WM_gizmomaptype_group_link_runtime. - */ wmGizmoGroupTypeRef *WM_gizmomaptype_group_link(wmGizmoMapType *gzmap_type, const char *idname) { wmGizmoGroupType *gzgt = WM_gizmogrouptype_find(idname, false); @@ -939,9 +922,6 @@ wmGizmoGroup *WM_gizmomaptype_group_init_runtime_with_region(wmGizmoMapType *gzm return gzgroup; } -/** - * Unlike #WM_gizmomaptype_group_unlink this doesn't maintain correct state, simply free. - */ void WM_gizmomaptype_group_free(wmGizmoGroupTypeRef *gzgt_ref) { MEM_freeN(gzgt_ref); @@ -1017,7 +997,6 @@ void wm_gizmogrouptype_setup_keymap(wmGizmoGroupType *gzgt, wmKeyConfig *keyconf * but for general purpose API this is too detailed & annoying. * * \note We may want to return a value if there is nothing to remove. - * * \{ */ void WM_gizmo_group_type_add_ptr_ex(wmGizmoGroupType *gzgt, wmGizmoMapType *gzmap_type) @@ -1059,9 +1038,6 @@ bool WM_gizmo_group_type_ensure(const char *idname) return WM_gizmo_group_type_ensure_ptr(gzgt); } -/** - * Call #WM_gizmo_group_type_free_ptr after to remove & free. - */ void WM_gizmo_group_type_remove_ptr_ex(struct Main *bmain, wmGizmoGroupType *gzgt, wmGizmoMapType *gzmap_type) 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 6a793d52f74..0a36068bb21 100644 --- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_group_type.c +++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_group_type.c @@ -71,7 +71,6 @@ wmGizmoGroupType *WM_gizmogrouptype_find(const char *idname, bool quiet) return NULL; } -/* caller must free */ void WM_gizmogrouptype_iter(GHashIterator *ghi) { BLI_ghashIterator_init(ghi, global_gizmogrouptype_hash); @@ -127,10 +126,6 @@ wmGizmoGroupType *WM_gizmogrouptype_append_ptr(void (*wtfunc)(struct wmGizmoGrou return gzgt; } -/** - * Append and insert into a gizmo typemap. - * This is most common for C gizmos which are enabled by default. - */ wmGizmoGroupTypeRef *WM_gizmogrouptype_append_and_link(wmGizmoMapType *gzmap_type, void (*wtfunc)(struct wmGizmoGroupType *)) { @@ -190,7 +185,6 @@ void wm_gizmogrouptype_free(void) global_gizmogrouptype_hash = NULL; } -/* called on initialize WM_init() */ void wm_gizmogrouptype_init(void) { /* reserve size is set based on blender default setup */ diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_intern.h b/source/blender/windowmanager/gizmo/intern/wm_gizmo_intern.h index dd2db209771..b6912d79076 100644 --- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_intern.h +++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_intern.h @@ -29,6 +29,12 @@ struct wmKeyConfig; /* -------------------------------------------------------------------- */ /* wmGizmo */ +/** + * Add/Remove \a gizmo to selection. + * Reallocates memory for selected gizmos so better not call for selecting multiple ones. + * + * \return if the selection has changed. + */ bool wm_gizmo_select_set_ex( struct wmGizmoMap *gzmap, struct wmGizmo *gz, bool select, bool use_array, bool use_callback); bool wm_gizmo_select_and_highlight(bContext *C, struct wmGizmoMap *gzmap, struct wmGizmo *gz); @@ -54,9 +60,15 @@ enum { TWEAK_MODAL_SNAP_OFF, }; +/** + * Create a new gizmo-group from \a gzgt. + */ struct wmGizmoGroup *wm_gizmogroup_new_from_type(struct wmGizmoMap *gzmap, struct wmGizmoGroupType *gzgt); void wm_gizmogroup_free(bContext *C, struct wmGizmoGroup *gzgroup); +/** + * Add \a gizmo to \a gzgroup and make sure its name is unique within the group. + */ void wm_gizmogroup_gizmo_register(struct wmGizmoGroup *gzgroup, struct wmGizmo *gz); struct wmGizmoGroup *wm_gizmogroup_find_by_type(const struct wmGizmoMap *gzmap, const struct wmGizmoGroupType *gzgt); @@ -66,6 +78,10 @@ struct wmGizmo *wm_gizmogroup_find_intersected_gizmo(wmWindowManager *wm, const int event_modifier, const int mval[2], int *r_part); +/** + * Adds all gizmos of \a gzgroup that can be selected to the head of \a listbase. + * Added items need freeing! + */ void wm_gizmogroup_intersectable_gizmos_to_list(wmWindowManager *wm, const struct wmGizmoGroup *gzgroup, const int event_modifier, @@ -137,6 +153,10 @@ struct wmGizmoMapType { }; void wm_gizmomap_select_array_clear(struct wmGizmoMap *gzmap); +/** + * Deselect all selected gizmos in \a gzmap. + * \return if selection has changed. + */ bool wm_gizmomap_deselect_all(struct wmGizmoMap *gzmap); void wm_gizmomap_select_array_shrink(struct wmGizmoMap *gzmap, int len_subtract); void wm_gizmomap_select_array_push_back(struct wmGizmoMap *gzmap, wmGizmo *gz); diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c index 6f952bc9526..d3e682f1490 100644 --- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c +++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c @@ -176,9 +176,6 @@ static wmGizmoMap *wm_gizmomap_new_from_type_ex(struct wmGizmoMapType *gzmap_typ return gzmap; } -/** - * Creates a gizmo-map with all registered gizmos for that type - */ wmGizmoMap *WM_gizmomap_new_from_type(const struct wmGizmoMapType_Params *gzmap_params) { wmGizmoMapType *gzmap_type = WM_gizmomaptype_ensure(gzmap_params); @@ -207,7 +204,6 @@ void wm_gizmomap_remove(wmGizmoMap *gzmap) MEM_freeN(gzmap); } -/** Re-create the gizmos (use when changing theme settings). */ void WM_gizmomap_reinit(wmGizmoMap *gzmap) { wmGizmoMapType *gzmap_type = gzmap->type; @@ -246,9 +242,6 @@ bool WM_gizmomap_is_any_selected(const wmGizmoMap *gzmap) return gzmap->gzmap_context.select.len != 0; } -/** - * \note We could use a callback to define bounds, for now just use matrix location. - */ bool WM_gizmomap_minmax(const wmGizmoMap *gzmap, bool UNUSED(use_hidden), bool use_select, @@ -713,10 +706,6 @@ static wmGizmo *gizmo_find_intersected_3d(bContext *C, return result; } -/** - * Try to find a gizmo under the mouse position. 2D intersections have priority over - * 3D ones (could check for smallest screen-space distance but not needed right now). - */ wmGizmo *wm_gizmomap_highlight_find(wmGizmoMap *gzmap, bContext *C, const wmEvent *event, @@ -843,10 +832,6 @@ void wm_gizmomaps_handled_modal_update(bContext *C, wmEvent *event, wmEventHandl CTX_wm_region_set(C, region); } -/** - * Deselect all selected gizmos in \a gzmap. - * \return if selection has changed. - */ bool wm_gizmomap_deselect_all(wmGizmoMap *gzmap) { wmGizmoMapSelectState *msel = &gzmap->gzmap_context.select; @@ -903,12 +888,6 @@ static bool wm_gizmomap_select_all_intern(bContext *C, wmGizmoMap *gzmap) return changed; } -/** - * Select/Deselect all selectable gizmos in \a gzmap. - * \return if selection has changed. - * - * TODO: select all by type. - */ bool WM_gizmomap_select_all(bContext *C, wmGizmoMap *gzmap, const int action) { bool changed = false; @@ -932,10 +911,6 @@ bool WM_gizmomap_select_all(bContext *C, wmGizmoMap *gzmap, const int action) return changed; } -/** - * Prepare context for gizmo handling (but only if area/region is - * part of screen). Version of #wm_handler_op_context for gizmos. - */ void wm_gizmomap_handler_context_op(bContext *C, wmEventHandler_Op *handler) { bScreen *screen = CTX_wm_screen(C); @@ -1037,9 +1012,6 @@ wmGizmo *wm_gizmomap_highlight_get(wmGizmoMap *gzmap) return gzmap->gzmap_context.highlight; } -/** - * Caller should call exit when (enable == False). - */ void wm_gizmomap_modal_set( wmGizmoMap *gzmap, bContext *C, wmGizmo *gz, const wmEvent *event, bool enable) { @@ -1247,9 +1219,6 @@ void wm_gizmomaptypes_free(void) } } -/** - * Initialize keymaps for all existing gizmo-groups - */ void wm_gizmos_keymap(wmKeyConfig *keyconf) { LISTBASE_FOREACH (wmGizmoMapType *, gzmap_type, &gizmomaptypes) { @@ -1293,10 +1262,6 @@ void WM_gizmoconfig_update_tag_group_remove(wmGizmoMap *gzmap) wm_gzmap_type_update_flag |= WM_GIZMOTYPE_GLOBAL_UPDATE_REMOVE; } -/** - * Run in case new types have been added (runs often, early exit where possible). - * Follows #WM_keyconfig_update conventions. - */ void WM_gizmoconfig_update(struct Main *bmain) { if (G.background) { diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_target_props.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_target_props.c index 63e833d73c3..57555fb5416 100644 --- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_target_props.c +++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_target_props.c @@ -319,10 +319,6 @@ void WM_gizmo_do_msg_notify_tag_refresh(bContext *UNUSED(C), WM_gizmomap_tag_refresh(gzmap); } -/** - * Runs on the "prepare draw" pass, - * drawing the region clears. - */ void WM_gizmo_target_property_subscribe_all(wmGizmo *gz, struct wmMsgBus *mbus, ARegion *region) { if (gz->type->target_property_defs_len) { @@ -355,9 +351,6 @@ void WM_gizmo_target_property_subscribe_all(wmGizmo *gz, struct wmMsgBus *mbus, } } -/** - * Auto-key function if auto-key is enabled. - */ void WM_gizmo_target_property_anim_autokey(bContext *C, const wmGizmo *UNUSED(gz), wmGizmoProperty *gz_prop) diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_type.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_type.c index 1523246d08b..602100a624e 100644 --- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_type.c +++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_type.c @@ -78,7 +78,6 @@ const wmGizmoType *WM_gizmotype_find(const char *idname, bool quiet) return NULL; } -/* caller must free */ void WM_gizmotype_iter(GHashIterator *ghi) { BLI_ghashIterator_init(ghi, global_gizmotype_hash); @@ -118,9 +117,6 @@ void WM_gizmotype_append_ptr(void (*gtfunc)(struct wmGizmoType *, void *), void wm_gizmotype_append__end(mt); } -/** - * Free but don't remove from ghash. - */ void WM_gizmotype_free_ptr(wmGizmoType *gzt) { if (gzt->rna_ext.srna) { /* python gizmo, allocs own string */ @@ -195,7 +191,6 @@ void wm_gizmotype_free(void) global_gizmotype_hash = NULL; } -/* called on initialize WM_init() */ void wm_gizmotype_init(void) { /* reserve size is set based on blender default setup */ diff --git a/source/blender/windowmanager/gizmo/wm_gizmo_wmapi.h b/source/blender/windowmanager/gizmo/wm_gizmo_wmapi.h index 18b3f40aba6..0612ba97db0 100644 --- a/source/blender/windowmanager/gizmo/wm_gizmo_wmapi.h +++ b/source/blender/windowmanager/gizmo/wm_gizmo_wmapi.h @@ -40,37 +40,63 @@ extern "C" { #endif /* -------------------------------------------------------------------- */ -/* wmGizmo */ +/** \name #wmGizmo + * \{ */ /* wm_gizmo_type.c, for init/exit */ + void wm_gizmotype_free(void); +/** + * Called on initialize #WM_init(). + */ void wm_gizmotype_init(void); /* wm_gizmogroup_type.c, for init/exit */ + void wm_gizmogrouptype_free(void); +/** + * Called on initialize #WM_init(). + */ void wm_gizmogrouptype_init(void); +/** \} */ + /* -------------------------------------------------------------------- */ -/* wmGizmoGroup */ +/** \name #wmGizmoGroup + * \{ */ void GIZMOGROUP_OT_gizmo_select(struct wmOperatorType *ot); void GIZMOGROUP_OT_gizmo_tweak(struct wmOperatorType *ot); bool wm_gizmogroup_is_any_selected(const struct wmGizmoGroup *gzgroup); +/** \} */ + /* -------------------------------------------------------------------- */ -/* wmGizmoMap */ +/** \name #wmGizmoMap + * \{ */ void wm_gizmomap_remove(struct wmGizmoMap *gzmap); +/** + * Initialize key-maps for all existing gizmo-groups + */ void wm_gizmos_keymap(struct wmKeyConfig *keyconf); void wm_gizmomaps_handled_modal_update(bContext *C, struct wmEvent *event, struct wmEventHandler_Op *handler); +/** + * Prepare context for gizmo handling (but only if area/region is + * part of screen). Version of #wm_handler_op_context for gizmos. + */ void wm_gizmomap_handler_context_op(bContext *C, struct wmEventHandler_Op *handler); void wm_gizmomap_handler_context_gizmo(bContext *C, struct wmEventHandler_Gizmo *handler); +/** + * Try to find a gizmo under the mouse position. 2D intersections have priority over + * 3D ones (could check for smallest screen-space distance but not needed right now). + */ struct wmGizmo *wm_gizmomap_highlight_find(struct wmGizmoMap *gzmap, bContext *C, const struct wmEvent *event, @@ -80,6 +106,9 @@ bool wm_gizmomap_highlight_set(struct wmGizmoMap *gzmap, struct wmGizmo *gz, int part); struct wmGizmo *wm_gizmomap_highlight_get(struct wmGizmoMap *gzmap); +/** + * Caller should call exit when (enable == False). + */ void wm_gizmomap_modal_set(struct wmGizmoMap *gzmap, bContext *C, struct wmGizmo *gz, @@ -90,11 +119,16 @@ struct wmGizmo *wm_gizmomap_modal_get(struct wmGizmoMap *gzmap); struct wmGizmo **wm_gizmomap_selected_get(wmGizmoMap *gzmap, int *r_selected_len); struct ListBase *wm_gizmomap_groups_get(wmGizmoMap *gzmap); +/** \} */ + /* -------------------------------------------------------------------- */ -/* wmGizmoMapType */ +/** \name #wmGizmoMapType + * \{ */ void wm_gizmomaptypes_free(void); +/** \} */ + #ifdef __cplusplus } #endif diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c index 47ee296823b..40f8da63e11 100644 --- a/source/blender/windowmanager/intern/wm.c +++ b/source/blender/windowmanager/intern/wm.c @@ -272,6 +272,7 @@ IDTypeInfo IDType_ID_WM = { .name_plural = "window_managers", .translation_context = BLT_I18NCONTEXT_ID_WINDOWMANAGER, .flags = IDTYPE_FLAGS_NO_COPY | IDTYPE_FLAGS_NO_LIBLINKING | IDTYPE_FLAGS_NO_ANIMDATA, + .asset_type_info = NULL, .init_data = NULL, .copy_data = NULL, @@ -279,6 +280,7 @@ IDTypeInfo IDType_ID_WM = { .make_local = NULL, .foreach_id = window_manager_foreach_id, .foreach_cache = NULL, + .foreach_path = NULL, .owner_get = NULL, .blend_write = window_manager_blend_write, @@ -339,13 +341,6 @@ void WM_operator_free_all_after(wmWindowManager *wm, struct wmOperator *op) } } -/** - * Use with extreme care!, - * properties, custom-data etc - must be compatible. - * - * \param op: Operator to assign the type to. - * \param ot: Operator type to assign. - */ void WM_operator_type_set(wmOperator *op, wmOperatorType *ot) { /* Not supported for Python. */ @@ -375,8 +370,6 @@ static void wm_reports_free(wmWindowManager *wm) WM_event_remove_timer(wm, NULL, wm->reports.reporttimer); } -/* All operations get registered in the windowmanager here. */ -/* Called on event handling by event_system.c. */ void wm_operator_register(bContext *C, wmOperator *op) { wmWindowManager *wm = CTX_wm_manager(C); @@ -413,10 +406,6 @@ void WM_operator_stack_clear(wmWindowManager *wm) WM_main_add_notifier(NC_WM | ND_HISTORY, NULL); } -/** - * This function is needed in the case when an addon id disabled - * while a modal operator it defined is running. - */ void WM_operator_handlers_clear(wmWindowManager *wm, wmOperatorType *ot) { LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { @@ -549,7 +538,6 @@ void wm_clear_default_size(bContext *C) } } -/* On startup, it adds all data, for matching. */ void wm_add_default(Main *bmain, bContext *C) { wmWindowManager *wm = BKE_libblock_alloc(bmain, ID_WM, "WinMan", 0); @@ -571,7 +559,6 @@ void wm_add_default(Main *bmain, bContext *C) wm_window_make_drawable(wm, win); } -/* Context is allowed to be NULL, do not free wm itself (lib_id.c). */ void wm_close_and_free(bContext *C, wmWindowManager *wm) { if (wm->autosavetimer) { diff --git a/source/blender/windowmanager/intern/wm_cursors.c b/source/blender/windowmanager/intern/wm_cursors.c index 9c020b16234..74ec2bcd41f 100644 --- a/source/blender/windowmanager/intern/wm_cursors.c +++ b/source/blender/windowmanager/intern/wm_cursors.c @@ -222,7 +222,6 @@ void WM_cursor_modal_restore(wmWindow *win) win->lastcursor = 0; } -/* to allow usage all over, we do entire WM */ void WM_cursor_wait(bool val) { if (!G.background) { @@ -240,9 +239,6 @@ void WM_cursor_wait(bool val) } } -/** - * \param bounds: can be NULL - */ void WM_cursor_grab_enable(wmWindow *win, int wrap, bool hide, int bounds[4]) { /* Only grab cursor when not running debug. @@ -307,9 +303,10 @@ static void wm_cursor_warp_relative(wmWindow *win, int x, int y) WM_cursor_warp(win, cx + x, cy + y); } -/* give it a modal keymap one day? */ bool wm_cursor_arrow_move(wmWindow *win, const wmEvent *event) { + /* TODO: give it a modal keymap? Hard coded for now */ + if (win && event->val == KM_PRESS) { /* Must move at least this much to avoid rounding in WM_cursor_warp. */ float fac = GHOST_GetNativePixelSize(win->ghostwin); @@ -334,7 +331,6 @@ bool wm_cursor_arrow_move(wmWindow *win, const wmEvent *event) return 0; } -/* after this you can call restore too */ void WM_cursor_time(wmWindow *win, int nr) { /* 10 8x8 digits */ diff --git a/source/blender/windowmanager/intern/wm_dragdrop.c b/source/blender/windowmanager/intern/wm_dragdrop.c index bc87347b2f3..e1017c4236e 100644 --- a/source/blender/windowmanager/intern/wm_dragdrop.c +++ b/source/blender/windowmanager/intern/wm_dragdrop.c @@ -89,7 +89,6 @@ typedef struct wmDropBoxMap { } wmDropBoxMap; -/* spaceid/regionid is zero for window drop maps */ ListBase *WM_dropboxmap_find(const char *idname, int spaceid, int regionid) { LISTBASE_FOREACH (wmDropBoxMap *, dm, &dropboxes) { @@ -153,7 +152,6 @@ void wm_dropbox_free(void) /* *********************************** */ -/* note that the pointer should be valid allocated and not on stack */ wmDrag *WM_event_start_drag( struct bContext *C, int icon, int type, void *poin, double value, unsigned int flags) { @@ -208,11 +206,6 @@ wmDrag *WM_event_start_drag( return drag; } -/** - * Additional work to cleanly end dragging. Additional because this doesn't actually remove the - * drag items. Should be called whenever dragging is stopped (successful or not, also when - * canceled). - */ void wm_drags_exit(wmWindowManager *wm, wmWindow *win) { bool any_active = false; @@ -403,7 +396,6 @@ void wm_drop_prepare(bContext *C, wmDrag *drag, wmDropBox *drop) wm_drags_exit(CTX_wm_manager(C), CTX_wm_window(C)); } -/* called in inner handler loop, region context */ void wm_drags_check_ops(bContext *C, const wmEvent *event) { wmWindowManager *wm = CTX_wm_manager(C); @@ -424,11 +416,6 @@ void wm_drags_check_ops(bContext *C, const wmEvent *event) } } -/** - * The operator of a dropbox should always be executed in the context determined by the mouse - * coordinates. The dropbox poll should check the context area and region as needed. - * So this always returns #WM_OP_INVOKE_DEFAULT. - */ wmOperatorCallContext wm_drop_operator_context_get(const wmDropBox *UNUSED(drop)) { return WM_OP_INVOKE_DEFAULT; @@ -484,17 +471,11 @@ ID *WM_drag_get_local_ID_from_event(const wmEvent *event, short idcode) return WM_drag_get_local_ID(lb->first, idcode); } -/** - * Check if the drag data is either a local ID or an external ID asset of type \a idcode. - */ bool WM_drag_is_ID_type(const wmDrag *drag, int idcode) { return WM_drag_get_local_ID(drag, idcode) || WM_drag_get_asset_data(drag, idcode); } -/** - * \note: Does not store \a asset in any way, so it's fine to pass a temporary. - */ wmDragAsset *WM_drag_create_asset_data(const AssetHandle *asset, AssetMetaData *metadata, const char *path, @@ -542,9 +523,6 @@ struct AssetMetaData *WM_drag_get_asset_meta_data(const wmDrag *drag, int idcode return NULL; } -/** - * \param flag_extra: Additional linking flags (from #eFileSel_Params_Flag). - */ ID *WM_drag_asset_id_import(wmDragAsset *asset_drag, const int flag_extra) { /* Only support passing in limited flags. */ @@ -603,15 +581,6 @@ bool WM_drag_asset_will_import_linked(const wmDrag *drag) return asset_drag->import_type == FILE_ASSET_IMPORT_LINK; } -/** - * When dragging a local ID, return that. Otherwise, if dragging an asset-handle, link or append - * that depending on what was chosen by the drag-box (currently append only in fact). - * - * Use #WM_drag_free_imported_drag_ID() as cancel callback of the drop-box, so that the asset - * import is rolled back if the drop operator fails. - * - * \param flag: #eFileSel_Params_Flag passed to linking code. - */ ID *WM_drag_get_local_ID_or_import_from_asset(const wmDrag *drag, int idcode) { if (!ELEM(drag->type, WM_DRAG_ASSET, WM_DRAG_ID)) { @@ -631,14 +600,6 @@ ID *WM_drag_get_local_ID_or_import_from_asset(const wmDrag *drag, int idcode) return WM_drag_asset_id_import(asset_drag, 0); } -/** - * \brief Free asset ID imported for canceled drop. - * - * If the asset was imported (linked/appended) using #WM_drag_get_local_ID_or_import_from_asset()` - * (typically via a #wmDropBox.copy() callback), we want the ID to be removed again if the drop - * operator cancels. - * This is for use as #wmDropBox.cancel() callback. - */ void WM_drag_free_imported_drag_ID(struct Main *bmain, wmDrag *drag, wmDropBox *drop) { if (drag->type != WM_DRAG_ASSET) { @@ -673,9 +634,6 @@ wmDragAssetCatalog *WM_drag_get_asset_catalog_data(const wmDrag *drag) return drag->poin; } -/** - * \note: Does not store \a asset in any way, so it's fine to pass a temporary. - */ void WM_drag_add_asset_list_item( wmDrag *drag, /* Context only needed for the hack in #ED_asset_handle_get_full_library_path(). */ @@ -912,7 +870,6 @@ void WM_drag_draw_default_fn(bContext *C, wmWindow *win, wmDrag *drag, const int wm_drag_draw_default(C, win, drag, xy); } -/* Called in #wm_draw_window_onscreen. */ void wm_drags_draw(bContext *C, wmWindow *win) { int xy[2]; diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c index d8d57a9370c..ab9de6ce4d4 100644 --- a/source/blender/windowmanager/intern/wm_draw.c +++ b/source/blender/windowmanager/intern/wm_draw.c @@ -148,6 +148,7 @@ static void wm_region_draw_overlay(bContext *C, ScrArea *area, ARegion *region) } /** \} */ + /* -------------------------------------------------------------------- */ /** \name Internal Utilities * \{ */ diff --git a/source/blender/windowmanager/intern/wm_event_query.c b/source/blender/windowmanager/intern/wm_event_query.c index ef733837bf7..22cd68ddbd7 100644 --- a/source/blender/windowmanager/intern/wm_event_query.c +++ b/source/blender/windowmanager/intern/wm_event_query.c @@ -71,7 +71,6 @@ static void event_ids_from_type_and_value(const short type, } } -/* for debugging only, getting inspecting events manually is tedious */ void WM_event_print(const wmEvent *event) { if (event) { @@ -218,7 +217,6 @@ bool WM_event_type_mask_test(const int event_type, const enum eEventType_Mask ma /** \name Event Motion Queries * \{ */ -/* for modal callbacks, check configuration for how to interpret exit with tweaks. */ bool WM_event_is_modal_tweak_exit(const wmEvent *event, int tweak_event) { /* if the release-confirm userpref setting is enabled, @@ -276,20 +274,6 @@ bool WM_event_is_mouse_drag_or_press(const wmEvent *event) (ISMOUSE_BUTTON(event->type) && (event->val == KM_PRESS)); } -/** - * Detect motion between selection (callers should only use this for selection picking), - * typically mouse press/click events. - * - * \param mval: Region relative coordinates, call with (-1, -1) resets the last cursor location. - * \returns True when there was motion since last called. - * - * NOTE(@campbellbarton): The logic used here isn't foolproof. - * It's possible that users move the cursor past #WM_EVENT_CURSOR_MOTION_THRESHOLD then back to - * a position within the threshold (between mouse clicks). - * In practice users never reported this since the threshold is very small (a few pixels). - * To prevent the unlikely case of values matching from another region, - * changing regions resets this value to (-1, -1). - */ bool WM_cursor_test_motion_and_update(const int mval[2]) { static int mval_prev[2] = {-1, -1}; @@ -360,11 +344,6 @@ int WM_userdef_event_map(int kmitype) return kmitype; } -/** - * Use so we can check if 'wmEvent.type' is released in modal operators. - * - * An alternative would be to add a 'wmEvent.type_nokeymap'... or similar. - */ int WM_userdef_event_type_from_keymap_type(int kmitype) { switch (kmitype) { @@ -447,7 +426,6 @@ bool WM_event_is_xr(const struct wmEvent *event) /** \name Event Tablet Input Access * \{ */ -/* applies the global tablet pressure correction curve */ float wm_pressure_curve(float pressure) { if (U.pressure_threshold_max != 0.0f) { @@ -463,8 +441,6 @@ float wm_pressure_curve(float pressure) return pressure; } -/* if this is a tablet event, return tablet pressure and set *pen_flip - * to 1 if the eraser tool is being used, 0 otherwise */ float WM_event_tablet_data(const wmEvent *event, int *pen_flip, float tilt[2]) { if (tilt) { diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index f51c8c48c48..1b6df9fb0db 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -64,6 +64,7 @@ #include "ED_asset.h" #include "ED_fileselect.h" #include "ED_info.h" +#include "ED_render.h" #include "ED_screen.h" #include "ED_undo.h" #include "ED_util.h" @@ -83,6 +84,7 @@ #include "wm.h" #include "wm_event_system.h" #include "wm_event_types.h" +#include "wm_surface.h" #include "wm_window.h" #include "DEG_depsgraph.h" @@ -287,9 +289,6 @@ void WM_main_add_notifier(unsigned int type, void *reference) note->reference = reference; } -/** - * Clear notifiers by reference, Used so listeners don't act on freed data. - */ void WM_main_remove_notifier_reference(const void *reference) { Main *bmain = G_MAIN; @@ -384,13 +383,10 @@ void wm_event_do_depsgraph(bContext *C, bool is_after_open_file) DEG_make_active(depsgraph); BKE_scene_graph_update_tagged(depsgraph, bmain); } + + wm_surfaces_do_depsgraph(C); } -/** - * Was part of #wm_event_do_notifiers, - * split out so it can be called once before entering the #WM_main loop. - * This ensures operators don't run before the UI and depsgraph are initialized. - */ void wm_event_do_refresh_wm_and_depsgraph(bContext *C) { wmWindowManager *wm = CTX_wm_manager(C); @@ -427,7 +423,6 @@ static void wm_event_execute_timers(bContext *C) CTX_wm_window_set(C, NULL); } -/* Called in mainloop. */ void wm_event_do_notifiers(bContext *C) { /* Run the timer before assigning 'wm' in the unlikely case a timer loads a file, see T80028. */ @@ -457,6 +452,9 @@ void wm_event_do_notifiers(bContext *C) else if (note->data == ND_DATACHANGED) { wm_window_title(wm, win); } + else if (note->data == ND_UNDO) { + ED_preview_restart_queue_work(C); + } } if (note->window == win) { if (note->category == NC_SCREEN) { @@ -752,9 +750,6 @@ static void wm_event_handler_ui_cancel(bContext *C) * Access to #wmWindowManager.reports * \{ */ -/** - * Show the report in the info header. - */ void WM_report_banner_show(void) { wmWindowManager *wm = G_MAIN->wm.first; @@ -770,9 +765,6 @@ void WM_report_banner_show(void) wm_reports->reporttimer->customdata = rti; } -/** - * Hide all currently displayed banners and abort their timer. - */ void WM_report_banners_cancel(Main *bmain) { wmWindowManager *wm = bmain->wm.first; @@ -855,9 +847,9 @@ bool WM_operator_poll(bContext *C, wmOperatorType *ot) return true; } -/* sets up the new context and calls 'wm_operator_invoke()' with poll_only */ bool WM_operator_poll_context(bContext *C, wmOperatorType *ot, short context) { + /* Sets up the new context and calls #wm_operator_invoke() with poll_only. */ return wm_operator_call_internal(C, ot, NULL, NULL, context, true, NULL); } @@ -892,11 +884,6 @@ bool WM_operator_check_ui_empty(wmOperatorType *ot) return true; } -/** - * Sets the active region for this space from the context. - * - * \see #BKE_area_find_region_active_win - */ void WM_operator_region_active_win_set(bContext *C) { ScrArea *area = CTX_wm_area(C); @@ -1103,13 +1090,6 @@ static int wm_operator_exec_notest(bContext *C, wmOperator *op) return retval; } -/** - * For running operators with frozen context (modal handlers, menus). - * - * \param store: Store settings for re-use. - * - * \warning do not use this within an operator to call its self! T29537. - */ int WM_operator_call_ex(bContext *C, wmOperator *op, const bool store) { return wm_operator_exec(C, op, false, store); @@ -1120,19 +1100,11 @@ int WM_operator_call(bContext *C, wmOperator *op) return WM_operator_call_ex(C, op, false); } -/** - * This is intended to be used when an invoke operator wants to call exec on its self - * and is basically like running op->type->exec() directly, no poll checks no freeing, - * since we assume whoever called invoke will take care of that - */ int WM_operator_call_notest(bContext *C, wmOperator *op) { return wm_operator_exec_notest(C, op); } -/** - * Execute this operator again, put here so it can share above code - */ int WM_operator_repeat(bContext *C, wmOperator *op) { const int op_flag = OP_IS_REPEAT; @@ -1149,12 +1121,6 @@ int WM_operator_repeat_last(bContext *C, wmOperator *op) op->flag &= ~op_flag; return ret; } -/** - * \return true if #WM_operator_repeat can run. - * Simple check for now but may become more involved. - * To be sure the operator can run call `WM_operator_poll(C, op->type)` also, since this call - * checks if #WM_operator_repeat() can run at all, not that it WILL run at any time. - */ bool WM_operator_repeat_check(const bContext *UNUSED(C), wmOperator *op) { if (op->type->exec != NULL) { @@ -1592,7 +1558,6 @@ static int wm_operator_call_internal(bContext *C, return 0; } -/* Invokes operator in context. */ int WM_operator_name_call_ptr(bContext *C, wmOperatorType *ot, wmOperatorCallContext context, @@ -1614,6 +1579,16 @@ int WM_operator_name_call(bContext *C, return 0; } +bool WM_operator_name_poll(bContext *C, const char *opstring) +{ + wmOperatorType *ot = WM_operatortype_find(opstring, 0); + if (!ot) { + return false; + } + + return WM_operator_poll(C, ot); +} + int WM_operator_name_call_with_properties(struct bContext *C, const char *opstring, wmOperatorCallContext context, @@ -1625,9 +1600,6 @@ int WM_operator_name_call_with_properties(struct bContext *C, return WM_operator_name_call_ptr(C, ot, context, &props_ptr); } -/** - * Call an existent menu. The menu can be created in C or Python. - */ void WM_menu_name_call(bContext *C, const char *menu_name, short context) { wmOperatorType *ot = WM_operatortype_find("WM_OT_call_menu", false); @@ -1638,13 +1610,6 @@ void WM_menu_name_call(bContext *C, const char *menu_name, short context) WM_operator_properties_free(&ptr); } -/** - * Similar to #WM_operator_name_call called with #WM_OP_EXEC_DEFAULT context. - * - * - #wmOperatorType is used instead of operator name since python already has the operator type. - * - `poll()` must be called by python before this runs. - * - reports can be passed to this function (so python can report them as exceptions). - */ int WM_operator_call_py(bContext *C, wmOperatorType *ot, wmOperatorCallContext context, @@ -1849,9 +1814,9 @@ void WM_operator_name_call_ptr_with_depends_on_cursor(bContext *C, * General API for different handler types. * \{ */ -/* Future extra customadata free? */ void wm_event_free_handler(wmEventHandler *handler) { + /* Future extra customa-data free? */ MEM_freeN(handler); } @@ -1923,7 +1888,6 @@ static void wm_handler_op_context(bContext *C, wmEventHandler_Op *handler, const } } -/* Called on exit or remove area, only here call cancel callback. */ void WM_event_remove_handlers(bContext *C, ListBase *handlers) { wmWindowManager *wm = CTX_wm_manager(C); @@ -3525,8 +3489,6 @@ static void wm_event_handle_xrevent(bContext *C, } #endif /* WITH_XR_OPENXR */ -/* Called in main loop. */ -/* Goes over entire hierarchy: events -> window -> screen -> area -> region. */ void wm_event_do_handlers(bContext *C) { wmWindowManager *wm = CTX_wm_manager(C); @@ -3836,12 +3798,6 @@ void WM_event_fileselect_event(wmWindowManager *wm, void *ophandle, int eventval /* Operator is supposed to have a filled "path" property. */ /* Optional property: file-type (XXX enum?) */ -/** - * The idea here is to keep a handler alive on window queue, owning the operator. - * The file window can send event to make it execute, thus ensuring - * executing happens outside of lower level queues, with UI refreshed. - * Should also allow multiwin solutions. - */ void WM_event_add_fileselect(bContext *C, wmOperator *op) { wmWindowManager *wm = CTX_wm_manager(C); @@ -3940,10 +3896,6 @@ wmEventHandler_Op *WM_event_add_modal_handler(bContext *C, wmOperator *op) return handler; } -/** - * Modal handlers store a pointer to an area which might be freed while the handler runs. - * Use this function to NULL all handler pointers to \a old_area. - */ void WM_event_modal_handler_area_replace(wmWindow *win, const ScrArea *old_area, ScrArea *new_area) { LISTBASE_FOREACH (wmEventHandler *, handler_base, &win->modalhandlers) { @@ -3958,10 +3910,6 @@ void WM_event_modal_handler_area_replace(wmWindow *win, const ScrArea *old_area, } } -/** - * Modal handlers store a pointer to a region which might be freed while the handler runs. - * Use this function to NULL all handler pointers to \a old_region. - */ void WM_event_modal_handler_region_replace(wmWindow *win, const ARegion *old_region, ARegion *new_region) @@ -4152,7 +4100,6 @@ struct wmEventHandler_Keymap *WM_event_add_keymap_handler_dynamic( return handler; } -/* Priorities not implemented yet, for time being just insert in begin of list. */ wmEventHandler_Keymap *WM_event_add_keymap_handler_priority(ListBase *handlers, wmKeyMap *keymap, int UNUSED(priority)) @@ -4259,7 +4206,6 @@ wmEventHandler_UI *WM_event_add_ui_handler(const bContext *C, return handler; } -/* Set "postpone" for win->modalhandlers, this is in a running for () loop in wm_handlers_do(). */ void WM_event_remove_ui_handler(ListBase *handlers, wmUIHandlerFunc handle_fn, wmUIHandlerRemoveFunc remove_fn, @@ -4324,9 +4270,10 @@ wmEventHandler_Dropbox *WM_event_add_dropbox_handler(ListBase *handlers, ListBas return handler; } -/* XXX(ton): solution works, still better check the real cause. */ void WM_event_remove_area_handler(ListBase *handlers, void *area) { + /* XXX(ton): solution works, still better check the real cause. */ + LISTBASE_FOREACH_MUTABLE (wmEventHandler *, handler_base, handlers) { if (handler_base->type == WM_HANDLER_TYPE_UI) { wmEventHandler_UI *handler = (wmEventHandler_UI *)handler_base; @@ -4752,9 +4699,6 @@ static wmEvent *wm_event_add_trackpad(wmWindow *win, const wmEvent *event, int d return event_new; } -/** - * Windows store own event queues #wmWindow.event_queue (no #bContext here). - */ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void *customdata) { if (UNLIKELY(G.f & G_FLAG_EVENT_SIMULATE)) { @@ -5372,10 +5316,6 @@ const char *WM_window_cursor_keymap_status_get(const wmWindow *win, return NULL; } -/** - * Similar to #BKE_screen_area_map_find_area_xy and related functions, - * use here since the area is stored in the window manager. - */ ScrArea *WM_window_status_area_find(wmWindow *win, bScreen *screen) { if (screen->state == SCREENFULL) { diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index a301b17227d..1d3fa158ac1 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -111,6 +111,7 @@ #include "ED_fileselect.h" #include "ED_image.h" #include "ED_outliner.h" +#include "ED_render.h" #include "ED_screen.h" #include "ED_undo.h" #include "ED_util.h" @@ -170,9 +171,6 @@ void WM_file_tag_modified(void) } } -/** - * Check if there is data that would be lost when closing the current file without saving. - */ bool wm_file_or_session_data_has_unsaved_changes(const Main *bmain, const wmWindowManager *wm) { return !wm->file_saved || ED_image_should_save_modified(bmain) || @@ -620,6 +618,8 @@ static void wm_file_read_pre(bContext *C, bool use_data, bool UNUSED(use_userdef /* 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(); + + ED_preview_restart_queue_free(); } /** @@ -955,16 +955,6 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports) /* #BKE_blendfile_read_result_setup sets new Main into context. */ Main *bmain = CTX_data_main(C); - /* When recovering a session from an unsaved file, this can have a blank path. */ - if (BKE_main_blendfile_path(bmain)[0] != '\0') { - G.save_over = 1; - G.relbase_valid = 1; - } - else { - G.save_over = 0; - G.relbase_valid = 0; - } - /* match the read WM with current WM */ wm_window_match_do(C, &wmbase, &bmain->wm, &bmain->wm); WM_check(C); /* opens window(s), checks keymaps */ @@ -1032,12 +1022,6 @@ static struct { bool override; } wm_init_state_app_template = {{0}}; -/** - * Used for setting app-template from the command line: - * - non-empty string: overrides. - * - empty string: override, using no app template. - * - NULL: clears override. - */ void WM_init_state_app_template_set(const char *app_template) { if (app_template) { @@ -1061,16 +1045,6 @@ const char *WM_init_state_app_template_get(void) /** \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. - * - * \param r_params_file_read_post: Support postponed initialization, - * needed for initial startup when only some sub-systems have been initialized. - * When non-null, #wm_file_read_post doesn't run, instead it's arguments are stored - * in this return argument. - * The caller is responsible for calling #wm_homefile_read_post with this return argument. - */ void wm_homefile_read_ex(bContext *C, const struct wmHomeFileRead_Params *params_homefile, ReportList *reports, @@ -1167,8 +1141,6 @@ void wm_homefile_read_ex(bContext *C, 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); } @@ -1372,10 +1344,7 @@ void wm_homefile_read_ex(bContext *C, if (use_data) { WM_check(C); /* opens window(s), checks keymaps */ - bmain->name[0] = '\0'; - - /* start with save preference untitled.blend */ - G.save_over = 0; + bmain->filepath[0] = '\0'; } { @@ -1406,10 +1375,6 @@ void wm_homefile_read(bContext *C, wm_homefile_read_ex(C, params_homefile, reports, NULL); } -/** - * Special case, support deferred execution of #wm_file_read_post, - * Needed when loading for the first time to workaround order of initialization bug, see T89046. - */ void wm_homefile_read_post(struct bContext *C, const struct wmFileReadPost_Params *params_file_read_post) { @@ -1417,6 +1382,8 @@ void wm_homefile_read_post(struct bContext *C, MEM_freeN((void *)params_file_read_post); } +/** \} */ + /* -------------------------------------------------------------------- */ /** \name Blend-File History API * \{ */ @@ -1514,18 +1481,18 @@ static void wm_history_file_write(void) static void wm_history_file_update(void) { RecentFile *recent; - const char *blendfile_name = BKE_main_blendfile_path_from_global(); + const char *blendfile_path = BKE_main_blendfile_path_from_global(); - /* no write history for recovered startup files */ - if (blendfile_name[0] == '\0') { + /* No write history for recovered startup files. */ + if (blendfile_path[0] == '\0') { return; } recent = G.recent_files.first; /* refresh recent-files.txt of recent opened files, when current file was changed */ - if (!(recent) || (BLI_path_cmp(recent->filepath, blendfile_name) != 0)) { + if (!(recent) || (BLI_path_cmp(recent->filepath, blendfile_path) != 0)) { - recent = wm_file_history_find(blendfile_name); + recent = wm_file_history_find(blendfile_path); if (recent) { BLI_remlink(&G.recent_files, recent); } @@ -1536,7 +1503,7 @@ static void wm_history_file_update(void) recent_next = recent->next; wm_history_file_free(recent); } - recent = wm_history_file_new(blendfile_name); + recent = wm_history_file_new(blendfile_path); } /* add current file to the beginning of list */ @@ -1546,7 +1513,7 @@ static void wm_history_file_update(void) wm_history_file_write(); /* also update most recent files on System */ - GHOST_addToSystemRecentFiles(blendfile_name); + GHOST_addToSystemRecentFiles(blendfile_path); } } @@ -1721,7 +1688,6 @@ static ImBuf *blend_file_thumb_from_camera(const bContext *C, return ibuf; } -/* easy access from gdb */ bool write_crash_blend(void) { char path[FILE_MAX]; @@ -1817,8 +1783,9 @@ static bool wm_file_write(bContext *C, if (file_preview_type == USER_FILE_PREVIEW_AUTO) { Scene *scene = CTX_data_scene(C); - bool do_render = (scene != NULL && scene->camera != NULL && - (BKE_screen_find_big_area(CTX_wm_screen(C), SPACE_VIEW3D, 0) != NULL)); + bScreen *screen = CTX_wm_screen(C); + bool do_render = (scene != NULL && scene->camera != NULL && screen != NULL && + (BKE_screen_find_big_area(screen, SPACE_VIEW3D, 0) != NULL)); file_preview_type = do_render ? USER_FILE_PREVIEW_CAMERA : USER_FILE_PREVIEW_SCREENSHOT; } @@ -1846,16 +1813,10 @@ static bool wm_file_write(bContext *C, ED_editors_flush_edits(bmain); - /* First time saving. */ - /* XXX(ton): temp solution to solve bug, real fix coming. */ - if ((BKE_main_blendfile_path(bmain)[0] == '\0') && (use_save_as_copy == false)) { - BLI_strncpy(bmain->name, filepath, sizeof(bmain->name)); - } - /* XXX(ton): temp solution to solve bug, real fix coming. */ bmain->recovered = 0; - if (BLO_write_file(CTX_data_main(C), + if (BLO_write_file(bmain, filepath, fileflags, &(const struct BlendFileWriteParams){ @@ -1869,10 +1830,7 @@ static bool wm_file_write(bContext *C, (CTX_wm_manager(C)->op_undo_depth == 0); if (use_save_as_copy == false) { - G.relbase_valid = 1; - BLI_strncpy(bmain->name, filepath, sizeof(bmain->name)); /* is guaranteed current file */ - - G.save_over = 1; /* disable untitled.blend convention */ + STRNCPY(bmain->filepath, filepath); /* is guaranteed current file */ } SET_FLAG_FROM_TEST(G.fileflags, fileflags & G_FILE_COMPRESS, G_FILE_COMPRESS); @@ -1923,8 +1881,13 @@ static void wm_autosave_location(char *filepath) const char *savedir; #endif - if (G_MAIN && G.relbase_valid) { - const char *basename = BLI_path_basename(BKE_main_blendfile_path_from_global()); + /* Normally there is no need to check for this to be NULL, + * however this runs on exit when it may be cleared. */ + Main *bmain = G_MAIN; + const char *blendfile_path = bmain ? BKE_main_blendfile_path(bmain) : NULL; + + if (blendfile_path && (blendfile_path[0] != '\0')) { + const char *basename = BLI_path_basename(blendfile_path); int len = strlen(basename) - 6; BLI_snprintf(path, sizeof(path), "%.*s_%d_autosave.blend", len, basename, pid); } @@ -2006,9 +1969,6 @@ void WM_autosave_init(wmWindowManager *wm) wm_autosave_timer_begin(wm); } -/** - * Run the auto-save timer action. - */ void wm_autosave_timer(Main *bmain, wmWindowManager *wm, wmTimer *UNUSED(wt)) { wm_autosave_timer_end(wm); @@ -2137,7 +2097,7 @@ static int wm_homefile_write_exec(bContext *C, wmOperator *op) fileflags, &(const struct BlendFileWriteParams){ /* Make all paths absolute when saving the startup file. - * On load the `G.relbase_valid` will be false so the paths + * On load the `G.main->filepath` will be empty so the paths * won't have a base for resolving the relative paths. */ .remap_mode = BLO_WRITE_PATH_REMAP_ABSOLUTE, /* Don't apply any path changes to the current blend file. */ @@ -2150,7 +2110,6 @@ static int wm_homefile_write_exec(bContext *C, wmOperator *op) printf("ok\n"); BKE_report(op->reports, RPT_INFO, "Startup file saved"); - G.save_over = 0; BKE_callback_exec_null(bmain, BKE_CB_EVT_SAVE_POST); @@ -2637,7 +2596,7 @@ static int wm_open_mainfile__select_file_path(bContext *C, wmOperator *op) set_next_operator_state(op, OPEN_MAINFILE_STATE_OPEN); Main *bmain = CTX_data_main(C); - const char *openname = BKE_main_blendfile_path(bmain); + const char *blendfile_path = BKE_main_blendfile_path(bmain); if (CTX_wm_window(C) == NULL) { /* in rare cases this could happen, when trying to invoke in background @@ -2650,10 +2609,10 @@ static int wm_open_mainfile__select_file_path(bContext *C, wmOperator *op) /* if possible, get the name of the most recently used .blend file */ if (G.recent_files.first) { struct RecentFile *recent = G.recent_files.first; - openname = recent->filepath; + blendfile_path = recent->filepath; } - RNA_string_set(op->ptr, "filepath", openname); + RNA_string_set(op->ptr, "filepath", blendfile_path); wm_open_init_load_ui(op, true); wm_open_init_use_scripts(op, true); op->customdata = NULL; @@ -2876,7 +2835,8 @@ static int wm_revert_mainfile_exec(bContext *C, wmOperator *op) static bool wm_revert_mainfile_poll(bContext *UNUSED(C)) { - return G.relbase_valid; + const char *blendfile_path = BKE_main_blendfile_path_from_global(); + return (blendfile_path[0] != '\0'); } void WM_OT_revert_mainfile(wmOperatorType *ot) @@ -3033,9 +2993,9 @@ void WM_OT_recover_auto_save(wmOperatorType *ot) * Both #WM_OT_save_as_mainfile & #WM_OT_save_mainfile. * \{ */ -static void wm_filepath_default(char *filepath) +static void wm_filepath_default(const Main *bmain, char *filepath) { - if (G.save_over == false) { + if (bmain->filepath[0] == '\0') { BLI_path_filename_ensure(filepath, FILE_MAX, "untitled.blend"); } } @@ -3046,7 +3006,8 @@ static void save_set_compress(wmOperator *op) prop = RNA_struct_find_property(op->ptr, "compress"); if (!RNA_property_is_set(op->ptr, prop)) { - if (G.save_over) { /* keep flag for existing file */ + const char *blendfile_path = BKE_main_blendfile_path_from_global(); + if (blendfile_path[0] != '\0') { /* Keep flag for existing file. */ RNA_property_boolean_set(op->ptr, prop, (G.fileflags & G_FILE_COMPRESS) != 0); } else { /* use userdef for new file */ @@ -3059,21 +3020,22 @@ static void save_set_filepath(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); PropertyRNA *prop; - char name[FILE_MAX]; + char filepath[FILE_MAX]; prop = RNA_struct_find_property(op->ptr, "filepath"); if (!RNA_property_is_set(op->ptr, prop)) { + const char *blendfile_path = BKE_main_blendfile_path(bmain); /* if not saved before, get the name of the most recently used .blend file */ - if (BKE_main_blendfile_path(bmain)[0] == '\0' && G.recent_files.first) { + if ((blendfile_path[0] == '\0') && G.recent_files.first) { struct RecentFile *recent = G.recent_files.first; - BLI_strncpy(name, recent->filepath, FILE_MAX); + STRNCPY(filepath, recent->filepath); } else { - BLI_strncpy(name, bmain->name, FILE_MAX); + STRNCPY(filepath, blendfile_path); } - wm_filepath_default(name); - RNA_property_string_set(op->ptr, prop, name); + wm_filepath_default(bmain, filepath); + RNA_property_string_set(op->ptr, prop, filepath); } } @@ -3105,12 +3067,32 @@ static int wm_save_as_mainfile_exec(bContext *C, wmOperator *op) BLO_WRITE_PATH_REMAP_NONE; save_set_compress(op); - if (RNA_struct_property_is_set(op->ptr, "filepath")) { + const bool is_filepath_set = RNA_struct_property_is_set(op->ptr, "filepath"); + if (is_filepath_set) { RNA_string_get(op->ptr, "filepath", path); } else { - BLI_strncpy(path, BKE_main_blendfile_path(bmain), FILE_MAX); - wm_filepath_default(path); + STRNCPY(path, BKE_main_blendfile_path(bmain)); + } + + if (path[0] == '\0') { + BKE_report(op->reports, + RPT_ERROR, + "Unable to save an unsaved file with an empty or unset \"filepath\" property"); + return OPERATOR_CANCELLED; + } + + /* NOTE(@campbellbarton): only check this for file-path properties so saving an already + * saved file never fails with an error. + * Even though this should never happen, there may be some corner case where a malformed + * path is stored in `G.main->filepath`: when the file path is initialized from recovering + * a blend file - for example, so in this case failing to save isn't ideal. */ + if (is_filepath_set && !BLI_path_is_abs_from_cwd(path)) { + BKE_reportf(op->reports, + RPT_ERROR, + "The \"filepath\" property was not an absolute path: \"%s\"", + path); + return OPERATOR_CANCELLED; } const int fileflags_orig = G.fileflags; @@ -3227,14 +3209,15 @@ static int wm_save_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *U /* if we're saving for the first time and prefer relative paths - * any existing paths will be absolute, * enable the option to remap paths to avoid confusion T37240. */ - if ((G.relbase_valid == false) && (U.flag & USER_RELPATHS)) { + const char *blendfile_path = BKE_main_blendfile_path_from_global(); + if ((blendfile_path[0] == '\0') && (U.flag & USER_RELPATHS)) { PropertyRNA *prop = RNA_struct_find_property(op->ptr, "relative_remap"); if (!RNA_property_is_set(op->ptr, prop)) { RNA_property_boolean_set(op->ptr, prop, true); } } - if (G.save_over) { + if (blendfile_path[0] != '\0') { char path[FILE_MAX]; RNA_string_get(op->ptr, "filepath", path); @@ -3336,6 +3319,7 @@ static uiBlock *block_create_autorun_warning(struct bContext *C, struct ARegion *region, void *UNUSED(arg1)) { + const char *blendfile_path = BKE_main_blendfile_path_from_global(); wmWindowManager *wm = CTX_wm_manager(C); uiBlock *block = UI_block_begin(C, region, "autorun_warning_popup", UI_EMBOSS); @@ -3383,7 +3367,7 @@ static uiBlock *block_create_autorun_warning(struct bContext *C, /* Allow reload if we have a saved file. * Otherwise just enable scripts and reset the depsgraphs. */ - if (G.relbase_valid && wm->file_saved) { + if ((blendfile_path[0] != '\0') && wm->file_saved) { but = uiDefIconTextBut(block, UI_BTYPE_BUT, 0, @@ -3640,10 +3624,10 @@ static uiBlock *block_create__close_file_dialog(struct bContext *C, uiItemL_ex(layout, TIP_("Save changes before closing?"), ICON_NONE, true, false); /* Filename. */ - const char *blendfile_pathpath = BKE_main_blendfile_path(CTX_data_main(C)); + const char *blendfile_path = BKE_main_blendfile_path(CTX_data_main(C)); char filename[FILE_MAX]; - if (blendfile_pathpath[0] != '\0') { - BLI_split_file_part(blendfile_pathpath, filename, sizeof(filename)); + if (blendfile_path[0] != '\0') { + BLI_split_file_part(blendfile_path, filename, sizeof(filename)); } else { STRNCPY(filename, "untitled.blend"); @@ -3810,10 +3794,6 @@ static void wm_free_operator_properties_callback(void *user_data) IDP_FreeProperty(properties); } -/** - * \return True if the dialog was created, the calling operator should return #OPERATOR_INTERFACE - * then. - */ bool wm_operator_close_file_dialog_if_needed(bContext *C, wmOperator *op, wmGenericCallbackFn post_action_fn) diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c index d373ecdac77..cf6ecd55757 100644 --- a/source/blender/windowmanager/intern/wm_files_link.c +++ b/source/blender/windowmanager/intern/wm_files_link.c @@ -52,9 +52,8 @@ #include "BLO_readfile.h" -#include "BLT_translation.h" - #include "BKE_armature.h" +#include "BKE_blendfile_link_append.h" #include "BKE_context.h" #include "BKE_global.h" #include "BKE_key.h" @@ -114,12 +113,13 @@ static bool wm_link_append_poll(bContext *C) static int wm_link_append_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { if (!RNA_struct_property_is_set(op->ptr, "filepath")) { + const char *blendfile_path = BKE_main_blendfile_path_from_global(); if (G.lib[0] != '\0') { RNA_string_set(op->ptr, "filepath", G.lib); } - else if (G.relbase_valid) { + else if (blendfile_path[0] != '\0') { char path[FILE_MAX]; - BLI_strncpy(path, BKE_main_blendfile_path_from_global(), sizeof(path)); + STRNCPY(path, blendfile_path); BLI_path_parent_dir(path); RNA_string_set(op->ptr, "filepath", path); } @@ -168,841 +168,6 @@ static int wm_link_append_flag(wmOperator *op) return flag; } -typedef struct WMLinkAppendDataItem { - char *name; - BLI_bitmap - *libraries; /* All libs (from WMLinkAppendData.libraries) to try to load this ID from. */ - short idcode; - - /** Type of action to do to append this item, and other append-specific information. */ - char append_action; - char append_tag; - - ID *new_id; - Library *source_library; - void *customdata; -} WMLinkAppendDataItem; - -typedef struct WMLinkAppendData { - LinkNodePair libraries; - LinkNodePair items; - int num_libraries; - int num_items; - /** - * Combines #eFileSel_Params_Flag from DNA_space_types.h & #eBLOLibLinkFlags from BLO_readfile.h - */ - int flag; - - /** Allows to easily find an existing items from an ID pointer. Used by append code. */ - GHash *new_id_to_item; - - /** Runtime info used by append code to manage re-use of already appended matching IDs. */ - GHash *library_weak_reference_mapping; - - /* Internal 'private' data */ - MemArena *memarena; -} WMLinkAppendData; - -typedef struct WMLinkAppendDataCallBack { - WMLinkAppendData *lapp_data; - WMLinkAppendDataItem *item; - ReportList *reports; - -} WMLinkAppendDataCallBack; - -enum { - WM_APPEND_ACT_UNSET = 0, - WM_APPEND_ACT_KEEP_LINKED, - WM_APPEND_ACT_REUSE_LOCAL, - WM_APPEND_ACT_MAKE_LOCAL, - WM_APPEND_ACT_COPY_LOCAL, -}; - -enum { - WM_APPEND_TAG_INDIRECT = 1 << 0, -}; - -static WMLinkAppendData *wm_link_append_data_new(const int flag) -{ - MemArena *ma = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); - WMLinkAppendData *lapp_data = BLI_memarena_calloc(ma, sizeof(*lapp_data)); - - lapp_data->flag = flag; - lapp_data->memarena = ma; - - return lapp_data; -} - -static void wm_link_append_data_free(WMLinkAppendData *lapp_data) -{ - if (lapp_data->new_id_to_item != NULL) { - BLI_ghash_free(lapp_data->new_id_to_item, NULL, NULL); - } - - BLI_assert(lapp_data->library_weak_reference_mapping == NULL); - - BLI_memarena_free(lapp_data->memarena); -} - -/* WARNING! *Never* call wm_link_append_data_library_add() after having added some items! */ - -static void wm_link_append_data_library_add(WMLinkAppendData *lapp_data, const char *libname) -{ - size_t len = strlen(libname) + 1; - char *libpath = BLI_memarena_alloc(lapp_data->memarena, len); - - BLI_strncpy(libpath, libname, len); - BLI_linklist_append_arena(&lapp_data->libraries, libpath, lapp_data->memarena); - lapp_data->num_libraries++; -} - -static WMLinkAppendDataItem *wm_link_append_data_item_add(WMLinkAppendData *lapp_data, - const char *idname, - const short idcode, - void *customdata) -{ - WMLinkAppendDataItem *item = BLI_memarena_calloc(lapp_data->memarena, sizeof(*item)); - size_t len = strlen(idname) + 1; - - item->name = BLI_memarena_alloc(lapp_data->memarena, len); - BLI_strncpy(item->name, idname, len); - item->idcode = idcode; - item->libraries = BLI_BITMAP_NEW_MEMARENA(lapp_data->memarena, lapp_data->num_libraries); - - item->new_id = NULL; - item->append_action = WM_APPEND_ACT_UNSET; - item->customdata = customdata; - - BLI_linklist_append_arena(&lapp_data->items, item, lapp_data->memarena); - lapp_data->num_items++; - - return item; -} - -/* -------------------------------------------------------------------- */ -/** \name Library appending helper functions. - * - * FIXME: Deduplicate code with similar one in readfile.c - * \{ */ - -static bool object_in_any_scene(Main *bmain, Object *ob) -{ - LISTBASE_FOREACH (Scene *, sce, &bmain->scenes) { - if (BKE_scene_object_find(sce, ob)) { - return true; - } - } - - return false; -} - -static bool object_in_any_collection(Main *bmain, Object *ob) -{ - LISTBASE_FOREACH (Collection *, collection, &bmain->collections) { - if (BKE_collection_has_object(collection, ob)) { - return true; - } - } - - LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { - if (scene->master_collection != NULL && - BKE_collection_has_object(scene->master_collection, ob)) { - return true; - } - } - - return false; -} - -static ID *wm_append_loose_data_instantiate_process_check(WMLinkAppendDataItem *item) -{ - /* We consider that if we either kept it linked, or re-used already local data, instantiation - * status of those should not be modified. */ - if (!ELEM(item->append_action, WM_APPEND_ACT_COPY_LOCAL, WM_APPEND_ACT_MAKE_LOCAL)) { - return NULL; - } - - ID *id = item->new_id; - if (id == NULL) { - return NULL; - } - - if (item->append_action == WM_APPEND_ACT_COPY_LOCAL) { - BLI_assert(ID_IS_LINKED(id)); - id = id->newid; - if (id == NULL) { - return NULL; - } - - BLI_assert(!ID_IS_LINKED(id)); - return id; - } - - BLI_assert(!ID_IS_LINKED(id)); - return id; -} - -static void wm_append_loose_data_instantiate_ensure_active_collection( - WMLinkAppendData *lapp_data, - Main *bmain, - Scene *scene, - ViewLayer *view_layer, - Collection **r_active_collection) -{ - /* Find or add collection as needed. */ - if (*r_active_collection == NULL) { - if (lapp_data->flag & FILE_ACTIVE_COLLECTION) { - LayerCollection *lc = BKE_layer_collection_get_active(view_layer); - *r_active_collection = lc->collection; - } - else { - *r_active_collection = BKE_collection_add( - bmain, scene->master_collection, DATA_("Appended Data")); - } - } -} - -/* TODO: De-duplicate this code with the one in readfile.c, think we need some utils code for that - * in BKE. */ -static void wm_append_loose_data_instantiate(WMLinkAppendData *lapp_data, - Main *bmain, - Scene *scene, - ViewLayer *view_layer, - const View3D *v3d) -{ - if (scene == NULL) { - /* In some cases, like the asset drag&drop e.g., the caller code manages instantiation itself. - */ - return; - } - - LinkNode *itemlink; - Collection *active_collection = NULL; - const bool do_obdata = (lapp_data->flag & BLO_LIBLINK_OBDATA_INSTANCE) != 0; - - /* Do NOT make base active here! screws up GUI stuff, - * if you want it do it at the editor level. */ - const bool object_set_active = false; - - /* First pass on obdata to enable their instantiation by default, then do a second pass on - * objects to clear it for any obdata already in use. */ - if (do_obdata) { - for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - ID *id = wm_append_loose_data_instantiate_process_check(item); - if (id == NULL) { - continue; - } - const ID_Type idcode = GS(id->name); - if (!OB_DATA_SUPPORT_ID(idcode)) { - continue; - } - - id->tag |= LIB_TAG_DOIT; - } - for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - ID *id = item->new_id; - if (id == NULL || GS(id->name) != ID_OB) { - continue; - } - - Object *ob = (Object *)id; - Object *new_ob = (Object *)id->newid; - if (ob->data != NULL) { - ((ID *)(ob->data))->tag &= ~LIB_TAG_DOIT; - } - if (new_ob != NULL && new_ob->data != NULL) { - ((ID *)(new_ob->data))->tag &= ~LIB_TAG_DOIT; - } - } - } - - /* First do collections, then objects, then obdata. */ - - /* NOTE: For collections we only view_layer-instantiate duplicated collections that have - * non-instantiated objects in them. */ - for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - ID *id = wm_append_loose_data_instantiate_process_check(item); - if (id == NULL || GS(id->name) != ID_GR) { - continue; - } - - /* We do not want to force instantiation of indirectly appended collections. Users can now - * easily instantiate collections (and their objects) as needed by themselves. See T67032. */ - /* We need to check that objects in that collections are already instantiated in a scene. - * Otherwise, it's better to add the collection to the scene's active collection, than to - * instantiate its objects in active scene's collection directly. See T61141. - * - * NOTE: We only check object directly into that collection, not recursively into its - * children. - */ - Collection *collection = (Collection *)id; - /* We always add collections directly selected by the user. */ - bool do_add_collection = (item->append_tag & WM_APPEND_TAG_INDIRECT) == 0; - if (!do_add_collection) { - LISTBASE_FOREACH (CollectionObject *, coll_ob, &collection->gobject) { - Object *ob = coll_ob->ob; - if (!object_in_any_scene(bmain, ob)) { - do_add_collection = true; - break; - } - } - } - if (do_add_collection) { - wm_append_loose_data_instantiate_ensure_active_collection( - lapp_data, bmain, scene, view_layer, &active_collection); - - /* In case user requested instantiation of collections as empties, we do so for the one they - * explicitly selected (originally directly linked IDs). */ - if ((lapp_data->flag & BLO_LIBLINK_COLLECTION_INSTANCE) != 0 && - (item->append_tag & WM_APPEND_TAG_INDIRECT) == 0) { - /* BKE_object_add(...) messes with the selection. */ - Object *ob = BKE_object_add_only_object(bmain, OB_EMPTY, collection->id.name + 2); - ob->type = OB_EMPTY; - ob->empty_drawsize = U.collection_instance_empty_size; - - const bool set_selected = (lapp_data->flag & FILE_AUTOSELECT) != 0; - /* TODO: why is it OK to make this active here but not in other situations? - * See other callers of #object_base_instance_init */ - const bool set_active = set_selected; - BLO_object_instantiate_object_base_instance_init( - bmain, active_collection, ob, view_layer, v3d, lapp_data->flag, set_active); - - /* Assign the collection. */ - ob->instance_collection = collection; - id_us_plus(&collection->id); - ob->transflag |= OB_DUPLICOLLECTION; - copy_v3_v3(ob->loc, scene->cursor.location); - } - else { - /* Add collection as child of active collection. */ - BKE_collection_child_add(bmain, active_collection, collection); - - if ((lapp_data->flag & FILE_AUTOSELECT) != 0) { - LISTBASE_FOREACH (CollectionObject *, coll_ob, &collection->gobject) { - Object *ob = coll_ob->ob; - Base *base = BKE_view_layer_base_find(view_layer, ob); - if (base) { - base->flag |= BASE_SELECTED; - BKE_scene_object_base_flag_sync_from_base(base); - } - } - } - } - } - } - - /* NOTE: For objects we only view_layer-instantiate duplicated objects that are not yet used - * anywhere. */ - for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - ID *id = wm_append_loose_data_instantiate_process_check(item); - if (id == NULL || GS(id->name) != ID_OB) { - continue; - } - - Object *ob = (Object *)id; - - if (object_in_any_collection(bmain, ob)) { - continue; - } - - wm_append_loose_data_instantiate_ensure_active_collection( - lapp_data, bmain, scene, view_layer, &active_collection); - - CLAMP_MIN(ob->id.us, 0); - ob->mode = OB_MODE_OBJECT; - - BLO_object_instantiate_object_base_instance_init( - bmain, active_collection, ob, view_layer, v3d, lapp_data->flag, object_set_active); - } - - if (!do_obdata) { - return; - } - - for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - ID *id = wm_append_loose_data_instantiate_process_check(item); - if (id == NULL) { - continue; - } - const ID_Type idcode = GS(id->name); - if (!OB_DATA_SUPPORT_ID(idcode)) { - continue; - } - if ((id->tag & LIB_TAG_DOIT) == 0) { - continue; - } - - wm_append_loose_data_instantiate_ensure_active_collection( - lapp_data, bmain, scene, view_layer, &active_collection); - - const int type = BKE_object_obdata_to_type(id); - BLI_assert(type != -1); - Object *ob = BKE_object_add_only_object(bmain, type, id->name + 2); - ob->data = id; - id_us_plus(id); - BKE_object_materials_test(bmain, ob, ob->data); - - BLO_object_instantiate_object_base_instance_init( - bmain, active_collection, ob, view_layer, v3d, lapp_data->flag, object_set_active); - - copy_v3_v3(ob->loc, scene->cursor.location); - - id->tag &= ~LIB_TAG_DOIT; - } - - /* Finally, add rigid body objects and constraints to current RB world(s). */ - for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - ID *id = wm_append_loose_data_instantiate_process_check(item); - if (id == NULL || GS(id->name) != ID_OB) { - continue; - } - BKE_rigidbody_ensure_local_object(bmain, (Object *)id); - } -} - -/** \} */ - -static int foreach_libblock_append_callback(LibraryIDLinkCallbackData *cb_data) -{ - /* NOTE: It is important to also skip liboverride references here, as those should never be made - * local. */ - if (cb_data->cb_flag & (IDWALK_CB_EMBEDDED | IDWALK_CB_INTERNAL | IDWALK_CB_LOOPBACK | - IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE)) { - return IDWALK_RET_NOP; - } - - WMLinkAppendDataCallBack *data = cb_data->user_data; - ID *id = *cb_data->id_pointer; - - if (id == NULL) { - return IDWALK_RET_NOP; - } - - if (!BKE_idtype_idcode_is_linkable(GS(id->name))) { - /* While we do not want to add non-linkable ID (shape keys...) to the list of linked items, - * unfortunately they can use fully linkable valid IDs too, like actions. Those need to be - * processed, so we need to recursively deal with them here. */ - /* NOTE: Since we are by-passing checks in `BKE_library_foreach_ID_link` by manually calling it - * recursively, we need to take care of potential recursion cases ourselves (e.g.animdata of - * shapekey referencing the shapekey itself). */ - if (id != cb_data->id_self) { - BKE_library_foreach_ID_link( - cb_data->bmain, id, foreach_libblock_append_callback, data, IDWALK_NOP); - } - return IDWALK_RET_NOP; - } - - const bool do_recursive = (data->lapp_data->flag & BLO_LIBLINK_APPEND_RECURSIVE) != 0; - if (!do_recursive && cb_data->id_owner->lib != id->lib) { - /* When `do_recursive` is false, we only make local IDs from same library(-ies) as the - * initially directly linked ones. */ - return IDWALK_RET_NOP; - } - - WMLinkAppendDataItem *item = BLI_ghash_lookup(data->lapp_data->new_id_to_item, id); - if (item == NULL) { - item = wm_link_append_data_item_add(data->lapp_data, id->name, GS(id->name), NULL); - item->new_id = id; - item->source_library = id->lib; - /* Since we did not have an item for that ID yet, we know user did not selected it explicitly, - * it was rather linked indirectly. This info is important for instantiation of collections. */ - item->append_tag |= WM_APPEND_TAG_INDIRECT; - BLI_ghash_insert(data->lapp_data->new_id_to_item, id, item); - } - - /* NOTE: currently there is no need to do anything else here, but in the future this would be - * the place to add specific per-usage decisions on how to append an ID. */ - - return IDWALK_RET_NOP; -} - -/* Perform append operation, using modern ID usage looper to detect which ID should be kept linked, - * made local, duplicated as local, re-used from local etc. - * - * TODO: Expose somehow this logic to the two other parts of code performing actual append - * (i.e. copy/paste and `bpy` link/append API). - * Then we can heavily simplify #BKE_library_make_local(). */ -static void wm_append_do(WMLinkAppendData *lapp_data, - ReportList *reports, - Main *bmain, - Scene *scene, - ViewLayer *view_layer, - const View3D *v3d) -{ - BLI_assert((lapp_data->flag & FILE_LINK) == 0); - - const bool set_fakeuser = (lapp_data->flag & BLO_LIBLINK_APPEND_SET_FAKEUSER) != 0; - const bool do_reuse_local_id = (lapp_data->flag & BLO_LIBLINK_APPEND_LOCAL_ID_REUSE) != 0; - - const int make_local_common_flags = LIB_ID_MAKELOCAL_FULL_LIBRARY | - ((lapp_data->flag & BLO_LIBLINK_APPEND_ASSET_DATA_CLEAR) != - 0 ? - LIB_ID_MAKELOCAL_ASSET_DATA_CLEAR : - 0); - - LinkNode *itemlink; - - /* Generate a mapping between newly linked IDs and their items, and tag linked IDs used as - * liboverride references as already existing. */ - lapp_data->new_id_to_item = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__); - for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - ID *id = item->new_id; - if (id == NULL) { - continue; - } - BLI_ghash_insert(lapp_data->new_id_to_item, id, item); - - /* This ensures that if a liboverride reference is also linked/used by some other appended - * data, it gets a local copy instead of being made directly local, so that the liboverride - * references remain valid (i.e. linked data). */ - if (ID_IS_OVERRIDE_LIBRARY_REAL(id)) { - id->override_library->reference->tag |= LIB_TAG_PRE_EXISTING; - } - } - - lapp_data->library_weak_reference_mapping = BKE_main_library_weak_reference_create(bmain); - - /* NOTE: Since we append items for IDs not already listed (i.e. implicitly linked indirect - * dependencies), this list will grow and we will process those IDs later, leading to a flatten - * recursive processing of all the linked dependencies. */ - for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - ID *id = item->new_id; - if (id == NULL) { - continue; - } - BLI_assert(item->customdata == NULL); - - /* In Append case linked IDs should never be marked as needing post-processing (instantiation - * of loose objects etc.). */ - BLI_assert((id->tag & LIB_TAG_DOIT) == 0); - - ID *existing_local_id = BKE_idtype_idcode_append_is_reusable(GS(id->name)) ? - BKE_main_library_weak_reference_search_item( - lapp_data->library_weak_reference_mapping, - id->lib->filepath, - id->name) : - NULL; - - if (item->append_action != WM_APPEND_ACT_UNSET) { - /* Already set, pass. */ - } - if (GS(id->name) == ID_OB && ((Object *)id)->proxy_from != NULL) { - CLOG_INFO(&LOG, 3, "Appended ID '%s' is proxified, keeping it linked...", id->name); - item->append_action = WM_APPEND_ACT_KEEP_LINKED; - } - else if (do_reuse_local_id && existing_local_id != NULL) { - CLOG_INFO(&LOG, 3, "Appended ID '%s' as a matching local one, re-using it...", id->name); - item->append_action = WM_APPEND_ACT_REUSE_LOCAL; - item->customdata = existing_local_id; - } - else if (id->tag & LIB_TAG_PRE_EXISTING) { - CLOG_INFO(&LOG, 3, "Appended ID '%s' was already linked, need to copy it...", id->name); - item->append_action = WM_APPEND_ACT_COPY_LOCAL; - } - else { - CLOG_INFO(&LOG, 3, "Appended ID '%s' will be made local...", id->name); - item->append_action = WM_APPEND_ACT_MAKE_LOCAL; - } - - /* Only check dependencies if we are not keeping linked data, nor re-using existing local data. - */ - if (!ELEM(item->append_action, WM_APPEND_ACT_KEEP_LINKED, WM_APPEND_ACT_REUSE_LOCAL)) { - WMLinkAppendDataCallBack cb_data = { - .lapp_data = lapp_data, .item = item, .reports = reports}; - BKE_library_foreach_ID_link( - bmain, id, foreach_libblock_append_callback, &cb_data, IDWALK_NOP); - } - - /* If we found a matching existing local id but are not re-using it, we need to properly clear - * its weak reference to linked data. */ - if (existing_local_id != NULL && - !ELEM(item->append_action, WM_APPEND_ACT_KEEP_LINKED, WM_APPEND_ACT_REUSE_LOCAL)) { - BKE_main_library_weak_reference_remove_item(lapp_data->library_weak_reference_mapping, - id->lib->filepath, - id->name, - existing_local_id); - } - } - - /* Effectively perform required operation on every linked ID. */ - for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - ID *id = item->new_id; - if (id == NULL) { - continue; - } - - ID *local_appended_new_id = NULL; - char lib_filepath[FILE_MAX]; - BLI_strncpy(lib_filepath, id->lib->filepath, sizeof(lib_filepath)); - char lib_id_name[MAX_ID_NAME]; - BLI_strncpy(lib_id_name, id->name, sizeof(lib_id_name)); - - switch (item->append_action) { - case WM_APPEND_ACT_COPY_LOCAL: - BKE_lib_id_make_local(bmain, id, make_local_common_flags | LIB_ID_MAKELOCAL_FORCE_COPY); - local_appended_new_id = id->newid; - break; - case WM_APPEND_ACT_MAKE_LOCAL: - BKE_lib_id_make_local(bmain, - id, - make_local_common_flags | LIB_ID_MAKELOCAL_FORCE_LOCAL | - LIB_ID_MAKELOCAL_OBJECT_NO_PROXY_CLEARING); - BLI_assert(id->newid == NULL); - local_appended_new_id = id; - break; - case WM_APPEND_ACT_KEEP_LINKED: - /* Nothing to do here. */ - break; - case WM_APPEND_ACT_REUSE_LOCAL: - /* We only need to set `newid` to ID found in previous loop, for proper remapping. */ - ID_NEW_SET(id, item->customdata); - /* This is not a 'new' local appended id, do not set `local_appended_new_id` here. */ - break; - case WM_APPEND_ACT_UNSET: - CLOG_ERROR( - &LOG, "Unexpected unset append action for '%s' ID, assuming 'keep link'", id->name); - break; - default: - BLI_assert(0); - } - - if (local_appended_new_id != NULL) { - if (BKE_idtype_idcode_append_is_reusable(GS(local_appended_new_id->name))) { - BKE_main_library_weak_reference_add_item(lapp_data->library_weak_reference_mapping, - lib_filepath, - lib_id_name, - local_appended_new_id); - } - - if (set_fakeuser) { - if (!ELEM(GS(local_appended_new_id->name), ID_OB, ID_GR)) { - /* Do not set fake user on objects nor collections (instancing). */ - id_fake_user_set(local_appended_new_id); - } - } - } - } - - BKE_main_library_weak_reference_destroy(lapp_data->library_weak_reference_mapping); - lapp_data->library_weak_reference_mapping = NULL; - - /* Remap IDs as needed. */ - for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - - if (item->append_action == WM_APPEND_ACT_KEEP_LINKED) { - continue; - } - - ID *id = item->new_id; - if (id == NULL) { - continue; - } - if (ELEM(item->append_action, WM_APPEND_ACT_COPY_LOCAL, WM_APPEND_ACT_REUSE_LOCAL)) { - BLI_assert(ID_IS_LINKED(id)); - id = id->newid; - if (id == NULL) { - continue; - } - } - - BLI_assert(!ID_IS_LINKED(id)); - - BKE_libblock_relink_to_newid(bmain, id, 0); - } - - /* Remove linked IDs when a local existing data has been reused instead. */ - BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false); - for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - - if (item->append_action != WM_APPEND_ACT_REUSE_LOCAL) { - continue; - } - - ID *id = item->new_id; - if (id == NULL) { - continue; - } - BLI_assert(ID_IS_LINKED(id)); - BLI_assert(id->newid != NULL); - - id->tag |= LIB_TAG_DOIT; - item->new_id = id->newid; - } - BKE_id_multi_tagged_delete(bmain); - - /* Instantiate newly created (duplicated) IDs as needed. */ - wm_append_loose_data_instantiate(lapp_data, bmain, scene, view_layer, v3d); - - /* Attempt to deal with object proxies. - * - * NOTE: Copied from `BKE_library_make_local`, but this is not really working (as in, not - * producing any useful result in any known use case), neither here nor in - * `BKE_library_make_local` currently. - * Proxies are end of life anyway, so not worth spending time on this. */ - for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - - if (item->append_action != WM_APPEND_ACT_COPY_LOCAL) { - continue; - } - - ID *id = item->new_id; - if (id == NULL) { - continue; - } - BLI_assert(ID_IS_LINKED(id)); - - /* Attempt to re-link copied proxy objects. This allows appending of an entire scene - * from another blend file into this one, even when that blend file contains proxified - * armatures that have local references. Since the proxified object needs to be linked - * (not local), this will only work when the "Localize all" checkbox is disabled. - * TL;DR: this is a dirty hack on top of an already weak feature (proxies). */ - if (GS(id->name) == ID_OB && ((Object *)id)->proxy != NULL) { - Object *ob = (Object *)id; - Object *ob_new = (Object *)id->newid; - bool is_local = false, is_lib = false; - - /* Proxies only work when the proxified object is linked-in from a library. */ - if (!ID_IS_LINKED(ob->proxy)) { - CLOG_WARN(&LOG, - "Proxy object %s will lose its link to %s, because the " - "proxified object is local", - id->newid->name, - ob->proxy->id.name); - continue; - } - - BKE_library_ID_test_usages(bmain, id, &is_local, &is_lib); - - /* We can only switch the proxy'ing to a made-local proxy if it is no longer - * referred to from a library. Not checking for local use; if new local proxy - * was not used locally would be a nasty bug! */ - if (is_local || is_lib) { - CLOG_WARN(&LOG, - "Made-local proxy object %s will lose its link to %s, " - "because the linked-in proxy is referenced (is_local=%i, is_lib=%i)", - id->newid->name, - ob->proxy->id.name, - is_local, - is_lib); - } - else { - /* we can switch the proxy'ing from the linked-in to the made-local proxy. - * BKE_object_make_proxy() shouldn't be used here, as it allocates memory that - * was already allocated by object_make_local() (which called BKE_object_copy). */ - ob_new->proxy = ob->proxy; - ob_new->proxy_group = ob->proxy_group; - ob_new->proxy_from = ob->proxy_from; - ob_new->proxy->proxy_from = ob_new; - ob->proxy = ob->proxy_from = ob->proxy_group = NULL; - } - } - } - - BKE_main_id_newptr_and_tag_clear(bmain); -} - -static void wm_link_do(WMLinkAppendData *lapp_data, - ReportList *reports, - Main *bmain, - Scene *scene, - ViewLayer *view_layer, - const View3D *v3d) -{ - Main *mainl; - BlendHandle *bh; - Library *lib; - - const int flag = lapp_data->flag; - const int id_tag_extra = 0; - - LinkNode *liblink, *itemlink; - int lib_idx, item_idx; - - BLI_assert(lapp_data->num_items && lapp_data->num_libraries); - - for (lib_idx = 0, liblink = lapp_data->libraries.list; liblink; - lib_idx++, liblink = liblink->next) { - char *libname = liblink->link; - BlendFileReadReport bf_reports = {.reports = reports}; - - if (STREQ(libname, BLO_EMBEDDED_STARTUP_BLEND)) { - bh = BLO_blendhandle_from_memory( - datatoc_startup_blend, datatoc_startup_blend_size, &bf_reports); - } - else { - bh = BLO_blendhandle_from_file(libname, &bf_reports); - } - - if (bh == NULL) { - /* Unlikely since we just browsed it, but possible - * Error reports will have been made by BLO_blendhandle_from_file() */ - continue; - } - - /* here appending/linking starts */ - struct LibraryLink_Params liblink_params; - BLO_library_link_params_init_with_context( - &liblink_params, bmain, flag, id_tag_extra, scene, view_layer, v3d); - /* In case of append, do not handle instantiation in linking process, but during append phase - * (see #wm_append_loose_data_instantiate ). */ - if ((flag & FILE_LINK) == 0) { - liblink_params.flag &= ~BLO_LIBLINK_NEEDS_ID_TAG_DOIT; - } - - mainl = BLO_library_link_begin(&bh, libname, &liblink_params); - lib = mainl->curlib; - BLI_assert(lib); - UNUSED_VARS_NDEBUG(lib); - - if (mainl->versionfile < 250) { - BKE_reportf(reports, - RPT_WARNING, - "Linking or appending from a very old .blend file format (%d.%d), no animation " - "conversion will " - "be done! You may want to re-save your lib file with current Blender", - mainl->versionfile, - mainl->subversionfile); - } - - /* For each lib file, we try to link all items belonging to that lib, - * and tag those successful to not try to load them again with the other libs. */ - for (item_idx = 0, itemlink = lapp_data->items.list; itemlink; - item_idx++, itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - ID *new_id; - - if (!BLI_BITMAP_TEST(item->libraries, lib_idx)) { - continue; - } - - new_id = BLO_library_link_named_part(mainl, &bh, item->idcode, item->name, &liblink_params); - - if (new_id) { - /* If the link is successful, clear item's libs 'todo' flags. - * This avoids trying to link same item with other libraries to come. */ - BLI_bitmap_set_all(item->libraries, false, lapp_data->num_libraries); - item->new_id = new_id; - item->source_library = new_id->lib; - } - } - - BLO_library_link_end(mainl, &bh, &liblink_params); - BLO_blendhandle_close(bh); - } -} - /** * Check if an item defined by \a name and \a group can be appended/linked. * @@ -1053,7 +218,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); PropertyRNA *prop; - WMLinkAppendData *lapp_data; + BlendfileLinkAppendContext *lapp_context; char path[FILE_MAX_LIBEXTRA], root[FILE_MAXDIR], libname[FILE_MAX_LIBEXTRA], relname[FILE_MAX]; char *group, *name; int totfiles = 0; @@ -1120,7 +285,14 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) /* We define our working data... * Note that here, each item 'uses' one library, and only one. */ - lapp_data = wm_link_append_data_new(flag); + LibraryLink_Params lapp_params; + BLO_library_link_params_init_with_context( + &lapp_params, bmain, flag, 0, scene, view_layer, CTX_wm_view3d(C)); + + lapp_context = BKE_blendfile_link_append_context_new(&lapp_params); + BKE_blendfile_link_append_context_embedded_blendfile_set( + lapp_context, datatoc_startup_blend, datatoc_startup_blend_size); + if (totfiles != 0) { GHash *libraries = BLI_ghash_new(BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, __func__); int lib_idx = 0; @@ -1138,7 +310,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) if (!BLI_ghash_haskey(libraries, libname)) { BLI_ghash_insert(libraries, BLI_strdup(libname), POINTER_FROM_INT(lib_idx)); lib_idx++; - wm_link_append_data_library_add(lapp_data, libname); + BKE_blendfile_link_append_context_library_add(lapp_context, libname, NULL); } } } @@ -1150,7 +322,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) BLI_join_dirfile(path, sizeof(path), root, relname); if (BLO_library_path_explode(path, libname, &group, &name)) { - WMLinkAppendDataItem *item; + BlendfileLinkAppendContextItem *item; if (!wm_link_append_item_poll(op->reports, path, group, name, do_append)) { continue; @@ -1158,9 +330,9 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) lib_idx = POINTER_AS_INT(BLI_ghash_lookup(libraries, libname)); - item = wm_link_append_data_item_add( - lapp_data, name, BKE_idtype_idcode_from_name(group), NULL); - BLI_BITMAP_ENABLE(item->libraries, lib_idx); + item = BKE_blendfile_link_append_context_item_add( + lapp_context, name, BKE_idtype_idcode_from_name(group), NULL); + BKE_blendfile_link_append_context_item_library_index_enable(lapp_context, item, lib_idx); } } RNA_END; @@ -1168,16 +340,17 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) BLI_ghash_free(libraries, MEM_freeN, NULL); } else { - WMLinkAppendDataItem *item; + BlendfileLinkAppendContextItem *item; - wm_link_append_data_library_add(lapp_data, libname); - item = wm_link_append_data_item_add(lapp_data, name, BKE_idtype_idcode_from_name(group), NULL); - BLI_BITMAP_ENABLE(item->libraries, 0); + BKE_blendfile_link_append_context_library_add(lapp_context, libname, NULL); + item = BKE_blendfile_link_append_context_item_add( + lapp_context, name, BKE_idtype_idcode_from_name(group), NULL); + BKE_blendfile_link_append_context_item_library_index_enable(lapp_context, item, 0); } - if (lapp_data->num_items == 0) { + if (BKE_blendfile_link_append_context_is_empty(lapp_context)) { /* Early out in case there is nothing to link. */ - wm_link_append_data_free(lapp_data); + BKE_blendfile_link_append_context_free(lapp_context); /* Clear pre existing tag. */ BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false); return OPERATOR_CANCELLED; @@ -1186,7 +359,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) /* XXX We'd need re-entrant locking on Main for this to work... */ // BKE_main_lock(bmain); - wm_link_do(lapp_data, op->reports, bmain, scene, view_layer, CTX_wm_view3d(C)); + BKE_blendfile_link(lapp_context, op->reports); // BKE_main_unlock(bmain); @@ -1196,10 +369,10 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) /* append, rather than linking */ if (do_append) { - wm_append_do(lapp_data, op->reports, bmain, scene, view_layer, CTX_wm_view3d(C)); + BKE_blendfile_append(lapp_context, op->reports); } - wm_link_append_data_free(lapp_data); + BKE_blendfile_link_append_context_free(lapp_context); /* important we unset, otherwise these object won't * link into other scenes from this blend file */ @@ -1351,33 +524,35 @@ static ID *wm_file_link_append_datablock_ex(Main *bmain, BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true); /* Define working data, with just the one item we want to link. */ - WMLinkAppendData *lapp_data = wm_link_append_data_new(flag); + LibraryLink_Params lapp_params; + BLO_library_link_params_init_with_context(&lapp_params, bmain, flag, 0, scene, view_layer, v3d); + + BlendfileLinkAppendContext *lapp_context = BKE_blendfile_link_append_context_new(&lapp_params); + BKE_blendfile_link_append_context_embedded_blendfile_set( + lapp_context, datatoc_startup_blend, datatoc_startup_blend_size); - wm_link_append_data_library_add(lapp_data, filepath); - WMLinkAppendDataItem *item = wm_link_append_data_item_add(lapp_data, id_name, id_code, NULL); - BLI_BITMAP_ENABLE(item->libraries, 0); + BKE_blendfile_link_append_context_library_add(lapp_context, filepath, NULL); + BlendfileLinkAppendContextItem *item = BKE_blendfile_link_append_context_item_add( + lapp_context, id_name, id_code, NULL); + BKE_blendfile_link_append_context_item_library_index_enable(lapp_context, item, 0); /* Link datablock. */ - wm_link_do(lapp_data, NULL, bmain, scene, view_layer, v3d); + BKE_blendfile_link(lapp_context, NULL); if (do_append) { - wm_append_do(lapp_data, NULL, bmain, scene, view_layer, v3d); + BKE_blendfile_append(lapp_context, NULL); } /* Get linked datablock and free working data. */ - ID *id = item->new_id; + ID *id = BKE_blendfile_link_append_context_item_newid_get(lapp_context, item); - wm_link_append_data_free(lapp_data); + BKE_blendfile_link_append_context_free(lapp_context); BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false); return id; } -/* - * NOTE: `scene` (and related `view_layer` and `v3d`) pointers may be NULL, in which case no - * instantiation of linked objects, collections etc. will be performed. - */ ID *WM_file_link_datablock(Main *bmain, Scene *scene, ViewLayer *view_layer, @@ -1392,10 +567,6 @@ ID *WM_file_link_datablock(Main *bmain, bmain, scene, view_layer, v3d, filepath, id_code, id_name, flag); } -/* - * NOTE: `scene` (and related `view_layer` and `v3d`) pointers may be NULL, in which case no - * instantiation of appended objects, collections etc. will be performed. - */ ID *WM_file_append_datablock(Main *bmain, Scene *scene, ViewLayer *view_layer, @@ -1444,291 +615,6 @@ static int wm_lib_relocate_invoke(bContext *C, wmOperator *op, const wmEvent *UN return OPERATOR_CANCELLED; } -static void lib_relocate_do_remap(Main *bmain, - ID *old_id, - ID *new_id, - ReportList *reports, - const bool do_reload, - const short remap_flags) -{ - BLI_assert(old_id); - if (do_reload) { - /* Since we asked for placeholders in case of missing IDs, - * we expect to always get a valid one. */ - BLI_assert(new_id); - } - if (new_id) { - CLOG_INFO(&LOG, - 4, - "Before remap of %s, old_id users: %d, new_id users: %d", - old_id->name, - old_id->us, - new_id->us); - BKE_libblock_remap_locked(bmain, old_id, new_id, remap_flags); - - if (old_id->flag & LIB_FAKEUSER) { - id_fake_user_clear(old_id); - id_fake_user_set(new_id); - } - - CLOG_INFO(&LOG, - 4, - "After remap of %s, old_id users: %d, new_id users: %d", - old_id->name, - old_id->us, - new_id->us); - - /* In some cases, new_id might become direct link, remove parent of library in this case. */ - if (new_id->lib->parent && (new_id->tag & LIB_TAG_INDIRECT) == 0) { - if (do_reload) { - BLI_assert_unreachable(); /* Should not happen in 'pure' reload case... */ - } - new_id->lib->parent = NULL; - } - } - - if (old_id->us > 0 && new_id && old_id->lib == new_id->lib) { - /* Note that this *should* not happen - but better be safe than sorry in this area, - * at least until we are 100% sure this cannot ever happen. - * Also, we can safely assume names were unique so far, - * so just replacing '.' by '~' should work, - * but this does not totally rules out the possibility of name collision. */ - size_t len = strlen(old_id->name); - size_t dot_pos; - bool has_num = false; - - for (dot_pos = len; dot_pos--;) { - char c = old_id->name[dot_pos]; - if (c == '.') { - break; - } - if (c < '0' || c > '9') { - has_num = false; - break; - } - has_num = true; - } - - if (has_num) { - old_id->name[dot_pos] = '~'; - } - else { - len = MIN2(len, MAX_ID_NAME - 7); - BLI_strncpy(&old_id->name[len], "~000", 7); - } - - id_sort_by_name(which_libbase(bmain, GS(old_id->name)), old_id, NULL); - - BKE_reportf( - reports, - RPT_WARNING, - "Lib Reload: Replacing all references to old data-block '%s' by reloaded one failed, " - "old one (%d remaining users) had to be kept and was renamed to '%s'", - new_id->name, - old_id->us, - old_id->name); - } -} - -static void lib_relocate_do(bContext *C, - Library *library, - WMLinkAppendData *lapp_data, - ReportList *reports, - const bool do_reload) -{ - ListBase *lbarray[INDEX_ID_MAX]; - int lba_idx; - - LinkNode *itemlink; - int item_idx; - - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - - /* Remove all IDs to be reloaded from Main. */ - lba_idx = set_listbasepointers(bmain, lbarray); - while (lba_idx--) { - ID *id = lbarray[lba_idx]->first; - const short idcode = id ? GS(id->name) : 0; - - if (!id || !BKE_idtype_idcode_is_linkable(idcode)) { - /* No need to reload non-linkable datatypes, - * those will get relinked with their 'users ID'. */ - continue; - } - - for (; id; id = id->next) { - if (id->lib == library) { - WMLinkAppendDataItem *item; - - /* We remove it from current Main, and add it to items to link... */ - /* Note that non-linkable IDs (like e.g. shapekeys) are also explicitly linked here... */ - BLI_remlink(lbarray[lba_idx], id); - /* Usual special code for ShapeKeys snowflakes... */ - Key *old_key = BKE_key_from_id(id); - if (old_key != NULL) { - BLI_remlink(which_libbase(bmain, GS(old_key->id.name)), &old_key->id); - } - - item = wm_link_append_data_item_add(lapp_data, id->name + 2, idcode, id); - BLI_bitmap_set_all(item->libraries, true, lapp_data->num_libraries); - - CLOG_INFO(&LOG, 4, "Datablock to seek for: %s", id->name); - } - } - } - - if (lapp_data->num_items == 0) { - /* Early out in case there is nothing to do. */ - return; - } - - BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true); - - /* We do not want any instantiation here! */ - wm_link_do(lapp_data, reports, bmain, NULL, NULL, NULL); - - BKE_main_lock(bmain); - - /* We add back old id to bmain. - * We need to do this in a first, separated loop, otherwise some of those may not be handled by - * ID remapping, which means they would still reference old data to be deleted... */ - for (item_idx = 0, itemlink = lapp_data->items.list; itemlink; - item_idx++, itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - ID *old_id = item->customdata; - - BLI_assert(old_id); - BLI_addtail(which_libbase(bmain, GS(old_id->name)), old_id); - - /* Usual special code for ShapeKeys snowflakes... */ - Key *old_key = BKE_key_from_id(old_id); - if (old_key != NULL) { - BLI_addtail(which_libbase(bmain, GS(old_key->id.name)), &old_key->id); - } - } - - /* Since our (old) reloaded IDs were removed from main, the user count done for them in linking - * code is wrong, we need to redo it here after adding them back to main. */ - BKE_main_id_refcount_recompute(bmain, false); - - /* Note that in reload case, we also want to replace indirect usages. */ - const short remap_flags = ID_REMAP_SKIP_NEVER_NULL_USAGE | - ID_REMAP_NO_INDIRECT_PROXY_DATA_USAGE | - (do_reload ? 0 : ID_REMAP_SKIP_INDIRECT_USAGE); - for (item_idx = 0, itemlink = lapp_data->items.list; itemlink; - item_idx++, itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - ID *old_id = item->customdata; - ID *new_id = item->new_id; - - lib_relocate_do_remap(bmain, old_id, new_id, reports, do_reload, remap_flags); - if (new_id == NULL) { - continue; - } - /* Usual special code for ShapeKeys snowflakes... */ - Key **old_key_p = BKE_key_from_id_p(old_id); - if (old_key_p == NULL) { - continue; - } - Key *old_key = *old_key_p; - Key *new_key = BKE_key_from_id(new_id); - if (old_key != NULL) { - *old_key_p = NULL; - id_us_min(&old_key->id); - lib_relocate_do_remap(bmain, &old_key->id, &new_key->id, reports, do_reload, remap_flags); - *old_key_p = old_key; - id_us_plus_no_lib(&old_key->id); - } - } - - BKE_main_unlock(bmain); - - for (item_idx = 0, itemlink = lapp_data->items.list; itemlink; - item_idx++, itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - ID *old_id = item->customdata; - - if (old_id->us == 0) { - BKE_id_free(bmain, old_id); - } - } - - /* Some datablocks can get reloaded/replaced 'silently' because they are not linkable - * (shape keys e.g.), so we need another loop here to clear old ones if possible. */ - lba_idx = set_listbasepointers(bmain, lbarray); - while (lba_idx--) { - ID *id, *id_next; - for (id = lbarray[lba_idx]->first; id; id = id_next) { - id_next = id->next; - /* XXX That check may be a bit to generic/permissive? */ - if (id->lib && (id->flag & LIB_TAG_PRE_EXISTING) && id->us == 0) { - BKE_id_free(bmain, id); - } - } - } - - /* Get rid of no more used libraries... */ - BKE_main_id_tag_idcode(bmain, ID_LI, LIB_TAG_DOIT, true); - lba_idx = set_listbasepointers(bmain, lbarray); - while (lba_idx--) { - ID *id; - for (id = lbarray[lba_idx]->first; id; id = id->next) { - if (id->lib) { - id->lib->id.tag &= ~LIB_TAG_DOIT; - } - } - } - Library *lib, *lib_next; - for (lib = which_libbase(bmain, ID_LI)->first; lib; lib = lib_next) { - lib_next = lib->id.next; - if (lib->id.tag & LIB_TAG_DOIT) { - id_us_clear_real(&lib->id); - if (lib->id.us == 0) { - BKE_id_free(bmain, (ID *)lib); - } - } - } - - /* Update overrides of reloaded linked data-blocks. */ - ID *id; - FOREACH_MAIN_ID_BEGIN (bmain, id) { - if (ID_IS_LINKED(id) || !ID_IS_OVERRIDE_LIBRARY_REAL(id) || - (id->tag & LIB_TAG_PRE_EXISTING) == 0) { - continue; - } - if ((id->override_library->reference->tag & LIB_TAG_PRE_EXISTING) == 0) { - BKE_lib_override_library_update(bmain, id); - } - } - FOREACH_MAIN_ID_END; - - /* Resync overrides if needed. */ - if (!USER_EXPERIMENTAL_TEST(&U, no_override_auto_resync)) { - BKE_lib_override_library_main_resync(bmain, - scene, - view_layer, - &(struct BlendFileReadReport){ - .reports = reports, - }); - /* We need to rebuild some of the deleted override rules (for UI feedback purpose). */ - BKE_lib_override_library_main_operations_create(bmain, true); - } - - BKE_main_collection_sync(bmain); - - BKE_main_lib_objects_recalc_all(bmain); - IMB_colormanagement_check_file_config(bmain); - - /* important we unset, otherwise these object won't - * link into other scenes from this blend file */ - BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false); - - /* recreate dependency graph to include new objects */ - DEG_relations_tag_update(bmain); -} - void WM_lib_reload(Library *lib, bContext *C, ReportList *reports) { if (!BLO_has_bfile_extension(lib->filepath_abs)) { @@ -1745,14 +631,34 @@ void WM_lib_reload(Library *lib, bContext *C, ReportList *reports) return; } - WMLinkAppendData *lapp_data = wm_link_append_data_new(BLO_LIBLINK_USE_PLACEHOLDERS | - BLO_LIBLINK_FORCE_INDIRECT); + Main *bmain = CTX_data_main(C); + LibraryLink_Params lapp_params; + BLO_library_link_params_init_with_context(&lapp_params, + bmain, + BLO_LIBLINK_USE_PLACEHOLDERS | + BLO_LIBLINK_FORCE_INDIRECT, + 0, + CTX_data_scene(C), + CTX_data_view_layer(C), + NULL); - wm_link_append_data_library_add(lapp_data, lib->filepath_abs); + BlendfileLinkAppendContext *lapp_context = BKE_blendfile_link_append_context_new(&lapp_params); + + BKE_blendfile_link_append_context_library_add(lapp_context, lib->filepath_abs, NULL); + + BKE_blendfile_library_relocate(lapp_context, reports, lib, true); + + BKE_blendfile_link_append_context_free(lapp_context); + + BKE_main_lib_objects_recalc_all(bmain); + IMB_colormanagement_check_file_config(bmain); - lib_relocate_do(C, lib, lapp_data, reports, true); + /* Important we unset, otherwise these object won't link into other scenes from this blend file. + */ + BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false); - wm_link_append_data_free(lapp_data); + /* Recreate dependency graph to include new IDs. */ + DEG_relations_tag_update(bmain); WM_event_add_notifier(C, NC_WINDOW, NULL); } @@ -1768,7 +674,7 @@ static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload) if (lib) { Main *bmain = CTX_data_main(C); PropertyRNA *prop; - WMLinkAppendData *lapp_data; + BlendfileLinkAppendContext *lapp_context; char path[FILE_MAX], root[FILE_MAXDIR], libname[FILE_MAX], relname[FILE_MAX]; short flag = 0; @@ -1813,13 +719,17 @@ static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload) return OPERATOR_CANCELLED; } + LibraryLink_Params lapp_params; + BLO_library_link_params_init_with_context( + &lapp_params, bmain, flag, 0, CTX_data_scene(C), CTX_data_view_layer(C), NULL); + if (BLI_path_cmp(lib->filepath_abs, path) == 0) { CLOG_INFO(&LOG, 4, "We are supposed to reload '%s' lib (%d)", lib->filepath, lib->id.us); do_reload = true; - lapp_data = wm_link_append_data_new(flag); - wm_link_append_data_library_add(lapp_data, path); + lapp_context = BKE_blendfile_link_append_context_new(&lapp_params); + BKE_blendfile_link_append_context_library_add(lapp_context, path, NULL); } else { int totfiles = 0; @@ -1839,7 +749,7 @@ static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload) } } - lapp_data = wm_link_append_data_new(flag); + lapp_context = BKE_blendfile_link_append_context_new(&lapp_params); if (totfiles) { RNA_BEGIN (op->ptr, itemptr, "files") { @@ -1852,27 +762,39 @@ static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload) } CLOG_INFO(&LOG, 4, "\tCandidate new lib to reload datablocks from: %s", path); - wm_link_append_data_library_add(lapp_data, path); + BKE_blendfile_link_append_context_library_add(lapp_context, path, NULL); } RNA_END; } else { CLOG_INFO(&LOG, 4, "\tCandidate new lib to reload datablocks from: %s", path); - wm_link_append_data_library_add(lapp_data, path); + BKE_blendfile_link_append_context_library_add(lapp_context, path, NULL); } } if (do_reload) { - lapp_data->flag |= BLO_LIBLINK_USE_PLACEHOLDERS | BLO_LIBLINK_FORCE_INDIRECT; + BKE_blendfile_link_append_context_flag_set( + lapp_context, BLO_LIBLINK_USE_PLACEHOLDERS | BLO_LIBLINK_FORCE_INDIRECT, true); } - lib_relocate_do(C, lib, lapp_data, op->reports, do_reload); + BKE_blendfile_library_relocate(lapp_context, op->reports, lib, do_reload); - wm_link_append_data_free(lapp_data); + BKE_blendfile_link_append_context_free(lapp_context); /* XXX TODO: align G.lib with other directory storage (like last opened image etc...) */ BLI_strncpy(G.lib, root, FILE_MAX); + BKE_main_lib_objects_recalc_all(bmain); + IMB_colormanagement_check_file_config(bmain); + + /* Important we unset, otherwise these object won't link into other scenes from this blend + * file. + */ + BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false); + + /* Recreate dependency graph to include new IDs. */ + DEG_relations_tag_update(bmain); + WM_event_add_notifier(C, NC_WINDOW, NULL); return OPERATOR_FINISHED; diff --git a/source/blender/windowmanager/intern/wm_gesture.c b/source/blender/windowmanager/intern/wm_gesture.c index ab971901a20..47f51214a8e 100644 --- a/source/blender/windowmanager/intern/wm_gesture.c +++ b/source/blender/windowmanager/intern/wm_gesture.c @@ -50,7 +50,6 @@ #include "BIF_glutil.h" -/* context checked on having screen, window and area */ wmGesture *WM_gesture_new(wmWindow *window, const ARegion *region, const wmEvent *event, int type) { wmGesture *gesture = MEM_callocN(sizeof(wmGesture), "new gesture"); @@ -129,7 +128,6 @@ bool WM_gesture_is_modal_first(const wmGesture *gesture) return (gesture->is_active_prev == false); } -/* tweak and line gestures */ int wm_gesture_evaluate(wmGesture *gesture, const wmEvent *event) { if (gesture->type == WM_GESTURE_TWEAK) { @@ -515,7 +513,6 @@ static void wm_gesture_draw_cross(wmWindow *win, wmGesture *gt) immUnbindProgram(); } -/* called in wm_draw.c */ void wm_gesture_draw(wmWindow *win) { wmGesture *gt = (wmGesture *)win->gesture.first; diff --git a/source/blender/windowmanager/intern/wm_gesture_ops.c b/source/blender/windowmanager/intern/wm_gesture_ops.c index 19b678d79d8..8d45d5aed67 100644 --- a/source/blender/windowmanager/intern/wm_gesture_ops.c +++ b/source/blender/windowmanager/intern/wm_gesture_ops.c @@ -124,6 +124,7 @@ static int UNUSED_FUNCTION(gesture_modal_state_from_operator)(wmOperator *op) } return GESTURE_MODAL_NOP; } + /** \} */ /* -------------------------------------------------------------------- */ @@ -569,7 +570,6 @@ static void gesture_tweak_modal(bContext *C, const wmEvent *event) } } -/* standard tweak, called after window handlers passed on event */ void wm_tweakevent_test(bContext *C, const wmEvent *event, int action) { wmWindow *win = CTX_wm_window(C); @@ -750,11 +750,6 @@ void WM_gesture_lines_cancel(bContext *C, wmOperator *op) gesture_modal_end(C, op); } -/** - * helper function, we may want to add options for conversion to view space - * - * caller must free. - */ const int (*WM_gesture_lasso_path_to_array(bContext *UNUSED(C), wmOperator *op, int *r_mcoords_len))[2] @@ -889,10 +884,6 @@ int WM_gesture_straightline_invoke(bContext *C, wmOperator *op, const wmEvent *e return OPERATOR_RUNNING_MODAL; } -/** - * This invoke callback starts the straightline gesture with a viewport preview to the right side - * of the line. - */ int WM_gesture_straightline_active_side_invoke(bContext *C, wmOperator *op, const wmEvent *event) { WM_gesture_straightline_invoke(C, op, event); @@ -928,11 +919,6 @@ static void wm_gesture_straightline_do_angle_snap(rcti *rect) rect->ymax = (int)line_snapped_end[1]; } -/** - * This modal callback calls exec once per mouse move event while the gesture is active with the - * updated line start and end values, so it can be used for tools that have a real time preview - * (like a gradient updating in real time over the mesh). - */ int WM_gesture_straightline_modal(bContext *C, wmOperator *op, const wmEvent *event) { wmGesture *gesture = op->customdata; @@ -1012,13 +998,6 @@ int WM_gesture_straightline_modal(bContext *C, wmOperator *op, const wmEvent *ev return OPERATOR_RUNNING_MODAL; } -/** - * This modal one-shot callback only calls exec once after the gesture finishes without any updates - * during the gesture execution. Should be used for operations that are intended to be applied once - * without real time preview (like a trimming tool that only applies the bisect operation once - * after finishing the gesture as the bisect operation is too heavy to be computed in real time for - * a preview). - */ int WM_gesture_straightline_oneshot_modal(bContext *C, wmOperator *op, const wmEvent *event) { wmGesture *gesture = op->customdata; diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index c382af03c4a..2f87e5789fe 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -223,10 +223,6 @@ static void sound_jack_sync_callback(Main *bmain, int mode, double time) } } -/** - * Initialize Blender and load the startup file & preferences - * (only called once). - */ void WM_init(bContext *C, int argc, const char **argv) { @@ -318,9 +314,9 @@ void WM_init(bContext *C, int argc, const char **argv) NULL, ¶ms_file_read_post); - /* NOTE: leave `G_MAIN->name` set to an empty string since this + /* NOTE: leave `G_MAIN->filepath` set to an empty string since this * matches behavior after loading a new file. */ - BLI_assert(G_MAIN->name[0] == '\0'); + BLI_assert(G_MAIN->filepath[0] == '\0'); /* Call again to set from preferences. */ BLT_lang_set(NULL); @@ -432,10 +428,6 @@ static int wm_exit_handler(bContext *C, const wmEvent *event, void *userdata) return WM_UI_HANDLER_BREAK; } -/** - * Cause a delayed #WM_exit() - * call to avoid leaking memory when trying to exit from within operators. - */ void wm_exit_schedule_delayed(const bContext *C) { /* What we do here is a little bit hacky, but quite simple and doesn't require bigger @@ -449,9 +441,6 @@ void wm_exit_schedule_delayed(const bContext *C) WM_event_add_mousemove(win); /* ensure handler actually gets called */ } -/** - * \note doesn't run exit() call #WM_exit() for that. - */ void WM_exit_ex(bContext *C, const bool do_python) { wmWindowManager *wm = C ? CTX_wm_manager(C) : NULL; @@ -547,6 +536,7 @@ void WM_exit_ex(bContext *C, const bool do_python) RE_engines_exit(); ED_preview_free_dbase(); /* frees a Main dbase, before BKE_blender_free! */ + ED_preview_restart_queue_free(); ED_assetlist_storage_exit(); if (wm) { @@ -655,11 +645,6 @@ void WM_exit_ex(bContext *C, const bool do_python) BKE_tempdir_session_purge(); } -/** - * \brief Main exit function to close Blender ordinarily. - * \note Use #wm_exit_schedule_delayed() to close Blender from an operator. - * Might leak memory otherwise. - */ void WM_exit(bContext *C) { WM_exit_ex(C, true); @@ -677,10 +662,6 @@ void WM_exit(bContext *C) exit(G.is_break == true); } -/** - * Needed for cases when operators are re-registered - * (when operator type pointers are stored). - */ void WM_script_tag_reload(void) { UI_interface_tag_script_reload(); diff --git a/source/blender/windowmanager/intern/wm_jobs.c b/source/blender/windowmanager/intern/wm_jobs.c index 2604105896d..66277ec57f4 100644 --- a/source/blender/windowmanager/intern/wm_jobs.c +++ b/source/blender/windowmanager/intern/wm_jobs.c @@ -187,12 +187,6 @@ static wmJob *wm_job_find(const wmWindowManager *wm, const void *owner, const in /* ******************* public API ***************** */ -/** - * \return current job or adds new job, but doesn't run it. - * - * \note every owner only gets a single job, - * adding a new one will stop running job and when stopped it starts the new one. - */ wmJob *WM_jobs_get(wmWindowManager *wm, wmWindow *win, const void *owner, @@ -223,7 +217,6 @@ wmJob *WM_jobs_get(wmWindowManager *wm, return wm_job; } -/* returns true if job runs, for UI (progress) indicators */ bool WM_jobs_test(const wmWindowManager *wm, const void *owner, int job_type) { /* job can be running or about to run (suspended) */ @@ -281,7 +274,6 @@ static void wm_jobs_update_progress_bars(wmWindowManager *wm) } } -/* time that job started */ double WM_jobs_starttime(const wmWindowManager *wm, const void *owner) { const wmJob *wm_job = wm_job_find(wm, owner, WM_JOB_TYPE_ANY); @@ -447,10 +439,6 @@ static void wm_jobs_test_suspend_stop(wmWindowManager *wm, wmJob *test) #endif } -/** - * if job running, the same owner gave it a new job. - * if different owner starts existing startjob, it suspends itself - */ void WM_jobs_start(wmWindowManager *wm, wmJob *wm_job) { if (wm_job->running) { @@ -550,7 +538,6 @@ static void wm_jobs_kill_job(wmWindowManager *wm, wmJob *wm_job) } } -/* wait until every job ended */ void WM_jobs_kill_all(wmWindowManager *wm) { wmJob *wm_job; @@ -563,7 +550,6 @@ void WM_jobs_kill_all(wmWindowManager *wm) SEQ_prefetch_stop_all(); } -/* wait until every job ended, except for one owner (used in undo to keep screen job alive) */ void WM_jobs_kill_all_except(wmWindowManager *wm, const void *owner) { LISTBASE_FOREACH_MUTABLE (wmJob *, wm_job, &wm->jobs) { @@ -584,7 +570,6 @@ void WM_jobs_kill_type(struct wmWindowManager *wm, const void *owner, int job_ty } } -/* signal job(s) from this owner or callback to stop, timer is required to get handled */ void WM_jobs_stop(wmWindowManager *wm, const void *owner, void *startjob) { LISTBASE_FOREACH (wmJob *, wm_job, &wm->jobs) { @@ -596,7 +581,6 @@ void WM_jobs_stop(wmWindowManager *wm, const void *owner, void *startjob) } } -/* actually terminate thread and job timer */ void WM_jobs_kill(wmWindowManager *wm, void *owner, void (*startjob)(void *, short int *, short int *, float *)) @@ -608,7 +592,6 @@ void WM_jobs_kill(wmWindowManager *wm, } } -/* kill job entirely, also removes timer itself */ void wm_jobs_timer_end(wmWindowManager *wm, wmTimer *wt) { LISTBASE_FOREACH (wmJob *, wm_job, &wm->jobs) { @@ -619,7 +602,6 @@ void wm_jobs_timer_end(wmWindowManager *wm, wmTimer *wt) } } -/* hardcoded to event TIMERJOBS */ void wm_jobs_timer(wmWindowManager *wm, wmTimer *wt) { LISTBASE_FOREACH_MUTABLE (wmJob *, wm_job, &wm->jobs) { diff --git a/source/blender/windowmanager/intern/wm_keymap.c b/source/blender/windowmanager/intern/wm_keymap.c index 35f6ce40dba..0214fce59b2 100644 --- a/source/blender/windowmanager/intern/wm_keymap.c +++ b/source/blender/windowmanager/intern/wm_keymap.c @@ -189,7 +189,6 @@ static bool wm_keymap_item_equals(wmKeyMapItem *a, wmKeyMapItem *b) (a->flag & KMI_REPEAT_IGNORE) == (b->flag & KMI_REPEAT_IGNORE))); } -/* properties can be NULL, otherwise the arg passed is used and ownership is given to the kmi */ void WM_keymap_item_properties_reset(wmKeyMapItem *kmi, struct IDProperty *properties) { if (LIKELY(kmi->ptr)) { @@ -514,7 +513,6 @@ static void keymap_item_set_id(wmKeyMap *keymap, wmKeyMapItem *kmi) } } -/* always add item */ wmKeyMapItem *WM_keymap_add_item( wmKeyMap *keymap, const char *idname, int type, int val, int modifier, int keymodifier) { @@ -1150,7 +1148,6 @@ const char *WM_key_event_string(const short type, const bool compact) return CTX_IFACE_(BLT_I18NCONTEXT_UI_EVENTS, it->name); } -/* TODO: also support (some) value, like e.g. double-click? */ int WM_keymap_item_raw_to_string(const short shift, const short ctrl, const short alt, @@ -1162,6 +1159,8 @@ int WM_keymap_item_raw_to_string(const short shift, char *result, const int result_len) { + /* TODO: also support (some) value, like e.g. double-click? */ + #define ADD_SEP \ if (p != buf) { \ *p++ = ' '; \ @@ -1307,6 +1306,10 @@ char *WM_modalkeymap_operator_items_to_string_buf(wmOperatorType *ot, /** \} */ +/* -------------------------------------------------------------------- */ +/** \name Keymap Finding Utilities + * \{ */ + static wmKeyMapItem *wm_keymap_item_find_in_keymap(wmKeyMap *keymap, const char *opname, IDProperty *properties, @@ -1676,10 +1679,6 @@ static bool kmi_filter_is_visible_type_mask(const wmKeyMap *km, kmi_filter_is_visible(km, kmi, user_data)); } -/** - * \param include_mask, exclude_mask: - * Event types to include/exclude when looking up keys (#eEventType_Mask). - */ wmKeyMapItem *WM_key_event_operator(const bContext *C, const char *opname, wmOperatorCallContext opcontext, diff --git a/source/blender/windowmanager/intern/wm_keymap_utils.c b/source/blender/windowmanager/intern/wm_keymap_utils.c index 795f78e215f..d424eef8262 100644 --- a/source/blender/windowmanager/intern/wm_keymap_utils.c +++ b/source/blender/windowmanager/intern/wm_keymap_utils.c @@ -43,7 +43,6 @@ /** \name Wrappers for #WM_keymap_add_item * \{ */ -/* menu wrapper for WM_keymap_add_item */ wmKeyMapItem *WM_keymap_add_menu( wmKeyMap *keymap, const char *idname, int type, int val, int modifier, int keymodifier) { @@ -73,7 +72,6 @@ wmKeyMapItem *WM_keymap_add_panel( return kmi; } -/* tool wrapper for WM_keymap_add_item */ wmKeyMapItem *WM_keymap_add_tool( wmKeyMap *keymap, const char *idname, int type, int val, int modifier, int keymodifier) { @@ -83,7 +81,6 @@ wmKeyMapItem *WM_keymap_add_tool( return kmi; } -/** Useful for mapping numbers to an enum. */ void WM_keymap_add_context_enum_set_items(wmKeyMap *keymap, const EnumPropertyItem *items, const char *data_path, @@ -203,8 +200,6 @@ wmKeyMap *WM_keymap_guess_from_context(const bContext *C) return km; } -/* Guess an appropriate keymap from the operator name */ -/* Needs to be kept up to date with Keymap and Operator naming */ wmKeyMap *WM_keymap_guess_opname(const bContext *C, const char *opname) { /* Op types purposely skipped for now: diff --git a/source/blender/windowmanager/intern/wm_menu_type.c b/source/blender/windowmanager/intern/wm_menu_type.c index bcaa2243f9f..799b6fc2e52 100644 --- a/source/blender/windowmanager/intern/wm_menu_type.c +++ b/source/blender/windowmanager/intern/wm_menu_type.c @@ -77,7 +77,6 @@ void WM_menutype_freelink(MenuType *mt) UNUSED_VARS_NDEBUG(ok); } -/* called on initialize WM_init() */ void WM_menutype_init(void) { /* reserve size is set based on blender default setup */ diff --git a/source/blender/windowmanager/intern/wm_operator_props.c b/source/blender/windowmanager/intern/wm_operator_props.c index 898671706d1..a5887fc07b3 100644 --- a/source/blender/windowmanager/intern/wm_operator_props.c +++ b/source/blender/windowmanager/intern/wm_operator_props.c @@ -72,7 +72,6 @@ static const EnumPropertyItem *wm_operator_properties_filesel_sort_items_itemf( return items; } -/* default properties for fileselect */ void WM_operator_properties_filesel(wmOperatorType *ot, int filter, short type, @@ -262,9 +261,6 @@ void WM_operator_properties_select_action(wmOperatorType *ot, int default_action wm_operator_properties_select_action_ex(ot, default_action, select_actions, hide_gui); } -/** - * only SELECT/DESELECT - */ void WM_operator_properties_select_action_simple(wmOperatorType *ot, int default_action, bool hide_gui) @@ -278,10 +274,6 @@ void WM_operator_properties_select_action_simple(wmOperatorType *ot, wm_operator_properties_select_action_ex(ot, default_action, select_actions, hide_gui); } -/** - * Use for all select random operators. - * Adds properties: percent, seed, action. - */ void WM_operator_properties_select_random(wmOperatorType *ot) { RNA_def_float_factor(ot->srna, @@ -357,9 +349,6 @@ void WM_operator_properties_border_to_rctf(struct wmOperator *op, rctf *rect) BLI_rctf_rcti_copy(rect, &rect_i); } -/** - * Use with #WM_gesture_box_invoke - */ void WM_operator_properties_gesture_box_ex(wmOperatorType *ot, bool deselect, bool extend) { PropertyRNA *prop; @@ -381,10 +370,6 @@ void WM_operator_properties_gesture_box_ex(wmOperatorType *ot, bool deselect, bo } } -/** - * Disable using cursor position, - * use when view operators are initialized from buttons. - */ void WM_operator_properties_use_cursor_init(wmOperatorType *ot) { PropertyRNA *prop = RNA_def_boolean(ot->srna, @@ -418,7 +403,6 @@ void WM_operator_properties_select_operation(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); } -/* Some tools don't support XOR/AND. */ void WM_operator_properties_select_operation_simple(wmOperatorType *ot) { static const EnumPropertyItem select_mode_items[] = { @@ -450,31 +434,6 @@ void WM_operator_properties_select_walk_direction(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); } -/** - * Selecting and tweaking items are overlapping operations. Getting both to work without conflicts - * requires special care. See - * https://wiki.blender.org/wiki/Human_Interface_Guidelines/Selection#Select-tweaking for the - * desired behavior. - * - * For default click selection (with no modifier keys held), the select operators can do the - * following: - * - On a mouse press on an unselected item, change selection and finish immediately after. - * This sends an undo push and allows transform to take over should a tweak event be caught now. - * - On a mouse press on a selected item, don't change selection state, but start modal execution - * of the operator. Idea is that we wait with deselecting other items until we know that the - * intention wasn't to tweak (mouse press+drag) all selected items. - * - If a tweak is recognized before the release event happens, cancel the operator, so that - * transform can take over and no undo-push is sent. - * - If the release event occurs rather than a tweak one, deselect all items but the one under the - * cursor, and finish the modal operator. - * - * This utility, together with #WM_generic_select_invoke() and #WM_generic_select_modal() should - * help getting the wanted behavior to work. Most generic logic should be handled in these, so that - * the select operators only have to care for the case dependent handling. - * - * Every select operator has slightly different requirements, e.g. sequencer strip selection - * also needs to account for handle selection. This should be the baseline behavior though. - */ void WM_operator_properties_generic_select(wmOperatorType *ot) { /* On the initial mouse press, this is set by #WM_generic_select_modal() to let the select @@ -499,9 +458,6 @@ void WM_operator_properties_gesture_box_zoom(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); } -/** - * Use with #WM_gesture_lasso_invoke - */ void WM_operator_properties_gesture_lasso(wmOperatorType *ot) { PropertyRNA *prop; @@ -509,9 +465,6 @@ void WM_operator_properties_gesture_lasso(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); } -/** - * Use with #WM_gesture_straightline_invoke - */ void WM_operator_properties_gesture_straightline(wmOperatorType *ot, int cursor) { PropertyRNA *prop; @@ -541,9 +494,6 @@ void WM_operator_properties_gesture_straightline(wmOperatorType *ot, int cursor) } } -/** - * Use with #WM_gesture_circle_invoke - */ void WM_operator_properties_gesture_circle(wmOperatorType *ot) { PropertyRNA *prop; @@ -582,9 +532,6 @@ void WM_operator_properties_mouse_select(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); } -/** - * \param nth_can_disable: Enable if we want to be able to select no interval at all. - */ void WM_operator_properties_checker_interval(wmOperatorType *ot, bool nth_can_disable) { const int nth_default = nth_can_disable ? 0 : 1; diff --git a/source/blender/windowmanager/intern/wm_operator_type.c b/source/blender/windowmanager/intern/wm_operator_type.c index 0e30df4ec99..0f6096e7b8b 100644 --- a/source/blender/windowmanager/intern/wm_operator_type.c +++ b/source/blender/windowmanager/intern/wm_operator_type.c @@ -89,7 +89,6 @@ wmOperatorType *WM_operatortype_find(const char *idname, bool quiet) return NULL; } -/* caller must free */ void WM_operatortype_iter(GHashIterator *ghi) { BLI_ghashIterator_init(ghi, global_ops_hash); @@ -132,7 +131,8 @@ static void wm_operatortype_append__end(wmOperatorType *ot) BLI_ghash_insert(global_ops_hash, (void *)ot->idname, ot); } -/* all ops in 1 list (for time being... needs evaluation later) */ +/* All ops in 1 list (for time being... needs evaluation later). */ + void WM_operatortype_append(void (*opfunc)(wmOperatorType *)) { wmOperatorType *ot = wm_operatortype_append__begin(); @@ -149,7 +149,6 @@ void WM_operatortype_append_ptr(void (*opfunc)(wmOperatorType *, void *), void * /** \} */ -/* called on initialize WM_exit() */ void WM_operatortype_remove_ptr(wmOperatorType *ot) { BLI_assert(ot == WM_operatortype_find(ot->idname, false)); @@ -184,7 +183,6 @@ bool WM_operatortype_remove(const char *idname) return true; } -/* called on initialize WM_init() */ void wm_operatortype_init(void) { /* reserve size is set based on blender default setup */ @@ -215,18 +213,6 @@ void wm_operatortype_free(void) global_ops_hash = NULL; } -/** - * Tag all operator-properties of \a ot defined after calling this, until - * the next #WM_operatortype_props_advanced_end call (if available), with - * #OP_PROP_TAG_ADVANCED. Previously defined ones properties not touched. - * - * Calling this multiple times without a call to #WM_operatortype_props_advanced_end, - * all calls after the first one are ignored. Meaning all proprieties defined after the - * first call are tagged as advanced. - * - * This doesn't do the actual tagging, #WM_operatortype_props_advanced_end does which is - * called for all operators during registration (see #wm_operatortype_append__end). - */ void WM_operatortype_props_advanced_begin(wmOperatorType *ot) { if (ot_prop_basic_count == -1) { @@ -235,14 +221,6 @@ void WM_operatortype_props_advanced_begin(wmOperatorType *ot) } } -/** - * Tags all operator-properties of \a ot defined since the first - * #WM_operatortype_props_advanced_begin call, - * or the last #WM_operatortype_props_advanced_end call, with #OP_PROP_TAG_ADVANCED. - * - * \note This is called for all operators during registration (see #wm_operatortype_append__end). - * So it does not need to be explicitly called in operator-type definition. - */ void WM_operatortype_props_advanced_end(wmOperatorType *ot) { PointerRNA struct_ptr; @@ -266,9 +244,6 @@ void WM_operatortype_props_advanced_end(wmOperatorType *ot) ot_prop_basic_count = -1; } -/** - * Remove memory of all previously executed tools. - */ void WM_operatortype_last_properties_clear_all(void) { GHashIterator iter; @@ -471,7 +446,6 @@ static void wm_macro_cancel(bContext *C, wmOperator *op) wm_macro_end(op, OPERATOR_CANCELLED); } -/* Names have to be static for now */ wmOperatorType *WM_operatortype_append_macro(const char *idname, const char *name, const char *description, @@ -613,9 +587,6 @@ char *WM_operatortype_description(struct bContext *C, return NULL; } -/** - * Use when we want a label, preferring the description. - */ char *WM_operatortype_description_or_name(struct bContext *C, struct wmOperatorType *ot, struct PointerRNA *properties) diff --git a/source/blender/windowmanager/intern/wm_operator_utils.c b/source/blender/windowmanager/intern/wm_operator_utils.c index 85a0a28de79..dbcfd814692 100644 --- a/source/blender/windowmanager/intern/wm_operator_utils.c +++ b/source/blender/windowmanager/intern/wm_operator_utils.c @@ -44,9 +44,6 @@ /** \name Generic Utilities * \{ */ -/** - * Only finish + pass through for press events (allowing press-tweak). - */ int WM_operator_flag_only_pass_through_on_press(int retval, const struct wmEvent *event) { if ((event->val != KM_PRESS) && @@ -337,10 +334,6 @@ static int op_generic_value_modal(bContext *C, wmOperator *op, const wmEvent *ev return OPERATOR_RUNNING_MODAL; } -/** - * Allow an operator with only and execute function to run modally, - * re-doing the action, using vertex coordinate store/restore instead of operator undo. - */ void WM_operator_type_modal_from_exec_for_object_edit_coords(wmOperatorType *ot) { PropertyRNA *prop; diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index ffdc99152b1..6c9b0af5186 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -116,13 +116,10 @@ #define UNDOCUMENTED_OPERATOR_TIP N_("(undocumented operator)") -/** \} */ - /* -------------------------------------------------------------------- */ /** \name Operator API * \{ */ -/* SOME_OT_op -> some.op */ void WM_operator_py_idname(char *to, const char *from) { const char *sep = strstr(from, "_OT_"); @@ -143,7 +140,6 @@ void WM_operator_py_idname(char *to, const char *from) } } -/* some.op -> SOME_OT_op */ void WM_operator_bl_idname(char *to, const char *from) { if (from) { @@ -167,10 +163,6 @@ void WM_operator_bl_idname(char *to, const char *from) } } -/** - * Sanity check to ensure #WM_operator_bl_idname won't fail. - * \returns true when there are no problems with \a idname, otherwise report an error. - */ bool WM_operator_py_idname_ok_or_report(ReportList *reports, const char *classname, const char *idname) @@ -219,15 +211,6 @@ bool WM_operator_py_idname_ok_or_report(ReportList *reports, return true; } -/** - * Print a string representation of the operator, - * with the args that it runs so python can run it again. - * - * When calling from an existing wmOperator, better to use simple version: - * `WM_operator_pystring(C, op);` - * - * \note Both \a op and \a opptr may be `NULL` (\a op is only used for macro operators). - */ char *WM_operator_pystring_ex(bContext *C, wmOperator *op, const bool all_args, @@ -308,9 +291,6 @@ char *WM_operator_pystring(bContext *C, wmOperator *op, const bool all_args, con return WM_operator_pystring_ex(C, op, all_args, macro_args, op->type, op->ptr); } -/** - * \return true if the string was shortened - */ bool WM_operator_pystring_abbreviate(char *str, int str_len_max) { const int str_len = strlen(str); @@ -608,9 +588,6 @@ static const char *wm_context_member_from_ptr(const bContext *C, } #endif -/** - * Calculate the path to `ptr` from context `C`, or return NULL if it can't be calculated. - */ char *WM_context_path_resolve_property_full(const bContext *C, const PointerRNA *ptr, PropertyRNA *prop, @@ -711,8 +688,6 @@ void WM_operator_properties_create(PointerRNA *ptr, const char *opstring) } } -/* similar to the function above except its uses ID properties - * used for keymaps and macros */ void WM_operator_properties_alloc(PointerRNA **ptr, IDProperty **properties, const char *opstring) { IDProperty *tmp_properties = NULL; @@ -763,14 +738,6 @@ void WM_operator_properties_sanitize(PointerRNA *ptr, const bool no_context) RNA_STRUCT_END; } -/** - * Set all props to their default. - * - * \param do_update: Only update un-initialized props. - * - * \note There's nothing specific to operators here. - * This could be made a general function. - */ bool WM_operator_properties_default(PointerRNA *ptr, const bool do_update) { bool changed = false; @@ -798,7 +765,6 @@ bool WM_operator_properties_default(PointerRNA *ptr, const bool do_update) return changed; } -/* remove all props without PROP_SKIP_SAVE */ void WM_operator_properties_reset(wmOperator *op) { if (op->ptr->data) { @@ -945,13 +911,6 @@ bool WM_operator_last_properties_store(wmOperator *UNUSED(op)) /** \name Default Operator Callbacks * \{ */ -/** - * Helper to get select and tweak-transform to work conflict free and as desired. See - * #WM_operator_properties_generic_select() for details. - * - * To be used together with #WM_generic_select_invoke() and - * #WM_operator_properties_generic_select(). - */ int WM_generic_select_modal(bContext *C, wmOperator *op, const wmEvent *event) { PropertyRNA *wait_to_deselect_prop = RNA_struct_find_property(op->ptr, @@ -1012,13 +971,6 @@ int WM_generic_select_modal(bContext *C, wmOperator *op, const wmEvent *event) return OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH; } -/** - * Helper to get select and tweak-transform to work conflict free and as desired. See - * #WM_operator_properties_generic_select() for details. - * - * To be used together with #WM_generic_select_modal() and - * #WM_operator_properties_generic_select(). - */ int WM_generic_select_invoke(bContext *C, wmOperator *op, const wmEvent *event) { RNA_int_set(op->ptr, "mouse_x", event->mval[0]); @@ -1063,7 +1015,6 @@ int WM_operator_smooth_viewtx_get(const wmOperator *op) return (op->flag & OP_IS_INVOKE) ? U.smooth_viewtx : 0; } -/* invoke callback, uses enum property named "type" */ int WM_menu_invoke_ex(bContext *C, wmOperator *op, wmOperatorCallContext opcontext) { PropertyRNA *prop = op->type->prop; @@ -1184,10 +1135,6 @@ static uiBlock *wm_enum_search_menu(bContext *C, ARegion *region, void *arg) return block; } -/** - * Similar to #WM_enum_search_invoke, but draws previews. Also, this can't - * be used as invoke callback directly since it needs additional info. - */ int WM_enum_search_invoke_previews(bContext *C, wmOperator *op, short prv_cols, short prv_rows) { static struct EnumSearchMenu search_menu; @@ -1210,7 +1157,6 @@ int WM_enum_search_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(eve return OPERATOR_INTERFACE; } -/* Can't be used as an invoke directly, needs message arg (can be NULL) */ int WM_operator_confirm_message_ex(bContext *C, wmOperator *op, const char *title, @@ -1255,7 +1201,6 @@ int WM_operator_confirm_or_exec(bContext *C, wmOperator *op, const wmEvent *UNUS return op->type->exec(C, op); } -/* op->invoke, opens fileselect if path property not set, otherwise executes */ int WM_operator_filesel(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { if (RNA_struct_property_is_set(op->ptr, "filepath")) { @@ -1280,7 +1225,6 @@ bool WM_operator_filesel_ensure_ext_imtype(wmOperator *op, const struct ImageFor return false; } -/* op->poll */ bool WM_operator_winactive(bContext *C) { if (CTX_wm_window(C) == NULL) { @@ -1289,7 +1233,6 @@ bool WM_operator_winactive(bContext *C) return 1; } -/* return false, if the UI should be disabled */ bool WM_operator_check_ui_enabled(const bContext *C, const char *idname) { wmWindowManager *wm = CTX_wm_manager(C); @@ -1327,9 +1270,6 @@ void WM_operator_last_properties_ensure(wmOperatorType *ot, PointerRNA *ptr) RNA_pointer_create(G_MAIN->wm.first, ot->srna, props, ptr); } -/** - * Use for drag & drop a path or name with operators invoke() function. - */ ID *WM_operator_drop_load_path(struct bContext *C, wmOperator *op, const short idcode) { Main *bmain = CTX_data_main(C); @@ -1633,20 +1573,11 @@ static int wm_operator_props_popup_ex(bContext *C, return OPERATOR_RUNNING_MODAL; } -/** - * Same as #WM_operator_props_popup but don't use operator redo. - * just wraps #WM_operator_props_dialog_popup. - */ int WM_operator_props_popup_confirm(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { return wm_operator_props_popup_ex(C, op, false, false); } -/** - * Same as #WM_operator_props_popup but call the operator first, - * This way - the button values correspond to the result of the operator. - * Without this, first access to a button will make the result jump, see T32452. - */ int WM_operator_props_popup_call(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { return wm_operator_props_popup_ex(C, op, true, true); @@ -3999,7 +3930,6 @@ static void gesture_zoom_border_modal_keymap(wmKeyConfig *keyconf) WM_modalkeymap_assign(keymap, "IMAGE_OT_view_zoom_border"); } -/* default keymap for windows and screens, only call once per WM */ void wm_window_keymap(wmKeyConfig *keyconf) { WM_keymap_ensure(keyconf, "Window", 0, 0); @@ -4067,7 +3997,8 @@ static const EnumPropertyItem *rna_id_itemf(bool *r_free, return item; } -/* can add more as needed */ +/* Can add more ID types as needed. */ + const EnumPropertyItem *RNA_action_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), diff --git a/source/blender/windowmanager/intern/wm_panel_type.c b/source/blender/windowmanager/intern/wm_panel_type.c index 24508c377a6..609bb55e075 100644 --- a/source/blender/windowmanager/intern/wm_panel_type.c +++ b/source/blender/windowmanager/intern/wm_panel_type.c @@ -69,7 +69,6 @@ void WM_paneltype_remove(PanelType *pt) UNUSED_VARS_NDEBUG(ok); } -/* called on initialize WM_init() */ void WM_paneltype_init(void) { /* reserve size is set based on blender default setup */ diff --git a/source/blender/windowmanager/intern/wm_stereo.c b/source/blender/windowmanager/intern/wm_stereo.c index 16a17484f4f..a62ced1a4bf 100644 --- a/source/blender/windowmanager/intern/wm_stereo.c +++ b/source/blender/windowmanager/intern/wm_stereo.c @@ -177,10 +177,6 @@ bool WM_stereo3d_enabled(wmWindow *win, bool skip_stereo3d_check) return true; } -/** - * If needed, adjust \a r_mouse_xy - * so that drawn cursor and handled mouse position are matching visually. - */ void wm_stereo3d_mouse_offset_apply(wmWindow *win, int r_mouse_xy[2]) { if (!WM_stereo3d_enabled(win, false)) { diff --git a/source/blender/windowmanager/intern/wm_subwindow.c b/source/blender/windowmanager/intern/wm_subwindow.c index 0cb76404258..524580ac88f 100644 --- a/source/blender/windowmanager/intern/wm_subwindow.c +++ b/source/blender/windowmanager/intern/wm_subwindow.c @@ -116,7 +116,6 @@ static void wmOrtho2_offset(const float x, const float y, const float ofs) wmOrtho2(ofs, x + ofs, ofs, y + ofs); } -/* Default pixel alignment for regions. */ void wmOrtho2_region_pixelspace(const ARegion *region) { wmOrtho2_offset(region->winx, region->winy, -0.01f); diff --git a/source/blender/windowmanager/intern/wm_surface.c b/source/blender/windowmanager/intern/wm_surface.c index 715f72d70cf..385b55f36f9 100644 --- a/source/blender/windowmanager/intern/wm_surface.c +++ b/source/blender/windowmanager/intern/wm_surface.c @@ -45,11 +45,24 @@ static wmSurface *g_drawable = NULL; void wm_surfaces_iter(bContext *C, void (*cb)(bContext *C, wmSurface *)) { - LISTBASE_FOREACH (wmSurface *, surf, &global_surface_list) { + /* Mutable iterator in case a surface is freed. */ + LISTBASE_FOREACH_MUTABLE (wmSurface *, surf, &global_surface_list) { cb(C, surf); } } +static void wm_surface_do_depsgraph_fn(bContext *C, wmSurface *surface) +{ + if (surface->do_depsgraph) { + surface->do_depsgraph(C); + } +} + +void wm_surfaces_do_depsgraph(bContext *C) +{ + wm_surfaces_iter(C, wm_surface_do_depsgraph_fn); +} + void wm_surface_clear_drawable(void) { if (g_drawable) { @@ -107,6 +120,9 @@ void wm_surface_add(wmSurface *surface) void wm_surface_remove(wmSurface *surface) { + if (surface == g_drawable) { + wm_surface_clear_drawable(); + } BLI_remlink(&global_surface_list, surface); surface->free_data(surface); MEM_freeN(surface); diff --git a/source/blender/windowmanager/intern/wm_toolsystem.c b/source/blender/windowmanager/intern/wm_toolsystem.c index 3ac1a7c0be1..7b8feac45b4 100644 --- a/source/blender/windowmanager/intern/wm_toolsystem.c +++ b/source/blender/windowmanager/intern/wm_toolsystem.c @@ -251,7 +251,6 @@ void WM_toolsystem_reinit(bContext *C, WorkSpace *workspace, const bToolKey *tke } } -/* Operate on all active tools. */ void WM_toolsystem_unlink_all(struct bContext *C, struct WorkSpace *workspace) { LISTBASE_FOREACH (bToolRef *, tref, &workspace->tools) { @@ -362,12 +361,6 @@ void WM_toolsystem_ref_set_from_runtime(struct bContext *C, } } -/** - * Sync the internal active state of a tool back into the tool system, - * this is needed for active brushes where the real active state is not stored in the tool system. - * - * \see #toolsystem_ref_link - */ void WM_toolsystem_ref_sync_from_context(Main *bmain, WorkSpace *workspace, bToolRef *tref) { bToolRef_Runtime *tref_rt = tref->runtime; @@ -505,14 +498,6 @@ bool WM_toolsystem_key_from_context(ViewLayer *view_layer, ScrArea *area, bToolK return false; } -/** - * Use to update the active tool (shown in the top bar) in the least disruptive way. - * - * This is a little involved since there may be multiple valid active tools - * depending on the mode and space type. - * - * Used when undoing since the active mode may have changed. - */ void WM_toolsystem_refresh_active(bContext *C) { Main *bmain = CTX_data_main(C); @@ -800,16 +785,12 @@ void WM_toolsystem_update_from_context(bContext *C, } } -/** - * For paint modes to support non-brush tools. - */ bool WM_toolsystem_active_tool_is_brush(const bContext *C) { bToolRef_Runtime *tref_rt = WM_toolsystem_runtime_from_context((bContext *)C); return tref_rt && (tref_rt->data_block[0] != '\0'); } -/* Follow wmMsgNotifyFn spec */ void WM_toolsystem_do_msg_notify_tag_refresh(bContext *C, wmMsgSubscribeKey *UNUSED(msg_key), wmMsgSubscribeValue *msg_val) diff --git a/source/blender/windowmanager/intern/wm_uilist_type.c b/source/blender/windowmanager/intern/wm_uilist_type.c index 82ba4aa6e6f..a2ae42d5ead 100644 --- a/source/blender/windowmanager/intern/wm_uilist_type.c +++ b/source/blender/windowmanager/intern/wm_uilist_type.c @@ -131,7 +131,6 @@ void WM_uilisttype_remove_ptr(Main *bmain, uiListType *ult) UNUSED_VARS_NDEBUG(ok); } -/* called on initialize WM_init() */ void WM_uilisttype_init(void) { uilisttypes_hash = BLI_ghash_str_new_ex("uilisttypes_hash gh", 16); @@ -151,16 +150,6 @@ void WM_uilisttype_free(void) uilisttypes_hash = NULL; } -/** - * The "full" list-ID is an internal name used for storing and identifying a list. It is built like - * this: - * "{uiListType.idname}_{list_id}", whereby "list_id" is an optional parameter passed to - * `UILayout.template_list()`. If it is not set, the full list-ID is just "{uiListType.idname}_". - * - * Note that whenever the Python API refers to the list-ID, it's the short, "non-full" one it - * passed to `UILayout.template_list()`. C code can query that through - * #WM_uilisttype_list_id_get(). - */ void WM_uilisttype_to_full_list_id(const uiListType *ult, const char *list_id, char r_full_list_id[/*UI_MAX_NAME_STR*/]) @@ -169,11 +158,6 @@ void WM_uilisttype_to_full_list_id(const uiListType *ult, BLI_snprintf(r_full_list_id, UI_MAX_NAME_STR, "%s_%s", ult->idname, list_id ? list_id : ""); } -/** - * Get the "non-full" list-ID, see #WM_uilisttype_to_full_list_id() for details. - * - * \note Assumes `uiList.list_id` was set using #WM_uilisttype_to_full_list_id()! - */ const char *WM_uilisttype_list_id_get(const uiListType *ult, uiList *list) { /* Some sanity check for the assumed behavior of #WM_uilisttype_to_full_list_id(). */ diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index 5f684a752d8..29c9f53f735 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -136,8 +136,6 @@ static struct WMInitStruct { static void wm_window_set_drawable(wmWindowManager *wm, wmWindow *win, bool activate); static bool wm_window_timer(const bContext *C); -/* XXX this one should correctly check for apple top header... - * done for Cocoa : returns window contents (and not frame) max size. */ void wm_get_screensize(int *r_width, int *r_height) { unsigned int uiwidth; @@ -148,7 +146,6 @@ void wm_get_screensize(int *r_width, int *r_height) *r_height = uiheight; } -/* size of all screens (desktop), useful since the mouse is bound by this */ void wm_get_desktopsize(int *r_width, int *r_height) { unsigned int uiwidth; @@ -198,8 +195,6 @@ static void wm_ghostwindow_destroy(wmWindowManager *wm, wmWindow *win) } } -/* including window itself, C can be NULL. - * ED_screen_exit should have been called */ void wm_window_free(bContext *C, wmWindowManager *wm, wmWindow *win) { /* update context */ @@ -260,7 +255,6 @@ static int find_free_winid(wmWindowManager *wm) return id; } -/* don't change context itself */ wmWindow *wm_window_new(const Main *bmain, wmWindowManager *wm, wmWindow *parent, bool dialog) { wmWindow *win = MEM_callocN(sizeof(wmWindow), "window"); @@ -276,7 +270,6 @@ wmWindow *wm_window_new(const Main *bmain, wmWindowManager *wm, wmWindow *parent return win; } -/* part of wm_window.c api */ wmWindow *wm_window_copy(Main *bmain, wmWindowManager *wm, wmWindow *win_src, @@ -307,10 +300,6 @@ wmWindow *wm_window_copy(Main *bmain, return win_dst; } -/** - * A higher level version of copy that tests the new window can be added. - * (called from the operator directly) - */ wmWindow *wm_window_copy_test(bContext *C, wmWindow *win_src, const bool duplicate_layout, @@ -353,13 +342,6 @@ static void wm_confirm_quit(bContext *C) wm_close_file_dialog(C, action); } -/** - * Call the quit confirmation prompt or exit directly if needed. The use can - * still cancel via the confirmation popup. Also, this may not quit Blender - * immediately, but rather schedule the closing. - * - * \param win: The window to show the confirmation popup/window in. - */ void wm_quit_with_optional_confirmation_prompt(bContext *C, wmWindow *win) { wmWindow *win_ctx = CTX_wm_window(C); @@ -387,7 +369,6 @@ void wm_quit_with_optional_confirmation_prompt(bContext *C, wmWindow *win) /** \} */ -/* this is event from ghost, or exit-blender op */ void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win) { wmWindow *win_other; @@ -447,13 +428,14 @@ void wm_window_title(wmWindowManager *wm, wmWindow *win) } else if (win->ghostwin) { /* this is set to 1 if you don't have startup.blend open */ - if (G.save_over && BKE_main_blendfile_path_from_global()[0]) { - char str[sizeof(((Main *)NULL)->name) + 24]; + const char *blendfile_path = BKE_main_blendfile_path_from_global(); + if (blendfile_path[0] != '\0') { + char str[sizeof(((Main *)NULL)->filepath) + 24]; BLI_snprintf(str, sizeof(str), "Blender%s [%s%s]", wm->file_saved ? "" : "*", - BKE_main_blendfile_path_from_global(), + blendfile_path, G_MAIN->recovered ? " (Recovered)" : ""); GHOST_SetTitle(win->ghostwin, str); } @@ -679,19 +661,6 @@ static void wm_window_ghostwindow_ensure(wmWindowManager *wm, wmWindow *win, boo ED_screen_global_areas_refresh(win); } -/** - * Initialize #wmWindow without ghostwin, open these and clear. - * - * window size is read from window, if 0 it uses prefsize - * called in #WM_check, also inits stuff after file read. - * - * \warning - * After running, 'win->ghostwin' can be NULL in rare cases - * (where OpenGL driver fails to create a context for eg). - * We could remove them with #wm_window_ghostwindows_remove_invalid - * but better not since caller may continue to use. - * Instead, caller needs to handle the error case and cleanup. - */ void wm_window_ghostwindows_ensure(wmWindowManager *wm) { BLI_assert(G.background == false); @@ -715,10 +684,6 @@ void wm_window_ghostwindows_ensure(wmWindowManager *wm) } } -/** - * Call after #wm_window_ghostwindows_ensure or #WM_check - * (after loading a new file) in the unlikely event a window couldn't be created. - */ void wm_window_ghostwindows_remove_invalid(bContext *C, wmWindowManager *wm) { BLI_assert(G.background == false); @@ -756,14 +721,6 @@ static bool wm_window_update_size_position(wmWindow *win) return false; } -/** - * \param space_type: SPACE_VIEW3D, SPACE_INFO, ... (eSpace_Type) - * \param toplevel: Not a child owned by other windows. A peer of main window. - * \param dialog: whether this should be made as a dialog-style window - * \param temp: whether this is considered a short-lived window - * \param alignment: how this window is positioned relative to its parent - * \return the window or NULL in case of failure. - */ wmWindow *WM_window_open(bContext *C, const char *title, int x, @@ -952,7 +909,6 @@ int wm_window_new_main_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -/* fullscreen operator callback */ int wm_window_fullscreen_toggle_exec(bContext *C, wmOperator *UNUSED(op)) { wmWindow *window = CTX_wm_window(C); @@ -1083,7 +1039,6 @@ void wm_window_make_drawable(wmWindowManager *wm, wmWindow *win) } } -/* Reset active the current window opengl drawing context. */ void wm_window_reset_drawable(void) { BLI_assert(BLI_thread_is_main()); @@ -1585,10 +1540,6 @@ void wm_window_process_events(const bContext *C) /** \name Ghost Init/Exit * \{ */ -/** - * \note #bContext can be null in background mode because we don't - * need to event handling. - */ void wm_ghost_init(bContext *C) { if (!g_system) { @@ -1627,7 +1578,6 @@ void wm_ghost_exit(void) /** \name Event Timer * \{ */ -/* to (de)activate running timers temporary */ void WM_event_timer_sleep(wmWindowManager *wm, wmWindow *UNUSED(win), wmTimer *timer, @@ -1769,19 +1719,11 @@ static char *wm_clipboard_text_get_ex(bool selection, int *r_len, bool firstline return newbuf; } -/** - * Return text from the clipboard. - * - * \note Caller needs to check for valid utf8 if this is a requirement. - */ char *WM_clipboard_text_get(bool selection, int *r_len) { return wm_clipboard_text_get_ex(selection, r_len, false); } -/** - * Convenience function for pasting to areas of Blender which don't support newlines. - */ char *WM_clipboard_text_get_firstline(bool selection, int *r_len) { return wm_clipboard_text_get_ex(selection, r_len, true); @@ -1890,9 +1832,6 @@ void wm_window_raise(wmWindow *win) /** \name Window Buffers * \{ */ -/** - * \brief Push rendered buffer to the screen. - */ void wm_window_swap_buffers(wmWindow *win) { GHOST_SwapWindowBuffers(win->ghostwin); @@ -1913,6 +1852,7 @@ 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]) @@ -2034,7 +1974,6 @@ uint *WM_window_pixels_read(wmWindowManager *wm, wmWindow *win, int r_size[2]) /** \name Initial Window State API * \{ */ -/* called whem no ghost system was initialized */ void WM_init_state_size_set(int stax, int stay, int sizx, int sizy) { wm_init_state.start_x = stax; /* left hand pos */ @@ -2044,7 +1983,6 @@ void WM_init_state_size_set(int stax, int stay, int sizx, int sizy) wm_init_state.override_flag |= WIN_OVERRIDE_GEOM; } -/* for borderless and border windows set from command-line */ void WM_init_state_fullscreen_set(void) { wm_init_state.windowstate = GHOST_kWindowStateFullScreen; @@ -2097,7 +2035,6 @@ void WM_init_tablet_api(void) } } -/* This function requires access to the GHOST_SystemHandle (g_system) */ void WM_cursor_warp(wmWindow *win, int x, int y) { if (win && win->ghostwin) { @@ -2114,9 +2051,6 @@ void WM_cursor_warp(wmWindow *win, int x, int y) } } -/** - * Set x, y to values we can actually position the cursor to. - */ void WM_cursor_compatible_xy(wmWindow *win, int *x, int *y) { float f = GHOST_GetNativePixelSize(win->ghostwin); @@ -2132,11 +2066,6 @@ void WM_cursor_compatible_xy(wmWindow *win, int *x, int *y) /** \name Window Size (public) * \{ */ -/** - * Support for native pixel size - * - * \note macOS retina opens window in size X, but it has up to 2 x more pixels. - */ int WM_window_pixels_x(const wmWindow *win) { float f = GHOST_GetNativePixelSize(win->ghostwin); @@ -2150,17 +2079,10 @@ int WM_window_pixels_y(const wmWindow *win) return (int)(f * (float)win->sizey); } -/** - * Get boundaries usable by all window contents, including global areas. - */ void WM_window_rect_calc(const wmWindow *win, rcti *r_rect) { BLI_rcti_init(r_rect, 0, WM_window_pixels_x(win), 0, WM_window_pixels_y(win)); } -/** - * Get boundaries usable by screen-layouts, excluding global areas. - * \note Depends on U.dpi_fac. Should that be outdated, call #WM_window_set_dpi first. - */ void WM_window_screen_rect_calc(const wmWindow *win, rcti *r_rect) { rcti window_rect, screen_rect; @@ -2210,11 +2132,6 @@ bool WM_window_is_maximized(const wmWindow *win) /** \name Window Screen/Scene/WorkSpaceViewLayer API * \{ */ -/** - * Some editor data may need to be synced with scene data (3D View camera and layers). - * This function ensures data is synced for editors - * in visible workspaces and their visible layouts. - */ void WM_windows_scene_data_sync(const ListBase *win_lb, Scene *scene) { LISTBASE_FOREACH (wmWindow *, win, win_lb) { @@ -2261,9 +2178,6 @@ Scene *WM_window_get_active_scene(const wmWindow *win) return win->scene; } -/** - * \warning Only call outside of area/region loops - */ void WM_window_set_active_scene(Main *bmain, bContext *C, wmWindow *win, Scene *scene) { wmWindowManager *wm = CTX_wm_manager(C); @@ -2376,9 +2290,6 @@ void WM_window_set_active_layout(wmWindow *win, WorkSpace *workspace, WorkSpaceL BKE_workspace_active_layout_set(win->workspace_hook, win->winid, workspace, layout); } -/** - * Get the active screen of the active workspace in \a win. - */ bScreen *WM_window_get_active_screen(const wmWindow *win) { const WorkSpace *workspace = WM_window_get_active_workspace(win); @@ -2481,4 +2392,5 @@ void WM_ghost_show_message_box(const char *title, BLI_assert(g_system); GHOST_ShowMessageBox(g_system, title, message, help_label, continue_label, link, dialog_options); } + /** \} */ 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 86a106462c3..81ef8c881f5 100644 --- a/source/blender/windowmanager/message_bus/intern/wm_message_bus.c +++ b/source/blender/windowmanager/message_bus/intern/wm_message_bus.c @@ -147,16 +147,6 @@ void WM_msgbus_handle(struct wmMsgBus *mbus, struct bContext *C) // printf("msgbus: keys=%u values=%u\n", a, b); } -/** - * \param msg_key_test: Needs following #wmMsgSubscribeKey fields filled in: - * - msg.params - * - msg.head.type - * - msg.head.id - * .. other values should be zeroed. - * - * \return The key for this subscription. - * note that this is only needed in rare cases when the key needs further manipulation. - */ wmMsgSubscribeKey *WM_msg_subscribe_with_key(struct wmMsgBus *mbus, const wmMsgSubscribeKey *msg_key_test, const wmMsgSubscribeValue *msg_val_params) @@ -239,9 +229,6 @@ void WM_msg_id_remove(struct wmMsgBus *mbus, const struct ID *id) * \note While we could have a separate type for ID's, use RNA since there is enough overlap. * \{ */ -/** - * \note #wmMsgBus.messages_tag_count isn't updated, caller must handle. - */ void wm_msg_subscribe_value_free(wmMsgSubscribeKey *msg_key, wmMsgSubscribeValueLink *msg_lnk) { if (msg_lnk->params.free_data) { diff --git a/source/blender/windowmanager/message_bus/intern/wm_message_bus_intern.h b/source/blender/windowmanager/message_bus/intern/wm_message_bus_intern.h index 24c0192fe14..18df17c3d1c 100644 --- a/source/blender/windowmanager/message_bus/intern/wm_message_bus_intern.h +++ b/source/blender/windowmanager/message_bus/intern/wm_message_bus_intern.h @@ -30,6 +30,9 @@ struct wmMsgBus { uint messages_tag_count; }; +/** + * \note #wmMsgBus.messages_tag_count isn't updated, caller must handle. + */ void wm_msg_subscribe_value_free(struct wmMsgSubscribeKey *msg_key, struct wmMsgSubscribeValueLink *msg_lnk); diff --git a/source/blender/windowmanager/message_bus/intern/wm_message_bus_rna.c b/source/blender/windowmanager/message_bus/intern/wm_message_bus_rna.c index 460dca57e4f..bc083793395 100644 --- a/source/blender/windowmanager/message_bus/intern/wm_message_bus_rna.c +++ b/source/blender/windowmanager/message_bus/intern/wm_message_bus_rna.c @@ -35,7 +35,9 @@ #include "RNA_access.h" -/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------- */ +/** \name Internal Utilities + * \{ */ BLI_INLINE uint void_hash_uint(const void *key) { @@ -208,7 +210,11 @@ void WM_msgtypeinfo_init_rna(wmMsgTypeInfo *msgtype_info) msgtype_info->msg_key_size = sizeof(wmMsgSubscribeKey_RNA); } -/* -------------------------------------------------------------------------- */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name RNA API + * \{ */ wmMsgSubscribeKey_RNA *WM_msg_lookup_rna(struct wmMsgBus *mbus, const wmMsgParams_RNA *msg_key_params) diff --git a/source/blender/windowmanager/message_bus/wm_message_bus.h b/source/blender/windowmanager/message_bus/wm_message_bus.h index 7ae356cf806..7ee2e5b6ee6 100644 --- a/source/blender/windowmanager/message_bus/wm_message_bus.h +++ b/source/blender/windowmanager/message_bus/wm_message_bus.h @@ -79,7 +79,7 @@ typedef struct wmMsg { } wmMsg; typedef struct wmMsgSubscribeKey { - /** Linked list for predicable ordering, otherwise we would depend on ghash bucketing. */ + /** Linked list for predicable ordering, otherwise we would depend on #GHash bucketing. */ struct wmMsgSubscribeKey *next, *prev; ListBase values; /* over-alloc, eg: wmMsgSubscribeKey_RNA */ @@ -124,6 +124,16 @@ void WM_msg_dump(struct wmMsgBus *mbus, const char *info); void WM_msgbus_handle(struct wmMsgBus *mbus, struct bContext *C); void WM_msg_publish_with_key(struct wmMsgBus *mbus, wmMsgSubscribeKey *msg_key); +/** + * \param msg_key_test: Needs following #wmMsgSubscribeKey fields filled in: + * - `msg.params` + * - `msg.head.type` + * - `msg.head.id` + * .. other values should be zeroed. + * + * \return The key for this subscription. + * note that this is only needed in rare cases when the key needs further manipulation. + */ wmMsgSubscribeKey *WM_msg_subscribe_with_key(struct wmMsgBus *mbus, const wmMsgSubscribeKey *msg_key_test, const wmMsgSubscribeValue *msg_val_params); diff --git a/source/blender/windowmanager/wm.h b/source/blender/windowmanager/wm.h index cfef70b7dcc..e67b1581875 100644 --- a/source/blender/windowmanager/wm.h +++ b/source/blender/windowmanager/wm.h @@ -43,49 +43,98 @@ typedef struct wmPaintCursor { short region_type; } wmPaintCursor; +/** + * Cause a delayed #WM_exit() + * call to avoid leaking memory when trying to exit from within operators. + */ void wm_exit_schedule_delayed(const bContext *C); +/** + * Context is allowed to be NULL, do not free wm itself (lib_id.c). + */ extern void wm_close_and_free(bContext *C, wmWindowManager *); extern void wm_close_and_free_all(bContext *C, ListBase *); +/** + * On startup, it adds all data, for matching. + */ extern void wm_add_default(struct Main *bmain, bContext *C); extern void wm_clear_default_size(bContext *C); /* register to windowmanager for redo or macro */ + +/** + * Called on event handling by `event_system.c`. + * + * All operations get registered in the windowmanager here. + */ void wm_operator_register(bContext *C, wmOperator *op); /* wm_operator.c, for init/exit */ + void wm_operatortype_free(void); +/** + * Called on initialize #WM_init(). + */ void wm_operatortype_init(void); +/** + * Default key-map for windows and screens, only call once per WM. + */ void wm_window_keymap(wmKeyConfig *keyconf); void wm_operatortypes_register(void); /* wm_gesture.c */ +/* called in wm_draw.c */ + void wm_gesture_draw(struct wmWindow *win); +/** + * Tweak and line gestures. + */ int wm_gesture_evaluate(wmGesture *gesture, const struct wmEvent *event); void wm_gesture_tag_redraw(struct wmWindow *win); /* wm_gesture_ops.c */ + +/** + * Standard tweak, called after window handlers passed on event. + */ void wm_tweakevent_test(bContext *C, const wmEvent *event, int action); /* wm_jobs.c */ + +/** + * Hard-coded to event #TIMERJOBS. + */ void wm_jobs_timer(wmWindowManager *wm, wmTimer *wt); +/** + * Kill job entirely, also removes timer itself. + */ void wm_jobs_timer_end(wmWindowManager *wm, wmTimer *wt); /* wm_files.c */ + +/** + * Run the auto-save timer action. + */ void wm_autosave_timer(struct Main *bmain, wmWindowManager *wm, wmTimer *wt); void wm_autosave_timer_begin(struct wmWindowManager *wm); void wm_autosave_timer_end(wmWindowManager *wm); void wm_autosave_delete(void); /* 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); void wm_stereo3d_draw_topbottom(wmWindow *win, int view); +/** + * If needed, adjust \a r_mouse_xy + * so that drawn cursor and handled mouse position are matching visually. + */ void wm_stereo3d_mouse_offset_apply(wmWindow *win, int r_mouse_xy[2]); int wm_stereo3d_set_exec(bContext *C, wmOperator *op); int wm_stereo3d_set_invoke(bContext *C, wmOperator *op, const wmEvent *event); @@ -93,7 +142,9 @@ void wm_stereo3d_set_draw(bContext *C, wmOperator *op); bool wm_stereo3d_set_check(bContext *C, wmOperator *op); void wm_stereo3d_set_cancel(bContext *C, wmOperator *op); -/* init operator properties */ +/** + * Initialize operator properties. + */ void wm_open_init_load_ui(wmOperator *op, bool use_prefs); void wm_open_init_use_scripts(wmOperator *op, bool use_prefs); diff --git a/source/blender/windowmanager/wm_event_system.h b/source/blender/windowmanager/wm_event_system.h index 9b0f128d071..925be8ab183 100644 --- a/source/blender/windowmanager/wm_event_system.h +++ b/source/blender/windowmanager/wm_event_system.h @@ -144,20 +144,36 @@ typedef struct wmEventHandler_Dropbox { } wmEventHandler_Dropbox; /* wm_event_system.c */ + void wm_event_free_all(wmWindow *win); void wm_event_free(wmEvent *event); void wm_event_free_handler(wmEventHandler *handler); -/* goes over entire hierarchy: events -> window -> screen -> area -> region */ +/** + * Goes over entire hierarchy: events -> window -> screen -> area -> region. + * + * \note Called in main loop. + */ void wm_event_do_handlers(bContext *C); +/** + * Windows store own event queues #wmWindow.event_queue (no #bContext here). + */ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void *customdata); #ifdef WITH_XR_OPENXR void wm_event_add_xrevent(wmWindow *win, struct wmXrActionData *actiondata, short val); #endif void wm_event_do_depsgraph(bContext *C, bool is_after_open_file); +/** + * Was part of #wm_event_do_notifiers, + * split out so it can be called once before entering the #WM_main loop. + * This ensures operators don't run before the UI and depsgraph are initialized. + */ void wm_event_do_refresh_wm_and_depsgraph(bContext *C); +/** + * Called in main-loop. + */ void wm_event_do_notifiers(bContext *C); void wm_event_handler_ui_cancel_ex(bContext *C, @@ -166,17 +182,36 @@ void wm_event_handler_ui_cancel_ex(bContext *C, bool reactivate_button); /* wm_event_query.c */ + +/** + * Applies the global tablet pressure correction curve. + */ float wm_pressure_curve(float raw_pressure); void wm_tablet_data_from_ghost(const struct GHOST_TabletData *tablet_data, wmTabletData *wmtab); -/* wm_keymap.c */ - /* wm_dropbox.c */ + void wm_dropbox_free(void); +/** + * Additional work to cleanly end dragging. Additional because this doesn't actually remove the + * drag items. Should be called whenever dragging is stopped + * (successful or not, also when canceled). + */ void wm_drags_exit(wmWindowManager *wm, wmWindow *win); void wm_drop_prepare(bContext *C, wmDrag *drag, wmDropBox *drop); +/** + * Called in inner handler loop, region context. + */ void wm_drags_check_ops(bContext *C, const wmEvent *event); +/** + * The operator of a dropbox should always be executed in the context determined by the mouse + * coordinates. The dropbox poll should check the context area and region as needed. + * So this always returns #WM_OP_INVOKE_DEFAULT. + */ wmOperatorCallContext wm_drop_operator_context_get(const wmDropBox *drop); +/** + * Called in #wm_draw_window_onscreen. + */ void wm_drags_draw(bContext *C, wmWindow *win); #ifdef __cplusplus diff --git a/source/blender/windowmanager/wm_event_types.h b/source/blender/windowmanager/wm_event_types.h index c175c211db6..437bd1057c2 100644 --- a/source/blender/windowmanager/wm_event_types.h +++ b/source/blender/windowmanager/wm_event_types.h @@ -405,7 +405,7 @@ enum { #define _VA_IS_EVENT_MOD4(v, a, b, c) (_VA_IS_EVENT_MOD3(v, a, b) || ((v)->c)) #define _VA_IS_EVENT_MOD5(v, a, b, c, d) (_VA_IS_EVENT_MOD4(v, a, b, c) || ((v)->d)) -/* reusable IS_EVENT_MOD(event, shift, ctrl, alt, oskey), macro */ +/** Reusable `IS_EVENT_MOD(event, shift, ctrl, alt, oskey)` macro. */ #define IS_EVENT_MOD(...) VA_NARGS_CALL_OVERLOAD(_VA_IS_EVENT_MOD, __VA_ARGS__) enum eEventType_Mask { diff --git a/source/blender/windowmanager/wm_files.h b/source/blender/windowmanager/wm_files.h index 135f31cf8ac..e63afb2ed2f 100644 --- a/source/blender/windowmanager/wm_files.h +++ b/source/blender/windowmanager/wm_files.h @@ -33,6 +33,7 @@ extern "C" { #endif /* wm_files.c */ + void wm_history_file_read(void); struct wmHomeFileRead_Params { @@ -62,6 +63,16 @@ struct wmHomeFileRead_Params { const char *app_template_override; }; +/** + * Called on startup, (context entirely filled with NULLs) + * or called for 'New File' both `startup.blend` and `userpref.blend` are checked. + * + * \param r_params_file_read_post: Support postponed initialization, + * needed for initial startup when only some sub-systems have been initialized. + * When non-null, #wm_file_read_post doesn't run, instead it's arguments are stored + * in this return argument. + * The caller is responsible for calling #wm_homefile_read_post with this return argument. + */ void wm_homefile_read_ex(struct bContext *C, const struct wmHomeFileRead_Params *params_homefile, struct ReportList *reports, @@ -70,15 +81,26 @@ void wm_homefile_read(struct bContext *C, const struct wmHomeFileRead_Params *params_homefile, struct ReportList *reports); +/** + * Special case, support deferred execution of #wm_file_read_post, + * Needed when loading for the first time to workaround order of initialization bug, see T89046. + */ void wm_homefile_read_post(struct bContext *C, const struct wmFileReadPost_Params *params_file_read_post); void wm_file_read_report(bContext *C, struct Main *bmain); void wm_close_file_dialog(bContext *C, struct wmGenericCallback *post_action); +/** + * \return True if the dialog was created, the calling operator should return #OPERATOR_INTERFACE + * then. + */ bool wm_operator_close_file_dialog_if_needed(bContext *C, wmOperator *op, wmGenericCallbackFn exec_fn); +/** + * Check if there is data that would be lost when closing the current file without saving. + */ bool wm_file_or_session_data_has_unsaved_changes(const Main *bmain, const wmWindowManager *wm); void WM_OT_save_homefile(struct wmOperatorType *ot); @@ -99,6 +121,7 @@ void WM_OT_save_as_mainfile(struct wmOperatorType *ot); void WM_OT_save_mainfile(struct wmOperatorType *ot); /* wm_files_link.c */ + void WM_OT_link(struct wmOperatorType *ot); void WM_OT_append(struct wmOperatorType *ot); diff --git a/source/blender/windowmanager/wm_surface.h b/source/blender/windowmanager/wm_surface.h index a2483d38154..e924b1e47ad 100644 --- a/source/blender/windowmanager/wm_surface.h +++ b/source/blender/windowmanager/wm_surface.h @@ -39,6 +39,8 @@ typedef struct wmSurface { void *customdata; void (*draw)(struct bContext *); + /* To evaluate the surface's depsgraph. Called as part of the main loop. */ + void (*do_depsgraph)(struct bContext *C); /** Free customdata, not the surface itself (done by wm_surface API) */ void (*free_data)(struct wmSurface *); @@ -56,6 +58,9 @@ void wm_surfaces_free(void); /* Utils */ void wm_surfaces_iter(struct bContext *C, void (*cb)(struct bContext *, wmSurface *)); +/* Evaluation. */ +void wm_surfaces_do_depsgraph(struct bContext *C); + /* Drawing */ void wm_surface_make_drawable(wmSurface *surface); void wm_surface_clear_drawable(void); diff --git a/source/blender/windowmanager/wm_window.h b/source/blender/windowmanager/wm_window.h index f205f923ec8..e44a39ecf1a 100644 --- a/source/blender/windowmanager/wm_window.h +++ b/source/blender/windowmanager/wm_window.h @@ -30,41 +30,93 @@ extern "C" { #endif /* *************** internal api ************** */ + +/** + * \note #bContext can be null in background mode because we don't + * need to event handling. + */ void wm_ghost_init(bContext *C); void wm_ghost_exit(void); +/** + * This one should correctly check for apple top header... + * done for Cocoa: returns window contents (and not frame) max size. + */ void wm_get_screensize(int *r_width, int *r_height); +/** + * Size of all screens (desktop), useful since the mouse is bound by this. + */ void wm_get_desktopsize(int *r_width, int *r_height); +/** + * Don't change context itself. + */ wmWindow *wm_window_new(const struct Main *bmain, wmWindowManager *wm, wmWindow *parent, bool dialog); +/** + * Part of `wm_window.c` API. + */ wmWindow *wm_window_copy(struct Main *bmain, wmWindowManager *wm, wmWindow *win_src, const bool duplicate_layout, const bool child); +/** + * A higher level version of copy that tests the new window can be added. + * (called from the operator directly). + */ wmWindow *wm_window_copy_test(bContext *C, wmWindow *win_src, const bool duplicate_layout, const bool child); +/** + * Including window itself. + * \param C: can be NULL. + * \note #ED_screen_exit should have been called. + */ void wm_window_free(bContext *C, wmWindowManager *wm, wmWindow *win); +/** + * This is event from ghost, or exit-Blender operator. + */ void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win); void wm_window_title(wmWindowManager *wm, wmWindow *win); +/** + * Initialize #wmWindow without `ghostwin`, open these and clear. + * + * Window size is read from window, if 0 it uses prefsize + * called in #WM_check, also initialize stuff after file read. + * + * \warning After running, `win->ghostwin` can be NULL in rare cases + * (where OpenGL driver fails to create a context for eg). + * We could remove them with #wm_window_ghostwindows_remove_invalid + * but better not since caller may continue to use. + * Instead, caller needs to handle the error case and cleanup. + */ void wm_window_ghostwindows_ensure(wmWindowManager *wm); +/** + * Call after #wm_window_ghostwindows_ensure or #WM_check + * (after loading a new file) in the unlikely event a window couldn't be created. + */ void wm_window_ghostwindows_remove_invalid(bContext *C, wmWindowManager *wm); void wm_window_process_events(const bContext *C); void wm_window_clear_drawable(wmWindowManager *wm); void wm_window_make_drawable(wmWindowManager *wm, wmWindow *win); +/** + * Reset active the current window opengl drawing context. + */ void wm_window_reset_drawable(void); void wm_window_raise(wmWindow *win); void wm_window_lower(wmWindow *win); void wm_window_set_size(wmWindow *win, int width, int height); void wm_window_get_position(wmWindow *win, int *r_pos_x, int *r_pos_y); +/** + * \brief Push rendered buffer to the screen. + */ void wm_window_swap_buffers(wmWindow *win); void wm_window_set_swap_interval(wmWindow *win, int interval); bool wm_window_get_swap_interval(wmWindow *win, int *intervalOut); @@ -79,8 +131,19 @@ void wm_window_IME_end(wmWindow *win); #endif /* *************** window operators ************** */ + int wm_window_close_exec(bContext *C, struct wmOperator *op); +/** + * Full-screen operator callback. + */ int wm_window_fullscreen_toggle_exec(bContext *C, struct wmOperator *op); +/** + * Call the quit confirmation prompt or exit directly if needed. The use can + * still cancel via the confirmation popup. Also, this may not quit Blender + * immediately, but rather schedule the closing. + * + * \param win: The window to show the confirmation popup/window in. + */ void wm_quit_with_optional_confirmation_prompt(bContext *C, wmWindow *win) ATTR_NONNULL(); int wm_window_new_exec(bContext *C, struct wmOperator *op); diff --git a/source/blender/windowmanager/xr/intern/wm_xr_actionmap.c b/source/blender/windowmanager/xr/intern/wm_xr_actionmap.c index 8903305adb4..076f279ccbb 100644 --- a/source/blender/windowmanager/xr/intern/wm_xr_actionmap.c +++ b/source/blender/windowmanager/xr/intern/wm_xr_actionmap.c @@ -85,9 +85,6 @@ static XrActionMapBinding *wm_xr_actionmap_binding_find_except(XrActionMapItem * return NULL; } -/** - * Ensure unique name among all action map bindings. - */ void WM_xr_actionmap_binding_ensure_unique(XrActionMapItem *ami, XrActionMapBinding *amb) { char name[MAX_NAME]; @@ -118,7 +115,6 @@ void WM_xr_actionmap_binding_ensure_unique(XrActionMapItem *ami, XrActionMapBind static XrActionMapBinding *wm_xr_actionmap_binding_copy(XrActionMapBinding *amb_src) { XrActionMapBinding *amb_dst = MEM_dupallocN(amb_src); - amb_dst->prev = amb_dst->next = NULL; return amb_dst; @@ -198,10 +194,6 @@ static void wm_xr_actionmap_item_properties_free(XrActionMapItem *ami) } } -/** - * Similar to #wm_xr_actionmap_item_properties_set() - * but checks for the #eXrActionType and #wmOperatorType having changed. - */ void WM_xr_actionmap_item_properties_update_ot(XrActionMapItem *ami) { switch (ami->type) { @@ -278,9 +270,6 @@ static XrActionMapItem *wm_xr_actionmap_item_find_except(XrActionMap *actionmap, return NULL; } -/** - * Ensure unique name among all action map items. - */ void WM_xr_actionmap_item_ensure_unique(XrActionMap *actionmap, XrActionMapItem *ami) { char name[MAX_NAME]; @@ -308,25 +297,29 @@ void WM_xr_actionmap_item_ensure_unique(XrActionMap *actionmap, XrActionMapItem BLI_strncpy(ami->name, name, MAX_NAME); } -static XrActionMapItem *wm_xr_actionmap_item_copy(XrActionMapItem *ami) +static XrActionMapItem *wm_xr_actionmap_item_copy(XrActionMapItem *ami_src) { - XrActionMapItem *amin = MEM_dupallocN(ami); - - amin->prev = amin->next = NULL; + XrActionMapItem *ami_dst = MEM_dupallocN(ami_src); + ami_dst->prev = ami_dst->next = NULL; - if (amin->op_properties) { - amin->op_properties_ptr = MEM_callocN(sizeof(PointerRNA), "wmOpItemPtr"); - WM_operator_properties_create(amin->op_properties_ptr, amin->op); + BLI_listbase_clear(&ami_dst->bindings); + LISTBASE_FOREACH (XrActionMapBinding *, amb, &ami_src->bindings) { + XrActionMapBinding *amb_new = wm_xr_actionmap_binding_copy(amb); + BLI_addtail(&ami_dst->bindings, amb_new); + } - amin->op_properties = IDP_CopyProperty(amin->op_properties); - amin->op_properties_ptr->data = amin->op_properties; + if (ami_dst->op_properties) { + ami_dst->op_properties_ptr = MEM_callocN(sizeof(PointerRNA), "wmOpItemPtr"); + WM_operator_properties_create(ami_dst->op_properties_ptr, ami_dst->op); + ami_dst->op_properties = IDP_CopyProperty(ami_src->op_properties); + ami_dst->op_properties_ptr->data = ami_dst->op_properties; } else { - amin->op_properties = NULL; - amin->op_properties_ptr = NULL; + ami_dst->op_properties = NULL; + ami_dst->op_properties_ptr = NULL; } - return amin; + return ami_dst; } XrActionMapItem *WM_xr_actionmap_item_add_copy(XrActionMap *actionmap, XrActionMapItem *ami_src) @@ -411,9 +404,6 @@ static XrActionMap *wm_xr_actionmap_find_except(wmXrRuntimeData *runtime, return NULL; } -/** - * Ensure unique name among all action maps. - */ void WM_xr_actionmap_ensure_unique(wmXrRuntimeData *runtime, XrActionMap *actionmap) { char name[MAX_NAME]; @@ -444,10 +434,9 @@ void WM_xr_actionmap_ensure_unique(wmXrRuntimeData *runtime, XrActionMap *action static XrActionMap *wm_xr_actionmap_copy(XrActionMap *am_src) { XrActionMap *am_dst = MEM_dupallocN(am_src); - am_dst->prev = am_dst->next = NULL; - BLI_listbase_clear(&am_dst->items); + BLI_listbase_clear(&am_dst->items); LISTBASE_FOREACH (XrActionMapItem *, ami, &am_src->items) { XrActionMapItem *ami_new = wm_xr_actionmap_item_copy(ami); BLI_addtail(&am_dst->items, ami_new); diff --git a/source/blender/windowmanager/xr/intern/wm_xr_draw.c b/source/blender/windowmanager/xr/intern/wm_xr_draw.c index 72d88bb3043..5d0163af5e1 100644 --- a/source/blender/windowmanager/xr/intern/wm_xr_draw.c +++ b/source/blender/windowmanager/xr/intern/wm_xr_draw.c @@ -139,12 +139,6 @@ static void wm_xr_draw_viewport_buffers_to_active_framebuffer( GPU_viewport_draw_to_screen_ex(vp->viewport, 0, &rect, draw_view->expects_srgb_buffer, true); } -/** - * \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; diff --git a/source/blender/windowmanager/xr/intern/wm_xr_intern.h b/source/blender/windowmanager/xr/intern/wm_xr_intern.h index 7de1f254224..e2368901757 100644 --- a/source/blender/windowmanager/xr/intern/wm_xr_intern.h +++ b/source/blender/windowmanager/xr/intern/wm_xr_intern.h @@ -213,6 +213,11 @@ void wm_xr_session_draw_data_update(wmXrSessionState *state, const XrSessionSettings *settings, const GHOST_XrDrawViewInfo *draw_view, wmXrDrawData *draw_data); +/** + * 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. + * Controller data and action sets will be updated separately via wm_xr_session_actions_update(). + */ void wm_xr_session_state_update(const XrSessionSettings *settings, const wmXrDrawData *draw_data, const GHOST_XrDrawViewInfo *draw_view, @@ -230,9 +235,16 @@ void wm_xr_session_controller_data_populate(const wmXrAction *grip_action, void wm_xr_session_controller_data_clear(wmXrSessionState *state); /* wm_xr_draw.c */ + void wm_xr_pose_to_mat(const GHOST_XrPose *pose, float r_mat[4][4]); void wm_xr_pose_scale_to_mat(const GHOST_XrPose *pose, float scale, float r_mat[4][4]); void wm_xr_pose_to_imat(const GHOST_XrPose *pose, float r_imat[4][4]); void wm_xr_pose_scale_to_imat(const GHOST_XrPose *pose, float scale, float r_imat[4][4]); +/** + * \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); void wm_xr_draw_controllers(const struct bContext *C, struct ARegion *region, void *customdata); diff --git a/source/blender/windowmanager/xr/intern/wm_xr_operators.c b/source/blender/windowmanager/xr/intern/wm_xr_operators.c index f3470edf2f7..c503f5d4fee 100644 --- a/source/blender/windowmanager/xr/intern/wm_xr_operators.c +++ b/source/blender/windowmanager/xr/intern/wm_xr_operators.c @@ -553,7 +553,7 @@ static int wm_xr_navigation_grab_modal(bContext *C, wmOperator *op, const wmEven wm_xr_navigation_grab_bimanual_state_update(actiondata, data); - /* Note: KM_PRESS and KM_RELEASE are the only two values supported by XR events during event + /* NOTE: #KM_PRESS and #KM_RELEASE are the only two values supported by XR events during event * dispatching (see #wm_xr_session_action_states_interpret()). For modal XR operators, modal * handling starts when an input is "pressed" (action state exceeds the action threshold) and * ends when the input is "released" (state falls below the threshold). */ diff --git a/source/blender/windowmanager/xr/intern/wm_xr_session.c b/source/blender/windowmanager/xr/intern/wm_xr_session.c index 3224869b04a..bad735ee598 100644 --- a/source/blender/windowmanager/xr/intern/wm_xr_session.c +++ b/source/blender/windowmanager/xr/intern/wm_xr_session.c @@ -30,6 +30,7 @@ #include "BLI_math.h" #include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" #include "DNA_camera_types.h" #include "DNA_space_types.h" @@ -154,10 +155,6 @@ void wm_xr_session_toggle(wmWindowManager *wm, } } -/** - * 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; @@ -168,9 +165,6 @@ 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); @@ -250,10 +244,9 @@ wmWindow *wm_xr_session_root_window_or_fallback_get(const wmWindowManager *wm, * It's important that the VR session follows some existing window, otherwise it would need to have * an own depsgraph, which is an expense we should avoid. */ -static void wm_xr_session_scene_and_evaluated_depsgraph_get(Main *bmain, - const wmWindowManager *wm, - Scene **r_scene, - Depsgraph **r_depsgraph) +static void wm_xr_session_scene_and_depsgraph_get(const wmWindowManager *wm, + Scene **r_scene, + Depsgraph **r_depsgraph) { const wmWindow *root_win = wm_xr_session_root_window_or_fallback_get(wm, wm->xr.runtime); @@ -263,7 +256,6 @@ static void wm_xr_session_scene_and_evaluated_depsgraph_get(Main *bmain, Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer); BLI_assert(scene && view_layer && depsgraph); - BKE_scene_graph_evaluated_ensure(depsgraph, bmain); *r_scene = scene; *r_depsgraph = depsgraph; } @@ -354,11 +346,6 @@ void wm_xr_session_draw_data_update(wmXrSessionState *state, } } -/** - * 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. - * Controller data and action sets will be updated separately via wm_xr_session_actions_update(). - */ void wm_xr_session_state_update(const XrSessionSettings *settings, const wmXrDrawData *draw_data, const GHOST_XrDrawViewInfo *draw_view, @@ -1314,7 +1301,6 @@ void wm_xr_session_controller_data_clear(wmXrSessionState *state) static void wm_xr_session_surface_draw(bContext *C) { wmWindowManager *wm = CTX_wm_manager(C); - Main *bmain = CTX_data_main(C); wmXrDrawData draw_data; if (!WM_xr_session_is_ready(&wm->xr)) { @@ -1323,12 +1309,32 @@ static void wm_xr_session_surface_draw(bContext *C) Scene *scene; Depsgraph *depsgraph; - wm_xr_session_scene_and_evaluated_depsgraph_get(bmain, wm, &scene, &depsgraph); + wm_xr_session_scene_and_depsgraph_get(wm, &scene, &depsgraph); + /* Might fail when force-redrawing windows with #WM_redraw_windows(), which is done on file + * writing for example. */ + // BLI_assert(DEG_is_fully_evaluated(depsgraph)); wm_xr_session_draw_data_populate(&wm->xr, scene, depsgraph, &draw_data); GHOST_XrSessionDrawViews(wm->xr.runtime->context, &draw_data); - GPU_framebuffer_restore(); + /* There's no active framebuffer if the session was cancelled (exception while drawing views). */ + if (GPU_framebuffer_active_get()) { + GPU_framebuffer_restore(); + } +} + +static void wm_xr_session_do_depsgraph(bContext *C) +{ + wmWindowManager *wm = CTX_wm_manager(C); + + if (!WM_xr_session_is_ready(&wm->xr)) { + return; + } + + Scene *scene; + Depsgraph *depsgraph; + wm_xr_session_scene_and_depsgraph_get(wm, &scene, &depsgraph); + BKE_scene_graph_evaluated_ensure(depsgraph, CTX_data_main(C)); } bool wm_xr_session_surface_offscreen_ensure(wmXrSurfaceData *surface_data, @@ -1439,6 +1445,7 @@ static wmSurface *wm_xr_session_surface_create(void) data->controller_art = MEM_callocN(sizeof(*(data->controller_art)), "XrControllerRegionType"); surface->draw = wm_xr_session_surface_draw; + surface->do_depsgraph = wm_xr_session_do_depsgraph; surface->free_data = wm_xr_session_surface_free_data; surface->activate = DRW_xr_drawing_begin; surface->deactivate = DRW_xr_drawing_end; |