diff options
Diffstat (limited to 'source/blender/windowmanager')
22 files changed, 1855 insertions, 435 deletions
diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt index 78b5d499644..3f5c86857b7 100644 --- a/source/blender/windowmanager/CMakeLists.txt +++ b/source/blender/windowmanager/CMakeLists.txt @@ -64,6 +64,7 @@ set(SRC intern/wm_operators.c intern/wm_subwindow.c intern/wm_window.c + intern/wm_stereo.c WM_api.h WM_keymap.h @@ -78,6 +79,13 @@ set(SRC wm_window.h ) +if(WITH_AUDASPACE) + list(APPEND INC + ../../../intern/audaspace/intern + ) + add_definitions(-DWITH_AUDASPACE) +endif() + add_definitions(${GL_DEFINITIONS}) if(WITH_INTERNATIONAL) diff --git a/source/blender/windowmanager/SConscript b/source/blender/windowmanager/SConscript index a6f64f7cdae..912d11762e1 100644 --- a/source/blender/windowmanager/SConscript +++ b/source/blender/windowmanager/SConscript @@ -32,6 +32,7 @@ sources = env.Glob('intern/*.c') incs = [ '.', + '#/intern/audaspace/intern', '#/intern/ghost', '#/intern/guardedalloc', '#/intern/memutil', diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index d2abfd419d1..bdb373a78ba 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -53,13 +53,11 @@ struct wmEvent; struct wmEventHandler; struct wmGesture; struct wmJob; -struct wmNotifier; struct wmOperatorType; struct wmOperator; struct rcti; struct PointerRNA; struct PropertyRNA; -struct EnumPropertyItem; struct MenuType; struct wmDropBox; struct wmDrag; @@ -105,6 +103,7 @@ void WM_window_open_temp (struct bContext *C, struct rcti *position, int type); /* returns true if draw method is triple buffer */ bool WM_is_draw_triple(struct wmWindow *win); +bool WM_stereo3d_enabled(struct wmWindow *win, bool only_fullscreen_test); /* files */ @@ -152,7 +151,7 @@ typedef void (*wmUIHandlerRemoveFunc)(struct bContext *C, void *userdata); struct wmEventHandler *WM_event_add_ui_handler( const struct bContext *C, ListBase *handlers, wmUIHandlerFunc ui_handle, wmUIHandlerRemoveFunc ui_remove, - void *userdata, const bool accept_dbl_click); + void *userdata, const char flag); void WM_event_remove_ui_handler( ListBase *handlers, wmUIHandlerFunc ui_handle, wmUIHandlerRemoveFunc ui_remove, @@ -166,23 +165,42 @@ void WM_event_free_ui_handler_all( struct wmEventHandler *WM_event_add_modal_handler(struct bContext *C, struct wmOperator *op); void WM_event_remove_handlers(struct bContext *C, ListBase *handlers); +/* handler flag */ +enum { + WM_HANDLER_BLOCKING = (1 << 0), /* after this handler all others are ignored */ + WM_HANDLER_ACCEPT_DBL_CLICK = (1 << 1), /* handler accepts double key press events */ + + /* internal */ + WM_HANDLER_DO_FREE = (1 << 7), /* handler tagged to be freed in wm_handlers_do() */ +}; + struct wmEventHandler *WM_event_add_dropbox_handler(ListBase *handlers, ListBase *dropboxes); /* mouse */ void WM_event_add_mousemove(struct bContext *C); bool WM_modal_tweak_exit(const struct wmEvent *event, int tweak_event); +bool WM_event_is_absolute(const struct wmEvent *event); /* notifiers */ void WM_event_add_notifier(const struct bContext *C, unsigned int type, void *reference); void WM_main_add_notifier(unsigned int type, void *reference); void WM_main_remove_notifier_reference(const void *reference); +void WM_main_remove_editor_id_reference(const struct ID *id); /* reports */ +void WM_report_banner_show(const struct bContext *C); void WM_report(const struct bContext *C, ReportType type, const char *message); void WM_reportf(const struct bContext *C, ReportType type, const char *format, ...) ATTR_PRINTF_FORMAT(3, 4); -void wm_event_add(struct wmWindow *win, const struct wmEvent *event_to_add); -void wm_event_init_from_window(struct wmWindow *win, struct wmEvent *event); +void wm_event_add_ex( + struct wmWindow *win, const struct wmEvent *event_to_add, + const struct wmEvent *event_to_add_after) + ATTR_NONNULL(1, 2); +void wm_event_add( + struct wmWindow *win, const struct wmEvent *event_to_add) + ATTR_NONNULL(1, 2); + +void wm_event_init_from_window(struct wmWindow *win, struct wmEvent *event); /* at maximum, every timestep seconds it triggers event_type events */ diff --git a/source/blender/windowmanager/WM_keymap.h b/source/blender/windowmanager/WM_keymap.h index c6c7314e963..fdde28c6bf1 100644 --- a/source/blender/windowmanager/WM_keymap.h +++ b/source/blender/windowmanager/WM_keymap.h @@ -101,7 +101,8 @@ int WM_keymap_map_type_get(struct wmKeyMapItem *kmi); const char *WM_key_event_string(short type); int WM_key_event_operator_id( const struct bContext *C, const char *opname, int opcontext, - struct IDProperty *properties, const bool is_hotkey, struct wmKeyMap **keymap_r); + struct IDProperty *properties, const bool is_hotkey, + struct wmKeyMap **r_keymap); char *WM_key_event_operator_string( const struct bContext *C, const char *opname, int opcontext, struct IDProperty *properties, const bool is_strict, char *str, int len); diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index 0e3e65d2e21..109ccc27d79 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -109,7 +109,6 @@ extern "C" { struct bContext; struct wmEvent; struct wmWindowManager; -struct uiLayout; struct wmOperator; struct ImBuf; @@ -124,17 +123,22 @@ struct ImBuf; /* ************** wmOperatorType ************************ */ /* flag */ -#define OPTYPE_REGISTER 1 /* register operators in stack after finishing */ -#define OPTYPE_UNDO 2 /* do undo push after after */ -#define OPTYPE_BLOCKING 4 /* let blender grab all input from the WM (X11) */ -#define OPTYPE_MACRO 8 -#define OPTYPE_GRAB_POINTER 16 /* grabs the cursor and optionally enables continuous cursor wrapping */ -#define OPTYPE_PRESET 32 /* show preset menu */ -#define OPTYPE_INTERNAL 64 /* some operators are mainly for internal use - * and don't make sense to be accessed from the - * search menu, even if poll() returns true. - * currently only used for the search toolbox */ -#define OPTYPE_LOCK_BYPASS 128 /* Allow operator to run when interface is locked */ +enum { + OPTYPE_REGISTER = (1 << 0), /* register operators in stack after finishing */ + OPTYPE_UNDO = (1 << 1), /* do undo push after after */ + OPTYPE_BLOCKING = (1 << 2), /* let blender grab all input from the WM (X11) */ + OPTYPE_MACRO = (1 << 3), + OPTYPE_GRAB_CURSOR = (1 << 4), /* grabs the cursor and optionally enables continuous cursor wrapping */ + OPTYPE_PRESET = (1 << 5), /* show preset menu */ + + /* some operators are mainly for internal use + * and don't make sense to be accessed from the + * search menu, even if poll() returns true. + * currently only used for the search toolbox */ + OPTYPE_INTERNAL = (1 << 6), + + OPTYPE_LOCK_BYPASS = (1 << 7), /* Allow operator to run when interface is locked */ +}; /* context to call operator in for WM_operator_name_call */ /* rna_ui.c contains EnumPropertyItem's of these, keep in sync */ @@ -454,7 +458,7 @@ typedef struct wmEvent { const char *keymap_idname; /* tablet info, only use when the tablet is active */ - struct wmTabletData *tablet_data; + const struct wmTabletData *tablet_data; /* custom data */ short custom; /* custom data type, stylus, 6dof, see wm_event_types.h */ diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c index 34069e0b873..c8ff6dac754 100644 --- a/source/blender/windowmanager/intern/wm.c +++ b/source/blender/windowmanager/intern/wm.c @@ -228,7 +228,7 @@ uiListType *WM_uilisttype_find(const char *idname, bool quiet) bool WM_uilisttype_add(uiListType *ult) { - BLI_ghash_insert(uilisttypes_hash, (void *)ult->idname, ult); + BLI_ghash_insert(uilisttypes_hash, ult->idname, ult); return 1; } @@ -285,7 +285,7 @@ MenuType *WM_menutype_find(const char *idname, bool quiet) bool WM_menutype_add(MenuType *mt) { - BLI_ghash_insert(menutypes_hash, (void *)mt->idname, mt); + BLI_ghash_insert(menutypes_hash, mt->idname, mt); return true; } diff --git a/source/blender/windowmanager/intern/wm_cursors.c b/source/blender/windowmanager/intern/wm_cursors.c index 68fd32cb450..d84b65847ca 100644 --- a/source/blender/windowmanager/intern/wm_cursors.c +++ b/source/blender/windowmanager/intern/wm_cursors.c @@ -313,21 +313,22 @@ void WM_cursor_time(wmWindow *win, int nr) } -/* ****************************************************************** - * Custom Cursor Description: +/** + * Custom Cursor Description + * ========================= * * Each bit represents a pixel, so 1 byte = 8 pixels, * the bytes go Left to Right. Top to bottom * the bits in a byte go right to left * (ie; 0x01, 0x80 represents a line of 16 pix with the first and last pix set.) * - * A 0 in the bitmap = bg_color, a 1 fg_color - * a 0 in the mask = transparent pix. + * - A 0 in the bitmap = bg_color, a 1 fg_color + * - a 0 in the mask = transparent pix. * * Until 32x32 cursors are supported on all platforms, the size of the * small cursors MUST be 16x16. * - * Large cursors have a MAXSIZE of 32x32. + * Large cursors have a maximum size of 32x32. * * Other than that, the specified size of the cursors is just a guideline, * However, the char array that defines the BM and MASK must be byte aligned. @@ -335,18 +336,20 @@ void WM_cursor_time(wmWindow *win, int nr) * (3 bytes = 17 bits rounded up to nearest whole byte). Pad extra bits * in mask with 0's. * - * Setting big_bm = NULL disables the large version of the cursor. + * Setting `big_bm = NULL` disables the large version of the cursor. * - * ******************************************************************* + * ---- * * There is a nice Python GUI utility that can be used for drawing cursors in * this format in the Blender source distribution, in - * blender/source/tools/MakeCursor.py . Start it with $ python MakeCursor.py - * It will copy its output to the console when you press 'Do it'. + * `./source/tools/utils/make_cursor_gui.py` . * + * Start it with the command `python3 make_cursor_gui.py` + * It will copy its output to the console when you press 'Do it'. */ -/* Because defining a cursor mixes declarations and executable code +/** + * Because defining a cursor mixes declarations and executable code * each cursor needs it's own scoping block or it would be split up * over several hundred lines of code. To enforce/document this better * I define 2 pretty brain-dead macros so it's obvious what the extra "[]" diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c index 7440570f4a0..16fe9ca5142 100644 --- a/source/blender/windowmanager/intern/wm_draw.c +++ b/source/blender/windowmanager/intern/wm_draw.c @@ -48,9 +48,11 @@ #include "BIF_gl.h" #include "BKE_context.h" +#include "BKE_image.h" #include "GHOST_C-api.h" +#include "ED_node.h" #include "ED_view3d.h" #include "ED_screen.h" @@ -165,6 +167,7 @@ static void wm_method_draw_full(bContext *C, wmWindow *win) if (ar->swinid) { CTX_wm_region_set(C, ar); ED_region_do_draw(C, ar); + ar->do_draw = false; wm_paintcursor_draw(C, ar); CTX_wm_region_set(C, NULL); } @@ -175,12 +178,14 @@ static void wm_method_draw_full(bContext *C, wmWindow *win) } ED_screen_draw(win); + win->screen->do_draw = false; /* draw overlapping regions */ for (ar = screen->regionbase.first; ar; ar = ar->next) { if (ar->swinid) { CTX_wm_menu_set(C, ar); ED_region_do_draw(C, ar); + ar->do_draw = false; CTX_wm_menu_set(C, NULL); } } @@ -278,6 +283,7 @@ static void wm_method_draw_overlap_all(bContext *C, wmWindow *win, int exchange) if (ar->do_draw) { CTX_wm_region_set(C, ar); ED_region_do_draw(C, ar); + ar->do_draw = false; wm_paintcursor_draw(C, ar); CTX_wm_region_set(C, NULL); @@ -288,6 +294,7 @@ static void wm_method_draw_overlap_all(bContext *C, wmWindow *win, int exchange) if (ar->swap == WIN_FRONT_OK) { CTX_wm_region_set(C, ar); ED_region_do_draw(C, ar); + ar->do_draw = false; wm_paintcursor_draw(C, ar); CTX_wm_region_set(C, NULL); @@ -300,7 +307,7 @@ static void wm_method_draw_overlap_all(bContext *C, wmWindow *win, int exchange) } } } - + wm_area_mark_invalid_backbuf(sa); CTX_wm_area_set(C, NULL); } @@ -308,6 +315,7 @@ static void wm_method_draw_overlap_all(bContext *C, wmWindow *win, int exchange) /* after area regions so we can do area 'overlay' drawing */ if (screen->do_draw) { ED_screen_draw(win); + win->screen->do_draw = false; if (exchange) screen->swap = WIN_FRONT_OK; @@ -315,6 +323,7 @@ static void wm_method_draw_overlap_all(bContext *C, wmWindow *win, int exchange) else if (exchange) { if (screen->swap == WIN_FRONT_OK) { ED_screen_draw(win); + win->screen->do_draw = false; screen->swap = WIN_BOTH_OK; } else if (screen->swap == WIN_BACK_OK) @@ -328,6 +337,7 @@ static void wm_method_draw_overlap_all(bContext *C, wmWindow *win, int exchange) if (ar->swinid && ar->do_draw) { CTX_wm_menu_set(C, ar); ED_region_do_draw(C, ar); + ar->do_draw = false; CTX_wm_menu_set(C, NULL); } } @@ -360,15 +370,6 @@ static void wm_method_draw_damage(bContext *C, wmWindow *win) /* used. if not, multiple smaller ones are used, with */ /* worst case wasted space being 23.4% for 3x3 textures */ -#define MAX_N_TEX 3 - -typedef struct wmDrawTriple { - GLuint bind[MAX_N_TEX * MAX_N_TEX]; - int x[MAX_N_TEX], y[MAX_N_TEX]; - int nx, ny; - GLenum target; -} wmDrawTriple; - static void split_width(int x, int n, int *splitx, int *nx) { int a, newnx, waste; @@ -405,16 +406,13 @@ static void split_width(int x, int n, int *splitx, int *nx) } } -static void wm_draw_triple_free(wmWindow *win) +static void wm_draw_triple_free(wmDrawTriple *triple) { - if (win->drawdata) { - wmDrawTriple *triple = win->drawdata; + if (triple) { glDeleteTextures(triple->nx * triple->ny, triple->bind); MEM_freeN(triple); - - win->drawdata = NULL; } } @@ -499,7 +497,7 @@ static int wm_triple_gen_textures(wmWindow *win, wmDrawTriple *triple) return 1; } -static void wm_triple_draw_textures(wmWindow *win, wmDrawTriple *triple, float alpha) +void wm_triple_draw_textures(wmWindow *win, wmDrawTriple *triple, float alpha) { const int winsize_x = WM_window_pixels_x(win); const int winsize_y = WM_window_pixels_y(win); @@ -571,7 +569,7 @@ static void wm_triple_copy_textures(wmWindow *win, wmDrawTriple *triple) glBindTexture(triple->target, 0); } -static void wm_draw_region_blend(wmWindow *win, ARegion *ar) +static void wm_draw_region_blend(wmWindow *win, ARegion *ar, wmDrawTriple *triple) { float fac = ED_region_blend_factor(ar); @@ -580,7 +578,7 @@ static void wm_draw_region_blend(wmWindow *win, ARegion *ar) wmSubWindowScissorSet(win, win->screen->mainwin, &ar->winrct, true); glEnable(GL_BLEND); - wm_triple_draw_textures(win, win->drawdata, 1.0f - fac); + wm_triple_draw_textures(win, triple, 1.0f - fac); glDisable(GL_BLEND); } } @@ -589,29 +587,46 @@ static void wm_method_draw_triple(bContext *C, wmWindow *win) { wmWindowManager *wm = CTX_wm_manager(C); wmDrawTriple *triple; + wmDrawData *dd, *dd_next, *drawdata = win->drawdata.first; bScreen *screen = win->screen; ScrArea *sa; ARegion *ar; - int copytex = 0; + int copytex = false; - if (win->drawdata) { + if (drawdata && drawdata->triple) { glClearColor(0, 0, 0, 0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); wmSubWindowSet(win, screen->mainwin); - wm_triple_draw_textures(win, win->drawdata, 1.0f); + wm_triple_draw_textures(win, drawdata->triple, 1.0f); } else { - win->drawdata = MEM_callocN(sizeof(wmDrawTriple), "wmDrawTriple"); + /* we run it when we start OR when we turn stereo on */ + if (drawdata == NULL) { + drawdata = MEM_callocN(sizeof(wmDrawData), "wmDrawData"); + BLI_addhead(&win->drawdata, drawdata); + } + + drawdata->triple = MEM_callocN(sizeof(wmDrawTriple), "wmDrawTriple"); - if (!wm_triple_gen_textures(win, win->drawdata)) { + if (!wm_triple_gen_textures(win, drawdata->triple)) { wm_draw_triple_fail(C, win); return; } } - triple = win->drawdata; + /* it means stereo was just turned off */ + /* note: we are removing all drawdatas that are not the first */ + for (dd = drawdata->next; dd; dd = dd_next) { + dd_next = dd->next; + + BLI_remlink(&win->drawdata, dd); + wm_draw_triple_free(dd->triple); + MEM_freeN(dd); + } + + triple = drawdata->triple; /* draw marked area regions */ for (sa = screen->areabase.first; sa; sa = sa->next) { @@ -619,16 +634,17 @@ static void wm_method_draw_triple(bContext *C, wmWindow *win) for (ar = sa->regionbase.first; ar; ar = ar->next) { if (ar->swinid && ar->do_draw) { - - if (ar->overlap == 0) { + + if (ar->overlap == false) { CTX_wm_region_set(C, ar); ED_region_do_draw(C, ar); + ar->do_draw = false; CTX_wm_region_set(C, NULL); - copytex = 1; + copytex = true; } } } - + wm_area_mark_invalid_backbuf(sa); CTX_wm_area_set(C, NULL); } @@ -662,14 +678,15 @@ static void wm_method_draw_triple(bContext *C, wmWindow *win) /* draw overlapping area regions (always like popups) */ for (sa = screen->areabase.first; sa; sa = sa->next) { CTX_wm_area_set(C, sa); - + for (ar = sa->regionbase.first; ar; ar = ar->next) { if (ar->swinid && ar->overlap) { CTX_wm_region_set(C, ar); ED_region_do_draw(C, ar); + ar->do_draw = false; CTX_wm_region_set(C, NULL); - - wm_draw_region_blend(win, ar); + + wm_draw_region_blend(win, ar, triple); } } @@ -678,12 +695,14 @@ static void wm_method_draw_triple(bContext *C, wmWindow *win) /* after area regions so we can do area 'overlay' drawing */ ED_screen_draw(win); + win->screen->do_draw = false; /* draw floating regions (menus) */ for (ar = screen->regionbase.first; ar; ar = ar->next) { if (ar->swinid) { CTX_wm_menu_set(C, ar); ED_region_do_draw(C, ar); + ar->do_draw = false; CTX_wm_menu_set(C, NULL); } } @@ -691,13 +710,188 @@ static void wm_method_draw_triple(bContext *C, wmWindow *win) /* always draw, not only when screen tagged */ if (win->gesture.first) wm_gesture_draw(win); - + /* needs pixel coords in screen */ if (wm->drags.first) { wm_drags_draw(C, win, NULL); } } +static void wm_method_draw_triple_multiview(bContext *C, wmWindow *win, StereoViews sview) +{ + wmWindowManager *wm = CTX_wm_manager(C); + wmDrawData *drawdata; + wmDrawTriple *triple_data, *triple_all; + bScreen *screen = win->screen; + ScrArea *sa; + ARegion *ar; + int copytex = false; + int id; + + /* we store the triple_data in sequence to triple_all */ + for (id = 0; id < 2; id++) { + drawdata = BLI_findlink(&win->drawdata, (sview * 2) + id); + + if (drawdata && drawdata->triple) { + if (id == 0) { + glClearColor(0, 0, 0, 0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + wmSubWindowSet(win, screen->mainwin); + + wm_triple_draw_textures(win, drawdata->triple, 1.0f); + } + } + else { + /* we run it when we start OR when we turn stereo on */ + if (drawdata == NULL) { + drawdata = MEM_callocN(sizeof(wmDrawData), "wmDrawData"); + BLI_addtail(&win->drawdata, drawdata); + } + + drawdata->triple = MEM_callocN(sizeof(wmDrawTriple), "wmDrawTriple"); + + if (!wm_triple_gen_textures(win, drawdata->triple)) { + wm_draw_triple_fail(C, win); + return; + } + } + } + + triple_data = ((wmDrawData *) BLI_findlink(&win->drawdata, sview * 2))->triple; + triple_all = ((wmDrawData *) BLI_findlink(&win->drawdata, (sview * 2) + 1))->triple; + + /* draw marked area regions */ + for (sa = screen->areabase.first; sa; sa = sa->next) { + CTX_wm_area_set(C, sa); + + switch (sa->spacetype) { + case SPACE_IMAGE: + { + SpaceImage *sima = sa->spacedata.first; + sima->iuser.multiview_eye = sview; + break; + } + case SPACE_VIEW3D: + { + View3D *v3d = sa->spacedata.first; + BGpic *bgpic = v3d->bgpicbase.first; + v3d->multiview_eye = sview; + if (bgpic) bgpic->iuser.multiview_eye = sview; + break; + } + case SPACE_NODE: + { + SpaceNode *snode = sa->spacedata.first; + if ((snode->flag & SNODE_BACKDRAW) && ED_node_is_compositor(snode)) { + Image *ima = BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node"); + ima->eye = sview; + } + break; + } + case SPACE_SEQ: + { + SpaceSeq *sseq = sa->spacedata.first; + sseq->multiview_eye = sview; + break; + } + } + + /* draw marked area regions */ + for (ar = sa->regionbase.first; ar; ar = ar->next) { + if (ar->swinid && ar->do_draw) { + + if (ar->overlap == false) { + CTX_wm_region_set(C, ar); + ED_region_do_draw(C, ar); + + if (sview == STEREO_RIGHT_ID) + ar->do_draw = false; + + CTX_wm_region_set(C, NULL); + copytex = true; + } + } + } + + wm_area_mark_invalid_backbuf(sa); + CTX_wm_area_set(C, NULL); + } + + if (copytex) { + wmSubWindowSet(win, screen->mainwin); + + wm_triple_copy_textures(win, triple_data); + } + + if (wm->paintcursors.first) { + for (sa = screen->areabase.first; sa; sa = sa->next) { + for (ar = sa->regionbase.first; ar; ar = ar->next) { + if (ar->swinid && ar->swinid == screen->subwinactive) { + CTX_wm_area_set(C, sa); + CTX_wm_region_set(C, ar); + + /* make region ready for draw, scissor, pixelspace */ + ED_region_set(C, ar); + wm_paintcursor_draw(C, ar); + + CTX_wm_region_set(C, NULL); + CTX_wm_area_set(C, NULL); + } + } + } + + wmSubWindowSet(win, screen->mainwin); + } + + /* draw overlapping area regions (always like popups) */ + for (sa = screen->areabase.first; sa; sa = sa->next) { + CTX_wm_area_set(C, sa); + + for (ar = sa->regionbase.first; ar; ar = ar->next) { + if (ar->swinid && ar->overlap) { + CTX_wm_region_set(C, ar); + ED_region_do_draw(C, ar); + if (sview == STEREO_RIGHT_ID) + ar->do_draw = false; + CTX_wm_region_set(C, NULL); + + wm_draw_region_blend(win, ar, triple_data); + } + } + + CTX_wm_area_set(C, NULL); + } + + /* after area regions so we can do area 'overlay' drawing */ + ED_screen_draw(win); + if (sview == STEREO_RIGHT_ID) + win->screen->do_draw = false; + + /* draw floating regions (menus) */ + for (ar = screen->regionbase.first; ar; ar = ar->next) { + if (ar->swinid) { + CTX_wm_menu_set(C, ar); + ED_region_do_draw(C, ar); + if (sview == STEREO_RIGHT_ID) + ar->do_draw = false; + CTX_wm_menu_set(C, NULL); + } + } + + /* always draw, not only when screen tagged */ + if (win->gesture.first) + wm_gesture_draw(win); + + /* needs pixel coords in screen */ + if (wm->drags.first) { + wm_drags_draw(C, win, NULL); + } + + /* copy the ui + overlays */ + wmSubWindowSet(win, screen->mainwin); + wm_triple_copy_textures(win, triple_all); +} /****************** main update call **********************/ @@ -848,8 +1042,16 @@ void wm_draw_update(bContext *C) wm_method_draw_overlap_all(C, win, 0); else if (drawmethod == USER_DRAW_OVERLAP_FLIP) wm_method_draw_overlap_all(C, win, 1); - else // if (drawmethod == USER_DRAW_TRIPLE) - wm_method_draw_triple(C, win); + else { /* USER_DRAW_TRIPLE */ + if ((WM_stereo3d_enabled(win, false)) == false) { + wm_method_draw_triple(C, win); + } + else { + wm_method_draw_triple_multiview(C, win, STEREO_LEFT_ID); + wm_method_draw_triple_multiview(C, win, STEREO_RIGHT_ID); + wm_method_draw_stereo3d(C, win); + } + } win->screen->do_draw_gesture = false; win->screen->do_draw_paintcursor = false; @@ -862,15 +1064,23 @@ void wm_draw_update(bContext *C) } } +void wm_draw_data_free(wmWindow *win) +{ + wmDrawData *dd; + + for (dd = win->drawdata.first; dd; dd = dd->next) { + wm_draw_triple_free(dd->triple); + } + BLI_freelistN(&win->drawdata); +} + void wm_draw_window_clear(wmWindow *win) { bScreen *screen = win->screen; ScrArea *sa; ARegion *ar; - int drawmethod = wm_automatic_draw_method(win); - if (drawmethod == USER_DRAW_TRIPLE) - wm_draw_triple_free(win); + wm_draw_data_free(win); /* clear screen swap flags */ if (screen) { diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index f1a46826435..075390f9a15 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -63,6 +63,7 @@ #include "ED_fileselect.h" #include "ED_info.h" +#include "ED_outliner.h" #include "ED_screen.h" #include "ED_view3d.h" #include "ED_util.h" @@ -96,7 +97,7 @@ static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, PointerRNA /* ************ event management ************** */ -void wm_event_add(wmWindow *win, const wmEvent *event_to_add) +void wm_event_add_ex(wmWindow *win, const wmEvent *event_to_add, const wmEvent *event_to_add_after) { wmEvent *event = MEM_mallocN(sizeof(wmEvent), "wmEvent"); @@ -104,7 +105,18 @@ void wm_event_add(wmWindow *win, const wmEvent *event_to_add) update_tablet_data(win, event); - BLI_addtail(&win->queue, event); + if (event_to_add_after == NULL) { + BLI_addtail(&win->queue, event); + } + else { + /* note, strictly speaking this breaks const-correctness, however we're only changing 'next' member */ + BLI_insertlinkafter(&win->queue, (void *)event_to_add_after, event); + } +} + +void wm_event_add(wmWindow *win, const wmEvent *event_to_add) +{ + wm_event_add_ex(win, event_to_add, NULL); } void wm_event_free(wmEvent *event) @@ -123,7 +135,7 @@ void wm_event_free(wmEvent *event) } if (event->tablet_data) { - MEM_freeN(event->tablet_data); + MEM_freeN((void *)event->tablet_data); } MEM_freeN(event); @@ -217,6 +229,7 @@ void WM_main_remove_notifier_reference(const void *reference) { Main *bmain = G.main; wmWindowManager *wm = bmain->wm.first; + if (wm) { wmNotifier *note, *note_next; @@ -232,6 +245,24 @@ void WM_main_remove_notifier_reference(const void *reference) } } +void WM_main_remove_editor_id_reference(const ID *id) +{ + Main *bmain = G.main; + bScreen *sc; + + for (sc = bmain->screen.first; sc; sc = sc->id.next) { + ScrArea *sa; + + for (sa = sc->areabase.first; sa; sa = sa->next) { + SpaceLink *sl; + + for (sl = sa->spacedata.first; sl; sl = sl->next) { + ED_spacedata_id_unref(sl, id); + } + } + } +} + static void wm_notifier_clear(wmNotifier *note) { /* NULL the entire notifier, only leaving (next, prev) members intact */ @@ -293,7 +324,7 @@ void wm_event_do_notifiers(bContext *C) do_anim = true; } } - if (ELEM(note->category, NC_SCENE, NC_OBJECT, NC_GEOM, NC_SCENE, NC_WM)) { + if (ELEM(note->category, NC_SCENE, NC_OBJECT, NC_GEOM, NC_WM)) { ED_info_stats_clear(win->screen->scene); WM_event_add_notifier(C, NC_SPACE | ND_SPACE_INFO, NULL); } @@ -535,10 +566,9 @@ void WM_event_print(const wmEvent *event) RNA_enum_identifier(event_type_items, event->type, &type_id); RNA_enum_identifier(event_value_items, event->val, &val_id); - printf("wmEvent type:%d / %s, val:%d / %s, \n" - " shift:%d, ctrl:%d, alt:%d, oskey:%d, keymodifier:%d, \n" - " mouse:(%d,%d), ascii:'%c', utf8:'%.*s', " - " keymap_idname:%s, pointer:%p\n", + printf("wmEvent type:%d / %s, val:%d / %s,\n" + " shift:%d, ctrl:%d, alt:%d, oskey:%d, keymodifier:%d,\n" + " mouse:(%d,%d), ascii:'%c', utf8:'%.*s', keymap_idname:%s, pointer:%p\n", event->type, type_id, event->val, val_id, event->shift, event->ctrl, event->alt, event->oskey, event->keymodifier, event->x, event->y, event->ascii, @@ -548,17 +578,19 @@ void WM_event_print(const wmEvent *event) if (ISNDOF(event->type)) { const wmNDOFMotionData *ndof = event->customdata; if (event->type == NDOF_MOTION) { - printf(" ndof: rot: (%.4f %.4f %.4f),\n" - " tx: (%.4f %.4f %.4f),\n" - " dt: %.4f, progress: %d\n", - UNPACK3(ndof->rvec), - UNPACK3(ndof->tvec), - ndof->dt, ndof->progress); + printf(" ndof: rot: (%.4f %.4f %.4f), tx: (%.4f %.4f %.4f), dt: %.4f, progress: %u\n", + UNPACK3(ndof->rvec), UNPACK3(ndof->tvec), ndof->dt, ndof->progress); } else { /* ndof buttons printed already */ } } + + if (event->tablet_data) { + const wmTabletData *wmtab = event->tablet_data; + printf(" tablet: active: %d, pressure %.4f, tilt: (%.4f %.4f)\n", + wmtab->Active, wmtab->Pressure, wmtab->Xtilt, wmtab->Ytilt); + } } else { printf("wmEvent - NULL\n"); @@ -567,26 +599,40 @@ void WM_event_print(const wmEvent *event) #endif /* NDEBUG */ +/** + * Show the report in the info header. + */ +void WM_report_banner_show(const bContext *C) +{ + wmWindowManager *wm = CTX_wm_manager(C); + ReportList *wm_reports = CTX_wm_reports(C); + ReportTimerInfo *rti; + + /* After adding reports to the global list, reset the report timer. */ + WM_event_remove_timer(wm, NULL, wm_reports->reporttimer); + + /* Records time since last report was added */ + wm_reports->reporttimer = WM_event_add_timer(wm, CTX_wm_window(C), TIMERREPORT, 0.05); + + rti = MEM_callocN(sizeof(ReportTimerInfo), "ReportTimerInfo"); + wm_reports->reporttimer->customdata = rti; +} + +bool WM_event_is_absolute(const wmEvent *event) +{ + return (event->tablet_data != NULL); +} + static void wm_add_reports(const bContext *C, ReportList *reports) { /* if the caller owns them, handle this */ if (reports->list.first && (reports->flag & RPT_OP_HOLD) == 0) { - - wmWindowManager *wm = CTX_wm_manager(C); ReportList *wm_reports = CTX_wm_reports(C); - ReportTimerInfo *rti; /* add reports to the global list, otherwise they are not seen */ BLI_movelisttolist(&wm_reports->list, &reports->list); - - /* After adding reports to the global list, reset the report timer. */ - WM_event_remove_timer(wm, NULL, wm_reports->reporttimer); - - /* Records time since last report was added */ - wm_reports->reporttimer = WM_event_add_timer(wm, CTX_wm_window(C), TIMERREPORT, 0.05); - - rti = MEM_callocN(sizeof(ReportTimerInfo), "ReportTimerInfo"); - wm_reports->reporttimer->customdata = rti; + + WM_report_banner_show(C); } } @@ -662,7 +708,8 @@ static void wm_operator_reports(bContext *C, wmOperator *op, int retval, bool ca wm_add_reports(C, op->reports); } -/* this function is mainly to check that the rules for freeing +/** + * This function is mainly to check that the rules for freeing * an operator are kept in sync. */ static bool wm_operator_register_check(wmWindowManager *wm, wmOperatorType *ot) @@ -781,23 +828,29 @@ int WM_operator_call(bContext *C, wmOperator *op) return WM_operator_call_ex(C, op, false); } -/* this is intended to be used when an invoke operator wants to call exec on its self +/** + * This is intended to be used when an invoke operator wants to call exec on its self * and is basically like running op->type->exec() directly, no poll checks no freeing, - * since we assume whoever called invoke will take care of that */ + * since we assume whoever called invoke will take care of that + */ int WM_operator_call_notest(bContext *C, wmOperator *op) { return wm_operator_exec_notest(C, op); } -/* do this operator again, put here so it can share above code */ +/** + * Execute this operator again, put here so it can share above code + */ int WM_operator_repeat(bContext *C, wmOperator *op) { return wm_operator_exec(C, op, true, true); } -/* true if WM_operator_repeat can run +/** + * \return true if #WM_operator_repeat can run * simple check for now but may become more involved. - * To be sure the operator can run call WM_operator_poll(C, op->type) also, since this call - * checks if WM_operator_repeat() can run at all, not that it WILL run at any time. */ + * To be sure the operator can run call `WM_operator_poll(C, op->type)` also, since this call + * checks if WM_operator_repeat() can run at all, not that it WILL run at any time. + */ bool WM_operator_repeat_check(const bContext *UNUSED(C), wmOperator *op) { if (op->type->exec != NULL) { @@ -1003,8 +1056,9 @@ bool WM_operator_last_properties_store(wmOperator *UNUSED(op)) #endif -static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, - PointerRNA *properties, ReportList *reports, const bool poll_only) +static int wm_operator_invoke( + bContext *C, wmOperatorType *ot, wmEvent *event, + PointerRNA *properties, ReportList *reports, const bool poll_only) { int retval = OPERATOR_PASS_THROUGH; @@ -1083,13 +1137,16 @@ static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, int bounds[4] = {-1, -1, -1, -1}; bool wrap; - if (op->opm) { + if (event == NULL) { + wrap = false; + } + else if (op->opm) { wrap = (U.uiflag & USER_CONTINUOUS_MOUSE) && - ((op->opm->flag & OP_GRAB_POINTER) || (op->opm->type->flag & OPTYPE_GRAB_POINTER)); + ((op->opm->flag & OP_IS_MODAL_GRAB_CURSOR) || (op->opm->type->flag & OPTYPE_GRAB_CURSOR)); } else { wrap = (U.uiflag & USER_CONTINUOUS_MOUSE) && - ((op->flag & OP_GRAB_POINTER) || (ot->flag & OPTYPE_GRAB_POINTER)); + ((op->flag & OP_IS_MODAL_GRAB_CURSOR) || (ot->flag & OPTYPE_GRAB_CURSOR)); } /* exception, cont. grab in header is annoying */ @@ -1101,16 +1158,16 @@ static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, } if (wrap) { - rcti *winrect = NULL; + const rcti *winrect = NULL; ARegion *ar = CTX_wm_region(C); ScrArea *sa = CTX_wm_area(C); - if (ar && ar->regiontype == RGN_TYPE_WINDOW && event && + if (ar && ar->regiontype == RGN_TYPE_WINDOW && BLI_rcti_isect_pt_v(&ar->winrct, &event->x)) { winrect = &ar->winrct; } - else if (sa) { + else if (sa && BLI_rcti_isect_pt_v(&sa->totrct, &event->x)) { winrect = &sa->totrct; } @@ -1139,12 +1196,15 @@ static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, return retval; } -/* WM_operator_name_call is the main accessor function +/** + * #WM_operator_name_call is the main accessor function * this is for python to access since its done the operator lookup * - * invokes operator in context */ -static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, PointerRNA *properties, ReportList *reports, - const short context, const bool poll_only) + * invokes operator in context + */ +static int wm_operator_call_internal( + bContext *C, wmOperatorType *ot, PointerRNA *properties, ReportList *reports, + const short context, const bool poll_only) { wmEvent *event; @@ -1153,7 +1213,7 @@ static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, PointerRNA CTX_wm_operator_poll_msg_set(C, NULL); /* dummie test */ - if (ot && C) { + if (ot) { wmWindow *window = CTX_wm_window(C); switch (context) { @@ -1284,13 +1344,16 @@ int WM_operator_name_call(bContext *C, const char *opstring, short context, Poin return 0; } -/* Similar to WM_operator_name_call called with WM_OP_EXEC_DEFAULT context. - * - wmOperatorType is used instead of operator name since python already has the operator type - * - poll() must be called by python before this runs. - * - reports can be passed to this function (so python can report them as exceptions) +/** + * Similar to #WM_operator_name_call called with #WM_OP_EXEC_DEFAULT context. + * + * - #wmOperatorType is used instead of operator name since python already has the operator type. + * - `poll()` must be called by python before this runs. + * - reports can be passed to this function (so python can report them as exceptions). */ -int WM_operator_call_py(bContext *C, wmOperatorType *ot, short context, - PointerRNA *properties, ReportList *reports, const bool is_undo) +int WM_operator_call_py( + bContext *C, wmOperatorType *ot, short context, + PointerRNA *properties, ReportList *reports, const bool is_undo) { int retval = OPERATOR_CANCELLED; @@ -1337,7 +1400,7 @@ void wm_event_free_handler(wmEventHandler *handler) } /* only set context when area/region is part of screen */ -static void wm_handler_op_context(bContext *C, wmEventHandler *handler) +static void wm_handler_op_context(bContext *C, wmEventHandler *handler, const wmEvent *event) { bScreen *screen = CTX_wm_screen(C); @@ -1358,10 +1421,27 @@ static void wm_handler_op_context(bContext *C, wmEventHandler *handler) } else { ARegion *ar; + wmOperator *op = handler->op ? (handler->op->opm ? handler->op->opm : handler->op) : NULL; CTX_wm_area_set(C, sa); - for (ar = sa->regionbase.first; ar; ar = ar->next) - if (ar == handler->op_region) - break; + + if (op && (op->flag & OP_IS_MODAL_CURSOR_REGION)) { + ar = BKE_area_find_region_xy(sa, handler->op_region_type, event->x, event->y); + if (ar) { + handler->op_region = ar; + } + } + else { + ar = NULL; + } + + if (ar == NULL) { + for (ar = sa->regionbase.first; ar; ar = ar->next) { + if (ar == handler->op_region) { + break; + } + } + } + /* XXX no warning print here, after full-area and back regions are remade */ if (ar) CTX_wm_region_set(C, ar); @@ -1379,11 +1459,12 @@ void WM_event_remove_handlers(bContext *C, ListBase *handlers) /* C is zero on freeing database, modal handlers then already were freed */ while ((handler = BLI_pophead(handlers))) { if (handler->op) { + wmWindow *win = CTX_wm_window(C); if (handler->op->type->cancel) { ScrArea *area = CTX_wm_area(C); ARegion *region = CTX_wm_region(C); - wm_handler_op_context(C, handler); + wm_handler_op_context(C, handler, win->eventstate); if (handler->op->type->flag & OPTYPE_UNDO) wm->op_undo_depth++; @@ -1397,7 +1478,7 @@ void WM_event_remove_handlers(bContext *C, ListBase *handlers) CTX_wm_region_set(C, region); } - WM_cursor_grab_disable(CTX_wm_window(C), NULL); + WM_cursor_grab_disable(win, NULL); WM_operator_free(handler->op); } else if (handler->ui_remove) { @@ -1515,7 +1596,8 @@ static void wm_event_modalkeymap(const bContext *C, wmOperator *op, wmEvent *eve } } -/* Check whether operator is allowed to run in case interface is locked, +/** + * Check whether operator is allowed to run in case interface is locked, * If interface is unlocked, will always return truth. */ static bool wm_operator_check_locked_interface(bContext *C, wmOperatorType *ot) @@ -1569,7 +1651,7 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand ARegion *region = CTX_wm_region(C); bool dbl_click_disabled = false; - wm_handler_op_context(C, handler); + wm_handler_op_context(C, handler, event); wm_region_mouse_co(C, event); wm_event_modalkeymap(C, op, event, &dbl_click_disabled); @@ -1714,10 +1796,14 @@ static int wm_handler_fileselect_do(bContext *C, ListBase *handlers, wmEventHand BLI_remlink(handlers, handler); if (val != EVT_FILESELECT_EXTERNAL_CANCEL) { - ED_screen_full_prevspace(C, CTX_wm_area(C)); + ScrArea *sa = CTX_wm_area(C); + 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); } - wm_handler_op_context(C, handler); + wm_handler_op_context(C, handler, CTX_wm_window(C)->eventstate); /* needed for UI_popup_menu_reports */ @@ -1843,7 +1929,7 @@ static int wm_action_not_handled(int action) static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers) { #ifndef NDEBUG - const int do_debug_handler = (G.debug & G_DEBUG_HANDLERS) && + const bool do_debug_handler = (G.debug & G_DEBUG_HANDLERS) && /* comment this out to flood the console! (if you really want to test) */ !ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE) ; @@ -2223,7 +2309,7 @@ void wm_event_do_handlers(bContext *C) Scene *scene = win->screen->scene; if (scene) { - int is_playing_sound = sound_scene_playing(win->screen->scene); + int is_playing_sound = BKE_sound_scene_playing(win->screen->scene); if (is_playing_sound != -1) { bool is_playing_screen; @@ -2240,7 +2326,7 @@ void wm_event_do_handlers(bContext *C) } if (is_playing_sound == 0) { - const float time = sound_sync_scene(scene); + const float time = BKE_sound_sync_scene(scene); if (finite(time)) { int ncfra = time * (float)FPS + 0.5f; if (ncfra != scene->r.cfra) { @@ -2330,6 +2416,11 @@ void wm_event_do_handlers(bContext *C) break; } + /* update azones if needed - done here because it needs to be independent from redraws */ + if (sa->flag & AREA_FLAG_ACTIONZONES_UPDATE) { + ED_area_azones_update(sa, &event->x); + } + if (wm_event_inside_i(event, &sa->totrct)) { CTX_wm_area_set(C, sa); @@ -2391,7 +2482,7 @@ void wm_event_do_handlers(bContext *C) /* XXX hrmf, this gives reliable previous mouse coord for area change, feels bad? * doing it on ghost queue gives errors when mousemoves go over area borders */ - if (doit && win->screen && win->screen->subwinactive != win->screen->mainwin) { + if (doit && win->screen->subwinactive != win->screen->mainwin) { win->eventstate->prevx = event->x; win->eventstate->prevy = event->y; //printf("win->eventstate->prev = %d %d\n", event->x, event->y); @@ -2448,11 +2539,12 @@ void WM_event_fileselect_event(wmWindowManager *wm, void *ophandle, int eventval /* operator is supposed to have a filled "path" property */ /* optional property: filetype (XXX enum?) */ -/* Idea is to keep a handler alive on window queue, owning the operator. +/** + * The idea here is to keep a handler alive on window queue, owning the operator. * The filewindow can send event to make it execute, thus ensuring * executing happens outside of lower level queues, with UI refreshed. - * Should also allow multiwin solutions */ - + * Should also allow multiwin solutions + */ void WM_event_add_fileselect(bContext *C, wmOperator *op) { wmEventHandler *handler, *handlernext; @@ -2529,6 +2621,7 @@ wmEventHandler *WM_event_add_modal_handler(bContext *C, wmOperator *op) handler->op_area = CTX_wm_area(C); /* means frozen screen context for modal handlers! */ handler->op_region = CTX_wm_region(C); + handler->op_region_type = handler->op_region ? handler->op_region->regiontype : -1; BLI_addhead(&win->modalhandlers, handler); @@ -2597,7 +2690,7 @@ void WM_event_remove_keymap_handler(ListBase *handlers, wmKeyMap *keymap) wmEventHandler *WM_event_add_ui_handler( const bContext *C, ListBase *handlers, wmUIHandlerFunc ui_handle, wmUIHandlerRemoveFunc ui_remove, - void *userdata, const bool accept_dbl_click) + void *userdata, const char flag) { wmEventHandler *handler = MEM_callocN(sizeof(wmEventHandler), "event ui handler"); handler->ui_handle = ui_handle; @@ -2614,9 +2707,8 @@ wmEventHandler *WM_event_add_ui_handler( handler->ui_menu = NULL; } - if (accept_dbl_click) { - handler->flag |= WM_HANDLER_ACCEPT_DBL_CLICK; - } + BLI_assert((flag & WM_HANDLER_DO_FREE) == 0); + handler->flag = flag; BLI_addhead(handlers, handler); @@ -2842,52 +2934,41 @@ static int convert_key(GHOST_TKey key) static void wm_eventemulation(wmEvent *event) { - /* Store last mmb event value to make emulation work when modifier keys are released first. */ - static int mmb_emulated = 0; /* this should be in a data structure somwhere */ + /* Store last mmb/rmb event value to make emulation work when modifier keys + * are released first. This really should be in a data structure somewhere. */ + static int emulating_event = EVENT_NONE; - /* middlemouse emulation */ + /* middlemouse and rightmouse emulation */ if (U.flag & USER_TWOBUTTONMOUSE) { if (event->type == LEFTMOUSE) { if (event->val == KM_PRESS && event->alt) { event->type = MIDDLEMOUSE; event->alt = 0; - mmb_emulated = 1; - } - else if (event->val == KM_RELEASE) { - /* only send middle-mouse release if emulated */ - if (mmb_emulated) { - event->type = MIDDLEMOUSE; - event->alt = 0; - } - mmb_emulated = 0; + emulating_event = MIDDLEMOUSE; } - } - - } - #ifdef __APPLE__ - - /* rightmouse emulation */ - if (U.flag & USER_TWOBUTTONMOUSE) { - if (event->type == LEFTMOUSE) { - - if (event->val == KM_PRESS && event->oskey) { + else if (event->val == KM_PRESS && event->oskey) { event->type = RIGHTMOUSE; event->oskey = 0; - mmb_emulated = 1; + emulating_event = RIGHTMOUSE; } +#endif else if (event->val == KM_RELEASE) { - if (mmb_emulated) { - event->oskey = RIGHTMOUSE; + /* only send middle-mouse release if emulated */ + if (emulating_event == MIDDLEMOUSE) { + event->type = MIDDLEMOUSE; event->alt = 0; } - mmb_emulated = 0; + else if (emulating_event == RIGHTMOUSE) { + event->type = RIGHTMOUSE; + event->oskey = 0; + } + emulating_event = EVENT_NONE; } } } -#endif /* numpad emulation */ if (U.flag & USER_NONUMPAD) { @@ -3109,7 +3190,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U event.x = evt->x = pd->x; event.y = evt->y = pd->y; - event.val = 0; + event.val = KM_NOTHING; /* Use prevx/prevy so we can calculate the delta later */ event.prevx = event.x - pd->deltaX; @@ -3337,7 +3418,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U event.type = TIMER; event.custom = EVT_DATA_TIMER; event.customdata = customdata; - event.val = 0; + event.val = KM_NOTHING; event.keymodifier = 0; wm_event_add(win, &event); @@ -3347,7 +3428,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U case GHOST_kEventNDOFMotion: { event.type = NDOF_MOTION; - event.val = 0; + event.val = KM_NOTHING; attach_ndof_data(&event, customdata); wm_event_add(win, &event); @@ -3504,7 +3585,7 @@ float WM_event_tablet_data(const wmEvent *event, int *pen_flip, float tilt[2]) zero_v2(tilt); if (event->tablet_data) { - wmTabletData *wmtab = event->tablet_data; + const wmTabletData *wmtab = event->tablet_data; erasor = (wmtab->Active == EVT_TABLET_ERASER); if (wmtab->Active != EVT_TABLET_NONE) { diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index f5a7ad164d6..5bd2bb88f84 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -301,7 +301,7 @@ static void wm_init_userdef(bContext *C, const bool from_memory) UI_init_userdef(); MEM_CacheLimiter_set_maximum(((size_t)U.memcachelimit) * 1024 * 1024); - sound_init(bmain); + BKE_sound_init(bmain); /* needed so loading a file from the command line respects user-pref [#26156] */ BKE_BIT_TEST_SET(G.fileflags, U.flag & USER_FILENOUI, G_FILE_NO_UI); @@ -506,13 +506,13 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports) } #endif - BKE_reset_undo(); - BKE_write_undo(C, "original"); /* save current state */ + BKE_undo_reset(); + BKE_undo_write(C, "original"); /* save current state */ success = true; } else if (retval == BKE_READ_EXOTIC_OK_OTHER) - BKE_write_undo(C, "Import file"); + BKE_undo_write(C, "Import file"); 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")); @@ -660,8 +660,8 @@ int wm_homefile_read(bContext *C, ReportList *reports, bool from_memory, const c // refresh_interface_font(); // undo_editmode_clear(); - BKE_reset_undo(); - BKE_write_undo(C, "original"); /* save current state */ + BKE_undo_reset(); + BKE_undo_write(C, "original"); /* save current state */ ED_editors_init(C); DAG_on_visible_update(CTX_data_main(C), true); @@ -846,11 +846,11 @@ static ImBuf *blend_file_thumb(Scene *scene, bScreen *screen, int **thumb_pt) 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, err_out); + IB_rect, OB_SOLID, false, false, false, R_ALPHAPREMUL, 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, err_out); + IB_rect, false, R_ALPHAPREMUL, NULL, err_out); } if (ibuf) { @@ -860,7 +860,7 @@ static ImBuf *blend_file_thumb(Scene *scene, bScreen *screen, int **thumb_pt) IMB_scaleImBuf(ibuf, BLEN_THUMB_SIZE, BLEN_THUMB_SIZE); /* add pretty overlay */ - IMB_overlayblend_thumb(ibuf->rect, ibuf->x, ibuf->y, aspect); + 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"); @@ -951,7 +951,7 @@ int wm_file_write(bContext *C, const char *filepath, int fileflags, ReportList * /* operator now handles overwrite checks */ if (G.fileflags & G_AUTOPACK) { - packAll(G.main, reports); + packAll(G.main, reports, false); } /* don't forget not to return without! */ @@ -991,7 +991,7 @@ int wm_file_write(bContext *C, const char *filepath, int fileflags, ReportList * /* run this function after because the file cant be written before the blend is */ if (ibuf_thumb) { IMB_thumb_delete(filepath, THB_FAIL); /* without this a failed thumb overrides */ - ibuf_thumb = IMB_thumb_create(filepath, THB_NORMAL, THB_SOURCE_BLEND, ibuf_thumb); + ibuf_thumb = IMB_thumb_create(filepath, THB_LARGE, THB_SOURCE_BLEND, ibuf_thumb); IMB_freeImBuf(ibuf_thumb); } @@ -1086,7 +1086,7 @@ void wm_autosave_location(char *filepath) if (G.main && G.relbase_valid) { const char *basename = BLI_path_basename(G.main->name); int len = strlen(basename) - 6; - BLI_snprintf(path, sizeof(path), "%.*s-%d.blend", len, basename, pid); + BLI_snprintf(path, sizeof(path), "%.*s.blend", len, basename); } else { BLI_snprintf(path, sizeof(path), "%d.blend", pid); @@ -1137,8 +1137,6 @@ void wm_autosave_timer(const bContext *C, wmWindowManager *wm, wmTimer *UNUSED(w } } - ED_editors_flush_edits(C, false); - wm_autosave_location(filepath); if (U.uiflag & USER_GLOBALUNDO) { @@ -1149,6 +1147,8 @@ void wm_autosave_timer(const bContext *C, wmWindowManager *wm, wmTimer *UNUSED(w /* save as regular blend file */ int fileflags = G.fileflags & ~(G_FILE_COMPRESS | G_FILE_AUTOPLAY | G_FILE_LOCK | G_FILE_SIGN | G_FILE_HISTORY); + ED_editors_flush_edits(C, false); + /* no error reporting to console */ BLO_write_file(CTX_data_main(C), filepath, fileflags, NULL, NULL); } diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index 32a49b6e160..edca1f97ecf 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -58,9 +58,10 @@ #include "BKE_screen.h" #include "BKE_DerivedMesh.h" #include "BKE_global.h" +#include "BKE_icons.h" #include "BKE_library.h" #include "BKE_main.h" -#include "BKE_mball.h" +#include "BKE_mball_tessellate.h" #include "BKE_node.h" #include "BKE_report.h" @@ -149,9 +150,11 @@ void WM_init(bContext *C, int argc, const char **argv) WM_menutype_init(); WM_uilisttype_init(); - set_free_windowmanager_cb(wm_close_and_free); /* library.c */ - set_free_notifier_reference_cb(WM_main_remove_notifier_reference); /* library.c */ - set_blender_test_break_cb(wm_window_testbreak); /* blender.c */ + BKE_library_callback_free_window_manager_set(wm_close_and_free); /* library.c */ + BKE_library_callback_free_notifier_reference_set(WM_main_remove_notifier_reference); /* library.c */ + 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 */ ED_spacetypes_init(); /* editors/space_api/spacetype.c */ @@ -170,6 +173,25 @@ void WM_init(bContext *C, int argc, const char **argv) BLF_lang_set(NULL); + if (!G.background) { + GPU_init(); + + GPU_set_mipmap(!(U.gameflags & USER_DISABLE_MIPMAP)); + GPU_set_linear_mipmap(true); + GPU_set_anisotropic(U.anisotropic_filter); + GPU_set_gpu_mipmapping(U.use_gpu_mipmap); + + UI_init(); + } + else { + /* Note: Currently only inits icons, which we now want in background mode too + * (scripts could use those in background processing...). + * In case we do more later, we may need to pass a 'background' flag. + * Called from 'UI_init' above */ + BKE_icons_init(1); + } + + ED_spacemacros_init(); /* note: there is a bug where python needs initializing before loading the @@ -195,17 +217,6 @@ void WM_init(bContext *C, int argc, const char **argv) wm_init_reports(C); /* reports cant be initialized before the wm */ - if (!G.background) { - GPU_init(); - - GPU_set_mipmap(!(U.gameflags & USER_DISABLE_MIPMAP)); - GPU_set_linear_mipmap(true); - GPU_set_anisotropic(U.anisotropic_filter); - GPU_set_gpu_mipmapping(U.use_gpu_mipmap); - - UI_init(); - } - clear_matcopybuf(); ED_render_clear_mtex_copybuf(); @@ -328,7 +339,7 @@ bool WM_init_game(bContext *C) WM_operator_name_call(C, "VIEW3D_OT_game_start", WM_OP_EXEC_DEFAULT, NULL); - sound_exit(); + BKE_sound_exit(); return true; } @@ -398,7 +409,7 @@ void WM_exit_ext(bContext *C, const bool do_python) { wmWindowManager *wm = C ? CTX_wm_manager(C) : NULL; - sound_exit(); + BKE_sound_exit(); /* first wrap up running stuff, we assume only the active WM is running */ /* modal handlers are on window level freed, others too? */ @@ -407,7 +418,7 @@ void WM_exit_ext(bContext *C, const bool do_python) wmWindow *win; if (!G.background) { - if ((U.uiflag2 & USER_KEEP_SESSION) || BKE_undo_valid(NULL)) { + if ((U.uiflag2 & USER_KEEP_SESSION) || BKE_undo_is_valid(NULL)) { /* save the undo state as quit.blend */ char filename[FILE_MAX]; bool has_edited; @@ -517,7 +528,7 @@ void WM_exit_ext(bContext *C, const bool do_python) GPU_exit(); } - BKE_reset_undo(); + BKE_undo_reset(); ED_file_exit(); /* for fsmenu */ @@ -539,7 +550,7 @@ void WM_exit_ext(bContext *C, const bool do_python) if (MEM_get_memory_blocks_in_use() != 0) { size_t mem_in_use = MEM_get_memory_in_use() + MEM_get_memory_in_use(); - printf("Error: Not freed memory blocks: %d, total unfreed memory %f MB\n", + printf("Error: Not freed memory blocks: %u, total unfreed memory %f MB\n", MEM_get_memory_blocks_in_use(), (double)mem_in_use / 1024 / 1024); MEM_printmemlist(); diff --git a/source/blender/windowmanager/intern/wm_jobs.c b/source/blender/windowmanager/intern/wm_jobs.c index 6bc858e861a..f8258d18c1a 100644 --- a/source/blender/windowmanager/intern/wm_jobs.c +++ b/source/blender/windowmanager/intern/wm_jobs.c @@ -157,8 +157,8 @@ static void wm_job_main_thread_yield(wmJob *wm_job, bool ending) BLI_ticket_mutex_lock(wm_job->main_thread_mutex); } -/* finds: - * if type or owner, compare for it, otherwise any matching job +/** + * Finds if type or owner, compare for it, otherwise any matching job. */ static wmJob *wm_job_find(wmWindowManager *wm, void *owner, const int job_type) { @@ -185,9 +185,12 @@ static wmJob *wm_job_find(wmWindowManager *wm, void *owner, const int job_type) /* ******************* public API ***************** */ -/* returns current or adds new job, but doesnt run it */ -/* every owner only gets a single job, adding a new one will stop running job and - * when stopped it starts the new one */ +/** + * \return current job or adds new job, but doesnt run it. + * + * \note every owner only gets a single job, + * adding a new one will stop running job and when stopped it starts the new one. + */ wmJob *WM_jobs_get(wmWindowManager *wm, wmWindow *win, void *owner, const char *name, int flag, int job_type) { wmJob *wm_job = wm_job_find(wm, owner, job_type); @@ -375,8 +378,10 @@ static void wm_jobs_test_suspend_stop(wmWindowManager *wm, wmJob *test) // if (suspend) printf("job suspended: %s\n", test->name); } -/* if job running, the same owner gave it a new job */ -/* if different owner starts existing startjob, it suspends itself */ +/** + * if job running, the same owner gave it a new job. + * if different owner starts existing startjob, it suspends itself + */ void WM_jobs_start(wmWindowManager *wm, wmJob *wm_job) { if (wm_job->running) { diff --git a/source/blender/windowmanager/intern/wm_keymap.c b/source/blender/windowmanager/intern/wm_keymap.c index 82e46c1b333..45177903cce 100644 --- a/source/blender/windowmanager/intern/wm_keymap.c +++ b/source/blender/windowmanager/intern/wm_keymap.c @@ -546,7 +546,7 @@ static void wm_keymap_diff(wmKeyMap *diff_km, wmKeyMap *from_km, wmKeyMap *to_km if (to_kmi) { orig_kmi = WM_keymap_item_find_id(orig_km, kmi->id); - if (!orig_kmi) + if (!orig_kmi && addon_km) orig_kmi = wm_keymap_find_item_equals(addon_km, kmi); if (orig_kmi) { @@ -929,7 +929,8 @@ int WM_keymap_item_to_string(wmKeyMapItem *kmi, char *str, const int len) static wmKeyMapItem *wm_keymap_item_find_handlers( const bContext *C, ListBase *handlers, const char *opname, int UNUSED(opcontext), - IDProperty *properties, const bool is_strict, const bool is_hotkey, wmKeyMap **keymap_r) + IDProperty *properties, const bool is_strict, const bool is_hotkey, + wmKeyMap **r_keymap) { wmWindowManager *wm = CTX_wm_manager(C); wmEventHandler *handler; @@ -966,7 +967,7 @@ static wmKeyMapItem *wm_keymap_item_find_handlers( #endif if (kmi->ptr && IDP_EqualsProperties_ex(properties, kmi->ptr->data, is_strict)) { - if (keymap_r) *keymap_r = keymap; + if (r_keymap) *r_keymap = keymap; return kmi; } /* Debug only, helps spotting mismatches between menu entries and shortcuts! */ @@ -989,11 +990,13 @@ static wmKeyMapItem *wm_keymap_item_find_handlers( "this might not be desired!\n", opname); printf("\tkm: '%s', kmi: '%s'\n", keymap->idname, kmi_str); #ifndef NDEBUG +#ifdef WITH_PYTHON printf("OPERATOR\n"); IDP_spit(properties); printf("KEYMAP\n"); IDP_spit(kmi->ptr->data); #endif +#endif printf("\n"); } @@ -1004,7 +1007,7 @@ static wmKeyMapItem *wm_keymap_item_find_handlers( } } else { - if (keymap_r) *keymap_r = keymap; + if (r_keymap) *r_keymap = keymap; return kmi; } } @@ -1013,13 +1016,14 @@ static wmKeyMapItem *wm_keymap_item_find_handlers( } /* ensure un-initialized keymap is never used */ - if (keymap_r) *keymap_r = NULL; + if (r_keymap) *r_keymap = NULL; return NULL; } static wmKeyMapItem *wm_keymap_item_find_props( const bContext *C, const char *opname, int opcontext, - IDProperty *properties, const bool is_strict, const bool is_hotkey, wmKeyMap **keymap_r) + IDProperty *properties, const bool is_strict, const bool is_hotkey, + wmKeyMap **r_keymap) { wmWindow *win = CTX_wm_window(C); ScrArea *sa = CTX_wm_area(C); @@ -1028,10 +1032,10 @@ static wmKeyMapItem *wm_keymap_item_find_props( /* look into multiple handler lists to find the item */ if (win) - found = wm_keymap_item_find_handlers(C, &win->handlers, opname, opcontext, properties, is_strict, is_hotkey, keymap_r); + found = wm_keymap_item_find_handlers(C, &win->handlers, opname, opcontext, properties, is_strict, is_hotkey, r_keymap); if (sa && found == NULL) - found = wm_keymap_item_find_handlers(C, &sa->handlers, opname, opcontext, properties, is_strict, is_hotkey, keymap_r); + found = wm_keymap_item_find_handlers(C, &sa->handlers, opname, opcontext, properties, is_strict, is_hotkey, r_keymap); if (found == NULL) { if (ELEM(opcontext, WM_OP_EXEC_REGION_WIN, WM_OP_INVOKE_REGION_WIN)) { @@ -1040,7 +1044,7 @@ static wmKeyMapItem *wm_keymap_item_find_props( ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW); if (ar) - found = wm_keymap_item_find_handlers(C, &ar->handlers, opname, opcontext, properties, is_strict, is_hotkey, keymap_r); + found = wm_keymap_item_find_handlers(C, &ar->handlers, opname, opcontext, properties, is_strict, is_hotkey, r_keymap); } } else if (ELEM(opcontext, WM_OP_EXEC_REGION_CHANNELS, WM_OP_INVOKE_REGION_CHANNELS)) { @@ -1048,18 +1052,18 @@ static wmKeyMapItem *wm_keymap_item_find_props( ar = BKE_area_find_region_type(sa, RGN_TYPE_CHANNELS); if (ar) - found = wm_keymap_item_find_handlers(C, &ar->handlers, opname, opcontext, properties, is_strict, is_hotkey, keymap_r); + found = wm_keymap_item_find_handlers(C, &ar->handlers, opname, opcontext, properties, is_strict, is_hotkey, r_keymap); } else if (ELEM(opcontext, WM_OP_EXEC_REGION_PREVIEW, WM_OP_INVOKE_REGION_PREVIEW)) { if (!(ar && ar->regiontype == RGN_TYPE_PREVIEW)) ar = BKE_area_find_region_type(sa, RGN_TYPE_PREVIEW); if (ar) - found = wm_keymap_item_find_handlers(C, &ar->handlers, opname, opcontext, properties, is_strict, is_hotkey, keymap_r); + found = wm_keymap_item_find_handlers(C, &ar->handlers, opname, opcontext, properties, is_strict, is_hotkey, r_keymap); } else { if (ar) - found = wm_keymap_item_find_handlers(C, &ar->handlers, opname, opcontext, properties, is_strict, is_hotkey, keymap_r); + found = wm_keymap_item_find_handlers(C, &ar->handlers, opname, opcontext, properties, is_strict, is_hotkey, r_keymap); } } @@ -1068,7 +1072,8 @@ static wmKeyMapItem *wm_keymap_item_find_props( static wmKeyMapItem *wm_keymap_item_find( const bContext *C, const char *opname, int opcontext, - IDProperty *properties, const bool is_hotkey, bool is_strict, wmKeyMap **keymap_r) + IDProperty *properties, const bool is_hotkey, bool is_strict, + wmKeyMap **r_keymap) { wmKeyMapItem *found; @@ -1081,7 +1086,7 @@ static wmKeyMapItem *wm_keymap_item_find( is_strict = is_strict && ((ot->flag & OPTYPE_MACRO) == 0); } - found = wm_keymap_item_find_props(C, opname, opcontext, properties, is_strict, is_hotkey, keymap_r); + found = wm_keymap_item_find_props(C, opname, opcontext, properties, is_strict, is_hotkey, r_keymap); /* This block is *only* useful in one case: when op uses an enum menu in its prop member * (then, we want to rerun a comparison with that 'prop' unset). Note this remains brittle, @@ -1105,7 +1110,7 @@ static wmKeyMapItem *wm_keymap_item_find( RNA_property_unset(&opptr, ot->prop); found = wm_keymap_item_find_props(C, opname, opcontext, properties_temp, - is_strict, is_hotkey, keymap_r); + is_strict, is_hotkey, r_keymap); } IDP_FreeProperty(properties_temp); @@ -1134,11 +1139,13 @@ static wmKeyMapItem *wm_keymap_item_find( "this might not be desired!\n", opname); printf("\tkm: '%s', kmi: '%s'\n", km->idname, kmi_str); #ifndef NDEBUG +#ifdef WITH_PYTHON printf("OPERATOR\n"); IDP_spit(properties); printf("KEYMAP\n"); IDP_spit(kmi->ptr->data); #endif +#endif printf("\n"); } @@ -1167,9 +1174,10 @@ char *WM_key_event_operator_string( int WM_key_event_operator_id( const bContext *C, const char *opname, int opcontext, - IDProperty *properties, const bool is_hotkey, wmKeyMap **keymap_r) + IDProperty *properties, const bool is_hotkey, + wmKeyMap **r_keymap) { - wmKeyMapItem *kmi = wm_keymap_item_find(C, opname, opcontext, properties, is_hotkey, true, keymap_r); + wmKeyMapItem *kmi = wm_keymap_item_find(C, opname, opcontext, properties, is_hotkey, true, r_keymap); if (kmi) return kmi->id; diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index 6f9646f35a1..66dd851fc91 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -172,6 +172,7 @@ void WM_operatortype_append(void (*opfunc)(wmOperatorType *)) 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; opfunc(ot); if (ot->name == NULL) { @@ -194,6 +195,7 @@ void WM_operatortype_append_ptr(void (*opfunc)(wmOperatorType *, void *), void * 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; 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); @@ -339,7 +341,9 @@ static int wm_macro_modal(bContext *C, wmOperator *op, const wmEvent *event) * */ if (op->opm->type->flag & OPTYPE_BLOCKING) { int bounds[4] = {-1, -1, -1, -1}; - int wrap = (U.uiflag & USER_CONTINUOUS_MOUSE) && ((op->opm->flag & OP_GRAB_POINTER) || (op->opm->type->flag & OPTYPE_GRAB_POINTER)); + const bool wrap = ( + (U.uiflag & USER_CONTINUOUS_MOUSE) && + ((op->opm->flag & OP_IS_MODAL_GRAB_CURSOR) || (op->opm->type->flag & OPTYPE_GRAB_CURSOR))); if (wrap) { ARegion *ar = CTX_wm_region(C); @@ -374,6 +378,7 @@ static void wm_macro_cancel(bContext *C, wmOperator *op) wmOperatorType *WM_operatortype_append_macro(const char *idname, const char *name, const char *description, int flag) { wmOperatorType *ot; + const char *i18n_context; if (WM_operatortype_find(idname, true)) { printf("%s: macro error: operator %s exists\n", __func__, idname); @@ -400,8 +405,9 @@ 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). */ - RNA_def_struct_translation_context(ot->srna, 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) : BLF_I18NCONTEXT_OPERATOR_DEFAULT; + RNA_def_struct_translation_context(ot->srna, i18n_context); + ot->translation_context = i18n_context; BLI_ghash_insert(global_ops_hash, (void *)ot->idname, ot); @@ -427,6 +433,7 @@ void WM_operatortype_append_macro_ptr(void (*opfunc)(wmOperatorType *, void *), /* 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; opfunc(ot, userdata); RNA_def_struct_ui_text(ot->srna, ot->name, ot->description); @@ -486,7 +493,7 @@ void WM_operatortype_remove_ptr(wmOperatorType *ot) if (ot->macro.first) wm_operatortype_free_macro(ot); - BLI_ghash_remove(global_ops_hash, (void *)ot->idname, NULL, NULL); + BLI_ghash_remove(global_ops_hash, ot->idname, NULL, NULL); WM_keyconfig_update_operatortype(); @@ -570,12 +577,13 @@ void WM_operator_bl_idname(char *to, const char *from) to[0] = 0; } -/* Print a string representation of the operator, with the args that it runs so python can run it again. +/** + * Print a string representation of the operator, with the args that it runs so python can run it again. * * When calling from an existing wmOperator, better to use simple version: - * WM_operator_pystring(C, op); + * `WM_operator_pystring(C, op);` * - * Note: both op and opptr may be NULL (op is only used for macro operators). + * \note Both \a op and \a opptr may be `NULL` (\a op is only used for macro operators). */ char *WM_operator_pystring_ex(bContext *C, wmOperator *op, const bool all_args, const bool macro_args, wmOperatorType *ot, PointerRNA *opptr) @@ -1263,6 +1271,13 @@ void WM_operator_properties_filesel(wmOperatorType *ot, int filter, short type, if (flag & WM_FILESEL_RELPATH) RNA_def_boolean(ot->srna, "relative_path", true, "Relative Path", "Select the file relative to the blend file"); + if ((filter & FILE_TYPE_IMAGE) || (filter & FILE_TYPE_MOVIE)) { + prop = RNA_def_boolean(ot->srna, "show_multiview", 0, "Enable Multi-View", ""); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + prop = RNA_def_boolean(ot->srna, "use_multiview", 0, "Use Multi-View", ""); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + } + prop = RNA_def_enum(ot->srna, "display_type", file_display_items, display, "Display Type", ""); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); } @@ -1392,7 +1407,7 @@ bool WM_operator_check_ui_enabled(const bContext *C, const char *idname) wmWindowManager *wm = CTX_wm_manager(C); Scene *scene = CTX_data_scene(C); - return !(ED_undo_valid(C, idname) == 0 || WM_jobs_test(wm, scene, WM_JOB_TYPE_ANY)); + return !((ED_undo_is_valid(C, idname) == false) || WM_jobs_test(wm, scene, WM_JOB_TYPE_ANY)); } wmOperator *WM_operator_last_redo(const bContext *C) @@ -1502,7 +1517,8 @@ static uiBlock *wm_block_create_redo(bContext *C, ARegion *ar, void *arg_op) block = UI_block_begin(C, ar, __func__, UI_EMBOSS); UI_block_flag_disable(block, UI_BLOCK_LOOP); - UI_block_flag_enable(block, UI_BLOCK_KEEP_OPEN | UI_BLOCK_MOVEMOUSE_QUIT); + /* UI_BLOCK_NUMSELECT for layer buttons */ + UI_block_flag_enable(block, UI_BLOCK_NUMSELECT | UI_BLOCK_KEEP_OPEN | UI_BLOCK_MOVEMOUSE_QUIT); /* if register is not enabled, the operator gets freed on OPERATOR_FINISHED * ui_apply_but_funcs_after calls ED_undo_operator_repeate_cb and crashes */ @@ -1539,6 +1555,9 @@ typedef struct wmOpPopUp { /* Only invoked by OK button in popups created with wm_block_dialog_create() */ static void dialog_exec_cb(bContext *C, void *arg1, void *arg2) { + wmWindowManager *wm = CTX_wm_manager(C); + wmWindow *win = CTX_wm_window(C); + wmOpPopUp *data = arg1; uiBlock *block = arg2; @@ -1551,7 +1570,11 @@ static void dialog_exec_cb(bContext *C, void *arg1, void *arg2) /* in this case, wm_operator_ui_popup_cancel wont run */ MEM_freeN(data); - UI_popup_block_close(C, block); + /* check window before 'block->handle' incase the + * popup execution closed the window and freed the block. see T44688. */ + if (BLI_findindex(&wm->windows, win) != -1) { + UI_popup_block_close(C, win, block); + } } static void dialog_check_cb(bContext *C, void *op_ptr, void *UNUSED(arg)) @@ -1708,18 +1731,20 @@ static int wm_operator_props_popup_ex(bContext *C, wmOperator *op, return OPERATOR_RUNNING_MODAL; } -/* Same as WM_operator_props_popup but don't use operator redo. - * just wraps WM_operator_props_dialog_popup. +/** + * Same as #WM_operator_props_popup but don't use operator redo. + * just wraps #WM_operator_props_dialog_popup. */ int WM_operator_props_popup_confirm(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { return wm_operator_props_popup_ex(C, op, false, false); } -/* Same as WM_operator_props_popup but call the operator first, +/** + * Same as #WM_operator_props_popup but call the operator first, * This way - the button values correspond to the result of the operator. - * Without this, first access to a button will make the result jump, - * see [#32452] */ + * Without this, first access to a button will make the result jump, see T32452. + */ int WM_operator_props_popup_call(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { return wm_operator_props_popup_ex(C, op, true, true); @@ -1823,21 +1848,16 @@ static void WM_OT_operator_defaults(wmOperatorType *ot) static void wm_block_splash_close(bContext *C, void *arg_block, void *UNUSED(arg)) { - UI_popup_block_close(C, arg_block); + wmWindow *win = CTX_wm_window(C); + UI_popup_block_close(C, win, arg_block); } static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *arg_unused); -/* XXX: hack to refresh splash screen with updated preset menu name, - * since popup blocks don't get regenerated like panels do */ -static void wm_block_splash_refreshmenu(bContext *UNUSED(C), void *UNUSED(arg_block), void *UNUSED(arg)) +static void wm_block_splash_refreshmenu(bContext *C, void *UNUSED(arg_block), void *UNUSED(arg)) { - /* ugh, causes crashes in other buttons, disabling for now until - * a better fix */ -#if 0 - UI_popup_block_close(C, arg_block); - UI_popup_block_invoke(C, wm_block_create_splash, NULL); -#endif + ARegion *ar_menu = CTX_wm_menu(C); + ED_region_tag_refresh_ui(ar_menu); } static int wm_resource_check_prev(void) @@ -1919,7 +1939,7 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar /* note on UI_BLOCK_NO_WIN_CLIP, the window size is not always synchronized * with the OS when the splash shows, window clipping in this case gives * ugly results and clipping the splash isn't useful anyway, just disable it [#32938] */ - UI_block_flag_enable(block, UI_BLOCK_KEEP_OPEN | UI_BLOCK_NO_WIN_CLIP); + UI_block_flag_enable(block, UI_BLOCK_LOOP | UI_BLOCK_KEEP_OPEN | UI_BLOCK_NO_WIN_CLIP); /* XXX splash scales with pixelsize, should become widget-units */ but = uiDefBut(block, UI_BTYPE_IMAGE, 0, "", 0, 0.5f * U.widget_unit, U.pixelsize * 501, U.pixelsize * 282, ibuf, 0.0, 0.0, 0, 0, ""); /* button owns the imbuf now */ @@ -1985,8 +2005,10 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar split = uiLayoutSplit(layout, 0.0f, false); col = uiLayoutColumn(split, false); uiItemL(col, IFACE_("Links"), ICON_NONE); +#if 0 uiItemStringO(col, IFACE_("Support an Open Animation Movie"), ICON_URL, "WM_OT_url_open", "url", "https://cloud.blender.org/join"); +#endif uiItemStringO(col, IFACE_("Donations"), ICON_URL, "WM_OT_url_open", "url", "http://www.blender.org/foundation/donation-payment/"); uiItemStringO(col, IFACE_("Credits"), ICON_URL, "WM_OT_url_open", "url", @@ -2440,18 +2462,18 @@ static void wm_open_mainfile_ui(bContext *UNUSED(C), wmOperator *op) struct FileRuntime *file_info = (struct FileRuntime *)&op->customdata; uiLayout *layout = op->layout; uiLayout *col = op->layout; - const char *autoexec_text = NULL; + const char *autoexec_text; uiItemR(layout, op->ptr, "load_ui", 0, NULL, ICON_NONE); col = uiLayoutColumn(layout, false); if (file_info->is_untrusted) { - autoexec_text = "Trusted Source [Untrusted Path]"; + autoexec_text = IFACE_("Trusted Source [Untrusted Path]"); uiLayoutSetActive(col, false); uiLayoutSetEnabled(col, false); } else { - autoexec_text = "Trusted Source"; + autoexec_text = IFACE_("Trusted Source"); } uiItemR(col, op->ptr, "use_scripts", 0, autoexec_text, ICON_NONE); @@ -2865,30 +2887,45 @@ static void wm_filepath_default(char *filepath) static void save_set_compress(wmOperator *op) { - if (!RNA_struct_property_is_set(op->ptr, "compress")) { - if (G.save_over) /* keep flag for existing file */ - RNA_boolean_set(op->ptr, "compress", (G.fileflags & G_FILE_COMPRESS) != 0); - else /* use userdef for new file */ - RNA_boolean_set(op->ptr, "compress", (U.flag & USER_FILECOMPRESS) != 0); + PropertyRNA *prop; + + prop = RNA_struct_find_property(op->ptr, "compress"); + if (!RNA_property_is_set(op->ptr, prop)) { + if (G.save_over) { /* keep flag for existing file */ + RNA_property_boolean_set(op->ptr, prop, (G.fileflags & G_FILE_COMPRESS) != 0); + } + else { /* use userdef for new file */ + RNA_property_boolean_set(op->ptr, prop, (U.flag & USER_FILECOMPRESS) != 0); + } } } -static int wm_save_as_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +static void save_set_filepath(wmOperator *op) { + PropertyRNA *prop; char name[FILE_MAX]; - save_set_compress(op); - - /* if not saved before, get the name of the most recently used .blend file */ - if (G.main->name[0] == 0 && G.recent_files.first) { - struct RecentFile *recent = G.recent_files.first; - BLI_strncpy(name, recent->filepath, FILE_MAX); + prop = RNA_struct_find_property(op->ptr, "filepath"); + if (!RNA_property_is_set(op->ptr, prop)) { + /* if not saved before, get the name of the most recently used .blend file */ + if (G.main->name[0] == 0 && G.recent_files.first) { + struct RecentFile *recent = G.recent_files.first; + BLI_strncpy(name, recent->filepath, FILE_MAX); + } + else { + BLI_strncpy(name, G.main->name, FILE_MAX); + } + + wm_filepath_default(name); + RNA_property_string_set(op->ptr, prop, name); } - else - BLI_strncpy(name, G.main->name, FILE_MAX); - - wm_filepath_default(name); - RNA_string_set(op->ptr, "filepath", name); +} + +static int wm_save_as_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + + save_set_compress(op); + save_set_filepath(op); WM_event_add_fileselect(C, op); @@ -2987,7 +3024,6 @@ static void WM_OT_save_as_mainfile(wmOperatorType *ot) static int wm_save_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - char name[FILE_MAX]; int ret; /* cancel if no active window */ @@ -2995,18 +3031,7 @@ static int wm_save_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *U return OPERATOR_CANCELLED; save_set_compress(op); - - /* if not saved before, get the name of the most recently used .blend file */ - if (G.main->name[0] == 0 && G.recent_files.first) { - struct RecentFile *recent = G.recent_files.first; - BLI_strncpy(name, recent->filepath, FILE_MAX); - } - else - BLI_strncpy(name, G.main->name, FILE_MAX); - - wm_filepath_default(name); - - RNA_string_set(op->ptr, "filepath", name); + save_set_filepath(op); /* if we're saving for the first time and prefer relative paths - any existing paths will be absolute, * enable the option to remap paths to avoid confusion [#37240] */ @@ -3018,8 +3043,11 @@ static int wm_save_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent *U } if (G.save_over) { - if (BLI_exists(name)) { - ret = WM_operator_confirm_message_ex(C, op, IFACE_("Save Over?"), ICON_QUESTION, name); + char path[FILE_MAX]; + + RNA_string_get(op->ptr, "filepath", path); + if (BLI_exists(path)) { + ret = WM_operator_confirm_message_ex(C, op, IFACE_("Save Over?"), ICON_QUESTION, path); } else { ret = wm_save_as_mainfile_exec(C, op); @@ -3144,9 +3172,10 @@ void WM_paint_cursor_end(wmWindowManager *wm, void *handle) /* **************** Border gesture *************** */ -/* Border gesture has two types: - * 1) WM_GESTURE_CROSS_RECT: starts a cross, on mouse click it changes to border - * 2) WM_GESTURE_RECT: starts immediate as a border, on mouse click or release it ends +/** + * Border gesture has two types: + * -# #WM_GESTURE_CROSS_RECT: starts a cross, on mouse click it changes to border. + * -# #WM_GESTURE_RECT: starts immediate as a border, on mouse click or release it ends. * * It stores 4 values (xmin, xmax, ymin, ymax) and event it ended with (event_type) */ @@ -3445,7 +3474,10 @@ static void tweak_gesture_modal(bContext *C, const wmEvent *event) tevent.type = EVT_TWEAK_M; tevent.val = val; /* mouse coords! */ - wm_event_add(window, &tevent); + + /* important we add immediately after this event, so future mouse releases + * (which may be in the queue already), are handled in order, see T44740 */ + wm_event_add_ex(window, &tevent, event); WM_gesture_end(C, gesture); /* frees gesture itself, and unregisters from window */ } @@ -3828,7 +3860,7 @@ void WM_OT_straightline_gesture(wmOperatorType *ot) #define WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE (35 * U.pixelsize) #define WM_RADIAL_CONTROL_DISPLAY_WIDTH (WM_RADIAL_CONTROL_DISPLAY_SIZE - WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE) #define WM_RADIAL_CONTROL_HEADER_LENGTH 180 -#define WM_RADIAL_MAX_STR 6 +#define WM_RADIAL_MAX_STR 10 typedef struct { PropertyType type; @@ -3874,10 +3906,12 @@ static void radial_control_set_initial_mouse(RadialControl *rc, const wmEvent *e switch (rc->subtype) { case PROP_NONE: case PROP_DISTANCE: - case PROP_PERCENTAGE: case PROP_PIXEL: d[0] = rc->initial_value * U.pixelsize; break; + case PROP_PERCENTAGE: + d[0] = (rc->initial_value) / 100.0f * WM_RADIAL_CONTROL_DISPLAY_WIDTH + WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE; + break; case PROP_FACTOR: d[0] = (1 - rc->initial_value) * WM_RADIAL_CONTROL_DISPLAY_WIDTH + WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE; break; @@ -3983,13 +4017,21 @@ static void radial_control_paint_cursor(bContext *C, int x, int y, void *customd switch (rc->subtype) { case PROP_NONE: case PROP_DISTANCE: - case PROP_PERCENTAGE: case PROP_PIXEL: r1 = rc->current_value * U.pixelsize; r2 = rc->initial_value * U.pixelsize; tex_radius = r1; alpha = 0.75; break; + case PROP_PERCENTAGE: + r1 = rc->current_value / 100.0f * WM_RADIAL_CONTROL_DISPLAY_WIDTH + WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE; + r2 = tex_radius = WM_RADIAL_CONTROL_DISPLAY_SIZE; + rmin = WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE; + BLI_snprintf(str, WM_RADIAL_MAX_STR, "%3.1f%%", rc->current_value); + strdrawlen = BLI_strlen_utf8(str); + tex_radius = r1; + alpha = 0.75; + break; case PROP_FACTOR: r1 = (1 - rc->current_value) * WM_RADIAL_CONTROL_DISPLAY_WIDTH + WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE; r2 = tex_radius = WM_RADIAL_CONTROL_DISPLAY_SIZE; @@ -4072,12 +4114,15 @@ typedef enum { RC_PROP_REQUIRE_BOOL = 4, } RCPropFlags; -/* attempt to retrieve the rna pointer/property from an rna path; - * returns 0 for failure, 1 for success, and also 1 if property is not - * set */ -static int radial_control_get_path(PointerRNA *ctx_ptr, wmOperator *op, - const char *name, PointerRNA *r_ptr, - PropertyRNA **r_prop, int req_length, RCPropFlags flags) +/** + * Attempt to retrieve the rna pointer/property from an rna path. + * + * \return 0 for failure, 1 for success, and also 1 if property is not set. + */ +static int radial_control_get_path( + PointerRNA *ctx_ptr, wmOperator *op, + const char *name, PointerRNA *r_ptr, + PropertyRNA **r_prop, int req_length, RCPropFlags flags) { PropertyRNA *unused_prop; int len; @@ -4211,8 +4256,7 @@ static int radial_control_invoke(bContext *C, wmOperator *op, const wmEvent *eve { wmWindowManager *wm; RadialControl *rc; - int min_value_int, max_value_int, step_int; - float step_float, precision; + if (!(op->customdata = rc = MEM_callocN(sizeof(RadialControl), "RadialControl"))) return OPERATOR_CANCELLED; @@ -4225,17 +4269,29 @@ static int radial_control_invoke(bContext *C, wmOperator *op, const wmEvent *eve /* get type, initial, min, and max values of the property */ switch ((rc->type = RNA_property_type(rc->prop))) { case PROP_INT: - rc->initial_value = RNA_property_int_get(&rc->ptr, rc->prop); - RNA_property_int_ui_range(&rc->ptr, rc->prop, &min_value_int, - &max_value_int, &step_int); - rc->min_value = min_value_int; - rc->max_value = max_value_int; + { + int value, min, max, step; + + value = RNA_property_int_get(&rc->ptr, rc->prop); + RNA_property_int_ui_range(&rc->ptr, rc->prop, &min, &max, &step); + + rc->initial_value = value; + rc->min_value = min_ii(value, min); + rc->max_value = max_ii(value, max); break; + } case PROP_FLOAT: - rc->initial_value = RNA_property_float_get(&rc->ptr, rc->prop); - RNA_property_float_ui_range(&rc->ptr, rc->prop, &rc->min_value, - &rc->max_value, &step_float, &precision); + { + float value, min, max, step, precision; + + value = RNA_property_float_get(&rc->ptr, rc->prop); + RNA_property_float_ui_range(&rc->ptr, rc->prop, &min, &max, &step, &precision); + + rc->initial_value = value; + rc->min_value = min_ff(value, min); + rc->max_value = max_ff(value, max); break; + } default: BKE_report(op->reports, RPT_ERROR, "Property must be an integer or a float"); MEM_freeN(rc); @@ -4424,12 +4480,15 @@ static int radial_control_modal(bContext *C, wmOperator *op, const wmEvent *even switch (rc->subtype) { case PROP_NONE: case PROP_DISTANCE: - case PROP_PERCENTAGE: case PROP_PIXEL: new_value = dist; if (snap) new_value = ((int)new_value + 5) / 10 * 10; new_value /= U.pixelsize; break; + case PROP_PERCENTAGE: + new_value = ((dist - WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE) / WM_RADIAL_CONTROL_DISPLAY_WIDTH) * 100.0f; + if (snap) new_value = ((int)(new_value + 2.5)) / 5 * 5; + break; case PROP_FACTOR: new_value = (WM_RADIAL_CONTROL_DISPLAY_SIZE - dist) / WM_RADIAL_CONTROL_DISPLAY_WIDTH; if (snap) new_value = ((int)ceil(new_value * 10.f) * 10.0f) / 100.f; @@ -4562,14 +4621,24 @@ static void redraw_timer_window_swap(bContext *C) CTX_wm_window_set(C, win); /* XXX context manipulation warning! */ } +enum eRedrawTimerItems { + eRTDrawRegion = 0, + eRTDrawRegionSwap = 1, + eRTDrawWindow = 2, + eRTDrawWindowSwap = 3, + eRTAnimationStep = 4, + eRTAnimationPlay = 5, + eRTUndo = 6, +}; + static EnumPropertyItem redraw_timer_type_items[] = { - {0, "DRAW", 0, "Draw Region", "Draw Region"}, - {1, "DRAW_SWAP", 0, "Draw Region + Swap", "Draw Region and Swap"}, - {2, "DRAW_WIN", 0, "Draw Window", "Draw Window"}, - {3, "DRAW_WIN_SWAP", 0, "Draw Window + Swap", "Draw Window and Swap"}, - {4, "ANIM_STEP", 0, "Anim Step", "Animation Steps"}, - {5, "ANIM_PLAY", 0, "Anim Play", "Animation Playback"}, - {6, "UNDO", 0, "Undo/Redo", "Undo/Redo"}, + {eRTDrawRegion, "DRAW", 0, "Draw Region", "Draw Region"}, + {eRTDrawRegionSwap, "DRAW_SWAP", 0, "Draw Region + Swap", "Draw Region and Swap"}, + {eRTDrawWindow, "DRAW_WIN", 0, "Draw Window", "Draw Window"}, + {eRTDrawWindowSwap, "DRAW_WIN_SWAP", 0, "Draw Window + Swap", "Draw Window and Swap"}, + {eRTAnimationStep, "ANIM_STEP", 0, "Anim Step", "Animation Steps"}, + {eRTAnimationPlay, "ANIM_PLAY", 0, "Anim Play", "Animation Playback"}, + {eRTUndo, "UNDO", 0, "Undo/Redo", "Undo/Redo"}, {0, NULL, 0, NULL, NULL} }; @@ -4586,11 +4655,13 @@ static int redraw_timer_exec(bContext *C, wmOperator *op) WM_cursor_wait(1); for (a = 0; a < iter; a++) { - if (type == 0) { - if (ar) + if (type == eRTDrawRegion) { + if (ar) { ED_region_do_draw(C, ar); + ar->do_draw = false; + } } - else if (type == 1) { + else if (type == eRTDrawRegionSwap) { wmWindow *win = CTX_wm_window(C); CTX_wm_menu_set(C, NULL); @@ -4599,7 +4670,7 @@ static int redraw_timer_exec(bContext *C, wmOperator *op) CTX_wm_window_set(C, win); /* XXX context manipulation warning! */ } - else if (type == 2) { + else if (type == eRTDrawWindow) { wmWindow *win = CTX_wm_window(C); ScrArea *sa; @@ -4616,6 +4687,7 @@ static int redraw_timer_exec(bContext *C, wmOperator *op) if (ar_iter->swinid) { CTX_wm_region_set(C, ar_iter); ED_region_do_draw(C, ar_iter); + ar->do_draw = false; } } } @@ -4625,10 +4697,10 @@ static int redraw_timer_exec(bContext *C, wmOperator *op) CTX_wm_area_set(C, sa_back); CTX_wm_region_set(C, ar_back); } - else if (type == 3) { + else if (type == eRTDrawWindowSwap) { redraw_timer_window_swap(C); } - else if (type == 4) { + else if (type == eRTAnimationStep) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); @@ -4636,7 +4708,7 @@ static int redraw_timer_exec(bContext *C, wmOperator *op) else scene->r.cfra++; BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene, scene->lay); } - else if (type == 5) { + else if (type == eRTAnimationPlay) { /* play anim, return on same frame as started with */ Main *bmain = CTX_data_main(C); @@ -4653,7 +4725,7 @@ static int redraw_timer_exec(bContext *C, wmOperator *op) redraw_timer_window_swap(C); } } - else { /* 6 */ + else { /* eRTUndo */ ED_undo_pop(C); ED_undo_redo(C); } @@ -4680,7 +4752,7 @@ static void WM_OT_redraw_timer(wmOperatorType *ot) ot->exec = redraw_timer_exec; ot->poll = WM_operator_winactive; - ot->prop = RNA_def_enum(ot->srna, "type", redraw_timer_type_items, 0, "Type", ""); + ot->prop = RNA_def_enum(ot->srna, "type", redraw_timer_type_items, eRTDrawRegion, "Type", ""); RNA_def_int(ot->srna, "iterations", 10, 1, INT_MAX, "Iterations", "Number of times to redraw", 1, 1000); } @@ -4727,6 +4799,7 @@ static void WM_OT_dependency_relations(wmOperatorType *ot) /* *************************** Mat/tex/etc. previews generation ************* */ typedef struct PreviewsIDEnsureStack { + bContext *C; Scene *scene; BLI_LINKSTACK_DECLARE(id_stack, ID *); @@ -4751,7 +4824,7 @@ static bool previews_id_ensure_callback(void *todo_v, ID **idptr, int UNUSED(cd_ if (id && (id->flag & LIB_DOIT)) { if (ELEM(GS(id->name), ID_MA, ID_TE, ID_IM, ID_WO, ID_LA)) { - previews_id_ensure(NULL, todo->scene, id); + previews_id_ensure(todo->C, todo->scene, id); } id->flag &= ~LIB_DOIT; /* Tag the ID as done in any case. */ BLI_LINKSTACK_PUSH(todo->id_stack, id); @@ -4776,6 +4849,7 @@ static int previews_ensure_exec(bContext *C, wmOperator *UNUSED(op)) for (scene = bmain->scene.first; scene; scene = scene->id.next) { preview_id_stack.scene = scene; + preview_id_stack.C = C; id = (ID *)scene; do { @@ -4808,6 +4882,38 @@ static void WM_OT_previews_ensure(wmOperatorType *ot) ot->exec = previews_ensure_exec; } +static int doc_view_manual_ui_context_exec(bContext *C, wmOperator *UNUSED(op)) +{ + PointerRNA ptr_props; + char buf[512]; + short retval = OPERATOR_CANCELLED; + + if (UI_but_online_manual_id_from_active(C, buf, sizeof(buf))) { + WM_operator_properties_create(&ptr_props, "WM_OT_doc_view_manual"); + RNA_string_set(&ptr_props, "doc_id", buf); + + retval = WM_operator_name_call_ptr( + C, WM_operatortype_find("WM_OT_doc_view_manual", false), + WM_OP_EXEC_DEFAULT, &ptr_props); + + WM_operator_properties_free(&ptr_props); + } + + return retval; +} + +static void WM_OT_doc_view_manual_ui_context(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "View Online Manual"; + ot->idname = "WM_OT_doc_view_manual_ui_context"; + ot->description = "View a context based online manual in a web browser"; + + /* callbacks */ + ot->poll = ED_operator_regionactive; + ot->exec = doc_view_manual_ui_context_exec; +} + /* ******************************************************* */ static void operatortype_ghash_free_cb(wmOperatorType *ot) @@ -4827,6 +4933,37 @@ static void operatortype_ghash_free_cb(wmOperatorType *ot) } /* ******************************************************* */ +/* toggle 3D for current window, turning it fullscreen if needed */ +static void WM_OT_stereo3d_set(wmOperatorType *ot) +{ + PropertyRNA *prop; + + ot->name = "Set Stereo 3D"; + ot->idname = "WM_OT_set_stereo_3d"; + ot->description = "Toggle 3D stereo support for current window (or change the display mode)"; + + ot->exec = wm_stereo3d_set_exec; + ot->invoke = wm_stereo3d_set_invoke; + ot->poll = WM_operator_winactive; + ot->ui = wm_stereo3d_set_draw; + ot->check = wm_stereo3d_set_check; + ot->cancel = wm_stereo3d_set_cancel; + + prop = RNA_def_enum(ot->srna, "display_mode", stereo3d_display_items, S3D_DISPLAY_ANAGLYPH, "Display Mode", ""); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_enum(ot->srna, "anaglyph_type", stereo3d_anaglyph_type_items, S3D_ANAGLYPH_REDCYAN, "Anaglyph Type", ""); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_enum(ot->srna, "interlace_type", stereo3d_interlace_type_items, S3D_INTERLACE_ROW, "Interlace Type", ""); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_boolean(ot->srna, "use_interlace_swap", false, "Swap Left/Right", + "Swap left and right stereo channels"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_boolean(ot->srna, "use_sidebyside_crosseyed", false, "Cross-Eyed", + "Right eye should see left image and vice-versa"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); +} + +/* ******************************************************* */ /* called on initialize WM_exit() */ void wm_operatortype_free(void) { @@ -4868,10 +5005,12 @@ void wm_operatortype_init(void) WM_operatortype_append(WM_OT_call_menu); WM_operatortype_append(WM_OT_call_menu_pie); WM_operatortype_append(WM_OT_radial_control); + WM_operatortype_append(WM_OT_stereo3d_set); #if defined(WIN32) WM_operatortype_append(WM_OT_console_toggle); #endif WM_operatortype_append(WM_OT_previews_ensure); + WM_operatortype_append(WM_OT_doc_view_manual_ui_context); } /* circleselect-like modal operators */ @@ -5098,6 +5237,8 @@ void wm_window_keymap(wmKeyConfig *keyconf) WM_keymap_verify_item(keymap, "WM_OT_window_fullscreen_toggle", F11KEY, KM_PRESS, KM_ALT, 0); WM_keymap_add_item(keymap, "WM_OT_quit_blender", QKEY, KM_PRESS, KM_CTRL, 0); + WM_keymap_add_item(keymap, "WM_OT_doc_view_manual_ui_context", F1KEY, KM_PRESS, KM_ALT, 0); + /* debug/testing */ WM_keymap_verify_item(keymap, "WM_OT_redraw_timer", TKEY, KM_PRESS, KM_ALT | KM_CTRL, 0); WM_keymap_verify_item(keymap, "WM_OT_debug_menu", DKEY, KM_PRESS, KM_ALT | KM_CTRL, 0); diff --git a/source/blender/windowmanager/intern/wm_playanim.c b/source/blender/windowmanager/intern/wm_playanim.c index 31883cf234c..cd97deaa88a 100644 --- a/source/blender/windowmanager/intern/wm_playanim.c +++ b/source/blender/windowmanager/intern/wm_playanim.c @@ -71,6 +71,20 @@ #include "WM_api.h" /* only for WM_main_playanim */ +#ifdef WITH_AUDASPACE +#include "AUD_C-API.h" + +AUD_Sound *source = NULL; +AUD_Handle *playback_handle = NULL; +AUD_Handle *scrub_handle = NULL; +#endif + +/* simple limiter to avoid flooding memory */ +#define USE_FRAME_CACHE_LIMIT +#ifdef USE_FRAME_CACHE_LIMIT +# define PLAY_FRAME_CACHE_MAX 30 +#endif + struct PlayState; static void playanim_window_zoom(struct PlayState *ps, const float zoom_offset); @@ -90,6 +104,7 @@ typedef struct PlayState { bool turbo; bool pingpong; bool noskip; + bool indicator; bool sstep; bool wait2; bool stopped; @@ -160,11 +175,11 @@ static struct WindowStateGlobal { eWS_Qual qual; } g_WS = {NULL}; -static void playanim_window_get_size(int *width_r, int *height_r) +static void playanim_window_get_size(int *r_width, int *r_height) { GHOST_RectangleHandle bounds = GHOST_GetClientBounds(g_WS.ghost_window); - *width_r = GHOST_GetWidthRectangle(bounds); - *height_r = GHOST_GetHeightRectangle(bounds); + *r_width = GHOST_GetWidthRectangle(bounds); + *r_height = GHOST_GetHeightRectangle(bounds); GHOST_DisposeRectangle(bounds); } @@ -222,8 +237,17 @@ typedef struct PlayAnimPict { } PlayAnimPict; static struct ListBase picsbase = {NULL, NULL}; +/* frames in memory - store them here to for easy deallocation later */ static bool fromdisk = false; static double ptottime = 0.0, swaptime = 0.04; +#ifdef WITH_AUDASPACE +static double fps_movie; +#endif + +#ifdef USE_FRAME_CACHE_LIMIT +static struct ListBase inmempicsbase = {NULL, NULL}; +static int added_images = 0; +#endif static PlayAnimPict *playanim_step(PlayAnimPict *playanim, int step) { @@ -322,6 +346,30 @@ static void playanim_toscreen(PlayState *ps, PlayAnimPict *picture, struct ImBuf BLF_draw(fontid, str, sizeof(str)); } + if (ps->indicator) { + float fac = ps->picture->frame / (double)(((PlayAnimPict *)picsbase.last)->frame - ((PlayAnimPict *)picsbase.first)->frame); + + fac = 2.0f * fac - 1.0f; + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + + glColor4f(0.0f, 1.0f, 0.0f, 1.0f); + + glBegin(GL_LINES); + glVertex2f(fac, -1.0f); + glVertex2f(fac, 1.0f); + glEnd(); + + glPopMatrix(); + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + } + GHOST_SwapWindowBuffers(g_WS.ghost_window); } @@ -429,6 +477,7 @@ 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 */ close(file); BLI_addtail(&picsbase, picture); count++; @@ -476,6 +525,76 @@ static void build_pict_list(PlayState *ps, const char *first, int totframes, int ps->loading = false; } +static void update_sound_fps(void) +{ +#ifdef WITH_AUDASPACE + if (playback_handle) { + /* swaptime stores the 1.0/fps ratio */ + double speed = 1.0 / (swaptime * fps_movie); + + AUD_setSoundPitch(playback_handle, speed); + } +#endif +} + +static void change_frame(PlayState *ps, int cx) +{ + int sizex, sizey; + int i; + + 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; + } + i = (i * cx) / sizex; + +#ifdef WITH_AUDASPACE + if (scrub_handle) { + AUD_stop(scrub_handle); + scrub_handle = NULL; + } + + if (playback_handle) { + AUD_Status status = AUD_getStatus(playback_handle); + if (status != AUD_STATUS_PLAYING) { + AUD_stop(playback_handle); + playback_handle = AUD_play(source, 1); + if (playback_handle) { + AUD_seek(playback_handle, i / fps_movie); + scrub_handle = AUD_pauseAfter(playback_handle, 1 / fps_movie); + } + update_sound_fps(); + } + else { + AUD_seek(playback_handle, i / fps_movie); + scrub_handle = AUD_pauseAfter(playback_handle, 1 / fps_movie); + } + } + else if (source) { + playback_handle = AUD_play(source, 1); + if (playback_handle) { + AUD_seek(playback_handle, i / fps_movie); + scrub_handle = AUD_pauseAfter(playback_handle, 1 / fps_movie); + } + update_sound_fps(); + } +#endif + + ps->picture = picsbase.first; + for (; i > 0; i--) { + if (ps->picture->next == NULL) break; + ps->picture = ps->picture->next; + } + + ps->sstep = true; + ps->wait2 = false; + ps->next_frame = 0; +} + static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void) { PlayState *ps = (PlayState *)ps_void; @@ -489,7 +608,6 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void) /* convert ghost event into value keyboard or mouse */ val = ELEM(type, GHOST_kEventKeyDown, GHOST_kEventButtonDown); - /* first check if we're busy loading files */ if (ps->loading) { switch (type) { @@ -535,6 +653,9 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void) case GHOST_kKeyA: if (val) ps->noskip = !ps->noskip; break; + case GHOST_kKeyI: + if (val) ps->indicator = !ps->indicator; + break; case GHOST_kKeyP: if (val) ps->pingpong = !ps->pingpong; break; @@ -548,42 +669,70 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void) } case GHOST_kKey1: case GHOST_kKeyNumpad1: - if (val) swaptime = ps->fstep / 60.0; + if (val) { + swaptime = ps->fstep / 60.0; + update_sound_fps(); + } break; case GHOST_kKey2: case GHOST_kKeyNumpad2: - if (val) swaptime = ps->fstep / 50.0; + if (val) { + swaptime = ps->fstep / 50.0; + update_sound_fps(); + } break; case GHOST_kKey3: case GHOST_kKeyNumpad3: - if (val) swaptime = ps->fstep / 30.0; + if (val) { + swaptime = ps->fstep / 30.0; + update_sound_fps(); + } break; case GHOST_kKey4: case GHOST_kKeyNumpad4: - if (g_WS.qual & WS_QUAL_SHIFT) + if (g_WS.qual & WS_QUAL_SHIFT) { swaptime = ps->fstep / 24.0; - else + update_sound_fps(); + } + else { swaptime = ps->fstep / 25.0; + update_sound_fps(); + } break; case GHOST_kKey5: case GHOST_kKeyNumpad5: - if (val) swaptime = ps->fstep / 20.0; + if (val) { + swaptime = ps->fstep / 20.0; + update_sound_fps(); + } break; case GHOST_kKey6: case GHOST_kKeyNumpad6: - if (val) swaptime = ps->fstep / 15.0; + if (val) { + swaptime = ps->fstep / 15.0; + update_sound_fps(); + } break; case GHOST_kKey7: case GHOST_kKeyNumpad7: - if (val) swaptime = ps->fstep / 12.0; + if (val) { + swaptime = ps->fstep / 12.0; + update_sound_fps(); + } break; case GHOST_kKey8: case GHOST_kKeyNumpad8: - if (val) swaptime = ps->fstep / 10.0; + if (val) { + swaptime = ps->fstep / 10.0; + update_sound_fps(); + } break; case GHOST_kKey9: case GHOST_kKeyNumpad9: - if (val) swaptime = ps->fstep / 6.0; + if (val) { + swaptime = ps->fstep / 6.0; + update_sound_fps(); + } break; case GHOST_kKeyLeftArrow: if (val) { @@ -646,6 +795,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void) } else { swaptime = ps->fstep / 5.0; + update_sound_fps(); } } break; @@ -662,10 +812,63 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void) } } break; + + case GHOST_kKeySpace: + if (val) { + if (ps->wait2 || ps->sstep) { + ps->wait2 = ps->sstep = false; +#ifdef WITH_AUDASPACE + { + PlayAnimPict *picture = picsbase.first; + /* TODO - store in ps direct? */ + int i = 0; + + while (picture && picture != ps->picture) { + i++; + picture = picture->next; + } + if (playback_handle) + AUD_stop(playback_handle); + playback_handle = AUD_play(source, 1); + if (playback_handle) + AUD_seek(playback_handle, i / fps_movie); + update_sound_fps(); + } +#endif + } + else { + ps->sstep = true; + ps->wait2 = true; +#ifdef WITH_AUDASPACE + if (playback_handle) { + AUD_stop(playback_handle); + playback_handle = NULL; + } +#endif + } + } + break; case GHOST_kKeyEnter: case GHOST_kKeyNumpadEnter: if (val) { ps->wait2 = ps->sstep = false; +#ifdef WITH_AUDASPACE + { + PlayAnimPict *picture = picsbase.first; + /* TODO - store in ps direct? */ + int i = 0; + while (picture && picture != ps->picture) { + i++; + picture = picture->next; + } + if (playback_handle) + AUD_stop(playback_handle); + playback_handle = AUD_play(source, 1); + if (playback_handle) + AUD_seek(playback_handle, i / fps_movie); + update_sound_fps(); + } +#endif } break; case GHOST_kKeyPeriod: @@ -677,6 +880,12 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void) else { ps->sstep = true; ps->wait2 = !ps->wait2; +#ifdef WITH_AUDASPACE + if (playback_handle) { + AUD_stop(playback_handle); + playback_handle = NULL; + } +#endif } } break; @@ -688,7 +897,10 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void) playanim_window_zoom(ps, 1.0f); } else { - swaptime /= 1.1; + if (swaptime > ps->fstep / 60.0) { + swaptime /= 1.1; + update_sound_fps(); + } } break; } @@ -700,7 +912,10 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void) playanim_window_zoom(ps, -1.0f); } else { - swaptime *= 1.1; + if (swaptime < ps->fstep / 5.0) { + swaptime *= 1.1; + update_sound_fps(); + } } break; } @@ -726,8 +941,10 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void) if (bd->button == GHOST_kButtonMaskLeft) { if (type == GHOST_kEventButtonDown) { - if (inside_window) + if (inside_window) { g_WS.qual |= WS_QUAL_LMOUSE; + change_frame(ps, cx); + } } else g_WS.qual &= ~WS_QUAL_LMOUSE; @@ -753,31 +970,12 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void) case GHOST_kEventCursorMove: { if (g_WS.qual & WS_QUAL_LMOUSE) { - int sizex, sizey; - int i; - GHOST_TEventCursorData *cd = GHOST_GetEventData(evt); int cx, cy; GHOST_ScreenToClient(g_WS.ghost_window, cd->x, cd->y, &cx, &cy); - 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; - } - i = (i * cx) / sizex; - ps->picture = picsbase.first; - for (; i > 0; i--) { - if (ps->picture->next == NULL) break; - ps->picture = ps->picture->next; - } - ps->sstep = true; - ps->wait2 = false; - ps->next_frame = 0; + change_frame(ps, cx); } break; } @@ -899,6 +1097,18 @@ 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; + + if (!AUD_init(AUD_OPENAL_DEVICE, specs, AUD_DEFAULT_BUFFER_SIZE)) + AUD_init(AUD_NULL_DEVICE, specs, AUD_DEFAULT_BUFFER_SIZE); + +#endif + /* ps.doubleb = true;*/ /* UNUSED */ ps.go = true; ps.direction = true; @@ -912,6 +1122,7 @@ static char *wm_main_playanim_intern(int argc, const char **argv) ps.stopped = false; ps.loading = false; ps.picture = NULL; + ps.indicator = false; ps.dropped_file[0] = 0; ps.zoom = 1.0f; /* resetmap = false */ @@ -1069,6 +1280,23 @@ static char *wm_main_playanim_intern(int argc, const char **argv) build_pict_list(&ps, filepath, (efra - sfra) + 1, ps.fstep, ps.fontid); +#ifdef WITH_AUDASPACE + source = AUD_load(filepath); + { + struct anim *anim_movie = ((struct PlayAnimPict *)picsbase.first)->anim; + if (anim_movie) { + short frs_sec = 25; + float frs_sec_base = 1.0; + + IMB_anim_get_fps(anim_movie, &frs_sec, &frs_sec_base, true); + + fps_movie = (double) frs_sec / (double) frs_sec_base; + /* enforce same fps for movie as sound */ + swaptime = ps.fstep / fps_movie; + } + } +#endif + for (i = 2; i < argc; i++) { BLI_strncpy(filepath, argv[i], sizeof(filepath)); build_pict_list(&ps, filepath, (efra - sfra) + 1, ps.fstep, ps.fontid); @@ -1108,6 +1336,13 @@ static char *wm_main_playanim_intern(int argc, const char **argv) } if (ptottime > 0.0) ptottime = 0.0; +#ifdef WITH_AUDASPACE + if (playback_handle) + AUD_stop(playback_handle); + playback_handle = AUD_play(source, 1); + update_sound_fps(); +#endif + while (ps.picture) { int hasevent; #ifndef USE_IMB_CACHE @@ -1130,11 +1365,39 @@ static char *wm_main_playanim_intern(int argc, const char **argv) } if (ibuf) { +#ifdef USE_FRAME_CACHE_LIMIT + LinkData *node; +#endif #ifdef USE_IMB_CACHE ps.picture->ibuf = ibuf; #endif +#ifdef USE_FRAME_CACHE_LIMIT + /* really basic memory conservation scheme. Keep frames in a fifo queue */ + node = inmempicsbase.last; + + while (node && added_images > PLAY_FRAME_CACHE_MAX) { + PlayAnimPict *pic = node->data; + + if (pic->ibuf && pic->ibuf != ibuf) { + LinkData *node_tmp; + IMB_freeImBuf(pic->ibuf); + pic->ibuf = NULL; + node_tmp = node->prev; + BLI_freelinkN(&inmempicsbase, node); + added_images--; + node = node_tmp; + } + else { + node = node->prev; + } + } + + BLI_addhead(&inmempicsbase, BLI_genericNodeN(ps.picture)); + added_images++; +#endif /* USE_FRAME_CACHE_LIMIT */ + BLI_strncpy(ibuf->name, ps.picture->name, sizeof(ibuf->name)); /* why only windows? (from 2.4x) - campbell */ @@ -1241,6 +1504,18 @@ static char *wm_main_playanim_intern(int argc, const char **argv) #endif BLI_freelistN(&picsbase); + BLI_freelistN(&inmempicsbase); + added_images = 0; + +#ifdef WITH_AUDASPACE + if (playback_handle) + AUD_stop(playback_handle); + if (scrub_handle) + AUD_stop(scrub_handle); + AUD_unload(source); + AUD_exit(); +#endif + #if 0 // XXX25 free_blender(); #else diff --git a/source/blender/windowmanager/intern/wm_stereo.c b/source/blender/windowmanager/intern/wm_stereo.c new file mode 100644 index 00000000000..13567518774 --- /dev/null +++ b/source/blender/windowmanager/intern/wm_stereo.c @@ -0,0 +1,599 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * The Original Code is Copyright (C) 2015 by Blender Foundation + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Dalai Felinto + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/windowmanager/intern/wm_stereo.c + * \ingroup wm + */ + + +#include <stdlib.h> +#include <string.h> + +#include "DNA_listBase.h" + +#include "RNA_access.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_listbase.h" +#include "BLI_rect.h" +#include "BLI_utildefines.h" + +#include "BIF_gl.h" + +#include "BKE_context.h" +#include "BKE_global.h" +#include "BKE_report.h" + +#include "GHOST_C-api.h" + +#include "ED_screen.h" + +#include "GPU_glew.h" + +#include "WM_api.h" +#include "WM_types.h" +#include "wm.h" +#include "wm_draw.h" /* wmDrawTriple */ +#include "wm_window.h" + +#include "UI_interface.h" +#include "UI_resources.h" + +static void wm_method_draw_stereo3d_pageflip(wmWindow *win) +{ + wmDrawData *drawdata; + int view; + + for (view = 0; view < 2; view ++) { + drawdata = BLI_findlink(&win->drawdata, (view * 2) + 1); + + if (view == STEREO_LEFT_ID) + glDrawBuffer(GL_BACK_LEFT); + else //STEREO_RIGHT_ID + glDrawBuffer(GL_BACK_RIGHT); + + wm_triple_draw_textures(win, drawdata->triple, 1.0f); + } + + glDrawBuffer(GL_BACK); +} + +static GLuint left_interlace_mask[32]; +static GLuint right_interlace_mask[32]; +static enum eStereo3dInterlaceType interlace_prev_type = -1; +static char interlace_prev_swap = -1; + +static void wm_interlace_masks_create(wmWindow *win) +{ + GLuint pattern; + char i; + bool swap = (win->stereo3d_format->flag & S3D_INTERLACE_SWAP) != 0; + enum eStereo3dInterlaceType interlace_type = win->stereo3d_format->interlace_type; + + if (interlace_prev_type == interlace_type && interlace_prev_swap == swap) + return; + + switch (interlace_type) { + case S3D_INTERLACE_ROW: + pattern = 0x00000000; + pattern = swap ? ~pattern : pattern; + for (i = 0; i < 32; i += 2) { + left_interlace_mask[i] = pattern; + right_interlace_mask[i] = ~pattern; + } + for (i = 1; i < 32; i += 2) { + left_interlace_mask[i] = ~pattern; + right_interlace_mask[i] = pattern; + } + break; + case S3D_INTERLACE_COLUMN: + pattern = 0x55555555; + pattern = swap ? ~pattern : pattern; + for (i = 0; i < 32; i++) { + left_interlace_mask[i] = pattern; + right_interlace_mask[i] = ~pattern; + } + break; + case S3D_INTERLACE_CHECKERBOARD: + default: + pattern = 0x55555555; + pattern = swap ? ~pattern : pattern; + for (i = 0; i < 32; i += 2) { + left_interlace_mask[i] = pattern; + right_interlace_mask[i] = ~pattern; + } + for (i = 1; i < 32; i += 2) { + left_interlace_mask[i] = ~pattern; + right_interlace_mask[i] = pattern; + } + break; + } + interlace_prev_type = interlace_type; + interlace_prev_swap = swap; +} + +static void wm_method_draw_stereo3d_interlace(wmWindow *win) +{ + wmDrawData *drawdata; + int view; + + wm_interlace_masks_create(win); + + for (view = 0; view < 2; view ++) { + drawdata = BLI_findlink(&win->drawdata, (view * 2) + 1); + + glEnable(GL_POLYGON_STIPPLE); + glPolygonStipple(view ? (GLubyte *) right_interlace_mask : (GLubyte *) left_interlace_mask); + + wm_triple_draw_textures(win, drawdata->triple, 1.0f); + glDisable(GL_POLYGON_STIPPLE); + } +} + +static void wm_method_draw_stereo3d_anaglyph(wmWindow *win) +{ + wmDrawData *drawdata; + int view, bit; + + for (view = 0; view < 2; view ++) { + drawdata = BLI_findlink(&win->drawdata, (view * 2) + 1); + + bit = view + 1; + switch (win->stereo3d_format->anaglyph_type) { + case S3D_ANAGLYPH_REDCYAN: + glColorMask((1&bit) ? GL_TRUE : GL_FALSE, + (2&bit) ? GL_TRUE : GL_FALSE, + (2&bit) ? GL_TRUE : GL_FALSE, + GL_FALSE); + break; + case S3D_ANAGLYPH_GREENMAGENTA: + glColorMask((2&bit) ? GL_TRUE : GL_FALSE, + (1&bit) ? GL_TRUE : GL_FALSE, + (2&bit) ? GL_TRUE : GL_FALSE, + GL_FALSE); + break; + case S3D_ANAGLYPH_YELLOWBLUE: + glColorMask((1&bit) ? GL_TRUE : GL_FALSE, + (1&bit) ? GL_TRUE : GL_FALSE, + (2&bit) ? GL_TRUE : GL_FALSE, + GL_FALSE); + break; + } + + wm_triple_draw_textures(win, drawdata->triple, 1.0f); + + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + } +} + +static void wm_method_draw_stereo3d_sidebyside(wmWindow *win) +{ + wmDrawData *drawdata; + wmDrawTriple *triple; + float halfx, halfy, ratiox, ratioy; + int x, y, offx, offy; + float alpha = 1.0f; + int view; + int soffx; + bool cross_eyed = (win->stereo3d_format->flag & S3D_SIDEBYSIDE_CROSSEYED) != 0; + + for (view = 0; view < 2; view ++) { + drawdata = BLI_findlink(&win->drawdata, (view * 2) + 1); + triple = drawdata->triple; + + soffx = WM_window_pixels_x(win) * 0.5f; + if (view == STEREO_LEFT_ID) { + if (!cross_eyed) + soffx = 0; + } + else { //RIGHT_LEFT_ID + if (cross_eyed) + soffx = 0; + } + + glEnable(triple->target); + + for (y = 0, offy = 0; y < triple->ny; offy += triple->y[y], y++) { + for (x = 0, offx = 0; x < triple->nx; offx += triple->x[x], x++) { + const int sizex = triple->x[x]; + const int sizey = triple->y[y]; + + /* wmOrtho for the screen has this same offset */ + ratiox = sizex; + ratioy = sizey; + halfx = GLA_PIXEL_OFS; + halfy = GLA_PIXEL_OFS; + + /* texture rectangle has unnormalized coordinates */ + if (triple->target == GL_TEXTURE_2D) { + ratiox /= triple->x[x]; + ratioy /= triple->y[y]; + halfx /= triple->x[x]; + halfy /= triple->y[y]; + } + + glBindTexture(triple->target, triple->bind[x + y * triple->nx]); + + glColor4f(1.0f, 1.0f, 1.0f, alpha); + glBegin(GL_QUADS); + glTexCoord2f(halfx, halfy); + glVertex2f(soffx + (offx * 0.5f), offy); + + glTexCoord2f(ratiox + halfx, halfy); + glVertex2f(soffx + ((offx + sizex) * 0.5f), offy); + + glTexCoord2f(ratiox + halfx, ratioy + halfy); + glVertex2f(soffx + ((offx + sizex) * 0.5f), offy + sizey); + + glTexCoord2f(halfx, ratioy + halfy); + glVertex2f(soffx + (offx * 0.5f), offy + sizey); + glEnd(); + } + } + + glBindTexture(triple->target, 0); + glDisable(triple->target); + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + } +} + +static void wm_method_draw_stereo3d_topbottom(wmWindow *win) +{ + wmDrawData *drawdata; + wmDrawTriple *triple; + float halfx, halfy, ratiox, ratioy; + int x, y, offx, offy; + float alpha = 1.0f; + int view; + int soffy; + + for (view = 0; view < 2; view ++) { + drawdata = BLI_findlink(&win->drawdata, (view * 2) + 1); + triple = drawdata->triple; + + if (view == STEREO_LEFT_ID) { + soffy = WM_window_pixels_y(win) * 0.5f; + } + else { /* STEREO_RIGHT_ID */ + soffy = 0; + } + + glEnable(triple->target); + + for (y = 0, offy = 0; y < triple->ny; offy += triple->y[y], y++) { + for (x = 0, offx = 0; x < triple->nx; offx += triple->x[x], x++) { + const int sizex = triple->x[x]; + const int sizey = triple->y[y]; + + /* wmOrtho for the screen has this same offset */ + ratiox = sizex; + ratioy = sizey; + halfx = GLA_PIXEL_OFS; + halfy = GLA_PIXEL_OFS; + + /* texture rectangle has unnormalized coordinates */ + if (triple->target == GL_TEXTURE_2D) { + ratiox /= triple->x[x]; + ratioy /= triple->y[y]; + halfx /= triple->x[x]; + halfy /= triple->y[y]; + } + + glBindTexture(triple->target, triple->bind[x + y * triple->nx]); + + glColor4f(1.0f, 1.0f, 1.0f, alpha); + glBegin(GL_QUADS); + glTexCoord2f(halfx, halfy); + glVertex2f(offx, soffy + (offy * 0.5f)); + + glTexCoord2f(ratiox + halfx, halfy); + glVertex2f(offx + sizex, soffy + (offy * 0.5f)); + + glTexCoord2f(ratiox + halfx, ratioy + halfy); + glVertex2f(offx + sizex, soffy + ((offy + sizey) * 0.5f)); + + glTexCoord2f(halfx, ratioy + halfy); + glVertex2f(offx, soffy + ((offy + sizey) * 0.5f)); + glEnd(); + } + } + + glBindTexture(triple->target, 0); + glDisable(triple->target); + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + } +} + +void wm_method_draw_stereo3d(const bContext *UNUSED(C), wmWindow *win) +{ + switch (win->stereo3d_format->display_mode) { + case S3D_DISPLAY_ANAGLYPH: + wm_method_draw_stereo3d_anaglyph(win); + break; + case S3D_DISPLAY_INTERLACE: + wm_method_draw_stereo3d_interlace(win); + break; + case S3D_DISPLAY_PAGEFLIP: + wm_method_draw_stereo3d_pageflip(win); + break; + case S3D_DISPLAY_SIDEBYSIDE: + wm_method_draw_stereo3d_sidebyside(win); + break; + case S3D_DISPLAY_TOPBOTTOM: + wm_method_draw_stereo3d_topbottom(win); + break; + default: + break; + } +} + +static bool wm_stereo3d_quadbuffer_supported(void) +{ + int gl_stereo = 0; + glGetBooleanv(GL_STEREO, (GLboolean *)&gl_stereo); + return gl_stereo != 0; +} + +static bool wm_stereo3d_is_fullscreen_required(eStereoDisplayMode stereo_display) +{ + return ELEM(stereo_display, + S3D_DISPLAY_SIDEBYSIDE, + S3D_DISPLAY_TOPBOTTOM); +} + +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 + * 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; + } + + if ((skip_stereo3d_check == false) && (ED_screen_stereo3d_required(screen) == false)) { + return false; + } + + /* some 3d methods change the window arrangment, 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; + } + + return true; +} + +/************************** Stereo 3D operator **********************************/ +typedef struct Stereo3dData { + Stereo3dFormat stereo3d_format; +} Stereo3dData; + +static bool wm_stereo3d_set_properties(bContext *UNUSED(C), wmOperator *op) +{ + Stereo3dData *s3dd = op->customdata; + Stereo3dFormat *s3d = &s3dd->stereo3d_format; + PropertyRNA *prop; + bool is_set = false; + + prop = RNA_struct_find_property(op->ptr, "display_mode"); + if (RNA_property_is_set(op->ptr, prop)) { + s3d->display_mode = RNA_property_enum_get(op->ptr, prop); + is_set = true; + } + + prop = RNA_struct_find_property(op->ptr, "anaglyph_type"); + if (RNA_property_is_set(op->ptr, prop)) { + s3d->anaglyph_type = RNA_property_enum_get(op->ptr, prop); + is_set = true; + } + + prop = RNA_struct_find_property(op->ptr, "interlace_type"); + if (RNA_property_is_set(op->ptr, prop)) { + s3d->interlace_type = RNA_property_enum_get(op->ptr, prop); + is_set = true; + } + + prop = RNA_struct_find_property(op->ptr, "use_interlace_swap"); + if (RNA_property_is_set(op->ptr, prop)) { + if (RNA_property_boolean_get(op->ptr, prop)) + s3d->flag |= S3D_INTERLACE_SWAP; + else + s3d->flag &= ~S3D_INTERLACE_SWAP; + is_set = true; + } + + prop = RNA_struct_find_property(op->ptr, "use_sidebyside_crosseyed"); + if (RNA_property_is_set(op->ptr, prop)) { + if (RNA_property_boolean_get(op->ptr, prop)) + s3d->flag |= S3D_SIDEBYSIDE_CROSSEYED; + else + s3d->flag &= ~S3D_SIDEBYSIDE_CROSSEYED; + is_set = true; + } + + return is_set; +} + +static void wm_stereo3d_set_init(bContext *C, wmOperator *op) +{ + Stereo3dData *s3dd; + wmWindow *win = CTX_wm_window(C); + + op->customdata = s3dd = MEM_callocN(sizeof(Stereo3dData), __func__); + + /* store the original win stereo 3d settings in case of cancel */ + s3dd->stereo3d_format = *win->stereo3d_format; +} + +int wm_stereo3d_set_exec(bContext *C, wmOperator *op) +{ + wmWindowManager *wm = CTX_wm_manager(C); + wmWindow *win_src = CTX_wm_window(C); + wmWindow *win_dst = NULL; + const bool is_fullscreen = WM_window_is_fullscreen(win_src); + char prev_display_mode = win_src->stereo3d_format->display_mode; + Stereo3dData *s3dd; + bool ok = true; + + if (G.background) + return OPERATOR_CANCELLED; + + if (op->customdata == NULL) { + /* no invoke means we need to set the operator properties here */ + wm_stereo3d_set_init(C, op); + wm_stereo3d_set_properties(C, op); + } + + s3dd = op->customdata; + *win_src->stereo3d_format = s3dd->stereo3d_format; + + if (prev_display_mode == S3D_DISPLAY_PAGEFLIP && + prev_display_mode != win_src->stereo3d_format->display_mode) + { + /* in case the hardward supports pageflip but not the display */ + if ((win_dst = wm_window_copy_test(C, win_src))) { + /* pass */ + } + else { + BKE_report(op->reports, RPT_ERROR, + "Failed to create a window without quad-buffer support, you may experience flickering"); + ok = false; + } + } + else if (win_src->stereo3d_format->display_mode == S3D_DISPLAY_PAGEFLIP) { + /* ED_screen_duplicate() can't handle other cases yet T44688 */ + if (win_src->screen->state != SCREENNORMAL) { + BKE_report(op->reports, RPT_ERROR, + "Failed to switch to Time Sequential mode when in fullscreen"); + ok = false; + } + /* pageflip requires a new window to be created with the proper OS flags */ + else if ((win_dst = wm_window_copy_test(C, win_src))) { + if (wm_stereo3d_quadbuffer_supported()) { + BKE_report(op->reports, RPT_INFO, "Quad-buffer window successfully created"); + } + else { + wm_window_close(C, wm, win_dst); + win_dst = NULL; + BKE_report(op->reports, RPT_ERROR, "Quad-buffer not supported by the system"); + ok = false; + } + } + else { + BKE_report(op->reports, RPT_ERROR, + "Failed to create a window compatible with the time sequential display method"); + ok = false; + } + } + + if (wm_stereo3d_is_fullscreen_required(s3dd->stereo3d_format.display_mode)) { + if (!is_fullscreen) { + BKE_report(op->reports, RPT_INFO, "Stereo 3D Mode requires the window to be fullscreen"); + } + } + + MEM_freeN(op->customdata); + + if (ok) { + if (win_dst) { + wm_window_close(C, wm, win_src); + } + + WM_event_add_notifier(C, NC_WINDOW, NULL); + return OPERATOR_FINISHED; + } + else { + /* without this, the popup won't be freed freed properly T44688 */ + CTX_wm_window_set(C, win_src); + win_src->stereo3d_format->display_mode = prev_display_mode; + return OPERATOR_CANCELLED; + } +} + +int wm_stereo3d_set_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + wm_stereo3d_set_init(C, op); + + if (wm_stereo3d_set_properties(C, op)) + return wm_stereo3d_set_exec(C, op); + else + return WM_operator_props_dialog_popup(C, op, 250, 100); +} + +void wm_stereo3d_set_draw(bContext *UNUSED(C), wmOperator *op) +{ + Stereo3dData *s3dd = op->customdata; + PointerRNA stereo3d_format_ptr; + uiLayout *layout = op->layout; + uiLayout *col; + + RNA_pointer_create(NULL, &RNA_Stereo3dDisplay, &s3dd->stereo3d_format, &stereo3d_format_ptr); + + col = uiLayoutColumn(layout, false); + uiItemR(col, &stereo3d_format_ptr, "display_mode", 0, NULL, ICON_NONE); + + switch (s3dd->stereo3d_format.display_mode) { + case S3D_DISPLAY_ANAGLYPH: + { + uiItemR(col, &stereo3d_format_ptr, "anaglyph_type", 0, NULL, ICON_NONE); + break; + } + case S3D_DISPLAY_INTERLACE: + { + uiItemR(col, &stereo3d_format_ptr, "interlace_type", 0, NULL, ICON_NONE); + uiItemR(col, &stereo3d_format_ptr, "use_interlace_swap", 0, NULL, ICON_NONE); + break; + } + case S3D_DISPLAY_SIDEBYSIDE: + { + uiItemR(col, &stereo3d_format_ptr, "use_sidebyside_crosseyed", 0, NULL, ICON_NONE); + /* fall-through */ + } + case S3D_DISPLAY_PAGEFLIP: + case S3D_DISPLAY_TOPBOTTOM: + default: + { + break; + } + } +} + +bool wm_stereo3d_set_check(bContext *UNUSED(C), wmOperator *UNUSED(op)) +{ + /* the check function guarantees that the menu is updated to show the + * sub-options when an enum change (e.g., it shows the anaglyph options + * when anaglyph is on, and the interlace options when this is on */ + return true; +} + +void wm_stereo3d_set_cancel(bContext *UNUSED(C), wmOperator *op) +{ + MEM_freeN(op->customdata); + op->customdata = NULL; +} diff --git a/source/blender/windowmanager/intern/wm_subwindow.c b/source/blender/windowmanager/intern/wm_subwindow.c index 4ce2415e310..d081644fa61 100644 --- a/source/blender/windowmanager/intern/wm_subwindow.c +++ b/source/blender/windowmanager/intern/wm_subwindow.c @@ -54,11 +54,12 @@ #include "WM_api.h" #include "wm_subwindow.h" -/* wmSubWindow stored in wmWindow... but not exposed outside this C file */ -/* it seems a bit redundant (area regions can store it too, but we keep it - * because we can store all kind of future opengl fanciness here */ - -/* we use indices and array because: +/** + * \note #wmSubWindow stored in #wmWindow but not exposed outside this C file, + * it seems a bit redundant (area regions can store it too, but we keep it + * because we can store all kind of future opengl fanciness here. + * + * We use indices and array because: * - index has safety, no pointers from this C file hanging around * - fast lookups of indices with array, list would give overhead * - old code used it this way... diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index 4f7e5ab75b3..d11d88db147 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -107,25 +107,25 @@ static struct WMInitStruct { /* XXX this one should correctly check for apple top header... * done for Cocoa : returns window contents (and not frame) max size*/ -void wm_get_screensize(int *width_r, int *height_r) +void wm_get_screensize(int *r_width, int *r_height) { unsigned int uiwidth; unsigned int uiheight; GHOST_GetMainDisplayDimensions(g_system, &uiwidth, &uiheight); - *width_r = uiwidth; - *height_r = uiheight; + *r_width = uiwidth; + *r_height = uiheight; } /* size of all screens (desktop), useful since the mouse is bound by this */ -void wm_get_desktopsize(int *width_r, int *height_r) +void wm_get_desktopsize(int *r_width, int *r_height) { unsigned int uiwidth; unsigned int uiheight; GHOST_GetAllDisplayDimensions(g_system, &uiwidth, &uiheight); - *width_r = uiwidth; - *height_r = uiheight; + *r_width = uiwidth; + *r_height = uiheight; } /* keeps offset and size within monitor bounds */ @@ -206,12 +206,13 @@ void wm_window_free(bContext *C, wmWindowManager *wm, wmWindow *win) wm_event_free_all(win); wm_subwindows_free(win); - - if (win->drawdata) - MEM_freeN(win->drawdata); - + + wm_draw_data_free(win); + wm_ghostwindow_destroy(win); - + + MEM_freeN(win->stereo3d_format); + MEM_freeN(win); } @@ -236,32 +237,60 @@ wmWindow *wm_window_new(bContext *C) BLI_addtail(&wm->windows, win); win->winid = find_free_winid(wm); + win->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Stereo 3D Format (window)"); + return win; } /* part of wm_window.c api */ -wmWindow *wm_window_copy(bContext *C, wmWindow *winorig) +wmWindow *wm_window_copy(bContext *C, wmWindow *win_src) { - wmWindow *win = wm_window_new(C); + wmWindow *win_dst = wm_window_new(C); - win->posx = winorig->posx + 10; - win->posy = winorig->posy; - win->sizex = winorig->sizex; - win->sizey = winorig->sizey; + win_dst->posx = win_src->posx + 10; + win_dst->posy = win_src->posy; + win_dst->sizex = win_src->sizex; + win_dst->sizey = win_src->sizey; /* duplicate assigns to window */ - win->screen = ED_screen_duplicate(win, winorig->screen); - BLI_strncpy(win->screenname, win->screen->id.name + 2, sizeof(win->screenname)); - win->screen->winid = win->winid; + win_dst->screen = ED_screen_duplicate(win_dst, win_src->screen); + BLI_strncpy(win_dst->screenname, win_dst->screen->id.name + 2, sizeof(win_dst->screenname)); + win_dst->screen->winid = win_dst->winid; - win->screen->do_refresh = true; - win->screen->do_draw = true; + win_dst->screen->do_refresh = true; + win_dst->screen->do_draw = true; - win->drawmethod = U.wmdrawmethod; - win->drawdata = NULL; - - return win; + win_dst->drawmethod = U.wmdrawmethod; + + BLI_listbase_clear(&win_dst->drawdata); + + *win_dst->stereo3d_format = *win_src->stereo3d_format; + + return win_dst; +} + +/** + * A higher level version of copy that tests the new window can be added. + * (called from the operator directly) + */ +wmWindow *wm_window_copy_test(bContext *C, wmWindow *win_src) +{ + wmWindowManager *wm = CTX_wm_manager(C); + wmWindow *win_dst; + + win_dst = wm_window_copy(C, win_src); + + WM_check(C); + + if (win_dst->ghostwin) { + WM_event_add_notifier(C, NC_WINDOW | NA_ADDED, NULL); + return win_dst; + } + else { + wm_window_close(C, wm, win_dst); + return NULL; + } } /* this is event from ghost, or exit-blender op */ @@ -367,6 +396,10 @@ static void wm_window_add_ghostwindow(wmWindowManager *wm, const char *title, wm glSettings.numOfAASamples = multisamples; + /* a new window is created when pageflip mode is required for a window */ + if (win->stereo3d_format->display_mode == S3D_DISPLAY_PAGEFLIP) + glSettings.flags |= GHOST_glStereoVisual; + if (!(U.uiflag2 & USER_OPENGL_NO_WARN_SUPPORT)) glSettings.flags |= GHOST_glWarnSupport; @@ -446,11 +479,11 @@ void wm_window_add_ghostwindows(wmWindowManager *wm) if (wm_init_state.size_x == 0) { wm_get_screensize(&wm_init_state.size_x, &wm_init_state.size_y); - /* note!, this isnt quite correct, active screen maybe offset 1000s if PX, - * we'd need a wm_get_screensize like function that gives offset, - * in practice the window manager will likely move to the correct monitor */ - wm_init_state.start_x = 0; - wm_init_state.start_y = 0; + /* note!, this isnt quite correct, active screen maybe offset 1000s if PX, + * we'd need a wm_get_screensize like function that gives offset, + * in practice the window manager will likely move to the correct monitor */ + wm_init_state.start_x = 0; + wm_init_state.start_y = 0; #ifdef WITH_X11 /* X11 */ /* X11, start maximized but use default sane size */ @@ -519,8 +552,7 @@ wmWindow *WM_window_open(bContext *C, const rcti *rect) win->sizey = BLI_rcti_size_y(rect); win->drawmethod = U.wmdrawmethod; - win->drawdata = NULL; - + WM_check(C); return win; @@ -606,12 +638,12 @@ void WM_window_open_temp(bContext *C, rcti *position, int type) /* operator callback */ int wm_window_duplicate_exec(bContext *C, wmOperator *UNUSED(op)) { - wm_window_copy(C, CTX_wm_window(C)); - WM_check(C); - - WM_event_add_notifier(C, NC_WINDOW | NA_ADDED, NULL); - - return OPERATOR_FINISHED; + wmWindow *win_src = CTX_wm_window(C); + bool ok; + + ok = (wm_window_copy_test(C, win_src) != NULL); + + return ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED; } @@ -1098,10 +1130,10 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr } -/* This timer system only gives maximum 1 timer event per redraw cycle, +/** + * This timer system only gives maximum 1 timer event per redraw cycle, * to prevent queues to get overloaded. - * Timer handlers should check for delta to decide if they just - * update, or follow real time. + * Timer handlers should check for delta to decide if they just update, or follow real time. * Timer handlers can also set duration to match frames passed */ static int wm_window_timer(const bContext *C) @@ -1132,7 +1164,7 @@ static int wm_window_timer(const bContext *C) wm_event_init_from_window(win, &event); event.type = wt->event_type; - event.val = 0; + event.val = KM_NOTHING; event.keymodifier = 0; event.custom = EVT_DATA_TIMER; event.customdata = wt; @@ -1395,10 +1427,10 @@ void WM_progress_clear(wmWindow *win) /* ************************************ */ -void wm_window_get_position(wmWindow *win, int *posx_r, int *posy_r) +void wm_window_get_position(wmWindow *win, int *r_pos_x, int *r_pos_y) { - *posx_r = win->posx; - *posy_r = win->posy; + *r_pos_x = win->posx; + *r_pos_y = win->posy; } void wm_window_set_size(wmWindow *win, int width, int height) diff --git a/source/blender/windowmanager/wm.h b/source/blender/windowmanager/wm.h index de04129a0ef..2f06ddab1e8 100644 --- a/source/blender/windowmanager/wm.h +++ b/source/blender/windowmanager/wm.h @@ -76,6 +76,14 @@ void wm_autosave_delete(void); void wm_autosave_read(bContext *C, struct ReportList *reports); void wm_autosave_location(char *filepath); +/* wm_stereo.c */ +void wm_method_draw_stereo3d(const bContext *C, wmWindow *win); +int wm_stereo3d_set_exec(bContext *C, wmOperator *op); +int wm_stereo3d_set_invoke(bContext *C, wmOperator *op, const wmEvent *event); +void wm_stereo3d_set_draw(bContext *C, wmOperator *op); +bool wm_stereo3d_set_check(bContext *C, wmOperator *op); +void wm_stereo3d_set_cancel(bContext *C, wmOperator *op); + /* init operator properties */ void wm_open_init_load_ui(wmOperator *op, bool use_prefs); void wm_open_init_use_scripts(wmOperator *op, bool use_prefs); diff --git a/source/blender/windowmanager/wm_draw.h b/source/blender/windowmanager/wm_draw.h index 3d72fe17c79..5dc52b2e4fb 100644 --- a/source/blender/windowmanager/wm_draw.h +++ b/source/blender/windowmanager/wm_draw.h @@ -32,6 +32,23 @@ #ifndef __WM_DRAW_H__ #define __WM_DRAW_H__ +#include "GPU_glew.h" + + +#define MAX_N_TEX 3 + +typedef struct wmDrawTriple { + GLuint bind[MAX_N_TEX * MAX_N_TEX]; + int x[MAX_N_TEX], y[MAX_N_TEX]; + int nx, ny; + GLenum target; +} wmDrawTriple; + +typedef struct wmDrawData { + struct wmDrawData *next, *prev; + wmDrawTriple *triple; +} wmDrawData; + struct bContext; struct wmWindow; struct ARegion; @@ -43,5 +60,9 @@ void wm_draw_region_clear (struct wmWindow *win, struct ARegion *ar); void wm_tag_redraw_overlay (struct wmWindow *win, struct ARegion *ar); +void wm_triple_draw_textures (struct wmWindow *win, struct wmDrawTriple *triple, float alpha); + +void wm_draw_data_free (struct wmWindow *win); + #endif /* __WM_DRAW_H__ */ diff --git a/source/blender/windowmanager/wm_event_system.h b/source/blender/windowmanager/wm_event_system.h index f89177a82ea..efc01b1f8a8 100644 --- a/source/blender/windowmanager/wm_event_system.h +++ b/source/blender/windowmanager/wm_event_system.h @@ -45,8 +45,8 @@ struct ARegion; typedef struct wmEventHandler { struct wmEventHandler *next, *prev; - int type; /* WM_HANDLER_DEFAULT, ... */ - int flag; /* WM_HANDLER_BLOCKING, ... */ + char type; /* WM_HANDLER_DEFAULT, ... */ + char flag; /* WM_HANDLER_BLOCKING, ... */ /* keymap handler */ wmKeyMap *keymap; /* pointer to builtin/custom keymaps */ @@ -56,6 +56,7 @@ typedef struct wmEventHandler { wmOperator *op; /* for derived/modal handlers */ struct ScrArea *op_area; /* for derived/modal handlers */ struct ARegion *op_region; /* for derived/modal handlers */ + short op_region_type; /* for derived/modal handlers */ /* ui handler */ wmUIHandlerFunc ui_handle; /* callback receiving events */ @@ -76,13 +77,6 @@ enum { WM_HANDLER_FILESELECT }; -/* handler flag */ -enum { - WM_HANDLER_BLOCKING = (1 << 0), /* after this handler all others are ignored */ - WM_HANDLER_DO_FREE = (1 << 1), /* handler tagged to be freed in wm_handlers_do() */ - WM_HANDLER_ACCEPT_DBL_CLICK = (1 << 2), /* handler accepts double key press events */ -}; - /* wm_event_system.c */ void wm_event_free_all (wmWindow *win); void wm_event_free (wmEvent *event); diff --git a/source/blender/windowmanager/wm_window.h b/source/blender/windowmanager/wm_window.h index 833234b0f13..a104f6aba39 100644 --- a/source/blender/windowmanager/wm_window.h +++ b/source/blender/windowmanager/wm_window.h @@ -32,17 +32,18 @@ #ifndef __WM_WINDOW_H__ #define __WM_WINDOW_H__ -struct bScreen; struct wmOperator; /* *************** internal api ************** */ void wm_ghost_init (bContext *C); void wm_ghost_exit(void); -void wm_get_screensize(int *width_r, int *height_r); -void wm_get_desktopsize(int *width_r, int *height_r); +void wm_get_screensize(int *r_width, int *r_height); +void wm_get_desktopsize(int *r_width, int *r_height); wmWindow *wm_window_new (bContext *C); +wmWindow *wm_window_copy (bContext *C, wmWindow *win_src); +wmWindow *wm_window_copy_test (bContext *C, wmWindow *win_src); void wm_window_free (bContext *C, wmWindowManager *wm, wmWindow *win); void wm_window_close (bContext *C, wmWindowManager *wm, wmWindow *win); @@ -56,7 +57,7 @@ void wm_window_make_drawable(wmWindowManager *wm, wmWindow *win); void wm_window_raise (wmWindow *win); void wm_window_lower (wmWindow *win); void wm_window_set_size (wmWindow *win, int width, int height); -void wm_window_get_position (wmWindow *win, int *posx_r, int *posy_r); +void wm_window_get_position (wmWindow *win, int *r_pos_x, int *r_pos_y); void wm_window_swap_buffers (wmWindow *win); void wm_window_set_swap_interval(wmWindow *win, int interval); bool wm_window_get_swap_interval(wmWindow *win, int *intervalOut); @@ -65,8 +66,6 @@ float wm_window_pixelsize(wmWindow *win); void wm_get_cursor_position (wmWindow *win, int *x, int *y); -wmWindow *wm_window_copy (bContext *C, wmWindow *winorig); - void wm_window_testbreak (void); #ifdef WITH_INPUT_IME |