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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/windowmanager/intern')
-rw-r--r--source/blender/windowmanager/intern/wm.c45
-rw-r--r--source/blender/windowmanager/intern/wm_dragdrop.c8
-rw-r--r--source/blender/windowmanager/intern/wm_draw.c60
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c118
-rw-r--r--source/blender/windowmanager/intern/wm_files.c363
-rw-r--r--source/blender/windowmanager/intern/wm_files_link.c5
-rw-r--r--source/blender/windowmanager/intern/wm_gesture.c5
-rw-r--r--source/blender/windowmanager/intern/wm_init_exit.c15
-rw-r--r--source/blender/windowmanager/intern/wm_keymap.c7
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c149
-rw-r--r--source/blender/windowmanager/intern/wm_playanim.c5
-rw-r--r--source/blender/windowmanager/intern/wm_stereo.c32
-rw-r--r--source/blender/windowmanager/intern/wm_window.c107
13 files changed, 670 insertions, 249 deletions
diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c
index b76a1f1d422..a09cc4aeb31 100644
--- a/source/blender/windowmanager/intern/wm.c
+++ b/source/blender/windowmanager/intern/wm.c
@@ -107,6 +107,17 @@ void WM_operator_free(wmOperator *op)
MEM_freeN(op);
}
+void WM_operator_free_all_after(wmWindowManager *wm, struct wmOperator *op)
+{
+ op = op->next;
+ while (op != NULL) {
+ wmOperator *op_next = op->next;
+ BLI_remlink(&wm->operators, op);
+ WM_operator_free(op);
+ op = op_next;
+ }
+}
+
/**
* Use with extreme care!,
* properties, customdata etc - must be compatible.
@@ -149,18 +160,23 @@ static void wm_reports_free(wmWindowManager *wm)
void wm_operator_register(bContext *C, wmOperator *op)
{
wmWindowManager *wm = CTX_wm_manager(C);
- int tot;
+ int tot = 0;
BLI_addtail(&wm->operators, op);
- tot = BLI_listbase_count(&wm->operators);
-
- while (tot > MAX_OP_REGISTERED) {
- wmOperator *opt = wm->operators.first;
- BLI_remlink(&wm->operators, opt);
- WM_operator_free(opt);
- tot--;
+
+ /* only count registered operators */
+ while (op) {
+ wmOperator *op_prev = op->prev;
+ if (op->type->flag & OPTYPE_REGISTER) {
+ tot += 1;
+ }
+ if (tot > MAX_OP_REGISTERED) {
+ BLI_remlink(&wm->operators, op);
+ WM_operator_free(op);
+ }
+ op = op_prev;
}
-
+
/* so the console is redrawn */
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_INFO_REPORT, NULL);
WM_event_add_notifier(C, NC_WM | ND_HISTORY, NULL);
@@ -414,7 +430,7 @@ void wm_clear_default_size(bContext *C)
/* on startup, it adds all data, for matching */
void wm_add_default(bContext *C)
{
- wmWindowManager *wm = BKE_libblock_alloc(CTX_data_main(C), ID_WM, "WinMan");
+ wmWindowManager *wm = BKE_libblock_alloc(CTX_data_main(C), ID_WM, "WinMan", 0);
wmWindow *win;
bScreen *screen = CTX_wm_screen(C); /* XXX from file read hrmf */
@@ -467,19 +483,22 @@ void wm_close_and_free(bContext *C, wmWindowManager *wm)
void wm_close_and_free_all(bContext *C, ListBase *wmlist)
{
- Main *bmain = CTX_data_main(C);
wmWindowManager *wm;
-
+
while ((wm = wmlist->first)) {
wm_close_and_free(C, wm);
BLI_remlink(wmlist, wm);
- BKE_libblock_free_data(bmain, &wm->id);
+ BKE_libblock_free_data(&wm->id, true);
MEM_freeN(wm);
}
}
void WM_main(bContext *C)
{
+ /* Single refresh before handling events.
+ * This ensures we don't run operators before the depsgraph has been evaluated. */
+ wm_event_do_refresh_wm_and_depsgraph(C);
+
while (1) {
/* get events from ghost, handle window events, add to window queues */
diff --git a/source/blender/windowmanager/intern/wm_dragdrop.c b/source/blender/windowmanager/intern/wm_dragdrop.c
index 3a53906a8e8..dd01efdb4c4 100644
--- a/source/blender/windowmanager/intern/wm_dragdrop.c
+++ b/source/blender/windowmanager/intern/wm_dragdrop.c
@@ -185,7 +185,7 @@ void WM_drag_free_list(struct ListBase *lb)
}
}
-static const char *dropbox_active(bContext *C, ListBase *handlers, wmDrag *drag, wmEvent *event)
+static const char *dropbox_active(bContext *C, ListBase *handlers, wmDrag *drag, const wmEvent *event)
{
wmEventHandler *handler = handlers->first;
for (; handler; handler = handler->next) {
@@ -203,7 +203,7 @@ static const char *dropbox_active(bContext *C, ListBase *handlers, wmDrag *drag,
}
/* return active operator name when mouse is in box */
-static const char *wm_dropbox_active(bContext *C, wmDrag *drag, wmEvent *event)
+static const char *wm_dropbox_active(bContext *C, wmDrag *drag, const wmEvent *event)
{
wmWindow *win = CTX_wm_window(C);
ScrArea *sa = CTX_wm_area(C);
@@ -223,7 +223,7 @@ static const char *wm_dropbox_active(bContext *C, wmDrag *drag, wmEvent *event)
}
-static void wm_drop_operator_options(bContext *C, wmDrag *drag, wmEvent *event)
+static void wm_drop_operator_options(bContext *C, wmDrag *drag, const wmEvent *event)
{
wmWindow *win = CTX_wm_window(C);
const int winsize_x = WM_window_pixels_x(win);
@@ -253,7 +253,7 @@ static void wm_drop_operator_options(bContext *C, wmDrag *drag, wmEvent *event)
}
/* called in inner handler loop, region context */
-void wm_drags_check_ops(bContext *C, wmEvent *event)
+void wm_drags_check_ops(bContext *C, const wmEvent *event)
{
wmWindowManager *wm = CTX_wm_manager(C);
wmDrag *drag;
diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c
index 3825db14e93..2b695c95258 100644
--- a/source/blender/windowmanager/intern/wm_draw.c
+++ b/source/blender/windowmanager/intern/wm_draw.c
@@ -430,7 +430,7 @@ static int wm_triple_gen_textures(wmWindow *win, wmDrawTriple *triple)
return 1;
}
-void wm_triple_draw_textures(wmWindow *win, wmDrawTriple *triple, float alpha)
+void wm_triple_draw_textures(wmWindow *win, wmDrawTriple *triple, float alpha, bool is_interlace)
{
const int sizex = WM_window_pixels_x(win);
const int sizey = WM_window_pixels_y(win);
@@ -451,7 +451,13 @@ void wm_triple_draw_textures(wmWindow *win, wmDrawTriple *triple, float alpha)
halfy /= triple->y;
}
- GPU_basic_shader_bind((triple->target == GL_TEXTURE_2D) ? GPU_SHADER_TEXTURE_2D : GPU_SHADER_TEXTURE_RECT);
+ /* interlace stereo buffer bind the shader before calling wm_triple_draw_textures */
+ if (is_interlace) {
+ glEnable(triple->target);
+ }
+ else {
+ GPU_basic_shader_bind((triple->target == GL_TEXTURE_2D) ? GPU_SHADER_TEXTURE_2D : GPU_SHADER_TEXTURE_RECT);
+ }
glBindTexture(triple->target, triple->bind);
@@ -472,7 +478,12 @@ void wm_triple_draw_textures(wmWindow *win, wmDrawTriple *triple, float alpha)
glBindTexture(triple->target, 0);
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
+ if (is_interlace) {
+ glDisable(triple->target);
+ }
+ else {
+ GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
+ }
}
static void wm_triple_copy_textures(wmWindow *win, wmDrawTriple *triple)
@@ -495,7 +506,7 @@ static void wm_draw_region_blend(wmWindow *win, ARegion *ar, wmDrawTriple *tripl
wmSubWindowScissorSet(win, win->screen->mainwin, &ar->winrct, true);
glEnable(GL_BLEND);
- wm_triple_draw_textures(win, triple, 1.0f - fac);
+ wm_triple_draw_textures(win, triple, 1.0f - fac, false);
glDisable(GL_BLEND);
}
}
@@ -516,7 +527,7 @@ static void wm_method_draw_triple(bContext *C, wmWindow *win)
wmSubWindowSet(win, screen->mainwin);
- wm_triple_draw_textures(win, drawdata->triple, 1.0f);
+ wm_triple_draw_textures(win, drawdata->triple, 1.0f, false);
}
else {
/* we run it when we start OR when we turn stereo on */
@@ -656,7 +667,7 @@ static void wm_method_draw_triple_multiview(bContext *C, wmWindow *win, StereoVi
wmSubWindowSet(win, screen->mainwin);
- wm_triple_draw_textures(win, drawdata->triple, 1.0f);
+ wm_triple_draw_textures(win, drawdata->triple, 1.0f, false);
}
}
else {
@@ -856,25 +867,13 @@ static bool wm_draw_update_test_window(wmWindow *win)
static int wm_automatic_draw_method(wmWindow *win)
{
- /* Ideally all cards would work well with triple buffer, since if it works
- * well gives the least redraws and is considerably faster at partial redraw
- * for sculpting or drawing overlapping menus. For typically lower end cards
- * copy to texture is slow though and so we use overlap instead there. */
-
+ /* We assume all supported GPUs now support triple buffer well. */
if (win->drawmethod == USER_DRAW_AUTOMATIC) {
- /* Windows software driver darkens color on each redraw */
- if (GPU_type_matches(GPU_DEVICE_SOFTWARE, GPU_OS_WIN, GPU_DRIVER_SOFTWARE))
- return USER_DRAW_OVERLAP_FLIP;
- else if (GPU_type_matches(GPU_DEVICE_SOFTWARE, GPU_OS_UNIX, GPU_DRIVER_SOFTWARE))
- return USER_DRAW_OVERLAP;
- /* drawing lower color depth again degrades colors each time */
- else if (GPU_color_depth() < 24)
- return USER_DRAW_OVERLAP;
- else
- return USER_DRAW_TRIPLE;
+ return USER_DRAW_TRIPLE;
}
- else
+ else {
return win->drawmethod;
+ }
}
bool WM_is_draw_triple(wmWindow *win)
@@ -915,15 +914,14 @@ void wm_draw_update(bContext *C)
for (win = wm->windows.first; win; win = win->next) {
#ifdef WIN32
- if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_ANY, GPU_DRIVER_ANY)) {
- GHOST_TWindowState state = GHOST_GetWindowState(win->ghostwin);
-
- if (state == GHOST_kWindowStateMinimized) {
- /* do not update minimized windows, it gives issues on intel drivers (see [#33223])
- * anyway, it seems logical to skip update for invisible windows
- */
- continue;
- }
+ GHOST_TWindowState state = GHOST_GetWindowState(win->ghostwin);
+
+ if (state == GHOST_kWindowStateMinimized) {
+ /* do not update minimized windows, gives issues on Intel (see T33223)
+ * and AMD (see T50856). it seems logical to skip update for invisible
+ * window anyway.
+ */
+ continue;
}
#endif
if (win->drawmethod != U.wmdrawmethod) {
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index d2b0acd836b..7e7314cc0c8 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -263,13 +263,56 @@ static void wm_notifier_clear(wmNotifier *note)
memset(((char *)note) + sizeof(Link), 0, sizeof(*note) - sizeof(Link));
}
+/**
+ * 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);
+ uint64_t win_combine_v3d_datamask = 0;
+
+ /* combine datamasks so 1 win doesn't disable UV's in another [#26448] */
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ win_combine_v3d_datamask |= ED_view3d_screen_datamask(win->screen);
+ }
+
+ /* cached: editor refresh callbacks now, they get context */
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ ScrArea *sa;
+
+ CTX_wm_window_set(C, win);
+ for (sa = win->screen->areabase.first; sa; sa = sa->next) {
+ if (sa->do_refresh) {
+ CTX_wm_area_set(C, sa);
+ ED_area_do_refresh(C, sa);
+ }
+ }
+
+ /* XXX make lock in future, or separated derivedmesh users in scene */
+ if (G.is_rendering == false) {
+ /* depsgraph & animation: update tagged datablocks */
+ Main *bmain = CTX_data_main(C);
+
+ /* copied to set's in scene_update_tagged_recursive() */
+ win->screen->scene->customdata_mask = win_combine_v3d_datamask;
+
+ /* XXX, hack so operators can enforce datamasks [#26482], gl render */
+ win->screen->scene->customdata_mask |= win->screen->scene->customdata_mask_modal;
+
+ BKE_scene_update_tagged(bmain->eval_ctx, bmain, win->screen->scene);
+ }
+ }
+
+ CTX_wm_window_set(C, NULL);
+}
+
/* called in mainloop */
void wm_event_do_notifiers(bContext *C)
{
wmWindowManager *wm = CTX_wm_manager(C);
wmNotifier *note, *next;
wmWindow *win;
- uint64_t win_combine_v3d_datamask = 0;
if (wm == NULL)
return;
@@ -373,39 +416,7 @@ void wm_event_do_notifiers(bContext *C)
MEM_freeN(note);
}
- /* combine datamasks so 1 win doesn't disable UV's in another [#26448] */
- for (win = wm->windows.first; win; win = win->next) {
- win_combine_v3d_datamask |= ED_view3d_screen_datamask(win->screen);
- }
-
- /* cached: editor refresh callbacks now, they get context */
- for (win = wm->windows.first; win; win = win->next) {
- ScrArea *sa;
-
- CTX_wm_window_set(C, win);
- for (sa = win->screen->areabase.first; sa; sa = sa->next) {
- if (sa->do_refresh) {
- CTX_wm_area_set(C, sa);
- ED_area_do_refresh(C, sa);
- }
- }
-
- /* XXX make lock in future, or separated derivedmesh users in scene */
- if (G.is_rendering == false) {
- /* depsgraph & animation: update tagged datablocks */
- Main *bmain = CTX_data_main(C);
-
- /* copied to set's in scene_update_tagged_recursive() */
- win->screen->scene->customdata_mask = win_combine_v3d_datamask;
-
- /* XXX, hack so operators can enforce datamasks [#26482], gl render */
- win->screen->scene->customdata_mask |= win->screen->scene->customdata_mask_modal;
-
- BKE_scene_update_tagged(bmain->eval_ctx, bmain, win->screen->scene);
- }
- }
-
- CTX_wm_window_set(C, NULL);
+ wm_event_do_refresh_wm_and_depsgraph(C);
}
static int wm_event_always_pass(const wmEvent *event)
@@ -615,6 +626,16 @@ bool WM_event_is_absolute(const wmEvent *event)
return (event->tablet_data != NULL);
}
+bool WM_event_is_last_mousemove(const wmEvent *event)
+{
+ while ((event = event->next)) {
+ if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
+ return false;
+ }
+ }
+ return true;
+}
+
#ifdef WITH_INPUT_NDOF
void WM_ndof_deadzone_set(float deadzone)
{
@@ -715,7 +736,9 @@ static void wm_operator_reports(bContext *C, wmOperator *op, int retval, bool ca
*/
static bool wm_operator_register_check(wmWindowManager *wm, wmOperatorType *ot)
{
- return wm && (wm->op_undo_depth == 0) && (ot->flag & OPTYPE_REGISTER);
+ /* Check undo flag here since undo operators are also added to the list,
+ * to support checking if the same operator is run twice. */
+ return wm && (wm->op_undo_depth == 0) && (ot->flag & (OPTYPE_REGISTER | OPTYPE_UNDO));
}
static void wm_operator_finished(bContext *C, wmOperator *op, const bool repeat)
@@ -878,6 +901,20 @@ bool WM_operator_repeat_check(const bContext *UNUSED(C), wmOperator *op)
return false;
}
+bool WM_operator_is_repeat(const bContext *C, const wmOperator *op)
+{
+ /* may be in the operators list or not */
+ wmOperator *op_prev;
+ if (op->prev == NULL && op->next == NULL) {
+ wmWindowManager *wm = CTX_wm_manager(C);
+ op_prev = wm->operators.last;
+ }
+ else {
+ op_prev = op->prev;
+ }
+ return (op_prev && (op->type == op_prev->type));
+}
+
static wmOperator *wm_operator_create(wmWindowManager *wm, wmOperatorType *ot,
PointerRNA *properties, ReportList *reports)
{
@@ -1063,6 +1100,9 @@ bool WM_operator_last_properties_store(wmOperator *UNUSED(op))
#endif
+/**
+ * Also used for exec when 'event' is NULL.
+ */
static int wm_operator_invoke(
bContext *C, wmOperatorType *ot, wmEvent *event,
PointerRNA *properties, ReportList *reports, const bool poll_only)
@@ -1078,7 +1118,9 @@ static int wm_operator_invoke(
wmOperator *op = wm_operator_create(wm, ot, properties, reports); /* if reports == NULL, they'll be initialized */
const bool is_nested_call = (wm->op_undo_depth != 0);
- op->flag |= OP_IS_INVOKE;
+ if (event != NULL) {
+ op->flag |= OP_IS_INVOKE;
+ }
/* initialize setting from previous run */
if (!is_nested_call) { /* not called by py script */
@@ -2836,7 +2878,7 @@ void WM_event_add_mousemove(bContext *C)
/* for modal callbacks, check configuration for how to interpret exit with tweaks */
-bool WM_modal_tweak_exit(const wmEvent *event, int tweak_event)
+bool WM_event_is_modal_tweak_exit(const wmEvent *event, int tweak_event)
{
/* if the release-confirm userpref setting is enabled,
* tweak events can be canceled when mouse is released
@@ -3179,6 +3221,8 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
GHOST_TEventCursorData *cd = customdata;
copy_v2_v2_int(&event.x, &cd->x);
+ wm_stereo3d_mouse_offset_apply(win, &event.x);
+
event.type = MOUSEMOVE;
wm_event_add_mousemove(win, &event);
copy_v2_v2_int(&evt->x, &event.x);
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c
index 05d63869074..637ace9cd82 100644
--- a/source/blender/windowmanager/intern/wm_files.c
+++ b/source/blender/windowmanager/intern/wm_files.c
@@ -316,7 +316,7 @@ static void wm_window_match_do(bContext *C, ListBase *oldwmlist)
}
/* in case UserDef was read, we re-initialize all, and do versioning */
-static void wm_init_userdef(bContext *C, const bool from_memory)
+static void wm_init_userdef(bContext *C, const bool read_userdef_from_memory)
{
Main *bmain = CTX_data_main(C);
@@ -336,14 +336,12 @@ static void wm_init_userdef(bContext *C, const bool from_memory)
}
/* avoid re-saving for every small change to our prefs, allow overrides */
- if (from_memory) {
+ if (read_userdef_from_memory) {
BLO_update_defaults_userpref_blend();
}
/* update tempdir from user preferences */
BKE_tempdir_init(U.tempdir);
-
- BKE_blender_userdef_refresh();
}
@@ -451,7 +449,7 @@ void wm_file_read_report(bContext *C)
* Logic shared between #WM_file_read & #wm_homefile_read,
* updates to make after reading a file.
*/
-static void wm_file_read_post(bContext *C, bool is_startup_file)
+static void wm_file_read_post(bContext *C, const bool is_startup_file, const bool use_userdef)
{
bool addons_loaded = false;
wmWindowManager *wm = CTX_wm_manager(C);
@@ -470,9 +468,14 @@ static void wm_file_read_post(bContext *C, bool is_startup_file)
if (is_startup_file) {
/* possible python hasn't been initialized */
if (CTX_py_init_get(C)) {
- /* sync addons, these may have changed from the defaults */
- BPY_execute_string(C, "__import__('addon_utils').reset_all()");
-
+ if (use_userdef) {
+ /* Only run when we have a template path found. */
+ if (BKE_appdir_app_template_any()) {
+ BPY_execute_string(C, "__import__('bl_app_template_utils').reset()");
+ }
+ /* sync addons, these may have changed from the defaults */
+ BPY_execute_string(C, "__import__('addon_utils').reset_all()");
+ }
BPY_python_reset(C);
addons_loaded = true;
}
@@ -554,7 +557,7 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports)
/* confusing this global... */
G.relbase_valid = 1;
- retval = BKE_blendfile_read(C, filepath, reports);
+ retval = BKE_blendfile_read(C, filepath, reports, 0);
/* when loading startup.blend's, we can be left with a blank path */
if (G.main->name[0]) {
G.save_over = 1;
@@ -586,7 +589,7 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports)
}
}
- wm_file_read_post(C, false);
+ wm_file_read_post(C, false, false);
success = true;
}
@@ -629,32 +632,47 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports)
/**
- * called on startup, (context entirely filled with NULLs)
- * or called for 'New File'
- * both startup.blend and userpref.blend are checked
- * the optional parameter custom_file points to an alternative startup page
- * custom_file can be NULL
+ * Called on startup, (context entirely filled with NULLs)
+ * or called for 'New File' both startup.blend and userpref.blend are checked.
+ *
+ * \param use_factory_settings: Ignore on-disk startup file, use bundled ``datatoc_startup_blend`` instead.
+ * Used for "Restore Factory Settings".
+ * \param use_userdef: Load factory settings as well as startup file.
+ * Disabled for "File New" we don't want to reload preferences.
+ * \param filepath_startup_override: Optional path pointing to an alternative blend file (may be NULL).
+ * \param app_template_override: Template to use instead of the template defined in user-preferences.
+ * When not-null, this is written into the user preferences.
*/
-int wm_homefile_read(bContext *C, ReportList *reports, bool from_memory, const char *custom_file)
+int wm_homefile_read(
+ bContext *C, ReportList *reports,
+ bool use_factory_settings, bool use_empty_data, bool use_userdef,
+ const char *filepath_startup_override, const char *app_template_override)
{
ListBase wmbase;
- char startstr[FILE_MAX];
- char prefstr[FILE_MAX];
- int success = 0;
+ bool success = false;
+
+ char filepath_startup[FILE_MAX];
+ char filepath_userdef[FILE_MAX];
+
+ /* When 'app_template' is set: '{BLENDER_USER_CONFIG}/{app_template}' */
+ char app_template_system[FILE_MAX];
+ /* When 'app_template' is set: '{BLENDER_SYSTEM_SCRIPTS}/startup/bl_app_templates_system/{app_template}' */
+ char app_template_config[FILE_MAX];
/* Indicates whether user preferences were really load from memory.
*
- * This is used for versioning code, and for this we can not rely on from_memory
+ * This is used for versioning code, and for this we can not rely on use_factory_settings
* passed via argument. This is because there might be configuration folder
* exists but it might not have userpref.blend and in this case we fallback to
* reading home file from memory.
*
* And in this case versioning code is to be run.
*/
- bool read_userdef_from_memory = true;
+ bool read_userdef_from_memory = false;
+ eBLOReadSkip skip_flags = use_userdef ? 0 : BLO_READ_SKIP_USERDEF;
/* options exclude eachother */
- BLI_assert((from_memory && custom_file) == 0);
+ BLI_assert((use_factory_settings && filepath_startup_override) == 0);
if ((G.f & G_SCRIPT_OVERRIDE_PREF) == 0) {
BKE_BIT_TEST_SET(G.f, (U.flag & USER_SCRIPT_AUTOEXEC_DISABLE) == 0, G_SCRIPT_AUTOEXEC);
@@ -665,77 +683,167 @@ int wm_homefile_read(bContext *C, ReportList *reports, bool from_memory, const c
UI_view2d_zoom_cache_reset();
G.relbase_valid = 0;
- if (!from_memory) {
- const char * const cfgdir = BKE_appdir_folder_id(BLENDER_USER_CONFIG, NULL);
- if (custom_file) {
- BLI_strncpy(startstr, custom_file, FILE_MAX);
- if (cfgdir) {
- BLI_make_file_string(G.main->name, prefstr, cfgdir, BLENDER_USERPREF_FILE);
+ /* put aside screens to match with persistent windows later */
+ wm_window_match_init(C, &wmbase);
+
+ filepath_startup[0] = '\0';
+ filepath_userdef[0] = '\0';
+ app_template_system[0] = '\0';
+ app_template_config[0] = '\0';
+
+ const char * const cfgdir = BKE_appdir_folder_id(BLENDER_USER_CONFIG, NULL);
+ if (!use_factory_settings) {
+ if (cfgdir) {
+ BLI_path_join(filepath_startup, sizeof(filepath_startup), cfgdir, BLENDER_STARTUP_FILE, NULL);
+ if (use_userdef) {
+ BLI_path_join(filepath_userdef, sizeof(filepath_startup), cfgdir, BLENDER_USERPREF_FILE, NULL);
}
- else {
- prefstr[0] = '\0';
+ }
+ else {
+ use_factory_settings = true;
+ }
+
+ if (filepath_startup_override) {
+ BLI_strncpy(filepath_startup, filepath_startup_override, FILE_MAX);
+ }
+ }
+
+ /* load preferences before startup.blend */
+ if (use_userdef) {
+ if (!use_factory_settings && BLI_exists(filepath_userdef)) {
+ UserDef *userdef = BKE_blendfile_userdef_read(filepath_userdef, NULL);
+ if (userdef != NULL) {
+ BKE_blender_userdef_set_data(userdef);
+ MEM_freeN(userdef);
+
+ skip_flags |= BLO_READ_SKIP_USERDEF;
+ printf("Read prefs: %s\n", filepath_userdef);
}
}
- else if (cfgdir) {
- BLI_make_file_string(G.main->name, startstr, cfgdir, BLENDER_STARTUP_FILE);
- BLI_make_file_string(G.main->name, prefstr, cfgdir, BLENDER_USERPREF_FILE);
+ }
+
+ const char *app_template = NULL;
+
+ if (filepath_startup_override != NULL) {
+ /* pass */
+ }
+ else if (app_template_override) {
+ /* This may be clearing the current template by setting to an empty string. */
+ app_template = app_template_override;
+ }
+ else if (!use_factory_settings && U.app_template[0]) {
+ app_template = U.app_template;
+ }
+
+ if ((app_template != NULL) && (app_template[0] != '\0')) {
+ BKE_appdir_app_template_id_search(app_template, app_template_system, sizeof(app_template_system));
+
+ /* Insert template name into startup file. */
+
+ /* note that the path is being set even when 'use_factory_settings == true'
+ * this is done so we can load a templates factory-settings */
+ if (!use_factory_settings) {
+ BLI_path_join(app_template_config, sizeof(app_template_config), cfgdir, app_template, NULL);
+ BLI_path_join(filepath_startup, sizeof(filepath_startup), app_template_config, BLENDER_STARTUP_FILE, NULL);
+ if (BLI_access(filepath_startup, R_OK) != 0) {
+ filepath_startup[0] = '\0';
+ }
}
else {
- startstr[0] = '\0';
- prefstr[0] = '\0';
- from_memory = 1;
+ filepath_startup[0] = '\0';
+ }
+
+ if (filepath_startup[0] == '\0') {
+ BLI_path_join(filepath_startup, sizeof(filepath_startup), app_template_system, BLENDER_STARTUP_FILE, NULL);
}
}
-
- /* put aside screens to match with persistent windows later */
- wm_window_match_init(C, &wmbase);
-
- if (!from_memory) {
- if (BLI_access(startstr, R_OK) == 0) {
- success = (BKE_blendfile_read(C, startstr, NULL) != BKE_BLENDFILE_READ_FAIL);
+
+ if (!use_factory_settings || (filepath_startup[0] != '\0')) {
+ if (BLI_access(filepath_startup, R_OK) == 0) {
+ success = (BKE_blendfile_read(C, filepath_startup, NULL, skip_flags) != BKE_BLENDFILE_READ_FAIL);
}
if (BLI_listbase_is_empty(&U.themes)) {
if (G.debug & G_DEBUG)
- printf("\nNote: No (valid) '%s' found, fall back to built-in default.\n\n", startstr);
- success = 0;
+ printf("\nNote: No (valid) '%s' found, fall back to built-in default.\n\n", filepath_startup);
+ success = false;
}
}
- if (success == 0 && custom_file && reports) {
- BKE_reportf(reports, RPT_ERROR, "Could not read '%s'", custom_file);
- /*We can not return from here because wm is already reset*/
+ if (success == false && filepath_startup_override && reports) {
+ /* We can not return from here because wm is already reset */
+ BKE_reportf(reports, RPT_ERROR, "Could not read '%s'", filepath_startup_override);
}
- if (success == 0) {
- success = BKE_blendfile_read_from_memory(C, datatoc_startup_blend, datatoc_startup_blend_size, NULL, true);
+ if (success == false) {
+ success = BKE_blendfile_read_from_memory(
+ C, datatoc_startup_blend, datatoc_startup_blend_size,
+ NULL, skip_flags, true);
+ if (success) {
+ if (use_userdef) {
+ if ((skip_flags & BLO_READ_SKIP_USERDEF) == 0) {
+ read_userdef_from_memory = true;
+ }
+ }
+ }
if (BLI_listbase_is_empty(&wmbase)) {
wm_clear_default_size(C);
}
- BKE_tempdir_init(U.tempdir);
+ }
-#ifdef WITH_PYTHON_SECURITY
- /* use alternative setting for security nuts
- * otherwise we'd need to patch the binary blob - startup.blend.c */
- U.flag |= USER_SCRIPT_AUTOEXEC_DISABLE;
-#endif
+ if (use_empty_data) {
+ BKE_blendfile_read_make_empty(C);
}
-
- /* check new prefs only after startup.blend was finished */
- if (!from_memory && BLI_exists(prefstr)) {
- int done = BKE_blendfile_read_userdef(prefstr, NULL);
- if (done != BKE_BLENDFILE_READ_FAIL) {
- read_userdef_from_memory = false;
- printf("Read new prefs: %s\n", prefstr);
+
+ /* Load template preferences,
+ * unlike regular preferences we only use some of the settings,
+ * see: BKE_blender_userdef_set_app_template */
+ if (app_template_system[0] != '\0') {
+ char temp_path[FILE_MAX];
+ temp_path[0] = '\0';
+ if (!use_factory_settings) {
+ BLI_path_join(temp_path, sizeof(temp_path), app_template_config, BLENDER_USERPREF_FILE, NULL);
+ if (BLI_access(temp_path, R_OK) != 0) {
+ temp_path[0] = '\0';
+ }
+ }
+
+ if (temp_path[0] == '\0') {
+ BLI_path_join(temp_path, sizeof(temp_path), app_template_system, BLENDER_USERPREF_FILE, NULL);
+ }
+
+ if (use_userdef) {
+ UserDef *userdef_template = NULL;
+ /* just avoids missing file warning */
+ if (BLI_exists(temp_path)) {
+ userdef_template = BKE_blendfile_userdef_read(temp_path, NULL);
+ }
+ if (userdef_template == NULL) {
+ /* we need to have preferences load to overwrite preferences from previous template */
+ userdef_template = BKE_blendfile_userdef_read_from_memory(
+ datatoc_startup_blend, datatoc_startup_blend_size, NULL);
+ read_userdef_from_memory = true;
+ }
+ if (userdef_template) {
+ BKE_blender_userdef_set_app_template(userdef_template);
+ BKE_blender_userdef_free_data(userdef_template);
+ MEM_freeN(userdef_template);
+ }
}
}
-
+
+ if (app_template_override) {
+ BLI_strncpy(U.app_template, app_template_override, sizeof(U.app_template));
+ }
+
/* prevent buggy files that had G_FILE_RELATIVE_REMAP written out by mistake. Screws up autosaves otherwise
* can remove this eventually, only in a 2.53 and older, now its not written */
G.fileflags &= ~G_FILE_RELATIVE_REMAP;
- /* check userdef before open window, keymaps etc */
- wm_init_userdef(C, read_userdef_from_memory);
+ if (use_userdef) {
+ /* check userdef before open window, keymaps etc */
+ wm_init_userdef(C, read_userdef_from_memory);
+ }
/* match the read WM with current WM */
wm_window_match_do(C, &wmbase);
@@ -743,14 +851,19 @@ int wm_homefile_read(bContext *C, ReportList *reports, bool from_memory, const c
G.main->name[0] = '\0';
- /* When loading factory settings, the reset solid OpenGL lights need to be applied. */
- if (!G.background) GPU_default_lights();
-
- /* XXX */
- G.save_over = 0; // start with save preference untitled.blend
- G.fileflags &= ~G_FILE_AUTOPLAY; /* disable autoplay in startup.blend... */
+ if (use_userdef) {
+ /* When loading factory settings, the reset solid OpenGL lights need to be applied. */
+ if (!G.background) {
+ GPU_default_lights();
+ }
+ }
+
+ /* start with save preference untitled.blend */
+ G.save_over = 0;
+ /* disable auto-play in startup.blend... */
+ G.fileflags &= ~G_FILE_AUTOPLAY;
- wm_file_read_post(C, true);
+ wm_file_read_post(C, true, use_userdef);
return true;
}
@@ -998,7 +1111,7 @@ static int wm_file_write(bContext *C, const char *filepath, int fileflags, Repor
BKE_reportf(reports, RPT_ERROR, "Cannot save blend file, path '%s' is not writable", filepath);
return ret;
}
-
+
/* note: used to replace the file extension (to ensure '.blend'),
* no need to now because the operator ensures,
* its handy for scripts to save to a predefined name without blender editing it */
@@ -1264,6 +1377,13 @@ static int wm_homefile_write_exec(bContext *C, wmOperator *op)
char filepath[FILE_MAX];
int fileflags;
+ const char *app_template = U.app_template[0] ? U.app_template : NULL;
+ const char * const cfgdir = BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, app_template);
+ if (cfgdir == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Unable to create user config path");
+ return OPERATOR_CANCELLED;
+ }
+
BLI_callback_exec(G.main, NULL, BLI_CB_EVT_SAVE_PRE);
/* check current window and close it if temp */
@@ -1273,7 +1393,8 @@ static int wm_homefile_write_exec(bContext *C, wmOperator *op)
/* update keymaps in user preferences */
WM_keyconfig_update(wm);
- BLI_make_file_string("/", filepath, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), BLENDER_STARTUP_FILE);
+ BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_STARTUP_FILE, NULL);
+
printf("trying to save homefile at %s ", filepath);
ED_editors_flush_edits(C, false);
@@ -1351,21 +1472,44 @@ static int wm_userpref_write_exec(bContext *C, wmOperator *op)
{
wmWindowManager *wm = CTX_wm_manager(C);
char filepath[FILE_MAX];
+ const char *cfgdir;
+ bool ok = false;
/* update keymaps in user preferences */
WM_keyconfig_update(wm);
- BLI_make_file_string("/", filepath, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), BLENDER_USERPREF_FILE);
- printf("trying to save userpref at %s ", filepath);
-
- if (BKE_blendfile_write_userdef(filepath, op->reports) == 0) {
- printf("fail\n");
- return OPERATOR_CANCELLED;
+ if ((cfgdir = BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL))) {
+ BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_USERPREF_FILE, NULL);
+ printf("trying to save userpref at %s ", filepath);
+ if (BKE_blendfile_userdef_write(filepath, op->reports) != 0) {
+ printf("ok\n");
+ ok = true;
+ }
+ else {
+ printf("fail\n");
+ }
+ }
+ else {
+ BKE_report(op->reports, RPT_ERROR, "Unable to create userpref path");
}
- printf("ok\n");
+ if (U.app_template[0] && (cfgdir = BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, U.app_template))) {
+ /* Also save app-template prefs */
+ BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_USERPREF_FILE, NULL);
+ printf("trying to save app-template userpref at %s ", filepath);
+ if (BKE_blendfile_userdef_write(filepath, op->reports) == 0) {
+ printf("fail\n");
+ ok = true;
+ }
+ else {
+ printf("ok\n");
+ }
+ }
+ else if (U.app_template[0]) {
+ BKE_report(op->reports, RPT_ERROR, "Unable to create app-template userpref path");
+ }
- return OPERATOR_FINISHED;
+ return ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
void WM_OT_save_userpref(wmOperatorType *ot)
@@ -1400,11 +1544,12 @@ void WM_OT_read_history(wmOperatorType *ot)
static int wm_homefile_read_exec(bContext *C, wmOperator *op)
{
- const bool from_memory = (STREQ(op->type->idname, "WM_OT_read_factory_settings"));
+ const bool use_factory_settings = (STREQ(op->type->idname, "WM_OT_read_factory_settings"));
+ bool use_userdef = false;
char filepath_buf[FILE_MAX];
const char *filepath = NULL;
- if (!from_memory) {
+ if (!use_factory_settings) {
PropertyRNA *prop = RNA_struct_find_property(op->ptr, "filepath");
/* This can be used when loading of a start-up file should only change
@@ -1424,9 +1569,36 @@ static int wm_homefile_read_exec(bContext *C, wmOperator *op)
else {
/* always load UI for factory settings (prefs will re-init) */
G.fileflags &= ~G_FILE_NO_UI;
+ /* Always load preferences with factory settings. */
+ use_userdef = true;
+ }
+
+ char app_template_buf[sizeof(U.app_template)];
+ const char *app_template;
+ PropertyRNA *prop_app_template = RNA_struct_find_property(op->ptr, "app_template");
+ const bool use_splash = !use_factory_settings && RNA_boolean_get(op->ptr, "use_splash");
+ const bool use_empty_data = RNA_boolean_get(op->ptr, "use_empty");
+
+ if (prop_app_template && RNA_property_is_set(op->ptr, prop_app_template)) {
+ RNA_property_string_get(op->ptr, prop_app_template, app_template_buf);
+ app_template = app_template_buf;
+
+ /* Always load preferences when switching templates. */
+ use_userdef = true;
+ }
+ else {
+ app_template = NULL;
}
- return wm_homefile_read(C, op->reports, from_memory, filepath) ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+ if (wm_homefile_read(C, op->reports, use_factory_settings, use_empty_data, use_userdef, filepath, app_template)) {
+ if (use_splash) {
+ WM_init_splash(C);
+ }
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
}
void WM_OT_read_homefile(wmOperatorType *ot)
@@ -1449,17 +1621,36 @@ void WM_OT_read_homefile(wmOperatorType *ot)
"Load user interface setup from the .blend file");
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(ot->srna, "use_empty", false, "Empty", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
+ /* So the splash can be kept open after loading a file (for templates). */
+ prop = RNA_def_boolean(ot->srna, "use_splash", false, "Splash", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
+ prop = RNA_def_string(ot->srna, "app_template", "Template", sizeof(U.app_template), "", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
/* omit poll to run in background mode */
}
void WM_OT_read_factory_settings(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
ot->name = "Load Factory Settings";
ot->idname = "WM_OT_read_factory_settings";
ot->description = "Load default file and user preferences";
ot->invoke = WM_operator_confirm;
ot->exec = wm_homefile_read_exec;
+
+ prop = RNA_def_string(ot->srna, "app_template", "Template", sizeof(U.app_template), "", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
+ prop = RNA_def_boolean(ot->srna, "use_empty", false, "Empty", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
/* omit poll to run in background mode */
}
diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c
index 3b733f9558c..7e6c6160b84 100644
--- a/source/blender/windowmanager/intern/wm_files_link.c
+++ b/source/blender/windowmanager/intern/wm_files_link.c
@@ -282,7 +282,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
PropertyRNA *prop;
WMLinkAppendData *lapp_data;
- char path[FILE_MAX_LIBEXTRA], root[FILE_MAXDIR], libname[FILE_MAX], relname[FILE_MAX];
+ char path[FILE_MAX_LIBEXTRA], root[FILE_MAXDIR], libname[FILE_MAX_LIBEXTRA], relname[FILE_MAX];
char *group, *name;
int totfiles = 0;
short flag;
@@ -608,7 +608,8 @@ static void lib_relocate_do(
}
/* Note that in reload case, we also want to replace indirect usages. */
- const short remap_flags = ID_REMAP_SKIP_NEVER_NULL_USAGE | (do_reload ? 0 : ID_REMAP_SKIP_INDIRECT_USAGE);
+ 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;
diff --git a/source/blender/windowmanager/intern/wm_gesture.c b/source/blender/windowmanager/intern/wm_gesture.c
index 46203333eb5..cc48b162352 100644
--- a/source/blender/windowmanager/intern/wm_gesture.c
+++ b/source/blender/windowmanager/intern/wm_gesture.c
@@ -71,6 +71,7 @@ wmGesture *WM_gesture_new(bContext *C, const wmEvent *event, int type)
gesture->type = type;
gesture->event_type = event->type;
gesture->swinid = ar->swinid; /* means only in area-region context! */
+ gesture->userdata_free = true; /* Free if userdata is set. */
wm_subwindow_origin_get(window, gesture->swinid, &sx, &sy);
@@ -114,7 +115,7 @@ void WM_gesture_end(bContext *C, wmGesture *gesture)
win->tweak = NULL;
BLI_remlink(&win->gesture, gesture);
MEM_freeN(gesture->customdata);
- if (gesture->userdata) {
+ if (gesture->userdata && gesture->userdata_free) {
MEM_freeN(gesture->userdata);
}
MEM_freeN(gesture);
@@ -137,7 +138,7 @@ int wm_gesture_evaluate(wmGesture *gesture)
int dx = BLI_rcti_size_x(rect);
int dy = BLI_rcti_size_y(rect);
if (abs(dx) + abs(dy) > U.tweak_threshold) {
- int theta = iroundf(4.0f * atan2f((float)dy, (float)dx) / (float)M_PI);
+ int theta = round_fl_to_int(4.0f * atan2f((float)dy, (float)dx) / (float)M_PI);
int val = EVT_GESTURE_W;
if (theta == 0) val = EVT_GESTURE_E;
diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c
index c11c398c616..e73ec2b081a 100644
--- a/source/blender/windowmanager/intern/wm_init_exit.c
+++ b/source/blender/windowmanager/intern/wm_init_exit.c
@@ -181,18 +181,15 @@ void WM_init(bContext *C, int argc, const char **argv)
ED_file_init(); /* for fsmenu */
ED_node_init_butfuncs();
- BLF_init(11, U.dpi); /* Please update source/gamengine/GamePlayer/GPG_ghost.cpp if you change this */
+ BLF_init(); /* Please update source/gamengine/GamePlayer/GPG_ghost.cpp if you change this */
BLT_lang_init();
- /* Enforce loading the UI for the initial homefile */
- G.fileflags &= ~G_FILE_NO_UI;
-
/* reports cant be initialized before the wm,
* but keep before file reading, since that may report errors */
wm_init_reports(C);
/* get the default database, plus a wm */
- wm_homefile_read(C, NULL, G.factory_startup, NULL);
+ wm_homefile_read(C, NULL, G.factory_startup, false, true, NULL, NULL);
BLT_lang_set(NULL);
@@ -444,8 +441,6 @@ void WM_exit_ext(bContext *C, const bool do_python)
{
wmWindowManager *wm = C ? CTX_wm_manager(C) : NULL;
- BKE_sound_exit();
-
/* first wrap up running stuff, we assume only the active WM is running */
/* modal handlers are on window level freed, others too? */
/* note; same code copied in wm_files.c */
@@ -574,7 +569,7 @@ void WM_exit_ext(bContext *C, const bool do_python)
ED_file_exit(); /* for fsmenu */
UI_exit();
- BKE_blender_userdef_free();
+ BKE_blender_userdef_free_data(&U);
RNA_exit(); /* should be after BPY_python_end so struct python slots are cleared */
@@ -591,6 +586,10 @@ void WM_exit_ext(bContext *C, const bool do_python)
BLI_threadapi_exit();
+ /* No need to call this early, rather do it late so that other pieces of Blender using sound may exit cleanly,
+ * see also T50676. */
+ BKE_sound_exit();
+
BKE_blender_atexit();
if (MEM_get_memory_blocks_in_use() != 0) {
diff --git a/source/blender/windowmanager/intern/wm_keymap.c b/source/blender/windowmanager/intern/wm_keymap.c
index e201fa433d4..db5fc23146f 100644
--- a/source/blender/windowmanager/intern/wm_keymap.c
+++ b/source/blender/windowmanager/intern/wm_keymap.c
@@ -121,6 +121,13 @@ static void wm_keymap_item_properties_update_ot(wmKeyMapItem *kmi)
if (ot->srna != kmi->ptr->type) {
/* matches wm_keymap_item_properties_set but doesnt alloc new ptr */
WM_operator_properties_create_ptr(kmi->ptr, ot);
+ /* 'kmi->ptr->data' NULL'd above, keep using existing properties.
+ * Note: the operators property types may have changed,
+ * we will need a more comprehensive sanitize function to support this properly.
+ */
+ if (kmi->properties) {
+ kmi->ptr->data = kmi->properties;
+ }
WM_operator_properties_sanitize(kmi->ptr, 1);
}
}
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index b9fd4d2e762..ae5a8319b00 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -177,7 +177,7 @@ void WM_operatortype_append(void (*opfunc)(wmOperatorType *))
/* XXX All ops should have a description but for now allow them not to. */
RNA_def_struct_ui_text(ot->srna, ot->name, ot->description ? ot->description : UNDOCUMENTED_OPERATOR_TIP);
- RNA_def_struct_identifier(ot->srna, ot->idname);
+ RNA_def_struct_identifier(&BLENDER_RNA, ot->srna, ot->idname);
BLI_ghash_insert(global_ops_hash, (void *)ot->idname, ot);
}
@@ -193,7 +193,7 @@ void WM_operatortype_append_ptr(void (*opfunc)(wmOperatorType *, void *), void *
ot->translation_context = BLT_I18NCONTEXT_OPERATOR_DEFAULT;
opfunc(ot, userdata);
RNA_def_struct_ui_text(ot->srna, ot->name, ot->description ? ot->description : UNDOCUMENTED_OPERATOR_TIP);
- RNA_def_struct_identifier(ot->srna, ot->idname);
+ RNA_def_struct_identifier(&BLENDER_RNA, ot->srna, ot->idname);
BLI_ghash_insert(global_ops_hash, (void *)ot->idname, ot);
}
@@ -398,7 +398,7 @@ wmOperatorType *WM_operatortype_append_macro(const char *idname, const char *nam
ot->description = UNDOCUMENTED_OPERATOR_TIP;
RNA_def_struct_ui_text(ot->srna, ot->name, ot->description);
- RNA_def_struct_identifier(ot->srna, ot->idname);
+ RNA_def_struct_identifier(&BLENDER_RNA, ot->srna, ot->idname);
/* Use i18n context from ext.srna if possible (py operators). */
i18n_context = ot->ext.srna ? RNA_struct_translation_context(ot->ext.srna) : BLT_I18NCONTEXT_OPERATOR_DEFAULT;
RNA_def_struct_translation_context(ot->srna, i18n_context);
@@ -432,7 +432,7 @@ void WM_operatortype_append_macro_ptr(void (*opfunc)(wmOperatorType *, void *),
opfunc(ot, userdata);
RNA_def_struct_ui_text(ot->srna, ot->name, ot->description);
- RNA_def_struct_identifier(ot->srna, ot->idname);
+ RNA_def_struct_identifier(&BLENDER_RNA, ot->srna, ot->idname);
BLI_ghash_insert(global_ops_hash, (void *)ot->idname, ot);
}
@@ -573,6 +573,46 @@ 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)
+{
+ const char *ch = idname;
+ int dot = 0;
+ int i;
+ for (i = 0; *ch; i++, ch++) {
+ if ((*ch >= 'a' && *ch <= 'z') || (*ch >= '0' && *ch <= '9') || *ch == '_') {
+ /* pass */
+ }
+ else if (*ch == '.') {
+ dot++;
+ }
+ else {
+ BKE_reportf(reports, RPT_ERROR,
+ "Registering operator class: '%s', invalid bl_idname '%s', at position %d",
+ classname, idname, i);
+ return false;
+ }
+ }
+
+ if (i > (MAX_NAME - 3)) {
+ BKE_reportf(reports, RPT_ERROR, "Registering operator class: '%s', invalid bl_idname '%s', "
+ "is too long, maximum length is %d", classname, idname,
+ MAX_NAME - 3);
+ return false;
+ }
+
+ if (dot != 1) {
+ BKE_reportf(reports, RPT_ERROR,
+ "Registering operator class: '%s', invalid bl_idname '%s', must contain 1 '.' character",
+ classname, idname);
+ return false;
+ }
+ 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:
@@ -806,9 +846,19 @@ static char *wm_prop_pystring_from_context(bContext *C, PointerRNA *ptr, Propert
} \
} (void)0
+#define CTX_TEST_SPACE_TYPE(space_data_type, member_full, dataptr_cmp) \
+ { \
+ const char *ctx_member_full = member_full; \
+ if (space_data->spacetype == space_data_type && ptr->data == dataptr_cmp) { \
+ member_id = ctx_member_full; \
+ break; \
+ } \
+ } (void)0
+
switch (GS(((ID *)ptr->id.data)->name)) {
case ID_SCE:
{
+ CTX_TEST_PTR_DATA_TYPE(C, "active_gpencil_brush", RNA_GPencilBrush, ptr, CTX_data_active_gpencil_brush(C));
CTX_TEST_PTR_ID(C, "scene", ptr->id.data);
break;
}
@@ -843,12 +893,22 @@ static char *wm_prop_pystring_from_context(bContext *C, PointerRNA *ptr, Propert
{
CTX_TEST_PTR_ID(C, "screen", ptr->id.data);
- CTX_TEST_PTR_DATA_TYPE(C, "space_data", RNA_Space, ptr, CTX_wm_space_data(C));
+ SpaceLink *space_data = CTX_wm_space_data(C);
+
+ CTX_TEST_PTR_DATA_TYPE(C, "space_data", RNA_Space, ptr, space_data);
CTX_TEST_PTR_DATA_TYPE(C, "area", RNA_Area, ptr, CTX_wm_area(C));
CTX_TEST_PTR_DATA_TYPE(C, "region", RNA_Region, ptr, CTX_wm_region(C));
+ CTX_TEST_SPACE_TYPE(SPACE_IMAGE, "space_data.uv_editor", space_data);
+ CTX_TEST_SPACE_TYPE(SPACE_VIEW3D, "space_data.fx_settings", &(CTX_wm_view3d(C)->fx_settings));
+ CTX_TEST_SPACE_TYPE(SPACE_NLA, "space_data.dopesheet", CTX_wm_space_nla(C)->ads);
+ CTX_TEST_SPACE_TYPE(SPACE_IPO, "space_data.dopesheet", CTX_wm_space_graph(C)->ads);
+ CTX_TEST_SPACE_TYPE(SPACE_ACTION, "space_data.dopesheet", &(CTX_wm_space_action(C)->ads));
+ CTX_TEST_SPACE_TYPE(SPACE_FILE, "space_data.params", CTX_wm_space_file(C)->params);
break;
}
+ default:
+ break;
}
if (member_id) {
@@ -860,6 +920,7 @@ static char *wm_prop_pystring_from_context(bContext *C, PointerRNA *ptr, Propert
}
#undef CTX_TEST_PTR_ID
#undef CTX_TEST_PTR_ID_CAST
+#undef CTX_TEST_SPACE_TYPE
}
return ret;
@@ -900,7 +961,7 @@ void WM_operator_properties_create_ptr(PointerRNA *ptr, wmOperatorType *ot)
void WM_operator_properties_create(PointerRNA *ptr, const char *opstring)
{
- wmOperatorType *ot = WM_operatortype_find(opstring, 0);
+ wmOperatorType *ot = WM_operatortype_find(opstring, false);
if (ot)
WM_operator_properties_create_ptr(ptr, ot);
@@ -1118,6 +1179,7 @@ static uiBlock *wm_enum_search_menu(bContext *C, ARegion *ar, void *arg_op)
block = UI_block_begin(C, ar, "_popup", UI_EMBOSS);
UI_block_flag_enable(block, UI_BLOCK_LOOP | UI_BLOCK_MOVEMOUSE_QUIT | UI_BLOCK_SEARCH_MENU);
+ search[0] = '\0';
#if 0 /* ok, this isn't so easy... */
uiDefBut(block, UI_BTYPE_LABEL, 0, RNA_struct_ui_name(op->type->srna), 10, 10, UI_searchbox_size_x(), UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
#endif
@@ -1402,20 +1464,6 @@ static void dialog_exec_cb(bContext *C, void *arg1, void *arg2)
}
}
-static void popup_check_cb(bContext *C, void *op_ptr, void *UNUSED(arg))
-{
- wmOperator *op = op_ptr;
- if (op->type->check) {
- if (op->type->check(C, op)) {
- /* check for popup and re-layout buttons */
- ARegion *ar_menu = CTX_wm_menu(C);
- if (ar_menu) {
- ED_region_tag_refresh_ui(ar_menu);
- }
- }
- }
-}
-
/* Dialogs are popups that require user verification (click OK) before exec */
static uiBlock *wm_block_dialog_create(bContext *C, ARegion *ar, void *userData)
{
@@ -1434,8 +1482,6 @@ static uiBlock *wm_block_dialog_create(bContext *C, ARegion *ar, void *userData)
layout = UI_block_layout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, data->width, data->height, 0, style);
- UI_block_func_set(block, popup_check_cb, op, NULL);
-
uiLayoutOperatorButs(C, layout, op, NULL, 'H', UI_LAYOUT_OP_SHOW_TITLE);
/* clear so the OK button is left alone */
@@ -1474,8 +1520,6 @@ static uiBlock *wm_operator_ui_create(bContext *C, ARegion *ar, void *userData)
layout = UI_block_layout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, data->width, data->height, 0, style);
- UI_block_func_set(block, popup_check_cb, op, NULL);
-
/* since ui is defined the auto-layout args are not used */
uiLayoutOperatorButs(C, layout, op, NULL, 'V', 0);
@@ -1522,7 +1566,7 @@ int WM_operator_ui_popup(bContext *C, wmOperator *op, int width, int height)
data->width = width;
data->height = height;
data->free_op = true; /* if this runs and gets registered we may want not to free it */
- UI_popup_block_ex(C, wm_operator_ui_create, NULL, wm_operator_ui_popup_cancel, data);
+ UI_popup_block_ex(C, wm_operator_ui_create, NULL, wm_operator_ui_popup_cancel, data, op);
return OPERATOR_RUNNING_MODAL;
}
@@ -1552,7 +1596,7 @@ static int wm_operator_props_popup_ex(bContext *C, wmOperator *op,
if (!do_redo || !(U.uiflag & USER_GLOBALUNDO))
return WM_operator_props_dialog_popup(C, op, 15 * UI_UNIT_X, UI_UNIT_Y);
- UI_popup_block_ex(C, wm_block_create_redo, NULL, wm_block_redo_cancel_cb, op);
+ UI_popup_block_ex(C, wm_block_create_redo, NULL, wm_block_redo_cancel_cb, op, op);
if (do_call)
wm_block_redo_cb(C, op, 0);
@@ -1594,7 +1638,7 @@ int WM_operator_props_dialog_popup(bContext *C, wmOperator *op, int width, int h
data->free_op = true; /* if this runs and gets registered we may want not to free it */
/* op is not executed until popup OK but is clicked */
- UI_popup_block_ex(C, wm_block_dialog_create, wm_operator_ui_popup_ok, wm_operator_ui_popup_cancel, data);
+ UI_popup_block_ex(C, wm_block_dialog_create, wm_operator_ui_popup_ok, wm_operator_ui_popup_cancel, data, op);
return OPERATOR_RUNNING_MODAL;
}
@@ -1761,6 +1805,36 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar
ibuf = IMB_ibImageFromMemory((unsigned char *)datatoc_splash_png,
datatoc_splash_png_size, IB_rect, NULL, "<splash screen>");
}
+
+ /* overwrite splash with template image */
+ if (U.app_template[0] != '\0') {
+ ImBuf *ibuf_template = NULL;
+ char splash_filepath[FILE_MAX];
+ char template_directory[FILE_MAX];
+
+ if (BKE_appdir_app_template_id_search(
+ U.app_template,
+ template_directory, sizeof(template_directory)))
+ {
+ BLI_join_dirfile(
+ splash_filepath, sizeof(splash_filepath), template_directory,
+ (U.pixelsize == 2) ? "splash_2x.png" : "splash.png");
+ ibuf_template = IMB_loadiffname(splash_filepath, IB_rect, NULL);
+ if (ibuf_template) {
+ const int x_expect = ibuf->x;
+ const int y_expect = 230 * (int)U.pixelsize;
+ /* don't cover the header text */
+ if (ibuf_template->x == x_expect && ibuf_template->y == y_expect) {
+ memcpy(ibuf->rect, ibuf_template->rect, ibuf_template->x * ibuf_template->y * sizeof(char[4]));
+ }
+ else {
+ printf("Splash expected %dx%d found %dx%d, ignoring: %s\n",
+ x_expect, y_expect, ibuf_template->x, ibuf_template->y, splash_filepath);
+ }
+ IMB_freeImBuf(ibuf_template);
+ }
+ }
+ }
#endif
block = UI_block_begin(C, ar, "_popup", UI_EMBOSS);
@@ -1786,13 +1860,13 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar
if (version_suffix != NULL && version_suffix[0]) {
/* placed after the version number in the image,
* placing y is tricky to match baseline */
- int x = 260 - (2 * UI_DPI_WINDOW_FAC);
- int y = 242 + (4 * UI_DPI_WINDOW_FAC);
- int w = 240;
+ int x = 260 * U.pixelsize - (2 * UI_DPI_FAC);
+ int y = 242 * U.pixelsize + (4 * UI_DPI_FAC);
+ int w = 240 * U.pixelsize;
/* hack to have text draw 'text_sel' */
UI_block_emboss_set(block, UI_EMBOSS_NONE);
- but = uiDefBut(block, UI_BTYPE_LABEL, 0, version_suffix, x * U.pixelsize, y * U.pixelsize, w * U.pixelsize, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL);
+ but = uiDefBut(block, UI_BTYPE_LABEL, 0, version_suffix, x, y, w, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL);
/* XXX, set internal flag - UI_SELECT */
UI_but_flag_enable(but, 1);
UI_block_emboss_set(block, UI_EMBOSS);
@@ -1846,7 +1920,7 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar
BLENDER_VERSION / 100, BLENDER_VERSION % 100);
uiItemStringO(col, IFACE_("Release Log"), ICON_URL, "WM_OT_url_open", "url", url);
uiItemStringO(col, IFACE_("Manual"), ICON_URL, "WM_OT_url_open", "url",
- "http://www.blender.org/manual");
+ "https://docs.blender.org/manual/en/dev/");
uiItemStringO(col, IFACE_("Blender Website"), ICON_URL, "WM_OT_url_open", "url", "http://www.blender.org");
if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "release")) {
BLI_snprintf(url, sizeof(url), "http://www.blender.org/documentation/blender_python_api_%d_%d"
@@ -2521,7 +2595,7 @@ static void tweak_gesture_modal(bContext *C, const wmEvent *event)
}
/* standard tweak, called after window handlers passed on event */
-void wm_tweakevent_test(bContext *C, wmEvent *event, int action)
+void wm_tweakevent_test(bContext *C, const wmEvent *event, int action)
{
wmWindow *win = CTX_wm_window(C);
@@ -3910,8 +3984,12 @@ static void previews_id_ensure(bContext *C, Scene *scene, ID *id)
}
}
-static int previews_id_ensure_callback(void *userdata, ID *UNUSED(self_id), ID **idptr, int UNUSED(cd_flag))
+static int previews_id_ensure_callback(void *userdata, ID *UNUSED(self_id), ID **idptr, int cb_flag)
{
+ if (cb_flag & IDWALK_CB_PRIVATE) {
+ return IDWALK_RET_NOP;
+ }
+
PreviewsIDEnsureData *data = userdata;
ID *id = *idptr;
@@ -3944,7 +4022,7 @@ static int previews_ensure_exec(bContext *C, wmOperator *UNUSED(op))
preview_id_data.scene = scene;
id = (ID *)scene;
- BKE_library_foreach_ID_link(id, previews_id_ensure_callback, &preview_id_data, IDWALK_RECURSE);
+ BKE_library_foreach_ID_link(NULL, id, previews_id_ensure_callback, &preview_id_data, IDWALK_RECURSE);
}
/* Check a last time for ID not used (fake users only, in theory), and
@@ -4558,4 +4636,3 @@ EnumPropertyItem *RNA_mask_local_itemf(bContext *C, PointerRNA *ptr, PropertyRNA
{
return rna_id_itemf(C, ptr, r_free, C ? (ID *)CTX_data_main(C)->mask.first : NULL, true);
}
-
diff --git a/source/blender/windowmanager/intern/wm_playanim.c b/source/blender/windowmanager/intern/wm_playanim.c
index 6bf7bcc2934..77378cf8e0c 100644
--- a/source/blender/windowmanager/intern/wm_playanim.c
+++ b/source/blender/windowmanager/intern/wm_playanim.c
@@ -1256,7 +1256,7 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
//GHOST_ActivateWindowDrawingContext(g_WS.ghost_window);
/* initialize the font */
- BLF_init(11, 72);
+ BLF_init();
ps.fontid = BLF_load_mem("monospace", (unsigned char *)datatoc_bmonofont_ttf, datatoc_bmonofont_ttf_size);
BLF_size(ps.fontid, 11, 72);
@@ -1428,8 +1428,7 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
ps.next_frame = ps.direction;
-
- while ((hasevent = GHOST_ProcessEvents(g_WS.ghost_system, 0)) || ps.wait2) {
+ while ((hasevent = GHOST_ProcessEvents(g_WS.ghost_system, ps.wait2))) {
if (hasevent) {
GHOST_DispatchEvents(g_WS.ghost_system);
}
diff --git a/source/blender/windowmanager/intern/wm_stereo.c b/source/blender/windowmanager/intern/wm_stereo.c
index 1c1c2ad35af..66ebf18c9e1 100644
--- a/source/blender/windowmanager/intern/wm_stereo.c
+++ b/source/blender/windowmanager/intern/wm_stereo.c
@@ -77,7 +77,7 @@ static void wm_method_draw_stereo3d_pageflip(wmWindow *win)
else //STEREO_RIGHT_ID
glDrawBuffer(GL_BACK_RIGHT);
- wm_triple_draw_textures(win, drawdata->triple, 1.0f);
+ wm_triple_draw_textures(win, drawdata->triple, 1.0f, false);
}
glDrawBuffer(GL_BACK);
@@ -120,7 +120,7 @@ static void wm_method_draw_stereo3d_interlace(wmWindow *win)
break;
}
- wm_triple_draw_textures(win, drawdata->triple, 1.0f);
+ wm_triple_draw_textures(win, drawdata->triple, 1.0f, true);
GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
}
interlace_prev_type = interlace_type;
@@ -157,7 +157,7 @@ static void wm_method_draw_stereo3d_anaglyph(wmWindow *win)
break;
}
- wm_triple_draw_textures(win, drawdata->triple, 1.0f);
+ wm_triple_draw_textures(win, drawdata->triple, 1.0f, false);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
}
@@ -345,6 +345,32 @@ bool WM_stereo3d_enabled(wmWindow *win, bool skip_stereo3d_check)
return true;
}
+/**
+ * If needed, this adjusts \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)
+{
+ if (!WM_stereo3d_enabled(win, false))
+ return;
+
+ if (win->stereo3d_format->display_mode == S3D_DISPLAY_SIDEBYSIDE) {
+ const int half_x = win->sizex / 2;
+ /* right half of the screen */
+ if (r_mouse_xy[0] > half_x) {
+ r_mouse_xy[0] -= half_x;
+ }
+ r_mouse_xy[0] *= 2;
+ }
+ else if (win->stereo3d_format->display_mode == S3D_DISPLAY_TOPBOTTOM) {
+ const int half_y = win->sizey / 2;
+ /* upper half of the screen */
+ if (r_mouse_xy[1] > half_y) {
+ r_mouse_xy[1] -= half_y;
+ }
+ r_mouse_xy[1] *= 2;
+ }
+}
+
/************************** Stereo 3D operator **********************************/
typedef struct Stereo3dData {
Stereo3dFormat stereo3d_format;
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c
index 2d43c47679d..79078b321da 100644
--- a/source/blender/windowmanager/intern/wm_window.c
+++ b/source/blender/windowmanager/intern/wm_window.c
@@ -77,6 +77,7 @@
#include "GPU_extensions.h"
#include "GPU_init_exit.h"
#include "GPU_glew.h"
+#include "BLF_api.h"
/* for assert */
#ifndef NDEBUG
@@ -311,7 +312,7 @@ void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win)
if (tmpwin == NULL)
do_exit = 1;
- if ((U.uiflag & USER_QUIT_PROMPT) && !wm->file_saved) {
+ if ((U.uiflag & USER_QUIT_PROMPT) && !wm->file_saved && !G.background) {
if (do_exit) {
if (!GHOST_confirmQuit(win->ghostwin))
return;
@@ -374,14 +375,49 @@ void wm_window_title(wmWindowManager *wm, wmWindow *win)
}
}
-static float wm_window_get_virtual_pixelsize(void)
+void WM_window_set_dpi(wmWindow *win)
{
- return ((U.virtual_pixel == VIRTUAL_PIXEL_NATIVE) ? 1.0f : 2.0f);
-}
+ float auto_dpi = GHOST_GetDPIHint(win->ghostwin);
-float wm_window_pixelsize(wmWindow *win)
-{
- return (GHOST_GetNativePixelSize(win->ghostwin) * wm_window_get_virtual_pixelsize());
+ /* Clamp auto DPI to 96, since our font/interface drawing does not work well
+ * with lower sizes. The main case we are interested in supporting is higher
+ * DPI. If a smaller UI is desired it is still possible to adjust UI scale. */
+ auto_dpi = max_ff(auto_dpi, 96.0f);
+
+ /* Lazily init UI scale size, preserving backwards compatibility by
+ * computing UI scale from ratio of previous DPI and auto DPI */
+ if (U.ui_scale == 0) {
+ int virtual_pixel = (U.virtual_pixel == VIRTUAL_PIXEL_NATIVE) ? 1 : 2;
+
+ if (U.dpi == 0) {
+ U.ui_scale = virtual_pixel;
+ }
+ else {
+ U.ui_scale = (virtual_pixel * U.dpi * 96.0f) / (auto_dpi * 72.0f);
+ }
+
+ CLAMP(U.ui_scale, 0.25f, 4.0f);
+ }
+
+ /* Blender's UI drawing assumes DPI 72 as a good default following macOS
+ * while Windows and Linux use DPI 96. GHOST assumes a default 96 so we
+ * remap the DPI to Blender's convention. */
+ auto_dpi *= GHOST_GetNativePixelSize(win->ghostwin);
+ int dpi = auto_dpi * U.ui_scale * (72.0 / 96.0f);
+
+ /* Automatically set larger pixel size for high DPI. */
+ int pixelsize = max_ii(1, (int)(dpi / 64));
+ /* User adjustment for pixel size. */
+ pixelsize = max_ii(1, pixelsize + U.ui_line_width);
+
+ /* Set user preferences globals for drawing, and for forward compatibility. */
+ U.pixelsize = pixelsize;
+ U.dpi = dpi / pixelsize;
+ U.virtual_pixel = (pixelsize == 1) ? VIRTUAL_PIXEL_NATIVE : VIRTUAL_PIXEL_DOUBLE;
+ U.widget_unit = (U.pixelsize * U.dpi * 20 + 36) / 72;
+
+ /* update font drawing */
+ BLF_default_dpi(U.pixelsize * U.dpi);
}
/* belongs to below */
@@ -441,8 +477,12 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm, const char *title, wm
/* store actual window size in blender window */
bounds = GHOST_GetClientBounds(win->ghostwin);
- win->sizex = GHOST_GetWidthRectangle(bounds);
- win->sizey = GHOST_GetHeightRectangle(bounds);
+
+ /* win32: gives undefined window size when minimized */
+ if (GHOST_GetWindowState(win->ghostwin) != GHOST_kWindowStateMinimized) {
+ win->sizex = GHOST_GetWidthRectangle(bounds);
+ win->sizey = GHOST_GetHeightRectangle(bounds);
+ }
GHOST_DisposeRectangle(bounds);
#ifndef __APPLE__
@@ -456,10 +496,8 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm, const char *title, wm
glClear(GL_COLOR_BUFFER_BIT);
}
- /* displays with larger native pixels, like Macbook. Used to scale dpi with */
/* needed here, because it's used before it reads userdef */
- U.pixelsize = wm_window_pixelsize(win);
- BKE_blender_userdef_refresh();
+ WM_window_set_dpi(win);
wm_window_swap_buffers(win);
@@ -618,15 +656,27 @@ wmWindow *WM_window_open(bContext *C, const rcti *rect)
* \param type: WM_WINDOW_RENDER, WM_WINDOW_USERPREFS...
* \return the window or NULL.
*/
-wmWindow *WM_window_open_temp(bContext *C, const rcti *rect_init, int type)
+wmWindow *WM_window_open_temp(bContext *C, int x, int y, int sizex, int sizey, int type)
{
wmWindow *win_prev = CTX_wm_window(C);
wmWindow *win;
ScrArea *sa;
Scene *scene = CTX_data_scene(C);
const char *title;
- rcti rect = *rect_init;
- const short px_virtual = (short)wm_window_get_virtual_pixelsize();
+
+ /* convert to native OS window coordinates */
+ const float native_pixel_size = GHOST_GetNativePixelSize(win_prev->ghostwin);
+ x /= native_pixel_size;
+ y /= native_pixel_size;
+ sizex /= native_pixel_size;
+ sizey /= native_pixel_size;
+
+ /* calculate postition */
+ rcti rect;
+ rect.xmin = x + win_prev->posx - sizex / 2;
+ rect.ymin = y + win_prev->posy - sizey / 2;
+ rect.xmax = rect.xmin + sizex;
+ rect.ymax = rect.ymin + sizey;
/* changes rect to fit within desktop */
wm_window_check_position(&rect);
@@ -644,9 +694,8 @@ wmWindow *WM_window_open_temp(bContext *C, const rcti *rect_init, int type)
win->posy = rect.ymin;
}
- /* multiply with virtual pixelsize, ghost handles native one (e.g. for retina) */
- win->sizex = BLI_rcti_size_x(&rect) * px_virtual;
- win->sizey = BLI_rcti_size_y(&rect) * px_virtual;
+ win->sizex = BLI_rcti_size_x(&rect);
+ win->sizey = BLI_rcti_size_y(&rect);
if (win->ghostwin) {
wm_window_set_size(win, win->sizex, win->sizey);
@@ -835,8 +884,7 @@ void wm_window_make_drawable(wmWindowManager *wm, wmWindow *win)
GHOST_ActivateWindowDrawingContext(win->ghostwin);
/* this can change per window */
- U.pixelsize = wm_window_pixelsize(win);
- BKE_blender_userdef_refresh();
+ WM_window_set_dpi(win);
}
}
@@ -1035,6 +1083,8 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
if (type == GHOST_kEventWindowSize) {
WM_jobs_stop(wm, win->screen, NULL);
}
+
+ WM_window_set_dpi(win);
/* win32: gives undefined window size when minimized */
if (state != GHOST_kWindowStateMinimized) {
@@ -1118,7 +1168,18 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
}
break;
}
-
+
+ case GHOST_kEventWindowDPIHintChanged:
+ {
+ WM_window_set_dpi(win);
+ /* font's are stored at each DPI level, without this we can easy load 100's of fonts */
+ BLF_cache_clear();
+
+ WM_main_add_notifier(NC_WINDOW, NULL); /* full redraw */
+ WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL); /* refresh region sizes */
+ break;
+ }
+
case GHOST_kEventOpenMainFile:
{
PointerRNA props_ptr;
@@ -1199,11 +1260,9 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
{
// only update if the actual pixel size changes
float prev_pixelsize = U.pixelsize;
- U.pixelsize = wm_window_pixelsize(win);
+ WM_window_set_dpi(win);
if (U.pixelsize != prev_pixelsize) {
- BKE_blender_userdef_refresh();
-
// close all popups since they are positioned with the pixel
// size baked in and it's difficult to correct them
wmWindow *oldWindow = CTX_wm_window(C);