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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/windowmanager/intern/wm_window.c')
-rw-r--r--source/blender/windowmanager/intern/wm_window.c322
1 files changed, 279 insertions, 43 deletions
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c
index 79078b321da..0e07b66996d 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 "RNA_enum_types.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,57 @@ 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;
+
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);
win_dst->drawmethod = U.wmdrawmethod;
@@ -276,12 +308,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 +337,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 +356,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 +370,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 +379,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 +694,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 +721,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 +732,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 +741,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 +773,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 +783,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 +819,107 @@ 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;
- ok = (wm_window_copy_test(C, win_src) != NULL);
+ 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 ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+ return (win_dst != NULL) ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
+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);
+
+ 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);
+ }
+}
+
+const EnumPropertyItem *wm_window_new_screen_itemf(
+ bContext *C, struct PointerRNA *UNUSED(ptr), struct PropertyRNA *UNUSED(prop), bool *r_free)
+{
+ if (C == NULL) {
+ return DummyRNA_NULL_items;
+ }
+ 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);
}
@@ -907,7 +1048,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
/* Ghost now can call this function for life resizes, but it should return if WM didn't initialize yet.
* Can happen on file read (especially full size window) */
- if ((wm->initialized & WM_INIT_WINDOW) == 0) {
+ if ((wm->initialized & WM_WINDOW_IS_INITIALIZED) == 0) {
return 1;
}
if (!ghostwin) {
@@ -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,96 @@ 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;
+}
+
+WorkSpace *WM_windows_workspace_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_workspace(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 */