From 91997ea89f12104f16ef181be0d359a9df6dbb1e Mon Sep 17 00:00:00 2001 From: Harley Acheson Date: Fri, 5 Sep 2025 00:05:50 +0200 Subject: [PATCH] UI: Save Temp Window Sizes & Positions Allow temporary windows (like File Browser, Preferences, Render, Drivers, Info) to open at their last positions and sizes. Pull Request: https://projects.blender.org/blender/blender/pulls/104727 --- intern/ghost/GHOST_Types.h | 6 +- intern/ghost/intern/GHOST_SystemHeadless.hh | 4 +- intern/ghost/intern/GHOST_SystemSDL.cc | 2 + intern/ghost/intern/GHOST_SystemWayland.cc | 2 + release/datafiles/userdef/userdef_default.c | 11 +- .../blender/blenkernel/BKE_blender_version.h | 2 +- .../blenloader/intern/versioning_userdef.cc | 6 ++ .../blender/editors/include/ED_fileselect.hh | 4 +- source/blender/editors/include/ED_screen.hh | 3 +- source/blender/editors/render/render_view.cc | 12 ++- source/blender/editors/screen/screen_edit.cc | 20 +--- source/blender/editors/screen/screen_ops.cc | 79 ++------------ source/blender/editors/space_file/filesel.cc | 25 +---- .../editors/space_outliner/outliner_edit.cc | 23 +--- source/blender/makesdna/DNA_userdef_types.h | 17 ++- source/blender/windowmanager/WM_api.hh | 4 + .../windowmanager/intern/wm_event_system.cc | 60 ++++------- .../blender/windowmanager/intern/wm_window.cc | 100 ++++++++++++++++-- 18 files changed, 184 insertions(+), 196 deletions(-) diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h index 39e34c0f42c..d8e57ce7712 100644 --- a/intern/ghost/GHOST_Types.h +++ b/intern/ghost/GHOST_Types.h @@ -178,6 +178,10 @@ typedef enum { * Setting cursors via #GHOST_SetCursorGenerator is supported. */ GHOST_kCapabilityCursorGenerator = (1 << 11), + /** + * Support accurately placing windows on multiple monitors. + */ + GHOST_kCapabilityMultiMonitorPlacement = (1 << 12), } GHOST_TCapabilityFlag; @@ -191,7 +195,7 @@ typedef enum { GHOST_kCapabilityClipboardImage | GHOST_kCapabilityDesktopSample | GHOST_kCapabilityInputIME | \ GHOST_kCapabilityTrackpadPhysicalDirection | GHOST_kCapabilityWindowDecorationStyles | \ GHOST_kCapabilityKeyboardHyperKey | GHOST_kCapabilityCursorRGBA | \ - GHOST_kCapabilityCursorGenerator) + GHOST_kCapabilityCursorGenerator | GHOST_kCapabilityMultiMonitorPlacement) /* Xtilt and Ytilt represent how much the pen is tilted away from * vertically upright in either the X or Y direction, with X and Y the diff --git a/intern/ghost/intern/GHOST_SystemHeadless.hh b/intern/ghost/intern/GHOST_SystemHeadless.hh index cf02a8d1cd7..3d53c27b28d 100644 --- a/intern/ghost/intern/GHOST_SystemHeadless.hh +++ b/intern/ghost/intern/GHOST_SystemHeadless.hh @@ -76,7 +76,9 @@ class GHOST_SystemHeadless : public GHOST_System { /* Wrap. */ GHOST_kCapabilityCursorRGBA | /* Wrap. */ - GHOST_kCapabilityCursorGenerator) + GHOST_kCapabilityCursorGenerator | + /* Wrap. */ + GHOST_kCapabilityMultiMonitorPlacement) ); } diff --git a/intern/ghost/intern/GHOST_SystemSDL.cc b/intern/ghost/intern/GHOST_SystemSDL.cc index 61ef6022322..eebf865f9fb 100644 --- a/intern/ghost/intern/GHOST_SystemSDL.cc +++ b/intern/ghost/intern/GHOST_SystemSDL.cc @@ -801,6 +801,8 @@ GHOST_TCapabilityFlag GHOST_SystemSDL::getCapabilities() const GHOST_kCapabilityInputIME | /* No support for window decoration styles. */ GHOST_kCapabilityWindowDecorationStyles | + /* No support for precisely placing windows on multiple monitors. */ + GHOST_kCapabilityMultiMonitorPlacement | /* No support for a Hyper modifier key. */ GHOST_kCapabilityKeyboardHyperKey | /* No support yet for RGBA mouse cursors. */ diff --git a/intern/ghost/intern/GHOST_SystemWayland.cc b/intern/ghost/intern/GHOST_SystemWayland.cc index 215eed8f8d1..f4e80292bf0 100644 --- a/intern/ghost/intern/GHOST_SystemWayland.cc +++ b/intern/ghost/intern/GHOST_SystemWayland.cc @@ -9074,6 +9074,8 @@ GHOST_TCapabilityFlag GHOST_SystemWayland::getCapabilities() const ~( /* WAYLAND doesn't support accessing the window position. */ GHOST_kCapabilityWindowPosition | + /* WAYLAND cannot precisely place windows among multiple monitors. */ + GHOST_kCapabilityMultiMonitorPlacement | /* WAYLAND doesn't support setting the cursor position directly, * this is an intentional choice, forcing us to use a software cursor in this case. */ GHOST_kCapabilityCursorWarp | diff --git a/release/datafiles/userdef/userdef_default.c b/release/datafiles/userdef/userdef_default.c index 7844dae0d0a..899139e203b 100644 --- a/release/datafiles/userdef/userdef_default.c +++ b/release/datafiles/userdef/userdef_default.c @@ -221,9 +221,16 @@ const UserDef U_default = { .details_flags = FILE_DETAILS_SIZE | FILE_DETAILS_DATETIME, .flag = FILE_HIDE_DOT, .filter_id = FILTER_ID_ALL, + }, - .temp_win_sizex = 1060, - .temp_win_sizey = 600, + .stored_bounds = + { + .file = {100.0f, 1160.0f, 350.0f, 950.0f}, + .userpref = {100.0f, 940.0f, 350.0f, 900.0f}, + .image = {50.0f, 1360.0f, 50.0f, 830.0f}, + .graph = {50.0f, 950.0f, 200.0f, 780.0f}, + .info = {100.0f, 1000.0f, 300.0f, 880.0f}, + .outliner = {100.0f, 550.0f, 350.0f, 800.0f}, }, .sequencer_proxy_setup = USER_SEQ_PROXY_SETUP_AUTOMATIC, diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index a5110e3d672..9c01021436a 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -27,7 +27,7 @@ /* Blender file format version. */ #define BLENDER_FILE_VERSION BLENDER_VERSION -#define BLENDER_FILE_SUBVERSION 75 +#define BLENDER_FILE_SUBVERSION 76 /* Minimum Blender version that supports reading file written with the current * version. Older Blender versions will test this and cancel loading the file, showing a warning to diff --git a/source/blender/blenloader/intern/versioning_userdef.cc b/source/blender/blenloader/intern/versioning_userdef.cc index ae5fd7775dd..5c166c566b0 100644 --- a/source/blender/blenloader/intern/versioning_userdef.cc +++ b/source/blender/blenloader/intern/versioning_userdef.cc @@ -1670,6 +1670,12 @@ void blo_do_versions_userdef(UserDef *userdef) userdef->preferences_display_type = USER_TEMP_SPACE_DISPLAY_WINDOW; } + if (!USER_VERSION_ATLEAST(500, 76)) { + if (userdef->stored_bounds.file.xmin == userdef->stored_bounds.file.xmax) { + memcpy(&userdef->stored_bounds, &U_default.stored_bounds, sizeof(userdef->stored_bounds)); + } + } + /** * Always bump subversion in BKE_blender_version.h when adding versioning * code here, and wrap it inside a USER_VERSION_ATLEAST check. diff --git a/source/blender/editors/include/ED_fileselect.hh b/source/blender/editors/include/ED_fileselect.hh index eb4eff5548d..b787059cf6b 100644 --- a/source/blender/editors/include/ED_fileselect.hh +++ b/source/blender/editors/include/ED_fileselect.hh @@ -125,9 +125,7 @@ void ED_fileselect_set_params_from_userdef(SpaceFile *sfile); * \param temp_win_size: If the browser was opened in a temporary window, * pass its size here so we can store that in the preferences. Otherwise NULL. */ -void ED_fileselect_params_to_userdef(SpaceFile *sfile, - const int temp_win_size[2], - bool is_maximized); +void ED_fileselect_params_to_userdef(SpaceFile *sfile); void ED_fileselect_init_layout(SpaceFile *sfile, ARegion *region); diff --git a/source/blender/editors/include/ED_screen.hh b/source/blender/editors/include/ED_screen.hh index fff827a6d98..c3c7b4e5e51 100644 --- a/source/blender/editors/include/ED_screen.hh +++ b/source/blender/editors/include/ED_screen.hh @@ -389,10 +389,9 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *area, short */ ScrArea *ED_screen_temp_space_open(bContext *C, const char *title, - const rcti *rect_unscaled, eSpace_Type space_type, int display_type, - bool dialog) ATTR_NONNULL(1, 3); + bool dialog) ATTR_NONNULL(1); void ED_screens_header_tools_menu_create(bContext *C, uiLayout *layout, void *arg); void ED_screens_footer_tools_menu_create(bContext *C, uiLayout *layout, void *arg); void ED_screens_region_flip_menu_create(bContext *C, uiLayout *layout, void *arg); diff --git a/source/blender/editors/render/render_view.cc b/source/blender/editors/render/render_view.cc index 598e1e7dcfe..2c41a57eada 100644 --- a/source/blender/editors/render/render_view.cc +++ b/source/blender/editors/render/render_view.cc @@ -149,6 +149,16 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports) sizex = std::max(sizex, 320); sizey = std::max(sizey, 256); + WM_window_dpi_set_userdef(CTX_wm_window(C)); + rctf *stored_bounds = &U.stored_bounds.image; + const bool bounds_valid = (stored_bounds && (BLI_rctf_size_x(stored_bounds) > 150.0f) && + (BLI_rctf_size_y(stored_bounds) > 100.0f)); + const bool mm_placement = WM_capabilities_flag() & WM_CAPABILITY_MULTIMONITOR_PLACEMENT; + if (bounds_valid && mm_placement) { + mx = int(stored_bounds->xmin * UI_SCALE_FAC); + my = int(stored_bounds->ymin * UI_SCALE_FAC); + } + const rcti window_rect = { /*xmin*/ mx, /*xmax*/ mx + sizex, @@ -164,7 +174,7 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports) true, false, true, - WIN_ALIGN_LOCATION_CENTER, + WIN_ALIGN_ABSOLUTE, nullptr, nullptr) == nullptr) { diff --git a/source/blender/editors/screen/screen_edit.cc b/source/blender/editors/screen/screen_edit.cc index 153f5b36f1d..32c8d9b3375 100644 --- a/source/blender/editors/screen/screen_edit.cc +++ b/source/blender/editors/screen/screen_edit.cc @@ -1891,26 +1891,12 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *area, const return static_cast(screen->areabase.first); } -ScrArea *ED_screen_temp_space_open(bContext *C, - const char *title, - const rcti *rect_unscaled, - eSpace_Type space_type, - int display_type, - bool dialog) +ScrArea *ED_screen_temp_space_open( + bContext *C, const char *title, eSpace_Type space_type, int display_type, bool dialog) { switch (display_type) { case USER_TEMP_SPACE_DISPLAY_WINDOW: - if (WM_window_open(C, - title, - rect_unscaled, - int(space_type), - false, - dialog, - true, - WIN_ALIGN_LOCATION_CENTER, - nullptr, - nullptr)) - { + if (WM_window_open_temp(C, title, space_type, dialog)) { return CTX_wm_area(C); } break; diff --git a/source/blender/editors/screen/screen_ops.cc b/source/blender/editors/screen/screen_ops.cc index bb56c6a0161..212a5d9c8ea 100644 --- a/source/blender/editors/screen/screen_ops.cc +++ b/source/blender/editors/screen/screen_ops.cc @@ -1541,8 +1541,11 @@ static void area_dupli_fn(bScreen * /*screen*/, ScrArea *area, void *user_data) /* operator callback */ static bool area_dupli_open(bContext *C, ScrArea *area, const blender::int2 position) { - const rcti window_rect = { - position.x, position.x + area->winx, position.y, position.y + area->winy}; + const wmWindow *win = CTX_wm_window(C); + const rcti window_rect = {win->posx + position.x, + win->posx + position.x + area->winx, + win->posy + position.y, + win->posy + position.y + area->winy}; /* Create new window. No need to set space_type since it will be copied over. */ wmWindow *newwin = WM_window_open(C, @@ -6236,12 +6239,6 @@ static void SCREEN_OT_back_to_previous(wmOperatorType *ot) static wmOperatorStatus userpref_show_exec(bContext *C, wmOperator *op) { - wmWindow *win_cur = CTX_wm_window(C); - /* Use eventstate, not event from _invoke, so this can be called through exec(). */ - const wmEvent *event = win_cur->eventstate; - int sizex = (680 + UI_NAVIGATION_REGION_WIDTH) * UI_SCALE_FAC; - int sizey = 520 * UI_SCALE_FAC; - PropertyRNA *prop = RNA_struct_find_property(op->ptr, "section"); if (prop && RNA_property_is_set(op->ptr, prop)) { /* Set active section via RNA, so it can fail properly. */ @@ -6253,19 +6250,11 @@ static wmOperatorStatus userpref_show_exec(bContext *C, wmOperator *op) RNA_property_update(C, &pref_ptr, active_section_prop); } - const rcti window_rect = { - /*xmin*/ event->xy[0], - /*xmax*/ event->xy[0] + sizex, - /*ymin*/ event->xy[1], - /*ymax*/ event->xy[1] + sizey, - }; - /* changes context! */ - if (ScrArea *area = ED_screen_temp_space_open( - C, nullptr, &window_rect, SPACE_USERPREF, U.preferences_display_type, false)) - { + if (WM_window_open_temp(C, nullptr, SPACE_USERPREF, false)) { /* The header only contains the editor switcher and looks empty. * So hiding in the temp window makes sense. */ + ScrArea *area = CTX_wm_area(C); ARegion *region_header = BKE_area_find_region_type(area, RGN_TYPE_HEADER); region_header->flag |= RGN_FLAG_HIDDEN; @@ -6324,13 +6313,6 @@ static void SCREEN_OT_userpref_show(wmOperatorType *ot) static wmOperatorStatus drivers_editor_show_exec(bContext *C, wmOperator *op) { - wmWindow *win_cur = CTX_wm_window(C); - /* Use eventstate, not event from _invoke, so this can be called through exec(). */ - const wmEvent *event = win_cur->eventstate; - - int sizex = 900 * UI_SCALE_FAC; - int sizey = 580 * UI_SCALE_FAC; - /* Get active property to show driver for * - Need to grab it first, or else this info disappears * after we've created the window @@ -6340,25 +6322,8 @@ static wmOperatorStatus drivers_editor_show_exec(bContext *C, wmOperator *op) PropertyRNA *prop; uiBut *but = UI_context_active_but_prop_get(C, &ptr, &prop, &index); - const rcti window_rect = { - /*xmin*/ event->xy[0], - /*xmax*/ event->xy[0] + sizex, - /*ymin*/ event->xy[1], - /*ymax*/ event->xy[1] + sizey, - }; - /* changes context! */ - if (WM_window_open(C, - IFACE_("Blender Drivers Editor"), - &window_rect, - SPACE_GRAPH, - false, - false, - true, - WIN_ALIGN_LOCATION_CENTER, - nullptr, - nullptr) != nullptr) - { + if (WM_window_open_temp(C, IFACE_("Blender Drivers Editor"), SPACE_GRAPH, false)) { ED_drivers_editor_init(C, CTX_wm_area(C)); /* activate driver F-Curve for the property under the cursor */ @@ -6414,34 +6379,8 @@ static void SCREEN_OT_drivers_editor_show(wmOperatorType *ot) static wmOperatorStatus info_log_show_exec(bContext *C, wmOperator *op) { - wmWindow *win_cur = CTX_wm_window(C); - /* Use eventstate, not event from _invoke, so this can be called through exec(). */ - const wmEvent *event = win_cur->eventstate; - const int shift_y = 480; - const int mx = event->xy[0]; - const int my = event->xy[1] + shift_y; - int sizex = 900 * UI_SCALE_FAC; - int sizey = 580 * UI_SCALE_FAC; - - const rcti window_rect = { - /*xmin*/ mx, - /*xmax*/ mx + sizex, - /*ymin*/ my, - /*ymax*/ my + sizey, - }; - /* changes context! */ - if (WM_window_open(C, - IFACE_("Blender Info Log"), - &window_rect, - SPACE_INFO, - false, - false, - true, - WIN_ALIGN_LOCATION_CENTER, - nullptr, - nullptr) != nullptr) - { + if (WM_window_open_temp(C, IFACE_("Blender Info Log"), SPACE_INFO, false)) { return OPERATOR_FINISHED; } BKE_report(op->reports, RPT_ERROR, "Failed to open window!"); diff --git a/source/blender/editors/space_file/filesel.cc b/source/blender/editors/space_file/filesel.cc index 45bdaee8123..0019f0b8047 100644 --- a/source/blender/editors/space_file/filesel.cc +++ b/source/blender/editors/space_file/filesel.cc @@ -685,9 +685,7 @@ void ED_fileselect_set_params_from_userdef(SpaceFile *sfile) } } -void ED_fileselect_params_to_userdef(SpaceFile *sfile, - const int temp_win_size[2], - const bool is_maximized) +void ED_fileselect_params_to_userdef(SpaceFile *sfile) { FileSelectParams *params = ED_fileselect_get_active_params(sfile); UserDef_FileSpaceData *sfile_udata_new = &U.file_space_data; @@ -711,11 +709,6 @@ void ED_fileselect_params_to_userdef(SpaceFile *sfile, (params->flag & FILE_SORT_INVERT); } - if (temp_win_size && !is_maximized) { - sfile_udata_new->temp_win_sizex = temp_win_size[0]; - sfile_udata_new->temp_win_sizey = temp_win_size[1]; - } - /* Tag preferences as dirty if something has changed. */ if (memcmp(sfile_udata_new, &sfile_udata_old, sizeof(sfile_udata_old)) != 0) { U.runtime.is_dirty = true; @@ -1327,21 +1320,7 @@ void ED_fileselect_exit(wmWindowManager *wm, SpaceFile *sfile) return; } if (sfile->op) { - wmWindow *temp_win = (wm->runtime->winactive && - WM_window_is_temp_screen(wm->runtime->winactive)) ? - wm->runtime->winactive : - nullptr; - if (temp_win) { - int win_size[2]; - bool is_maximized; - - ED_fileselect_window_params_get(temp_win, win_size, &is_maximized); - ED_fileselect_params_to_userdef(sfile, win_size, is_maximized); - } - else { - ED_fileselect_params_to_userdef(sfile, nullptr, false); - } - + ED_fileselect_params_to_userdef(sfile); WM_event_fileselect_event(wm, sfile->op, EVT_FILESELECT_EXTERNAL_CANCEL); sfile->op = nullptr; } diff --git a/source/blender/editors/space_outliner/outliner_edit.cc b/source/blender/editors/space_outliner/outliner_edit.cc index 737e4ef050f..4e55c96b080 100644 --- a/source/blender/editors/space_outliner/outliner_edit.cc +++ b/source/blender/editors/space_outliner/outliner_edit.cc @@ -2495,28 +2495,9 @@ void OUTLINER_OT_orphans_purge(wmOperatorType *ot) static wmOperatorStatus outliner_orphans_manage_invoke(bContext *C, wmOperator * /*op*/, - const wmEvent *event) + const wmEvent * /*event*/) { - const int sizex = int(450.0f * UI_SCALE_FAC); - const int sizey = int(450.0f * UI_SCALE_FAC); - const rcti window_rect = { - /*xmin*/ event->xy[0], - /*xmax*/ event->xy[0] + sizex, - /*ymin*/ event->xy[1], - /*ymax*/ event->xy[1] + sizey, - }; - - if (WM_window_open(C, - IFACE_("Manage Unused Data"), - &window_rect, - SPACE_OUTLINER, - false, - false, - true, - WIN_ALIGN_LOCATION_CENTER, - nullptr, - nullptr) != nullptr) - { + if (WM_window_open_temp(C, IFACE_("Manage Unused Data"), SPACE_OUTLINER, false)) { SpaceOutliner *soutline = CTX_wm_space_outliner(C); soutline->outlinevis = SO_ID_ORPHANS; return OPERATOR_FINISHED; diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index 477de3a8aab..eccbd221ce8 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -8,6 +8,8 @@ #pragma once +#include "BLI_rect.h" + #include "DNA_ID.h" #include "DNA_colorband_types.h" #include "DNA_listBase.h" @@ -194,12 +196,17 @@ typedef struct UserDef_FileSpaceData { int flag; /* FileSelectParams.flag */ int _pad0; uint64_t filter_id; /* FileSelectParams.filter_id */ - - /** Info used when creating the file browser in a temporary window. */ - int temp_win_sizex; - int temp_win_sizey; } UserDef_FileSpaceData; +typedef struct UserDef_TempWinBounds { + rctf file; + rctf userpref; + rctf image; + rctf graph; + rctf info; + rctf outliner; +} UserDef_TempWinBounds; + /** * Checking experimental members must use the #USER_EXPERIMENTAL_TEST() macro * unless the #USER_DEVELOPER_UI is known to be enabled. @@ -614,6 +621,8 @@ typedef struct UserDef { UserDef_SpaceData space_data; UserDef_FileSpaceData file_space_data; + UserDef_TempWinBounds stored_bounds; + UserDef_Experimental experimental; /** Runtime data (keep last). */ diff --git a/source/blender/windowmanager/WM_api.hh b/source/blender/windowmanager/WM_api.hh index c79e9e8bce4..72a1c24e6fb 100644 --- a/source/blender/windowmanager/WM_api.hh +++ b/source/blender/windowmanager/WM_api.hh @@ -207,6 +207,8 @@ enum eWM_CapabilitiesFlag { WM_CAPABILITY_CURSOR_RGBA = (1 << 10), /** Support on demand cursor generation. */ WM_CAPABILITY_CURSOR_GENERATOR = (1 << 11), + /** Ability to save/restore windows among multiple monitors. */ + WM_CAPABILITY_MULTIMONITOR_PLACEMENT = (1 << 12), /** The initial value, indicates the value needs to be set by inspecting GHOST. */ WM_CAPABILITY_INITIALIZED = (1u << 31), }; @@ -398,6 +400,8 @@ wmWindow *WM_window_open(bContext *C, void (*area_setup_fn)(bScreen *screen, ScrArea *area, void *user_data), void *area_setup_user_data) ATTR_NONNULL(1, 3); +wmWindow *WM_window_open_temp(bContext *C, const char *title, int space_type, bool dialog); + void WM_window_dpi_set_userdef(const wmWindow *win); /** * Return the windows DPI as a scale, bypassing UI scale preference. diff --git a/source/blender/windowmanager/intern/wm_event_system.cc b/source/blender/windowmanager/intern/wm_event_system.cc index c2d379152a9..ddf6af8e4d4 100644 --- a/source/blender/windowmanager/intern/wm_event_system.cc +++ b/source/blender/windowmanager/intern/wm_event_system.cc @@ -2817,43 +2817,26 @@ static eHandlerActionFlag wm_handler_fileselect_do(bContext *C, switch (val) { case EVT_FILESELECT_FULL_OPEN: { - wmWindow *win = CTX_wm_window(C); - const blender::int2 window_size = WM_window_native_pixel_size(win); - const blender::int2 window_center = window_size / 2; - - const rcti window_rect = { - /*xmin*/ window_center[0], - /*xmax*/ window_center[0] + int(U.file_space_data.temp_win_sizex * UI_SCALE_FAC), - /*ymin*/ window_center[1], - /*ymax*/ window_center[1] + int(U.file_space_data.temp_win_sizey * UI_SCALE_FAC), - }; - - if (ScrArea *area = ED_screen_temp_space_open(C, - IFACE_("Blender File View"), - &window_rect, - SPACE_FILE, - U.filebrowser_display_type, - true)) - { - ARegion *region_header = BKE_area_find_region_type(area, RGN_TYPE_HEADER); - - BLI_assert(area->spacetype == SPACE_FILE); - - region_header->flag |= RGN_FLAG_HIDDEN; - /* Header on bottom, #AZone triangle to toggle header looks misplaced at the top. */ - region_header->alignment = RGN_ALIGN_BOTTOM; - - /* Settings for file-browser, #sfile is not operator owner but sends events. */ - SpaceFile *sfile = (SpaceFile *)area->spacedata.first; - sfile->op = handler->op; - - ED_fileselect_set_params_from_userdef(sfile); - } - else { - BKE_report(&wm->runtime->reports, RPT_ERROR, "Failed to open window!"); + ScrArea *area = ED_screen_temp_space_open( + C, IFACE_("Blender File View"), SPACE_FILE, U.filebrowser_display_type, true); + if (!area) { + BKE_report(&wm->runtime->reports, RPT_ERROR, "Failed to open file browser!"); return WM_HANDLER_BREAK; } + ARegion *region_header = BKE_area_find_region_type(area, RGN_TYPE_HEADER); + BLI_assert(area->spacetype == SPACE_FILE); + + region_header->flag |= RGN_FLAG_HIDDEN; + /* Header on bottom, #AZone triangle to toggle header looks misplaced at the top. */ + region_header->alignment = RGN_ALIGN_BOTTOM; + + /* Settings for file-browser, #sfile is not operator owner but sends events. */ + SpaceFile *sfile = (SpaceFile *)area->spacedata.first; + sfile->op = handler->op; + + ED_fileselect_set_params_from_userdef(sfile); + action = WM_HANDLER_BREAK; break; } @@ -2894,11 +2877,7 @@ static eHandlerActionFlag wm_handler_fileselect_do(bContext *C, continue; } - int win_size[2]; - bool is_maximized; - ED_fileselect_window_params_get(win, win_size, &is_maximized); - ED_fileselect_params_to_userdef( - static_cast(file_area->spacedata.first), win_size, is_maximized); + ED_fileselect_params_to_userdef(static_cast(file_area->spacedata.first)); if (BLI_listbase_is_single(&file_area->spacedata)) { BLI_assert(root_win != win); @@ -2930,8 +2909,7 @@ static eHandlerActionFlag wm_handler_fileselect_do(bContext *C, } if (!temp_win && ctx_area->full) { - ED_fileselect_params_to_userdef( - static_cast(ctx_area->spacedata.first), nullptr, false); + ED_fileselect_params_to_userdef(static_cast(ctx_area->spacedata.first)); ED_screen_full_prevspace(C, ctx_area); } } diff --git a/source/blender/windowmanager/intern/wm_window.cc b/source/blender/windowmanager/intern/wm_window.cc index 9d5ca7a67a7..0de9e585a37 100644 --- a/source/blender/windowmanager/intern/wm_window.cc +++ b/source/blender/windowmanager/intern/wm_window.cc @@ -447,8 +447,51 @@ void wm_quit_with_optional_confirmation_prompt(bContext *C, wmWindow *win) /** \name Window Close * \{ */ +static rctf *stored_window_bounds(eSpace_Type space_type) +{ + if (space_type == SPACE_IMAGE) { + return &U.stored_bounds.image; + } + if (space_type == SPACE_USERPREF) { + return &U.stored_bounds.userpref; + } + if (space_type == SPACE_GRAPH) { + return &U.stored_bounds.graph; + } + if (space_type == SPACE_INFO) { + return &U.stored_bounds.info; + } + if (space_type == SPACE_OUTLINER) { + return &U.stored_bounds.outliner; + } + if (space_type == SPACE_FILE) { + return &U.stored_bounds.file; + } + + return nullptr; +} + void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win) { + bScreen *screen = WM_window_get_active_screen(win); + + if (screen->temp && BLI_listbase_is_single(&screen->areabase) && !WM_window_is_maximized(win)) { + ScrArea *area = static_cast(screen->areabase.first); + rctf *stored_bounds = stored_window_bounds(eSpace_Type(area->spacetype)); + + if (stored_bounds) { + /* Get DPI and scale from parent window, if there is one. */ + WM_window_dpi_set_userdef(win->parent ? win->parent : win); + const float f = GHOST_GetNativePixelSize(static_cast(win->ghostwin)); + stored_bounds->xmin = float(win->posx) * f / UI_SCALE_FAC; + stored_bounds->xmax = stored_bounds->xmin + float(win->sizex) * f / UI_SCALE_FAC; + stored_bounds->ymin = float(win->posy) * f / UI_SCALE_FAC; + stored_bounds->ymax = stored_bounds->ymin + float(win->sizey) * f / UI_SCALE_FAC; + /* Tag user preferences as dirty. */ + U.runtime.is_dirty = true; + } + } + wmWindow *win_other; /* First check if there is another main window remaining. */ @@ -472,7 +515,6 @@ void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win) } } - 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); @@ -1148,23 +1190,23 @@ wmWindow *WM_window_open(bContext *C, const float native_pixel_size = GHOST_GetNativePixelSize( static_cast(win_prev->ghostwin)); /* Convert to native OS window coordinates. */ - rect.xmin = win_prev->posx + (x / native_pixel_size); - rect.ymin = win_prev->posy + (y / native_pixel_size); + rect.xmin = x / native_pixel_size; + rect.ymin = y / native_pixel_size; sizex /= native_pixel_size; sizey /= native_pixel_size; if (alignment == WIN_ALIGN_LOCATION_CENTER) { /* Window centered around x,y location. */ - rect.xmin -= sizex / 2; - rect.ymin -= sizey / 2; + rect.xmin += win_prev->posx - (sizex / 2); + rect.ymin += win_prev->posy - (sizey / 2); } else if (alignment == WIN_ALIGN_PARENT_CENTER) { /* Centered within parent. X,Y as offsets from there. */ - rect.xmin += (win_prev->sizex - sizex) / 2; - rect.ymin += (win_prev->sizey - sizey) / 2; + rect.xmin += win_prev->posx + ((win_prev->sizex - sizex) / 2); + rect.ymin += win_prev->posy + ((win_prev->sizey - sizey) / 2); } - else { - /* Positioned absolutely within parent bounds. */ + else if (alignment == WIN_ALIGN_ABSOLUTE) { + /* Positioned absolutely in desktop coordinates. */ } rect.xmax = rect.xmin + sizex; @@ -1282,6 +1324,43 @@ wmWindow *WM_window_open(bContext *C, return nullptr; } +wmWindow *WM_window_open_temp(bContext *C, const char *title, int space_type, bool dialog) +{ + rcti rect; + WM_window_dpi_set_userdef(CTX_wm_window(C)); + eWindowAlignment align; + rctf *stored_bounds = stored_window_bounds(eSpace_Type(space_type)); + const bool bounds_valid = (stored_bounds && (BLI_rctf_size_x(stored_bounds) > 150.0f) && + (BLI_rctf_size_y(stored_bounds) > 100.0f)); + const bool mm_placement = WM_capabilities_flag() & WM_CAPABILITY_MULTIMONITOR_PLACEMENT; + + if (bounds_valid && mm_placement) { + rect.xmin = (int)(stored_bounds->xmin * UI_SCALE_FAC); + rect.ymin = (int)(stored_bounds->ymin * UI_SCALE_FAC); + rect.xmax = (int)(stored_bounds->xmax * UI_SCALE_FAC); + rect.ymax = (int)(stored_bounds->ymax * UI_SCALE_FAC); + align = WIN_ALIGN_ABSOLUTE; + } + else { + wmWindow *win_cur = CTX_wm_window(C); + const int width = int((bounds_valid ? BLI_rctf_size_x(stored_bounds) : 800.0f) * UI_SCALE_FAC); + const int height = int((bounds_valid ? BLI_rctf_size_y(stored_bounds) : 600.0f) * + UI_SCALE_FAC); + /* Use eventstate, not event from _invoke, so this can be called through exec(). */ + const wmEvent *event = win_cur->eventstate; + rect.xmin = event->xy[0]; + rect.ymin = event->xy[1]; + rect.xmax = event->xy[0] + width; + rect.ymax = event->xy[1] + height; + align = WIN_ALIGN_LOCATION_CENTER; + } + + wmWindow *win = WM_window_open( + C, title, &rect, space_type, false, dialog, true, align, nullptr, nullptr); + + return win; +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -2242,6 +2321,9 @@ eWM_CapabilitiesFlag WM_capabilities_flag() if (ghost_flag & GHOST_kCapabilityCursorGenerator) { flag |= WM_CAPABILITY_CURSOR_GENERATOR; } + if (ghost_flag & GHOST_kCapabilityMultiMonitorPlacement) { + flag |= WM_CAPABILITY_MULTIMONITOR_PLACEMENT; + } return flag; }