Enable setting an initial position and maximized launch (#2817)

This PR includes the code changes that enable users to set an initial position
(top left corner) and launch maximized. There are some corner cases:

1. Multiple monitors. The user should be able to set the initial position to
any monitors attached. For the monitors on the left side of the major monitor,
the initial position values are negative.

2. If the initial position is larger than the screen resolution and the window
is off-screen, the current solution is to check if the top left corner of the
window intersect with any monitors. If it is not, we set the initial position
to the top left corner of the nearest monitor.

3. If the user wants to launch maximized and provides an initial position, we
launch the maximized window on the monitor where the position is located.

# Testing

To test:
1. Check-out this branch and build on VS2019
2. Launch Terminal, and open Settings. Then close the terminal.
3. Add the following setting into Json settings file as part of "globals", just
after "initialRows":
  "initialPosition": "1000, 1000",
  "launchMode": "default"

My test data:
I have already tested with the following variables:
  1. showTabsInTitlebar true or false
  2. The initial position of the top left corner of the window
  3. Whether to launch maximized
  4. The DPI of the monitor

Test data combination:

Non-client island window (showTabsInTitlebar true)

1. Three monitors with the same DPI (100%), left, middle and right, with the
middle one as the primary, resolution: 1980 * 1200, 1920 * 1200, 1920 * 1080
    launchMode: default
      In-Screen test: (0, 0), (1000, 500), (2000, 300), (-1000, 400),
        (-100, 200), (-2000, 100), (0, 1119)
      out-of-screen:
        (200, -200): initialize to (0, 0)
        (200, 1500): initialize to (0, 0)
        (2000, -200): initialize to (1920, 0)
        (2500, 2000): initialize to (1920, 0)
        (4000 100): initialize to (1920, 0)
        (-1000, -100): initialize to (-1920, 0)
        (-3000, 100): initialize to (-1920, 0)
        (10000, -10000): initialize to (1920, 0)
        (-10000, 10000): initialize to (-1920, 0)
        (0, -10000): initialize to (0, 0)
        (0, -1):  initialize to (0, 0)
        (0, 1200):  initialize to (0, 0)
    launch mode: maximize
        (100, 100)
        (-1000, 100): On the left monitor
        (0, -2000): On the primary monitor
        (10000, 10000): On the primary monitor


2. Left monitor 200% DPI, primary monitor 100% DPI
    In screen: (-1900, 100), (-3000, 100), (-1000, 100)
    our-of-screen: (-8000, 100): initialize at (-1920, 0)
    launch Maximized:  (-100, 100): launch maximized on the left monitor
      correctly

3. Left monitor 100% DPI, primary monitor 200% DPI
    In-screen: (-1900, 100), (300, 100), (-800, 100), (-200, 100)
    out-of-screen: (-3000, 100): initialize at (-1920, 0)
    launch maximized: (100, 100), (-1000, 100)

For client island window, the test data is the same as above.

Issues:

1. If we set the initial position on the monitor with a different DPI as the
primary monitor, and the window "lays" across two monitors, then the window
still renders as it is on the primary monitor. The size of the window is
correct.

Closes #1043
This commit is contained in:
Kaiyu Wang 2019-10-16 21:51:50 -07:00 committed by Dustin L. Howett (MSFT)
parent b293b2bada
commit 35d7d20a07
12 changed files with 378 additions and 62 deletions

View file

@ -343,6 +343,60 @@ namespace winrt::TerminalApp::implementation
return TermControl::GetProposedDimensions(settings, dpi);
}
// Method Description:
// - Get the launch mode in json settings file. Now there
// two launch mode: default, maximized. Default means the window
// will launch according to the launch dimensions provided. Maximized
// means the window will launch as a maximized window
// Arguments:
// - <none>
// Return Value:
// - LaunchMode enum that indicates the launch mode
LaunchMode App::GetLaunchMode()
{
if (!_loadedInitialSettings)
{
// Load settings if we haven't already
LoadSettings();
}
return _settings->GlobalSettings().GetLaunchMode();
}
// Method Description:
// - Get the user defined initial position from Json settings file.
// This position represents the top left corner of the Terminal window.
// This setting is optional, if not provided, we will use the system
// default size, which is provided in IslandWindow::MakeWindow.
// Arguments:
// - defaultInitialX: the system default x coordinate value
// - defaultInitialY: the system defualt y coordinate value
// Return Value:
// - a point containing the requested initial position in pixels.
winrt::Windows::Foundation::Point App::GetLaunchInitialPositions(int32_t defaultInitialX, int32_t defaultInitialY)
{
if (!_loadedInitialSettings)
{
// Load settings if we haven't already
LoadSettings();
}
winrt::Windows::Foundation::Point point((float)defaultInitialX, (float)defaultInitialY);
auto initialX = _settings->GlobalSettings().GetInitialX();
auto initialY = _settings->GlobalSettings().GetInitialY();
if (initialX.has_value())
{
point.X = gsl::narrow_cast<float>(initialX.value());
}
if (initialY.has_value())
{
point.Y = gsl::narrow_cast<float>(initialY.value());
}
return point;
}
bool App::GetShowTabsInTitlebar()
{
if (!_loadedInitialSettings)

View file

@ -31,6 +31,8 @@ namespace winrt::TerminalApp::implementation
void LoadSettings();
Windows::Foundation::Point GetLaunchDimensions(uint32_t dpi);
winrt::Windows::Foundation::Point GetLaunchInitialPositions(int32_t defaultInitialX, int32_t defaultInitialY);
LaunchMode GetLaunchMode();
bool GetShowTabsInTitlebar();
Windows::UI::Xaml::UIElement GetRoot() noexcept;

View file

@ -3,9 +3,16 @@
namespace TerminalApp
{
enum LaunchMode
{
DefaultMode,
MaximizedMode,
};
delegate void LastTabClosedEventArgs();
[default_interface] runtimeclass App : Microsoft.Toolkit.Win32.UI.XamlHost.XamlApplication
{
App();
void Initialize();
@ -18,12 +25,13 @@ namespace TerminalApp
void Create();
void LoadSettings();
Windows.UI.Xaml.UIElement GetRoot();
String Title { get; };
Windows.Foundation.Point GetLaunchDimensions(UInt32 dpi);
Windows.Foundation.Point GetLaunchInitialPositions(Int32 defaultInitialX, Int32 defaultInitialY);
LaunchMode GetLaunchMode();
Boolean GetShowTabsInTitlebar();
void TitlebarClicked();
void WindowCloseButtonClicked();

View file

@ -7,6 +7,7 @@
#include "../../inc/DefaultSettings.h"
#include "Utils.h"
#include "JsonUtils.h"
#include <sstream>
using namespace TerminalApp;
using namespace winrt::Microsoft::Terminal::Settings;
@ -20,12 +21,15 @@ static constexpr std::string_view DefaultProfileKey{ "defaultProfile" };
static constexpr std::string_view AlwaysShowTabsKey{ "alwaysShowTabs" };
static constexpr std::string_view InitialRowsKey{ "initialRows" };
static constexpr std::string_view InitialColsKey{ "initialCols" };
static constexpr std::string_view InitialPositionKey{ "initialPosition" };
static constexpr std::string_view ShowTitleInTitlebarKey{ "showTerminalTitleInTitlebar" };
static constexpr std::string_view RequestedThemeKey{ "requestedTheme" };
static constexpr std::string_view ShowTabsInTitlebarKey{ "showTabsInTitlebar" };
static constexpr std::string_view WordDelimitersKey{ "wordDelimiters" };
static constexpr std::string_view CopyOnSelectKey{ "copyOnSelect" };
static constexpr std::string_view LaunchModeKey{ "launchMode" };
static constexpr std::wstring_view DefaultLaunchModeValue{ L"default" };
static constexpr std::wstring_view MaximizedLaunchModeValue{ L"maximized" };
static constexpr std::wstring_view LightThemeValue{ L"light" };
static constexpr std::wstring_view DarkThemeValue{ L"dark" };
static constexpr std::wstring_view SystemThemeValue{ L"system" };
@ -37,11 +41,14 @@ GlobalAppSettings::GlobalAppSettings() :
_alwaysShowTabs{ true },
_initialRows{ DEFAULT_ROWS },
_initialCols{ DEFAULT_COLS },
_initialX{},
_initialY{},
_showTitleInTitlebar{ true },
_showTabsInTitlebar{ true },
_requestedTheme{ ElementTheme::Default },
_wordDelimiters{ DEFAULT_WORD_DELIMITERS },
_copyOnSelect{ false }
_copyOnSelect{ false },
_launchMode{ LaunchMode::DefaultMode }
{
}
@ -124,6 +131,16 @@ void GlobalAppSettings::SetCopyOnSelect(const bool copyOnSelect) noexcept
_copyOnSelect = copyOnSelect;
}
LaunchMode GlobalAppSettings::GetLaunchMode() const noexcept
{
return _launchMode;
}
void GlobalAppSettings::SetLaunchMode(const LaunchMode launchMode)
{
_launchMode = launchMode;
}
#pragma region ExperimentalSettings
bool GlobalAppSettings::GetShowTabsInTitlebar() const noexcept
{
@ -134,6 +151,17 @@ void GlobalAppSettings::SetShowTabsInTitlebar(const bool showTabsInTitlebar) noe
{
_showTabsInTitlebar = showTabsInTitlebar;
}
std::optional<int32_t> GlobalAppSettings::GetInitialX() const noexcept
{
return _initialX;
}
std::optional<int32_t> GlobalAppSettings::GetInitialY() const noexcept
{
return _initialY;
}
#pragma endregion
// Method Description:
@ -147,6 +175,7 @@ void GlobalAppSettings::ApplyToSettings(TerminalSettings& settings) const noexce
settings.KeyBindings(GetKeybindings());
settings.InitialRows(_initialRows);
settings.InitialCols(_initialCols);
settings.WordDelimiters(_wordDelimiters);
settings.CopyOnSelect(_copyOnSelect);
}
@ -164,11 +193,13 @@ Json::Value GlobalAppSettings::ToJson() const
jsonObject[JsonKey(DefaultProfileKey)] = winrt::to_string(Utils::GuidToString(_defaultProfile));
jsonObject[JsonKey(InitialRowsKey)] = _initialRows;
jsonObject[JsonKey(InitialColsKey)] = _initialCols;
jsonObject[JsonKey(InitialPositionKey)] = _SerializeInitialPosition(_initialX, _initialY);
jsonObject[JsonKey(AlwaysShowTabsKey)] = _alwaysShowTabs;
jsonObject[JsonKey(ShowTitleInTitlebarKey)] = _showTitleInTitlebar;
jsonObject[JsonKey(ShowTabsInTitlebarKey)] = _showTabsInTitlebar;
jsonObject[JsonKey(WordDelimitersKey)] = winrt::to_string(_wordDelimiters);
jsonObject[JsonKey(CopyOnSelectKey)] = _copyOnSelect;
jsonObject[JsonKey(LaunchModeKey)] = winrt::to_string(_SerializeLaunchMode(_launchMode));
jsonObject[JsonKey(RequestedThemeKey)] = winrt::to_string(_SerializeTheme(_requestedTheme));
jsonObject[JsonKey(KeybindingsKey)] = _keybindings->ToJson();
@ -208,7 +239,10 @@ void GlobalAppSettings::LayerJson(const Json::Value& json)
{
_initialCols = initialCols.asInt();
}
if (auto initialPosition{ json[JsonKey(InitialPositionKey)] })
{
_ParseInitialPosition(GetWstringFromJson(initialPosition), _initialX, _initialY);
}
if (auto showTitleInTitlebar{ json[JsonKey(ShowTitleInTitlebarKey)] })
{
_showTitleInTitlebar = showTitleInTitlebar.asBool();
@ -229,6 +263,11 @@ void GlobalAppSettings::LayerJson(const Json::Value& json)
_copyOnSelect = copyOnSelect.asBool();
}
if (auto launchMode{ json[JsonKey(LaunchModeKey)] })
{
_launchMode = _ParseLaunchMode(GetWstringFromJson(launchMode));
}
if (auto requestedTheme{ json[JsonKey(RequestedThemeKey)] })
{
_requestedTheme = _ParseTheme(GetWstringFromJson(requestedTheme));
@ -281,6 +320,117 @@ std::wstring_view GlobalAppSettings::_SerializeTheme(const ElementTheme theme) n
}
}
// Method Description:
// - Helper function for converting the initial position string into
// 2 coordinate values. We allow users to only provide one coordinate,
// thus, we use comma as the separater:
// (100, 100): standard input string
// (, 100), (100, ): if a value is missing, we set this value as a default
// (,): both x and y are set to default
// (abc, 100): if a value is not valid, we treat it as default
// (100, 100, 100): we only read the first two values, this is equivalent to (100, 100)
// Arguments:
// - initialPosition: the initial position string from json
// initialX: reference to the _initialX member
// initialY: reference to the _initialY member
// Return Value:
// - None
void GlobalAppSettings::_ParseInitialPosition(const std::wstring& initialPosition,
std::optional<int32_t>& initialX,
std::optional<int32_t>& initialY) noexcept
{
const wchar_t singleCharDelim = L',';
std::wstringstream tokenStream(initialPosition);
std::wstring token;
uint8_t initialPosIndex = 0;
// Get initial position values till we run out of delimiter separated values in the stream
// or we hit max number of allowable values (= 2)
// Non-numeral values or empty string will be caught as exception and we do not assign them
for (; std::getline(tokenStream, token, singleCharDelim) && (initialPosIndex < 2); initialPosIndex++)
{
try
{
int32_t position = std::stoi(token);
if (initialPosIndex == 0)
{
initialX.emplace(position);
}
if (initialPosIndex == 1)
{
initialY.emplace(position);
}
}
catch (...)
{
// Do nothing
}
}
}
// Method Description:
// - Helper function for converting X/Y initial positions to a string
// value.
// Arguments:
// - initialX: reference to the _initialX member
// initialY: reference to the _initialY member
// Return Value:
// - The concatenated string for the the current initialX and initialY
std::string GlobalAppSettings::_SerializeInitialPosition(const std::optional<int32_t>& initialX,
const std::optional<int32_t>& initialY) noexcept
{
std::string serializedInitialPos = "";
if (initialX.has_value())
{
serializedInitialPos += initialX.value();
}
serializedInitialPos += ", ";
if (initialY.has_value())
{
serializedInitialPos += initialY.value();
}
return serializedInitialPos;
}
// Method Description:
// - Helper function for converting the user-specified launch mode
// to a LaunchMode enum value
// Arguments:
// - launchModeString: The string value from the settings file to parse
// Return Value:
// - The corresponding enum value which maps to the string provided by the user
LaunchMode GlobalAppSettings::_ParseLaunchMode(const std::wstring& launchModeString) noexcept
{
if (launchModeString == MaximizedLaunchModeValue)
{
return LaunchMode::MaximizedMode;
}
return LaunchMode::DefaultMode;
}
// Method Description:
// - Helper function for converting a LaunchMode to its corresponding string
// value.
// Arguments:
// - launchMode: The enum value to convert to a string.
// Return Value:
// - The string value for the given LaunchMode
std::wstring_view GlobalAppSettings::_SerializeLaunchMode(const LaunchMode launchMode) noexcept
{
switch (launchMode)
{
case LaunchMode::MaximizedMode:
return MaximizedLaunchModeValue;
default:
return DefaultLaunchModeValue;
}
}
// Method Description:
// - Adds the given colorscheme to our map of schemes, using its name as the key.
// Arguments:

View file

@ -61,6 +61,13 @@ public:
bool GetCopyOnSelect() const noexcept;
void SetCopyOnSelect(const bool copyOnSelect) noexcept;
std::optional<int32_t> GetInitialX() const noexcept;
std::optional<int32_t> GetInitialY() const noexcept;
winrt::TerminalApp::LaunchMode GetLaunchMode() const noexcept;
void SetLaunchMode(const winrt::TerminalApp::LaunchMode launchMode);
winrt::Windows::UI::Xaml::ElementTheme GetRequestedTheme() const noexcept;
Json::Value ToJson() const;
@ -78,6 +85,9 @@ private:
int32_t _initialRows;
int32_t _initialCols;
std::optional<int32_t> _initialX;
std::optional<int32_t> _initialY;
bool _showStatusline;
bool _alwaysShowTabs;
bool _showTitleInTitlebar;
@ -87,9 +97,21 @@ private:
bool _copyOnSelect;
winrt::Windows::UI::Xaml::ElementTheme _requestedTheme;
winrt::TerminalApp::LaunchMode _launchMode;
static winrt::Windows::UI::Xaml::ElementTheme _ParseTheme(const std::wstring& themeString) noexcept;
static std::wstring_view _SerializeTheme(const winrt::Windows::UI::Xaml::ElementTheme theme) noexcept;
static void _ParseInitialPosition(const std::wstring& initialPosition,
std::optional<int32_t>& initialX,
std::optional<int32_t>& initialY) noexcept;
static std::string _SerializeInitialPosition(const std::optional<int32_t>& initialX,
const std::optional<int32_t>& initialY) noexcept;
static std::wstring_view _SerializeLaunchMode(const winrt::TerminalApp::LaunchMode launchMode) noexcept;
static winrt::TerminalApp::LaunchMode _ParseLaunchMode(const std::wstring& launchModeString) noexcept;
friend class TerminalAppLocalTests::SettingsTests;
friend class TerminalAppLocalTests::ColorSchemeTests;
};

