Make the window name `_quake` special (#9785)
## Summary of the Pull Request This PR adds some special behavior to the window named "\_quake". * When creating the quake window, it ignores "initialRows" and "initialCols" and opens on the top half of the monitor. - It uses `initialPosition` to determine which monitor this is * It cannot be moved * It can only be vertically resized on the bottom border. * It's always in focus mode. - We should probably have an issue tracking "Allow showing tabs in focus mode"? Maybe? - This one element is maybe the one I'm least attached to When renaming a window to "\_quake", it adopts all those behaviors as well. It does not exit focus mode when leaving QM, nor does it resize back. That seemed unnecessary. ## References * As spec'ed in #9274 * See also #8888 ## PR Checklist * [x] In the pursuit of #653 * [x] I work here * [ ] Tests added/passed * [ ] Requires documentation to be updated, but I'm not gonna do any of that till quake mode is totally done. ## Detailed Description of the Pull Request / Additional comments Note that this doesn't do things like: * dropdown * global hotkey summon * summon to the current monitor * summon to the current desktop I'm doing #653 _very_ piecemeal, to try and make the PRs less egregious. ## Validation Steps Performed * validated that center on launch still works * validated that QM works on different monitors based on `initialPosition` * validated entering/exiting QM behaves as expected ## TODO! * [ ] When snapping the quake window between desktops with <kbd>win+shift+arrow</kbd>, the window doesn't horizontally re-size to the new monitor dimensions. It should.
This commit is contained in:
parent
3d09c7de1b
commit
dc6631355f
|
@ -1026,14 +1026,20 @@ hsl
|
|||
hstr
|
||||
hstring
|
||||
hsv
|
||||
HTBOTTOMLEFT
|
||||
HTBOTTOMRIGHT
|
||||
HTCAPTION
|
||||
HTCLIENT
|
||||
HTLEFT
|
||||
htm
|
||||
HTMAXBUTTON
|
||||
HTMINBUTTON
|
||||
html
|
||||
HTMLTo
|
||||
HTRIGHT
|
||||
HTTOP
|
||||
HTTOPLEFT
|
||||
HTTOPRIGHT
|
||||
hu
|
||||
hungapp
|
||||
HVP
|
||||
|
|
|
@ -285,12 +285,21 @@ namespace winrt::TerminalApp::implementation
|
|||
// launched _fullscreen_, toggle fullscreen mode. This will make sure
|
||||
// that the window size is _first_ set up as something sensible, so
|
||||
// leaving fullscreen returns to a reasonable size.
|
||||
//
|
||||
// We know at the start, that the root TerminalPage definitely isn't
|
||||
// in focus nor fullscreen mode. So "Toggle" here will always work
|
||||
// to "enable".
|
||||
const auto launchMode = this->GetLaunchMode();
|
||||
if (launchMode == LaunchMode::FullscreenMode)
|
||||
if (IsQuakeWindow())
|
||||
{
|
||||
_root->ToggleFocusMode();
|
||||
}
|
||||
else if (launchMode == LaunchMode::FullscreenMode)
|
||||
{
|
||||
_root->ToggleFullscreen();
|
||||
}
|
||||
else if (launchMode == LaunchMode::FocusMode || launchMode == LaunchMode::MaximizedFocusMode)
|
||||
else if (launchMode == LaunchMode::FocusMode ||
|
||||
launchMode == LaunchMode::MaximizedFocusMode)
|
||||
{
|
||||
_root->ToggleFocusMode();
|
||||
}
|
||||
|
@ -1439,4 +1448,9 @@ namespace winrt::TerminalApp::implementation
|
|||
}
|
||||
}
|
||||
|
||||
bool AppLogic::IsQuakeWindow() const noexcept
|
||||
{
|
||||
return _root->IsQuakeWindow();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -66,6 +66,7 @@ namespace winrt::TerminalApp::implementation
|
|||
void WindowName(const winrt::hstring& name);
|
||||
uint64_t WindowId();
|
||||
void WindowId(const uint64_t& id);
|
||||
bool IsQuakeWindow() const noexcept;
|
||||
|
||||
Windows::Foundation::Size GetLaunchDimensions(uint32_t dpi);
|
||||
bool CenterOnLaunch();
|
||||
|
@ -158,6 +159,7 @@ namespace winrt::TerminalApp::implementation
|
|||
FORWARDED_TYPED_EVENT(SetTaskbarProgress, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable, _root, SetTaskbarProgress);
|
||||
FORWARDED_TYPED_EVENT(IdentifyWindowsRequested, Windows::Foundation::IInspectable, Windows::Foundation::IInspectable, _root, IdentifyWindowsRequested);
|
||||
FORWARDED_TYPED_EVENT(RenameWindowRequested, Windows::Foundation::IInspectable, winrt::TerminalApp::RenameWindowRequestedArgs, _root, RenameWindowRequested);
|
||||
FORWARDED_TYPED_EVENT(IsQuakeWindowChanged, Windows::Foundation::IInspectable, Windows::Foundation::IInspectable, _root, IsQuakeWindowChanged);
|
||||
|
||||
#ifdef UNIT_TESTING
|
||||
friend class TerminalAppLocalTests::CommandlineTest;
|
||||
|
|
|
@ -52,6 +52,7 @@ namespace TerminalApp
|
|||
String WindowName;
|
||||
UInt64 WindowId;
|
||||
void RenameFailed();
|
||||
Boolean IsQuakeWindow();
|
||||
|
||||
Windows.Foundation.Size GetLaunchDimensions(UInt32 dpi);
|
||||
Boolean CenterOnLaunch { get; };
|
||||
|
@ -85,5 +86,6 @@ namespace TerminalApp
|
|||
event Windows.Foundation.TypedEventHandler<Object, Object> SetTaskbarProgress;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> IdentifyWindowsRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, RenameWindowRequestedArgs> RenameWindowRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> IsQuakeWindowChanged;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -272,12 +272,17 @@ namespace winrt::TerminalApp::implementation
|
|||
(_tabs.Size() > 1) ||
|
||||
_settings.GlobalSettings().AlwaysShowTabs());
|
||||
|
||||
// collapse/show the tabs themselves
|
||||
_tabView.Visibility(isVisible ? Visibility::Visible : Visibility::Collapsed);
|
||||
|
||||
// collapse/show the row that the tabs are in.
|
||||
// NaN is the special value XAML uses for "Auto" sizing.
|
||||
_tabRow.Height(isVisible ? NAN : 0);
|
||||
if (_tabView)
|
||||
{
|
||||
// collapse/show the tabs themselves
|
||||
_tabView.Visibility(isVisible ? Visibility::Visible : Visibility::Collapsed);
|
||||
}
|
||||
if (_tabRow)
|
||||
{
|
||||
// collapse/show the row that the tabs are in.
|
||||
// NaN is the special value XAML uses for "Auto" sizing.
|
||||
_tabRow.Height(isVisible ? NAN : 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
|
|
@ -42,6 +42,8 @@ namespace winrt
|
|||
using IInspectable = Windows::Foundation::IInspectable;
|
||||
}
|
||||
|
||||
static constexpr std::wstring_view QuakeWindowName{ L"_quake" };
|
||||
|
||||
namespace winrt::TerminalApp::implementation
|
||||
{
|
||||
TerminalPage::TerminalPage() :
|
||||
|
@ -2062,9 +2064,20 @@ namespace winrt::TerminalApp::implementation
|
|||
// - <none>
|
||||
void TerminalPage::ToggleFocusMode()
|
||||
{
|
||||
_isInFocusMode = !_isInFocusMode;
|
||||
_UpdateTabView();
|
||||
_FocusModeChangedHandlers(*this, nullptr);
|
||||
_SetFocusMode(!_isInFocusMode);
|
||||
}
|
||||
|
||||
void TerminalPage::_SetFocusMode(const bool inFocusMode)
|
||||
{
|
||||
// If we're the quake window, we must always be in focus mode.
|
||||
// Prevent leaving focus mode here.
|
||||
const bool newInFocusMode = inFocusMode || IsQuakeWindow();
|
||||
if (newInFocusMode != FocusMode())
|
||||
{
|
||||
_isInFocusMode = newInFocusMode;
|
||||
_UpdateTabView();
|
||||
_FocusModeChangedHandlers(*this, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
|
@ -2610,6 +2623,7 @@ namespace winrt::TerminalApp::implementation
|
|||
|
||||
winrt::fire_and_forget TerminalPage::WindowName(const winrt::hstring& value)
|
||||
{
|
||||
const bool oldIsQuakeMode = IsQuakeWindow();
|
||||
const bool changed = _WindowName != value;
|
||||
if (changed)
|
||||
{
|
||||
|
@ -2631,6 +2645,16 @@ namespace winrt::TerminalApp::implementation
|
|||
if (page->_startupState == StartupState::Initialized)
|
||||
{
|
||||
page->IdentifyWindow();
|
||||
|
||||
// If we're entering quake mode, or leaving it
|
||||
if (IsQuakeWindow() != oldIsQuakeMode)
|
||||
{
|
||||
// If we're entering Quake Mode from ~Focus Mode, then this will enter Focus Mode
|
||||
// If we're entering Quake Mode from Focus Mode, then this will do nothing
|
||||
// If we're leaving Quake Mode (we're already in Focus Mode), then this will do nothing
|
||||
_SetFocusMode(true);
|
||||
_IsQuakeWindowChangedHandlers(*this, nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2773,4 +2797,8 @@ namespace winrt::TerminalApp::implementation
|
|||
}
|
||||
}
|
||||
|
||||
bool TerminalPage::IsQuakeWindow() const noexcept
|
||||
{
|
||||
return WindowName() == QuakeWindowName;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -107,6 +107,7 @@ namespace winrt::TerminalApp::implementation
|
|||
void WindowId(const uint64_t& value);
|
||||
winrt::hstring WindowIdForDisplay() const noexcept;
|
||||
winrt::hstring WindowNameForDisplay() const noexcept;
|
||||
bool IsQuakeWindow() const noexcept;
|
||||
|
||||
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
|
||||
|
||||
|
@ -122,6 +123,7 @@ namespace winrt::TerminalApp::implementation
|
|||
TYPED_EVENT(Initialized, IInspectable, winrt::Windows::UI::Xaml::RoutedEventArgs);
|
||||
TYPED_EVENT(IdentifyWindowsRequested, IInspectable, IInspectable);
|
||||
TYPED_EVENT(RenameWindowRequested, Windows::Foundation::IInspectable, winrt::TerminalApp::RenameWindowRequestedArgs);
|
||||
TYPED_EVENT(IsQuakeWindowChanged, IInspectable, IInspectable);
|
||||
|
||||
private:
|
||||
friend struct TerminalPageT<TerminalPage>; // for Xaml to bind events
|
||||
|
@ -337,6 +339,8 @@ namespace winrt::TerminalApp::implementation
|
|||
|
||||
void _UpdateTeachingTipTheme(winrt::Windows::UI::Xaml::FrameworkElement element);
|
||||
|
||||
void _SetFocusMode(const bool inFocusMode);
|
||||
|
||||
#pragma region ActionHandlers
|
||||
// These are all defined in AppActionHandlers.cpp
|
||||
#define ON_ALL_ACTIONS(action) DECLARE_ACTION_HANDLER(action);
|
||||
|
|
|
@ -33,6 +33,7 @@ namespace TerminalApp
|
|||
String WindowNameForDisplay { get; };
|
||||
String WindowIdForDisplay { get; };
|
||||
void RenameFailed();
|
||||
Boolean IsQuakeWindow();
|
||||
|
||||
// We cannot use the default XAML APIs because we want to make sure
|
||||
// that there's only one application-global dialog visible at a time,
|
||||
|
@ -54,5 +55,6 @@ namespace TerminalApp
|
|||
event Windows.Foundation.TypedEventHandler<Object, Object> SetTaskbarProgress;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> IdentifyWindowsRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, RenameWindowRequestedArgs> RenameWindowRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> IsQuakeWindowChanged;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,6 +57,9 @@ AppHost::AppHost() noexcept :
|
|||
_window = std::make_unique<IslandWindow>();
|
||||
}
|
||||
|
||||
// Update our own internal state tracking if we're in quake mode or not.
|
||||
_IsQuakeWindowChanged(nullptr, nullptr);
|
||||
|
||||
// Tell the window to callback to us when it's about to handle a WM_CREATE
|
||||
auto pfn = std::bind(&AppHost::_HandleCreateWindow,
|
||||
this,
|
||||
|
@ -251,6 +254,7 @@ void AppHost::Initialize()
|
|||
_logic.SetTaskbarProgress({ this, &AppHost::SetTaskbarProgress });
|
||||
_logic.IdentifyWindowsRequested({ this, &AppHost::_IdentifyWindowsRequested });
|
||||
_logic.RenameWindowRequested({ this, &AppHost::_RenameWindowRequested });
|
||||
_logic.IsQuakeWindowChanged({ this, &AppHost::_IsQuakeWindowChanged });
|
||||
|
||||
_window->UpdateTitle(_logic.Title());
|
||||
|
||||
|
@ -379,39 +383,58 @@ void AppHost::_HandleCreateWindow(const HWND hwnd, RECT proposedRect, LaunchMode
|
|||
|
||||
// Get the size of a window we'd need to host that client rect. This will
|
||||
// add the titlebar space.
|
||||
const auto nonClientSize = _window->GetTotalNonClientExclusiveSize(dpix);
|
||||
adjustedWidth = islandWidth + nonClientSize.cx;
|
||||
adjustedHeight = islandHeight + nonClientSize.cy;
|
||||
const til::size nonClientSize = _window->GetTotalNonClientExclusiveSize(dpix);
|
||||
adjustedWidth = islandWidth + nonClientSize.width<long>();
|
||||
adjustedHeight = islandHeight + nonClientSize.height<long>();
|
||||
|
||||
const COORD dimensions{ Utils::ClampToShortMax(adjustedWidth, 1),
|
||||
Utils::ClampToShortMax(adjustedHeight, 1) };
|
||||
til::size dimensions{ Utils::ClampToShortMax(adjustedWidth, 1),
|
||||
Utils::ClampToShortMax(adjustedHeight, 1) };
|
||||
|
||||
if (centerOnLaunch)
|
||||
{
|
||||
// Find nearest monitor for the position that we've actually settled on
|
||||
HMONITOR hMonNearest = MonitorFromRect(&proposedRect, MONITOR_DEFAULTTONEAREST);
|
||||
MONITORINFO nearestMonitorInfo;
|
||||
nearestMonitorInfo.cbSize = sizeof(MONITORINFO);
|
||||
// Get monitor dimensions:
|
||||
GetMonitorInfo(hMonNearest, &nearestMonitorInfo);
|
||||
const COORD desktopDimensions{ gsl::narrow<short>(nearestMonitorInfo.rcWork.right - nearestMonitorInfo.rcWork.left),
|
||||
// Find nearest monitor for the position that we've actually settled on
|
||||
HMONITOR hMonNearest = MonitorFromRect(&proposedRect, MONITOR_DEFAULTTONEAREST);
|
||||
MONITORINFO nearestMonitorInfo;
|
||||
nearestMonitorInfo.cbSize = sizeof(MONITORINFO);
|
||||
// Get monitor dimensions:
|
||||
GetMonitorInfo(hMonNearest, &nearestMonitorInfo);
|
||||
const til::size desktopDimensions{ gsl::narrow<short>(nearestMonitorInfo.rcWork.right - nearestMonitorInfo.rcWork.left),
|
||||
gsl::narrow<short>(nearestMonitorInfo.rcWork.bottom - nearestMonitorInfo.rcWork.top) };
|
||||
// Move our proposed location into the center of that specific monitor.
|
||||
proposedRect.left = nearestMonitorInfo.rcWork.left +
|
||||
((desktopDimensions.X / 2) - (dimensions.X / 2));
|
||||
proposedRect.top = nearestMonitorInfo.rcWork.top +
|
||||
((desktopDimensions.Y / 2) - (dimensions.Y / 2));
|
||||
}
|
||||
const COORD origin{ gsl::narrow<short>(proposedRect.left),
|
||||
gsl::narrow<short>(proposedRect.top) };
|
||||
|
||||
const auto newPos = Viewport::FromDimensions(origin, dimensions);
|
||||
til::point origin{ (proposedRect.left),
|
||||
(proposedRect.top) };
|
||||
|
||||
if (_logic.IsQuakeWindow())
|
||||
{
|
||||
// If we just use rcWork by itself, we'll fail to account for the invisible
|
||||
// space reserved for the resize handles. So retrieve that size here.
|
||||
const til::size ncSize{ _window->GetTotalNonClientExclusiveSize(dpix) };
|
||||
const til::size availableSpace = desktopDimensions + nonClientSize;
|
||||
|
||||
origin = til::point{
|
||||
::base::ClampSub<long>(nearestMonitorInfo.rcWork.left, (nonClientSize.width() / 2)),
|
||||
(nearestMonitorInfo.rcWork.top)
|
||||
};
|
||||
dimensions = til::size{
|
||||
availableSpace.width(),
|
||||
availableSpace.height() / 2
|
||||
};
|
||||
launchMode = LaunchMode::FocusMode;
|
||||
}
|
||||
else if (centerOnLaunch)
|
||||
{
|
||||
// Move our proposed location into the center of that specific monitor.
|
||||
origin = til::point{
|
||||
(nearestMonitorInfo.rcWork.left + ((desktopDimensions.width() / 2) - (dimensions.width() / 2))),
|
||||
(nearestMonitorInfo.rcWork.top + ((desktopDimensions.height() / 2) - (dimensions.height() / 2)))
|
||||
};
|
||||
}
|
||||
|
||||
const til::rectangle newRect{ origin, dimensions };
|
||||
bool succeeded = SetWindowPos(hwnd,
|
||||
nullptr,
|
||||
newPos.Left(),
|
||||
newPos.Top(),
|
||||
newPos.Width(),
|
||||
newPos.Height(),
|
||||
newRect.left<int>(),
|
||||
newRect.top<int>(),
|
||||
newRect.width<int>(),
|
||||
newRect.height<int>(),
|
||||
SWP_NOACTIVATE | SWP_NOZORDER);
|
||||
|
||||
// Refresh the dpi of HWND because the dpi where the window will launch may be different
|
||||
|
@ -674,3 +697,9 @@ winrt::fire_and_forget AppHost::_RenameWindowRequested(const winrt::Windows::Fou
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AppHost::_IsQuakeWindowChanged(const winrt::Windows::Foundation::IInspectable&,
|
||||
const winrt::Windows::Foundation::IInspectable&)
|
||||
{
|
||||
_window->IsQuakeWindow(_logic.IsQuakeWindow());
|
||||
}
|
||||
|
|
|
@ -59,4 +59,7 @@ private:
|
|||
const winrt::TerminalApp::RenameWindowRequestedArgs args);
|
||||
|
||||
GUID _CurrentDesktopGuid();
|
||||
|
||||
void _IsQuakeWindowChanged(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
const winrt::Windows::Foundation::IInspectable& args);
|
||||
};
|
||||
|
|
|
@ -170,7 +170,7 @@ LRESULT IslandWindow::_OnSizing(const WPARAM wParam, const LPARAM lParam)
|
|||
{
|
||||
// If we haven't been given the callback that would adjust the dimension,
|
||||
// then we can't do anything, so just bail out.
|
||||
return FALSE;
|
||||
return false;
|
||||
}
|
||||
|
||||
LPRECT winRect = reinterpret_cast<LPRECT>(lParam);
|
||||
|
@ -182,8 +182,9 @@ LRESULT IslandWindow::_OnSizing(const WPARAM wParam, const LPARAM lParam)
|
|||
// 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);
|
||||
// If this fails, we'll use the default of 96. I think it can only fail for
|
||||
// bad parameters, which we won't have, so no big deal.
|
||||
LOG_IF_FAILED(GetDpiForMonitor(hmon, MDT_EFFECTIVE_DPI, &dpix, &dpiy));
|
||||
|
||||
const auto widthScale = base::ClampedNumeric<float>(dpix) / USER_DEFAULT_SCREEN_DPI;
|
||||
const long minWidthScaled = minimumWidth * widthScale;
|
||||
|
@ -195,6 +196,16 @@ LRESULT IslandWindow::_OnSizing(const WPARAM wParam, const LPARAM lParam)
|
|||
|
||||
auto clientHeight = winRect->bottom - winRect->top - nonClientSize.cy;
|
||||
|
||||
// If we're the quake window, prevent resizing on all sides except the
|
||||
// bottom. This also applies to resizing with the Alt+Space menu
|
||||
if (IsQuakeWindow() && wParam != WMSZ_BOTTOM)
|
||||
{
|
||||
// Stuff our current window size into the lParam, and return true. This
|
||||
// will tell User32 to use our current dimensions to resize to.
|
||||
::GetWindowRect(_window.get(), winRect);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (wParam != WMSZ_TOP && wParam != WMSZ_BOTTOM)
|
||||
{
|
||||
// If user has dragged anything but the top or bottom border (so e.g. left border,
|
||||
|
@ -244,7 +255,31 @@ LRESULT IslandWindow::_OnSizing(const WPARAM wParam, const LPARAM lParam)
|
|||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Handle the WM_MOVING message
|
||||
// - If we're the quake window, then we don't want to be able to be moved.
|
||||
// Immediately return our current window position, which will prevent us from
|
||||
// being moved at all.
|
||||
// Arguments:
|
||||
// - lParam: a LPRECT with the proposed window position, that should be filled
|
||||
// with the resultant position.
|
||||
// Return Value:
|
||||
// - true iff we handled this message.
|
||||
LRESULT IslandWindow::_OnMoving(const WPARAM /*wParam*/, const LPARAM lParam)
|
||||
{
|
||||
LPRECT winRect = reinterpret_cast<LPRECT>(lParam);
|
||||
// If we're the quake window, prevent moving the window
|
||||
if (IsQuakeWindow())
|
||||
{
|
||||
// Stuff our current window into the lParam, and return true. This
|
||||
// will tell User32 to use our current position to move to.
|
||||
::GetWindowRect(_window.get(), winRect);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void IslandWindow::Initialize()
|
||||
|
@ -405,6 +440,10 @@ long IslandWindow::_calculateTotalSize(const bool isWidth, const long clientSize
|
|||
{
|
||||
return _OnSizing(wparam, lparam);
|
||||
}
|
||||
case WM_MOVING:
|
||||
{
|
||||
return _OnMoving(wparam, lparam);
|
||||
}
|
||||
case WM_CLOSE:
|
||||
{
|
||||
// If the user wants to close the app by clicking 'X' button,
|
||||
|
@ -749,6 +788,7 @@ void IslandWindow::_SetIsBorderless(const bool borderlessEnabled)
|
|||
// Resize the window, with SWP_FRAMECHANGED, to trigger user32 to
|
||||
// recalculate the non/client areas
|
||||
const til::rectangle windowPos{ GetWindowRect() };
|
||||
|
||||
SetWindowPos(GetHandle(),
|
||||
HWND_TOP,
|
||||
windowPos.left<int>(),
|
||||
|
@ -931,5 +971,70 @@ winrt::fire_and_forget IslandWindow::SummonWindow()
|
|||
LOG_IF_WIN32_BOOL_FALSE(ShowWindow(_window.get(), SW_SHOW));
|
||||
}
|
||||
|
||||
bool IslandWindow::IsQuakeWindow() const noexcept
|
||||
{
|
||||
return _isQuakeWindow;
|
||||
}
|
||||
|
||||
void IslandWindow::IsQuakeWindow(bool isQuakeWindow) noexcept
|
||||
{
|
||||
if (_isQuakeWindow != isQuakeWindow)
|
||||
{
|
||||
_isQuakeWindow = isQuakeWindow;
|
||||
// Don't enter quake mode if we don't have an HWND yet
|
||||
if (IsQuakeWindow() && _window)
|
||||
{
|
||||
_enterQuakeMode();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void IslandWindow::_enterQuakeMode()
|
||||
{
|
||||
if (!_window)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RECT windowRect = GetWindowRect();
|
||||
HMONITOR hmon = MonitorFromRect(&windowRect, MONITOR_DEFAULTTONEAREST);
|
||||
MONITORINFO nearestMonitorInfo;
|
||||
|
||||
UINT dpix = USER_DEFAULT_SCREEN_DPI;
|
||||
UINT dpiy = USER_DEFAULT_SCREEN_DPI;
|
||||
// If this fails, we'll use the default of 96. I think it can only fail for
|
||||
// bad parameters, which we won't have, so no big deal.
|
||||
LOG_IF_FAILED(GetDpiForMonitor(hmon, MDT_EFFECTIVE_DPI, &dpix, &dpiy));
|
||||
|
||||
nearestMonitorInfo.cbSize = sizeof(MONITORINFO);
|
||||
// Get monitor dimensions:
|
||||
GetMonitorInfo(hmon, &nearestMonitorInfo);
|
||||
const til::size desktopDimensions{ (nearestMonitorInfo.rcWork.right - nearestMonitorInfo.rcWork.left),
|
||||
(nearestMonitorInfo.rcWork.bottom - nearestMonitorInfo.rcWork.top) };
|
||||
|
||||
// If we just use rcWork by itself, we'll fail to account for the invisible
|
||||
// space reserved for the resize handles. So retrieve that size here.
|
||||
const til::size ncSize{ GetTotalNonClientExclusiveSize(dpix) };
|
||||
const til::size availableSpace = desktopDimensions + ncSize;
|
||||
|
||||
const til::point origin{
|
||||
::base::ClampSub<long>(nearestMonitorInfo.rcWork.left, (ncSize.width() / 2)),
|
||||
(nearestMonitorInfo.rcWork.top)
|
||||
};
|
||||
const til::size dimensions{
|
||||
availableSpace.width(),
|
||||
availableSpace.height() / 2
|
||||
};
|
||||
|
||||
const til::rectangle newRect{ origin, dimensions };
|
||||
SetWindowPos(GetHandle(),
|
||||
HWND_TOP,
|
||||
newRect.left<int>(),
|
||||
newRect.top<int>(),
|
||||
newRect.width<int>(),
|
||||
newRect.height<int>(),
|
||||
SWP_SHOWWINDOW | SWP_FRAMECHANGED | SWP_NOACTIVATE);
|
||||
}
|
||||
|
||||
DEFINE_EVENT(IslandWindow, DragRegionClicked, _DragRegionClickedHandlers, winrt::delegate<>);
|
||||
DEFINE_EVENT(IslandWindow, WindowCloseButtonClicked, _windowCloseButtonClickedHandler, winrt::delegate<>);
|
||||
|
|
|
@ -40,7 +40,8 @@ public:
|
|||
|
||||
winrt::fire_and_forget SummonWindow();
|
||||
|
||||
#pragma endregion
|
||||
bool IsQuakeWindow() const noexcept;
|
||||
void IsQuakeWindow(bool isQuakeWindow) noexcept;
|
||||
|
||||
DECLARE_EVENT(DragRegionClicked, _DragRegionClickedHandlers, winrt::delegate<>);
|
||||
DECLARE_EVENT(WindowCloseButtonClicked, _windowCloseButtonClickedHandler, winrt::delegate<>);
|
||||
|
@ -66,6 +67,7 @@ protected:
|
|||
|
||||
void _HandleCreateWindow(const WPARAM wParam, const LPARAM lParam) noexcept;
|
||||
[[nodiscard]] LRESULT _OnSizing(const WPARAM wParam, const LPARAM lParam);
|
||||
[[nodiscard]] LRESULT _OnMoving(const WPARAM wParam, const LPARAM lParam);
|
||||
|
||||
bool _borderless{ false };
|
||||
bool _alwaysOnTop{ false };
|
||||
|
@ -87,6 +89,9 @@ protected:
|
|||
void _OnGetMinMaxInfo(const WPARAM wParam, const LPARAM lParam);
|
||||
long _calculateTotalSize(const bool isWidth, const long clientSize, const long nonClientSize);
|
||||
|
||||
bool _isQuakeWindow{ false };
|
||||
void _enterQuakeMode();
|
||||
|
||||
private:
|
||||
// This minimum width allows for width the tabs fit
|
||||
static constexpr long minimumWidth = 460L;
|
||||
|
|
|
@ -532,6 +532,23 @@ int NonClientIslandWindow::_GetResizeHandleHeight() const noexcept
|
|||
const auto originalRet = DefWindowProc(_window.get(), WM_NCHITTEST, 0, lParam);
|
||||
if (originalRet != HTCLIENT)
|
||||
{
|
||||
// If we're the quake window, suppress resizing on any side except the
|
||||
// bottom. I don't believe that this actually works on the top. That's
|
||||
// handled below.
|
||||
if (IsQuakeWindow())
|
||||
{
|
||||
switch (originalRet)
|
||||
{
|
||||
case HTBOTTOMRIGHT:
|
||||
case HTRIGHT:
|
||||
case HTTOPRIGHT:
|
||||
case HTTOP:
|
||||
case HTTOPLEFT:
|
||||
case HTLEFT:
|
||||
case HTBOTTOMLEFT:
|
||||
return HTCLIENT;
|
||||
}
|
||||
}
|
||||
return originalRet;
|
||||
}
|
||||
|
||||
|
@ -551,7 +568,9 @@ int NonClientIslandWindow::_GetResizeHandleHeight() const noexcept
|
|||
// the top of the drag bar is used to resize the window
|
||||
if (!_isMaximized && isOnResizeBorder)
|
||||
{
|
||||
return HTTOP;
|
||||
// However, if we're the quake window, then just return HTCAPTION so we
|
||||
// don't get a resize handle on the top.
|
||||
return IsQuakeWindow() ? HTCAPTION : HTTOP;
|
||||
}
|
||||
|
||||
return HTCAPTION;
|
||||
|
|
|
@ -25,6 +25,14 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned"
|
|||
point(static_cast<ptrdiff_t>(x), static_cast<ptrdiff_t>(y))
|
||||
{
|
||||
}
|
||||
constexpr point(ptrdiff_t width, int height) noexcept :
|
||||
point(width, static_cast<ptrdiff_t>(height))
|
||||
{
|
||||
}
|
||||
constexpr point(int width, ptrdiff_t height) noexcept :
|
||||
point(static_cast<ptrdiff_t>(width), height)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
point(size_t x, size_t y)
|
||||
|
@ -32,6 +40,11 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned"
|
|||
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(x).AssignIfValid(&_x));
|
||||
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(y).AssignIfValid(&_y));
|
||||
}
|
||||
point(long x, long y)
|
||||
{
|
||||
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(x).AssignIfValid(&_x));
|
||||
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(y).AssignIfValid(&_y));
|
||||
}
|
||||
|
||||
constexpr point(ptrdiff_t x, ptrdiff_t y) noexcept :
|
||||
_x(x),
|
||||
|
|
|
@ -40,6 +40,11 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned"
|
|||
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(width).AssignIfValid(&_width));
|
||||
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(height).AssignIfValid(&_height));
|
||||
}
|
||||
size(long width, long height)
|
||||
{
|
||||
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(width).AssignIfValid(&_width));
|
||||
THROW_HR_IF(E_ABORT, !base::MakeCheckedNum(height).AssignIfValid(&_height));
|
||||
}
|
||||
|
||||
constexpr size(ptrdiff_t width, ptrdiff_t height) noexcept :
|
||||
_width(width),
|
||||
|
|
Loading…
Reference in New Issue