terminal/src/cascadia/WindowsTerminal/IslandWindow.cpp

576 lines
20 KiB
C++
Raw Normal View History

// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "IslandWindow.h"
#include "../types/inc/Viewport.hpp"
#include "resource.h"
extern "C" IMAGE_DOS_HEADER __ImageBase;
using namespace winrt::Windows::UI;
using namespace winrt::Windows::UI::Composition;
using namespace winrt::Windows::UI::Xaml;
using namespace winrt::Windows::UI::Xaml::Hosting;
using namespace winrt::Windows::Foundation::Numerics;
using namespace ::Microsoft::Console::Types;
#define XAML_HOSTING_WINDOW_CLASS_NAME L"CASCADIA_HOSTING_WINDOW_CLASS"
IslandWindow::IslandWindow() noexcept :
_interopWindowHandle{ nullptr },
_rootGrid{ nullptr },
_source{ nullptr },
_pfnCreateCallback{ nullptr }
{
}
IslandWindow::~IslandWindow()
{
_source.Close();
}
// Method Description:
// - Create the actual window that we'll use for the application.
// Arguments:
// - <none>
// Return Value:
// - <none>
void IslandWindow::MakeWindow() noexcept
{
WNDCLASS wc{};
wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
wc.hInstance = reinterpret_cast<HINSTANCE>(&__ImageBase);
wc.lpszClassName = XAML_HOSTING_WINDOW_CLASS_NAME;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.hIcon = LoadIconW(wc.hInstance, MAKEINTRESOURCEW(IDI_APPICON));
RegisterClass(&wc);
WINRT_ASSERT(!_window);
// Create the window with the default size here - During the creation of the
2019-05-21 08:15:44 +02:00
// window, the system will give us a chance to set its size in WM_CREATE.
// WM_CREATE will be handled synchronously, before CreateWindow returns.
WINRT_VERIFY(CreateWindow(wc.lpszClassName,
L"Windows Terminal",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
nullptr,
nullptr,
wc.hInstance,
this));
WINRT_ASSERT(_window);
}
// Method Description:
// - Called when no tab is remaining to close the window.
// Arguments:
// - <none>
// Return Value:
// - <none>
void IslandWindow::Close()
{
PostQuitMessage(0);
}
// Method Description:
// - Set a callback to be called when we process a WM_CREATE message. This gives
// the AppHost a chance to resize the window to the proper size.
// Arguments:
// - pfn: a function to be called during the handling of WM_CREATE. It takes two
// parameters:
// * HWND: the HWND of the window that's being created.
// * RECT: The position on the screen that the system has proposed for our
// window.
// Return Value:
// - <none>
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
2019-10-17 06:51:50 +02:00
void IslandWindow::SetCreateCallback(std::function<void(const HWND, const RECT, winrt::TerminalApp::LaunchMode& launchMode)> pfn) noexcept
{
_pfnCreateCallback = pfn;
}
Snap to character grid when resizing window (#3181) When user resizes window, snap the size to align with the character grid (like e.g. putty, mintty and most unix terminals). Properly resolves arbitrary pane configuration (even with different font sizes and padding) trying to align each pane as close as possible. It also fixes terminal minimum size enforcement which was not quite well handled, especially with multiple panes. This PR does not however try to keep the terminals aligned at other user actions (e.g. font change or pane split). That is to be tracked by some other activity. Snapping is resolved in the pane tree, recursively, so it (hopefully) works for any possible layout. Along the way I had to clean up some things as so to make the resulting code not so cumbersome: 1. Pane.cpp: Replaced _firstPercent and _secondPercent with single _desiredSplitPosition to reduce invariants - these had to be kept in sync so their sum always gives 1 (and were not really a percent). The desired part refers to fact that since panes are aligned, there is usually some deviation from that ratio. 2. Pane.cpp: Fixed _GetMinSize() - it was improperly accounting for split direction 3. TerminalControl: Made dedicated member for padding instead of reading it from a control itself. This is because the winrt property functions turned out to be slow and this algorithm needs to access it many times. I also cached scrollbar width for the same reason. 4. AppHost: Moved window to client size resolution to virtual method, where IslandWindow and NonClientIslandWindow have their own implementations (as opposite to pointer casting). One problem with current implementation is I had to make a long call chain from the window that requests snapping to the (root) pane that implements it: IslandWindow -> AppHost's callback -> App -> TerminalPage -> Tab -> Pane. I don't know if this can be done better. ## Validation Steps Performed Spam split pane buttons, randomly change font sizes with ctrl+mouse wheel and drag the window back and forth. Closes #2834 Closes #2277
2020-01-08 22:19:23 +01:00
// Method Description:
// - Set a callback to be called when the window is being resized by user. For given
// requested window dimension (width or height, whichever border is dragged) it should
// return a resulting window dimension that is actually set. It is used to make the
// window 'snap' to the underling terminal's character grid.
// Arguments:
// - pfn: a function that transforms requested to actual window dimension.
// pfn's parameters:
// * widthOrHeight: whether the dimension is width (true) or height (false)
// * dimension: The requested dimension that comes from user dragging a border
// of the window. It is in pixels and represents only the client area.
// pfn's return value:
// * A dimension of client area that the window should resize to.
// Return Value:
// - <none>
void IslandWindow::SetSnapDimensionCallback(std::function<float(bool, float)> pfn) noexcept
{
_pfnSnapDimensionCallback = pfn;
}
// Method Description:
// - Handles a WM_CREATE message. Calls our create callback, if one's been set.
// Arguments:
// - wParam: unused
// - lParam: the lParam of a WM_CREATE, which is a pointer to a CREATESTRUCTW
// Return Value:
// - <none>
void IslandWindow::_HandleCreateWindow(const WPARAM, const LPARAM lParam) noexcept
{
// Get proposed window rect from create structure
CREATESTRUCTW* pcs = reinterpret_cast<CREATESTRUCTW*>(lParam);
RECT rc;
rc.left = pcs->x;
rc.top = pcs->y;
rc.right = rc.left + pcs->cx;
rc.bottom = rc.top + pcs->cy;
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
2019-10-17 06:51:50 +02:00
winrt::TerminalApp::LaunchMode launchMode = winrt::TerminalApp::LaunchMode::DefaultMode;
if (_pfnCreateCallback)
{
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
2019-10-17 06:51:50 +02:00
_pfnCreateCallback(_window.get(), rc, launchMode);
}
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
2019-10-17 06:51:50 +02:00
int nCmdShow = SW_SHOW;
if (launchMode == winrt::TerminalApp::LaunchMode::MaximizedMode)
{
nCmdShow = SW_MAXIMIZE;
}
ShowWindow(_window.get(), nCmdShow);
UpdateWindow(_window.get());
}
Snap to character grid when resizing window (#3181) When user resizes window, snap the size to align with the character grid (like e.g. putty, mintty and most unix terminals). Properly resolves arbitrary pane configuration (even with different font sizes and padding) trying to align each pane as close as possible. It also fixes terminal minimum size enforcement which was not quite well handled, especially with multiple panes. This PR does not however try to keep the terminals aligned at other user actions (e.g. font change or pane split). That is to be tracked by some other activity. Snapping is resolved in the pane tree, recursively, so it (hopefully) works for any possible layout. Along the way I had to clean up some things as so to make the resulting code not so cumbersome: 1. Pane.cpp: Replaced _firstPercent and _secondPercent with single _desiredSplitPosition to reduce invariants - these had to be kept in sync so their sum always gives 1 (and were not really a percent). The desired part refers to fact that since panes are aligned, there is usually some deviation from that ratio. 2. Pane.cpp: Fixed _GetMinSize() - it was improperly accounting for split direction 3. TerminalControl: Made dedicated member for padding instead of reading it from a control itself. This is because the winrt property functions turned out to be slow and this algorithm needs to access it many times. I also cached scrollbar width for the same reason. 4. AppHost: Moved window to client size resolution to virtual method, where IslandWindow and NonClientIslandWindow have their own implementations (as opposite to pointer casting). One problem with current implementation is I had to make a long call chain from the window that requests snapping to the (root) pane that implements it: IslandWindow -> AppHost's callback -> App -> TerminalPage -> Tab -> Pane. I don't know if this can be done better. ## Validation Steps Performed Spam split pane buttons, randomly change font sizes with ctrl+mouse wheel and drag the window back and forth. Closes #2834 Closes #2277
2020-01-08 22:19:23 +01:00
// Method Description:
// - Handles a WM_SIZING message, which occurs when user drags a window border
// or corner. It intercepts this resize action and applies 'snapping' i.e.
// aligns the terminal's size to its cell grid. We're given the window size,
// which we then adjust based on the terminal's properties (like font size).
// Arguments:
// - wParam: Specifies which edge of the window is being dragged.
// - lParam: Pointer to the requested window rectangle (this is, the one that
// originates from current drag action). It also acts as the return value
// (it's a ref parameter).
// Return Value:
// - <none>
LRESULT IslandWindow::_OnSizing(const WPARAM wParam, const LPARAM lParam)
{
if (!_pfnSnapDimensionCallback)
{
// 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;
}
LPRECT winRect = reinterpret_cast<LPRECT>(lParam);
// Find nearest monitor.
HMONITOR hmon = MonitorFromRect(winRect, MONITOR_DEFAULTTONEAREST);
// 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);
const auto nonClientSize = GetTotalNonClientExclusiveSize(dpix);
auto clientWidth = winRect->right - winRect->left - nonClientSize.cx;
auto clientHeight = winRect->bottom - winRect->top - nonClientSize.cy;
if (wParam != WMSZ_TOP && wParam != WMSZ_BOTTOM)
{
// If user has dragged anything but the top or bottom border (so e.g. left border,
// top-right corner etc.), then this means that the width has changed. We thus ask to
// adjust this new width so that terminal(s) is/are aligned to their character grid(s).
clientWidth = gsl::narrow_cast<int>(_pfnSnapDimensionCallback(true, gsl::narrow_cast<float>(clientWidth)));
}
if (wParam != WMSZ_LEFT && wParam != WMSZ_RIGHT)
{
// Analogous to above, but for height.
clientHeight = gsl::narrow_cast<int>(_pfnSnapDimensionCallback(false, gsl::narrow_cast<float>(clientHeight)));
}
// Now make the window rectangle match the calculated client width and height,
// regarding which border the user is dragging. E.g. if user drags left border, then
// we make sure to adjust the 'left' component of rectangle and not the 'right'. Note
// that top-left and bottom-left corners also 'include' left border, hence we match
// this in multi-case switch.
// Set width
switch (wParam)
{
case WMSZ_LEFT:
case WMSZ_TOPLEFT:
case WMSZ_BOTTOMLEFT:
winRect->left = winRect->right - (clientWidth + nonClientSize.cx);
break;
case WMSZ_RIGHT:
case WMSZ_TOPRIGHT:
case WMSZ_BOTTOMRIGHT:
winRect->right = winRect->left + (clientWidth + nonClientSize.cx);
break;
}
// Set height
switch (wParam)
{
case WMSZ_BOTTOM:
case WMSZ_BOTTOMLEFT:
case WMSZ_BOTTOMRIGHT:
winRect->bottom = winRect->top + (clientHeight + nonClientSize.cy);
break;
case WMSZ_TOP:
case WMSZ_TOPLEFT:
case WMSZ_TOPRIGHT:
winRect->top = winRect->bottom - (clientHeight + nonClientSize.cy);
break;
}
return TRUE;
}
void IslandWindow::Initialize()
{
const bool initialized = (_interopWindowHandle != nullptr);
_source = DesktopWindowXamlSource{};
auto interop = _source.as<IDesktopWindowXamlSourceNative>();
winrt::check_hresult(interop->AttachToWindow(_window.get()));
// stash the child interop handle so we can resize it when the main hwnd is resized
interop->get_WindowHandle(&_interopWindowHandle);
_rootGrid = winrt::Windows::UI::Xaml::Controls::Grid();
_source.Content(_rootGrid);
}
void IslandWindow::OnSize(const UINT width, const UINT height)
{
// update the interop window size
SetWindowPos(_interopWindowHandle, 0, 0, 0, width, height, SWP_SHOWWINDOW);
if (_rootGrid)
{
const auto size = GetLogicalSize();
_rootGrid.Width(size.Width);
_rootGrid.Height(size.Height);
}
}
[[nodiscard]] LRESULT IslandWindow::MessageHandler(UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept
{
switch (message)
{
case WM_CREATE:
{
_HandleCreateWindow(wparam, lparam);
return 0;
}
case WM_SETFOCUS:
{
if (_interopWindowHandle != nullptr)
{
// TODO GitHub #2447: Properly attach WindowUiaProvider for signaling model
/*
// set the text area to have focus for accessibility consumers
if (_pUiaProvider)
{
LOG_IF_FAILED(_pUiaProvider->SetTextAreaFocus());
}
break;
*/
// send focus to the child window
SetFocus(_interopWindowHandle);
return 0; // eat the message
}
}
case WM_NCLBUTTONDOWN:
case WM_NCLBUTTONUP:
case WM_NCMBUTTONDOWN:
case WM_NCMBUTTONUP:
case WM_NCRBUTTONDOWN:
case WM_NCRBUTTONUP:
case WM_NCXBUTTONDOWN:
case WM_NCXBUTTONUP:
{
// If we clicked in the titlebar, raise an event so the app host can
// dispatch an appropriate event.
_DragRegionClickedHandlers();
break;
}
case WM_MENUCHAR:
{
// GH#891: return this LRESULT here to prevent the app from making a
// bell when alt+key is pressed. A menu is active and the user presses a
// key that does not correspond to any mnemonic or accelerator key,
return MAKELRESULT(0, MNC_CLOSE);
}
Snap to character grid when resizing window (#3181) When user resizes window, snap the size to align with the character grid (like e.g. putty, mintty and most unix terminals). Properly resolves arbitrary pane configuration (even with different font sizes and padding) trying to align each pane as close as possible. It also fixes terminal minimum size enforcement which was not quite well handled, especially with multiple panes. This PR does not however try to keep the terminals aligned at other user actions (e.g. font change or pane split). That is to be tracked by some other activity. Snapping is resolved in the pane tree, recursively, so it (hopefully) works for any possible layout. Along the way I had to clean up some things as so to make the resulting code not so cumbersome: 1. Pane.cpp: Replaced _firstPercent and _secondPercent with single _desiredSplitPosition to reduce invariants - these had to be kept in sync so their sum always gives 1 (and were not really a percent). The desired part refers to fact that since panes are aligned, there is usually some deviation from that ratio. 2. Pane.cpp: Fixed _GetMinSize() - it was improperly accounting for split direction 3. TerminalControl: Made dedicated member for padding instead of reading it from a control itself. This is because the winrt property functions turned out to be slow and this algorithm needs to access it many times. I also cached scrollbar width for the same reason. 4. AppHost: Moved window to client size resolution to virtual method, where IslandWindow and NonClientIslandWindow have their own implementations (as opposite to pointer casting). One problem with current implementation is I had to make a long call chain from the window that requests snapping to the (root) pane that implements it: IslandWindow -> AppHost's callback -> App -> TerminalPage -> Tab -> Pane. I don't know if this can be done better. ## Validation Steps Performed Spam split pane buttons, randomly change font sizes with ctrl+mouse wheel and drag the window back and forth. Closes #2834 Closes #2277
2020-01-08 22:19:23 +01:00
case WM_SIZING:
{
return _OnSizing(wparam, lparam);
}
case WM_CLOSE:
{
// If the user wants to close the app by clicking 'X' button,
// we hand off the close experience to the app layer. If all the tabs
// are closed, the window will be closed as well.
_windowCloseButtonClickedHandler();
return 0;
}
}
// TODO: handle messages here...
return base_type::MessageHandler(message, wparam, lparam);
}
Accessibility: Set-up UIA Tree (#1691) **The Basics of Accessibility** - [What is a User Interaction Automation (UIA) Tree?](https://docs.microsoft.com/en-us/dotnet/framework/ui-automation/ui-automation-tree-overview) - Other projects (i.e.: Narrator) can take advantage of this UIA tree and are used to present information within it. - Some things like XAML already have a UIA Tree. So some UIA tree navigation and features are already there. It's just a matter of getting them hooked up and looking right. **Accessibility in our Project** There's a few important classes... regarding Accessibility... - **WindowUiaProvider**: This sets up the UIA tree for a window. So this is the top-level for the UIA tree. - **ScreenInfoUiaProvider**: This sets up the UIA tree for a terminal buffer. - **UiaTextRange**: This is essential to interacting with the UIA tree for the terminal buffer. Actually gets portions of the buffer and presents them. regarding the Windows Terminal window... - **BaseWindow**: The foundation to a window. Deals with HWNDs and that kind of stuff. - **IslandWindow**: This extends `BaseWindow` and is actually what holds our Windows Terminal - **NonClientIslandWindow**: An extension of the `IslandWindow` regarding ConHost... - **IConsoleWindow**: This is an interface for the console window. - **Window**: This is the actual window for ConHost. Extends `IConsoleWindow` - `IConsoleWindow` changes: - move into `Microsoft::Console::Types` (a shared space) - Have `IslandWindow` extend it - `WindowUiaProvider` changes: - move into `Microsoft::Console::Types` (a shared space) - Hook up `WindowUiaProvider` to IslandWindow (yay! we now have a tree) ### Changes to the WindowUiaProvider As mentioned earlier, the WindowUiaProvider is the top-level UIA provider for our projects. To reuse as much code as possible, I created `Microsoft::Console::Types::WindowUiaProviderBase`. Any existing functions that reference a `ScreenInfoUiaProvider` were virtual-ized. In each project, a `WindowUiaProvider : WindowUiaProviderBase` was created to define those virtual functions. Note that that will be the main difference between ConHost and Windows Terminal moving forward: how many TextBuffers are on the screen. So, ConHost should be the same as before, with only one `ScreenInfoUiaProvider`, whereas Windows Terminal needs to (1) update which one is on the screen and (2) may have multiple on the screen. 🚨 Windows Terminal doesn't have the `ScreenInfoUiaProvider` hooked up yet. We'll have all the XAML elements in the UIA tree. But, since `TermControl` is a custom XAML Control, I need to hook up the `ScreenInfoUiaProvider` to it. This work will be done in a new PR and resolve GitHub Issue #1352. ### Moved to `Microsoft::Console::Types` These files got moved to a shared area so that they can be used by both ConHost and Windows Terminal. This means that any references to the `ServiceLocator` had to be removed. - `IConsoleWindow` - Windows Terminal: `IslandWindow : IConsoleWindow` - `ScreenInfoUiaProvider` - all references to `ServiceLocator` and `SCREEN_INFORMATION` were removed. `IRenderData` was used to accomplish this. Refer to next section for more details. - `UiaTextRange` - all references to `ServiceLocator` and `SCREEN_INFORMATION` were removed. `IRenderData` was used to accomplish this. Refer to next section for more details. - since most of the functions were `static`, that means that an `IRenderData` had to be added into most of them. ### Changes to IRenderData Since `IRenderData` is now being used to abstract out `ServiceLocator` and `SCREEN_INFORMATION`, I had to add a few functions here: - `bool IsAreaSelected()` - `void ClearSelection()` - `void SelectNewRegion(...)` - `HRESULT SearchForText(...)` `SearchForText()` is a problem here. The overall new design is great! But Windows Terminal doesn't have a way to search for text in the buffer yet, whereas ConHost does. So I'm punting on this issue for now. It looks nasty, but just look at all the other pretty things here. :)
2019-07-30 00:21:15 +02:00
// Routine Description:
// - Creates/retrieves a handle to the UI Automation provider COM interfaces
// Arguments:
// - <none>
// Return Value:
// - Pointer to UI Automation provider class/interfaces.
IRawElementProviderSimple* IslandWindow::_GetUiaProvider()
{
if (nullptr == _pUiaProvider)
{
try
{
// TODO GitHub #3195: Remove WindowUiaProvider in WindowsTerminal
//Microsoft::WRL::MakeAndInitialize<WindowUiaProvider>(&_pUiaProvider, this);
Accessibility: Set-up UIA Tree (#1691) **The Basics of Accessibility** - [What is a User Interaction Automation (UIA) Tree?](https://docs.microsoft.com/en-us/dotnet/framework/ui-automation/ui-automation-tree-overview) - Other projects (i.e.: Narrator) can take advantage of this UIA tree and are used to present information within it. - Some things like XAML already have a UIA Tree. So some UIA tree navigation and features are already there. It's just a matter of getting them hooked up and looking right. **Accessibility in our Project** There's a few important classes... regarding Accessibility... - **WindowUiaProvider**: This sets up the UIA tree for a window. So this is the top-level for the UIA tree. - **ScreenInfoUiaProvider**: This sets up the UIA tree for a terminal buffer. - **UiaTextRange**: This is essential to interacting with the UIA tree for the terminal buffer. Actually gets portions of the buffer and presents them. regarding the Windows Terminal window... - **BaseWindow**: The foundation to a window. Deals with HWNDs and that kind of stuff. - **IslandWindow**: This extends `BaseWindow` and is actually what holds our Windows Terminal - **NonClientIslandWindow**: An extension of the `IslandWindow` regarding ConHost... - **IConsoleWindow**: This is an interface for the console window. - **Window**: This is the actual window for ConHost. Extends `IConsoleWindow` - `IConsoleWindow` changes: - move into `Microsoft::Console::Types` (a shared space) - Have `IslandWindow` extend it - `WindowUiaProvider` changes: - move into `Microsoft::Console::Types` (a shared space) - Hook up `WindowUiaProvider` to IslandWindow (yay! we now have a tree) ### Changes to the WindowUiaProvider As mentioned earlier, the WindowUiaProvider is the top-level UIA provider for our projects. To reuse as much code as possible, I created `Microsoft::Console::Types::WindowUiaProviderBase`. Any existing functions that reference a `ScreenInfoUiaProvider` were virtual-ized. In each project, a `WindowUiaProvider : WindowUiaProviderBase` was created to define those virtual functions. Note that that will be the main difference between ConHost and Windows Terminal moving forward: how many TextBuffers are on the screen. So, ConHost should be the same as before, with only one `ScreenInfoUiaProvider`, whereas Windows Terminal needs to (1) update which one is on the screen and (2) may have multiple on the screen. 🚨 Windows Terminal doesn't have the `ScreenInfoUiaProvider` hooked up yet. We'll have all the XAML elements in the UIA tree. But, since `TermControl` is a custom XAML Control, I need to hook up the `ScreenInfoUiaProvider` to it. This work will be done in a new PR and resolve GitHub Issue #1352. ### Moved to `Microsoft::Console::Types` These files got moved to a shared area so that they can be used by both ConHost and Windows Terminal. This means that any references to the `ServiceLocator` had to be removed. - `IConsoleWindow` - Windows Terminal: `IslandWindow : IConsoleWindow` - `ScreenInfoUiaProvider` - all references to `ServiceLocator` and `SCREEN_INFORMATION` were removed. `IRenderData` was used to accomplish this. Refer to next section for more details. - `UiaTextRange` - all references to `ServiceLocator` and `SCREEN_INFORMATION` were removed. `IRenderData` was used to accomplish this. Refer to next section for more details. - since most of the functions were `static`, that means that an `IRenderData` had to be added into most of them. ### Changes to IRenderData Since `IRenderData` is now being used to abstract out `ServiceLocator` and `SCREEN_INFORMATION`, I had to add a few functions here: - `bool IsAreaSelected()` - `void ClearSelection()` - `void SelectNewRegion(...)` - `HRESULT SearchForText(...)` `SearchForText()` is a problem here. The overall new design is great! But Windows Terminal doesn't have a way to search for text in the buffer yet, whereas ConHost does. So I'm punting on this issue for now. It looks nasty, but just look at all the other pretty things here. :)
2019-07-30 00:21:15 +02:00
}
catch (...)
{
LOG_HR(wil::ResultFromCaughtException());
_pUiaProvider = nullptr;
}
}
return _pUiaProvider;
}
// Method Description:
// - Called when the window has been resized (or maximized)
// Arguments:
// - width: the new width of the window _in pixels_
// - height: the new height of the window _in pixels_
void IslandWindow::OnResize(const UINT width, const UINT height)
{
if (_interopWindowHandle)
{
OnSize(width, height);
}
}
// Method Description:
// - Called when the window is minimized to the taskbar.
void IslandWindow::OnMinimize()
{
Enable dragging with the entire titlebar (#1948) * This definitely works for getting shadow, pointy corners back Don't do anything in NCPAINT. If you do, you have to do everything. But the whole point of DwmExtendFrameIntoClientArea is to let you paint the NC area in your normal paint. So just do that dummy. * This doesn't transition across monitors. * This has a window style change I think is wrong. * I'm not sure the margins change is important. * The window style was _not_ important * Still getting a black xaml islands area (the HRGN) when we switch to high DPI * I don't know if this affects anything. * heyo this works. I'm not entirely sure why. But if we only update the titlebar drag region when that actually changes, it's a _lot_ smoother. I'm not super happy with the duplicated work in _UpdateDragRegion and OnSize, but checking this in in case I can't figure that out. * Add more comments and cleanup * Try making the button RightCustomContent * * Make the MinMaxClose's drag bar's min size the same as a caption button * Make the new tab button transparent, to see how that looks * Make sure the TabView doesn't push the MMC off the window * Create a TitlebarControl * The TitlebarControl is owned by the NCIW. It consists of a Content, DragBar, and MMCControl. * The App instatntiates a TabRowControl at runtime, and either places it in the UI (for tabs below titlebar) or hangs on to it, and gives it to the NCIW when the NCIW creates its UI. * When the NCIW is created, it creates a grid with two rows, one for the titlebar and one for the app content. * The MMCControl is only responsible for Min Max Close now, and is closer to the window implementation. * The drag bar takes up all the space from the right of the TabRow to the left of the MMC * Things that **DON'T** work: - When you add tabs, the drag bar doesn't update it's size. It only updates OnSize - The MMCControl's Min and Max buttons don't seem to work anymore. - They should probably just expose their OnMinimizeClick and OnMaximizeClick events for the Titlebar to handle minimizing and maximizing. - The drag bar is Magenta (#ff00ff) currently. - I'm not _sure_ we need a TabRowControl. We could probably get away with removing it from the UI tree, I was just being dumb before. * Fix the MMC buttons not working I forgot to plumb the window handle through * Make the titlebar less magenta * Resize the drag region as we add/remove tabs * Move the actual MMC handling to the TitlebarControl * Some PR nits, fix the titlebar painting on maximize * Put the TabRow in our XAML * Remove dead code in preparation for review * Horrifyingly try Gdi Plus as a solution, that is _wrong_ though * Revert "Horrifyingly try Gdi Plus as a solution, that is _wrong_ though" This reverts commit e038b5d9216c6710c2a7f81840d76f8130cd73b8. * This fixes the bottom border but breaks the titlebar painting * Fix the NC bottom border * A bunch of the more minor PR nits * Add a MinimizeClick event to the MMCControl This works for Minimize. This is what I wanted to do originally. * Add events for _all_ of the buttons, not just the Minimize btn * Change hoe setting the titlebar content works Now the app triggers a callcack on the host to set the content, instead of the host querying the app. * Move the tab row to the bottom of it's available space * Fix the theme reloading * PR nits from @miniksa * Update src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp Co-Authored-By: Michael Niksa <miniksa@microsoft.com> * This needed to be fixed, was missed in other PR nits * runformat wait _what_ * Does this fix the CI build?
2019-07-19 00:21:33 +02:00
// TODO GH#1989 Stop rendering island content when the app is minimized.
}
// Method Description:
// - Called when the window is restored from having been minimized.
void IslandWindow::OnRestore()
{
Enable dragging with the entire titlebar (#1948) * This definitely works for getting shadow, pointy corners back Don't do anything in NCPAINT. If you do, you have to do everything. But the whole point of DwmExtendFrameIntoClientArea is to let you paint the NC area in your normal paint. So just do that dummy. * This doesn't transition across monitors. * This has a window style change I think is wrong. * I'm not sure the margins change is important. * The window style was _not_ important * Still getting a black xaml islands area (the HRGN) when we switch to high DPI * I don't know if this affects anything. * heyo this works. I'm not entirely sure why. But if we only update the titlebar drag region when that actually changes, it's a _lot_ smoother. I'm not super happy with the duplicated work in _UpdateDragRegion and OnSize, but checking this in in case I can't figure that out. * Add more comments and cleanup * Try making the button RightCustomContent * * Make the MinMaxClose's drag bar's min size the same as a caption button * Make the new tab button transparent, to see how that looks * Make sure the TabView doesn't push the MMC off the window * Create a TitlebarControl * The TitlebarControl is owned by the NCIW. It consists of a Content, DragBar, and MMCControl. * The App instatntiates a TabRowControl at runtime, and either places it in the UI (for tabs below titlebar) or hangs on to it, and gives it to the NCIW when the NCIW creates its UI. * When the NCIW is created, it creates a grid with two rows, one for the titlebar and one for the app content. * The MMCControl is only responsible for Min Max Close now, and is closer to the window implementation. * The drag bar takes up all the space from the right of the TabRow to the left of the MMC * Things that **DON'T** work: - When you add tabs, the drag bar doesn't update it's size. It only updates OnSize - The MMCControl's Min and Max buttons don't seem to work anymore. - They should probably just expose their OnMinimizeClick and OnMaximizeClick events for the Titlebar to handle minimizing and maximizing. - The drag bar is Magenta (#ff00ff) currently. - I'm not _sure_ we need a TabRowControl. We could probably get away with removing it from the UI tree, I was just being dumb before. * Fix the MMC buttons not working I forgot to plumb the window handle through * Make the titlebar less magenta * Resize the drag region as we add/remove tabs * Move the actual MMC handling to the TitlebarControl * Some PR nits, fix the titlebar painting on maximize * Put the TabRow in our XAML * Remove dead code in preparation for review * Horrifyingly try Gdi Plus as a solution, that is _wrong_ though * Revert "Horrifyingly try Gdi Plus as a solution, that is _wrong_ though" This reverts commit e038b5d9216c6710c2a7f81840d76f8130cd73b8. * This fixes the bottom border but breaks the titlebar painting * Fix the NC bottom border * A bunch of the more minor PR nits * Add a MinimizeClick event to the MMCControl This works for Minimize. This is what I wanted to do originally. * Add events for _all_ of the buttons, not just the Minimize btn * Change hoe setting the titlebar content works Now the app triggers a callcack on the host to set the content, instead of the host querying the app. * Move the tab row to the bottom of it's available space * Fix the theme reloading * PR nits from @miniksa * Update src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp Co-Authored-By: Michael Niksa <miniksa@microsoft.com> * This needed to be fixed, was missed in other PR nits * runformat wait _what_ * Does this fix the CI build?
2019-07-19 00:21:33 +02:00
// TODO GH#1989 Stop rendering island content when the app is minimized.
}
Enable dragging with the entire titlebar (#1948) * This definitely works for getting shadow, pointy corners back Don't do anything in NCPAINT. If you do, you have to do everything. But the whole point of DwmExtendFrameIntoClientArea is to let you paint the NC area in your normal paint. So just do that dummy. * This doesn't transition across monitors. * This has a window style change I think is wrong. * I'm not sure the margins change is important. * The window style was _not_ important * Still getting a black xaml islands area (the HRGN) when we switch to high DPI * I don't know if this affects anything. * heyo this works. I'm not entirely sure why. But if we only update the titlebar drag region when that actually changes, it's a _lot_ smoother. I'm not super happy with the duplicated work in _UpdateDragRegion and OnSize, but checking this in in case I can't figure that out. * Add more comments and cleanup * Try making the button RightCustomContent * * Make the MinMaxClose's drag bar's min size the same as a caption button * Make the new tab button transparent, to see how that looks * Make sure the TabView doesn't push the MMC off the window * Create a TitlebarControl * The TitlebarControl is owned by the NCIW. It consists of a Content, DragBar, and MMCControl. * The App instatntiates a TabRowControl at runtime, and either places it in the UI (for tabs below titlebar) or hangs on to it, and gives it to the NCIW when the NCIW creates its UI. * When the NCIW is created, it creates a grid with two rows, one for the titlebar and one for the app content. * The MMCControl is only responsible for Min Max Close now, and is closer to the window implementation. * The drag bar takes up all the space from the right of the TabRow to the left of the MMC * Things that **DON'T** work: - When you add tabs, the drag bar doesn't update it's size. It only updates OnSize - The MMCControl's Min and Max buttons don't seem to work anymore. - They should probably just expose their OnMinimizeClick and OnMaximizeClick events for the Titlebar to handle minimizing and maximizing. - The drag bar is Magenta (#ff00ff) currently. - I'm not _sure_ we need a TabRowControl. We could probably get away with removing it from the UI tree, I was just being dumb before. * Fix the MMC buttons not working I forgot to plumb the window handle through * Make the titlebar less magenta * Resize the drag region as we add/remove tabs * Move the actual MMC handling to the TitlebarControl * Some PR nits, fix the titlebar painting on maximize * Put the TabRow in our XAML * Remove dead code in preparation for review * Horrifyingly try Gdi Plus as a solution, that is _wrong_ though * Revert "Horrifyingly try Gdi Plus as a solution, that is _wrong_ though" This reverts commit e038b5d9216c6710c2a7f81840d76f8130cd73b8. * This fixes the bottom border but breaks the titlebar painting * Fix the NC bottom border * A bunch of the more minor PR nits * Add a MinimizeClick event to the MMCControl This works for Minimize. This is what I wanted to do originally. * Add events for _all_ of the buttons, not just the Minimize btn * Change hoe setting the titlebar content works Now the app triggers a callcack on the host to set the content, instead of the host querying the app. * Move the tab row to the bottom of it's available space * Fix the theme reloading * PR nits from @miniksa * Update src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp Co-Authored-By: Michael Niksa <miniksa@microsoft.com> * This needed to be fixed, was missed in other PR nits * runformat wait _what_ * Does this fix the CI build?
2019-07-19 00:21:33 +02:00
void IslandWindow::SetContent(winrt::Windows::UI::Xaml::UIElement content)
{
_rootGrid.Children().Clear();
Enable dragging with the entire titlebar (#1948) * This definitely works for getting shadow, pointy corners back Don't do anything in NCPAINT. If you do, you have to do everything. But the whole point of DwmExtendFrameIntoClientArea is to let you paint the NC area in your normal paint. So just do that dummy. * This doesn't transition across monitors. * This has a window style change I think is wrong. * I'm not sure the margins change is important. * The window style was _not_ important * Still getting a black xaml islands area (the HRGN) when we switch to high DPI * I don't know if this affects anything. * heyo this works. I'm not entirely sure why. But if we only update the titlebar drag region when that actually changes, it's a _lot_ smoother. I'm not super happy with the duplicated work in _UpdateDragRegion and OnSize, but checking this in in case I can't figure that out. * Add more comments and cleanup * Try making the button RightCustomContent * * Make the MinMaxClose's drag bar's min size the same as a caption button * Make the new tab button transparent, to see how that looks * Make sure the TabView doesn't push the MMC off the window * Create a TitlebarControl * The TitlebarControl is owned by the NCIW. It consists of a Content, DragBar, and MMCControl. * The App instatntiates a TabRowControl at runtime, and either places it in the UI (for tabs below titlebar) or hangs on to it, and gives it to the NCIW when the NCIW creates its UI. * When the NCIW is created, it creates a grid with two rows, one for the titlebar and one for the app content. * The MMCControl is only responsible for Min Max Close now, and is closer to the window implementation. * The drag bar takes up all the space from the right of the TabRow to the left of the MMC * Things that **DON'T** work: - When you add tabs, the drag bar doesn't update it's size. It only updates OnSize - The MMCControl's Min and Max buttons don't seem to work anymore. - They should probably just expose their OnMinimizeClick and OnMaximizeClick events for the Titlebar to handle minimizing and maximizing. - The drag bar is Magenta (#ff00ff) currently. - I'm not _sure_ we need a TabRowControl. We could probably get away with removing it from the UI tree, I was just being dumb before. * Fix the MMC buttons not working I forgot to plumb the window handle through * Make the titlebar less magenta * Resize the drag region as we add/remove tabs * Move the actual MMC handling to the TitlebarControl * Some PR nits, fix the titlebar painting on maximize * Put the TabRow in our XAML * Remove dead code in preparation for review * Horrifyingly try Gdi Plus as a solution, that is _wrong_ though * Revert "Horrifyingly try Gdi Plus as a solution, that is _wrong_ though" This reverts commit e038b5d9216c6710c2a7f81840d76f8130cd73b8. * This fixes the bottom border but breaks the titlebar painting * Fix the NC bottom border * A bunch of the more minor PR nits * Add a MinimizeClick event to the MMCControl This works for Minimize. This is what I wanted to do originally. * Add events for _all_ of the buttons, not just the Minimize btn * Change hoe setting the titlebar content works Now the app triggers a callcack on the host to set the content, instead of the host querying the app. * Move the tab row to the bottom of it's available space * Fix the theme reloading * PR nits from @miniksa * Update src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp Co-Authored-By: Michael Niksa <miniksa@microsoft.com> * This needed to be fixed, was missed in other PR nits * runformat wait _what_ * Does this fix the CI build?
2019-07-19 00:21:33 +02:00
_rootGrid.Children().Append(content);
}
Snap to character grid when resizing window (#3181) When user resizes window, snap the size to align with the character grid (like e.g. putty, mintty and most unix terminals). Properly resolves arbitrary pane configuration (even with different font sizes and padding) trying to align each pane as close as possible. It also fixes terminal minimum size enforcement which was not quite well handled, especially with multiple panes. This PR does not however try to keep the terminals aligned at other user actions (e.g. font change or pane split). That is to be tracked by some other activity. Snapping is resolved in the pane tree, recursively, so it (hopefully) works for any possible layout. Along the way I had to clean up some things as so to make the resulting code not so cumbersome: 1. Pane.cpp: Replaced _firstPercent and _secondPercent with single _desiredSplitPosition to reduce invariants - these had to be kept in sync so their sum always gives 1 (and were not really a percent). The desired part refers to fact that since panes are aligned, there is usually some deviation from that ratio. 2. Pane.cpp: Fixed _GetMinSize() - it was improperly accounting for split direction 3. TerminalControl: Made dedicated member for padding instead of reading it from a control itself. This is because the winrt property functions turned out to be slow and this algorithm needs to access it many times. I also cached scrollbar width for the same reason. 4. AppHost: Moved window to client size resolution to virtual method, where IslandWindow and NonClientIslandWindow have their own implementations (as opposite to pointer casting). One problem with current implementation is I had to make a long call chain from the window that requests snapping to the (root) pane that implements it: IslandWindow -> AppHost's callback -> App -> TerminalPage -> Tab -> Pane. I don't know if this can be done better. ## Validation Steps Performed Spam split pane buttons, randomly change font sizes with ctrl+mouse wheel and drag the window back and forth. Closes #2834 Closes #2277
2020-01-08 22:19:23 +01:00
// Method Description:
// - Gets the difference between window and client area size.
// Arguments:
// - dpi: dpi of a monitor on which the window is placed
// Return Value
// - The size difference
SIZE IslandWindow::GetTotalNonClientExclusiveSize(const UINT dpi) const noexcept
{
const auto windowStyle = static_cast<DWORD>(GetWindowLong(_window.get(), GWL_STYLE));
RECT islandFrame{};
// 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_IF_WIN32_BOOL_FALSE(AdjustWindowRectExForDpi(&islandFrame, windowStyle, false, 0, dpi));
return {
islandFrame.right - islandFrame.left,
islandFrame.bottom - islandFrame.top
};
}
Enable dragging with the entire titlebar (#1948) * This definitely works for getting shadow, pointy corners back Don't do anything in NCPAINT. If you do, you have to do everything. But the whole point of DwmExtendFrameIntoClientArea is to let you paint the NC area in your normal paint. So just do that dummy. * This doesn't transition across monitors. * This has a window style change I think is wrong. * I'm not sure the margins change is important. * The window style was _not_ important * Still getting a black xaml islands area (the HRGN) when we switch to high DPI * I don't know if this affects anything. * heyo this works. I'm not entirely sure why. But if we only update the titlebar drag region when that actually changes, it's a _lot_ smoother. I'm not super happy with the duplicated work in _UpdateDragRegion and OnSize, but checking this in in case I can't figure that out. * Add more comments and cleanup * Try making the button RightCustomContent * * Make the MinMaxClose's drag bar's min size the same as a caption button * Make the new tab button transparent, to see how that looks * Make sure the TabView doesn't push the MMC off the window * Create a TitlebarControl * The TitlebarControl is owned by the NCIW. It consists of a Content, DragBar, and MMCControl. * The App instatntiates a TabRowControl at runtime, and either places it in the UI (for tabs below titlebar) or hangs on to it, and gives it to the NCIW when the NCIW creates its UI. * When the NCIW is created, it creates a grid with two rows, one for the titlebar and one for the app content. * The MMCControl is only responsible for Min Max Close now, and is closer to the window implementation. * The drag bar takes up all the space from the right of the TabRow to the left of the MMC * Things that **DON'T** work: - When you add tabs, the drag bar doesn't update it's size. It only updates OnSize - The MMCControl's Min and Max buttons don't seem to work anymore. - They should probably just expose their OnMinimizeClick and OnMaximizeClick events for the Titlebar to handle minimizing and maximizing. - The drag bar is Magenta (#ff00ff) currently. - I'm not _sure_ we need a TabRowControl. We could probably get away with removing it from the UI tree, I was just being dumb before. * Fix the MMC buttons not working I forgot to plumb the window handle through * Make the titlebar less magenta * Resize the drag region as we add/remove tabs * Move the actual MMC handling to the TitlebarControl * Some PR nits, fix the titlebar painting on maximize * Put the TabRow in our XAML * Remove dead code in preparation for review * Horrifyingly try Gdi Plus as a solution, that is _wrong_ though * Revert "Horrifyingly try Gdi Plus as a solution, that is _wrong_ though" This reverts commit e038b5d9216c6710c2a7f81840d76f8130cd73b8. * This fixes the bottom border but breaks the titlebar painting * Fix the NC bottom border * A bunch of the more minor PR nits * Add a MinimizeClick event to the MMCControl This works for Minimize. This is what I wanted to do originally. * Add events for _all_ of the buttons, not just the Minimize btn * Change hoe setting the titlebar content works Now the app triggers a callcack on the host to set the content, instead of the host querying the app. * Move the tab row to the bottom of it's available space * Fix the theme reloading * PR nits from @miniksa * Update src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp Co-Authored-By: Michael Niksa <miniksa@microsoft.com> * This needed to be fixed, was missed in other PR nits * runformat wait _what_ * Does this fix the CI build?
2019-07-19 00:21:33 +02:00
void IslandWindow::OnAppInitialized()
{
// Do a quick resize to force the island to paint
const auto size = GetPhysicalSize();
OnSize(size.cx, size.cy);
}
Enable dragging with the entire titlebar (#1948) * This definitely works for getting shadow, pointy corners back Don't do anything in NCPAINT. If you do, you have to do everything. But the whole point of DwmExtendFrameIntoClientArea is to let you paint the NC area in your normal paint. So just do that dummy. * This doesn't transition across monitors. * This has a window style change I think is wrong. * I'm not sure the margins change is important. * The window style was _not_ important * Still getting a black xaml islands area (the HRGN) when we switch to high DPI * I don't know if this affects anything. * heyo this works. I'm not entirely sure why. But if we only update the titlebar drag region when that actually changes, it's a _lot_ smoother. I'm not super happy with the duplicated work in _UpdateDragRegion and OnSize, but checking this in in case I can't figure that out. * Add more comments and cleanup * Try making the button RightCustomContent * * Make the MinMaxClose's drag bar's min size the same as a caption button * Make the new tab button transparent, to see how that looks * Make sure the TabView doesn't push the MMC off the window * Create a TitlebarControl * The TitlebarControl is owned by the NCIW. It consists of a Content, DragBar, and MMCControl. * The App instatntiates a TabRowControl at runtime, and either places it in the UI (for tabs below titlebar) or hangs on to it, and gives it to the NCIW when the NCIW creates its UI. * When the NCIW is created, it creates a grid with two rows, one for the titlebar and one for the app content. * The MMCControl is only responsible for Min Max Close now, and is closer to the window implementation. * The drag bar takes up all the space from the right of the TabRow to the left of the MMC * Things that **DON'T** work: - When you add tabs, the drag bar doesn't update it's size. It only updates OnSize - The MMCControl's Min and Max buttons don't seem to work anymore. - They should probably just expose their OnMinimizeClick and OnMaximizeClick events for the Titlebar to handle minimizing and maximizing. - The drag bar is Magenta (#ff00ff) currently. - I'm not _sure_ we need a TabRowControl. We could probably get away with removing it from the UI tree, I was just being dumb before. * Fix the MMC buttons not working I forgot to plumb the window handle through * Make the titlebar less magenta * Resize the drag region as we add/remove tabs * Move the actual MMC handling to the TitlebarControl * Some PR nits, fix the titlebar painting on maximize * Put the TabRow in our XAML * Remove dead code in preparation for review * Horrifyingly try Gdi Plus as a solution, that is _wrong_ though * Revert "Horrifyingly try Gdi Plus as a solution, that is _wrong_ though" This reverts commit e038b5d9216c6710c2a7f81840d76f8130cd73b8. * This fixes the bottom border but breaks the titlebar painting * Fix the NC bottom border * A bunch of the more minor PR nits * Add a MinimizeClick event to the MMCControl This works for Minimize. This is what I wanted to do originally. * Add events for _all_ of the buttons, not just the Minimize btn * Change hoe setting the titlebar content works Now the app triggers a callcack on the host to set the content, instead of the host querying the app. * Move the tab row to the bottom of it's available space * Fix the theme reloading * PR nits from @miniksa * Update src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp Co-Authored-By: Michael Niksa <miniksa@microsoft.com> * This needed to be fixed, was missed in other PR nits * runformat wait _what_ * Does this fix the CI build?
2019-07-19 00:21:33 +02:00
// Method Description:
// - Called when the app wants to change its theme. We'll update the root UI
// element of the entire XAML tree, so that all UI elements get the theme
// applied.
// Arguments:
// - arg: the ElementTheme to use as the new theme for the UI
// Return Value:
// - <none>
void IslandWindow::OnApplicationThemeChanged(const winrt::Windows::UI::Xaml::ElementTheme& requestedTheme)
Enable dragging with the entire titlebar (#1948) * This definitely works for getting shadow, pointy corners back Don't do anything in NCPAINT. If you do, you have to do everything. But the whole point of DwmExtendFrameIntoClientArea is to let you paint the NC area in your normal paint. So just do that dummy. * This doesn't transition across monitors. * This has a window style change I think is wrong. * I'm not sure the margins change is important. * The window style was _not_ important * Still getting a black xaml islands area (the HRGN) when we switch to high DPI * I don't know if this affects anything. * heyo this works. I'm not entirely sure why. But if we only update the titlebar drag region when that actually changes, it's a _lot_ smoother. I'm not super happy with the duplicated work in _UpdateDragRegion and OnSize, but checking this in in case I can't figure that out. * Add more comments and cleanup * Try making the button RightCustomContent * * Make the MinMaxClose's drag bar's min size the same as a caption button * Make the new tab button transparent, to see how that looks * Make sure the TabView doesn't push the MMC off the window * Create a TitlebarControl * The TitlebarControl is owned by the NCIW. It consists of a Content, DragBar, and MMCControl. * The App instatntiates a TabRowControl at runtime, and either places it in the UI (for tabs below titlebar) or hangs on to it, and gives it to the NCIW when the NCIW creates its UI. * When the NCIW is created, it creates a grid with two rows, one for the titlebar and one for the app content. * The MMCControl is only responsible for Min Max Close now, and is closer to the window implementation. * The drag bar takes up all the space from the right of the TabRow to the left of the MMC * Things that **DON'T** work: - When you add tabs, the drag bar doesn't update it's size. It only updates OnSize - The MMCControl's Min and Max buttons don't seem to work anymore. - They should probably just expose their OnMinimizeClick and OnMaximizeClick events for the Titlebar to handle minimizing and maximizing. - The drag bar is Magenta (#ff00ff) currently. - I'm not _sure_ we need a TabRowControl. We could probably get away with removing it from the UI tree, I was just being dumb before. * Fix the MMC buttons not working I forgot to plumb the window handle through * Make the titlebar less magenta * Resize the drag region as we add/remove tabs * Move the actual MMC handling to the TitlebarControl * Some PR nits, fix the titlebar painting on maximize * Put the TabRow in our XAML * Remove dead code in preparation for review * Horrifyingly try Gdi Plus as a solution, that is _wrong_ though * Revert "Horrifyingly try Gdi Plus as a solution, that is _wrong_ though" This reverts commit e038b5d9216c6710c2a7f81840d76f8130cd73b8. * This fixes the bottom border but breaks the titlebar painting * Fix the NC bottom border * A bunch of the more minor PR nits * Add a MinimizeClick event to the MMCControl This works for Minimize. This is what I wanted to do originally. * Add events for _all_ of the buttons, not just the Minimize btn * Change hoe setting the titlebar content works Now the app triggers a callcack on the host to set the content, instead of the host querying the app. * Move the tab row to the bottom of it's available space * Fix the theme reloading * PR nits from @miniksa * Update src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp Co-Authored-By: Michael Niksa <miniksa@microsoft.com> * This needed to be fixed, was missed in other PR nits * runformat wait _what_ * Does this fix the CI build?
2019-07-19 00:21:33 +02:00
{
_rootGrid.RequestedTheme(requestedTheme);
// Invalidate the window rect, so that we'll repaint any elements we're
// drawing ourselves to match the new theme
::InvalidateRect(_window.get(), nullptr, false);
}
Enable fullscreen mode (#3408) ## Summary of the Pull Request Enables the `toggleFullscreen` action to be able to enter fullscreen mode, bound by default to <kbd>alt+enter</kbd>. The action is bubbled up to the WindowsTerminal (Win32) layer, where the window resizes itself to take the entire size of the monitor. This largely reuses code from conhost. Conhost already had a fullscreen mode, so I figured I might as well re-use that. ## References Unfortunately there are still very thin borders around the window when the NonClientIslandWindow is fullscreened. I think I know where the problem is. However, that area of code is about to get a massive overhaul with #3064, so I didn't want to necessarily make it worse right now. A follow up should be filed to add support for "Always show / reveal / never show tabs in fullscreen mode". Currently, the only mode is "never show tabs". Additionally, some of this code (particularily re:drawing the nonclient area) could be re-used for #2238. ## PR Checklist * [x] Closes #531, #3411 * [x] I work here * [n/a] Tests added/passed 😭 * [x] Requires documentation to be updated ## Validation Steps Performed * Manually tested both the NonClientIslandWindow and the IslandWindow. * Cherry-pick commit 8e56bfe * Don't draw the tab strip when maximized (cherry picked from commit bac4be7c0f3ed1cdcd4f9ae8980fc98103538613) * Fix the vista window flash for the NCIW (cherry picked from commit 7d3a18a893c02bd2ed75026f2aac52e20321a1cf) * Some code cleanup for review (cherry picked from commit 9e22b7730bba426adcbfd9e7025f192dbf8efb32) * A tad bit more notes and cleanup * Update schema, docs * Most of the PR comments * I'm not sure this actually works, so I'm committing it to revert it and check * Update some comments that were lost. * Fix a build break? * oh no
2019-11-05 20:40:29 +01:00
// Method Description:
// - Toggles our fullscreen state. See _SetIsFullscreen for more details.
// Arguments:
// - <none>
// Return Value:
// - <none>
void IslandWindow::ToggleFullscreen()
{
_SetIsFullscreen(!_fullscreen);
}
// From GdiEngine::s_SetWindowLongWHelper
void _SetWindowLongWHelper(const HWND hWnd, const int nIndex, const LONG dwNewLong) noexcept
{
// SetWindowLong has strange error handling. On success, it returns the
// previous Window Long value and doesn't modify the Last Error state. To
// deal with this, we set the last error to 0/S_OK first, call it, and if
// the previous long was 0, we check if the error was non-zero before
// reporting. Otherwise, we'll get an "Error: The operation has completed
// successfully." and there will be another screenshot on the internet
// making fun of Windows. See:
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms633591(v=vs.85).aspx
SetLastError(0);
LONG const lResult = SetWindowLongW(hWnd, nIndex, dwNewLong);
if (0 == lResult)
{
LOG_LAST_ERROR_IF(0 != GetLastError());
}
}
// Method Description:
// - Controls setting us into or out of fullscreen mode. Largely taken from
// Window::SetIsFullscreen in conhost.
// - When entering fullscreen mode, we'll save the current window size and
// location, and expand to take the entire monitor size. When leaving, we'll
// use that saved size to restore back to.
// - When we're entering fullscreen we need to do some additional modification
// of our window styles. However, the NonClientIslandWindow very explicitly
// _doesn't_ need to do these steps. Subclasses should override
// _ShouldUpdateStylesOnFullscreen to disable setting these window styles.
// Arguments:
// - fullscreenEnabled true if we should enable fullscreen mode, false to disable.
// Return Value:
// - <none>
void IslandWindow::_SetIsFullscreen(const bool fullscreenEnabled)
{
// It is possible to enter _SetIsFullscreen even if we're already in full
// screen. Use the old is in fullscreen flag to gate checks that rely on the
// current state.
const auto oldIsInFullscreen = _fullscreen;
_fullscreen = fullscreenEnabled;
Use WS_POPUP for NonClientIslandWindow instead of overriding WM_NCCALCSIZE to remove borders (#3721) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Fixes the sides disappearing when entering full screen mode when the window is maximized. However, now, a Vista-style frame briefly appears when entering/exiting full screen. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Closes #3709 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] Tests added/passed * [x] Requires documentation to be updated (no) * [ ] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments When the non-client island window is maximized and has the WS_OVERLAPPEDWINDOW style, SetWindowPos is "lying": the position ends up being offset compared to the one we gave it (found by debugging). So I changed it to use WS_POPUP like the client island window was already doing. But now it has the Vista frame that appears briefly when entering/exiting full screen like the client island window. <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed
2019-12-16 21:58:38 +01:00
HWND const hWnd = GetWindowHandle();
// First, modify regular window styles as appropriate
auto windowStyle = GetWindowLongW(hWnd, GWL_STYLE);
// When moving to fullscreen, remove WS_OVERLAPPEDWINDOW, which specifies
// styles for non-fullscreen windows (e.g. caption bar), and add the
// WS_POPUP style to allow us to size ourselves to the monitor size.
// Do the reverse when restoring from fullscreen.
// Doing these modifications to that window will cause a vista-style
// window frame to briefly appear when entering and exiting fullscreen.
if (_fullscreen)
Enable fullscreen mode (#3408) ## Summary of the Pull Request Enables the `toggleFullscreen` action to be able to enter fullscreen mode, bound by default to <kbd>alt+enter</kbd>. The action is bubbled up to the WindowsTerminal (Win32) layer, where the window resizes itself to take the entire size of the monitor. This largely reuses code from conhost. Conhost already had a fullscreen mode, so I figured I might as well re-use that. ## References Unfortunately there are still very thin borders around the window when the NonClientIslandWindow is fullscreened. I think I know where the problem is. However, that area of code is about to get a massive overhaul with #3064, so I didn't want to necessarily make it worse right now. A follow up should be filed to add support for "Always show / reveal / never show tabs in fullscreen mode". Currently, the only mode is "never show tabs". Additionally, some of this code (particularily re:drawing the nonclient area) could be re-used for #2238. ## PR Checklist * [x] Closes #531, #3411 * [x] I work here * [n/a] Tests added/passed 😭 * [x] Requires documentation to be updated ## Validation Steps Performed * Manually tested both the NonClientIslandWindow and the IslandWindow. * Cherry-pick commit 8e56bfe * Don't draw the tab strip when maximized (cherry picked from commit bac4be7c0f3ed1cdcd4f9ae8980fc98103538613) * Fix the vista window flash for the NCIW (cherry picked from commit 7d3a18a893c02bd2ed75026f2aac52e20321a1cf) * Some code cleanup for review (cherry picked from commit 9e22b7730bba426adcbfd9e7025f192dbf8efb32) * A tad bit more notes and cleanup * Update schema, docs * Most of the PR comments * I'm not sure this actually works, so I'm committing it to revert it and check * Update some comments that were lost. * Fix a build break? * oh no
2019-11-05 20:40:29 +01:00
{
Use WS_POPUP for NonClientIslandWindow instead of overriding WM_NCCALCSIZE to remove borders (#3721) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Fixes the sides disappearing when entering full screen mode when the window is maximized. However, now, a Vista-style frame briefly appears when entering/exiting full screen. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Closes #3709 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] Tests added/passed * [x] Requires documentation to be updated (no) * [ ] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments When the non-client island window is maximized and has the WS_OVERLAPPEDWINDOW style, SetWindowPos is "lying": the position ends up being offset compared to the one we gave it (found by debugging). So I changed it to use WS_POPUP like the client island window was already doing. But now it has the Vista frame that appears briefly when entering/exiting full screen like the client island window. <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed
2019-12-16 21:58:38 +01:00
WI_ClearAllFlags(windowStyle, WS_OVERLAPPEDWINDOW);
WI_SetFlag(windowStyle, WS_POPUP);
}
else
{
WI_ClearFlag(windowStyle, WS_POPUP);
WI_SetAllFlags(windowStyle, WS_OVERLAPPEDWINDOW);
}
Enable fullscreen mode (#3408) ## Summary of the Pull Request Enables the `toggleFullscreen` action to be able to enter fullscreen mode, bound by default to <kbd>alt+enter</kbd>. The action is bubbled up to the WindowsTerminal (Win32) layer, where the window resizes itself to take the entire size of the monitor. This largely reuses code from conhost. Conhost already had a fullscreen mode, so I figured I might as well re-use that. ## References Unfortunately there are still very thin borders around the window when the NonClientIslandWindow is fullscreened. I think I know where the problem is. However, that area of code is about to get a massive overhaul with #3064, so I didn't want to necessarily make it worse right now. A follow up should be filed to add support for "Always show / reveal / never show tabs in fullscreen mode". Currently, the only mode is "never show tabs". Additionally, some of this code (particularily re:drawing the nonclient area) could be re-used for #2238. ## PR Checklist * [x] Closes #531, #3411 * [x] I work here * [n/a] Tests added/passed 😭 * [x] Requires documentation to be updated ## Validation Steps Performed * Manually tested both the NonClientIslandWindow and the IslandWindow. * Cherry-pick commit 8e56bfe * Don't draw the tab strip when maximized (cherry picked from commit bac4be7c0f3ed1cdcd4f9ae8980fc98103538613) * Fix the vista window flash for the NCIW (cherry picked from commit 7d3a18a893c02bd2ed75026f2aac52e20321a1cf) * Some code cleanup for review (cherry picked from commit 9e22b7730bba426adcbfd9e7025f192dbf8efb32) * A tad bit more notes and cleanup * Update schema, docs * Most of the PR comments * I'm not sure this actually works, so I'm committing it to revert it and check * Update some comments that were lost. * Fix a build break? * oh no
2019-11-05 20:40:29 +01:00
Use WS_POPUP for NonClientIslandWindow instead of overriding WM_NCCALCSIZE to remove borders (#3721) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Fixes the sides disappearing when entering full screen mode when the window is maximized. However, now, a Vista-style frame briefly appears when entering/exiting full screen. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Closes #3709 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] Tests added/passed * [x] Requires documentation to be updated (no) * [ ] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments When the non-client island window is maximized and has the WS_OVERLAPPEDWINDOW style, SetWindowPos is "lying": the position ends up being offset compared to the one we gave it (found by debugging). So I changed it to use WS_POPUP like the client island window was already doing. But now it has the Vista frame that appears briefly when entering/exiting full screen like the client island window. <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed
2019-12-16 21:58:38 +01:00
_SetWindowLongWHelper(hWnd, GWL_STYLE, windowStyle);
Enable fullscreen mode (#3408) ## Summary of the Pull Request Enables the `toggleFullscreen` action to be able to enter fullscreen mode, bound by default to <kbd>alt+enter</kbd>. The action is bubbled up to the WindowsTerminal (Win32) layer, where the window resizes itself to take the entire size of the monitor. This largely reuses code from conhost. Conhost already had a fullscreen mode, so I figured I might as well re-use that. ## References Unfortunately there are still very thin borders around the window when the NonClientIslandWindow is fullscreened. I think I know where the problem is. However, that area of code is about to get a massive overhaul with #3064, so I didn't want to necessarily make it worse right now. A follow up should be filed to add support for "Always show / reveal / never show tabs in fullscreen mode". Currently, the only mode is "never show tabs". Additionally, some of this code (particularily re:drawing the nonclient area) could be re-used for #2238. ## PR Checklist * [x] Closes #531, #3411 * [x] I work here * [n/a] Tests added/passed 😭 * [x] Requires documentation to be updated ## Validation Steps Performed * Manually tested both the NonClientIslandWindow and the IslandWindow. * Cherry-pick commit 8e56bfe * Don't draw the tab strip when maximized (cherry picked from commit bac4be7c0f3ed1cdcd4f9ae8980fc98103538613) * Fix the vista window flash for the NCIW (cherry picked from commit 7d3a18a893c02bd2ed75026f2aac52e20321a1cf) * Some code cleanup for review (cherry picked from commit 9e22b7730bba426adcbfd9e7025f192dbf8efb32) * A tad bit more notes and cleanup * Update schema, docs * Most of the PR comments * I'm not sure this actually works, so I'm committing it to revert it and check * Update some comments that were lost. * Fix a build break? * oh no
2019-11-05 20:40:29 +01:00
Use WS_POPUP for NonClientIslandWindow instead of overriding WM_NCCALCSIZE to remove borders (#3721) <!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Fixes the sides disappearing when entering full screen mode when the window is maximized. However, now, a Vista-style frame briefly appears when entering/exiting full screen. <!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> ## References <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Closes #3709 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] Tests added/passed * [x] Requires documentation to be updated (no) * [ ] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments When the non-client island window is maximized and has the WS_OVERLAPPEDWINDOW style, SetWindowPos is "lying": the position ends up being offset compared to the one we gave it (found by debugging). So I changed it to use WS_POPUP like the client island window was already doing. But now it has the Vista frame that appears briefly when entering/exiting full screen like the client island window. <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed
2019-12-16 21:58:38 +01:00
// Now modify extended window styles as appropriate
// When moving to fullscreen, remove the window edge style to avoid an
// ugly border when not focused.
auto exWindowStyle = GetWindowLongW(hWnd, GWL_EXSTYLE);
WI_UpdateFlag(exWindowStyle, WS_EX_WINDOWEDGE, !_fullscreen);
_SetWindowLongWHelper(hWnd, GWL_EXSTYLE, exWindowStyle);
Enable fullscreen mode (#3408) ## Summary of the Pull Request Enables the `toggleFullscreen` action to be able to enter fullscreen mode, bound by default to <kbd>alt+enter</kbd>. The action is bubbled up to the WindowsTerminal (Win32) layer, where the window resizes itself to take the entire size of the monitor. This largely reuses code from conhost. Conhost already had a fullscreen mode, so I figured I might as well re-use that. ## References Unfortunately there are still very thin borders around the window when the NonClientIslandWindow is fullscreened. I think I know where the problem is. However, that area of code is about to get a massive overhaul with #3064, so I didn't want to necessarily make it worse right now. A follow up should be filed to add support for "Always show / reveal / never show tabs in fullscreen mode". Currently, the only mode is "never show tabs". Additionally, some of this code (particularily re:drawing the nonclient area) could be re-used for #2238. ## PR Checklist * [x] Closes #531, #3411 * [x] I work here * [n/a] Tests added/passed 😭 * [x] Requires documentation to be updated ## Validation Steps Performed * Manually tested both the NonClientIslandWindow and the IslandWindow. * Cherry-pick commit 8e56bfe * Don't draw the tab strip when maximized (cherry picked from commit bac4be7c0f3ed1cdcd4f9ae8980fc98103538613) * Fix the vista window flash for the NCIW (cherry picked from commit 7d3a18a893c02bd2ed75026f2aac52e20321a1cf) * Some code cleanup for review (cherry picked from commit 9e22b7730bba426adcbfd9e7025f192dbf8efb32) * A tad bit more notes and cleanup * Update schema, docs * Most of the PR comments * I'm not sure this actually works, so I'm committing it to revert it and check * Update some comments that were lost. * Fix a build break? * oh no
2019-11-05 20:40:29 +01:00
_BackupWindowSizes(oldIsInFullscreen);
_ApplyWindowSize();
}
// Method Description:
// - Used in entering/exiting fullscreen mode. Saves the current window size,
// and the full size of the monitor, for use in _ApplyWindowSize.
// - Taken from conhost's Window::_BackupWindowSizes
// Arguments:
// - fCurrentIsInFullscreen: true if we're currently in fullscreen mode.
// Return Value:
// - <none>
void IslandWindow::_BackupWindowSizes(const bool fCurrentIsInFullscreen)
{
if (_fullscreen)
{
// Note: the current window size depends on the current state of the
// window. So don't back it up if we're already in full screen.
if (!fCurrentIsInFullscreen)
{
_nonFullscreenWindowSize = GetWindowRect();
}
// get and back up the current monitor's size
HMONITOR const hCurrentMonitor = MonitorFromWindow(GetWindowHandle(), MONITOR_DEFAULTTONEAREST);
MONITORINFO currMonitorInfo;
currMonitorInfo.cbSize = sizeof(currMonitorInfo);
if (GetMonitorInfo(hCurrentMonitor, &currMonitorInfo))
{
_fullscreenWindowSize = currMonitorInfo.rcMonitor;
}
}
}
// Method Description:
// - Applys the appropriate window size for transitioning to/from fullscreen mode.
// - Taken from conhost's Window::_ApplyWindowSize
// Arguments:
// - <none>
// Return Value:
// - <none>
void IslandWindow::_ApplyWindowSize()
{
const auto newSize = _fullscreen ? _fullscreenWindowSize : _nonFullscreenWindowSize;
LOG_IF_WIN32_BOOL_FALSE(SetWindowPos(GetWindowHandle(),
HWND_TOP,
newSize.left,
newSize.top,
newSize.right - newSize.left,
newSize.bottom - newSize.top,
SWP_FRAMECHANGED));
}
DEFINE_EVENT(IslandWindow, DragRegionClicked, _DragRegionClickedHandlers, winrt::delegate<>);
DEFINE_EVENT(IslandWindow, WindowCloseButtonClicked, _windowCloseButtonClickedHandler, winrt::delegate<>);