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:
authorGaia Clary <gaia.clary@machinimatrix.org>2019-05-22 23:35:40 +0300
committerGaia Clary <gaia.clary@machinimatrix.org>2019-05-22 23:35:40 +0300
commit4755c2345854dd97234de2438e00008311537dde (patch)
tree3f7f5a029c50fda39630bdb6ef518f925df01f18 /source/blender/windowmanager/intern
parent43e6bb85cee0802887eae9489a2bd73836daf41d (diff)
parentb471e48c305b6fdee69a862b50547a59dd368c4d (diff)
Merge branch 'master' into collada
Diffstat (limited to 'source/blender/windowmanager/intern')
-rw-r--r--source/blender/windowmanager/intern/wm.c1
-rw-r--r--source/blender/windowmanager/intern/wm_dragdrop.c2
-rw-r--r--source/blender/windowmanager/intern/wm_draw.c11
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c13
-rw-r--r--source/blender/windowmanager/intern/wm_files.c745
-rw-r--r--source/blender/windowmanager/intern/wm_gesture.c6
-rw-r--r--source/blender/windowmanager/intern/wm_init_exit.c15
-rw-r--r--source/blender/windowmanager/intern/wm_keymap.c11
-rw-r--r--source/blender/windowmanager/intern/wm_operator_props.c20
-rw-r--r--source/blender/windowmanager/intern/wm_operator_type.c3
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c36
-rw-r--r--source/blender/windowmanager/intern/wm_playanim.c2
-rw-r--r--source/blender/windowmanager/intern/wm_toolsystem.c16
-rw-r--r--source/blender/windowmanager/intern/wm_utils.c71
-rw-r--r--source/blender/windowmanager/intern/wm_window.c184
15 files changed, 790 insertions, 346 deletions
diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c
index 7647e9f558f..77e17ad4687 100644
--- a/source/blender/windowmanager/intern/wm.c
+++ b/source/blender/windowmanager/intern/wm.c
@@ -82,7 +82,6 @@ void WM_operator_free(wmOperator *op)
if (op->properties) {
IDP_FreeProperty(op->properties);
- MEM_freeN(op->properties);
}
if (op->reports && (op->reports->flag & RPT_FREE)) {
diff --git a/source/blender/windowmanager/intern/wm_dragdrop.c b/source/blender/windowmanager/intern/wm_dragdrop.c
index 30311d83509..e4ecf7e6e94 100644
--- a/source/blender/windowmanager/intern/wm_dragdrop.c
+++ b/source/blender/windowmanager/intern/wm_dragdrop.c
@@ -442,7 +442,7 @@ void wm_drags_draw(bContext *C, wmWindow *win, rcti *rect)
drag_rect_minmax(rect, x, y, x + iconsize, y + iconsize);
}
else {
- UI_icon_draw_aspect(x, y, drag->icon, 1.0f / UI_DPI_FAC, 0.8, text_col);
+ UI_icon_draw_ex(x, y, drag->icon, U.inv_dpi_fac, 0.8, 0.0f, text_col, false);
}
}
diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c
index 6ecbf4ef5ac..6b6a04cacad 100644
--- a/source/blender/windowmanager/intern/wm_draw.c
+++ b/source/blender/windowmanager/intern/wm_draw.c
@@ -917,6 +917,17 @@ void WM_draw_region_free(ARegion *ar)
ar->visible = 0;
}
+void wm_draw_region_test(bContext *C, ScrArea *sa, ARegion *ar)
+{
+ /* Function for redraw timer benchmark. */
+ bool use_viewport = wm_region_use_viewport(sa, ar);
+ wm_draw_region_buffer_create(ar, false, use_viewport);
+ wm_draw_region_bind(ar, 0);
+ ED_region_do_draw(C, ar);
+ wm_draw_region_unbind(ar, 0);
+ ar->do_draw = false;
+}
+
void WM_redraw_windows(bContext *C)
{
wmWindow *win_prev = CTX_wm_window(C);
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index 13b6260e2b9..6683085e6d3 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -1293,7 +1293,6 @@ static bool operator_last_properties_init_impl(wmOperator *op, IDProperty *last_
IDP_MergeGroup(op->properties, replaceprops, true);
IDP_FreeProperty(replaceprops);
- MEM_freeN(replaceprops);
return changed;
}
@@ -1316,7 +1315,6 @@ bool WM_operator_last_properties_store(wmOperator *op)
{
if (op->type->last_properties) {
IDP_FreeProperty(op->type->last_properties);
- MEM_freeN(op->type->last_properties);
op->type->last_properties = NULL;
}
@@ -1680,6 +1678,17 @@ int WM_operator_name_call(bContext *C, const char *opstring, short context, Poin
return 0;
}
+int WM_operator_name_call_with_properties(struct bContext *C,
+ const char *opstring,
+ short context,
+ struct IDProperty *properties)
+{
+ PointerRNA props_ptr;
+ wmOperatorType *ot = WM_operatortype_find(opstring, false);
+ RNA_pointer_create(NULL, ot->srna, properties, &props_ptr);
+ return WM_operator_name_call_ptr(C, ot, context, &props_ptr);
+}
+
/**
* Call an existent menu. The menu can be created in C or Python.
*/
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c
index 6d90d4745a6..097db49aea6 100644
--- a/source/blender/windowmanager/intern/wm_files.c
+++ b/source/blender/windowmanager/intern/wm_files.c
@@ -76,6 +76,7 @@
#include "BKE_blender_undo.h"
#include "BKE_context.h"
#include "BKE_global.h"
+#include "BKE_idprop.h"
#include "BKE_main.h"
#include "BKE_packedFile.h"
#include "BKE_report.h"
@@ -98,6 +99,7 @@
#include "ED_datafiles.h"
#include "ED_fileselect.h"
+#include "ED_image.h"
#include "ED_screen.h"
#include "ED_view3d.h"
#include "ED_util.h"
@@ -488,18 +490,21 @@ void wm_file_read_report(bContext *C, Main *bmain)
static void wm_file_read_post(bContext *C,
const bool is_startup_file,
const bool is_factory_startup,
+ const bool use_data,
+ const bool use_userdef,
const bool reset_app_template)
{
bool addons_loaded = false;
wmWindowManager *wm = CTX_wm_manager(C);
- if (!G.background) {
- /* remove windows which failed to be added via WM_check */
- wm_window_ghostwindows_remove_invalid(C, wm);
+ if (use_data) {
+ if (!G.background) {
+ /* remove windows which failed to be added via WM_check */
+ wm_window_ghostwindows_remove_invalid(C, wm);
+ }
+ CTX_wm_window_set(C, wm->windows.first);
}
- CTX_wm_window_set(C, wm->windows.first);
-
#ifdef WITH_PYTHON
if (is_startup_file) {
/* possible python hasn't been initialized */
@@ -513,41 +518,56 @@ static void wm_file_read_post(bContext *C,
/* sync addons, these may have changed from the defaults */
BPY_execute_string(C, (const char *[]){"addon_utils", NULL}, "addon_utils.reset_all()");
}
- BPY_python_reset(C);
+ if (use_data) {
+ BPY_python_reset(C);
+ }
addons_loaded = true;
}
}
else {
/* run any texts that were loaded in and flagged as modules */
- BPY_python_reset(C);
+ if (use_data) {
+ BPY_python_reset(C);
+ }
addons_loaded = true;
}
#else
UNUSED_VARS(is_startup_file, reset_app_template);
#endif /* WITH_PYTHON */
- WM_operatortype_last_properties_clear_all();
-
- /* important to do before NULL'ing the context */
Main *bmain = CTX_data_main(C);
- BLI_callback_exec(bmain, NULL, BLI_CB_EVT_VERSION_UPDATE);
- BLI_callback_exec(bmain, NULL, BLI_CB_EVT_LOAD_POST);
- if (is_factory_startup) {
- BLI_callback_exec(bmain, NULL, BLI_CB_EVT_LOAD_FACTORY_STARTUP_POST);
+
+ if (use_userdef) {
+ if (is_factory_startup) {
+ BLI_callback_exec(bmain, NULL, BLI_CB_EVT_LOAD_FACTORY_USERDEF_POST);
+ }
+ }
+
+ if (use_data) {
+ /* important to do before NULL'ing the context */
+ BLI_callback_exec(bmain, NULL, BLI_CB_EVT_VERSION_UPDATE);
+ BLI_callback_exec(bmain, NULL, BLI_CB_EVT_LOAD_POST);
+ if (is_factory_startup) {
+ BLI_callback_exec(bmain, NULL, BLI_CB_EVT_LOAD_FACTORY_STARTUP_POST);
+ }
}
- /* After load post, so for example the driver namespace can be filled
- * before evaluating the depsgraph. */
- DEG_on_visible_update(bmain, true);
- wm_event_do_depsgraph(C);
+ if (use_data) {
+ WM_operatortype_last_properties_clear_all();
- ED_editors_init(C);
+ /* After load post, so for example the driver namespace can be filled
+ * before evaluating the depsgraph. */
+ DEG_on_visible_update(bmain, true);
+ wm_event_do_depsgraph(C);
+
+ ED_editors_init(C);
#if 1
- WM_event_add_notifier(C, NC_WM | ND_FILEREAD, NULL);
+ WM_event_add_notifier(C, NC_WM | ND_FILEREAD, NULL);
#else
- WM_msg_publish_static(CTX_wm_message_bus(C), WM_MSG_STATICTYPE_FILE_READ);
+ WM_msg_publish_static(CTX_wm_message_bus(C), WM_MSG_STATICTYPE_FILE_READ);
#endif
+ }
/* report any errors.
* currently disabled if addons aren't yet loaded */
@@ -555,25 +575,29 @@ static void wm_file_read_post(bContext *C,
wm_file_read_report(C, bmain);
}
- if (!G.background) {
- if (wm->undo_stack == NULL) {
- wm->undo_stack = BKE_undosys_stack_create();
- }
- else {
- BKE_undosys_stack_clear(wm->undo_stack);
+ if (use_data) {
+ if (!G.background) {
+ if (wm->undo_stack == NULL) {
+ wm->undo_stack = BKE_undosys_stack_create();
+ }
+ else {
+ BKE_undosys_stack_clear(wm->undo_stack);
+ }
+ BKE_undosys_stack_init_from_main(wm->undo_stack, bmain);
+ BKE_undosys_stack_init_from_context(wm->undo_stack, C);
}
- BKE_undosys_stack_init_from_main(wm->undo_stack, bmain);
- BKE_undosys_stack_init_from_context(wm->undo_stack, C);
}
- if (!G.background) {
- /* in background mode this makes it hard to load
- * a blend file and do anything since the screen
- * won't be set to a valid value again */
- CTX_wm_window_set(C, NULL); /* exits queues */
+ if (use_data) {
+ if (!G.background) {
+ /* in background mode this makes it hard to load
+ * a blend file and do anything since the screen
+ * won't be set to a valid value again */
+ CTX_wm_window_set(C, NULL); /* exits queues */
- /* Ensure tools are registered. */
- WM_toolsystem_init(C);
+ /* Ensure tools are registered. */
+ WM_toolsystem_init(C);
+ }
}
}
@@ -600,6 +624,8 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports)
/* we didn't succeed, now try to read Blender file */
if (retval == BKE_READ_EXOTIC_OK_BLEND) {
+ bool use_data = true;
+ bool use_userdef = false;
const int G_f_orig = G.f;
ListBase wmbase;
@@ -638,6 +664,7 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports)
if (retval == BKE_BLENDFILE_READ_OK_USERPREFS) {
/* in case a userdef is read from regular .blend */
wm_init_userdef(bmain, false);
+ use_userdef = true;
}
if (retval != BKE_BLENDFILE_READ_FAIL) {
@@ -646,7 +673,7 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports)
}
}
- wm_file_read_post(C, false, false, false);
+ wm_file_read_post(C, false, false, use_data, use_userdef, false);
success = true;
}
@@ -716,26 +743,6 @@ const char *WM_init_state_app_template_get(void)
return wm_init_state_app_template.override ? wm_init_state_app_template.app_template : NULL;
}
-static bool wm_app_template_has_userpref(const char *app_template)
-{
- /* Test if app template provides a userpref.blend. If not, we will
- * share user preferences with the rest of Blender. */
- if (!app_template && app_template[0]) {
- return false;
- }
-
- char app_template_path[FILE_MAX];
- if (!BKE_appdir_app_template_id_search(
- app_template, app_template_path, sizeof(app_template_path))) {
- return false;
- }
-
- char userpref_path[FILE_MAX];
- BLI_path_join(
- userpref_path, sizeof(userpref_path), app_template_path, BLENDER_USERPREF_FILE, NULL);
- return BLI_exists(userpref_path);
-}
-
/**
* Called on startup, (context entirely filled with NULLs)
* or called for 'New File' both startup.blend and userpref.blend are checked.
@@ -758,6 +765,7 @@ void wm_homefile_read(bContext *C,
ReportList *reports,
bool use_factory_settings,
bool use_empty_data,
+ bool use_data,
bool use_userdef,
const char *filepath_startup_override,
const char *app_template_override,
@@ -788,7 +796,14 @@ void wm_homefile_read(bContext *C,
* And in this case versioning code is to be run.
*/
bool read_userdef_from_memory = false;
- eBLOReadSkip skip_flags = use_userdef ? 0 : BLO_READ_SKIP_USERDEF;
+ eBLOReadSkip skip_flags = 0;
+
+ if (use_data == false) {
+ skip_flags |= BLO_READ_SKIP_DATA;
+ }
+ if (use_userdef == false) {
+ skip_flags |= BLO_READ_SKIP_USERDEF;
+ }
/* True if we load startup.blend from memory
* or use app-template startup.blend which the user hasn't saved. */
@@ -801,14 +816,16 @@ void wm_homefile_read(bContext *C,
SET_FLAG_FROM_TEST(G.f, (U.flag & USER_SCRIPT_AUTOEXEC_DISABLE) == 0, G_FLAG_SCRIPT_AUTOEXEC);
}
- BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_LOAD_PRE);
+ if (use_data) {
+ BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_LOAD_PRE);
- UI_view2d_zoom_cache_reset();
+ G.relbase_valid = 0;
- G.relbase_valid = 0;
+ /* put aside screens to match with persistent windows later */
+ wm_window_match_init(C, &wmbase);
+ }
- /* put aside screens to match with persistent windows later */
- wm_window_match_init(C, &wmbase);
+ UI_view2d_zoom_cache_reset();
filepath_startup[0] = '\0';
filepath_userdef[0] = '\0';
@@ -931,7 +948,9 @@ void wm_homefile_read(bContext *C,
}
if (success) {
if (update_defaults) {
- BLO_update_defaults_startup_blend(CTX_data_main(C), app_template);
+ if (use_data) {
+ BLO_update_defaults_startup_blend(CTX_data_main(C), app_template);
+ }
}
is_factory_startup = filepath_startup_is_factory;
}
@@ -1010,10 +1029,12 @@ void wm_homefile_read(bContext *C,
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;
+ if (use_data) {
+ /* 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;
+ }
bmain = CTX_data_main(C);
@@ -1023,8 +1044,10 @@ void wm_homefile_read(bContext *C,
reset_app_template = true;
}
- /* match the read WM with current WM */
- wm_window_match_do(C, &wmbase, &bmain->wm, &bmain->wm);
+ if (use_data) {
+ /* match the read WM with current WM */
+ wm_window_match_do(C, &wmbase, &bmain->wm, &bmain->wm);
+ }
if (use_factory_settings) {
/* Clear keymaps because the current default keymap may have been initialized
@@ -1036,14 +1059,16 @@ void wm_homefile_read(bContext *C,
}
}
- WM_check(C); /* opens window(s), checks keymaps */
+ if (use_data) {
+ WM_check(C); /* opens window(s), checks keymaps */
- bmain->name[0] = '\0';
+ bmain->name[0] = '\0';
- /* start with save preference untitled.blend */
- G.save_over = 0;
+ /* start with save preference untitled.blend */
+ G.save_over = 0;
+ }
- wm_file_read_post(C, true, is_factory_startup, reset_app_template);
+ wm_file_read_post(C, true, is_factory_startup, use_data, use_userdef, reset_app_template);
if (r_is_factory_startup) {
*r_is_factory_startup = is_factory_startup;
@@ -1245,7 +1270,6 @@ static ImBuf *blend_file_thumb(const bContext *C,
BLEN_THUMB_SIZE * 2,
BLEN_THUMB_SIZE * 2,
IB_rect,
- V3D_OFSDRAW_NONE,
R_ALPHAPREMUL,
0,
NULL,
@@ -1653,6 +1677,7 @@ static int wm_userpref_autoexec_add_exec(bContext *UNUSED(C), wmOperator *UNUSED
{
bPathCompare *path_cmp = MEM_callocN(sizeof(bPathCompare), "bPathCompare");
BLI_addtail(&U.autoexec_paths, path_cmp);
+ U.runtime.is_dirty = true;
return OPERATOR_FINISHED;
}
@@ -1673,6 +1698,7 @@ static int wm_userpref_autoexec_remove_exec(bContext *UNUSED(C), wmOperator *op)
bPathCompare *path_cmp = BLI_findlink(&U.autoexec_paths, index);
if (path_cmp) {
BLI_freelinkN(&U.autoexec_paths, path_cmp);
+ U.runtime.is_dirty = true;
}
return OPERATOR_FINISHED;
}
@@ -1694,69 +1720,141 @@ void WM_OT_userpref_autoexec_path_remove(wmOperatorType *ot)
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 = true;
- bool use_template_userpref = wm_app_template_has_userpref(U.app_template);
- /* update keymaps in user preferences */
+ /* Update keymaps in user preferences. */
WM_keyconfig_update(wm);
- if ((cfgdir = BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL))) {
- bool ok_write;
- BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_USERPREF_FILE, NULL);
+ const bool ok = BKE_blendfile_userdef_write_all(op->reports);
- printf("Writing userprefs: '%s' ", filepath);
- if (use_template_userpref) {
- ok_write = BKE_blendfile_userdef_write_app_template(filepath, op->reports);
- }
- else {
- ok_write = BKE_blendfile_userdef_write(filepath, op->reports);
- }
+ return ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+}
- if (ok_write) {
- printf("ok\n");
- }
- else {
- printf("fail\n");
- ok = false;
- }
- }
- else {
- BKE_report(op->reports, RPT_ERROR, "Unable to create userpref path");
- }
+void WM_OT_save_userpref(wmOperatorType *ot)
+{
+ ot->name = "Save Preferences";
+ ot->idname = "WM_OT_save_userpref";
+ ot->description = "Save preferences separately, overrides startup file preferences";
- if (use_template_userpref) {
- if ((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);
+ ot->invoke = WM_operator_confirm;
+ ot->exec = wm_userpref_write_exec;
+}
- printf("Writing userprefs app-template: '%s' ", filepath);
- if (BKE_blendfile_userdef_write(filepath, op->reports) != 0) {
- printf("ok\n");
+static void rna_struct_update_when_changed(bContext *C,
+ Main *bmain,
+ PointerRNA *ptr_a,
+ PointerRNA *ptr_b)
+{
+ CollectionPropertyIterator iter;
+ PropertyRNA *iterprop = RNA_struct_iterator_property(ptr_a->type);
+ BLI_assert(ptr_a->type == ptr_b->type);
+ RNA_property_collection_begin(ptr_a, iterprop, &iter);
+ for (; iter.valid; RNA_property_collection_next(&iter)) {
+ PropertyRNA *prop = iter.ptr.data;
+ if (STREQ(RNA_property_identifier(prop), "rna_type")) {
+ continue;
+ }
+ switch (RNA_property_type(prop)) {
+ case PROP_POINTER: {
+ PointerRNA ptr_sub_a = RNA_property_pointer_get(ptr_a, prop);
+ PointerRNA ptr_sub_b = RNA_property_pointer_get(ptr_b, prop);
+ rna_struct_update_when_changed(C, bmain, &ptr_sub_a, &ptr_sub_b);
+ break;
}
- else {
- printf("fail\n");
- ok = false;
+ case PROP_COLLECTION:
+ /* Don't handle collections. */
+ break;
+ default: {
+ if (!RNA_property_equals(bmain, ptr_a, ptr_b, prop, RNA_EQ_STRICT)) {
+ RNA_property_update(C, ptr_b, prop);
+ }
}
}
- else {
- BKE_report(op->reports, RPT_ERROR, "Unable to create app-template userpref path");
- ok = false;
- }
}
+ RNA_property_collection_end(&iter);
+}
- return ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+static void wm_userpref_update_when_changed(bContext *C,
+ Main *bmain,
+ UserDef *userdef_prev,
+ UserDef *userdef_curr)
+{
+ PointerRNA ptr_a, ptr_b;
+ RNA_pointer_create(NULL, &RNA_Preferences, userdef_prev, &ptr_a);
+ RNA_pointer_create(NULL, &RNA_Preferences, userdef_curr, &ptr_b);
+ const bool is_dirty = userdef_curr->runtime.is_dirty;
+
+ rna_struct_update_when_changed(C, bmain, &ptr_a, &ptr_b);
+
+#ifdef WITH_PYTHON
+ BPY_execute_string(C, (const char *[]){"addon_utils", NULL}, "addon_utils.reset_all()");
+#endif
+
+ WM_keyconfig_reload(C);
+ userdef_curr->runtime.is_dirty = is_dirty;
}
-void WM_OT_save_userpref(wmOperatorType *ot)
+static int wm_userpref_read_exec(bContext *C, wmOperator *op)
{
- ot->name = "Save Preferences";
- ot->idname = "WM_OT_save_userpref";
- ot->description = "Save preferences separately, overrides startup file preferences";
+ const bool use_data = false;
+ const bool use_userdef = true;
+ const bool use_factory_settings = STREQ(op->type->idname, "WM_OT_read_factory_userpref");
+
+ UserDef U_backup = U;
+
+ wm_homefile_read(C,
+ op->reports,
+ use_factory_settings,
+ false,
+ use_data,
+ use_userdef,
+ NULL,
+ WM_init_state_app_template_get(),
+ NULL);
+
+#define USERDEF_RESTORE(member) \
+ { \
+ U.member = U_backup.member; \
+ } \
+ ((void)0)
+
+ USERDEF_RESTORE(userpref);
+
+#undef USERDEF_RESTORE
+
+ Main *bmain = CTX_data_main(C);
+
+ wm_userpref_update_when_changed(C, bmain, &U_backup, &U);
+
+ if (use_factory_settings) {
+ U.runtime.is_dirty = true;
+ }
+
+ /* Needed to recalculate UI scaling values (eg, #UserDef.inv_dpi_fac). */
+ wm_window_clear_drawable(bmain->wm.first);
+
+ WM_event_add_notifier(C, NC_WINDOW, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void WM_OT_read_userpref(wmOperatorType *ot)
+{
+ ot->name = "Load Preferences";
+ ot->idname = "WM_OT_read_userpref";
+ ot->description = "Load last saved preferences";
ot->invoke = WM_operator_confirm;
- ot->exec = wm_userpref_write_exec;
+ ot->exec = wm_userpref_read_exec;
+}
+
+void WM_OT_read_factory_userpref(wmOperatorType *ot)
+{
+ ot->name = "Load Factory Preferences";
+ ot->idname = "WM_OT_read_factory_userpref";
+ ot->description = "Load default preferences";
+
+ ot->invoke = WM_operator_confirm;
+ ot->exec = wm_userpref_read_exec;
}
static int wm_history_file_read_exec(bContext *UNUSED(C), wmOperator *UNUSED(op))
@@ -1816,14 +1914,15 @@ static int wm_homefile_read_exec(bContext *C, wmOperator *op)
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");
+ const bool use_temporary_preferences = RNA_boolean_get(op->ptr, "use_temporary_preferences");
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 with own preferences. */
- use_userdef = wm_app_template_has_userpref(app_template) ||
- wm_app_template_has_userpref(U.app_template);
+ use_userdef = BKE_appdir_app_template_has_userpref(app_template) ||
+ BKE_appdir_app_template_has_userpref(U.app_template);
/* Turn override off, since we're explicitly loading a different app-template. */
WM_init_state_app_template_set(NULL);
@@ -1833,10 +1932,12 @@ static int wm_homefile_read_exec(bContext *C, wmOperator *op)
app_template = WM_init_state_app_template_get();
}
+ bool use_data = true;
wm_homefile_read(C,
op->reports,
use_factory_settings,
use_empty_data,
+ use_data,
use_userdef,
filepath,
app_template,
@@ -1844,20 +1945,56 @@ static int wm_homefile_read_exec(bContext *C, wmOperator *op)
if (use_splash) {
WM_init_splash(C);
}
+ SET_FLAG_FROM_TEST(G.f, use_temporary_preferences, G_FLAG_USERPREF_NO_SAVE_ON_EXIT);
+
return OPERATOR_FINISHED;
}
+static void wm_homefile_read_after_dialog_callback(bContext *C, void *user_data)
+{
+ WM_operator_name_call_with_properties(
+ C, "WM_OT_read_homefile", WM_OP_EXEC_DEFAULT, (IDProperty *)user_data);
+}
+
+static void wm_free_operator_properties_callback(void *user_data)
+{
+ IDProperty *properties = (IDProperty *)user_data;
+ IDP_FreeProperty(properties);
+}
+
static int wm_homefile_read_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
- wmWindowManager *wm = CTX_wm_manager(C);
- if (U.uiflag & USER_SAVE_PROMPT && !wm->file_saved) {
- return WM_operator_confirm_message(C, op, "Changes in current file will be lost. Continue?");
+ if (U.uiflag & USER_SAVE_PROMPT && wm_file_or_image_is_modified(C)) {
+ wmGenericCallback *callback = MEM_callocN(sizeof(*callback), __func__);
+ callback->exec = wm_homefile_read_after_dialog_callback;
+ callback->user_data = IDP_CopyProperty(op->properties);
+ callback->free_user_data = wm_free_operator_properties_callback;
+ wm_close_file_dialog(C, callback);
+ return OPERATOR_INTERFACE;
}
else {
return wm_homefile_read_exec(C, op);
}
}
+static void read_homefile_props(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ 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);
+
+ prop = RNA_def_boolean(ot->srna,
+ "use_temporary_preferences",
+ false,
+ "Temporary Preferences",
+ "Don't save preferences on exit");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+}
+
void WM_OT_read_homefile(wmOperatorType *ot)
{
PropertyRNA *prop;
@@ -1877,23 +2014,17 @@ void WM_OT_read_homefile(wmOperatorType *ot)
ot->srna, "load_ui", true, "Load UI", "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);
+ read_homefile_props(ot);
/* 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 preferences";
@@ -1901,12 +2032,7 @@ void WM_OT_read_factory_settings(wmOperatorType *ot)
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);
-
+ read_homefile_props(ot);
/* omit poll to run in background mode */
}
@@ -1939,13 +2065,88 @@ static bool wm_file_read_opwrap(bContext *C,
return success;
}
-/* currently fits in a pointer */
-struct FileRuntime {
- bool is_untrusted;
+/* Generic operator state utilities
+ *********************************************/
+
+static void create_operator_state(wmOperatorType *ot, int first_state)
+{
+ PropertyRNA *prop = RNA_def_int(
+ ot->srna, "state", first_state, INT32_MIN, INT32_MAX, "State", "", INT32_MIN, INT32_MAX);
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+}
+
+static int get_operator_state(wmOperator *op)
+{
+ return RNA_int_get(op->ptr, "state");
+}
+
+static void set_next_operator_state(wmOperator *op, int state)
+{
+ RNA_int_set(op->ptr, "state", state);
+}
+
+typedef struct OperatorDispatchTarget {
+ int state;
+ int (*run)(bContext *C, wmOperator *op);
+} OperatorDispatchTarget;
+
+static int operator_state_dispatch(bContext *C, wmOperator *op, OperatorDispatchTarget *targets)
+{
+ int state = get_operator_state(op);
+ for (int i = 0; targets[i].run; i++) {
+ OperatorDispatchTarget target = targets[i];
+ if (target.state == state) {
+ return target.run(C, op);
+ }
+ }
+ BLI_assert(false);
+ return OPERATOR_CANCELLED;
+}
+
+/* Open Mainfile operator
+ ********************************************/
+
+enum {
+ OPEN_MAINFILE_STATE_DISCARD_CHANGES,
+ OPEN_MAINFILE_STATE_SELECT_FILE_PATH,
+ OPEN_MAINFILE_STATE_OPEN,
};
-static int wm_open_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+static int wm_open_mainfile_dispatch(bContext *C, wmOperator *op);
+
+static void wm_open_mainfile_after_dialog_callback(bContext *C, void *user_data)
{
+ WM_operator_name_call_with_properties(
+ C, "WM_OT_open_mainfile", WM_OP_INVOKE_DEFAULT, (IDProperty *)user_data);
+}
+
+static int wm_open_mainfile__discard_changes(bContext *C, wmOperator *op)
+{
+ if (RNA_boolean_get(op->ptr, "display_file_selector")) {
+ set_next_operator_state(op, OPEN_MAINFILE_STATE_SELECT_FILE_PATH);
+ }
+ else {
+ set_next_operator_state(op, OPEN_MAINFILE_STATE_OPEN);
+ }
+
+ if (U.uiflag & USER_SAVE_PROMPT && wm_file_or_image_is_modified(C)) {
+ wmGenericCallback *callback = MEM_callocN(sizeof(*callback), __func__);
+ callback->exec = wm_open_mainfile_after_dialog_callback;
+ callback->user_data = IDP_CopyProperty(op->properties);
+ callback->free_user_data = wm_free_operator_properties_callback;
+ wm_close_file_dialog(C, callback);
+ return OPERATOR_INTERFACE;
+ }
+ else {
+ return wm_open_mainfile_dispatch(C, op);
+ }
+}
+
+static int wm_open_mainfile__select_file_path(bContext *C, wmOperator *op)
+{
+ set_next_operator_state(op, OPEN_MAINFILE_STATE_OPEN);
+
Main *bmain = CTX_data_main(C);
const char *openname = BKE_main_blendfile_path(bmain);
@@ -1973,7 +2174,7 @@ static int wm_open_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *U
return OPERATOR_RUNNING_MODAL;
}
-static int wm_open_mainfile_exec(bContext *C, wmOperator *op)
+static int wm_open_mainfile__open(bContext *C, wmOperator *op)
{
char filepath[FILE_MAX];
bool success;
@@ -2011,6 +2212,33 @@ static int wm_open_mainfile_exec(bContext *C, wmOperator *op)
}
}
+static OperatorDispatchTarget wm_open_mainfile_dispatch_targets[] = {
+ {OPEN_MAINFILE_STATE_DISCARD_CHANGES, wm_open_mainfile__discard_changes},
+ {OPEN_MAINFILE_STATE_SELECT_FILE_PATH, wm_open_mainfile__select_file_path},
+ {OPEN_MAINFILE_STATE_OPEN, wm_open_mainfile__open},
+ {0, NULL},
+};
+
+static int wm_open_mainfile_dispatch(bContext *C, wmOperator *op)
+{
+ return operator_state_dispatch(C, op, wm_open_mainfile_dispatch_targets);
+}
+
+static int wm_open_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ return wm_open_mainfile_dispatch(C, op);
+}
+
+static int wm_open_mainfile_exec(bContext *C, wmOperator *op)
+{
+ return wm_open_mainfile__open(C, op);
+}
+
+/* currently fits in a pointer */
+struct FileRuntime {
+ bool is_untrusted;
+};
+
static bool wm_open_mainfile_check(bContext *UNUSED(C), wmOperator *op)
{
struct FileRuntime *file_info = (struct FileRuntime *)&op->customdata;
@@ -2091,6 +2319,12 @@ void WM_OT_open_mainfile(wmOperatorType *ot)
"Trusted Source",
"Allow .blend file to execute scripts automatically, default available from "
"system preferences");
+
+ PropertyRNA *prop = RNA_def_boolean(
+ ot->srna, "display_file_selector", true, "Display File Selector", "");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
+ create_operator_state(ot, OPEN_MAINFILE_STATE_DISCARD_CHANGES);
}
/** \} */
@@ -2629,9 +2863,228 @@ void wm_test_autorun_warning(bContext *C)
if (win) {
wmWindow *prevwin = CTX_wm_window(C);
CTX_wm_window_set(C, win);
- UI_popup_block_invoke(C, block_create_autorun_warning, NULL);
+ UI_popup_block_invoke(C, block_create_autorun_warning, NULL, NULL);
CTX_wm_window_set(C, prevwin);
}
}
+/* Close File Dialog
+ *************************************/
+
+static char save_images_when_file_is_closed = true;
+
+static void wm_block_file_close_cancel(bContext *C, void *arg_block, void *UNUSED(arg_data))
+{
+ wmWindow *win = CTX_wm_window(C);
+ UI_popup_block_close(C, win, arg_block);
+}
+
+static void wm_block_file_close_discard(bContext *C, void *arg_block, void *arg_data)
+{
+ wmGenericCallback *callback = WM_generic_callback_steal((wmGenericCallback *)arg_data);
+
+ /* Close the popup before executing the callback. Otherwise
+ * the popup might be closed by the callback, which will lead
+ * to a crash. */
+ wmWindow *win = CTX_wm_window(C);
+ UI_popup_block_close(C, win, arg_block);
+
+ callback->exec(C, callback->user_data);
+ WM_generic_callback_free(callback);
+}
+
+static void wm_block_file_close_save(bContext *C, void *arg_block, void *arg_data)
+{
+ wmGenericCallback *callback = WM_generic_callback_steal((wmGenericCallback *)arg_data);
+ bool execute_callback = true;
+
+ wmWindow *win = CTX_wm_window(C);
+ UI_popup_block_close(C, win, arg_block);
+
+ if (save_images_when_file_is_closed) {
+ ReportList *reports = CTX_wm_reports(C);
+ if (!ED_image_save_all_modified(C, reports)) {
+ execute_callback = false;
+ }
+ WM_report_banner_show();
+ }
+
+ Main *bmain = CTX_data_main(C);
+ bool file_has_been_saved_before = BKE_main_blendfile_path(bmain)[0] != '\0';
+
+ if (file_has_been_saved_before) {
+ WM_operator_name_call(C, "WM_OT_save_mainfile", WM_OP_EXEC_DEFAULT, NULL);
+ }
+ else {
+ WM_operator_name_call(C, "WM_OT_save_mainfile", WM_OP_INVOKE_DEFAULT, NULL);
+ execute_callback = false;
+ }
+
+ if (execute_callback) {
+ callback->exec(C, callback->user_data);
+ }
+ WM_generic_callback_free(callback);
+}
+
+static void wm_block_file_close_cancel_button(uiBlock *block, wmGenericCallback *post_action)
+{
+ uiBut *but = uiDefIconTextBut(
+ block, UI_BTYPE_BUT, 0, 0, IFACE_("Cancel"), 0, 0, 0, UI_UNIT_Y, 0, 0, 0, 0, 0, "");
+ UI_but_func_set(but, wm_block_file_close_cancel, block, post_action);
+ UI_but_drawflag_disable(but, UI_BUT_TEXT_LEFT);
+}
+
+static void wm_block_file_close_discard_button(uiBlock *block, wmGenericCallback *post_action)
+{
+ uiBut *but = uiDefIconTextBut(
+ block, UI_BTYPE_BUT, 0, 0, IFACE_("Discard Changes"), 0, 0, 0, UI_UNIT_Y, 0, 0, 0, 0, 0, "");
+ UI_but_func_set(but, wm_block_file_close_discard, block, post_action);
+ UI_but_drawflag_disable(but, UI_BUT_TEXT_LEFT);
+}
+
+static void wm_block_file_close_save_button(uiBlock *block, wmGenericCallback *post_action)
+{
+ uiBut *but = uiDefIconTextBut(
+ block, UI_BTYPE_BUT, 0, 0, IFACE_("Save"), 0, 0, 0, UI_UNIT_Y, 0, 0, 0, 0, 0, "");
+ UI_but_func_set(but, wm_block_file_close_save, block, post_action);
+ UI_but_drawflag_disable(but, UI_BUT_TEXT_LEFT);
+ UI_but_flag_enable(but, UI_BUT_ACTIVE_DEFAULT);
+}
+
+static const char *close_file_dialog_name = "file_close_popup";
+
+static uiBlock *block_create__close_file_dialog(struct bContext *C, struct ARegion *ar, void *arg1)
+{
+ wmGenericCallback *post_action = (wmGenericCallback *)arg1;
+ Main *bmain = CTX_data_main(C);
+
+ uiStyle *style = UI_style_get();
+ uiBlock *block = UI_block_begin(C, ar, close_file_dialog_name, UI_EMBOSS);
+
+ UI_block_flag_enable(
+ block, UI_BLOCK_KEEP_OPEN | UI_BLOCK_LOOP | UI_BLOCK_NO_WIN_CLIP | UI_BLOCK_NUMSELECT);
+ UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP);
+ UI_block_emboss_set(block, UI_EMBOSS);
+
+ uiLayout *layout = UI_block_layout(block,
+ UI_LAYOUT_VERTICAL,
+ UI_LAYOUT_PANEL,
+ 10,
+ 2,
+ U.widget_unit * 24,
+ U.widget_unit * 6,
+ 0,
+ style);
+
+ /* Title */
+ bool blend_file_is_saved = BKE_main_blendfile_path(bmain)[0] != '\0';
+ if (blend_file_is_saved) {
+ uiItemL(layout, "This file has unsaved changes.", ICON_INFO);
+ }
+ else {
+ uiItemL(layout, "This file has not been saved yet.", ICON_INFO);
+ }
+
+ /* Image Saving */
+ ReportList reports;
+ BKE_reports_init(&reports, RPT_STORE);
+ uint modified_images_count = ED_image_save_all_modified_info(C, &reports);
+
+ if (modified_images_count > 0) {
+ char message[64];
+ BLI_snprintf(message,
+ sizeof(message),
+ (modified_images_count == 1) ? "Save %u modified image" :
+ "Save %u modified images",
+ modified_images_count);
+ uiDefButBitC(block,
+ UI_BTYPE_CHECKBOX,
+ 1,
+ 0,
+ message,
+ 0,
+ 0,
+ 0,
+ UI_UNIT_Y,
+ &save_images_when_file_is_closed,
+ 0,
+ 0,
+ 0,
+ 0,
+ "");
+
+ LISTBASE_FOREACH (Report *, report, &reports.list) {
+ uiItemL(layout, report->message, ICON_ERROR);
+ }
+ }
+
+ BKE_reports_clear(&reports);
+
+ uiItemL(layout, "", ICON_NONE);
+
+ /* Buttons */
+#ifdef _WIN32
+ const bool windows_layout = true;
+#else
+ const bool windows_layout = false;
+#endif
+
+ uiLayout *split = uiLayoutSplit(layout, 0.0f, true);
+
+ if (windows_layout) {
+ /* Windows standard layout. */
+ uiLayout *col = uiLayoutColumn(split, false);
+ uiItemS(col);
+
+ col = uiLayoutColumn(split, false);
+ wm_block_file_close_save_button(block, post_action);
+
+ col = uiLayoutColumn(split, false);
+ wm_block_file_close_discard_button(block, post_action);
+
+ col = uiLayoutColumn(split, false);
+ wm_block_file_close_cancel_button(block, post_action);
+ }
+ else {
+ /* macOS and Linux standard layout. */
+ uiLayout *col = uiLayoutColumn(split, false);
+ wm_block_file_close_discard_button(block, post_action);
+
+ col = uiLayoutColumn(split, false);
+ uiItemS(col);
+
+ col = uiLayoutColumn(split, false);
+ wm_block_file_close_cancel_button(block, post_action);
+
+ col = uiLayoutColumn(split, false);
+ wm_block_file_close_save_button(block, post_action);
+ }
+
+ UI_block_bounds_set_centered(block, 10);
+ return block;
+}
+
+static void free_post_file_close_action(void *arg)
+{
+ wmGenericCallback *action = (wmGenericCallback *)arg;
+ WM_generic_callback_free(action);
+}
+
+void wm_close_file_dialog(bContext *C, wmGenericCallback *post_action)
+{
+ if (!UI_popup_block_name_exists(C, close_file_dialog_name)) {
+ UI_popup_block_invoke(
+ C, block_create__close_file_dialog, post_action, free_post_file_close_action);
+ }
+ else {
+ WM_generic_callback_free(post_action);
+ }
+}
+
+bool wm_file_or_image_is_modified(const bContext *C)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ return !wm->file_saved || ED_image_should_save_modified(C);
+}
+
/** \} */
diff --git a/source/blender/windowmanager/intern/wm_gesture.c b/source/blender/windowmanager/intern/wm_gesture.c
index b12bb89ea9f..e117a1bcdfe 100644
--- a/source/blender/windowmanager/intern/wm_gesture.c
+++ b/source/blender/windowmanager/intern/wm_gesture.c
@@ -62,7 +62,7 @@ wmGesture *WM_gesture_new(bContext *C, const wmEvent *event, int type)
gesture->type = type;
gesture->event_type = event->type;
gesture->winrct = ar->winrct;
- gesture->userdata_free = true; /* Free if userdata is set. */
+ gesture->user_data.use_free = true; /* Free if userdata is set. */
gesture->modal_state = GESTURE_MODAL_NOP;
if (ELEM(type,
@@ -106,9 +106,7 @@ void WM_gesture_end(bContext *C, wmGesture *gesture)
}
BLI_remlink(&win->gesture, gesture);
MEM_freeN(gesture->customdata);
- if (gesture->userdata && gesture->userdata_free) {
- MEM_freeN(gesture->userdata);
- }
+ WM_generic_user_data_free(&gesture->user_data);
MEM_freeN(gesture);
}
diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c
index 97ba9190351..04a3115992f 100644
--- a/source/blender/windowmanager/intern/wm_init_exit.c
+++ b/source/blender/windowmanager/intern/wm_init_exit.c
@@ -52,6 +52,7 @@
#include "BLO_writefile.h"
#include "BLO_undofile.h"
+#include "BKE_blendfile.h"
#include "BKE_blender.h"
#include "BKE_blender_undo.h"
#include "BKE_context.h"
@@ -254,11 +255,15 @@ void WM_init(bContext *C, int argc, const char **argv)
/* get the default database, plus a wm */
bool is_factory_startup = true;
+ const bool use_data = true;
+ const bool use_userdef = true;
+
wm_homefile_read(C,
NULL,
G.factory_startup,
false,
- true,
+ use_data,
+ use_userdef,
NULL,
WM_init_state_app_template_get(),
&is_factory_startup);
@@ -469,6 +474,14 @@ void WM_exit_ext(bContext *C, const bool do_python)
WM_event_remove_handlers(C, &win->modalhandlers);
ED_screen_exit(C, win, WM_window_get_active_screen(win));
}
+
+ if (!G.background) {
+ if ((U.pref_flag & USER_PREF_FLAG_SAVE) && ((G.f & G_FLAG_USERPREF_NO_SAVE_ON_EXIT) == 0)) {
+ if (U.runtime.is_dirty) {
+ BKE_blendfile_userdef_write_all(NULL);
+ }
+ }
+ }
}
BLI_timer_free();
diff --git a/source/blender/windowmanager/intern/wm_keymap.c b/source/blender/windowmanager/intern/wm_keymap.c
index bae9a5de1e6..a4ee735d911 100644
--- a/source/blender/windowmanager/intern/wm_keymap.c
+++ b/source/blender/windowmanager/intern/wm_keymap.c
@@ -310,6 +310,7 @@ bool WM_keyconfig_remove(wmWindowManager *wm, wmKeyConfig *keyconf)
if (BLI_findindex(&wm->keyconfigs, keyconf) != -1) {
if (STREQLEN(U.keyconfigstr, keyconf->idname, sizeof(U.keyconfigstr))) {
BLI_strncpy(U.keyconfigstr, wm->defaultconf->idname, sizeof(U.keyconfigstr));
+ U.runtime.is_dirty = true;
WM_keyconfig_update_tag(NULL, NULL);
}
@@ -360,6 +361,9 @@ void WM_keyconfig_set_active(wmWindowManager *wm, const char *idname)
WM_keyconfig_update(wm);
BLI_strncpy(U.keyconfigstr, idname, sizeof(U.keyconfigstr));
+ if (wm->initialized & WM_KEYCONFIG_IS_INITIALIZED) {
+ U.runtime.is_dirty = true;
+ }
WM_keyconfig_update_tag(NULL, NULL);
WM_keyconfig_update(wm);
@@ -1120,7 +1124,8 @@ const char *WM_key_event_string(const short type, const bool compact)
if (platform == MACOS) {
icon_glyph = "\xe2\x87\xa7";
}
- return key_event_icon_or_text(font_id, IFACE_("Shift"), icon_glyph);
+ return key_event_icon_or_text(
+ font_id, CTX_IFACE_(BLT_I18NCONTEXT_ID_WINDOWMANAGER, "Shift"), icon_glyph);
}
case LEFTCTRLKEY:
case RIGHTCTRLKEY:
@@ -1407,7 +1412,6 @@ static wmKeyMapItem *wm_keymap_item_find_in_keymap(wmKeyMap *keymap,
}
IDP_FreeProperty(properties_default);
- MEM_freeN(properties_default);
}
}
}
@@ -1581,7 +1585,6 @@ static wmKeyMapItem *wm_keymap_item_find(const bContext *C,
}
IDP_FreeProperty(properties_temp);
- MEM_freeN(properties_temp);
}
}
@@ -1620,7 +1623,6 @@ static wmKeyMapItem *wm_keymap_item_find(const bContext *C,
}
IDP_FreeProperty(properties_default);
- MEM_freeN(properties_default);
}
}
}
@@ -2017,7 +2019,6 @@ void WM_keymap_item_restore_to_default(bContext *C, wmKeyMap *keymap, wmKeyMapIt
if (orig->properties) {
if (kmi->properties) {
IDP_FreeProperty(kmi->properties);
- MEM_freeN(kmi->properties);
kmi->properties = NULL;
}
diff --git a/source/blender/windowmanager/intern/wm_operator_props.c b/source/blender/windowmanager/intern/wm_operator_props.c
index ece57f5a63b..3ad7247d993 100644
--- a/source/blender/windowmanager/intern/wm_operator_props.c
+++ b/source/blender/windowmanager/intern/wm_operator_props.c
@@ -94,7 +94,9 @@ void WM_operator_properties_filesel(wmOperatorType *ot,
}
if (flag & WM_FILESEL_FILES) {
- RNA_def_collection_runtime(ot->srna, "files", &RNA_OperatorFileListElement, "Files", "");
+ prop = RNA_def_collection_runtime(
+ ot->srna, "files", &RNA_OperatorFileListElement, "Files", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
if (action == FILE_SAVE) {
@@ -344,11 +346,11 @@ void WM_operator_properties_gesture_box(wmOperatorType *ot)
void WM_operator_properties_select_operation(wmOperatorType *ot)
{
static const EnumPropertyItem select_mode_items[] = {
- {SEL_OP_SET, "SET", 0, "New", ""},
- {SEL_OP_ADD, "ADD", 0, "Add", ""},
- {SEL_OP_SUB, "SUB", 0, "Subtract", ""},
- {SEL_OP_XOR, "XOR", 0, "Difference", ""},
- {SEL_OP_AND, "AND", 0, "Intersect", ""},
+ {SEL_OP_SET, "SET", ICON_SELECT_SET, "Set", "Set a new selection"},
+ {SEL_OP_ADD, "ADD", ICON_SELECT_EXTEND, "Extend", "Extend existing selection"},
+ {SEL_OP_SUB, "SUB", ICON_SELECT_SUBTRACT, "Subtract", "Subtract existing selection"},
+ {SEL_OP_XOR, "XOR", ICON_SELECT_DIFFERENCE, "Difference", "Inverts existing selection"},
+ {SEL_OP_AND, "AND", ICON_SELECT_INTERSECT, "Intersect", "Intersect existing selection"},
{0, NULL, 0, NULL, NULL},
};
PropertyRNA *prop = RNA_def_enum(ot->srna, "mode", select_mode_items, SEL_OP_SET, "Mode", "");
@@ -359,9 +361,9 @@ void WM_operator_properties_select_operation(wmOperatorType *ot)
void WM_operator_properties_select_operation_simple(wmOperatorType *ot)
{
static const EnumPropertyItem select_mode_items[] = {
- {SEL_OP_SET, "SET", 0, "New", ""},
- {SEL_OP_ADD, "ADD", 0, "Add", ""},
- {SEL_OP_SUB, "SUB", 0, "Subtract", ""},
+ {SEL_OP_SET, "SET", ICON_SELECT_SET, "Set", "Set a new selection"},
+ {SEL_OP_ADD, "ADD", ICON_SELECT_EXTEND, "Extend", "Extend existing selection"},
+ {SEL_OP_SUB, "SUB", ICON_SELECT_SUBTRACT, "Subtract", "Subtract existing selection"},
{0, NULL, 0, NULL, NULL},
};
PropertyRNA *prop = RNA_def_enum(ot->srna, "mode", select_mode_items, SEL_OP_SET, "Mode", "");
diff --git a/source/blender/windowmanager/intern/wm_operator_type.c b/source/blender/windowmanager/intern/wm_operator_type.c
index 3585cffc615..179b4402200 100644
--- a/source/blender/windowmanager/intern/wm_operator_type.c
+++ b/source/blender/windowmanager/intern/wm_operator_type.c
@@ -156,7 +156,6 @@ void WM_operatortype_remove_ptr(wmOperatorType *ot)
if (ot->last_properties) {
IDP_FreeProperty(ot->last_properties);
- MEM_freeN(ot->last_properties);
}
if (ot->macro.first) {
@@ -194,7 +193,6 @@ static void operatortype_ghash_free_cb(wmOperatorType *ot)
{
if (ot->last_properties) {
IDP_FreeProperty(ot->last_properties);
- MEM_freeN(ot->last_properties);
}
if (ot->macro.first) {
@@ -279,7 +277,6 @@ void WM_operatortype_last_properties_clear_all(void)
if (ot->last_properties) {
IDP_FreeProperty(ot->last_properties);
- MEM_freeN(ot->last_properties);
ot->last_properties = NULL;
}
}
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index ec803c9bba7..4a99c2de6e7 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -691,7 +691,6 @@ void WM_operator_properties_free(PointerRNA *ptr)
if (properties) {
IDP_FreeProperty(properties);
- MEM_freeN(properties);
ptr->data = NULL; /* just in case */
}
}
@@ -870,7 +869,7 @@ int WM_enum_search_invoke_previews(bContext *C, wmOperator *op, short prv_cols,
search_menu.prv_cols = prv_cols;
search_menu.prv_rows = prv_rows;
- UI_popup_block_invoke(C, wm_enum_search_menu, &search_menu);
+ UI_popup_block_invoke(C, wm_enum_search_menu, &search_menu, NULL);
return OPERATOR_INTERFACE;
}
@@ -879,13 +878,17 @@ int WM_enum_search_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(eve
{
static struct EnumSearchMenu search_menu;
search_menu.op = op;
- UI_popup_block_invoke(C, wm_enum_search_menu, &search_menu);
+ UI_popup_block_invoke(C, wm_enum_search_menu, &search_menu, NULL);
return OPERATOR_INTERFACE;
}
/* Can't be used as an invoke directly, needs message arg (can be NULL) */
-int WM_operator_confirm_message_ex(
- bContext *C, wmOperator *op, const char *title, const int icon, const char *message)
+int WM_operator_confirm_message_ex(bContext *C,
+ wmOperator *op,
+ const char *title,
+ const int icon,
+ const char *message,
+ const short opcontext)
{
uiPopupMenu *pup;
uiLayout *layout;
@@ -900,8 +903,7 @@ int WM_operator_confirm_message_ex(
pup = UI_popup_menu_begin(C, title, icon);
layout = UI_popup_menu_layout(pup);
- uiItemFullO_ptr(
- layout, op->type, message, ICON_NONE, properties, WM_OP_EXEC_REGION_WIN, 0, NULL);
+ uiItemFullO_ptr(layout, op->type, message, ICON_NONE, properties, opcontext, 0, NULL);
UI_popup_menu_end(C, pup);
return OPERATOR_INTERFACE;
@@ -909,7 +911,8 @@ int WM_operator_confirm_message_ex(
int WM_operator_confirm_message(bContext *C, wmOperator *op, const char *message)
{
- return WM_operator_confirm_message_ex(C, op, IFACE_("OK?"), ICON_QUESTION, message);
+ return WM_operator_confirm_message_ex(
+ C, op, IFACE_("OK?"), ICON_QUESTION, message, WM_OP_EXEC_REGION_WIN);
}
int WM_operator_confirm(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
@@ -1398,7 +1401,7 @@ int WM_operator_redo_popup(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- UI_popup_block_invoke(C, wm_block_create_redo, op);
+ UI_popup_block_invoke(C, wm_block_create_redo, op, NULL);
return OPERATOR_CANCELLED;
}
@@ -1710,7 +1713,7 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar
static int wm_splash_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event))
{
- UI_popup_block_invoke(C, wm_block_create_splash, NULL);
+ UI_popup_block_invoke(C, wm_block_create_splash, NULL, NULL);
return OPERATOR_FINISHED;
}
@@ -1816,7 +1819,7 @@ static int wm_search_menu_invoke(bContext *C, wmOperator *UNUSED(op), const wmEv
data.size[0] = UI_searchbox_size_x() * 2;
data.size[1] = UI_searchbox_size_y();
- UI_popup_block_invoke(C, wm_block_search_menu, &data);
+ UI_popup_block_invoke(C, wm_block_search_menu, &data, NULL);
return OPERATOR_INTERFACE;
}
@@ -3082,8 +3085,7 @@ static void redraw_timer_step(bContext *C,
{
if (type == eRTDrawRegion) {
if (ar) {
- ED_region_do_draw(C, ar);
- ar->do_draw = false;
+ wm_draw_region_test(C, sa, ar);
}
}
else if (type == eRTDrawRegionSwap) {
@@ -3107,8 +3109,7 @@ static void redraw_timer_step(bContext *C,
for (ar_iter = sa_iter->regionbase.first; ar_iter; ar_iter = ar_iter->next) {
if (ar_iter->visible) {
CTX_wm_region_set(C, ar_iter);
- ED_region_do_draw(C, ar_iter);
- ar_iter->do_draw = false;
+ wm_draw_region_test(C, sa_iter, ar_iter);
}
}
}
@@ -3153,6 +3154,7 @@ static int redraw_timer_exec(bContext *C, wmOperator *op)
wmWindow *win = CTX_wm_window(C);
ScrArea *sa = CTX_wm_area(C);
ARegion *ar = CTX_wm_region(C);
+ wmWindowManager *wm = CTX_wm_manager(C);
double time_start, time_delta;
const int type = RNA_enum_get(op->ptr, "type");
const int iter = RNA_int_get(op->ptr, "iterations");
@@ -3166,6 +3168,8 @@ static int redraw_timer_exec(bContext *C, wmOperator *op)
time_start = PIL_check_seconds_timer();
+ wm_window_make_drawable(wm, win);
+
for (a = 0; a < iter; a++) {
redraw_timer_step(C, bmain, scene, depsgraph, win, sa, ar, type, cfra);
iter_steps += 1;
@@ -3504,6 +3508,8 @@ void wm_operatortypes_register(void)
WM_operatortype_append(WM_OT_read_factory_settings);
WM_operatortype_append(WM_OT_save_homefile);
WM_operatortype_append(WM_OT_save_userpref);
+ WM_operatortype_append(WM_OT_read_userpref);
+ WM_operatortype_append(WM_OT_read_factory_userpref);
WM_operatortype_append(WM_OT_userpref_autoexec_path_add);
WM_operatortype_append(WM_OT_userpref_autoexec_path_remove);
WM_operatortype_append(WM_OT_window_fullscreen_toggle);
diff --git a/source/blender/windowmanager/intern/wm_playanim.c b/source/blender/windowmanager/intern/wm_playanim.c
index 844316bc925..7cc44bcad99 100644
--- a/source/blender/windowmanager/intern/wm_playanim.c
+++ b/source/blender/windowmanager/intern/wm_playanim.c
@@ -1063,7 +1063,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
break;
}
- case GHOST_kEventQuit:
+ case GHOST_kEventQuitRequest:
case GHOST_kEventWindowClose: {
ps->go = false;
break;
diff --git a/source/blender/windowmanager/intern/wm_toolsystem.c b/source/blender/windowmanager/intern/wm_toolsystem.c
index f429415bee9..3ea58d8c4e5 100644
--- a/source/blender/windowmanager/intern/wm_toolsystem.c
+++ b/source/blender/windowmanager/intern/wm_toolsystem.c
@@ -574,6 +574,20 @@ void WM_toolsystem_refresh_active(bContext *C)
}
}
}
+
+ BKE_workspace_id_tag_all_visible(bmain, LIB_TAG_DOIT);
+
+ LISTBASE_FOREACH (WorkSpace *, workspace, &bmain->workspaces) {
+ if (workspace->id.tag & LIB_TAG_DOIT) {
+ workspace->id.tag &= ~LIB_TAG_DOIT;
+ /* Refresh to ensure data is initialized.
+ * This is needed because undo can load a state which no longer has the underlying DNA data
+ * needed for the tool (un-initialized paint-slots for eg), see: T64339. */
+ for (bToolRef *tref = workspace->tools.first; tref; tref = tref->next) {
+ toolsystem_refresh_ref(C, workspace, tref);
+ }
+ }
+ }
}
void WM_toolsystem_refresh_screen_area(WorkSpace *workspace, ViewLayer *view_layer, ScrArea *sa)
@@ -712,7 +726,7 @@ static const char *toolsystem_default_tool(const bToolKey *tkey)
case SPACE_IMAGE:
switch (tkey->mode) {
case SI_MODE_PAINT:
- return "builtin_brush.draw";
+ return "builtin_brush.Draw";
}
break;
case SPACE_NODE: {
diff --git a/source/blender/windowmanager/intern/wm_utils.c b/source/blender/windowmanager/intern/wm_utils.c
new file mode 100644
index 00000000000..c0ee1ec44db
--- /dev/null
+++ b/source/blender/windowmanager/intern/wm_utils.c
@@ -0,0 +1,71 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup wm
+ *
+ * Generic helper utilies that aren't assosiated with a particular area.
+ */
+
+#include "WM_types.h"
+#include "WM_api.h"
+
+#include "MEM_guardedalloc.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Generic Callback
+ * \{ */
+
+void WM_generic_callback_free(wmGenericCallback *callback)
+{
+ if (callback->free_user_data) {
+ callback->free_user_data(callback->user_data);
+ }
+ MEM_freeN(callback);
+}
+
+static void do_nothing(struct bContext *UNUSED(C), void *UNUSED(user_data))
+{
+}
+
+wmGenericCallback *WM_generic_callback_steal(wmGenericCallback *callback)
+{
+ wmGenericCallback *new_callback = MEM_dupallocN(callback);
+ callback->exec = do_nothing;
+ callback->free_user_data = NULL;
+ callback->user_data = NULL;
+ return new_callback;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Generic User Data
+ * \{ */
+
+void WM_generic_user_data_free(wmGenericUserData *wm_userdata)
+{
+ if (wm_userdata->data && wm_userdata->use_free) {
+ if (wm_userdata->free_fn) {
+ wm_userdata->free_fn(wm_userdata->data);
+ }
+ else {
+ MEM_freeN(wm_userdata->data);
+ }
+ }
+}
+
+/** \} */
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c
index e98067d78cc..7ae572e5685 100644
--- a/source/blender/windowmanager/intern/wm_window.c
+++ b/source/blender/windowmanager/intern/wm_window.c
@@ -61,6 +61,7 @@
#include "WM_types.h"
#include "wm.h"
#include "wm_draw.h"
+#include "wm_files.h"
#include "wm_window.h"
#include "wm_event_system.h"
@@ -356,150 +357,9 @@ wmWindow *wm_window_copy_test(bContext *C,
/** \name Quit Confirmation Dialog
* \{ */
-/** Cancel quitting and close the dialog */
-static void wm_block_confirm_quit_cancel(bContext *C, void *arg_block, void *UNUSED(arg))
+static void wm_save_file_on_quit_dialog_callback(bContext *C, void *UNUSED(user_data))
{
- wmWindow *win = CTX_wm_window(C);
- UI_popup_block_close(C, win, arg_block);
-}
-
-/** Discard the file changes and quit */
-ATTR_NORETURN
-static void wm_block_confirm_quit_discard(bContext *C, void *arg_block, void *UNUSED(arg))
-{
- wmWindow *win = CTX_wm_window(C);
- UI_popup_block_close(C, win, arg_block);
- WM_exit(C);
-}
-
-/* Save changes and quit */
-static void wm_block_confirm_quit_save(bContext *C, void *arg_block, void *UNUSED(arg))
-{
- PointerRNA props_ptr;
- wmWindow *win = CTX_wm_window(C);
-
- UI_popup_block_close(C, win, arg_block);
-
- wmOperatorType *ot = WM_operatortype_find("WM_OT_save_mainfile", false);
-
- WM_operator_properties_create_ptr(&props_ptr, ot);
- RNA_boolean_set(&props_ptr, "exit", true);
- /* No need for second confirmation popup. */
- RNA_boolean_set(&props_ptr, "check_existing", false);
- WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr);
- WM_operator_properties_free(&props_ptr);
-}
-
-/* Build the confirm dialog UI */
-static uiBlock *block_create_confirm_quit(struct bContext *C,
- struct ARegion *ar,
- void *UNUSED(arg1))
-{
- Main *bmain = CTX_data_main(C);
-
- uiStyle *style = UI_style_get();
- uiBlock *block = UI_block_begin(C, ar, "confirm_quit_popup", UI_EMBOSS);
-
- UI_block_flag_enable(
- block, UI_BLOCK_KEEP_OPEN | UI_BLOCK_LOOP | UI_BLOCK_NO_WIN_CLIP | UI_BLOCK_NUMSELECT);
- UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP);
- UI_block_emboss_set(block, UI_EMBOSS);
-
- uiLayout *layout = UI_block_layout(block,
- UI_LAYOUT_VERTICAL,
- UI_LAYOUT_PANEL,
- 10,
- 2,
- U.widget_unit * 24,
- U.widget_unit * 6,
- 0,
- style);
-
- /* Text and some vertical space */
- {
- char *message;
- if (BKE_main_blendfile_path(bmain)[0] == '\0') {
- message = BLI_strdup(IFACE_("This file has not been saved yet. Save before closing?"));
- }
- else {
- const char *basename = BLI_path_basename(BKE_main_blendfile_path(bmain));
- message = BLI_sprintfN(IFACE_("Save changes to \"%s\" before closing?"), basename);
- }
- uiItemL(layout, message, ICON_ERROR);
- MEM_freeN(message);
- }
-
- uiItemS(layout);
- uiItemS(layout);
-
- /* Buttons */
- uiBut *but;
-
- uiLayout *split = uiLayoutSplit(layout, 0.0f, true);
-
- uiLayout *col = uiLayoutColumn(split, false);
-
- but = uiDefIconTextBut(block,
- UI_BTYPE_BUT,
- 0,
- ICON_SCREEN_BACK,
- IFACE_("Cancel"),
- 0,
- 0,
- 0,
- UI_UNIT_Y,
- NULL,
- 0,
- 0,
- 0,
- 0,
- TIP_("Do not quit"));
- UI_but_func_set(but, wm_block_confirm_quit_cancel, block, NULL);
-
- /* empty space between buttons */
- col = uiLayoutColumn(split, false);
- uiItemS(col);
-
- col = uiLayoutColumn(split, 1);
- but = uiDefIconTextBut(block,
- UI_BTYPE_BUT,
- 0,
- ICON_CANCEL,
- IFACE_("Discard Changes"),
- 0,
- 0,
- 50,
- UI_UNIT_Y,
- NULL,
- 0,
- 0,
- 0,
- 0,
- TIP_("Discard changes and quit"));
- UI_but_func_set(but, wm_block_confirm_quit_discard, block, NULL);
-
- col = uiLayoutColumn(split, 1);
- but = uiDefIconTextBut(block,
- UI_BTYPE_BUT,
- 0,
- ICON_FILE_TICK,
- IFACE_("Save & Quit"),
- 0,
- 0,
- 50,
- UI_UNIT_Y,
- NULL,
- 0,
- 0,
- 0,
- 0,
- TIP_("Save and quit"));
- UI_but_func_set(but, wm_block_confirm_quit_save, block, NULL);
- UI_but_flag_enable(but, UI_BUT_ACTIVE_DEFAULT);
-
- UI_block_bounds_set_centered(block, 10);
-
- return block;
+ wm_exit_schedule_delayed(C);
}
/**
@@ -508,16 +368,9 @@ static uiBlock *block_create_confirm_quit(struct bContext *C,
*/
static void wm_confirm_quit(bContext *C)
{
- wmWindow *win = CTX_wm_window(C);
-
- if (GHOST_SupportsNativeDialogs() == 0) {
- if (!UI_popup_block_name_exists(C, "confirm_quit_popup")) {
- UI_popup_block_invoke(C, block_create_confirm_quit, NULL);
- }
- }
- else if (GHOST_confirmQuit(win->ghostwin)) {
- wm_exit_schedule_delayed(C);
- }
+ wmGenericCallback *action = MEM_callocN(sizeof(*action), __func__);
+ action->exec = wm_save_file_on_quit_dialog_callback;
+ wm_close_file_dialog(C, action);
}
/**
@@ -529,7 +382,6 @@ static void wm_confirm_quit(bContext *C)
*/
void wm_quit_with_optional_confirmation_prompt(bContext *C, wmWindow *win)
{
- wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win_ctx = CTX_wm_window(C);
/* The popup will be displayed in the context window which may not be set
@@ -537,7 +389,7 @@ void wm_quit_with_optional_confirmation_prompt(bContext *C, wmWindow *win)
CTX_wm_window_set(C, win);
if (U.uiflag & USER_SAVE_PROMPT) {
- if (!wm->file_saved && !G.background) {
+ if (wm_file_or_image_is_modified(C) && !G.background) {
wm_confirm_quit(C);
}
else {
@@ -672,6 +524,7 @@ void WM_window_set_dpi(wmWindow *win)
U.dpi = dpi / pixelsize;
U.virtual_pixel = (pixelsize == 1) ? VIRTUAL_PIXEL_NATIVE : VIRTUAL_PIXEL_DOUBLE;
U.dpi_fac = ((U.pixelsize * (float)U.dpi) / 72.0f);
+ U.inv_dpi_fac = 1.0f / U.dpi_fac;
/* Set user preferences globals for drawing, and for forward compatibility. */
U.widget_unit = (U.pixelsize * U.dpi * 20 + 36) / 72;
@@ -1264,8 +1117,25 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
GHOST_TEventType type = GHOST_GetEventType(evt);
int time = GHOST_GetEventTime(evt);
- if (type == GHOST_kEventQuit) {
- WM_exit(C);
+ if (type == GHOST_kEventQuitRequest) {
+ /* Find an active window to display quit dialog in. */
+ GHOST_WindowHandle ghostwin = GHOST_GetEventWindow(evt);
+ wmWindow *win;
+
+ if (ghostwin && GHOST_ValidWindow(g_system, ghostwin)) {
+ win = GHOST_GetWindowUserData(ghostwin);
+ }
+ else {
+ win = wm->winactive;
+ }
+
+ /* Display quit dialog or quit immediately. */
+ if (win) {
+ wm_quit_with_optional_confirmation_prompt(C, win);
+ }
+ else {
+ wm_exit_schedule_delayed(C);
+ }
}
else {
GHOST_WindowHandle ghostwin = GHOST_GetEventWindow(evt);