diff options
Diffstat (limited to 'source/blender/windowmanager/intern/wm_window.c')
-rw-r--r-- | source/blender/windowmanager/intern/wm_window.c | 308 |
1 files changed, 267 insertions, 41 deletions
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index 79078b321da..09b2b50687a 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -38,6 +38,7 @@ #include "DNA_listBase.h" #include "DNA_screen_types.h" #include "DNA_windowmanager_types.h" +#include "DNA_workspace_types.h" #include "MEM_guardedalloc.h" @@ -51,12 +52,16 @@ #include "BKE_blender.h" #include "BKE_context.h" +#include "BKE_icons.h" #include "BKE_library.h" #include "BKE_global.h" #include "BKE_main.h" +#include "BKE_screen.h" +#include "BKE_workspace.h" #include "RNA_access.h" +#include "RNA_define.h" #include "WM_api.h" #include "WM_types.h" @@ -66,19 +71,23 @@ #include "wm_subwindow.h" #include "wm_event_system.h" +#include "ED_scene.h" #include "ED_screen.h" #include "ED_fileselect.h" #include "UI_interface.h" +#include "UI_interface_icons.h" #include "PIL_time.h" #include "GPU_draw.h" #include "GPU_extensions.h" #include "GPU_init_exit.h" -#include "GPU_glew.h" +#include "GPU_immediate.h" #include "BLF_api.h" +#include "UI_resources.h" + /* for assert */ #ifndef NDEBUG # include "BLI_threads.h" @@ -213,6 +222,7 @@ void wm_window_free(bContext *C, wmWindowManager *wm, wmWindow *win) wm_ghostwindow_destroy(win); + BKE_workspace_instance_hook_free(G.main, win->workspace_hook); MEM_freeN(win->stereo3d_format); MEM_freeN(win); @@ -233,35 +243,60 @@ static int find_free_winid(wmWindowManager *wm) /* don't change context itself */ wmWindow *wm_window_new(bContext *C) { + Main *bmain = CTX_data_main(C); wmWindowManager *wm = CTX_wm_manager(C); wmWindow *win = MEM_callocN(sizeof(wmWindow), "window"); - + BLI_addtail(&wm->windows, win); win->winid = find_free_winid(wm); win->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Stereo 3D Format (window)"); + win->workspace_hook = BKE_workspace_instance_hook_create(bmain); return win; } +/** + * A higher level version of copy that tests the new window can be added. + */ +static wmWindow *wm_window_new_test(bContext *C) +{ + wmWindow *win = wm_window_new(C); + + WM_check(C); + + if (win->ghostwin) { + WM_event_add_notifier(C, NC_WINDOW | NA_ADDED, NULL); + return win; + } + else { + wmWindowManager *wm = CTX_wm_manager(C); + wm_window_close(C, wm, win); + return NULL; + } +} /* part of wm_window.c api */ -wmWindow *wm_window_copy(bContext *C, wmWindow *win_src) +wmWindow *wm_window_copy(bContext *C, wmWindow *win_src, const bool duplicate_layout) { wmWindow *win_dst = wm_window_new(C); - + WorkSpace *workspace = WM_window_get_active_workspace(win_src); + WorkSpaceLayout *layout_old = WM_window_get_active_layout(win_src); + Scene *scene = WM_window_get_active_scene(win_src); + WorkSpaceLayout *layout_new; + bScreen *new_screen; + 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_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_dst->screen->do_refresh = true; - win_dst->screen->do_draw = true; + win_dst->scene = scene; + WM_window_set_active_workspace(win_dst, workspace); + layout_new = duplicate_layout ? ED_workspace_layout_duplicate(workspace, layout_old, win_dst) : layout_old; + WM_window_set_active_layout(win_dst, workspace, layout_new); + new_screen = WM_window_get_active_screen(win_dst); + BLI_strncpy(win_dst->screenname, new_screen->id.name + 2, sizeof(win_dst->screenname)); win_dst->drawmethod = U.wmdrawmethod; @@ -276,12 +311,12 @@ wmWindow *wm_window_copy(bContext *C, wmWindow *win_src) * 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) +wmWindow *wm_window_copy_test(bContext *C, wmWindow *win_src, const bool duplicate_layout) { wmWindowManager *wm = CTX_wm_manager(C); wmWindow *win_dst; - win_dst = wm_window_copy(C, win_src); + win_dst = wm_window_copy(C, win_src, duplicate_layout); WM_check(C); @@ -305,7 +340,7 @@ void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win) for (tmpwin = wm->windows.first; tmpwin; tmpwin = tmpwin->next) { if (tmpwin == win) continue; - if (tmpwin->screen->temp == 0) + if (WM_window_is_temp_screen(tmpwin) == false) break; } @@ -324,8 +359,10 @@ void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win) WM_exit(C); } else { - bScreen *screen = win->screen; - + bScreen *screen = WM_window_get_active_screen(win); + WorkSpace *workspace = WM_window_get_active_workspace(win); + WorkSpaceLayout *layout = BKE_workspace_active_layout_get(win->workspace_hook); + BLI_remlink(&wm->windows, win); wm_draw_window_clear(win); @@ -336,8 +373,8 @@ void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win) /* for regular use this will _never_ be NULL, * however we may be freeing an improperly initialized window. */ - if (win->screen) { - ED_screen_exit(C, win, win->screen); + if (screen) { + ED_screen_exit(C, win, screen); } wm_window_free(C, wm, win); @@ -345,14 +382,16 @@ void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win) /* if temp screen, delete it after window free (it stops jobs that can access it) */ if (screen && screen->temp) { Main *bmain = CTX_data_main(C); - BKE_libblock_free(bmain, screen); + + BLI_assert(BKE_workspace_layout_screen_get(layout) == screen); + BKE_workspace_layout_remove(bmain, workspace, layout); } - } + } } void wm_window_title(wmWindowManager *wm, wmWindow *win) { - if (win->screen && win->screen->temp) { + if (WM_window_is_temp_screen(win)) { /* nothing to do for 'temp' windows, * because WM_window_open_temp always sets window title */ } @@ -658,8 +697,10 @@ wmWindow *WM_window_open(bContext *C, const rcti *rect) */ wmWindow *WM_window_open_temp(bContext *C, int x, int y, int sizex, int sizey, int type) { + Main *bmain = CTX_data_main(C); wmWindow *win_prev = CTX_wm_window(C); wmWindow *win; + bScreen *screen; ScrArea *sa; Scene *scene = CTX_data_scene(C); const char *title; @@ -683,7 +724,7 @@ wmWindow *WM_window_open_temp(bContext *C, int x, int y, int sizex, int sizey, i /* test if we have a temp screen already */ for (win = CTX_wm_manager(C)->windows.first; win; win = win->next) - if (win->screen->temp) + if (WM_window_is_temp_screen(win)) break; /* add new window? */ @@ -694,6 +735,8 @@ wmWindow *WM_window_open_temp(bContext *C, int x, int y, int sizex, int sizey, i win->posy = rect.ymin; } + screen = WM_window_get_active_screen(win); + win->sizex = BLI_rcti_size_x(&rect); win->sizey = BLI_rcti_size_y(&rect); @@ -701,19 +744,27 @@ wmWindow *WM_window_open_temp(bContext *C, int x, int y, int sizex, int sizey, i wm_window_set_size(win, win->sizex, win->sizey); wm_window_raise(win); } - - if (win->screen == NULL) { - /* add new screen */ - win->screen = ED_screen_add(win, scene, "temp"); + + if (WM_window_get_active_workspace(win) == NULL) { + WorkSpace *workspace = WM_window_get_active_workspace(win_prev); + WM_window_set_active_workspace(win, workspace); } - else { - /* switch scene for rendering */ - if (win->screen->scene != scene) - ED_screen_set_scene(C, win->screen, scene); + + if (screen == NULL) { + /* add new screen layout */ + WorkSpace *workspace = WM_window_get_active_workspace(win); + WorkSpaceLayout *layout = ED_workspace_layout_add(workspace, win, "temp"); + + screen = BKE_workspace_layout_screen_get(layout); + WM_window_set_active_layout(win, workspace, layout); } - win->screen->temp = 1; - + if (WM_window_get_active_scene(win) != scene) { + WM_window_change_active_scene(bmain, C, win, scene); + } + + screen->temp = 1; + /* make window active, and validate/resize */ CTX_wm_window_set(C, win); WM_check(C); @@ -725,7 +776,7 @@ wmWindow *WM_window_open_temp(bContext *C, int x, int y, int sizex, int sizey, i */ /* ensure it shows the right spacetype editor */ - sa = win->screen->areabase.first; + sa = screen->areabase.first; CTX_wm_area_set(C, sa); if (type == WM_WINDOW_RENDER) { @@ -735,7 +786,7 @@ wmWindow *WM_window_open_temp(bContext *C, int x, int y, int sizex, int sizey, i ED_area_newspace(C, sa, SPACE_USERPREF, false); } - ED_screen_set(C, win->screen); + ED_screen_change(C, screen); ED_screen_refresh(CTX_wm_manager(C), win); /* test scale */ if (sa->spacetype == SPACE_IMAGE) @@ -771,17 +822,104 @@ int wm_window_close_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_FINISHED; } -/* operator callback */ -int wm_window_duplicate_exec(bContext *C, wmOperator *UNUSED(op)) +static WorkSpaceLayout *wm_window_new_find_layout(wmOperator *op, WorkSpace *workspace) +{ + ListBase *listbase = BKE_workspace_layouts_get(workspace); + const int layout_id = RNA_enum_get(op->ptr, "screen"); + int i = 0; + + for (WorkSpaceLayout *layout = listbase->first; layout; layout = layout->next) { + if (i++ == layout_id) { + return layout; + } + } + + BLI_assert(0); + return NULL; +} + +/* new window operator callback */ +int wm_window_new_exec(bContext *C, wmOperator *op) { wmWindow *win_src = CTX_wm_window(C); - bool ok; + WorkSpace *workspace = WM_window_get_active_workspace(win_src); + WorkSpaceLayout *layout_new = wm_window_new_find_layout(op, workspace); + bScreen *screen_new = BKE_workspace_layout_screen_get(layout_new); + wmWindow *win_dst; + + if ((win_dst = wm_window_new_test(C))) { + if (screen_new->winid) { + /* layout/screen is already used, duplicate it */ + layout_new = ED_workspace_layout_duplicate(workspace, layout_new, win_dst); + screen_new = BKE_workspace_layout_screen_get(layout_new); + } + /* New window with a different screen but same workspace */ + WM_window_set_active_workspace(win_dst, workspace); + WM_window_set_active_screen(win_dst, workspace, screen_new); + win_dst->scene = win_src->scene; + screen_new->winid = win_dst->winid; + CTX_wm_window_set(C, win_dst); + ED_screen_refresh(CTX_wm_manager(C), win_dst); + } + + return (win_dst != NULL) ? OPERATOR_FINISHED : OPERATOR_CANCELLED; +} - ok = (wm_window_copy_test(C, win_src) != NULL); +int wm_window_new_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + wmWindow *win = CTX_wm_window(C); + WorkSpace *workspace = WM_window_get_active_workspace(win); + ListBase *listbase = BKE_workspace_layouts_get(workspace); - return ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED; + if (BLI_listbase_count_ex(listbase, 2) == 1) { + RNA_enum_set(op->ptr, "screen", 0); + return wm_window_new_exec(C, op); + } + else { + return WM_enum_search_invoke_previews(C, op, 6, 2); + } } +struct EnumPropertyItem *wm_window_new_screen_itemf( + bContext *C, struct PointerRNA *UNUSED(ptr), struct PropertyRNA *UNUSED(prop), bool *r_free) +{ + wmWindow *win = CTX_wm_window(C); + WorkSpace *workspace = WM_window_get_active_workspace(win); + ListBase *listbase = BKE_workspace_layouts_get(workspace); + EnumPropertyItem *item = NULL; + EnumPropertyItem tmp = {0, "", 0, "", ""}; + int value = 0, totitem = 0; + int count_act_screens = 0; + /* XXX setting max number of windows to 20. We'd need support + * for dynamic strings in EnumPropertyItem.name to avoid this. */ + static char active_screens[20][MAX_NAME + 12]; + + for (WorkSpaceLayout *layout = listbase->first; layout; layout = layout->next) { + bScreen *screen = BKE_workspace_layout_screen_get(layout); + const char *layout_name = BKE_workspace_layout_name_get(layout); + + if (screen->winid) { + BLI_snprintf(active_screens[count_act_screens], sizeof(*active_screens), "%s (Duplicate)", layout_name); + tmp.name = active_screens[count_act_screens++]; + } + else { + tmp.name = layout_name; + } + + tmp.value = value; + tmp.identifier = layout_name; + UI_id_icon_render(C, CTX_data_scene(C), &screen->id, true, false); + tmp.icon = BKE_icon_id_ensure(&screen->id); + + RNA_enum_item_add(&item, &totitem, &tmp); + value++; + } + + RNA_enum_item_end(&item, &totitem); + *r_free = true; + + return item; +} /* fullscreen operator callback */ int wm_window_fullscreen_toggle_exec(bContext *C, wmOperator *UNUSED(op)) @@ -881,8 +1019,11 @@ void wm_window_make_drawable(wmWindowManager *wm, wmWindow *win) if (G.debug & G_DEBUG_EVENTS) { printf("%s: set drawable %d\n", __func__, win->winid); } + + immDeactivate(); GHOST_ActivateWindowDrawingContext(win->ghostwin); - + immActivate(); + /* this can change per window */ WM_window_set_dpi(win); } @@ -1081,7 +1222,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr /* stop screencast if resize */ if (type == GHOST_kEventWindowSize) { - WM_jobs_stop(wm, win->screen, NULL); + WM_jobs_stop(wm, WM_window_get_active_screen(win), NULL); } WM_window_set_dpi(win); @@ -1116,6 +1257,8 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr win->posx != posx || win->posy != posy) { + const bScreen *screen = WM_window_get_active_screen(win); + win->sizex = sizex; win->sizey = sizey; win->posx = posx; @@ -1152,6 +1295,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr wm_window_make_drawable(wm, win); wm_draw_window_clear(win); + BKE_icon_changed(screen->id.icon_id); WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL); WM_event_add_notifier(C, NC_WINDOW | NA_EDITED, NULL); @@ -1263,6 +1407,8 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr WM_window_set_dpi(win); if (U.pixelsize != prev_pixelsize) { + BKE_icon_changed(WM_window_get_active_screen(win)->id.icon_id); + // close all popups since they are positioned with the pixel // size baked in and it's difficult to correct them wmWindow *oldWindow = CTX_wm_window(C); @@ -1768,6 +1914,86 @@ bool WM_window_is_fullscreen(wmWindow *win) return win->windowstate == GHOST_kWindowStateFullScreen; } +/** + * Some editor data may need to be synced with scene data (3D View camera and layers). + * This function ensures data is synced for editors in visible workspaces and their visible layouts. + */ +void WM_windows_scene_data_sync(const ListBase *win_lb, Scene *scene) +{ + for (wmWindow *win = win_lb->first; win; win = win->next) { + if (WM_window_get_active_scene(win) == scene) { + ED_workspace_scene_data_sync(win->workspace_hook, scene); + } + } +} + +Scene *WM_windows_scene_get_from_screen(const wmWindowManager *wm, const bScreen *screen) +{ + for (wmWindow *win = wm->windows.first; win; win = win->next) { + if (WM_window_get_active_screen(win) == screen) { + return WM_window_get_active_scene(win); + } + } + + return NULL; +} + +Scene *WM_window_get_active_scene(const wmWindow *win) +{ + return win->scene; +} + +/** + * \warning Only call outside of area/region loops + */ +void WM_window_change_active_scene(Main *bmain, bContext *C, wmWindow *win, Scene *scene_new) +{ + const bScreen *screen = WM_window_get_active_screen(win); + + ED_scene_exit(C); + win->scene = scene_new; + ED_scene_changed_update(bmain, C, scene_new, screen); +} + +WorkSpace *WM_window_get_active_workspace(const wmWindow *win) +{ + return BKE_workspace_active_get(win->workspace_hook); +} +void WM_window_set_active_workspace(wmWindow *win, WorkSpace *workspace) +{ + BKE_workspace_active_set(win->workspace_hook, workspace); +} + +WorkSpaceLayout *WM_window_get_active_layout(const wmWindow *win) +{ + const WorkSpace *workspace = WM_window_get_active_workspace(win); + return (LIKELY(workspace != NULL) ? BKE_workspace_active_layout_get(win->workspace_hook) : NULL); +} +void WM_window_set_active_layout(wmWindow *win, WorkSpace *workspace, WorkSpaceLayout *layout) +{ + BKE_workspace_hook_layout_for_workspace_set(win->workspace_hook, workspace, layout); +} + +/** + * Get the active screen of the active workspace in \a win. + */ +bScreen *WM_window_get_active_screen(const wmWindow *win) +{ + const WorkSpace *workspace = WM_window_get_active_workspace(win); + /* May be NULL in rare cases like closing Blender */ + return (LIKELY(workspace != NULL) ? BKE_workspace_active_screen_get(win->workspace_hook) : NULL); +} +void WM_window_set_active_screen(wmWindow *win, WorkSpace *workspace, bScreen *screen) +{ + BKE_workspace_active_screen_set(win->workspace_hook, workspace, screen); +} + +bool WM_window_is_temp_screen(const wmWindow *win) +{ + const bScreen *screen = WM_window_get_active_screen(win); + return (screen && screen->temp != 0); +} + #ifdef WITH_INPUT_IME /* note: keep in mind wm_window_IME_begin is also used to reposition the IME window */ |