View file

@ -33,7 +33,8 @@ AppHost::AppHost() noexcept :
auto pfn = std::bind(&AppHost::_HandleCreateWindow,
this,
std::placeholders::_1,
std::placeholders::_2);
std::placeholders::_2,
std::placeholders::_3);
_window->SetCreateCallback(pfn);
_window->MakeWindow();
@ -129,63 +130,113 @@ void AppHost::LastTabClosed(const winrt::Windows::Foundation::IInspectable& /*se
// - proposedRect: The location and size of the window that we're about to
// create. We'll use this rect to determine which monitor the window is about
// to appear on.
// - launchMode: A LaunchMode enum reference that indicates the launch mode
// Return Value:
// - <none>
void AppHost::_HandleCreateWindow(const HWND hwnd, const RECT proposedRect)
// - None
void AppHost::_HandleCreateWindow(const HWND hwnd, RECT proposedRect, winrt::TerminalApp::LaunchMode& launchMode)
{
// Find nearest montitor.
HMONITOR hmon = MonitorFromRect(&proposedRect, MONITOR_DEFAULTTONEAREST);
launchMode = _app.GetLaunchMode();
// This API guarantees that dpix and dpiy will be equal, but neither is an
// optional parameter so give two UINTs.
UINT dpix = USER_DEFAULT_SCREEN_DPI;
UINT dpiy = USER_DEFAULT_SCREEN_DPI;
// If this fails, we'll use the default of 96.
GetDpiForMonitor(hmon, MDT_EFFECTIVE_DPI, &dpix, &dpiy);
// Acquire the actual intial position
winrt::Windows::Foundation::Point initialPosition = _app.GetLaunchInitialPositions(proposedRect.left, proposedRect.top);
proposedRect.left = gsl::narrow_cast<long>(initialPosition.X);
proposedRect.top = gsl::narrow_cast<long>(initialPosition.Y);
auto initialSize = _app.GetLaunchDimensions(dpix);
const short _currentWidth = Utils::ClampToShortMax(
static_cast<long>(ceil(initialSize.X)), 1);
const short _currentHeight = Utils::ClampToShortMax(
static_cast<long>(ceil(initialSize.Y)), 1);
// Create a RECT from our requested client size
auto nonClient = Viewport::FromDimensions({ _currentWidth,
_currentHeight })
.ToRect();
// Get the size of a window we'd need to host that client rect. This will
// add the titlebar space.
if (_useNonClientArea)
long adjustedHeight = 0;
long adjustedWidth = 0;
if (launchMode == winrt::TerminalApp::LaunchMode::DefaultMode)
{
// If we're in NC tabs mode, do the math ourselves. Get the margins
// we're using for the window - this will include the size of the
// titlebar content.
auto pNcWindow = static_cast<NonClientIslandWindow*>(_window.get());
const MARGINS margins = pNcWindow->GetFrameMargins();
nonClient.left = 0;
nonClient.top = 0;
nonClient.right = margins.cxLeftWidth + nonClient.right + margins.cxRightWidth;
nonClient.bottom = margins.cyTopHeight + nonClient.bottom + margins.cyBottomHeight;
}
else
{
bool succeeded = AdjustWindowRectExForDpi(&nonClient, WS_OVERLAPPEDWINDOW, false, 0, dpix);
if (!succeeded)
// Find nearest montitor.
HMONITOR hmon = MonitorFromRect(&proposedRect, MONITOR_DEFAULTTONEAREST);
// Get nearest monitor information
MONITORINFO monitorInfo;
monitorInfo.cbSize = sizeof(MONITORINFO);
GetMonitorInfo(hmon, &monitorInfo);
// This API guarantees that dpix and dpiy will be equal, but neither is an
// optional parameter so give two UINTs.
UINT dpix = USER_DEFAULT_SCREEN_DPI;
UINT dpiy = USER_DEFAULT_SCREEN_DPI;
// If this fails, we'll use the default of 96.
GetDpiForMonitor(hmon, MDT_EFFECTIVE_DPI, &dpix, &dpiy);
// We need to check if the top left point of the titlebar of the window is within any screen
RECT offScreenTestRect;
offScreenTestRect.left = proposedRect.left;
offScreenTestRect.top = proposedRect.top;
offScreenTestRect.right = offScreenTestRect.left + 1;
offScreenTestRect.bottom = offScreenTestRect.top + 1;
bool isTitlebarIntersectWithMonitors = false;
EnumDisplayMonitors(
nullptr, &offScreenTestRect, [](HMONITOR, HDC, LPRECT, LPARAM lParam) -> BOOL {
auto intersectWithMonitor = reinterpret_cast<bool*>(lParam);
*intersectWithMonitor = true;
// Continue the enumeration
return FALSE;
},
reinterpret_cast<LPARAM>(&isTitlebarIntersectWithMonitors));
if (!isTitlebarIntersectWithMonitors)
{
// If we failed to get the correct window size for whatever reason, log
// the error and go on. We'll use whatever the control proposed as the
// size of our window, which will be at least close.
LOG_LAST_ERROR();
nonClient = Viewport::FromDimensions({ _currentWidth,
_currentHeight })
.ToRect();
// If the title bar is out-of-screen, we set the initial position to
// the top left corner of the nearest monitor
proposedRect.left = monitorInfo.rcWork.left;
proposedRect.top = monitorInfo.rcWork.top;
}
}
const auto adjustedHeight = nonClient.bottom - nonClient.top;
const auto adjustedWidth = nonClient.right - nonClient.left;
auto initialSize = _app.GetLaunchDimensions(dpix);
const short _currentWidth = Utils::ClampToShortMax(
static_cast<long>(ceil(initialSize.X)), 1);
const short _currentHeight = Utils::ClampToShortMax(
static_cast<long>(ceil(initialSize.Y)), 1);
// Create a RECT from our requested client size
auto nonClient = Viewport::FromDimensions({ _currentWidth,
_currentHeight })
.ToRect();
// Get the size of a window we'd need to host that client rect. This will
// add the titlebar space.
if (_useNonClientArea)
{
// If we're in NC tabs mode, do the math ourselves. Get the margins
// we're using for the window - this will include the size of the
// titlebar content.
const auto pNcWindow = static_cast<NonClientIslandWindow*>(_window.get());
const MARGINS margins = pNcWindow->GetFrameMargins();
nonClient.left = 0;
nonClient.top = 0;
nonClient.right = margins.cxLeftWidth + nonClient.right + margins.cxRightWidth;
nonClient.bottom = margins.cyTopHeight + nonClient.bottom + margins.cyBottomHeight;
}
else
{
bool succeeded = AdjustWindowRectExForDpi(&nonClient, WS_OVERLAPPEDWINDOW, false, 0, dpix);
if (!succeeded)
{
// If we failed to get the correct window size for whatever reason, log
// the error and go on. We'll use whatever the control proposed as the
// size of our window, which will be at least close.
LOG_LAST_ERROR();
nonClient = Viewport::FromDimensions({ _currentWidth,
_currentHeight })
.ToRect();
}
// For client island scenario, there is an invisible border of 8 pixels.
// We need to remove this border to guarantee the left edge of the window
// coincides with the screen
const auto pCWindow = static_cast<IslandWindow*>(_window.get());
const RECT frame = pCWindow->GetFrameBorderMargins(dpix);
proposedRect.left += frame.left;
}
adjustedHeight = nonClient.bottom - nonClient.top;
adjustedWidth = nonClient.right - nonClient.left;
}
const COORD origin{ gsl::narrow<short>(proposedRect.left),
gsl::narrow<short>(proposedRect.top) };
@ -193,7 +244,6 @@ void AppHost::_HandleCreateWindow(const HWND hwnd, const RECT proposedRect)
Utils::ClampToShortMax(adjustedHeight, 1) };
const auto newPos = Viewport::FromDimensions(origin, dimensions);
bool succeeded = SetWindowPos(hwnd,
nullptr,
newPos.Left(),
@ -202,6 +252,10 @@ void AppHost::_HandleCreateWindow(const HWND hwnd, const RECT proposedRect)
newPos.Height(),
SWP_NOACTIVATE | SWP_NOZORDER);
// Refresh the dpi of HWND becuase the dpi where the window will launch may be different
// at this time
_window->RefreshCurrentDPI();
// If we can't resize the window, that's really okay. We can just go on with
// the originally proposed window size.
LOG_LAST_ERROR_IF(!succeeded);

View file

@ -24,7 +24,7 @@ private:
std::unique_ptr<IslandWindow> _window;
winrt::TerminalApp::App _app;
void _HandleCreateWindow(const HWND hwnd, const RECT proposedRect);
void _HandleCreateWindow(const HWND hwnd, RECT proposedRect, winrt::TerminalApp::LaunchMode& launchMode);
void _UpdateTitleBarContent(const winrt::Windows::Foundation::IInspectable& sender,
const winrt::Windows::UI::Xaml::UIElement& arg);
void _UpdateTheme(const winrt::TerminalApp::App&,

View file

@ -226,6 +226,15 @@ public:
PostMessageW(_window.get(), CM_UPDATE_TITLE, 0, reinterpret_cast<LPARAM>(nullptr));
}
// Method Description:
// Reset the current dpi of the window. This method is only called after we change the
// initial launch position. This makes sure the dpi is consistent with the monitor on which
// the window will launch
void RefreshCurrentDPI()
{
_currentDpi = GetDpiForWindow(_window.get());
}
protected:
using base_type = BaseWindow<T>;
wil::unique_hwnd _window;

View file

@ -88,7 +88,7 @@ void IslandWindow::Close()
// window.
// Return Value:
// - <none>
void IslandWindow::SetCreateCallback(std::function<void(const HWND, const RECT)> pfn) noexcept
void IslandWindow::SetCreateCallback(std::function<void(const HWND, const RECT, winrt::TerminalApp::LaunchMode& launchMode)> pfn) noexcept
{
_pfnCreateCallback = pfn;
}
@ -110,12 +110,19 @@ void IslandWindow::_HandleCreateWindow(const WPARAM, const LPARAM lParam) noexce
rc.right = rc.left + pcs->cx;
rc.bottom = rc.top + pcs->cy;
winrt::TerminalApp::LaunchMode launchMode = winrt::TerminalApp::LaunchMode::DefaultMode;
if (_pfnCreateCallback)
{
_pfnCreateCallback(_window.get(), rc);
_pfnCreateCallback(_window.get(), rc, launchMode);
}
ShowWindow(_window.get(), SW_SHOW);
int nCmdShow = SW_SHOW;
if (launchMode == winrt::TerminalApp::LaunchMode::MaximizedMode)
{
nCmdShow = SW_MAXIMIZE;
}
ShowWindow(_window.get(), nCmdShow);
UpdateWindow(_window.get());
}
@ -236,6 +243,15 @@ IRawElementProviderSimple* IslandWindow::_GetUiaProvider()
return _pUiaProvider;
}
RECT IslandWindow::GetFrameBorderMargins(unsigned int currentDpi)
{
const auto windowStyle = GetWindowStyle(_window.get());
const auto targetStyle = windowStyle & ~WS_DLGFRAME;
RECT frame{};
AdjustWindowRectExForDpi(&frame, targetStyle, false, GetWindowExStyle(_window.get()), currentDpi);
return frame;
}
// Method Description:
// - Called when the window has been resized (or maximized)
// Arguments:

View file

@ -23,6 +23,7 @@ public:
[[nodiscard]] virtual LRESULT MessageHandler(UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept override;
IRawElementProviderSimple* _GetUiaProvider();
RECT GetFrameBorderMargins(unsigned int currentDpi);
void OnResize(const UINT width, const UINT height) override;
void OnMinimize() override;
void OnRestore() override;
@ -31,7 +32,7 @@ public:
virtual void Initialize();
void SetCreateCallback(std::function<void(const HWND, const RECT)> pfn) noexcept;
void SetCreateCallback(std::function<void(const HWND, const RECT, winrt::TerminalApp::LaunchMode& launchMode)> pfn) noexcept;
void UpdateTheme(const winrt::Windows::UI::Xaml::ElementTheme& requestedTheme);
@ -85,7 +86,7 @@ protected:
winrt::Windows::UI::Xaml::Controls::Grid _rootGrid;
std::function<void(const HWND, const RECT)> _pfnCreateCallback;
std::function<void(const HWND, const RECT, winrt::TerminalApp::LaunchMode& launchMode)> _pfnCreateCallback;
void _HandleCreateWindow(const WPARAM wParam, const LPARAM lParam) noexcept;
};

View file

@ -21,7 +21,6 @@ Author(s):
#include "IslandWindow.h"
#include "../../types/inc/Viewport.hpp"
#include <dwmapi.h>
#include <windowsx.h>
#include <wil\resource.h>
class NonClientIslandWindow : public IslandWindow

View file

@ -28,6 +28,7 @@ Abstract:
#include <stdlib.h>
#include <string.h>
#include <shellscalingapi.h>
#include <windowsx.h>
#include "../inc/LibraryIncludes.h"