diff options
Diffstat (limited to 'source/blender/windowmanager/intern/wm_window.c')
-rw-r--r-- | source/blender/windowmanager/intern/wm_window.c | 566 |
1 files changed, 479 insertions, 87 deletions
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index 2d7ed9d0295..acc9a500247 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,35 +52,48 @@ #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" #include "wm.h" #include "wm_draw.h" #include "wm_window.h" -#include "wm_subwindow.h" #include "wm_event_system.h" +#include "ED_anim_api.h" +#include "ED_scene.h" #include "ED_screen.h" #include "ED_fileselect.h" #include "UI_interface.h" -#include "UI_resources.h" +#include "UI_interface_icons.h" #include "PIL_time.h" +#include "GPU_batch.h" #include "GPU_draw.h" #include "GPU_extensions.h" +#include "GPU_framebuffer.h" #include "GPU_init_exit.h" -#include "GPU_glew.h" +#include "GPU_immediate.h" +#include "GPU_material.h" +#include "GPU_texture.h" #include "BLF_api.h" +#include "UI_resources.h" + +#include "../../../intern/gawain/gawain/gwn_context.h" + /* for assert */ #ifndef NDEBUG # include "BLI_threads.h" @@ -162,12 +176,23 @@ static void wm_window_check_position(rcti *rect) } -static void wm_ghostwindow_destroy(wmWindow *win) +static void wm_ghostwindow_destroy(wmWindowManager *wm, wmWindow *win) { if (win->ghostwin) { + /* We need this window's opengl context active to discard it. */ + GHOST_ActivateWindowDrawingContext(win->ghostwin); + GWN_context_active_set(win->gwnctx); + + /* Delete local gawain objects. */ + GWN_context_discard(win->gwnctx); + GHOST_DisposeWindow(g_system, win->ghostwin); win->ghostwin = NULL; - win->multisamples = 0; + win->gwnctx = NULL; + + /* prevents non-drawable state of main windows (bugs #22967 and #25071, possibly #22477 too) */ + wm->windrawable = NULL; + wm->winactive = NULL; } } @@ -186,10 +211,7 @@ void wm_window_free(bContext *C, wmWindowManager *wm, wmWindow *win) CTX_wm_window_set(C, NULL); } - /* always set drawable and active to NULL, - * prevents non-drawable state of main windows (bugs #22967 and #25071, possibly #22477 too) */ - wm->windrawable = NULL; - wm->winactive = NULL; + BKE_screen_area_map_free(&win->global_areas); /* end running jobs, a job end also removes its timer */ for (wt = wm->timers.first; wt; wt = wtnext) { @@ -208,12 +230,10 @@ void wm_window_free(bContext *C, wmWindowManager *wm, wmWindow *win) if (win->eventstate) MEM_freeN(win->eventstate); wm_event_free_all(win); - wm_subwindows_free(win); - - wm_draw_data_free(win); - wm_ghostwindow_destroy(win); + wm_ghostwindow_destroy(wm, win); + BKE_workspace_instance_hook_free(G_MAIN, win->workspace_hook); MEM_freeN(win->stereo3d_format); MEM_freeN(win); @@ -234,6 +254,7 @@ 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"); @@ -241,33 +262,50 @@ wmWindow *wm_window_new(bContext *C) 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) { Main *bmain = CTX_data_main(C); 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(bmain, 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->drawmethod = U.wmdrawmethod; - - BLI_listbase_clear(&win_dst->drawdata); + win_dst->scene = scene; + WM_window_set_active_workspace(win_dst, workspace); + layout_new = duplicate_layout ? ED_workspace_layout_duplicate(bmain, workspace, layout_old, win_dst) : layout_old; + WM_window_set_active_layout(win_dst, workspace, layout_new); *win_dst->stereo3d_format = *win_src->stereo3d_format; @@ -278,12 +316,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); @@ -455,7 +493,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; } @@ -463,36 +501,50 @@ void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win) wm_quit_with_optional_confirmation_prompt(C, win); } else { - /* We're just closing a window */ - 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); - CTX_wm_window_set(C, win); /* needed by handlers */ WM_event_remove_handlers(C, &win->handlers); WM_event_remove_handlers(C, &win->modalhandlers); /* 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); + } + + if (tmpwin) { + BLF_batch_reset(); + gpu_batch_presets_reset(); + immDeactivate(); } wm_window_free(C, wm, win); + /* keep imediatemode active before the next `wm_window_make_drawable` call */ + if (tmpwin) { + GHOST_ActivateWindowDrawingContext(tmpwin->ghostwin); + GWN_context_active_set(tmpwin->gwnctx); + immActivate(); + } + /* 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 */ } @@ -556,26 +608,29 @@ void WM_window_set_dpi(wmWindow *win) U.dpi = dpi / pixelsize; U.virtual_pixel = (pixelsize == 1) ? VIRTUAL_PIXEL_NATIVE : VIRTUAL_PIXEL_DOUBLE; U.widget_unit = (U.pixelsize * U.dpi * 20 + 36) / 72; + U.dpi_fac = ((U.pixelsize * (float)U.dpi) / 72.0f); /* update font drawing */ BLF_default_dpi(U.pixelsize * U.dpi); } +static void wm_window_ensure_eventstate(wmWindow *win) +{ + if (win->eventstate) { + return; + } + + win->eventstate = MEM_callocN(sizeof(wmEvent), "window event state"); + wm_get_cursor_position(win, &win->eventstate->x, &win->eventstate->y); +} + /* belongs to below */ static void wm_window_ghostwindow_add(wmWindowManager *wm, const char *title, wmWindow *win) { GHOST_WindowHandle ghostwin; GHOST_GLSettings glSettings = {0}; - static int multisamples = -1; int scr_w, scr_h, posy; - /* force setting multisamples only once, it requires restart - and you cannot - * mix it, either all windows have it, or none (tested in OSX opengl) */ - if (multisamples == -1) - multisamples = U.ogl_multisamples; - - 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; @@ -596,6 +651,13 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm, const char *title, wm if (ghostwin) { GHOST_RectangleHandle bounds; + /* XXX Fix crash when a new window is created. + * However this should be move somewhere else. (fclem) */ + BLF_batch_reset(); + gpu_batch_presets_reset(); + + win->gwnctx = GWN_context_create(); + /* the new window has already been made drawable upon creation */ wm->windrawable = win; @@ -605,11 +667,7 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm, const char *title, wm win->ghostwin = ghostwin; GHOST_SetWindowUserData(ghostwin, win); /* pointer back */ - if (win->eventstate == NULL) - win->eventstate = MEM_callocN(sizeof(wmEvent), "window event state"); - - /* store multisamples window was created with, in case user prefs change */ - win->multisamples = multisamples; + wm_window_ensure_eventstate(win); /* store actual window size in blender window */ bounds = GHOST_GetClientBounds(win->ghostwin); @@ -640,7 +698,6 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm, const char *title, wm //GHOST_SetWindowState(ghostwin, GHOST_kWindowStateModified); /* standard state vars for window */ - glEnable(GL_SCISSOR_TEST); GPU_state_init(); } } @@ -715,8 +772,7 @@ void wm_window_ghostwindows_ensure(wmWindowManager *wm) wm_window_ghostwindow_add(wm, "Blender", win); } /* happens after fileread */ - if (win->eventstate == NULL) - win->eventstate = MEM_callocN(sizeof(wmEvent), "window event state"); + wm_window_ensure_eventstate(win); /* add keymap handlers (1 handler for all keys in map!) */ keymap = WM_keymap_find(wm->defaultconf, "Window", 0, 0); @@ -734,6 +790,11 @@ void wm_window_ghostwindows_ensure(wmWindowManager *wm) WM_event_add_dropbox_handler(&win->handlers, lb); } wm_window_title(wm, win); + + /* add topbar */ + if (BLI_listbase_is_empty(&win->global_areas.areabase)) { + ED_screen_global_areas_create(win); + } } } @@ -771,8 +832,6 @@ wmWindow *WM_window_open(bContext *C, const rcti *rect) win->sizex = BLI_rcti_size_x(rect); win->sizey = BLI_rcti_size_y(rect); - win->drawmethod = U.wmdrawmethod; - WM_check(C); if (win->ghostwin) { @@ -797,6 +856,7 @@ wmWindow *WM_window_open_temp(bContext *C, int x, int y, int sizex, int sizey, i 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; @@ -820,7 +880,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? */ @@ -831,6 +891,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); @@ -839,17 +901,29 @@ wmWindow *WM_window_open_temp(bContext *C, int x, int y, int sizex, int sizey, i wm_window_raise(win); } - if (win->screen == NULL) { - /* add new screen */ - win->screen = ED_screen_add(bmain, 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(bmain, workspace, win, "temp"); + + screen = BKE_workspace_layout_screen_get(layout); + WM_window_set_active_layout(win, workspace, layout); } - win->screen->temp = 1; + if (win->scene == NULL) { + win->scene = scene; + } + /* In case we reuse an already existing temp window (see win lookup above). */ + else 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); @@ -862,25 +936,35 @@ 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) { ED_area_newspace(C, sa, SPACE_IMAGE, false); } + else if (type == WM_WINDOW_DRIVERS) { + ED_area_newspace(C, sa, SPACE_IPO, false); + } else { 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 */ + /* do additional setup for specific editor type */ + if (type == WM_WINDOW_DRIVERS) { + ED_drivers_editor_init(C, sa); + } + if (sa->spacetype == SPACE_IMAGE) title = IFACE_("Blender Render"); else if (ELEM(sa->spacetype, SPACE_OUTLINER, SPACE_USERPREF)) title = IFACE_("Blender User Preferences"); else if (sa->spacetype == SPACE_FILE) title = IFACE_("Blender File View"); + else if (sa->spacetype == SPACE_IPO) + title = IFACE_("Blender Drivers Editor"); else title = "Blender"; @@ -908,17 +992,109 @@ 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) { + Main *bmain = CTX_data_main(C); 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(bmain, 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_at_most(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)) @@ -1011,6 +1187,8 @@ static int query_qual(modifierKeyType qual) void wm_window_make_drawable(wmWindowManager *wm, wmWindow *win) { + BLI_assert(GPU_framebuffer_current_get() == 0); + if (win != wm->windrawable && win->ghostwin) { // win->lmbut = 0; /* keeps hanging when mousepressed while other window opened */ @@ -1018,13 +1196,41 @@ void wm_window_make_drawable(wmWindowManager *wm, wmWindow *win) if (G.debug & G_DEBUG_EVENTS) { printf("%s: set drawable %d\n", __func__, win->winid); } + + BLF_batch_reset(); + gpu_batch_presets_reset(); + immDeactivate(); GHOST_ActivateWindowDrawingContext(win->ghostwin); + GWN_context_active_set(win->gwnctx); + immActivate(); /* this can change per window */ WM_window_set_dpi(win); } } +/* Reset active the current window opengl drawing context. */ +void wm_window_reset_drawable(void) +{ + BLI_assert(BLI_thread_is_main()); + BLI_assert(GPU_framebuffer_current_get() == 0); + wmWindowManager *wm = G_MAIN->wm.first; + + if (wm == NULL) + return; + + wmWindow *win = wm->windrawable; + + if (win && win->ghostwin) { + BLF_batch_reset(); + gpu_batch_presets_reset(); + immDeactivate(); + GHOST_ActivateWindowDrawingContext(win->ghostwin); + GWN_context_active_set(win->gwnctx); + immActivate(); + } +} + /* called by ghost, here we handle events for windows themselves or send to event system */ /* mouse coordinate converversion happens here */ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr) @@ -1044,7 +1250,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) { @@ -1218,7 +1424,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); @@ -1253,6 +1459,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; @@ -1288,7 +1496,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); @@ -1400,6 +1608,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); @@ -1408,7 +1618,6 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr CTX_wm_window_set(C, oldWindow); wm_window_make_drawable(wm, win); - wm_draw_window_clear(win); WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL); WM_event_add_notifier(C, NC_WINDOW | NA_EDITED, NULL); @@ -1539,13 +1748,22 @@ void wm_window_testbreak(void) /* **************** init ********************** */ +/* bContext can be null in background mode because we don't + * need to event handling. */ void wm_ghost_init(bContext *C) { if (!g_system) { - GHOST_EventConsumerHandle consumer = GHOST_CreateEventConsumer(ghost_event_proc, C); + GHOST_EventConsumerHandle consumer; + + if (C != NULL) { + consumer = GHOST_CreateEventConsumer(ghost_event_proc, C); + } g_system = GHOST_CreateSystem(); - GHOST_AddEventConsumer(g_system, consumer); + + if (C != NULL) { + GHOST_AddEventConsumer(g_system, consumer); + } if (wm_init_state.native_pixels) { GHOST_UseNativePixels(); @@ -1789,14 +2007,9 @@ void wm_window_raise(wmWindow *win) void wm_window_swap_buffers(wmWindow *win) { - -#ifdef WIN32 - glDisable(GL_SCISSOR_TEST); + GPU_texture_orphans_delete(); /* XXX should be done elsewhere. */ + GPU_material_orphans_delete(); /* XXX Amen to that. */ GHOST_SwapWindowBuffers(win->ghostwin); - glEnable(GL_SCISSOR_TEST); -#else - GHOST_SwapWindowBuffers(win->ghostwin); -#endif } void wm_window_set_swap_interval (wmWindow *win, int interval) @@ -1887,19 +2100,58 @@ float WM_cursor_pressure(const struct wmWindow *win) /* support for native pixel size */ /* mac retina opens window in size X, but it has up to 2 x more pixels */ -int WM_window_pixels_x(wmWindow *win) +int WM_window_pixels_x(const wmWindow *win) { float f = GHOST_GetNativePixelSize(win->ghostwin); return (int)(f * (float)win->sizex); } - -int WM_window_pixels_y(wmWindow *win) +int WM_window_pixels_y(const wmWindow *win) { float f = GHOST_GetNativePixelSize(win->ghostwin); return (int)(f * (float)win->sizey); +} +/** + * Get boundaries usable by all window contents, including global areas. + */ +void WM_window_rect_calc(const wmWindow *win, rcti *r_rect) +{ + BLI_rcti_init(r_rect, 0, WM_window_pixels_x(win), 0, WM_window_pixels_y(win)); +} +/** + * Get boundaries usable by screen-layouts, excluding global areas. + * \note Depends on U.dpi_fac. Should that be outdated, call #WM_window_set_dpi first. + */ +void WM_window_screen_rect_calc(const wmWindow *win, rcti *r_rect) +{ + rcti rect; + + BLI_rcti_init(&rect, 0, WM_window_pixels_x(win), 0, WM_window_pixels_y(win)); + + /* Substract global areas from screen rectangle. */ + for (ScrArea *global_area = win->global_areas.areabase.first; global_area; global_area = global_area->next) { + if (global_area->global->flag & GLOBAL_AREA_IS_HIDDEN) { + continue; + } + + switch (global_area->global->align) { + case GLOBAL_AREA_ALIGN_TOP: + rect.ymax -= ED_area_global_size_y(global_area); + break; + case GLOBAL_AREA_ALIGN_BOTTOM: + rect.ymin += ED_area_global_size_y(global_area); + break; + default: + BLI_assert(0); + break; + } + } + + BLI_assert(rect.xmin < rect.xmax); + BLI_assert(rect.ymin < rect.ymax); + *r_rect = rect; } bool WM_window_is_fullscreen(wmWindow *win) @@ -1907,6 +2159,115 @@ 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); + Scene *scene_old = win->scene; + + ED_scene_change_update(bmain, C, win, screen, scene_old, scene_new); +} + +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); +} + +struct ViewLayer *WM_window_get_active_view_layer_ex(const wmWindow *win, Scene **r_scene) +{ + const WorkSpace *workspace = WM_window_get_active_workspace(win); + Scene *scene = WM_window_get_active_scene(win); + /* May be NULL in rare cases like closing Blender */ + bScreen *screen = (LIKELY(workspace != NULL) ? BKE_workspace_active_screen_get(win->workspace_hook) : NULL); + if (screen != NULL) { + if (r_scene) { + *r_scene = scene; + } + return BKE_workspace_view_layer_get(workspace, scene); + } + return NULL; +} + +struct ViewLayer *WM_window_get_active_view_layer(const wmWindow *win) +{ + return WM_window_get_active_view_layer_ex(win, NULL); +} + +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 */ @@ -1925,3 +2286,34 @@ void wm_window_IME_end(wmWindow *win) win->ime_data = NULL; } #endif /* WITH_INPUT_IME */ + +/* ****** direct opengl context management ****** */ + +void *WM_opengl_context_create(void) +{ + /* On Windows there is a problem creating contexts that share lists + * from one context that is current in another thread. + * So we should call this function only on the main thread. + */ + BLI_assert(BLI_thread_is_main()); + BLI_assert(GPU_framebuffer_current_get() == 0); + return GHOST_CreateOpenGLContext(g_system); +} + +void WM_opengl_context_dispose(void *context) +{ + BLI_assert(GPU_framebuffer_current_get() == 0); + GHOST_DisposeOpenGLContext(g_system, (GHOST_ContextHandle)context); +} + +void WM_opengl_context_activate(void *context) +{ + BLI_assert(GPU_framebuffer_current_get() == 0); + GHOST_ActivateOpenGLContext((GHOST_ContextHandle)context); +} + +void WM_opengl_context_release(void *context) +{ + BLI_assert(GPU_framebuffer_current_get() == 0); + GHOST_ReleaseOpenGLContext((GHOST_ContextHandle)context); +} |