diff options
author | Julian Eisel <eiseljulian@gmail.com> | 2017-04-04 22:39:57 +0300 |
---|---|---|
committer | Julian Eisel <eiseljulian@gmail.com> | 2017-04-04 22:39:57 +0300 |
commit | 7576ad3d043ac5d15e0c5a68e65339904441b5e7 (patch) | |
tree | bb990cce1eec04d45ab57e8a42af2669f9d7522f /source/blender/windowmanager/intern | |
parent | 10b24eabbab0193f6944cdf3bec7b386c75d5445 (diff) | |
parent | db0f67f46454fd0bfeb886d3e61227b65fbc6ac1 (diff) |
Merge branch 'blender2.8' into transform-manipulatorstransform-manipulators
Conflicts:
intern/gawain/gawain/immediate.h
intern/gawain/src/immediate.c
source/blender/editors/physics/physics_ops.c
source/blender/editors/screen/glutil.c
source/blender/editors/space_view3d/space_view3d.c
source/blender/editors/space_view3d/view3d_draw.c
source/blender/editors/space_view3d/view3d_edit.c
source/blender/editors/space_view3d/view3d_ops.c
source/blender/editors/transform/transform_manipulator.c
Diffstat (limited to 'source/blender/windowmanager/intern')
-rw-r--r-- | source/blender/windowmanager/intern/wm.c | 34 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_dragdrop.c | 8 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_draw.c | 2 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_event_system.c | 20 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_files.c | 330 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_gesture.c | 328 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_init_exit.c | 10 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_keymap.c | 11 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_operators.c | 162 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_playanim.c | 23 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_stereo.c | 28 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_subwindow.c | 29 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_window.c | 169 |
13 files changed, 836 insertions, 318 deletions
diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c index b76a1f1d422..4351cd22b18 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); diff --git a/source/blender/windowmanager/intern/wm_dragdrop.c b/source/blender/windowmanager/intern/wm_dragdrop.c index 2d1dcd7f3c9..0402a528e8d 100644 --- a/source/blender/windowmanager/intern/wm_dragdrop.c +++ b/source/blender/windowmanager/intern/wm_dragdrop.c @@ -46,6 +46,8 @@ #include "BKE_context.h" +#include "GPU_shader.h" + #include "IMB_imbuf_types.h" #include "UI_interface.h" @@ -332,8 +334,10 @@ void wm_drags_draw(bContext *C, wmWindow *win, rcti *rect) if (rect) drag_rect_minmax(rect, x, y, x + drag->sx, y + drag->sy); else { - glColor4f(1.0, 1.0, 1.0, 0.65); /* this blends texture */ - glaDrawPixelsTexScaled(x, y, drag->imb->x, drag->imb->y, GL_RGBA, GL_UNSIGNED_BYTE, GL_NEAREST, drag->imb->rect, drag->scale, drag->scale); + float col[4] = {1.0f, 1.0f, 1.0f, 0.65f}; /* this blends texture */ + immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR); + immDrawPixelsTexScaled(x, y, drag->imb->x, drag->imb->y, GL_RGBA, GL_UNSIGNED_BYTE, GL_NEAREST, + drag->imb->rect, drag->scale, drag->scale, 1.0f, 1.0f, col); } } else { diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c index 809a5cac6e8..daba01cb3a6 100644 --- a/source/blender/windowmanager/intern/wm_draw.c +++ b/source/blender/windowmanager/intern/wm_draw.c @@ -57,8 +57,6 @@ #include "GPU_draw.h" #include "GPU_extensions.h" -#include "GPU_glew.h" -#include "GPU_basic_shader.h" #include "GPU_immediate.h" #include "RE_engine.h" diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index d9d8fbc6cfa..2e04f4ea929 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -713,7 +713,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) @@ -876,6 +878,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) { @@ -3275,6 +3291,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..1095195acd5 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 use_factory_settings) { Main *bmain = CTX_data_main(C); @@ -336,7 +336,7 @@ 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 (use_factory_settings) { BLO_update_defaults_userpref_blend(); } @@ -470,6 +470,10 @@ 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)) { + /* 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()"); @@ -554,7 +558,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; @@ -629,22 +633,34 @@ 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 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, + 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. @@ -652,9 +668,10 @@ int wm_homefile_read(bContext *C, ReportList *reports, bool from_memory, const c * And in this case versioning code is to be run. */ bool read_userdef_from_memory = true; + eBLOReadSkip skip_flags = 0; /* 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,71 +682,146 @@ 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); - } - else { - prefstr[0] = '\0'; - } + /* 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); + BLI_path_join(filepath_userdef, sizeof(filepath_startup), cfgdir, BLENDER_USERPREF_FILE, NULL); } - 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); + 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_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); + + read_userdef_from_memory = false; + skip_flags |= BLO_READ_SKIP_USERDEF; + printf("Read prefs: %s\n", filepath_userdef); + } + } + + const char *app_template = NULL; + + if (filepath_startup_override != NULL) { + /* pass */ + } + else if (app_template_override) { + app_template = app_template_override; + } + else if (!use_factory_settings && U.app_template[0]) { + app_template = U.app_template; + } + + if (app_template != NULL) { + BKE_appdir_app_template_id_search(app_template, app_template_system, sizeof(app_template_system)); + BLI_path_join(app_template_config, sizeof(app_template_config), cfgdir, app_template, NULL); + } + + /* insert template name into startup file */ + if (app_template != NULL) { + /* 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(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 (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); + } + + 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); + } + 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; @@ -744,11 +836,14 @@ 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 (!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); @@ -879,7 +974,7 @@ static void wm_history_file_update(void) /* screen can be NULL */ -static ImBuf *blend_file_thumb(Scene *scene, bScreen *screen, BlendThumbnail **thumb_pt) +static ImBuf *blend_file_thumb(Scene *scene, SceneLayer *sl, bScreen *screen, BlendThumbnail **thumb_pt) { /* will be scaled down, but gives some nice oversampling */ ImBuf *ibuf; @@ -916,14 +1011,14 @@ static ImBuf *blend_file_thumb(Scene *scene, bScreen *screen, BlendThumbnail **t /* gets scaled to BLEN_THUMB_SIZE */ if (scene->camera) { ibuf = ED_view3d_draw_offscreen_imbuf_simple( - scene, scene->camera, + scene, sl, scene->camera, BLEN_THUMB_SIZE * 2, BLEN_THUMB_SIZE * 2, IB_rect, OB_SOLID, false, false, false, R_ALPHAPREMUL, 0, false, NULL, NULL, NULL, err_out); } else { ibuf = ED_view3d_draw_offscreen_imbuf( - scene, v3d, ar, + scene, sl, v3d, ar, BLEN_THUMB_SIZE * 2, BLEN_THUMB_SIZE * 2, IB_rect, false, R_ALPHAPREMUL, 0, false, NULL, NULL, NULL, err_out); @@ -1019,7 +1114,7 @@ static int wm_file_write(bContext *C, const char *filepath, int fileflags, Repor /* Main now can store a .blend thumbnail, usefull for background mode or thumbnail customization. */ main_thumb = thumb = CTX_data_main(C)->blen_thumb; if ((U.flag & USER_SAVE_PREVIEWS) && BLI_thread_is_main()) { - ibuf_thumb = blend_file_thumb(CTX_data_scene(C), CTX_wm_screen(C), &thumb); + ibuf_thumb = blend_file_thumb(CTX_data_scene(C), CTX_data_scene_layer(C), CTX_wm_screen(C), &thumb); } /* operator now handles overwrite checks */ @@ -1264,6 +1359,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 +1375,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 +1454,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 +1526,11 @@ 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")); 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 @@ -1426,7 +1552,34 @@ static int wm_homefile_read_exec(bContext *C, wmOperator *op) G.fileflags &= ~G_FILE_NO_UI; } - return wm_homefile_read(C, op->reports, from_memory, filepath) ? OPERATOR_FINISHED : OPERATOR_CANCELLED; + 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; + } + else if (!use_factory_settings) { + /* TODO: dont reset prefs on 'New File' */ + BLI_strncpy(app_template_buf, U.app_template, sizeof(app_template_buf)); + app_template = app_template_buf; + } + else { + app_template = NULL; + } + + if (wm_homefile_read(C, op->reports, use_factory_settings, use_empty_data, 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 +1602,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_gesture.c b/source/blender/windowmanager/intern/wm_gesture.c index 46203333eb5..d49c83fa729 100644 --- a/source/blender/windowmanager/intern/wm_gesture.c +++ b/source/blender/windowmanager/intern/wm_gesture.c @@ -45,15 +45,14 @@ #include "BKE_context.h" - #include "WM_api.h" #include "WM_types.h" #include "wm.h" #include "wm_subwindow.h" #include "wm_draw.h" -#include "GPU_basic_shader.h" +#include "GPU_immediate.h" #include "BIF_glutil.h" @@ -168,69 +167,156 @@ int wm_gesture_evaluate(wmGesture *gesture) /* ******************* gesture draw ******************* */ +static void wm_gesture_draw_line(wmGesture *gt) +{ + rcti *rect = (rcti *)gt->customdata; + + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", COMP_F32, 2, KEEP_FLOAT); + unsigned line_origin = add_attrib(format, "line_origin", COMP_F32, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_COLOR); + + immUniform4f("color1", 0.4f, 0.4f, 0.4f, 1.0f); + immUniform4f("color2", 1.0f, 1.0f, 1.0f, 1.0f); + immUniform1f("dash_width", 8.0f); + immUniform1f("dash_width_on", 4.0f); + + float xmin = (float)rect->xmin; + float ymin = (float)rect->ymin; + + immBegin(PRIM_LINES, 2); + + immAttrib2f(line_origin, xmin, ymin); + immVertex2f(pos, xmin, ymin); + immAttrib2f(line_origin, xmin, ymin); + immVertex2f(pos, (float)rect->xmax, (float)rect->ymax); + + immEnd(); + + immUnbindProgram(); +} + +static void imm_draw_line_box_dashed(unsigned pos, unsigned line_origin, float x1, float y1, float x2, float y2) +{ + immBegin(PRIM_LINES, 8); + immAttrib2f(line_origin, x1, y1); + immVertex2f(pos, x1, y1); + immVertex2f(pos, x1, y2); + immAttrib2f(line_origin, x1, y2); + immVertex2f(pos, x1, y2); + immVertex2f(pos, x2, y2); + immAttrib2f(line_origin, x2, y1); + immVertex2f(pos, x2, y2); + immVertex2f(pos, x2, y1); + immAttrib2f(line_origin, x1, y1); + immVertex2f(pos, x2, y1); + immVertex2f(pos, x1, y1); + immEnd(); +} + static void wm_gesture_draw_rect(wmGesture *gt) { rcti *rect = (rcti *)gt->customdata; + + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", COMP_F32, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); glEnable(GL_BLEND); - glColor4f(1.0, 1.0, 1.0, 0.05); - glBegin(GL_QUADS); - glVertex2s(rect->xmax, rect->ymin); - glVertex2s(rect->xmax, rect->ymax); - glVertex2s(rect->xmin, rect->ymax); - glVertex2s(rect->xmin, rect->ymin); - glEnd(); + + immUniform4f("color", 1.0f, 1.0f, 1.0f, 0.05f); + + immBegin(GL_QUADS, 4); + + immVertex2f(pos, (float)rect->xmax, (float)rect->ymin); + immVertex2f(pos, (float)rect->xmax, (float)rect->ymax); + immVertex2f(pos, (float)rect->xmin, (float)rect->ymax); + immVertex2f(pos, (float)rect->xmin, (float)rect->ymin); + + immEnd(); + + immUnbindProgram(); + glDisable(GL_BLEND); + + format = immVertexFormat(); + pos = add_attrib(format, "pos", COMP_F32, 2, KEEP_FLOAT); + unsigned line_origin = add_attrib(format, "line_origin", COMP_F32, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_COLOR); + + immUniform4f("color1", 0.4f, 0.4f, 0.4f, 1.0f); + immUniform4f("color2", 1.0f, 1.0f, 1.0f, 1.0f); + immUniform1f("dash_width", 8.0f); + immUniform1f("dash_width_on", 4.0f); - GPU_basic_shader_bind(GPU_SHADER_LINE | GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR); - glColor3ub(96, 96, 96); - GPU_basic_shader_line_stipple(1, 0xCCCC); - sdrawbox(rect->xmin, rect->ymin, rect->xmax, rect->ymax); - glColor3ub(255, 255, 255); - GPU_basic_shader_line_stipple(1, 0x3333); - sdrawbox(rect->xmin, rect->ymin, rect->xmax, rect->ymax); - GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); + imm_draw_line_box_dashed(pos, line_origin, + (float)rect->xmin, (float)rect->ymin, (float)rect->xmax, (float)rect->ymax); + + immUnbindProgram(); + + // wm_gesture_draw_line(gt); // draws a diagonal line in the lined box to test wm_gesture_draw_line } -static void wm_gesture_draw_line(wmGesture *gt) +static void imm_draw_lined_dashed_circle(unsigned pos, unsigned line_origin, float x, float y, float rad, int nsegments) { - rcti *rect = (rcti *)gt->customdata; - - GPU_basic_shader_bind(GPU_SHADER_LINE | GPU_SHADER_STIPPLE); - glColor3ub(96, 96, 96); - GPU_basic_shader_line_stipple(1, 0xAAAA); - sdrawline(rect->xmin, rect->ymin, rect->xmax, rect->ymax); - glColor3ub(255, 255, 255); - GPU_basic_shader_line_stipple(1, 0x5555); - sdrawline(rect->xmin, rect->ymin, rect->xmax, rect->ymax); - - GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); - + float xpos, ypos; + + xpos = x + rad; + ypos = y; + + immBegin(PRIM_LINES, nsegments * 2); + + for (int i = 1; i <= nsegments; ++i) { + float angle = 2 * M_PI * ((float)i / (float)nsegments); + + immAttrib2f(line_origin, xpos, ypos); + immVertex2f(pos, xpos, ypos); + + xpos = x + rad * cosf(angle); + ypos = y + rad * sinf(angle); + + immVertex2f(pos, xpos, ypos); + } + + immEnd(); } static void wm_gesture_draw_circle(wmGesture *gt) { rcti *rect = (rcti *)gt->customdata; - glTranslatef((float)rect->xmin, (float)rect->ymin, 0.0f); - glEnable(GL_BLEND); - glColor4f(1.0, 1.0, 1.0, 0.05); - glutil_draw_filled_arc(0.0, M_PI * 2.0, rect->xmax, 40); + + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", COMP_F32, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + immUniformColor4f(1.0, 1.0, 1.0, 0.05); + imm_draw_filled_circle(pos, (float)rect->xmin, (float)rect->ymin, (float)rect->xmax, 40); + + immUnbindProgram(); + glDisable(GL_BLEND); - // for USE_GLSL works bad because of no relation between lines - GPU_basic_shader_bind(GPU_SHADER_LINE | GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR); - glColor3ub(96, 96, 96); - GPU_basic_shader_line_stipple(1, 0xAAAA); - glutil_draw_lined_arc(0.0, M_PI * 2.0, rect->xmax, 40); - glColor3ub(255, 255, 255); - GPU_basic_shader_line_stipple(1, 0x5555); - glutil_draw_lined_arc(0.0, M_PI * 2.0, rect->xmax, 40); - - GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); - glTranslatef(-rect->xmin, -rect->ymin, 0.0f); + format = immVertexFormat(); + pos = add_attrib(format, "pos", COMP_F32, 2, KEEP_FLOAT); + unsigned line_origin = add_attrib(format, "line_origin", COMP_F32, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_COLOR); + + immUniform4f("color1", 0.4f, 0.4f, 0.4f, 1.0f); + immUniform4f("color2", 1.0f, 1.0f, 1.0f, 1.0f); + immUniform1f("dash_width", 4.0f); + immUniform1f("dash_width_on", 2.0f); + imm_draw_lined_dashed_circle(pos, line_origin, + (float)rect->xmin, (float)rect->ymin, (float)rect->xmax, 40); + + immUnbindProgram(); } struct LassoFillData { @@ -253,6 +339,7 @@ static void draw_filled_lasso(wmWindow *win, wmGesture *gt) int i; rcti rect; rcti rect_win; + float red[4] = {1.0f, 0.0f, 0.0f, 0.0f}; for (i = 0; i < tot; i++, lasso += 2) { moves[i][0] = lasso[0]; @@ -278,28 +365,28 @@ static void draw_filled_lasso(wmWindow *win, wmGesture *gt) (const int (*)[2])moves, tot, draw_filled_lasso_px_cb, &lasso_fill_data); - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + /* Additive Blending */ + glEnable(GL_BLEND); + glBlendFunc(GL_ONE, GL_ONE); - glColor4f(1, 1, 1, 1); - glPixelTransferf(GL_RED_BIAS, 1); - glPixelTransferf(GL_GREEN_BIAS, 1); - glPixelTransferf(GL_BLUE_BIAS, 1); + GLint unpack_alignment; + glGetIntegerv(GL_UNPACK_ALIGNMENT, &unpack_alignment); - GPU_basic_shader_bind(GPU_SHADER_TEXTURE_2D | GPU_SHADER_USE_COLOR); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - glEnable(GL_BLEND); - glaDrawPixelsTex(rect.xmin, rect.ymin, w, h, GL_ALPHA, GL_UNSIGNED_BYTE, GL_NEAREST, pixel_buf); - glDisable(GL_BLEND); + GPUShader *shader = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR); + GPU_shader_bind(shader); + GPU_shader_uniform_vector(shader, GPU_shader_get_uniform(shader, "shuffle"), 4, 1, red); - GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); + immDrawPixelsTex(rect.xmin, rect.ymin, w, h, GL_RED, GL_UNSIGNED_BYTE, GL_NEAREST, pixel_buf, 1.0f, 1.0f, NULL); - glPixelTransferf(GL_RED_BIAS, 0); - glPixelTransferf(GL_GREEN_BIAS, 0); - glPixelTransferf(GL_BLUE_BIAS, 0); + GPU_shader_unbind(); - glPixelStorei(GL_UNPACK_ALIGNMENT, 4); + glPixelStorei(GL_UNPACK_ALIGNMENT, unpack_alignment); MEM_freeN(pixel_buf); + + glDisable(GL_BLEND); } MEM_freeN(moves); @@ -309,35 +396,57 @@ static void draw_filled_lasso(wmWindow *win, wmGesture *gt) static void wm_gesture_draw_lasso(wmWindow *win, wmGesture *gt, bool filled) { const short *lasso = (short *)gt->customdata; - int i; + int i, numverts; + float x, y; if (filled) { draw_filled_lasso(win, gt); } - // for USE_GLSL can't check this yet - GPU_basic_shader_bind(GPU_SHADER_LINE | GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR); - glColor3ub(96, 96, 96); - GPU_basic_shader_line_stipple(1, 0xAAAA); - glBegin(GL_LINE_STRIP); - for (i = 0; i < gt->points; i++, lasso += 2) - glVertex2sv(lasso); - if (gt->type == WM_GESTURE_LASSO) - glVertex2sv((short *)gt->customdata); - glEnd(); - - glColor3ub(255, 255, 255); - GPU_basic_shader_line_stipple(1, 0x5555); - glBegin(GL_LINE_STRIP); - lasso = (short *)gt->customdata; - for (i = 0; i < gt->points; i++, lasso += 2) - glVertex2sv(lasso); - if (gt->type == WM_GESTURE_LASSO) - glVertex2sv((short *)gt->customdata); - glEnd(); - - GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); - + numverts = gt->points; + if (gt->type == WM_GESTURE_LASSO) { + numverts++; + } + + /* Nothing to drawe, do early output. */ + if (numverts < 2) { + return; + } + + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", COMP_F32, 2, KEEP_FLOAT); + unsigned line_origin = add_attrib(format, "line_origin", COMP_F32, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_COLOR); + + immUniform4f("color1", 0.4f, 0.4f, 0.4f, 1.0f); + immUniform4f("color2", 1.0f, 1.0f, 1.0f, 1.0f); + immUniform1f("dash_width", 2.0f); + immUniform1f("dash_width_on", 1.0f); + + immBegin(PRIM_LINE_STRIP, numverts); + + for (i = 0; i < gt->points; i++, lasso += 2) { + + /* get line_origin coordinates only from the first vertex of each line */ + if (!(i % 2)) { + x = (float)lasso[0]; + y = (float)lasso[1]; + } + + immAttrib2f(line_origin, x, y); + immVertex2f(pos, (float)lasso[0], (float)lasso[1]); + } + + if (gt->type == WM_GESTURE_LASSO) { + immAttrib2f(line_origin, x, y); + lasso = (short *)gt->customdata; + immVertex2f(pos, (float)lasso[0], (float)lasso[1]); + } + + immEnd(); + + immUnbindProgram(); } static void wm_gesture_draw_cross(wmWindow *win, wmGesture *gt) @@ -346,25 +455,52 @@ static void wm_gesture_draw_cross(wmWindow *win, wmGesture *gt) const int winsize_x = WM_window_pixels_x(win); const int winsize_y = WM_window_pixels_y(win); - GPU_basic_shader_bind(GPU_SHADER_LINE | GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR); - glColor3ub(96, 96, 96); - GPU_basic_shader_line_stipple(1, 0xCCCC); - sdrawline(rect->xmin - winsize_x, rect->ymin, rect->xmin + winsize_x, rect->ymin); - sdrawline(rect->xmin, rect->ymin - winsize_y, rect->xmin, rect->ymin + winsize_y); - - glColor3ub(255, 255, 255); - GPU_basic_shader_line_stipple(1, 0x3333); - sdrawline(rect->xmin - winsize_x, rect->ymin, rect->xmin + winsize_x, rect->ymin); - sdrawline(rect->xmin, rect->ymin - winsize_y, rect->xmin, rect->ymin + winsize_y); - GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); + float x1, x2, y1, y2; + + VertexFormat *format = immVertexFormat(); + unsigned pos = add_attrib(format, "pos", COMP_F32, 2, KEEP_FLOAT); + unsigned line_origin = add_attrib(format, "line_origin", COMP_F32, 2, KEEP_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_COLOR); + + immUniform4f("color1", 0.4f, 0.4f, 0.4f, 1.0f); + immUniform4f("color2", 1.0f, 1.0f, 1.0f, 1.0f); + immUniform1f("dash_width", 8.0f); + immUniform1f("dash_width_on", 4.0f); + + immBegin(PRIM_LINES, 4); + + x1 = (float)(rect->xmin - winsize_x); + y1 = (float)rect->ymin; + x2 = (float)(rect->xmin + winsize_x); + y2 = y1; + + immAttrib2f(line_origin, x1, y1); + immVertex2f(pos, x1, y1); + immAttrib2f(line_origin, x1, y1); + immVertex2f(pos, x2, y2); + + x1 = (float)rect->xmin; + y1 = (float)(rect->ymin - winsize_y); + x2 = x1; + y2 = (float)(rect->ymin + winsize_y); + + immAttrib2f(line_origin, x1, y1); + immVertex2f(pos, x1, y1); + immAttrib2f(line_origin, x1, y1); + immVertex2f(pos, x2, y2); + + immEnd(); + + immUnbindProgram(); } /* called in wm_draw.c */ void wm_gesture_draw(wmWindow *win) { wmGesture *gt = (wmGesture *)win->gesture.first; - - GPU_basic_shader_line_width(1); + + glLineWidth(1.0f); for (; gt; gt = gt->next) { /* all in subwindow space */ wmSubWindowSet(win, gt->swinid); diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index fbbde2a6d28..131e216ac8d 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -193,7 +193,7 @@ void WM_init(bContext *C, int argc, const char **argv) 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, NULL, NULL); BLT_lang_set(NULL); @@ -445,8 +445,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 */ @@ -578,7 +576,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 */ @@ -595,6 +593,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 4179ac7f993..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); } } @@ -1861,10 +1868,6 @@ wmKeyMap *WM_keymap_guess_opname(const bContext *C, const char *opname) else if (STRPREFIX(opname, "OUTLINER_OT")) { km = WM_keymap_find_all(C, "Outliner", sl->spacetype, 0); } - /* Layer Manager */ - else if (STRPREFIX(opname, "COLLECTIONS_OT")) { - km = WM_keymap_find_all(C, "Collection Manager", sl->spacetype, 0); - } /* Transform */ else if (STRPREFIX(opname, "TRANSFORM_OT")) { /* check for relevant editor */ diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index 6591005b5f3..a6f9e84cac3 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -86,9 +86,13 @@ #include "BKE_idcode.h" -#include "BIF_glutil.h" /* for paint cursor */ #include "BLF_api.h" +#include "BIF_glutil.h" /* for paint cursor */ + +#include "GPU_immediate.h" +#include "GPU_matrix.h" + #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" @@ -97,9 +101,6 @@ #include "ED_util.h" #include "ED_view3d.h" -#include "GPU_basic_shader.h" -#include "GPU_immediate.h" - #include "RNA_access.h" #include "RNA_define.h" #include "RNA_enum_types.h" @@ -904,7 +905,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); @@ -1108,45 +1109,70 @@ int WM_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) return WM_menu_invoke_ex(C, op, WM_OP_INVOKE_REGION_WIN); } +struct EnumSearchMenu { + wmOperator *op; /* the operator that will be executed when selecting an item */ + + bool use_previews; + short prv_cols, prv_rows; +}; /* generic enum search invoke popup */ -static uiBlock *wm_enum_search_menu(bContext *C, ARegion *ar, void *arg_op) +static uiBlock *wm_enum_search_menu(bContext *C, ARegion *ar, void *arg) { - static char search[256] = ""; - wmEvent event; + struct EnumSearchMenu *search_menu = arg; wmWindow *win = CTX_wm_window(C); + wmOperator *op = search_menu->op; + /* template_ID uses 4 * widget_unit for width, we use a bit more, some items may have a suffix to show */ + const int width = search_menu->use_previews ? 5 * U.widget_unit * search_menu->prv_cols : UI_searchbox_size_x(); + const int height = search_menu->use_previews ? 5 * U.widget_unit * search_menu->prv_rows : UI_searchbox_size_y(); + static char search[256] = ""; uiBlock *block; uiBut *but; - wmOperator *op = (wmOperator *)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'; + BLI_assert(search_menu->use_previews || (search_menu->prv_cols == 0 && search_menu->prv_rows == 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 but = uiDefSearchButO_ptr(block, op->type, op->ptr->data, search, 0, ICON_VIEWZOOM, sizeof(search), - 10, 10, UI_searchbox_size_x(), UI_UNIT_Y, 0, 0, ""); + 10, 10, width, UI_UNIT_Y, search_menu->prv_rows, search_menu->prv_cols, ""); /* fake button, it holds space for search items */ - uiDefBut(block, UI_BTYPE_LABEL, 0, "", 10, 10 - UI_searchbox_size_y(), UI_searchbox_size_x(), UI_searchbox_size_y(), NULL, 0, 0, 0, 0, NULL); + uiDefBut(block, UI_BTYPE_LABEL, 0, "", 10, 10 - UI_searchbox_size_y(), width, height, NULL, 0, 0, 0, 0, NULL); UI_block_bounds_set_popup(block, 6, 0, -UI_UNIT_Y); /* move it downwards, mouse over button */ - - wm_event_init_from_window(win, &event); - event.type = EVT_BUT_OPEN; - event.val = KM_PRESS; - event.customdata = but; - event.customdatafree = false; - wm_event_add(win, &event); + UI_but_focus_on_enter_event(win, but); 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; + + search_menu.op = op; + search_menu.use_previews = true; + search_menu.prv_cols = prv_cols; + search_menu.prv_rows = prv_rows; + + UI_popup_block_invoke(C, wm_enum_search_menu, &search_menu); + + return OPERATOR_INTERFACE; +} int WM_enum_search_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - UI_popup_block_invoke(C, wm_enum_search_menu, op); + static struct EnumSearchMenu search_menu; + search_menu.op = op; + UI_popup_block_invoke(C, wm_enum_search_menu, &search_menu); return OPERATOR_INTERFACE; } @@ -1406,20 +1432,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) { @@ -1438,8 +1450,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 */ @@ -1478,8 +1488,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); @@ -1526,7 +1534,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; } @@ -1556,7 +1564,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); @@ -1598,7 +1606,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; } @@ -1765,6 +1773,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); @@ -2079,14 +2117,22 @@ static void WM_OT_window_close(wmOperatorType *ot) ot->poll = WM_operator_winactive; } -static void WM_OT_window_duplicate(wmOperatorType *ot) +static void WM_OT_window_new(wmOperatorType *ot) { - ot->name = "Duplicate Window"; - ot->idname = "WM_OT_window_duplicate"; - ot->description = "Duplicate the current Blender window"; - - ot->exec = wm_window_duplicate_exec; + PropertyRNA *prop; + + ot->name = "New Window"; + ot->idname = "WM_OT_window_new"; + ot->description = "Create a new Blender window"; + + ot->exec = wm_window_new_exec; + ot->invoke = wm_window_new_invoke; ot->poll = wm_operator_winactive_normal; + + prop = RNA_def_enum(ot->srna, "screen", DummyRNA_NULL_items, 0, "Screen", ""); + RNA_def_enum_funcs(prop, wm_window_new_screen_itemf); + RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); + ot->prop = prop; } static void WM_OT_window_fullscreen_toggle(wmOperatorType *ot) @@ -3047,8 +3093,8 @@ static void radial_control_paint_tex(RadialControl *rc, float radius, float alph /* set up rotation if available */ if (rc->rot_prop) { rot = RNA_property_float_get(&rc->rot_ptr, rc->rot_prop); - glPushMatrix(); - glRotatef(RAD2DEGF(rot), 0, 0, 1); + gpuPushMatrix(); + gpuRotate2D(RAD2DEGF(rot)); } /* draw textured quad */ @@ -3070,7 +3116,7 @@ static void radial_control_paint_tex(RadialControl *rc, float radius, float alph /* undo rotation */ if (rc->rot_prop) - glPopMatrix(); + gpuPopMatrix(); } else { /* flat color if no texture available */ @@ -3138,7 +3184,7 @@ static void radial_control_paint_cursor(bContext *C, int x, int y, void *customd /* Keep cursor in the original place */ x = rc->initial_mouse[0] - ar->winrct.xmin; y = rc->initial_mouse[1] - ar->winrct.ymin; - glTranslatef((float)x, (float)y, 0.0f); + gpuTranslate2f((float)x, (float)y); glEnable(GL_BLEND); glEnable(GL_LINE_SMOOTH); @@ -3146,7 +3192,7 @@ static void radial_control_paint_cursor(bContext *C, int x, int y, void *customd /* apply zoom if available */ if (rc->zoom_prop) { RNA_property_float_get_array(&rc->zoom_ptr, rc->zoom_prop, zoom); - glScalef(zoom[0], zoom[1], 1); + gpuScale2fv(zoom); } /* draw rotated texture */ @@ -3163,23 +3209,23 @@ static void radial_control_paint_cursor(bContext *C, int x, int y, void *customd immUniformColor3fvAlpha(col, 0.5); if (rc->subtype == PROP_ANGLE) { - glPushMatrix(); + gpuPushMatrix(); /* draw original angle line */ - glRotatef(RAD2DEGF(rc->initial_value), 0, 0, 1); + gpuRotate2D(RAD2DEGF(rc->initial_value)); immBegin(GL_LINES, 2); immVertex2f(pos, (float)WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE, 0.0f); immVertex2f(pos, (float)WM_RADIAL_CONTROL_DISPLAY_SIZE, 0.0f); immEnd(); /* draw new angle line */ - glRotatef(RAD2DEGF(rc->current_value - rc->initial_value), 0, 0, 1); + gpuRotate2D(RAD2DEGF(rc->current_value - rc->initial_value)); immBegin(GL_LINES, 2); immVertex2f(pos, (float)WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE, 0.0f); immVertex2f(pos, (float)WM_RADIAL_CONTROL_DISPLAY_SIZE, 0.0f); immEnd(); - glPopMatrix(); + gpuPopMatrix(); } /* draw circles on top */ @@ -3187,6 +3233,7 @@ static void radial_control_paint_cursor(bContext *C, int x, int y, void *customd imm_draw_lined_circle(pos, 0.0f, 0.0f, r2, 40); if (rmin > 0.0f) imm_draw_lined_circle(pos, 0.0, 0.0f, rmin, 40); + immUnbindProgram(); BLF_size(fontid, 1.5 * fstyle_points * U.pixelsize, U.dpi); BLF_enable(fontid, BLF_SHADOW); @@ -3203,7 +3250,6 @@ static void radial_control_paint_cursor(bContext *C, int x, int y, void *customd glDisable(GL_BLEND); glDisable(GL_LINE_SMOOTH); - immUnbindProgram(); } typedef enum { @@ -4177,7 +4223,7 @@ void wm_operatortype_init(void) global_ops_hash = BLI_ghash_str_new_ex("wm_operatortype_init gh", 2048); WM_operatortype_append(WM_OT_window_close); - WM_operatortype_append(WM_OT_window_duplicate); + WM_operatortype_append(WM_OT_window_new); WM_operatortype_append(WM_OT_read_history); WM_operatortype_append(WM_OT_read_homefile); WM_operatortype_append(WM_OT_read_factory_settings); @@ -4419,7 +4465,7 @@ void wm_window_keymap(wmKeyConfig *keyconf) wmKeyMapItem *kmi; /* note, this doesn't replace existing keymap items */ - WM_keymap_verify_item(keymap, "WM_OT_window_duplicate", WKEY, KM_PRESS, KM_CTRL | KM_ALT, 0); + WM_keymap_verify_item(keymap, "WM_OT_window_new", WKEY, KM_PRESS, KM_CTRL | KM_ALT, 0); #ifdef __APPLE__ WM_keymap_add_item(keymap, "WM_OT_read_homefile", NKEY, KM_PRESS, KM_OSKEY, 0); WM_keymap_add_menu(keymap, "INFO_MT_file_open_recent", OKEY, KM_PRESS, KM_SHIFT | KM_OSKEY, 0); diff --git a/source/blender/windowmanager/intern/wm_playanim.c b/source/blender/windowmanager/intern/wm_playanim.c index 6bf7bcc2934..46c7599ec56 100644 --- a/source/blender/windowmanager/intern/wm_playanim.c +++ b/source/blender/windowmanager/intern/wm_playanim.c @@ -64,6 +64,8 @@ #include "BIF_gl.h" #include "BIF_glutil.h" +#include "GPU_matrix.h" + #include "DNA_scene_types.h" #include "ED_datafiles.h" /* for fonts */ #include "GHOST_C-api.h" @@ -190,10 +192,7 @@ static void playanim_window_get_size(int *r_width, int *r_height) static void playanim_gl_matrix(void) { /* unified matrix, note it affects offset for drawing */ - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(0.0f, 1.0f, 0.0f, 1.0f, -1.0f, 1.0f); - glMatrixMode(GL_MODELVIEW); + gpuOrtho2D(0.0f, 1.0f, 0.0f, 1.0f); } /* implementation */ @@ -318,7 +317,7 @@ static void playanim_toscreen(PlayState *ps, PlayAnimPict *picture, struct ImBuf glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - fdrawcheckerboard(offs_x, offs_y, offs_x + span_x, offs_y + span_y); + imm_draw_checker_box(offs_x, offs_y, offs_x + span_x, offs_y + span_y); } glRasterPos2f(offs_x + (ps->draw_flip[0] ? span_x : 0.0f), @@ -354,12 +353,12 @@ static void playanim_toscreen(PlayState *ps, PlayAnimPict *picture, struct ImBuf float fac = ps->picture->frame / (double)(((PlayAnimPict *)picsbase.last)->frame - ((PlayAnimPict *)picsbase.first)->frame); fac = 2.0f * fac - 1.0f; - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); + glMatrixMode(GL_PROJECTION); /* TODO: convert this nasty code */ + gpuPushMatrix(); + gpuLoadIdentity(); glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); + gpuPushMatrix(); + gpuLoadIdentity(); glColor4f(0.0f, 1.0f, 0.0f, 1.0f); @@ -368,9 +367,9 @@ static void playanim_toscreen(PlayState *ps, PlayAnimPict *picture, struct ImBuf glVertex2f(fac, 1.0f); glEnd(); - glPopMatrix(); + gpuPopMatrix(); glMatrixMode(GL_PROJECTION); - glPopMatrix(); + gpuPopMatrix(); glMatrixMode(GL_MODELVIEW); } diff --git a/source/blender/windowmanager/intern/wm_stereo.c b/source/blender/windowmanager/intern/wm_stereo.c index d312f4c007c..bd22cb191c7 100644 --- a/source/blender/windowmanager/intern/wm_stereo.c +++ b/source/blender/windowmanager/intern/wm_stereo.c @@ -52,8 +52,6 @@ #include "ED_screen.h" -#include "GPU_glew.h" -#include "GPU_basic_shader.h" #include "GPU_immediate.h" #include "WM_api.h" @@ -396,6 +394,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_subwindow.c b/source/blender/windowmanager/intern/wm_subwindow.c index 458ac4a121a..d73aa107cab 100644 --- a/source/blender/windowmanager/intern/wm_subwindow.c +++ b/source/blender/windowmanager/intern/wm_subwindow.c @@ -47,8 +47,7 @@ #include "BIF_gl.h" -#include "GPU_extensions.h" -#include "GPU_basic_shader.h" +#include "GPU_matrix.h" #include "WM_api.h" #include "wm_subwindow.h" @@ -150,7 +149,7 @@ static void wm_swin_matrix_get(wmWindow *win, wmSubWindow *swin, float mat[4][4] orthographic_m4(mat, -GLA_PIXEL_OFS, (float)width - GLA_PIXEL_OFS, -GLA_PIXEL_OFS, (float)height - GLA_PIXEL_OFS, -100, 100); } else { - glGetFloatv(GL_PROJECTION_MATRIX, (float *)mat); + gpuGetProjectionMatrix3D(mat); } } void wm_subwindow_matrix_get(wmWindow *win, int swinid, float mat[4][4]) @@ -216,7 +215,7 @@ int wm_subwindow_open(wmWindow *win, const rcti *winrct, bool activate) /* extra service */ wm_swin_size_get(swin, &width, &height); wmOrtho2_pixelspace(width, height); - glLoadIdentity(); + gpuLoadIdentity(); } return swin->swinid; @@ -322,7 +321,7 @@ void wmSubWindowScissorSet(wmWindow *win, int swinid, const rcti *srct, bool src glScissor(_curswin->winrct.xmin, _curswin->winrct.ymin, width, height); wmOrtho2_pixelspace(width, height); - glLoadIdentity(); + gpuLoadIdentity(); glFlush(); } @@ -333,31 +332,13 @@ void wmSubWindowSet(wmWindow *win, int swinid) wmSubWindowScissorSet(win, swinid, NULL, true); } -void wmFrustum(float x1, float x2, float y1, float y2, float n, float f) -{ - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glFrustum(x1, x2, y1, y2, n, f); - glMatrixMode(GL_MODELVIEW); -} - -void wmOrtho(float x1, float x2, float y1, float y2, float n, float f) -{ - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - - glOrtho(x1, x2, y1, y2, n, f); - - glMatrixMode(GL_MODELVIEW); -} - void wmOrtho2(float x1, float x2, float y1, float y2) { /* prevent opengl from generating errors */ if (x1 == x2) x2 += 1.0f; if (y1 == y2) y2 += 1.0f; - wmOrtho(x1, x2, y1, y2, -100, 100); + gpuOrtho(x1, x2, y1, y2, -100, 100); } static void wmOrtho2_offset(const float x, const float y, const float ofs) diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index e271225e437..2027afef103 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -58,6 +58,7 @@ #include "RNA_access.h" +#include "RNA_define.h" #include "WM_api.h" #include "WM_types.h" @@ -71,6 +72,7 @@ #include "ED_fileselect.h" #include "UI_interface.h" +#include "UI_interface_icons.h" #include "PIL_time.h" @@ -78,6 +80,9 @@ #include "GPU_extensions.h" #include "GPU_init_exit.h" #include "GPU_immediate.h" +#include "BLF_api.h" + +#include "UI_resources.h" /* for assert */ #ifndef NDEBUG @@ -244,6 +249,25 @@ wmWindow *wm_window_new(bContext *C) return win; } +/** + * A higher level version of copy that tests the new window can be added. + */ +static wmWindow *wm_window_new_test(bContext *C) +{ + wmWindow *win = wm_window_new(C); + + WM_check(C); + + if (win->ghostwin) { + WM_event_add_notifier(C, NC_WINDOW | NA_ADDED, NULL); + return win; + } + else { + wmWindowManager *wm = CTX_wm_manager(C); + wm_window_close(C, wm, win); + return NULL; + } +} /* part of wm_window.c api */ wmWindow *wm_window_copy(bContext *C, wmWindow *win_src) @@ -312,7 +336,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; @@ -375,14 +399,39 @@ void wm_window_title(wmWindowManager *wm, wmWindow *win) } } -static float wm_window_get_virtual_pixelsize(void) +static void wm_window_set_dpi(wmWindow *win) { - return ((U.virtual_pixel == VIRTUAL_PIXEL_NATIVE) ? 1.0f : 2.0f); -} + int auto_dpi = GHOST_GetDPIHint(win->ghostwin); -float wm_window_pixelsize(wmWindow *win) -{ - return (GHOST_GetNativePixelSize(win->ghostwin) * wm_window_get_virtual_pixelsize()); + /* 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. */ + int dpi = auto_dpi * U.ui_scale * (72.0 / 96.0f); + + /* Automatically set larger pixel size for high DPI. */ + int pixelsize = MAX2(1, dpi / 54); + + /* Set user preferences globals for drawing, and for forward compatibility. */ + U.pixelsize = GHOST_GetNativePixelSize(win->ghostwin) * pixelsize; + U.dpi = dpi / pixelsize; + U.virtual_pixel = (pixelsize == 1) ? VIRTUAL_PIXEL_NATIVE : VIRTUAL_PIXEL_DOUBLE; + + BKE_blender_userdef_refresh(); } /* belongs to below */ @@ -457,10 +506,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); @@ -627,7 +674,6 @@ wmWindow *WM_window_open_temp(bContext *C, const rcti *rect_init, int type) Scene *scene = CTX_data_scene(C); const char *title; rcti rect = *rect_init; - const short px_virtual = (short)wm_window_get_virtual_pixelsize(); /* changes rect to fit within desktop */ wm_window_check_position(&rect); @@ -645,9 +691,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); @@ -723,17 +768,79 @@ int wm_window_close_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_FINISHED; } -/* operator callback */ -int wm_window_duplicate_exec(bContext *C, wmOperator *UNUSED(op)) +/* new window operator callback */ +int wm_window_new_exec(bContext *C, wmOperator *op) { + Main *bmain = CTX_data_main(C); wmWindow *win_src = CTX_wm_window(C); - bool ok; + const int screen_id = RNA_enum_get(op->ptr, "screen"); + bScreen *screen = BLI_findlink(&bmain->screen, screen_id); + wmWindow *win_dst; - ok = (wm_window_copy_test(C, win_src) != NULL); + if (screen->winid) { + /* Screen is already used, duplicate window and screen */ + win_dst = wm_window_copy_test(C, win_src); + } + else if ((win_dst = wm_window_new_test(C))) { + /* New window with a different screen */ + win_dst->screen = screen; + screen->winid = win_dst->winid; + CTX_wm_window_set(C, win_dst); + ED_screen_refresh(CTX_wm_manager(C), win_dst); + } - return ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED; + return (win_dst != NULL) ? OPERATOR_FINISHED : OPERATOR_CANCELLED; } +int wm_window_new_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + Main *bmain = CTX_data_main(C); + + if (BLI_listbase_count_ex(&bmain->screen, 2) == 1) { + RNA_enum_set(op->ptr, "screen", 0); + return wm_window_new_exec(C, op); + } + else { + return WM_enum_search_invoke_previews(C, op, 6, 2); + } +} + +struct EnumPropertyItem *wm_window_new_screen_itemf( + bContext *C, struct PointerRNA *UNUSED(ptr), struct PropertyRNA *UNUSED(prop), bool *r_free) +{ + Main *bmain = CTX_data_main(C); + EnumPropertyItem *item = NULL; + EnumPropertyItem tmp = {0, "", 0, "", ""}; + int value = 0, totitem = 0; + int count_act_screens = 0; + /* XXX setting max number of windows to 20. We'd need support + * for dynamic strings in EnumPropertyItem.name to avoid this. */ + static char active_screens[20][MAX_NAME + 12]; + + for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) { + if (screen->winid) { + BLI_snprintf(active_screens[count_act_screens], sizeof(*active_screens), "%s (Duplicate)", + screen->id.name + 2); + tmp.name = active_screens[count_act_screens++]; + } + else { + tmp.name = screen->id.name + 2; + } + + tmp.value = value; + tmp.identifier = screen->id.name; + UI_id_icon_render(C, CTX_data_scene(C), &screen->id, true, false); + tmp.icon = BKE_icon_id_ensure(&screen->id); + + RNA_enum_item_add(&item, &totitem, &tmp); + value++; + } + + RNA_enum_item_end(&item, &totitem); + *r_free = true; + + return item; +} /* fullscreen operator callback */ int wm_window_fullscreen_toggle_exec(bContext *C, wmOperator *UNUSED(op)) @@ -828,7 +935,7 @@ void wm_window_make_drawable(wmWindowManager *wm, wmWindow *win) { if (win != wm->windrawable && win->ghostwin) { // win->lmbut = 0; /* keeps hanging when mousepressed while other window opened */ - + wm->windrawable = win; if (G.debug & G_DEBUG_EVENTS) { printf("%s: set drawable %d\n", __func__, win->winid); @@ -839,8 +946,7 @@ void wm_window_make_drawable(wmWindowManager *wm, wmWindow *win) immActivate(); /* this can change per window */ - U.pixelsize = wm_window_pixelsize(win); - BKE_blender_userdef_refresh(); + wm_window_set_dpi(win); } } @@ -1039,6 +1145,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) { @@ -1123,7 +1231,19 @@ 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(); + + BKE_blender_userdef_refresh(); + 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; @@ -1204,10 +1324,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(); BKE_icon_changed(win->screen->id.icon_id); // close all popups since they are positioned with the pixel |