Changeset View
Changeset View
Standalone View
Standalone View
source/blender/windowmanager/intern/wm_window.c
| Show First 20 Lines • Show All 291 Lines • ▼ Show 20 Lines | else { | ||||
| wm_window_close(C, wm, win_dst); | wm_window_close(C, wm, win_dst); | ||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| } | } | ||||
| /* this is event from ghost, or exit-blender op */ | /* this is event from ghost, or exit-blender op */ | ||||
| void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win) | void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win) | ||||
| { | { | ||||
| wmWindow *tmpwin; | wmWindow *normal_win; | ||||
| bool do_exit = false; | bool do_exit = false; | ||||
| /* first check if we have to quit (there are non-temp remaining windows) */ | /* first check if we have to quit (there are no normal windows remaining) */ | ||||
| for (tmpwin = wm->windows.first; tmpwin; tmpwin = tmpwin->next) { | for (normal_win = wm->windows.first; normal_win; normal_win = normal_win->next) { | ||||
| if (tmpwin == win) | if (normal_win == win) | ||||
| continue; | continue; | ||||
| if (tmpwin->screen->temp == 0) | if (normal_win->screen->type == SCREEN_TYPE_NORMAL) | ||||
| break; | break; | ||||
| } | } | ||||
| if (tmpwin == NULL) | if (normal_win == NULL) | ||||
| do_exit = 1; | do_exit = 1; | ||||
| if ((U.uiflag & USER_QUIT_PROMPT) && !wm->file_saved) { | if ((U.uiflag & USER_QUIT_PROMPT) && !wm->file_saved) { | ||||
| if (do_exit) { | if (do_exit) { | ||||
| if (!GHOST_confirmQuit(win->ghostwin)) | if (!GHOST_confirmQuit(win->ghostwin)) | ||||
| return; | return; | ||||
| } | } | ||||
| } | } | ||||
| Show All 13 Lines | else { | ||||
| WM_event_remove_handlers(C, &win->handlers); | WM_event_remove_handlers(C, &win->handlers); | ||||
| WM_event_remove_handlers(C, &win->modalhandlers); | WM_event_remove_handlers(C, &win->modalhandlers); | ||||
| /* for regular use this will _never_ be NULL, | /* for regular use this will _never_ be NULL, | ||||
| * however we may be freeing an improperly initialized window. */ | * however we may be freeing an improperly initialized window. */ | ||||
| if (win->screen) { | if (win->screen) { | ||||
| ED_screen_exit(C, win, win->screen); | ED_screen_exit(C, win, win->screen); | ||||
| } | } | ||||
| #ifdef WITH_INPUT_HMD | |||||
| if (wm->hmd_view.hmd_win == win) { | |||||
| wm->hmd_view.hmd_win = NULL; | |||||
| } | |||||
| #endif | |||||
| wm_window_free(C, wm, win); | wm_window_free(C, wm, win); | ||||
| /* if temp screen, delete it after window free (it stops jobs that can access it) */ | /* if temp screen, delete it after window free (it stops jobs that can access it) */ | ||||
| if (screen && screen->temp) { | if (screen && screen->type == SCREEN_TYPE_TEMP) { | ||||
| Main *bmain = CTX_data_main(C); | Main *bmain = CTX_data_main(C); | ||||
| BKE_libblock_free(bmain, screen); | BKE_libblock_free(bmain, screen); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| void wm_window_title(wmWindowManager *wm, wmWindow *win) | /** | ||||
| * Set window title to \a title if it's non-NULL, else to autogenerated string. | |||||
| */ | |||||
| void wm_window_title(wmWindowManager *wm, wmWindow *win, const char *title) | |||||
| { | { | ||||
| if (win->screen && win->screen->temp) { | if (win->screen && ELEM(win->screen->type, SCREEN_TYPE_TEMP, SCREEN_TYPE_RESTRICTED)) { | ||||
| /* nothing to do for 'temp' windows, | /* nothing to do for temporary or restricted windows, | ||||
| * because WM_window_open_temp always sets window title */ | * because WM_window_open_temp/WM_window_open_restricted always sets window title */ | ||||
| } | } | ||||
| else if (win->ghostwin) { | else if (win->ghostwin) { | ||||
| if (title) { | |||||
| GHOST_SetTitle(win->ghostwin, title); | |||||
| } | |||||
| /* this is set to 1 if you don't have startup.blend open */ | /* this is set to 1 if you don't have startup.blend open */ | ||||
| if (G.save_over && G.main->name[0]) { | else if (G.save_over && G.main->name[0]) { | ||||
| char str[sizeof(G.main->name) + 24]; | char str[sizeof(G.main->name) + 24]; | ||||
| BLI_snprintf(str, sizeof(str), "Blender%s [%s%s]", wm->file_saved ? "" : "*", G.main->name, | BLI_snprintf(str, sizeof(str), "Blender%s [%s%s]", wm->file_saved ? "" : "*", G.main->name, | ||||
| G.main->recovered ? " (Recovered)" : ""); | G.main->recovered ? " (Recovered)" : ""); | ||||
| GHOST_SetTitle(win->ghostwin, str); | GHOST_SetTitle(win->ghostwin, str); | ||||
| } | } | ||||
| else | else | ||||
| GHOST_SetTitle(win->ghostwin, "Blender"); | GHOST_SetTitle(win->ghostwin, "Blender"); | ||||
| ▲ Show 20 Lines • Show All 170 Lines • ▼ Show 20 Lines | if (win->ghostwin == NULL) { | ||||
| } | } | ||||
| wm_window_ghostwindow_add(wm, "Blender", win); | wm_window_ghostwindow_add(wm, "Blender", win); | ||||
| } | } | ||||
| /* happens after fileread */ | /* happens after fileread */ | ||||
| if (win->eventstate == NULL) | if (win->eventstate == NULL) | ||||
| win->eventstate = MEM_callocN(sizeof(wmEvent), "window event state"); | win->eventstate = MEM_callocN(sizeof(wmEvent), "window event state"); | ||||
| #ifdef WITH_INPUT_HMD | |||||
| /* Try to open an HMD device when reading a file that has a running HMD session stored. */ | |||||
| if (win == wm->hmd_view.hmd_win && win->screen->is_hmd_running) { | |||||
| WM_device_HMD_state_set(U.hmd_settings.device, true); | |||||
| } | |||||
| #endif | |||||
| /* add keymap handlers (1 handler for all keys in map!) */ | /* add keymap handlers (1 handler for all keys in map!) */ | ||||
| keymap = WM_keymap_find(wm->defaultconf, "Window", 0, 0); | keymap = WM_keymap_find(wm->defaultconf, "Window", 0, 0); | ||||
| WM_event_add_keymap_handler(&win->handlers, keymap); | WM_event_add_keymap_handler(&win->handlers, keymap); | ||||
| keymap = WM_keymap_find(wm->defaultconf, "Screen", 0, 0); | keymap = WM_keymap_find(wm->defaultconf, "Screen", 0, 0); | ||||
| WM_event_add_keymap_handler(&win->handlers, keymap); | WM_event_add_keymap_handler(&win->handlers, keymap); | ||||
| keymap = WM_keymap_find(wm->defaultconf, "Screen Editing", 0, 0); | keymap = WM_keymap_find(wm->defaultconf, "Screen Editing", 0, 0); | ||||
| WM_event_add_keymap_handler(&win->modalhandlers, keymap); | WM_event_add_keymap_handler(&win->modalhandlers, keymap); | ||||
| /* add drop boxes */ | /* add drop boxes */ | ||||
| { | { | ||||
| ListBase *lb = WM_dropboxmap_find("Window", 0, 0); | ListBase *lb = WM_dropboxmap_find("Window", 0, 0); | ||||
| WM_event_add_dropbox_handler(&win->handlers, lb); | WM_event_add_dropbox_handler(&win->handlers, lb); | ||||
| } | } | ||||
| wm_window_title(wm, win); | wm_window_title(wm, win, NULL); | ||||
| } | } | ||||
| } | } | ||||
| /** | /** | ||||
| * Call after #wm_window_ghostwindows_ensure or #WM_check | * Call after #wm_window_ghostwindows_ensure or #WM_check | ||||
| * (after loading a new file) in the unlikely event a window couldn't be created. | * (after loading a new file) in the unlikely event a window couldn't be created. | ||||
| */ | */ | ||||
| void wm_window_ghostwindows_remove_invalid(bContext *C, wmWindowManager *wm) | void wm_window_ghostwindows_remove_invalid(bContext *C, wmWindowManager *wm) | ||||
| Show All 36 Lines | wmWindow *WM_window_open(bContext *C, const rcti *rect) | ||||
| else { | else { | ||||
| wm_window_close(C, CTX_wm_manager(C), win); | wm_window_close(C, CTX_wm_manager(C), win); | ||||
| CTX_wm_window_set(C, win_prev); | CTX_wm_window_set(C, win_prev); | ||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| } | } | ||||
| /** | /** | ||||
| * Uses `screen->temp` tag to define what to do, currently it limits | * Sets up the window and the screen for a desired \a type. | ||||
| * to only one "temp" window for render out, preferences, filewindow, etc... | |||||
| * | * | ||||
| * \param type: WM_WINDOW_RENDER, WM_WINDOW_USERPREFS... | * \return if the window is valid. | ||||
| * \return the window or NULL. | |||||
| */ | */ | ||||
| wmWindow *WM_window_open_temp(bContext *C, const rcti *rect_init, int type) | static bool wm_window_setup_type(bContext *C, Scene *scene, wmWindow *win, rcti rect, int type) | ||||
| { | { | ||||
| wmWindow *win_prev = CTX_wm_window(C); | wmWindow *win_prev = CTX_wm_window(C); | ||||
| wmWindow *win; | const short px_virtual = (short)wm_window_get_virtual_pixelsize(); | ||||
| ScrArea *sa; | ScrArea *sa; | ||||
| Scene *scene = CTX_data_scene(C); | |||||
| const char *title; | const char *title; | ||||
| rcti rect = *rect_init; | |||||
| const short px_virtual = (short)wm_window_get_virtual_pixelsize(); | |||||
| /* changes rect to fit within desktop */ | |||||
| wm_window_check_position(&rect); | |||||
| /* test if we have a temp screen already */ | |||||
| for (win = CTX_wm_manager(C)->windows.first; win; win = win->next) | |||||
| if (win->screen->temp) | |||||
| break; | |||||
| /* add new window? */ | |||||
| if (win == NULL) { | |||||
| win = wm_window_new(C); | |||||
| win->posx = rect.xmin; | |||||
| win->posy = rect.ymin; | |||||
| } | |||||
| /* multiply with virtual pixelsize, ghost handles native one (e.g. for retina) */ | /* multiply with virtual pixelsize, ghost handles native one (e.g. for retina) */ | ||||
| win->sizex = BLI_rcti_size_x(&rect) * px_virtual; | win->sizex = BLI_rcti_size_x(&rect) * px_virtual; | ||||
| win->sizey = BLI_rcti_size_y(&rect) * px_virtual; | win->sizey = BLI_rcti_size_y(&rect) * px_virtual; | ||||
| if (win->ghostwin) { | if (win->ghostwin) { | ||||
| wm_window_set_size(win, win->sizex, win->sizey); | wm_window_set_size(win, win->sizex, win->sizey); | ||||
| wm_window_raise(win); | wm_window_raise(win); | ||||
| } | } | ||||
| if (win->screen == NULL) { | if (win->screen == NULL) { | ||||
| /* add new screen */ | /* add new screen */ | ||||
| win->screen = ED_screen_add(win, scene, "temp"); | win->screen = ED_screen_add(win, scene, "temp"); | ||||
| } | } | ||||
| else { | else { | ||||
| /* switch scene for rendering */ | /* switch scene for rendering */ | ||||
| if (win->screen->scene != scene) | if (win->screen->scene != scene) | ||||
| ED_screen_set_scene(C, win->screen, scene); | ED_screen_set_scene(C, win->screen, scene); | ||||
| } | } | ||||
| win->screen->temp = 1; | |||||
| /* make window active, and validate/resize */ | /* make window active, and validate/resize */ | ||||
| CTX_wm_window_set(C, win); | CTX_wm_window_set(C, win); | ||||
| WM_check(C); | WM_check(C); | ||||
| /* It's possible `win->ghostwin == NULL`. | /* It's possible `win->ghostwin == NULL`. | ||||
| * instead of attempting to cleanup here (in a half finished state), | * instead of attempting to cleanup here (in a half finished state), | ||||
| * finish setting up the screen, then free it at the end of the function, | * finish setting up the screen, then free it at the end of the function, | ||||
| * to avoid having to take into account a partially-created window. | * to avoid having to take into account a partially-created window. | ||||
| */ | */ | ||||
| /* ensure it shows the right spacetype editor */ | /* ensure we show the right spacetype editor */ | ||||
| sa = win->screen->areabase.first; | sa = win->screen->areabase.first; | ||||
| CTX_wm_area_set(C, sa); | CTX_wm_area_set(C, sa); | ||||
| if (type == WM_WINDOW_RENDER) { | int spacetype = SPACE_EMPTY; | ||||
| ED_area_newspace(C, sa, SPACE_IMAGE, false); | switch (type) { | ||||
| } | case WM_WINDOW_RENDER: | ||||
| else { | spacetype = SPACE_IMAGE; | ||||
| ED_area_newspace(C, sa, SPACE_USERPREF, false); | title = IFACE_("Blender Render"); | ||||
| break; | |||||
| case WM_WINDOW_USERPREFS: | |||||
| spacetype = SPACE_USERPREF; | |||||
| title = IFACE_("Blender User Preferences"); | |||||
| break; | |||||
| case WM_WINDOW_HMD: | |||||
| spacetype = SPACE_VIEW3D; | |||||
| title = IFACE_("HMD View"); | |||||
| break; | |||||
| default: | |||||
| title = IFACE_("Blender"); | |||||
| BLI_assert(0); | |||||
| break; | |||||
| } | } | ||||
| ED_area_newspace(C, sa, spacetype, false); | |||||
| ED_screen_set(C, win->screen); | ED_screen_set(C, win->screen); | ||||
| ED_screen_refresh(CTX_wm_manager(C), win); /* test scale */ | ED_screen_refresh(CTX_wm_manager(C), win); /* test scale */ | ||||
| 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 | |||||
| title = "Blender"; | |||||
| if (win->ghostwin) { | if (win->ghostwin) { | ||||
| GHOST_SetTitle(win->ghostwin, title); | GHOST_SetTitle(win->ghostwin, title); | ||||
| return win; | |||||
| } | } | ||||
| else { | else { | ||||
| /* very unlikely! but opening a new window can fail */ | /* very unlikely! but opening a new window can fail */ | ||||
| wm_window_close(C, CTX_wm_manager(C), win); | wm_window_close(C, CTX_wm_manager(C), win); | ||||
| CTX_wm_window_set(C, win_prev); | CTX_wm_window_set(C, win_prev); | ||||
| return false; | |||||
| } | |||||
| return true; | |||||
| } | |||||
| /** | |||||
| * Uses `screen->temp` tag to define what to do, currently it limits | |||||
| * to only one "temp" window for render out, preferences, filewindow, etc... | |||||
| * | |||||
| * \param type: WM_WINDOW_RENDER, WM_WINDOW_USERPREFS, WM_WINDOW_HMD... | |||||
| * \return the window or NULL. | |||||
| */ | |||||
| wmWindow *WM_window_open_temp(bContext *C, const rcti *rect_init, int type) | |||||
| { | |||||
| Scene *scene = CTX_data_scene(C); | |||||
| wmWindow *win; | |||||
| rcti rect = *rect_init; | |||||
| /* changes rect to fit within desktop */ | |||||
| wm_window_check_position(&rect); | |||||
| /* test if we have a temp screen already */ | |||||
| for (win = CTX_wm_manager(C)->windows.first; win; win = win->next) | |||||
| if (win->screen->type == SCREEN_TYPE_TEMP) | |||||
| break; | |||||
| /* add new window? */ | |||||
| if (win == NULL) { | |||||
| win = wm_window_new(C); | |||||
| win->posx = rect.xmin; | |||||
| win->posy = rect.ymin; | |||||
| } | |||||
| if (!wm_window_setup_type(C, scene, win, rect, type)) { | |||||
| return NULL; | |||||
| } | |||||
| /* after window setup! */ | |||||
| win->screen->type = SCREEN_TYPE_TEMP; | |||||
| return win; | |||||
| } | |||||
| /** | |||||
| * Opens a new, restricted window. A restricted window only allows to display one particulare editor. It | |||||
| * will only display the main region and won't allow you to go out of fullscreen or switch the editor. | |||||
| * | |||||
| * \param type: WM_WINDOW_RENDER, WM_WINDOW_USERPREFS, WM_WINDOW_HMD... | |||||
| * \return the window or NULL. | |||||
| */ | |||||
| wmWindow *WM_window_open_restricted(bContext *C, const rcti *rect_init, int type) | |||||
| { | |||||
| Scene *scene = CTX_data_scene(C); | |||||
| wmWindow *win = wm_window_new(C); | |||||
| rcti rect = *rect_init; | |||||
| /* changes rect to fit within desktop */ | |||||
| wm_window_check_position(&rect); | |||||
| win->posx = rect.xmin; | |||||
| win->posy = rect.ymin; | |||||
| if (!wm_window_setup_type(C, scene, win, rect, type)) { | |||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| ED_screen_state_toggle(C, win, win->screen->areabase.first, SCREENFULL); | |||||
| win->screen->type = SCREEN_TYPE_RESTRICTED; | |||||
| return win; | |||||
| } | } | ||||
| /* ****************** Operators ****************** */ | /* ****************** Operators ****************** */ | ||||
| int wm_window_close_exec(bContext *C, wmOperator *UNUSED(op)) | int wm_window_close_exec(bContext *C, wmOperator *UNUSED(op)) | ||||
| { | { | ||||
| wmWindowManager *wm = CTX_wm_manager(C); | wmWindowManager *wm = CTX_wm_manager(C); | ||||
| wmWindow *win = CTX_wm_window(C); | wmWindow *win = CTX_wm_window(C); | ||||
| wm_window_close(C, wm, win); | wm_window_close(C, wm, win); | ||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| /* operator callback */ | /* operator callback */ | ||||
| int wm_window_duplicate_exec(bContext *C, wmOperator *UNUSED(op)) | int wm_window_duplicate_exec(bContext *C, wmOperator *UNUSED(op)) | ||||
| { | { | ||||
| wmWindow *win_src = CTX_wm_window(C); | wmWindow *win_src = CTX_wm_window(C); | ||||
| bool ok; | bool ok; | ||||
| ok = (wm_window_copy_test(C, win_src) != NULL); | ok = (wm_window_copy_test(C, win_src) != NULL); | ||||
| return ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED; | return ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED; | ||||
| } | } | ||||
| void WM_window_fullscreen_toggle(const wmWindow *win, const bool force_full, const bool force_normal) | |||||
| { | |||||
| /* mutally exclusive, forcing both doesn't work */ | |||||
| if (force_full && force_normal) { | |||||
| printf("%s - WARNING: force_full and force normal can't both be true!", __func__); | |||||
| return; | |||||
| } | |||||
| GHOST_TWindowState state = GHOST_GetWindowState(win->ghostwin); | |||||
| if ((force_full && state == GHOST_kWindowStateFullScreen) || | |||||
| (force_normal && state == GHOST_kWindowStateNormal)) | |||||
| { | |||||
| return; | |||||
| } | |||||
| if (state != GHOST_kWindowStateFullScreen) | |||||
| GHOST_SetWindowState(win->ghostwin, GHOST_kWindowStateFullScreen); | |||||
| else | |||||
| GHOST_SetWindowState(win->ghostwin, GHOST_kWindowStateNormal); | |||||
| } | |||||
| /* fullscreen operator callback */ | /* fullscreen operator callback */ | ||||
| int wm_window_fullscreen_toggle_exec(bContext *C, wmOperator *UNUSED(op)) | int wm_window_fullscreen_toggle_exec(bContext *C, wmOperator *UNUSED(op)) | ||||
| { | { | ||||
| wmWindow *window = CTX_wm_window(C); | wmWindow *win = CTX_wm_window(C); | ||||
| GHOST_TWindowState state; | |||||
| if (G.background) | if (G.background || !ED_screen_is_editable(CTX_wm_screen(C))) | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| state = GHOST_GetWindowState(window->ghostwin); | WM_window_fullscreen_toggle(win, false, false); | ||||
| if (state != GHOST_kWindowStateFullScreen) | |||||
| GHOST_SetWindowState(window->ghostwin, GHOST_kWindowStateFullScreen); | |||||
| else | |||||
| GHOST_SetWindowState(window->ghostwin, GHOST_kWindowStateNormal); | |||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| /* ************ events *************** */ | /* ************ events *************** */ | ||||
| void wm_cursor_position_from_ghost(wmWindow *win, int *x, int *y) | void wm_cursor_position_from_ghost(wmWindow *win, int *x, int *y) | ||||
| { | { | ||||
| float fac = GHOST_GetNativePixelSize(win->ghostwin); | float fac = GHOST_GetNativePixelSize(win->ghostwin); | ||||
| ▲ Show 20 Lines • Show All 453 Lines • ▼ Show 20 Lines | #endif | ||||
| wm_draw_window_clear(win); | wm_draw_window_clear(win); | ||||
| WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL); | WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL); | ||||
| WM_event_add_notifier(C, NC_WINDOW | NA_EDITED, NULL); | WM_event_add_notifier(C, NC_WINDOW | NA_EDITED, NULL); | ||||
| } | } | ||||
| break; | break; | ||||
| } | } | ||||
| #ifdef WITH_INPUT_HMD | |||||
| case GHOST_kEventHMD: | |||||
| { | |||||
| GHOST_TEventOpenHMDData *hmd_data = data; | |||||
| if (hmd_data->subtype == GHOST_kDeviceNumChanged) { | |||||
| if (WM_device_HMD_num_devices_get() > 0) { | |||||
| if (U.hmd_settings.device == -1) { /* Only if 'None' item is selected */ | |||||
| U.hmd_settings.device = 0; /* last device plugged in */ | |||||
| } | |||||
| } | |||||
| else { | |||||
| U.hmd_settings.device = -1; | |||||
| } | |||||
| } | |||||
| else { | |||||
| wm_event_add_ghostevent(wm, win, type, time, data); | |||||
| } | |||||
| break; | |||||
| } | |||||
| #endif | |||||
| case GHOST_kEventTrackpad: | case GHOST_kEventTrackpad: | ||||
| { | { | ||||
| GHOST_TEventTrackpadData *pd = data; | GHOST_TEventTrackpadData *pd = data; | ||||
| wm_cursor_position_from_ghost(win, &pd->x, &pd->y); | wm_cursor_position_from_ghost(win, &pd->x, &pd->y); | ||||
| wm_event_add_ghostevent(wm, win, type, time, data); | wm_event_add_ghostevent(wm, win, type, time, data); | ||||
| break; | break; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 499 Lines • Show Last 20 Lines | |||||