diff options
Diffstat (limited to 'source/blender/windowmanager/intern/wm_window.c')
-rw-r--r-- | source/blender/windowmanager/intern/wm_window.c | 244 |
1 files changed, 189 insertions, 55 deletions
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index 3ff323862b3..66df41e5b84 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" @@ -55,6 +56,8 @@ #include "BKE_library.h" #include "BKE_global.h" #include "BKE_main.h" +#include "BKE_screen.h" +#include "BKE_workspace.h" #include "RNA_access.h" @@ -68,6 +71,7 @@ #include "wm_subwindow.h" #include "wm_event_system.h" +#include "ED_scene.h" #include "ED_screen.h" #include "ED_fileselect.h" @@ -218,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); @@ -238,13 +243,15 @@ 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; } @@ -270,22 +277,26 @@ static wmWindow *wm_window_new_test(bContext *C) } /* 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; @@ -300,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); @@ -329,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; } @@ -348,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); @@ -360,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); @@ -369,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 */ } @@ -668,8 +683,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; @@ -693,7 +710,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? */ @@ -704,6 +721,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); @@ -711,19 +730,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); @@ -735,7 +762,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) { @@ -745,7 +772,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) @@ -781,23 +808,42 @@ int wm_window_close_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_FINISHED; } +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) { - Main *bmain = CTX_data_main(C); wmWindow *win_src = CTX_wm_window(C); - const int screen_id = RNA_enum_get(op->ptr, "screen"); - bScreen *screen = BLI_findlink(&bmain->screen, screen_id); + 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 (screen->winid) { - /* Screen is already used, duplicate window and screen */ - win_dst = wm_window_copy_test(C, win_src); - } - else if ((win_dst = wm_window_new_test(C))) { - /* New window with a different screen */ - win_dst->screen = screen; - screen->winid = win_dst->winid; + 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); } @@ -807,9 +853,11 @@ int wm_window_new_exec(bContext *C, wmOperator *op) int wm_window_new_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - Main *bmain = CTX_data_main(C); + wmWindow *win = CTX_wm_window(C); + WorkSpace *workspace = WM_window_get_active_workspace(win); + ListBase *listbase = BKE_workspace_layouts_get(workspace); - if (BLI_listbase_count_ex(&bmain->screen, 2) == 1) { + if (BLI_listbase_count_ex(listbase, 2) == 1) { RNA_enum_set(op->ptr, "screen", 0); return wm_window_new_exec(C, op); } @@ -821,7 +869,9 @@ int wm_window_new_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(even struct EnumPropertyItem *wm_window_new_screen_itemf( bContext *C, struct PointerRNA *UNUSED(ptr), struct PropertyRNA *UNUSED(prop), bool *r_free) { - Main *bmain = CTX_data_main(C); + 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; @@ -830,18 +880,20 @@ struct EnumPropertyItem *wm_window_new_screen_itemf( * for dynamic strings in EnumPropertyItem.name to avoid this. */ static char active_screens[20][MAX_NAME + 12]; - for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) { + 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)", - screen->id.name + 2); + BLI_snprintf(active_screens[count_act_screens], sizeof(*active_screens), "%s (Duplicate)", layout_name); tmp.name = active_screens[count_act_screens++]; } else { - tmp.name = screen->id.name + 2; + tmp.name = layout_name; } tmp.value = value; - tmp.identifier = screen->id.name; + 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); @@ -1156,7 +1208,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); @@ -1191,6 +1243,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; @@ -1227,7 +1281,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(win->screen->id.icon_id); + 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); @@ -1340,7 +1394,7 @@ 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(win->screen->id.icon_id); + 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 @@ -1847,6 +1901,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 */ |