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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/windowmanager')
-rw-r--r--source/blender/windowmanager/CMakeLists.txt1
-rw-r--r--source/blender/windowmanager/SConscript4
-rw-r--r--source/blender/windowmanager/WM_api.h21
-rw-r--r--source/blender/windowmanager/WM_types.h1
-rw-r--r--source/blender/windowmanager/intern/wm.c4
-rw-r--r--source/blender/windowmanager/intern/wm_cursors.c18
-rw-r--r--source/blender/windowmanager/intern/wm_dragdrop.c2
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c8
-rw-r--r--source/blender/windowmanager/intern/wm_files.c397
-rw-r--r--source/blender/windowmanager/intern/wm_init_exit.c35
-rw-r--r--source/blender/windowmanager/intern/wm_keymap.c37
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c455
-rw-r--r--source/blender/windowmanager/intern/wm_playanim.c142
-rw-r--r--source/blender/windowmanager/intern/wm_stereo.c4
-rw-r--r--source/blender/windowmanager/intern/wm_window.c207
-rw-r--r--source/blender/windowmanager/wm_event_types.h1
-rw-r--r--source/blender/windowmanager/wm_files.h5
-rw-r--r--source/blender/windowmanager/wm_window.h8
18 files changed, 966 insertions, 384 deletions
diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt
index 5328e62367b..c5e8cbf1260 100644
--- a/source/blender/windowmanager/CMakeLists.txt
+++ b/source/blender/windowmanager/CMakeLists.txt
@@ -29,6 +29,7 @@ set(INC
../blenkernel
../blenlib
../blenloader
+ ../blentranslation
../compositor
../editors/include
../gpu
diff --git a/source/blender/windowmanager/SConscript b/source/blender/windowmanager/SConscript
index e05bc130c20..ec1b265d800 100644
--- a/source/blender/windowmanager/SConscript
+++ b/source/blender/windowmanager/SConscript
@@ -42,6 +42,7 @@ incs = [
'../blenkernel',
'../blenlib',
'../blenloader',
+ '../blentranslation',
'../compositor',
'../editors/include',
'../gpu',
@@ -55,7 +56,8 @@ incs = [
]
incs = ' '.join(incs)
-defs = env['BF_GL_DEFINITIONS']
+defs = []
+defs += env['BF_GL_DEFINITIONS']
if env['WITH_BF_PYTHON']:
defs.append('WITH_PYTHON')
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index 28e24e442ca..11407678e53 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -87,18 +87,19 @@ void WM_init_splash (struct bContext *C);
void WM_check (struct bContext *C);
-struct wmWindow *WM_window_open (struct bContext *C, const struct rcti *rect);
-
int WM_window_pixels_x (struct wmWindow *win);
int WM_window_pixels_y (struct wmWindow *win);
bool WM_window_is_fullscreen (struct wmWindow *win);
/* defines for 'type' WM_window_open_temp */
-#define WM_WINDOW_RENDER 0
-#define WM_WINDOW_USERPREFS 1
-// #define WM_WINDOW_FILESEL 2 // UNUSED
+enum {
+ WM_WINDOW_RENDER = 1,
+ WM_WINDOW_USERPREFS,
+ // WM_WINDOW_FILESEL // UNUSED
+};
-void WM_window_open_temp (struct bContext *C, struct rcti *position, int type);
+struct wmWindow *WM_window_open(struct bContext *C, const struct rcti *rect);
+struct wmWindow *WM_window_open_temp(struct bContext *C, const struct rcti *rect_init, int type);
/* returns true if draw method is triple buffer */
bool WM_is_draw_triple(struct wmWindow *win);
@@ -130,6 +131,7 @@ void WM_paint_cursor_end(struct wmWindowManager *wm, void *handle);
void WM_paint_cursor_tag_redraw(struct wmWindow *win, struct ARegion *ar);
void WM_cursor_warp (struct wmWindow *win, int x, int y);
+void WM_cursor_compatible_xy(wmWindow *win, int *x, int *y);
float WM_cursor_pressure (const struct wmWindow *win);
/* event map */
@@ -208,7 +210,9 @@ void wm_event_init_from_window(struct wmWindow *win, struct wmEvent *event);
/* at maximum, every timestep seconds it triggers event_type events */
struct wmTimer *WM_event_add_timer(struct wmWindowManager *wm, struct wmWindow *win, int event_type, double timestep);
+struct wmTimer *WM_event_add_timer_notifier(struct wmWindowManager *wm, struct wmWindow *win, unsigned int type, double timestep);
void WM_event_remove_timer(struct wmWindowManager *wm, struct wmWindow *win, struct wmTimer *timer);
+void WM_event_remove_timer_notifier(struct wmWindowManager *wm, struct wmWindow *win, struct wmTimer *timer);
void WM_event_timer_sleep(struct wmWindowManager *wm, struct wmWindow *win, struct wmTimer *timer, bool do_sleep);
/* operator api, default callbacks */
@@ -276,7 +280,7 @@ void WM_operator_properties_create(struct PointerRNA *ptr, const char *opstring
void WM_operator_properties_create_ptr(struct PointerRNA *ptr, struct wmOperatorType *ot);
void WM_operator_properties_clear(struct PointerRNA *ptr);
void WM_operator_properties_free(struct PointerRNA *ptr);
-void WM_operator_properties_filesel(struct wmOperatorType *ot, int filter, short type, short action, short flag, short display);
+void WM_operator_properties_filesel(struct wmOperatorType *ot, int filter, short type, short action, short flag, short display, short sort);
void WM_operator_properties_border(struct wmOperatorType *ot);
void WM_operator_properties_border_to_rcti(struct wmOperator *op, struct rcti *rect);
void WM_operator_properties_border_to_rctf(struct wmOperator *op, rctf *rect);
@@ -286,6 +290,7 @@ void WM_operator_properties_gesture_straightline(struct wmOperatorType *ot, int
void WM_operator_properties_select_all(struct wmOperatorType *ot);
void WM_operator_properties_select_action(struct wmOperatorType *ot, int default_action);
void WM_operator_properties_select_action_simple(struct wmOperatorType *ot, int default_action);
+void WM_operator_properties_select_random(struct wmOperatorType *ot);
bool WM_operator_check_ui_enabled(const struct bContext *C, const char *idname);
wmOperator *WM_operator_last_redo(const struct bContext *C);
@@ -415,7 +420,7 @@ enum {
WM_JOB_TYPE_OBJECT_SIM_FLUID,
WM_JOB_TYPE_OBJECT_BAKE_TEXTURE,
WM_JOB_TYPE_OBJECT_BAKE,
- WM_JOB_TYPE_FILESEL_THUMBNAIL,
+ WM_JOB_TYPE_FILESEL_READDIR,
WM_JOB_TYPE_CLIP_BUILD_PROXY,
WM_JOB_TYPE_CLIP_TRACK_MARKERS,
WM_JOB_TYPE_CLIP_SOLVE_CAMERA,
diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h
index 109ccc27d79..3c0e99bddd0 100644
--- a/source/blender/windowmanager/WM_types.h
+++ b/source/blender/windowmanager/WM_types.h
@@ -361,6 +361,7 @@ typedef struct wmNotifier {
#define ND_SPACE_NODE_VIEW (17<<16)
#define ND_SPACE_CHANGED (18<<16) /*sent to a new editor type after it's replaced an old one*/
#define ND_SPACE_CLIP (19<<16)
+#define ND_SPACE_FILE_PREVIEW (20<<16)
/* subtype, 256 entries too */
#define NOTE_SUBTYPE 0x0000FF00
diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c
index c8ff6dac754..b76a1f1d422 100644
--- a/source/blender/windowmanager/intern/wm.c
+++ b/source/blender/windowmanager/intern/wm.c
@@ -376,7 +376,7 @@ void WM_check(bContext *C)
}
/* case: no open windows at all, for old file reads */
- wm_window_add_ghostwindows(wm);
+ wm_window_ghostwindows_ensure(wm);
}
/* case: fileread */
@@ -467,11 +467,13 @@ void wm_close_and_free(bContext *C, wmWindowManager *wm)
void wm_close_and_free_all(bContext *C, ListBase *wmlist)
{
+ Main *bmain = CTX_data_main(C);
wmWindowManager *wm;
while ((wm = wmlist->first)) {
wm_close_and_free(C, wm);
BLI_remlink(wmlist, wm);
+ BKE_libblock_free_data(bmain, &wm->id);
MEM_freeN(wm);
}
}
diff --git a/source/blender/windowmanager/intern/wm_cursors.c b/source/blender/windowmanager/intern/wm_cursors.c
index d84b65847ca..d9466cbd035 100644
--- a/source/blender/windowmanager/intern/wm_cursors.c
+++ b/source/blender/windowmanager/intern/wm_cursors.c
@@ -199,14 +199,10 @@ void WM_cursor_grab_enable(wmWindow *win, bool wrap, bool hide, int bounds[4])
* It helps not to get a stuck WM when hitting a breakpoint
* */
GHOST_TGrabCursorMode mode = GHOST_kGrabNormal;
- float fac = GHOST_GetNativePixelSize(win->ghostwin);
- /* in case pixel coords differ from window/mouse coords */
if (bounds) {
- bounds[0] /= fac;
- bounds[1] /= fac;
- bounds[2] /= fac;
- bounds[3] /= fac;
+ wm_cursor_position_to_ghost(win, &bounds[0], &bounds[1]);
+ wm_cursor_position_to_ghost(win, &bounds[2], &bounds[3]);
}
if (hide) {
@@ -234,7 +230,15 @@ void WM_cursor_grab_disable(wmWindow *win, const int mouse_ungrab_xy[2])
{
if ((G.debug & G_DEBUG) == 0) {
if (win && win->ghostwin) {
- GHOST_SetCursorGrab(win->ghostwin, GHOST_kGrabDisable, NULL, mouse_ungrab_xy);
+ if (mouse_ungrab_xy) {
+ int mouse_xy[2] = {mouse_ungrab_xy[0], mouse_ungrab_xy[1]};
+ wm_cursor_position_to_ghost(win, &mouse_xy[0], &mouse_xy[1]);
+ GHOST_SetCursorGrab(win->ghostwin, GHOST_kGrabDisable, NULL, mouse_xy);
+ }
+ else {
+ GHOST_SetCursorGrab(win->ghostwin, GHOST_kGrabDisable, NULL, NULL);
+ }
+
win->grabcursor = GHOST_kGrabDisable;
}
}
diff --git a/source/blender/windowmanager/intern/wm_dragdrop.c b/source/blender/windowmanager/intern/wm_dragdrop.c
index cdc3c9eaaff..3a53906a8e8 100644
--- a/source/blender/windowmanager/intern/wm_dragdrop.c
+++ b/source/blender/windowmanager/intern/wm_dragdrop.c
@@ -37,7 +37,7 @@
#include "MEM_guardedalloc.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "BLI_blenlib.h"
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index ff67758db11..187c11ef3da 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -1801,7 +1801,13 @@ static int wm_handler_fileselect_do(bContext *C, ListBase *handlers, wmEventHand
const SpaceLink *sl = sa->spacedata.first;
const bool was_prev_temp = (sl->next && sl->next->spacetype == SPACE_IMAGE);
- ED_screen_full_prevspace(C, sa, was_prev_temp);
+ if (sa->full) {
+ ED_screen_full_prevspace(C, sa, was_prev_temp);
+ }
+ /* user may have left fullscreen */
+ else {
+ ED_area_prevspace(C, sa);
+ }
}
wm_handler_op_context(C, handler, CTX_wm_window(C)->eventstate);
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c
index 74be3bc6f5d..8288b2ed1ef 100644
--- a/source/blender/windowmanager/intern/wm_files.c
+++ b/source/blender/windowmanager/intern/wm_files.c
@@ -60,7 +60,7 @@
#include "BLI_system.h"
#include BLI_SYSTEM_PID_H
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "DNA_object_types.h"
#include "DNA_space_types.h"
@@ -76,10 +76,12 @@
#include "BKE_context.h"
#include "BKE_depsgraph.h"
#include "BKE_global.h"
+#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_packedFile.h"
#include "BKE_report.h"
#include "BKE_sound.h"
+#include "BKE_scene.h"
#include "BKE_screen.h"
#include "BLO_readfile.h"
@@ -105,6 +107,9 @@
#include "GPU_draw.h"
+/* only to report a missing engine */
+#include "RE_engine.h"
+
#ifdef WITH_PYTHON
#include "BPY_extern.h"
#endif
@@ -116,7 +121,11 @@
#include "wm_window.h"
#include "wm_event_system.h"
-static void write_history(void);
+static RecentFile *wm_file_history_find(const char *filepath);
+static void wm_history_file_free(RecentFile *recent);
+static void wm_history_file_update(void);
+static void wm_history_file_write(void);
+
/* To be able to read files without windows closing, opening, moving
* we try to prepare for worst case:
@@ -330,11 +339,13 @@ static void wm_init_userdef(bContext *C, const bool from_memory)
#define BKE_READ_EXOTIC_FAIL_FORMAT -2 /* file format is not supported */
#define BKE_READ_EXOTIC_FAIL_OPEN -1 /* Can't open the file */
#define BKE_READ_EXOTIC_OK_BLEND 0 /* .blend file */
+#if 0
#define BKE_READ_EXOTIC_OK_OTHER 1 /* other supported formats */
+#endif
/* intended to check for non-blender formats but for now it only reads blends */
-static int wm_read_exotic(Scene *UNUSED(scene), const char *name)
+static int wm_read_exotic(const char *name)
{
int len;
gzFile gzfile;
@@ -396,8 +407,108 @@ void WM_file_autoexec_init(const char *filepath)
}
}
+void wm_file_read_report(bContext *C)
+{
+ ReportList *reports = NULL;
+ Scene *sce;
+
+ for (sce = G.main->scene.first; sce; sce = sce->id.next) {
+ if (sce->r.engine[0] &&
+ BLI_findstring(&R_engines, sce->r.engine, offsetof(RenderEngineType, idname)) == NULL)
+ {
+ if (reports == NULL) {
+ reports = CTX_wm_reports(C);
+ }
+
+ BKE_reportf(reports, RPT_ERROR,
+ "Engine '%s' not available for scene '%s' "
+ "(an addon may need to be installed or enabled)",
+ sce->r.engine, sce->id.name + 2);
+ }
+ }
+
+ if (reports) {
+ if (!G.background) {
+ WM_report_banner_show(C);
+ }
+ }
+}
+
+/**
+ * Logic shared between #WM_file_read & #wm_homefile_read,
+ * updates to make after reading a file.
+ */
+static void wm_file_read_post(bContext *C, bool is_startup_file)
+{
+ 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);
+ }
+
+ CTX_wm_window_set(C, wm->windows.first);
+
+ ED_editors_init(C);
+ DAG_on_visible_update(CTX_data_main(C), true);
+
+#ifdef WITH_PYTHON
+ if (is_startup_file) {
+ /* possible python hasn't been initialized */
+ if (CTX_py_init_get(C)) {
+ /* sync addons, these may have changed from the defaults */
+ BPY_string_exec(C, "__import__('addon_utils').reset_all()");
+
+ BPY_python_reset(C);
+ addons_loaded = true;
+ }
+ }
+ else {
+ /* run any texts that were loaded in and flagged as modules */
+ BPY_python_reset(C);
+ addons_loaded = true;
+ }
+#endif /* WITH_PYTHON */
+
+ WM_operatortype_last_properties_clear_all();
+
+ /* important to do before NULL'ing the context */
+ BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_VERSION_UPDATE);
+ BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_LOAD_POST);
+
+ /* would otherwise be handled by event loop */
+ if (G.background) {
+ Main *bmain = CTX_data_main(C);
+ BKE_scene_update_tagged(bmain->eval_ctx, bmain, CTX_data_scene(C));
+ }
+
+ WM_event_add_notifier(C, NC_WM | ND_FILEREAD, NULL);
+
+ /* report any errors.
+ * currently disabled if addons aren't yet loaded */
+ if (addons_loaded) {
+ wm_file_read_report(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 (!G.background) {
+// undo_editmode_clear();
+ BKE_undo_reset();
+ BKE_undo_write(C, "original"); /* save current state */
+ }
+}
+
bool WM_file_read(bContext *C, const char *filepath, ReportList *reports)
{
+ /* assume automated tasks with background, don't write recent file list */
+ const bool do_history = (G.background == false) && (CTX_wm_manager(C)->op_undo_depth == 0);
bool success = false;
int retval;
@@ -413,16 +524,13 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports)
/* first try to append data from exotic file formats... */
/* it throws error box when file doesn't exist and returns -1 */
/* note; it should set some error message somewhere... (ton) */
- retval = wm_read_exotic(CTX_data_scene(C), filepath);
+ retval = wm_read_exotic(filepath);
/* we didn't succeed, now try to read Blender file */
if (retval == BKE_READ_EXOTIC_OK_BLEND) {
int G_f = G.f;
ListBase wmbase;
- /* assume automated tasks with background, don't write recent file list */
- const bool do_history = (G.background == false) && (CTX_wm_manager(C)->op_undo_depth == 0);
-
/* put aside screens to match with persistent windows later */
/* also exit screens and editors */
wm_window_match_init(C, &wmbase);
@@ -457,62 +565,18 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports)
if (retval != BKE_READ_FILE_FAIL) {
if (do_history) {
- write_history();
- }
- }
-
-
- WM_event_add_notifier(C, NC_WM | ND_FILEREAD, NULL);
-// refresh_interface_font();
-
- CTX_wm_window_set(C, CTX_wm_manager(C)->windows.first);
-
- ED_editors_init(C);
- DAG_on_visible_update(CTX_data_main(C), true);
-
-#ifdef WITH_PYTHON
- /* run any texts that were loaded in and flagged as modules */
- BPY_python_reset(C);
-#endif
-
- WM_operatortype_last_properties_clear_all();
-
- /* important to do before NULL'ing the context */
- BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_VERSION_UPDATE);
- BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_LOAD_POST);
-
- 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 0
- /* gives popups on windows but not linux, bug in report API
- * but disable for now to stop users getting annoyed */
- /* TODO, make this show in header info window */
- {
- Scene *sce;
- for (sce = G.main->scene.first; sce; sce = sce->id.next) {
- if (sce->r.engine[0] &&
- BLI_findstring(&R_engines, sce->r.engine, offsetof(RenderEngineType, idname)) == NULL)
- {
- BKE_reportf(reports, RPT_ERROR, "Engine '%s' not available for scene '%s' "
- "(an addon may need to be installed or enabled)",
- sce->r.engine, sce->id.name + 2);
- }
+ wm_history_file_update();
}
}
-#endif
- BKE_undo_reset();
- BKE_undo_write(C, "original"); /* save current state */
+ wm_file_read_post(C, false);
success = true;
}
+#if 0
else if (retval == BKE_READ_EXOTIC_OK_OTHER)
BKE_undo_write(C, "Import file");
+#endif
else if (retval == BKE_READ_EXOTIC_FAIL_OPEN) {
BKE_reportf(reports, RPT_ERROR, "Cannot read file '%s': %s", filepath,
errno ? strerror(errno) : TIP_("unable to open the file"));
@@ -528,6 +592,18 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports)
BLI_assert(!"invalid 'retval'");
}
+
+ if (success == false) {
+ /* remove from recent files list */
+ if (do_history) {
+ RecentFile *recent = wm_file_history_find(filepath);
+ if (recent) {
+ wm_history_file_free(recent);
+ wm_history_file_write();
+ }
+ }
+ }
+
WM_cursor_wait(0);
return success;
@@ -657,44 +733,15 @@ int wm_homefile_read(bContext *C, ReportList *reports, bool from_memory, const c
G.save_over = 0; // start with save preference untitled.blend
G.fileflags &= ~G_FILE_AUTOPLAY; /* disable autoplay in startup.blend... */
-// refresh_interface_font();
-
-// undo_editmode_clear();
- BKE_undo_reset();
- BKE_undo_write(C, "original"); /* save current state */
-
- ED_editors_init(C);
- DAG_on_visible_update(CTX_data_main(C), true);
-
-#ifdef WITH_PYTHON
- if (CTX_py_init_get(C)) {
- /* sync addons, these may have changed from the defaults */
- BPY_string_exec(C, "__import__('addon_utils').reset_all()");
-
- BPY_python_reset(C);
- }
-#endif
-
- WM_operatortype_last_properties_clear_all();
-
- /* important to do before NULL'ing the context */
- BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_VERSION_UPDATE);
- BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_LOAD_POST);
-
- WM_event_add_notifier(C, NC_WM | ND_FILEREAD, NULL);
-
- /* in background mode the scene will stay NULL */
- if (!G.background) {
- CTX_wm_window_set(C, NULL); /* exits queues */
- }
+ wm_file_read_post(C, true);
return true;
}
-int wm_history_read_exec(bContext *UNUSED(C), wmOperator *UNUSED(op))
+int wm_history_file_read_exec(bContext *UNUSED(C), wmOperator *UNUSED(op))
{
ED_file_read_bookmarks();
- wm_read_history();
+ wm_history_file_read();
return OPERATOR_FINISHED;
}
@@ -725,7 +772,10 @@ int wm_homefile_read_exec(bContext *C, wmOperator *op)
return wm_homefile_read(C, op->reports, from_memory, filepath) ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
-void wm_read_history(void)
+/** \name WM History File API
+ * \{ */
+
+void wm_history_file_read(void)
{
char name[FILE_MAX];
LinkNode *l, *lines;
@@ -757,18 +807,35 @@ void wm_read_history(void)
BLI_file_free_lines(lines);
}
-static void write_history(void)
+static RecentFile *wm_history_file_new(const char *filepath)
+{
+ RecentFile *recent = MEM_mallocN(sizeof(RecentFile), "RecentFile");
+ recent->filepath = BLI_strdup(filepath);
+ return recent;
+}
+
+static void wm_history_file_free(RecentFile *recent)
+{
+ BLI_assert(BLI_findindex(&G.recent_files, recent) != -1);
+ MEM_freeN(recent->filepath);
+ BLI_freelinkN(&G.recent_files, recent);
+}
+
+static RecentFile *wm_file_history_find(const char *filepath)
+{
+ return BLI_findstring_ptr(&G.recent_files, filepath, offsetof(RecentFile, filepath));
+}
+
+/**
+ * Write #BLENDER_HISTORY_FILE as-is, without checking the environment
+ * (thats handled by #wm_history_file_update).
+ */
+static void wm_history_file_write(void)
{
- struct RecentFile *recent, *next_recent;
- char name[FILE_MAX];
const char *user_config_dir;
+ char name[FILE_MAX];
FILE *fp;
- int i;
- /* no write history for recovered startup files */
- if (G.main->name[0] == 0)
- return;
-
/* will be NULL in background mode */
user_config_dir = BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL);
if (!user_config_dir)
@@ -776,48 +843,64 @@ static void write_history(void)
BLI_make_file_string("/", name, user_config_dir, BLENDER_HISTORY_FILE);
+ fp = BLI_fopen(name, "w");
+ if (fp) {
+ struct RecentFile *recent;
+ for (recent = G.recent_files.first; recent; recent = recent->next) {
+ fprintf(fp, "%s\n", recent->filepath);
+ }
+ fclose(fp);
+ }
+}
+
+/**
+ * Run after saving a file to refresh the #BLENDER_HISTORY_FILE list.
+ */
+static void wm_history_file_update(void)
+{
+ RecentFile *recent;
+
+ /* no write history for recovered startup files */
+ if (G.main->name[0] == 0)
+ return;
+
recent = G.recent_files.first;
/* refresh recent-files.txt of recent opened files, when current file was changed */
if (!(recent) || (BLI_path_cmp(recent->filepath, G.main->name) != 0)) {
- fp = BLI_fopen(name, "w");
- if (fp) {
- /* add current file to the beginning of list */
- recent = (RecentFile *)MEM_mallocN(sizeof(RecentFile), "RecentFile");
- recent->filepath = BLI_strdup(G.main->name);
- BLI_addhead(&(G.recent_files), recent);
- /* write current file to recent-files.txt */
- fprintf(fp, "%s\n", recent->filepath);
- recent = recent->next;
- i = 1;
- /* write rest of recent opened files to recent-files.txt */
- while ((i < U.recent_files) && (recent)) {
- /* this prevents to have duplicities in list */
- if (BLI_path_cmp(recent->filepath, G.main->name) != 0) {
- fprintf(fp, "%s\n", recent->filepath);
- recent = recent->next;
- }
- else {
- next_recent = recent->next;
- MEM_freeN(recent->filepath);
- BLI_freelinkN(&(G.recent_files), recent);
- recent = next_recent;
- }
- i++;
+
+ recent = wm_file_history_find(G.main->name);
+ if (recent) {
+ BLI_remlink(&G.recent_files, recent);
+ }
+ else {
+ RecentFile *recent_next;
+ for (recent = BLI_findlink(&G.recent_files, U.recent_files - 1); recent; recent = recent_next) {
+ recent_next = recent->next;
+ wm_history_file_free(recent);
}
- fclose(fp);
+ recent = wm_history_file_new(G.main->name);
}
+ /* add current file to the beginning of list */
+ BLI_addhead(&(G.recent_files), recent);
+
+ /* write current file to recent-files.txt */
+ wm_history_file_write();
+
/* also update most recent files on System */
GHOST_addToSystemRecentFiles(G.main->name);
}
}
+/** \} */
+
+
/* screen can be NULL */
-static ImBuf *blend_file_thumb(Scene *scene, bScreen *screen, int **thumb_pt)
+static ImBuf *blend_file_thumb(Scene *scene, bScreen *screen, BlendThumbnail **thumb_pt)
{
/* will be scaled down, but gives some nice oversampling */
ImBuf *ibuf;
- int *thumb;
+ BlendThumbnail *thumb;
char err_out[256] = "unknown";
/* screen if no camera found */
@@ -825,7 +908,11 @@ static ImBuf *blend_file_thumb(Scene *scene, bScreen *screen, int **thumb_pt)
ARegion *ar = NULL;
View3D *v3d = NULL;
- *thumb_pt = NULL;
+ /* In case we are given a valid thumbnail data, just generate image from it. */
+ if (*thumb_pt) {
+ thumb = *thumb_pt;
+ return BKE_main_thumbnail_to_imbuf(NULL, thumb);
+ }
/* scene can be NULL if running a script at startup and calling the save operator */
if (G.background || scene == NULL)
@@ -845,13 +932,18 @@ static ImBuf *blend_file_thumb(Scene *scene, bScreen *screen, int **thumb_pt)
/* gets scaled to BLEN_THUMB_SIZE */
if (scene->camera) {
- ibuf = ED_view3d_draw_offscreen_imbuf_simple(scene, scene->camera,
- BLEN_THUMB_SIZE * 2, BLEN_THUMB_SIZE * 2,
- IB_rect, OB_SOLID, false, false, false, R_ALPHAPREMUL, NULL, err_out);
+ ibuf = ED_view3d_draw_offscreen_imbuf_simple(
+ scene, scene->camera,
+ BLEN_THUMB_SIZE * 2, BLEN_THUMB_SIZE * 2,
+ IB_rect, OB_SOLID, false, false, false, R_ALPHAPREMUL, 0, NULL,
+ NULL, err_out);
}
else {
- ibuf = ED_view3d_draw_offscreen_imbuf(scene, v3d, ar, BLEN_THUMB_SIZE * 2, BLEN_THUMB_SIZE * 2,
- IB_rect, false, R_ALPHAPREMUL, NULL, err_out);
+ ibuf = ED_view3d_draw_offscreen_imbuf(
+ scene, v3d, ar,
+ BLEN_THUMB_SIZE * 2, BLEN_THUMB_SIZE * 2,
+ IB_rect, false, R_ALPHAPREMUL, 0, NULL,
+ NULL, err_out);
}
if (ibuf) {
@@ -863,13 +955,7 @@ static ImBuf *blend_file_thumb(Scene *scene, bScreen *screen, int **thumb_pt)
/* add pretty overlay */
IMB_thumb_overlay_blend(ibuf->rect, ibuf->x, ibuf->y, aspect);
- /* first write into thumb buffer */
- thumb = MEM_mallocN(((2 + (BLEN_THUMB_SIZE * BLEN_THUMB_SIZE))) * sizeof(int), "write_file thumb");
-
- thumb[0] = BLEN_THUMB_SIZE;
- thumb[1] = BLEN_THUMB_SIZE;
-
- memcpy(thumb + 2, ibuf->rect, BLEN_THUMB_SIZE * BLEN_THUMB_SIZE * sizeof(int));
+ thumb = BKE_main_thumbnail_from_imbuf(NULL, ibuf);
}
else {
/* '*thumb_pt' needs to stay NULL to prevent a bad thumbnail from being handled */
@@ -908,25 +994,26 @@ int wm_file_write(bContext *C, const char *filepath, int fileflags, ReportList *
{
Library *li;
int len;
- int *thumb = NULL;
+ int ret = -1;
+ BlendThumbnail *thumb, *main_thumb;
ImBuf *ibuf_thumb = NULL;
len = strlen(filepath);
if (len == 0) {
BKE_report(reports, RPT_ERROR, "Path is empty, cannot save");
- return -1;
+ return ret;
}
if (len >= FILE_MAX) {
BKE_report(reports, RPT_ERROR, "Path too long, cannot save");
- return -1;
+ return ret;
}
/* Check if file write permission is ok */
if (BLI_exists(filepath) && !BLI_file_is_writable(filepath)) {
BKE_reportf(reports, RPT_ERROR, "Cannot save blend file, path '%s' is not writable", filepath);
- return -1;
+ return ret;
}
/* note: used to replace the file extension (to ensure '.blend'),
@@ -937,18 +1024,21 @@ int wm_file_write(bContext *C, const char *filepath, int fileflags, ReportList *
for (li = G.main->library.first; li; li = li->id.next) {
if (BLI_path_cmp(li->filepath, filepath) == 0) {
BKE_reportf(reports, RPT_ERROR, "Cannot overwrite used library '%.240s'", filepath);
- return -1;
+ return ret;
}
}
+ /* Call pre-save callbacks befores writing preview, that way you can generate custom file thumbnail... */
+ BLI_callback_exec(G.main, NULL, BLI_CB_EVT_SAVE_PRE);
+
/* blend file thumbnail */
/* save before exit_editmode, otherwise derivedmeshes for shared data corrupt #27765) */
+ /* 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);
}
- BLI_callback_exec(G.main, NULL, BLI_CB_EVT_SAVE_PRE);
-
/* operator now handles overwrite checks */
if (G.fileflags & G_AUTOPACK) {
@@ -984,7 +1074,7 @@ int wm_file_write(bContext *C, const char *filepath, int fileflags, ReportList *
/* prevent background mode scripts from clobbering history */
if (!G.background) {
- write_history();
+ wm_history_file_update();
}
BLI_callback_exec(G.main, NULL, BLI_CB_EVT_SAVE_POST);
@@ -993,22 +1083,21 @@ int wm_file_write(bContext *C, const char *filepath, int fileflags, ReportList *
if (ibuf_thumb) {
IMB_thumb_delete(filepath, THB_FAIL); /* without this a failed thumb overrides */
ibuf_thumb = IMB_thumb_create(filepath, THB_LARGE, THB_SOURCE_BLEND, ibuf_thumb);
- IMB_freeImBuf(ibuf_thumb);
}
- if (thumb) MEM_freeN(thumb);
+ ret = 0; /* Success. */
}
- else {
- if (ibuf_thumb) IMB_freeImBuf(ibuf_thumb);
- if (thumb) MEM_freeN(thumb);
-
- WM_cursor_wait(0);
- return -1;
+
+ if (ibuf_thumb) {
+ IMB_freeImBuf(ibuf_thumb);
+ }
+ if (thumb && thumb != main_thumb) {
+ MEM_freeN(thumb);
}
WM_cursor_wait(0);
-
- return 0;
+
+ return ret;
}
/**
diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c
index 9750bfd2f7f..ba4a807dbd7 100644
--- a/source/blender/windowmanager/intern/wm_init_exit.c
+++ b/source/blender/windowmanager/intern/wm_init_exit.c
@@ -107,7 +107,7 @@
#include "UI_interface.h"
#include "BLF_api.h"
-#include "BLF_translation.h"
+#include "BLT_lang.h"
#include "GPU_buffers.h"
#include "GPU_draw.h"
@@ -159,7 +159,9 @@ void WM_init(bContext *C, int argc, const char **argv)
BKE_library_callback_free_editor_id_reference_set(WM_main_remove_editor_id_reference); /* library.c */
BKE_blender_callback_test_break_set(wm_window_testbreak); /* blender.c */
BKE_spacedata_callback_id_unref_set(ED_spacedata_id_unref); /* screen.c */
- DAG_editors_update_cb(ED_render_id_flush_update, ED_render_scene_update); /* depsgraph.c */
+ DAG_editors_update_cb(ED_render_id_flush_update,
+ ED_render_scene_update,
+ ED_render_scene_update_pre); /* depsgraph.c */
ED_spacetypes_init(); /* editors/space_api/spacetype.c */
@@ -167,16 +169,20 @@ void WM_init(bContext *C, int argc, const char **argv)
ED_node_init_butfuncs();
BLF_init(11, U.dpi); /* Please update source/gamengine/GamePlayer/GPG_ghost.cpp if you change this */
- BLF_lang_init();
+ BLT_lang_init();
/* Enforce loading the UI for the initial homefile */
G.fileflags &= ~G_FILE_NO_UI;
+ /* reports cant be initialized before the wm,
+ * but keep before file reading, since that may report errors */
+ wm_init_reports(C);
+
/* get the default database, plus a wm */
wm_homefile_read(C, NULL, G.factory_startup, NULL);
- BLF_lang_set(NULL);
+ BLT_lang_set(NULL);
if (!G.background) {
/* sets 3D mouse deadzone */
@@ -189,6 +195,10 @@ void WM_init(bContext *C, int argc, const char **argv)
GPU_set_anisotropic(U.anisotropic_filter);
GPU_set_gpu_mipmapping(U.use_gpu_mipmap);
+#ifdef WITH_OPENSUBDIV
+ openSubdiv_init();
+#endif
+
UI_init();
}
else {
@@ -223,14 +233,12 @@ void WM_init(bContext *C, int argc, const char **argv)
if (!G.background && !wm_start_with_console)
GHOST_toggleConsole(3);
- wm_init_reports(C); /* reports cant be initialized before the wm */
-
clear_matcopybuf();
ED_render_clear_mtex_copybuf();
// glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- wm_read_history();
+ wm_history_file_read();
/* allow a path of "", this is what happens when making a new file */
#if 0
@@ -253,13 +261,24 @@ void WM_init(bContext *C, int argc, const char **argv)
/* that prevents loading both the kept session, and the file on the command line */
}
else {
+ /* note, logic here is from wm_file_read_post,
+ * call functions that depend on Python being initialized. */
+
/* normally 'wm_homefile_read' will do this,
* however python is not initialized when called from this function.
*
* unlikely any handlers are set but its possible,
* note that recovering the last session does its own callbacks. */
+ CTX_wm_window_set(C, CTX_wm_manager(C)->windows.first);
+
BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_VERSION_UPDATE);
BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_LOAD_POST);
+
+ wm_file_read_report(C);
+
+ if (!G.background) {
+ CTX_wm_window_set(C, NULL);
+ }
}
}
@@ -503,7 +522,7 @@ void WM_exit_ext(bContext *C, const bool do_python)
#ifdef WITH_INTERNATIONAL
BLF_free_unifont();
BLF_free_unifont_mono();
- BLF_lang_free();
+ BLT_lang_free();
#endif
ANIM_keyingset_infos_exit();
diff --git a/source/blender/windowmanager/intern/wm_keymap.c b/source/blender/windowmanager/intern/wm_keymap.c
index 7570b4044b2..016583e69a5 100644
--- a/source/blender/windowmanager/intern/wm_keymap.c
+++ b/source/blender/windowmanager/intern/wm_keymap.c
@@ -50,7 +50,7 @@
#include "BKE_main.h"
#include "BKE_screen.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "RNA_access.h"
#include "RNA_enum_types.h"
@@ -586,8 +586,23 @@ static void wm_keymap_patch(wmKeyMap *km, wmKeyMap *diff_km)
/* Do not re-add an already existing keymap item! See T42088. */
/* We seek only for exact copy here! See T42137. */
kmi_add = wm_keymap_find_item_equals(km, kmdi->add_item);
+
+ /* If kmi_add is same as kmi_remove (can happen in some cases, typically when we got kmi_remove
+ * from wm_keymap_find_item_equals_result()), no need to add or remove anything, see T45579. */
+ /* Note: This typically happens when we apply user-defined keymap diff to a base one that was exported
+ * with that customized keymap already. In that case:
+ * - wm_keymap_find_item_equals(km, kmdi->remove_item) finds nothing (because actual shortcut of
+ * current base does not match kmdi->remove_item any more).
+ * - wm_keymap_find_item_equals_result(km, kmdi->remove_item) finds the current kmi from
+ * base keymap (because it does exactly the same thing).
+ * - wm_keymap_find_item_equals(km, kmdi->add_item) finds the same kmi, since base keymap was
+ * exported with that user-defined shortcut already!
+ * Maybe we should rather keep user-defined keymaps specific to a given base one? */
+ if (kmi_add != NULL && kmi_add == kmi_remove) {
+ kmi_remove = NULL;
+ }
/* only if nothing to remove or item to remove found */
- if (!kmi_add && (!kmdi->remove_item || kmi_remove)) {
+ else if (!kmi_add && (!kmdi->remove_item || kmi_remove)) {
kmi_add = wm_keymap_item_copy(kmdi->add_item);
kmi_add->flag |= KMI_USER_MODIFIED;
@@ -888,15 +903,21 @@ static void wm_user_modal_keymap_set_items(wmWindowManager *wm, wmKeyMap *km)
const char *WM_key_event_string(const short type, const bool compact)
{
- const char *name = NULL;
+ EnumPropertyItem *it;
+ const int i = RNA_enum_from_value(event_type_items, (int)type);
+
+ if (i == -1) {
+ return "";
+ }
+ it = &event_type_items[i];
+
/* We first try enum items' description (abused as shortname here), and fall back to usual name if empty. */
- if ((compact && RNA_enum_description(event_type_items, (int)type, &name) && name[0]) ||
- RNA_enum_name(event_type_items, (int)type, &name))
- {
- return IFACE_(name);
+ if (compact && it->description[0]) {
+ /* XXX No context for enum descriptions... In practice shall not be an issue though. */
+ return IFACE_(it->description);
}
- return "";
+ return CTX_IFACE_(BLT_I18NCONTEXT_UI_EVENTS, it->name);
}
/* TODO: also support (some) value, like e.g. double-click? */
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index cab9b02d830..eabc8614c80 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -54,15 +54,18 @@
#include "DNA_windowmanager_types.h"
#include "DNA_mesh_types.h" /* only for USE_BMESH_SAVE_AS_COMPAT */
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "PIL_time.h"
#include "BLI_blenlib.h"
+#include "BLI_bitmap.h"
#include "BLI_dial.h"
#include "BLI_dynstr.h" /*for WM_operator_pystring */
+#include "BLI_linklist.h"
#include "BLI_linklist_stack.h"
#include "BLI_math.h"
+#include "BLI_memarena.h"
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
@@ -74,6 +77,7 @@
#include "BKE_brush.h"
#include "BKE_context.h"
#include "BKE_depsgraph.h"
+#include "BKE_icons.h"
#include "BKE_idprop.h"
#include "BKE_image.h"
#include "BKE_library.h"
@@ -170,8 +174,8 @@ void WM_operatortype_append(void (*opfunc)(wmOperatorType *))
ot = MEM_callocN(sizeof(wmOperatorType), "operatortype");
ot->srna = RNA_def_struct_ptr(&BLENDER_RNA, "", &RNA_OperatorProperties);
/* Set the default i18n context now, so that opfunc can redefine it if needed! */
- RNA_def_struct_translation_context(ot->srna, BLF_I18NCONTEXT_OPERATOR_DEFAULT);
- ot->translation_context = BLF_I18NCONTEXT_OPERATOR_DEFAULT;
+ RNA_def_struct_translation_context(ot->srna, BLT_I18NCONTEXT_OPERATOR_DEFAULT);
+ ot->translation_context = BLT_I18NCONTEXT_OPERATOR_DEFAULT;
opfunc(ot);
if (ot->name == NULL) {
@@ -193,8 +197,8 @@ void WM_operatortype_append_ptr(void (*opfunc)(wmOperatorType *, void *), void *
ot = MEM_callocN(sizeof(wmOperatorType), "operatortype");
ot->srna = RNA_def_struct_ptr(&BLENDER_RNA, "", &RNA_OperatorProperties);
/* Set the default i18n context now, so that opfunc can redefine it if needed! */
- RNA_def_struct_translation_context(ot->srna, BLF_I18NCONTEXT_OPERATOR_DEFAULT);
- ot->translation_context = BLF_I18NCONTEXT_OPERATOR_DEFAULT;
+ RNA_def_struct_translation_context(ot->srna, BLT_I18NCONTEXT_OPERATOR_DEFAULT);
+ ot->translation_context = BLT_I18NCONTEXT_OPERATOR_DEFAULT;
opfunc(ot, userdata);
RNA_def_struct_ui_text(ot->srna, ot->name, ot->description ? ot->description : UNDOCUMENTED_OPERATOR_TIP);
RNA_def_struct_identifier(ot->srna, ot->idname);
@@ -404,7 +408,7 @@ wmOperatorType *WM_operatortype_append_macro(const char *idname, const char *nam
RNA_def_struct_ui_text(ot->srna, ot->name, ot->description);
RNA_def_struct_identifier(ot->srna, ot->idname);
/* Use i18n context from ext.srna if possible (py operators). */
- i18n_context = ot->ext.srna ? RNA_struct_translation_context(ot->ext.srna) : BLF_I18NCONTEXT_OPERATOR_DEFAULT;
+ i18n_context = ot->ext.srna ? RNA_struct_translation_context(ot->ext.srna) : BLT_I18NCONTEXT_OPERATOR_DEFAULT;
RNA_def_struct_translation_context(ot->srna, i18n_context);
ot->translation_context = i18n_context;
@@ -431,8 +435,8 @@ void WM_operatortype_append_macro_ptr(void (*opfunc)(wmOperatorType *, void *),
ot->description = UNDOCUMENTED_OPERATOR_TIP;
/* Set the default i18n context now, so that opfunc can redefine it if needed! */
- RNA_def_struct_translation_context(ot->srna, BLF_I18NCONTEXT_OPERATOR_DEFAULT);
- ot->translation_context = BLF_I18NCONTEXT_OPERATOR_DEFAULT;
+ RNA_def_struct_translation_context(ot->srna, BLT_I18NCONTEXT_OPERATOR_DEFAULT);
+ ot->translation_context = BLT_I18NCONTEXT_OPERATOR_DEFAULT;
opfunc(ot, userdata);
RNA_def_struct_ui_text(ot->srna, ot->name, ot->description);
@@ -1206,19 +1210,18 @@ bool WM_operator_filesel_ensure_ext_imtype(wmOperator *op, const struct ImageFor
}
/* default properties for fileselect */
-void WM_operator_properties_filesel(wmOperatorType *ot, int filter, short type, short action, short flag, short display)
+void WM_operator_properties_filesel(wmOperatorType *ot, int filter, short type, short action, short flag, short display, short sort)
{
PropertyRNA *prop;
static EnumPropertyItem file_display_items[] = {
- {FILE_DEFAULTDISPLAY, "FILE_DEFAULTDISPLAY", 0, "Default", "Automatically determine display type for files"},
- {FILE_SHORTDISPLAY, "FILE_SHORTDISPLAY", ICON_SHORTDISPLAY, "Short List", "Display files as short list"},
- {FILE_LONGDISPLAY, "FILE_LONGDISPLAY", ICON_LONGDISPLAY, "Long List", "Display files as a detailed list"},
- {FILE_IMGDISPLAY, "FILE_IMGDISPLAY", ICON_IMGDISPLAY, "Thumbnails", "Display files as thumbnails"},
+ {FILE_DEFAULTDISPLAY, "DEFAULT", 0, "Default", "Automatically determine display type for files"},
+ {FILE_SHORTDISPLAY, "LIST_SHORT", ICON_SHORTDISPLAY, "Short List", "Display files as short list"},
+ {FILE_LONGDISPLAY, "LIST_LONG", ICON_LONGDISPLAY, "Long List", "Display files as a detailed list"},
+ {FILE_IMGDISPLAY, "THUMBNAIL", ICON_IMGDISPLAY, "Thumbnails", "Display files as thumbnails"},
{0, NULL, 0, NULL, NULL}
};
-
if (flag & WM_FILESEL_FILEPATH)
RNA_def_string_file_path(ot->srna, "filepath", NULL, FILE_MAX, "File Path", "Path to file");
@@ -1261,6 +1264,8 @@ void WM_operator_properties_filesel(wmOperatorType *ot, int filter, short type,
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
prop = RNA_def_boolean(ot->srna, "filter_folder", (filter & FILE_TYPE_FOLDER) != 0, "Filter folders", "");
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(ot->srna, "filter_blenlib", (filter & FILE_TYPE_BLENDERLIB) != 0, "Filter Blender IDs", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
prop = RNA_def_int(ot->srna, "filemode", type, FILE_LOADLIB, FILE_SPECIAL,
"File Browser Mode", "The setting for the file browser mode to load a .blend file, a library or a special file",
@@ -1279,6 +1284,10 @@ void WM_operator_properties_filesel(wmOperatorType *ot, int filter, short type,
prop = RNA_def_enum(ot->srna, "display_type", file_display_items, display, "Display Type", "");
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
+ prop = RNA_def_enum(ot->srna, "sort_method", file_sort_items, sort, "File sorting mode", "");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
+
}
static void wm_operator_properties_select_action_ex(wmOperatorType *ot, int default_action,
@@ -1314,6 +1323,22 @@ void WM_operator_properties_select_action_simple(wmOperatorType *ot, int default
wm_operator_properties_select_action_ex(ot, default_action, select_actions);
}
+/**
+ * Use for all select random operators.
+ * Adds properties: percent, seed, action.
+ */
+void WM_operator_properties_select_random(wmOperatorType *ot)
+{
+ RNA_def_float_percentage(
+ ot->srna, "percent", 50.f, 0.0f, 100.0f,
+ "Percent", "Percentage of objects to select randomly", 0.f, 100.0f);
+ RNA_def_int(
+ ot->srna, "seed", 0, 0, INT_MAX,
+ "Random Seed", "Seed for the random number generator", 0, 255);
+
+ WM_operator_properties_select_action_simple(ot, SEL_SELECT);
+}
+
void WM_operator_properties_select_all(wmOperatorType *ot)
{
WM_operator_properties_select_action(ot, SEL_TOGGLE);
@@ -1533,6 +1558,8 @@ static uiBlock *wm_block_create_redo(bContext *C, ARegion *ar, void *arg_op)
if (op->type->flag & OPTYPE_MACRO) {
for (op = op->macro.first; op; op = op->next) {
uiLayoutOperatorButs(C, layout, op, NULL, 'H', UI_LAYOUT_OP_SHOW_TITLE);
+ if (op->next)
+ uiItemS(layout);
}
}
else {
@@ -1604,7 +1631,7 @@ static uiBlock *wm_block_dialog_create(bContext *C, ARegion *ar, void *userData)
/* intentionally don't use 'UI_BLOCK_MOVEMOUSE_QUIT', some dialogues have many items
* where quitting by accident is very annoying */
- UI_block_flag_enable(block, UI_BLOCK_KEEP_OPEN);
+ UI_block_flag_enable(block, UI_BLOCK_KEEP_OPEN | UI_BLOCK_NUMSELECT);
layout = UI_block_layout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, data->width, data->height, 0, style);
@@ -2220,6 +2247,17 @@ static int wm_operator_winactive_normal(bContext *C)
return 1;
}
+/* included for script-access */
+static void WM_OT_window_close(wmOperatorType *ot)
+{
+ ot->name = "Close Window";
+ ot->idname = "WM_OT_window_close";
+ ot->description = "Close the current Blender window";
+
+ ot->exec = wm_window_close_exec;
+ ot->poll = WM_operator_winactive;
+}
+
static void WM_OT_window_duplicate(wmOperatorType *ot)
{
ot->name = "Duplicate Window";
@@ -2298,7 +2336,7 @@ static void WM_OT_read_history(wmOperatorType *ot)
ot->description = "Reloads history and bookmarks";
ot->invoke = WM_operator_confirm;
- ot->exec = wm_history_read_exec;
+ ot->exec = wm_history_file_read_exec;
/* this operator is only used for loading settings from a previous blender install */
ot->flag = OPTYPE_INTERNAL;
@@ -2491,7 +2529,7 @@ static void WM_OT_open_mainfile(wmOperatorType *ot)
/* omit window poll so this can work in background mode */
WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_BLENDER, FILE_BLENDER, FILE_OPENFILE,
- WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY);
+ WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
RNA_def_boolean(ot->srna, "load_ui", true, "Load UI", "Load user interface setup in the .blend file");
RNA_def_boolean(ot->srna, "use_scripts", true, "Trusted Source",
@@ -2582,43 +2620,180 @@ static int wm_link_append_invoke(bContext *C, wmOperator *op, const wmEvent *UNU
static short wm_link_append_flag(wmOperator *op)
{
+ PropertyRNA *prop;
short flag = 0;
- if (RNA_boolean_get(op->ptr, "autoselect")) flag |= FILE_AUTOSELECT;
- if (RNA_boolean_get(op->ptr, "active_layer")) flag |= FILE_ACTIVELAY;
- if (RNA_struct_find_property(op->ptr, "relative_path") && RNA_boolean_get(op->ptr, "relative_path")) flag |= FILE_RELPATH;
- if (RNA_boolean_get(op->ptr, "link")) flag |= FILE_LINK;
- if (RNA_boolean_get(op->ptr, "instance_groups")) flag |= FILE_GROUP_INSTANCE;
+ if (RNA_boolean_get(op->ptr, "autoselect"))
+ flag |= FILE_AUTOSELECT;
+ if (RNA_boolean_get(op->ptr, "active_layer"))
+ flag |= FILE_ACTIVELAY;
+ if ((prop = RNA_struct_find_property(op->ptr, "relative_path")) && RNA_property_boolean_get(op->ptr, prop))
+ flag |= FILE_RELPATH;
+ if (RNA_boolean_get(op->ptr, "link"))
+ flag |= FILE_LINK;
+ if (RNA_boolean_get(op->ptr, "instance_groups"))
+ flag |= FILE_GROUP_INSTANCE;
return flag;
}
+typedef struct WMLinkAppendDataItem {
+ char *name;
+ BLI_bitmap *libraries; /* All libs (from WMLinkAppendData.libraries) to try to load this ID from. */
+ short idcode;
+
+ ID *new_id;
+ void *customdata;
+} WMLinkAppendDataItem;
+
+typedef struct WMLinkAppendData {
+ LinkNodePair libraries;
+ LinkNodePair items;
+ int num_libraries;
+ int num_items;
+ short flag;
+
+ /* Internal 'private' data */
+ MemArena *memarena;
+} WMLinkAppendData;
+
+static WMLinkAppendData *wm_link_append_data_new(const int flag)
+{
+ MemArena *ma = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
+ WMLinkAppendData *lapp_data = BLI_memarena_calloc(ma, sizeof(*lapp_data));
+
+ lapp_data->flag = flag;
+ lapp_data->memarena = ma;
+
+ return lapp_data;
+}
+
+static void wm_link_append_data_free(WMLinkAppendData *lapp_data)
+{
+ BLI_memarena_free(lapp_data->memarena);
+}
+
+/* WARNING! *Never* call wm_link_append_data_library_add() after having added some items! */
+
+static void wm_link_append_data_library_add(WMLinkAppendData *lapp_data, const char *libname)
+{
+ size_t len = strlen(libname) + 1;
+ char *libpath = BLI_memarena_alloc(lapp_data->memarena, len);
+
+ BLI_strncpy(libpath, libname, len);
+ BLI_linklist_append_arena(&lapp_data->libraries, libpath, lapp_data->memarena);
+ lapp_data->num_libraries++;
+}
+
+static WMLinkAppendDataItem *wm_link_append_data_item_add(
+ WMLinkAppendData *lapp_data, const char *idname, const short idcode, void *customdata)
+{
+ WMLinkAppendDataItem *item = BLI_memarena_alloc(lapp_data->memarena, sizeof(*item));
+ size_t len = strlen(idname) + 1;
+
+ item->name = BLI_memarena_alloc(lapp_data->memarena, len);
+ BLI_strncpy(item->name, idname, len);
+ item->idcode = idcode;
+ item->libraries = BLI_BITMAP_NEW_MEMARENA(lapp_data->memarena, lapp_data->num_libraries);
+
+ item->new_id = NULL;
+ item->customdata = customdata;
+
+ BLI_linklist_append_arena(&lapp_data->items, item, lapp_data->memarena);
+ lapp_data->num_items++;
+
+ return item;
+}
+
+static void wm_link_do(
+ WMLinkAppendData *lapp_data, ReportList *reports, Main *bmain, Scene *scene, View3D *v3d)
+{
+ Main *mainl;
+ BlendHandle *bh;
+ Library *lib;
+
+ const int flag = lapp_data->flag;
+
+ LinkNode *liblink, *itemlink;
+ int lib_idx, item_idx;
+
+ BLI_assert(lapp_data->num_items && lapp_data->num_libraries);
+
+ for (lib_idx = 0, liblink = lapp_data->libraries.list; liblink; lib_idx++, liblink = liblink->next) {
+ char *libname = liblink->link;
+
+ bh = BLO_blendhandle_from_file(libname, reports);
+
+ if (bh == NULL) {
+ /* Unlikely since we just browsed it, but possible
+ * Error reports will have been made by BLO_blendhandle_from_file() */
+ continue;
+ }
+
+ /* here appending/linking starts */
+ mainl = BLO_library_link_begin(bmain, &bh, libname);
+ lib = mainl->curlib;
+ BLI_assert(lib);
+ UNUSED_VARS_NDEBUG(lib);
+
+ if (mainl->versionfile < 250) {
+ BKE_reportf(reports, RPT_WARNING,
+ "Linking or appending from a very old .blend file format (%d.%d), no animation conversion will "
+ "be done! You may want to re-save your lib file with current Blender",
+ mainl->versionfile, mainl->subversionfile);
+ }
+
+ /* For each lib file, we try to link all items belonging to that lib,
+ * and tag those successful to not try to load them again with the other libs. */
+ for (item_idx = 0, itemlink = lapp_data->items.list; itemlink; item_idx++, itemlink = itemlink->next) {
+ WMLinkAppendDataItem *item = itemlink->link;
+ ID *new_id;
+
+ if (!BLI_BITMAP_TEST(item->libraries, lib_idx)) {
+ continue;
+ }
+
+ new_id = BLO_library_link_named_part_ex(mainl, &bh, item->idcode, item->name, flag, scene, v3d);
+ if (new_id) {
+ /* If the link is sucessful, clear item's libs 'todo' flags.
+ * This avoids trying to link same item with other libraries to come. */
+ BLI_BITMAP_SET_ALL(item->libraries, false, lapp_data->num_libraries);
+ item->new_id = new_id;
+ }
+ }
+
+ BLO_library_link_end(mainl, &bh, flag, scene, v3d);
+ BLO_blendhandle_close(bh);
+ }
+}
+
static int wm_link_append_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
- Main *mainl = NULL;
- BlendHandle *bh;
- Library *lib;
PropertyRNA *prop;
- char name[FILE_MAX], dir[FILE_MAX], libname[FILE_MAX], group[BLO_GROUP_MAX];
- int idcode, totfiles = 0;
+ WMLinkAppendData *lapp_data;
+ char path[FILE_MAX_LIBEXTRA], root[FILE_MAXDIR], libname[FILE_MAX], relname[FILE_MAX];
+ char *group, *name;
+ int totfiles = 0;
short flag;
- RNA_string_get(op->ptr, "filename", name);
- RNA_string_get(op->ptr, "directory", dir);
+ RNA_string_get(op->ptr, "filename", relname);
+ RNA_string_get(op->ptr, "directory", root);
+
+ BLI_join_dirfile(path, sizeof(path), root, relname);
/* test if we have a valid data */
- if (BLO_is_a_library(dir, libname, group) == 0) {
- BKE_report(op->reports, RPT_ERROR, "Not a library");
+ if (!BLO_library_path_explode(path, libname, &group, &name)) {
+ BKE_reportf(op->reports, RPT_ERROR, "'%s': not a library", path);
return OPERATOR_CANCELLED;
}
- else if (group[0] == 0) {
- BKE_report(op->reports, RPT_ERROR, "Nothing indicated");
+ else if (!group) {
+ BKE_reportf(op->reports, RPT_ERROR, "'%s': nothing indicated", path);
return OPERATOR_CANCELLED;
}
else if (BLI_path_cmp(bmain->name, libname) == 0) {
- BKE_report(op->reports, RPT_ERROR, "Cannot use current file as library");
+ BKE_reportf(op->reports, RPT_ERROR, "'%s': cannot use current file as library", path);
return OPERATOR_CANCELLED;
}
@@ -2627,84 +2802,113 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
if (prop) {
totfiles = RNA_property_collection_length(op->ptr, prop);
if (totfiles == 0) {
- if (name[0] == '\0') {
- BKE_report(op->reports, RPT_ERROR, "Nothing indicated");
+ if (!name) {
+ BKE_reportf(op->reports, RPT_ERROR, "'%s': nothing indicated", path);
return OPERATOR_CANCELLED;
}
}
}
- else if (name[0] == '\0') {
- BKE_report(op->reports, RPT_ERROR, "Nothing indicated");
- return OPERATOR_CANCELLED;
- }
-
- bh = BLO_blendhandle_from_file(libname, op->reports);
-
- if (bh == NULL) {
- /* unlikely since we just browsed it, but possible
- * error reports will have been made by BLO_blendhandle_from_file() */
+ else if (!name) {
+ BKE_reportf(op->reports, RPT_ERROR, "'%s': nothing indicated", path);
return OPERATOR_CANCELLED;
}
-
- /* from here down, no error returns */
-
- idcode = BKE_idcode_from_name(group);
-
- /* now we have or selected, or an indicated file */
- if (RNA_boolean_get(op->ptr, "autoselect"))
- BKE_scene_base_deselect_all(scene);
-
-
flag = wm_link_append_flag(op);
/* sanity checks for flag */
- if (scene->id.lib && (flag & FILE_GROUP_INSTANCE)) {
- /* TODO, user never gets this message */
- BKE_reportf(op->reports, RPT_WARNING, "Scene '%s' is linked, group instance disabled", scene->id.name + 2);
+ if (scene && scene->id.lib) {
+ BKE_reportf(op->reports, RPT_WARNING,
+ "Scene '%s' is linked, instantiation of objects & groups is disabled", scene->id.name + 2);
flag &= ~FILE_GROUP_INSTANCE;
+ scene = NULL;
}
+ /* from here down, no error returns */
+ if (scene && RNA_boolean_get(op->ptr, "autoselect")) {
+ BKE_scene_base_deselect_all(scene);
+ }
+
/* tag everything, all untagged data can be made local
* its also generally useful to know what is new
*
- * take extra care BKE_main_id_flag_all(LIB_LINK_TAG, false) is called after! */
- BKE_main_id_flag_all(bmain, LIB_PRE_EXISTING, 1);
+ * take extra care BKE_main_id_flag_all(bmain, LIB_PRE_EXISTING, false) is called after! */
+ BKE_main_id_flag_all(bmain, LIB_PRE_EXISTING, true);
- /* here appending/linking starts */
- mainl = BLO_library_append_begin(bmain, &bh, libname);
- lib = mainl->curlib;
- BLI_assert(lib);
+ /* We define our working data...
+ * Note that here, each item 'uses' one library, and only one. */
+ lapp_data = wm_link_append_data_new(flag);
+ if (totfiles != 0) {
+ GHash *libraries = BLI_ghash_new(BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, __func__);
+ int lib_idx = 0;
- if (mainl->versionfile < 250) {
- BKE_reportf(op->reports, RPT_WARNING,
- "Linking or appending from a very old .blend file format (%d.%d), no animation conversion will "
- "be done! You may want to re-save your lib file with current Blender",
- mainl->versionfile, mainl->subversionfile);
- }
+ RNA_BEGIN (op->ptr, itemptr, "files")
+ {
+ RNA_string_get(&itemptr, "name", relname);
+
+ BLI_join_dirfile(path, sizeof(path), root, relname);
+
+ if (BLO_library_path_explode(path, libname, &group, &name)) {
+ if (!group || !name) {
+ continue;
+ }
+
+ if (!BLI_ghash_haskey(libraries, libname)) {
+ BLI_ghash_insert(libraries, BLI_strdup(libname), SET_INT_IN_POINTER(lib_idx));
+ lib_idx++;
+ wm_link_append_data_library_add(lapp_data, libname);
+ }
+ }
+ }
+ RNA_END;
- if (totfiles == 0) {
- BLO_library_append_named_part_ex(C, mainl, &bh, name, idcode, flag);
- }
- else {
RNA_BEGIN (op->ptr, itemptr, "files")
{
- RNA_string_get(&itemptr, "name", name);
- BLO_library_append_named_part_ex(C, mainl, &bh, name, idcode, flag);
+ RNA_string_get(&itemptr, "name", relname);
+
+ BLI_join_dirfile(path, sizeof(path), root, relname);
+
+ if (BLO_library_path_explode(path, libname, &group, &name)) {
+ WMLinkAppendDataItem *item;
+ if (!group || !name) {
+ printf("skipping %s\n", path);
+ continue;
+ }
+
+ lib_idx = GET_INT_FROM_POINTER(BLI_ghash_lookup(libraries, libname));
+
+ item = wm_link_append_data_item_add(lapp_data, name, BKE_idcode_from_name(group), NULL);
+ BLI_BITMAP_ENABLE(item->libraries, lib_idx);
+ }
}
RNA_END;
+
+ BLI_ghash_free(libraries, MEM_freeN, NULL);
}
- BLO_library_append_end(C, mainl, &bh, idcode, flag);
-
+ else {
+ WMLinkAppendDataItem *item;
+
+ wm_link_append_data_library_add(lapp_data, libname);
+ item = wm_link_append_data_item_add(lapp_data, name, BKE_idcode_from_name(group), NULL);
+ BLI_BITMAP_ENABLE(item->libraries, 0);
+ }
+
+ /* XXX We'd need re-entrant locking on Main for this to work... */
+ /* BKE_main_lock(bmain); */
+
+ wm_link_do(lapp_data, op->reports, bmain, scene, CTX_wm_view3d(C));
+
+ /* BKE_main_unlock(bmain); */
+
+ wm_link_append_data_free(lapp_data);
+
/* mark all library linked objects to be updated */
BKE_main_lib_objects_recalc_all(bmain);
IMB_colormanagement_check_file_config(bmain);
/* append, rather than linking */
if ((flag & FILE_LINK) == 0) {
- BLI_assert(BLI_findindex(&bmain->library, lib) != -1);
- BKE_library_make_local(bmain, lib, true);
+ BKE_library_make_local(bmain, NULL, true);
}
/* important we unset, otherwise these object wont
@@ -2716,10 +2920,9 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
/* free gpu materials, some materials depend on existing objects, such as lamps so freeing correctly refreshes */
GPU_materials_free();
- BLO_blendhandle_close(bh);
/* XXX TODO: align G.lib with other directory storage (like last opened image etc...) */
- BLI_strncpy(G.lib, dir, FILE_MAX);
+ BLI_strncpy(G.lib, root, FILE_MAX);
WM_event_add_notifier(C, NC_WINDOW, NULL);
@@ -2759,9 +2962,9 @@ static void WM_OT_link(wmOperatorType *ot)
ot->flag |= OPTYPE_UNDO;
WM_operator_properties_filesel(
- ot, FILE_TYPE_FOLDER | FILE_TYPE_BLENDER, FILE_LOADLIB, FILE_OPENFILE,
+ ot, FILE_TYPE_FOLDER | FILE_TYPE_BLENDER | FILE_TYPE_BLENDERLIB, FILE_LOADLIB, FILE_OPENFILE,
WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILENAME | WM_FILESEL_RELPATH | WM_FILESEL_FILES,
- FILE_DEFAULTDISPLAY);
+ FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
wm_link_append_properties_common(ot, true);
}
@@ -2779,9 +2982,9 @@ static void WM_OT_append(wmOperatorType *ot)
ot->flag |= OPTYPE_UNDO;
WM_operator_properties_filesel(
- ot, FILE_TYPE_FOLDER | FILE_TYPE_BLENDER, FILE_LOADLIB, FILE_OPENFILE,
+ ot, FILE_TYPE_FOLDER | FILE_TYPE_BLENDER | FILE_TYPE_BLENDERLIB, FILE_LOADLIB, FILE_OPENFILE,
WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILENAME | WM_FILESEL_FILES,
- FILE_DEFAULTDISPLAY);
+ FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
wm_link_append_properties_common(ot, false);
}
@@ -2872,7 +3075,7 @@ static void WM_OT_recover_auto_save(wmOperatorType *ot)
ot->invoke = wm_recover_auto_save_invoke;
WM_operator_properties_filesel(ot, FILE_TYPE_BLENDER, FILE_BLENDER, FILE_OPENFILE,
- WM_FILESEL_FILEPATH, FILE_LONGDISPLAY);
+ WM_FILESEL_FILEPATH, FILE_LONGDISPLAY, FILE_SORT_TIME);
}
/* *************** save file as **************** */
@@ -3005,7 +3208,7 @@ static void WM_OT_save_as_mainfile(wmOperatorType *ot)
/* omit window poll so this can work in background mode */
WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_BLENDER, FILE_BLENDER, FILE_SAVE,
- WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY);
+ WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
RNA_def_boolean(ot->srna, "compress", false, "Compress", "Write compressed .blend file");
RNA_def_boolean(ot->srna, "relative_remap", true, "Remap Relative",
"Remap relative paths when saving in a different directory");
@@ -3072,7 +3275,7 @@ static void WM_OT_save_mainfile(wmOperatorType *ot)
/* omit window poll so this can work in background mode */
WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_BLENDER, FILE_BLENDER, FILE_SAVE,
- WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY);
+ WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
RNA_def_boolean(ot->srna, "compress", false, "Compress", "Write compressed .blend file");
RNA_def_boolean(ot->srna, "relative_remap", false, "Remap Relative",
"Remap relative paths when saving in a different directory");
@@ -3120,7 +3323,7 @@ static int wm_console_toggle_exec(bContext *UNUSED(C), wmOperator *UNUSED(op))
static void WM_OT_console_toggle(wmOperatorType *ot)
{
/* XXX Have to mark these for xgettext, as under linux they do not exists... */
- ot->name = CTX_N_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Toggle System Console");
+ ot->name = CTX_N_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Toggle System Console");
ot->idname = "WM_OT_console_toggle";
ot->description = N_("Toggle System Console");
@@ -4377,7 +4580,7 @@ static void radial_control_cancel(bContext *C, wmOperator *op)
static int radial_control_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
RadialControl *rc = op->customdata;
- float new_value, dist, zoom[2];
+ float new_value, dist = 0.0f, zoom[2];
float delta[2], ret = OPERATOR_RUNNING_MODAL;
bool snap;
float angle_precision = 0.0f;
@@ -4897,6 +5100,72 @@ static void WM_OT_previews_ensure(wmOperatorType *ot)
ot->exec = previews_ensure_exec;
}
+/* *************************** Datablocks previews clear ************* */
+
+/* Only types supporting previews currently. */
+static EnumPropertyItem preview_id_type_items[] = {
+ {FILTER_ID_SCE, "SCENE", 0, "Scenes", ""},
+ {FILTER_ID_GR, "GROUP", 0, "Groups", ""},
+ {FILTER_ID_OB, "OBJECT", 0, "Objects", ""},
+ {FILTER_ID_MA, "MATERIAL", 0, "Materials", ""},
+ {FILTER_ID_LA, "LAMP", 0, "Lamps", ""},
+ {FILTER_ID_WO, "WORLD", 0, "Worlds", ""},
+ {FILTER_ID_TE, "TEXTURE", 0, "Textures", ""},
+ {FILTER_ID_IM, "IMAGE", 0, "Images", ""},
+#if 0 /* XXX TODO */
+ {FILTER_ID_BR, "BRUSH", 0, "Brushes", ""},
+#endif
+ {0, NULL, 0, NULL, NULL}
+};
+
+static int previews_clear_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ ListBase *lb[] = {&bmain->object, &bmain->group,
+ &bmain->mat, &bmain->world, &bmain->lamp, &bmain->tex, &bmain->image, NULL};
+ int i;
+
+ const int id_filters = RNA_enum_get(op->ptr, "id_type");
+
+ for (i = 0; lb[i]; i++) {
+ ID *id = lb[i]->first;
+
+ if (!id) continue;
+
+// printf("%s: %d, %d, %d -> %d\n", id->name, GS(id->name), BKE_idcode_to_idfilter(GS(id->name)),
+// id_filters, BKE_idcode_to_idfilter(GS(id->name)) & id_filters);
+
+ if (!id || !(BKE_idcode_to_idfilter(GS(id->name)) & id_filters)) {
+ continue;
+ }
+
+ for (; id; id = id->next) {
+ PreviewImage *prv_img = BKE_previewimg_id_ensure(id);
+
+ BKE_previewimg_clear(prv_img);
+ }
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+static void WM_OT_previews_clear(wmOperatorType *ot)
+{
+ ot->name = "Clear DataBlock Previews";
+ ot->idname = "WM_OT_previews_clear";
+ ot->description = "Clear datablock previews (only for some types like objects, materials, textures, etc.)";
+
+ ot->exec = previews_clear_exec;
+ ot->invoke = WM_menu_invoke;
+
+ ot->prop = RNA_def_enum_flag(ot->srna, "id_type", preview_id_type_items,
+ FILTER_ID_SCE | FILTER_ID_OB | FILTER_ID_GR |
+ FILTER_ID_MA | FILTER_ID_LA | FILTER_ID_WO | FILTER_ID_TE | FILTER_ID_IM,
+ "DataBlock Type", "Which datablock previews to clear");
+}
+
+/* *************************** Doc from UI ************* */
+
static int doc_view_manual_ui_context_exec(bContext *C, wmOperator *UNUSED(op))
{
PointerRNA ptr_props;
@@ -4992,6 +5261,7 @@ void wm_operatortype_init(void)
/* reserve size is set based on blender default setup */
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_read_history);
WM_operatortype_append(WM_OT_read_homefile);
@@ -5025,6 +5295,7 @@ void wm_operatortype_init(void)
WM_operatortype_append(WM_OT_console_toggle);
#endif
WM_operatortype_append(WM_OT_previews_ensure);
+ WM_operatortype_append(WM_OT_previews_clear);
WM_operatortype_append(WM_OT_doc_view_manual_ui_context);
}
diff --git a/source/blender/windowmanager/intern/wm_playanim.c b/source/blender/windowmanager/intern/wm_playanim.c
index e63b4661870..2150d94d9b0 100644
--- a/source/blender/windowmanager/intern/wm_playanim.c
+++ b/source/blender/windowmanager/intern/wm_playanim.c
@@ -77,10 +77,10 @@
# include AUD_SOUND_H
# include AUD_SPECIAL_H
-AUD_Sound *source = NULL;
-AUD_Handle *playback_handle = NULL;
-AUD_Handle *scrub_handle = NULL;
-AUD_Device *audio_device = NULL;
+static AUD_Sound *source = NULL;
+static AUD_Handle *playback_handle = NULL;
+static AUD_Handle *scrub_handle = NULL;
+static AUD_Device *audio_device = NULL;
#endif
/* simple limiter to avoid flooding memory */
@@ -383,7 +383,6 @@ static void build_pict_list_ex(PlayState *ps, const char *first, int totframes,
// short val;
PlayAnimPict *picture = NULL;
struct ImBuf *ibuf = NULL;
- char str[32 + FILE_MAX];
struct anim *anim;
if (IMB_isanim(first)) {
@@ -402,8 +401,7 @@ static void build_pict_list_ex(PlayState *ps, const char *first, int totframes,
picture->anim = anim;
picture->frame = pic;
picture->IB_flags = IB_rect;
- BLI_snprintf(str, sizeof(str), "%s : %4.d", first, pic + 1);
- picture->name = strdup(str);
+ picture->name = BLI_sprintfN("%s : %4.d", first, pic + 1);
BLI_addtail(&picsbase, picture);
}
}
@@ -414,7 +412,14 @@ static void build_pict_list_ex(PlayState *ps, const char *first, int totframes,
else {
int count = 0;
+ int fp_framenr;
+ struct {
+ char head[FILE_MAX], tail[FILE_MAX];
+ unsigned short digits;
+ } fp_decoded;
+
BLI_strncpy(filepath, first, sizeof(filepath));
+ fp_framenr = BLI_stringdec(filepath, fp_decoded.head, fp_decoded.tail, &fp_decoded.digits);
pupdate_time();
ptottime = 1.0;
@@ -480,8 +485,8 @@ static void build_pict_list_ex(PlayState *ps, const char *first, int totframes,
}
picture->mem = mem;
- picture->name = strdup(filepath);
- picture->frame = count; /* not exact but should work for positioning */
+ picture->name = BLI_strdup(filepath);
+ picture->frame = count;
close(file);
BLI_addtail(&picsbase, picture);
count++;
@@ -505,7 +510,9 @@ static void build_pict_list_ex(PlayState *ps, const char *first, int totframes,
ptottime = 0.0;
}
- BLI_newname(filepath, +fstep);
+ /* create a new filepath each time */
+ fp_framenr += fstep;
+ BLI_stringenc(filepath, fp_decoded.head, fp_decoded.tail, fp_decoded.digits, fp_framenr);
while ((hasevent = GHOST_ProcessEvents(g_WS.ghost_system, 0))) {
if (hasevent) {
@@ -544,17 +551,16 @@ static void update_sound_fps(void)
static void change_frame(PlayState *ps, int cx)
{
int sizex, sizey;
- int i;
+ int i, i_last;
- playanim_window_get_size(&sizex, &sizey);
- ps->picture = picsbase.first;
- /* TODO - store in ps direct? */
- i = 0;
- while (ps->picture) {
- i++;
- ps->picture = ps->picture->next;
+ if (BLI_listbase_is_empty(&picsbase)) {
+ return;
}
- i = (i * cx) / sizex;
+
+ playanim_window_get_size(&sizex, &sizey);
+ i_last = ((struct PlayAnimPict *)picsbase.last)->frame;
+ i = (i_last * cx) / sizex;
+ CLAMP(i, 0, i_last);
#ifdef WITH_AUDASPACE
if (scrub_handle) {
@@ -588,11 +594,8 @@ static void change_frame(PlayState *ps, int cx)
}
#endif
- ps->picture = picsbase.first;
- for (; i > 0; i--) {
- if (ps->picture->next == NULL) break;
- ps->picture = ps->picture->next;
- }
+ ps->picture = BLI_findlink(&picsbase, i);
+ BLI_assert(ps->picture != NULL);
ps->sstep = true;
ps->wait2 = false;
@@ -977,6 +980,19 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
GHOST_TEventCursorData *cd = GHOST_GetEventData(evt);
int cx, cy;
+ /* Ignore 'in-between' events, since they can make scrubbing lag.
+ *
+ * Ideally we would keep into the event queue and see if this is the last motion event.
+ * however the API currently doesn't support this. */
+ {
+ int x_test, y_test;
+ GHOST_GetCursorPosition(g_WS.ghost_system, &x_test, &y_test);
+ if (x_test != cd->x || y_test != cd->y) {
+ /* we're not the last event... skipping */
+ break;
+ }
+ }
+
GHOST_ScreenToClient(g_WS.ghost_window, cd->x, cd->y, &cx, &cy);
change_frame(ps, cx);
@@ -1093,7 +1109,6 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
GHOST_TUns32 maxwinx, maxwiny;
int i;
/* This was done to disambiguate the name for use under c++. */
- struct anim *anim = NULL;
int start_x = 0, start_y = 0;
int sfra = -1;
int efra = -1;
@@ -1101,20 +1116,6 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
PlayState ps = {0};
-#ifdef WITH_AUDASPACE
- AUD_DeviceSpecs specs;
-
- specs.rate = AUD_RATE_44100;
- specs.format = AUD_FORMAT_S16;
- specs.channels = AUD_CHANNELS_STEREO;
-
- AUD_initOnce();
-
- if (!(audio_device = AUD_init("OpenAL", specs, 1024, "Blender")))
- audio_device = AUD_init("Null", specs, 0, "Blender");
-
-#endif
-
/* ps.doubleb = true;*/ /* UNUSED */
ps.go = true;
ps.direction = true;
@@ -1208,12 +1209,13 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
BLI_strncpy(filepath, argv[1], sizeof(filepath));
}
else {
- BLI_current_working_dir(filepath, sizeof(filepath));
- BLI_add_slash(filepath);
+ printf("%s: no filepath argument given\n", __func__);
+ exit(1);
}
if (IMB_isanim(filepath)) {
/* OCIO_TODO: support different input color spaces */
+ struct anim *anim;
anim = IMB_open_anim(filepath, IB_rect, 0, NULL);
if (anim) {
ibuf = IMB_anim_absolute(anim, 0, IMB_TC_NONE, IMB_PROXY_NONE);
@@ -1485,13 +1487,13 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
}
}
}
- ps.picture = picsbase.first;
- anim = NULL;
- while (ps.picture) {
- if (ps.picture && ps.picture->anim && (anim != ps.picture->anim)) {
- // to prevent divx crashes
- anim = ps.picture->anim;
- IMB_close_anim(anim);
+ while ((ps.picture = BLI_pophead(&picsbase))) {
+ if (ps.picture->anim) {
+ if ((ps.picture->next == NULL) ||
+ (ps.picture->next->anim != ps.picture->anim))
+ {
+ IMB_close_anim(ps.picture->anim);
+ }
}
if (ps.picture->ibuf) {
@@ -1501,7 +1503,8 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
MEM_freeN(ps.picture->mem);
}
- ps.picture = ps.picture->next;
+ MEM_freeN((void *)ps.picture->name);
+ MEM_freeN(ps.picture);
}
/* cleanup */
@@ -1514,12 +1517,16 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
added_images = 0;
#ifdef WITH_AUDASPACE
- if (playback_handle)
+ if (playback_handle) {
AUD_Handle_stop(playback_handle);
- if (scrub_handle)
+ playback_handle = NULL;
+ }
+ if (scrub_handle) {
AUD_Handle_stop(scrub_handle);
+ scrub_handle = NULL;
+ }
AUD_Sound_free(source);
- AUD_exit(audio_device);
+ source = NULL;
#endif
#if 0 // XXX25
@@ -1557,18 +1564,43 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
void WM_main_playanim(int argc, const char **argv)
{
+ const char *argv_next[2];
bool looping = true;
+#ifdef WITH_AUDASPACE
+ {
+ AUD_DeviceSpecs specs;
+
+ specs.rate = AUD_RATE_44100;
+ specs.format = AUD_FORMAT_S16;
+ specs.channels = AUD_CHANNELS_STEREO;
+
+ AUD_initOnce();
+
+ if (!(audio_device = AUD_init("OpenAL", specs, 1024, "Blender"))) {
+ audio_device = AUD_init("Null", specs, 0, "Blender");
+ }
+ }
+#endif
+
while (looping) {
const char *filepath = wm_main_playanim_intern(argc, argv);
if (filepath) { /* use simple args */
- argv[1] = "-a";
- argv[2] = filepath;
- argc = 3;
+ argv_next[0] = argv[0];
+ argv_next[1] = filepath;
+ argc = 2;
+
+ /* continue with new args */
+ argv = argv_next;
}
else {
looping = false;
}
}
+
+#ifdef WITH_AUDASPACE
+ AUD_exit(audio_device);
+ AUD_exitOnce();
+#endif
}
diff --git a/source/blender/windowmanager/intern/wm_stereo.c b/source/blender/windowmanager/intern/wm_stereo.c
index b3ddb2499dd..98c45bfb6ea 100644
--- a/source/blender/windowmanager/intern/wm_stereo.c
+++ b/source/blender/windowmanager/intern/wm_stereo.c
@@ -369,7 +369,7 @@ bool WM_stereo3d_enabled(wmWindow *win, bool skip_stereo3d_check)
{
bScreen *screen = win->screen;
- /* some 3d methods change the window arrangment, thus they shouldn't
+ /* some 3d methods change the window arrangement, thus they shouldn't
* toggle on/off just because there is no 3d elements being drawn */
if (wm_stereo3d_is_fullscreen_required(win->stereo3d_format->display_mode)) {
return GHOST_GetWindowState(win->ghostwin) == GHOST_kWindowStateFullScreen;
@@ -379,7 +379,7 @@ bool WM_stereo3d_enabled(wmWindow *win, bool skip_stereo3d_check)
return false;
}
- /* some 3d methods change the window arrangment, thus they shouldn't
+ /* some 3d methods change the window arrangement, thus they shouldn't
* toggle on/off just because there is no 3d elements being drawn */
if (wm_stereo3d_is_fullscreen_required(win->stereo3d_format->display_mode)) {
return GHOST_GetWindowState(win->ghostwin) == GHOST_kWindowStateFullScreen;
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c
index c5387242206..d8e6671afda 100644
--- a/source/blender/windowmanager/intern/wm_window.c
+++ b/source/blender/windowmanager/intern/wm_window.c
@@ -47,7 +47,7 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
-#include "BLF_translation.h"
+#include "BLT_translation.h"
#include "BKE_blender.h"
#include "BKE_context.h"
@@ -329,12 +329,17 @@ void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win)
CTX_wm_window_set(C, win); /* needed by handlers */
WM_event_remove_handlers(C, &win->handlers);
WM_event_remove_handlers(C, &win->modalhandlers);
- ED_screen_exit(C, win, win->screen);
+
+ /* for regular use this will _never_ be NULL,
+ * however we may be freeing an improperly initialized window. */
+ if (win->screen) {
+ ED_screen_exit(C, win, win->screen);
+ }
wm_window_free(C, wm, win);
/* if temp screen, delete it after window free (it stops jobs that can access it) */
- if (screen->temp) {
+ if (screen && screen->temp) {
Main *bmain = CTX_data_main(C);
BKE_libblock_free(bmain, screen);
}
@@ -380,7 +385,7 @@ float wm_window_pixelsize(wmWindow *win)
}
/* belongs to below */
-static void wm_window_add_ghostwindow(wmWindowManager *wm, const char *title, wmWindow *win)
+static void wm_window_ghostwindow_add(wmWindowManager *wm, const char *title, wmWindow *win)
{
GHOST_WindowHandle ghostwin;
GHOST_GLSettings glSettings = {0};
@@ -466,14 +471,26 @@ static void wm_window_add_ghostwindow(wmWindowManager *wm, const char *title, wm
}
}
-/* for wmWindows without ghostwin, open these and clear */
-/* window size is read from window, if 0 it uses prefsize */
-/* called in WM_check, also inits stuff after file read */
-void wm_window_add_ghostwindows(wmWindowManager *wm)
+/**
+ * Initialize #wmWindows without ghostwin, open these and clear.
+ *
+ * window size is read from window, if 0 it uses prefsize
+ * called in #WM_check, also inits stuff after file read.
+ *
+ * \warning
+ * After running, 'win->ghostwin' can be NULL in rare cases
+ * (where OpenGL driver fails to create a context for eg).
+ * We could remove them with #wm_window_ghostwindows_remove_invalid
+ * but better not since caller may continue to use.
+ * Instead, caller needs to handle the error case and cleanup.
+ */
+void wm_window_ghostwindows_ensure(wmWindowManager *wm)
{
wmKeyMap *keymap;
wmWindow *win;
+ BLI_assert(G.background == false);
+
/* no commandline prefsize? then we set this.
* Note that these values will be used only
* when there is no startup.blend yet.
@@ -521,7 +538,7 @@ void wm_window_add_ghostwindows(wmWindowManager *wm)
win->cursor = CURSOR_STD;
}
- wm_window_add_ghostwindow(wm, "Blender", win);
+ wm_window_ghostwindow_add(wm, "Blender", win);
}
/* happens after fileread */
if (win->eventstate == NULL)
@@ -546,11 +563,33 @@ void wm_window_add_ghostwindows(wmWindowManager *wm)
}
}
-/* new window, no screen yet, but we open ghostwindow for it */
-/* also gets the window level handlers */
-/* area-rip calls this */
+/**
+ * Call after #wm_window_ghostwindows_ensure or #WM_check
+ * (after loading a new file) in the unlikely event a window couldn't be created.
+ */
+void wm_window_ghostwindows_remove_invalid(bContext *C, wmWindowManager *wm)
+{
+ wmWindow *win, *win_next;
+
+ BLI_assert(G.background == false);
+
+ for (win = wm->windows.first; win; win = win_next) {
+ win_next = win->next;
+ if (win->ghostwin == NULL) {
+ wm_window_close(C, wm, win);
+ }
+ }
+}
+
+/**
+ * new window, no screen yet, but we open ghostwindow for it,
+ * also gets the window level handlers
+ * \note area-rip calls this.
+ * \return the window or NULL.
+ */
wmWindow *WM_window_open(bContext *C, const rcti *rect)
{
+ wmWindow *win_prev = CTX_wm_window(C);
wmWindow *win = wm_window_new(C);
win->posx = rect->xmin;
@@ -561,22 +600,35 @@ wmWindow *WM_window_open(bContext *C, const rcti *rect)
win->drawmethod = U.wmdrawmethod;
WM_check(C);
-
- return win;
-}
-/* uses screen->temp tag to define what to do, currently it limits
- * to only one "temp" window for render out, preferences, filewindow, etc */
-/* type is defined in WM_api.h */
+ if (win->ghostwin) {
+ return win;
+ }
+ else {
+ wm_window_close(C, CTX_wm_manager(C), win);
+ CTX_wm_window_set(C, win_prev);
+ return NULL;
+ }
+}
-void WM_window_open_temp(bContext *C, rcti *position, int type)
+/**
+ * Uses `screen->temp` tag to define what to do, currently it limits
+ * to only one "temp" window for render out, preferences, filewindow, etc...
+ *
+ * \param type: WM_WINDOW_RENDER, WM_WINDOW_USERPREFS...
+ * \return the window or NULL.
+ */
+wmWindow *WM_window_open_temp(bContext *C, const rcti *rect_init, int type)
{
+ wmWindow *win_prev = CTX_wm_window(C);
wmWindow *win;
ScrArea *sa;
Scene *scene = CTX_data_scene(C);
-
+ const char *title;
+ rcti rect = *rect_init;
+
/* changes rect to fit within desktop */
- wm_window_check_position(position);
+ wm_window_check_position(&rect);
/* test if we have a temp screen already */
for (win = CTX_wm_manager(C)->windows.first; win; win = win->next)
@@ -587,12 +639,12 @@ void WM_window_open_temp(bContext *C, rcti *position, int type)
if (win == NULL) {
win = wm_window_new(C);
- win->posx = position->xmin;
- win->posy = position->ymin;
+ win->posx = rect.xmin;
+ win->posy = rect.ymin;
}
- win->sizex = BLI_rcti_size_x(position);
- win->sizey = BLI_rcti_size_y(position);
+ 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);
@@ -614,7 +666,13 @@ void WM_window_open_temp(bContext *C, rcti *position, int type)
/* make window active, and validate/resize */
CTX_wm_window_set(C, win);
WM_check(C);
-
+
+ /* It's possible `win->ghostwin == NULL`.
+ * instead of attempting to cleanup here (in a half finished state),
+ * finish setting up the screen, then free it at the end of the function,
+ * to avoid having to take into account a partially-created window.
+ */
+
/* ensure it shows the right spacetype editor */
sa = win->screen->areabase.first;
CTX_wm_area_set(C, sa);
@@ -630,18 +688,38 @@ void WM_window_open_temp(bContext *C, rcti *position, int type)
ED_screen_refresh(CTX_wm_manager(C), win); /* test scale */
if (sa->spacetype == SPACE_IMAGE)
- GHOST_SetTitle(win->ghostwin, IFACE_("Blender Render"));
+ title = IFACE_("Blender Render");
else if (ELEM(sa->spacetype, SPACE_OUTLINER, SPACE_USERPREF))
- GHOST_SetTitle(win->ghostwin, IFACE_("Blender User Preferences"));
+ title = IFACE_("Blender User Preferences");
else if (sa->spacetype == SPACE_FILE)
- GHOST_SetTitle(win->ghostwin, IFACE_("Blender File View"));
+ title = IFACE_("Blender File View");
else
- GHOST_SetTitle(win->ghostwin, "Blender");
+ title = "Blender";
+
+ if (win->ghostwin) {
+ GHOST_SetTitle(win->ghostwin, title);
+ return win;
+ }
+ else {
+ /* very unlikely! but opening a new window can fail */
+ wm_window_close(C, CTX_wm_manager(C), win);
+ CTX_wm_window_set(C, win_prev);
+
+ return NULL;
+ }
}
/* ****************** Operators ****************** */
+int wm_window_close_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wmWindow *win = CTX_wm_window(C);
+ wm_window_close(C, wm, win);
+ return OPERATOR_FINISHED;
+}
+
/* operator callback */
int wm_window_duplicate_exec(bContext *C, wmOperator *UNUSED(op))
{
@@ -676,7 +754,7 @@ int wm_window_fullscreen_toggle_exec(bContext *C, wmOperator *UNUSED(op))
/* ************ events *************** */
-static void wm_convert_cursor_position(wmWindow *win, int *x, int *y)
+void wm_cursor_position_from_ghost(wmWindow *win, int *x, int *y)
{
float fac = GHOST_GetNativePixelSize(win->ghostwin);
@@ -687,11 +765,21 @@ static void wm_convert_cursor_position(wmWindow *win, int *x, int *y)
*y *= fac;
}
+void wm_cursor_position_to_ghost(wmWindow *win, int *x, int *y)
+{
+ float fac = GHOST_GetNativePixelSize(win->ghostwin);
+
+ *x /= fac;
+ *y /= fac;
+ *y = win->sizey - *y - 1;
+
+ GHOST_ClientToScreen(win->ghostwin, *x, *y, x, y);
+}
void wm_get_cursor_position(wmWindow *win, int *x, int *y)
{
GHOST_GetCursorPosition(g_system, x, y);
- wm_convert_cursor_position(win, x, y);
+ wm_cursor_position_from_ghost(win, x, y);
}
typedef enum {
@@ -1017,9 +1105,12 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
#if defined(__APPLE__) || defined(WIN32)
/* OSX and Win32 don't return to the mainloop while resize */
- wm_event_do_handlers(C);
wm_event_do_notifiers(C);
wm_draw_update(C);
+
+ /* Warning! code above nulls 'C->wm.window', causing BGE to quit, see: T45699.
+ * Further, its easier to match behavior across platforms, so restore the window. */
+ CTX_wm_window_set(C, win);
#endif
}
}
@@ -1115,7 +1206,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
{
GHOST_TEventTrackpadData *pd = data;
- wm_convert_cursor_position(win, &pd->x, &pd->y);
+ wm_cursor_position_from_ghost(win, &pd->x, &pd->y);
wm_event_add_ghostevent(wm, win, type, time, data);
break;
}
@@ -1123,7 +1214,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
{
GHOST_TEventCursorData *cd = data;
- wm_convert_cursor_position(win, &cd->x, &cd->y);
+ wm_cursor_position_from_ghost(win, &cd->x, &cd->y);
wm_event_add_ghostevent(wm, win, type, time, data);
break;
}
@@ -1166,6 +1257,8 @@ static int wm_window_timer(const bContext *C)
wm_jobs_timer(C, wm, wt);
else if (wt->event_type == TIMERAUTOSAVE)
wm_autosave_timer(C, wm, wt);
+ else if (wt->event_type == TIMERNOTIFIER)
+ WM_main_add_notifier(GET_UINT_FROM_POINTER(wt->customdata), NULL);
else if (win) {
wmEvent event;
wm_event_init_from_window(win, &event);
@@ -1272,7 +1365,7 @@ void WM_event_timer_sleep(wmWindowManager *wm, wmWindow *UNUSED(win), wmTimer *t
wmTimer *WM_event_add_timer(wmWindowManager *wm, wmWindow *win, int event_type, double timestep)
{
wmTimer *wt = MEM_callocN(sizeof(wmTimer), "window timer");
-
+
wt->event_type = event_type;
wt->ltime = PIL_check_seconds_timer();
wt->ntime = wt->ltime + timestep;
@@ -1285,6 +1378,23 @@ wmTimer *WM_event_add_timer(wmWindowManager *wm, wmWindow *win, int event_type,
return wt;
}
+wmTimer *WM_event_add_timer_notifier(wmWindowManager *wm, wmWindow *win, unsigned int type, double timestep)
+{
+ wmTimer *wt = MEM_callocN(sizeof(wmTimer), "window timer");
+
+ wt->event_type = TIMERNOTIFIER;
+ wt->ltime = PIL_check_seconds_timer();
+ wt->ntime = wt->ltime + timestep;
+ wt->stime = wt->ltime;
+ wt->timestep = timestep;
+ wt->win = win;
+ wt->customdata = SET_UINT_IN_POINTER(type);
+
+ BLI_addtail(&wm->timers, wt);
+
+ return wt;
+}
+
void WM_event_remove_timer(wmWindowManager *wm, wmWindow *UNUSED(win), wmTimer *timer)
{
wmTimer *wt;
@@ -1317,6 +1427,12 @@ void WM_event_remove_timer(wmWindowManager *wm, wmWindow *UNUSED(win), wmTimer *
}
}
+void WM_event_remove_timer_notifier(wmWindowManager *wm, wmWindow *win, wmTimer *timer)
+{
+ timer->customdata = NULL;
+ WM_event_remove_timer(wm, win, timer);
+}
+
/* ******************* clipboard **************** */
static char *wm_clipboard_text_get_ex(bool selection, int *r_len,
@@ -1513,14 +1629,9 @@ void WM_init_native_pixels(bool do_it)
void WM_cursor_warp(wmWindow *win, int x, int y)
{
if (win && win->ghostwin) {
- float f = GHOST_GetNativePixelSize(win->ghostwin);
int oldx = x, oldy = y;
- x = x / f;
- y = y / f;
- y = win->sizey - y - 1;
-
- GHOST_ClientToScreen(win->ghostwin, x, y, &x, &y);
+ wm_cursor_position_to_ghost(win, &x, &y);
GHOST_SetCursorPosition(g_system, x, y);
win->eventstate->prevx = oldx;
@@ -1532,6 +1643,18 @@ void WM_cursor_warp(wmWindow *win, int x, int y)
}
/**
+ * Set x, y to values we can actually position the cursor to.
+ */
+void WM_cursor_compatible_xy(wmWindow *win, int *x, int *y)
+{
+ float f = GHOST_GetNativePixelSize(win->ghostwin);
+ if (f != 1.0f) {
+ *x = (int)(*x / f) * f;
+ *y = (int)(*y / f) * f;
+ }
+}
+
+/**
* Get the cursor pressure, in most cases you'll want to use wmTabletData from the event
*/
float WM_cursor_pressure(const struct wmWindow *win)
diff --git a/source/blender/windowmanager/wm_event_types.h b/source/blender/windowmanager/wm_event_types.h
index ecc29de0e7d..390e769aa88 100644
--- a/source/blender/windowmanager/wm_event_types.h
+++ b/source/blender/windowmanager/wm_event_types.h
@@ -303,6 +303,7 @@ enum {
TIMERAUTOSAVE = 0x0115, /* timer event, autosave */
TIMERREPORT = 0x0116, /* timer event, reports */
TIMERREGION = 0x0117, /* timer event, region slide in/out */
+ TIMERNOTIFIER = 0x0118, /* timer event, notifier sender */
TIMERF = 0x011F, /* last timer */
/* Tweak, gestures: 0x500x, 0x501x */
diff --git a/source/blender/windowmanager/wm_files.h b/source/blender/windowmanager/wm_files.h
index 526696138a5..4b35f662a99 100644
--- a/source/blender/windowmanager/wm_files.h
+++ b/source/blender/windowmanager/wm_files.h
@@ -31,13 +31,14 @@
#ifndef __WM_FILES_H__
#define __WM_FILES_H__
-void wm_read_history(void);
+void wm_history_file_read(void);
+int wm_history_file_read_exec(bContext *C, wmOperator *op);
int wm_file_write(struct bContext *C, const char *target, int fileflags, struct ReportList *reports);
-int wm_history_read_exec(bContext *C, wmOperator *op);
int wm_homefile_read_exec(struct bContext *C, struct wmOperator *op);
int wm_homefile_read(struct bContext *C, struct ReportList *reports, bool from_memory, const char *filepath);
int wm_homefile_write_exec(struct bContext *C, struct wmOperator *op);
int wm_userpref_write_exec(struct bContext *C, struct wmOperator *op);
+void wm_file_read_report(bContext *C);
#endif /* __WM_FILES_H__ */
diff --git a/source/blender/windowmanager/wm_window.h b/source/blender/windowmanager/wm_window.h
index a104f6aba39..c106f9d7851 100644
--- a/source/blender/windowmanager/wm_window.h
+++ b/source/blender/windowmanager/wm_window.h
@@ -48,7 +48,8 @@ void wm_window_free (bContext *C, wmWindowManager *wm, wmWindow *win);
void wm_window_close (bContext *C, wmWindowManager *wm, wmWindow *win);
void wm_window_title (wmWindowManager *wm, wmWindow *win);
-void wm_window_add_ghostwindows (wmWindowManager *wm);
+void wm_window_ghostwindows_ensure(wmWindowManager *wm);
+void wm_window_ghostwindows_remove_invalid(bContext *C, wmWindowManager *wm);
void wm_window_process_events (const bContext *C);
void wm_window_process_events_nosleep(void);
@@ -64,7 +65,9 @@ bool wm_window_get_swap_interval(wmWindow *win, int *intervalOut);
float wm_window_pixelsize(wmWindow *win);
-void wm_get_cursor_position (wmWindow *win, int *x, int *y);
+void wm_get_cursor_position (wmWindow *win, int *x, int *y);
+void wm_cursor_position_from_ghost (wmWindow *win, int *x, int *y);
+void wm_cursor_position_to_ghost (wmWindow *win, int *x, int *y);
void wm_window_testbreak (void);
@@ -74,6 +77,7 @@ void wm_window_IME_end (wmWindow *win);
#endif
/* *************** window operators ************** */
+int wm_window_close_exec(bContext *C, struct wmOperator *op);
int wm_window_duplicate_exec(bContext *C, struct wmOperator *op);
int wm_window_fullscreen_toggle_exec(bContext *C, struct wmOperator *op);