terminal/src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp

973 lines
38 KiB
C++
Raw Normal View History

/********************************************************
* *
* Copyright (C) Microsoft. All rights reserved. *
* *
********************************************************/
#include "pch.h"
#include "NonClientIslandWindow.h"
#include "../types/inc/utils.hpp"
#include "TerminalThemeHelpers.h"
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;
using namespace ::Microsoft::Console::Types;
static constexpr int AutohideTaskbarSize = 2;
NonClientIslandWindow::NonClientIslandWindow(const ElementTheme& requestedTheme) noexcept :
IslandWindow{},
_backgroundBrushColor{ 0, 0, 0 },
_theme{ requestedTheme },
_isMaximized{ false }
{
}
NonClientIslandWindow::~NonClientIslandWindow()
{
}
Replace the HRGN-based titlebar cutout with an overlay window (#5485) Also known as "Kill HRGN II: Kills Regions Dead (#5485)" Copying the description from @greg904 in #4778. --- 8< --- My understanding is that the XAML framework uses another way of getting mouse input that doesn't work with `WM_SYSCOMMAND` with `SC_MOVE`. It looks like it "steals" our mouse messages like `WM_LBUTTONDOWN`. Before, we were cutting (with `HRGN`s) the drag bar part of the XAML islands window in order to catch mouse messages and be able to implement the drag bar that can move the window. However this "cut" doesn't only apply to input (mouse messages) but also to the graphics so we had to paint behind with the same color as the drag bar using GDI to hide the fact that we were cutting the window. The main issue with this is that we have to replicate exactly the rendering on the XAML drag bar using GDI and this is bad because: 1. it's hard to keep track of the right color: if a dialog is open, it will cover the whole window including the drag bar with a transparent white layer and it's hard to keep track of those things. 2. we can't do acrylic with GDI So I found another method, which is to instead put a "drag window" exactly where the drag bar is, but on top of the XAML islands window (in Z order). I've found that this lets us receive the `WM_LBUTTONDOWN` messages. --- >8 --- Dustin's notes: I've based this on the implementation of the input sink window in the UWP application frame host. Tested manually in all configurations (debug, release) with snap, drag, move, double-click and double-click on the resize handle. Tested at 200% scale. Closes #4744 Closes #2100 Closes #4778 (superseded.)
2020-04-25 00:22:40 +02:00
static constexpr const wchar_t* dragBarClassName{ L"DRAG_BAR_WINDOW_CLASS" };
[[nodiscard]] LRESULT __stdcall NonClientIslandWindow::_StaticInputSinkWndProc(HWND const window, UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept
{
WINRT_ASSERT(window);
if (WM_NCCREATE == message)
{
auto cs = reinterpret_cast<CREATESTRUCT*>(lparam);
auto nonClientIslandWindow{ reinterpret_cast<NonClientIslandWindow*>(cs->lpCreateParams) };
SetWindowLongPtr(window, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(nonClientIslandWindow));
// fall through to default window procedure
}
else if (auto nonClientIslandWindow{ reinterpret_cast<NonClientIslandWindow*>(GetWindowLongPtr(window, GWLP_USERDATA)) })
{
return nonClientIslandWindow->_InputSinkMessageHandler(message, wparam, lparam);
}
return DefWindowProc(window, message, wparam, lparam);
}
void NonClientIslandWindow::MakeWindow() noexcept
{
IslandWindow::MakeWindow();
static ATOM dragBarWindowClass{ []() {
WNDCLASSEX wcEx{};
wcEx.cbSize = sizeof(wcEx);
wcEx.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
wcEx.lpszClassName = dragBarClassName;
wcEx.hbrBackground = reinterpret_cast<HBRUSH>(GetStockObject(BLACK_BRUSH));
wcEx.hCursor = LoadCursor(nullptr, IDC_ARROW);
wcEx.lpfnWndProc = &NonClientIslandWindow::_StaticInputSinkWndProc;
wcEx.hInstance = wil::GetModuleInstanceHandle();
wcEx.cbWndExtra = sizeof(NonClientIslandWindow*);
return RegisterClassEx(&wcEx);
}() };
// The drag bar window is a child window of the top level window that is put
// right on top of the drag bar. The XAML island window "steals" our mouse
// messages which makes it hard to implement a custom drag area. By putting
// a window on top of it, we prevent it from "stealing" the mouse messages.
_dragBarWindow.reset(CreateWindowExW(WS_EX_LAYERED | WS_EX_NOREDIRECTIONBITMAP,
dragBarClassName,
L"",
WS_CHILD,
0,
0,
0,
0,
GetHandle(),
Replace the HRGN-based titlebar cutout with an overlay window (#5485) Also known as "Kill HRGN II: Kills Regions Dead (#5485)" Copying the description from @greg904 in #4778. --- 8< --- My understanding is that the XAML framework uses another way of getting mouse input that doesn't work with `WM_SYSCOMMAND` with `SC_MOVE`. It looks like it "steals" our mouse messages like `WM_LBUTTONDOWN`. Before, we were cutting (with `HRGN`s) the drag bar part of the XAML islands window in order to catch mouse messages and be able to implement the drag bar that can move the window. However this "cut" doesn't only apply to input (mouse messages) but also to the graphics so we had to paint behind with the same color as the drag bar using GDI to hide the fact that we were cutting the window. The main issue with this is that we have to replicate exactly the rendering on the XAML drag bar using GDI and this is bad because: 1. it's hard to keep track of the right color: if a dialog is open, it will cover the whole window including the drag bar with a transparent white layer and it's hard to keep track of those things. 2. we can't do acrylic with GDI So I found another method, which is to instead put a "drag window" exactly where the drag bar is, but on top of the XAML islands window (in Z order). I've found that this lets us receive the `WM_LBUTTONDOWN` messages. --- >8 --- Dustin's notes: I've based this on the implementation of the input sink window in the UWP application frame host. Tested manually in all configurations (debug, release) with snap, drag, move, double-click and double-click on the resize handle. Tested at 200% scale. Closes #4744 Closes #2100 Closes #4778 (superseded.)
2020-04-25 00:22:40 +02:00
nullptr,
wil::GetModuleInstanceHandle(),
this));
THROW_HR_IF_NULL(E_UNEXPECTED, _dragBarWindow);
}
// Function Description:
// - The window procedure for the drag bar forwards clicks on its client area to its parent as non-client clicks.
LRESULT NonClientIslandWindow::_InputSinkMessageHandler(UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept
Replace the HRGN-based titlebar cutout with an overlay window (#5485) Also known as "Kill HRGN II: Kills Regions Dead (#5485)" Copying the description from @greg904 in #4778. --- 8< --- My understanding is that the XAML framework uses another way of getting mouse input that doesn't work with `WM_SYSCOMMAND` with `SC_MOVE`. It looks like it "steals" our mouse messages like `WM_LBUTTONDOWN`. Before, we were cutting (with `HRGN`s) the drag bar part of the XAML islands window in order to catch mouse messages and be able to implement the drag bar that can move the window. However this "cut" doesn't only apply to input (mouse messages) but also to the graphics so we had to paint behind with the same color as the drag bar using GDI to hide the fact that we were cutting the window. The main issue with this is that we have to replicate exactly the rendering on the XAML drag bar using GDI and this is bad because: 1. it's hard to keep track of the right color: if a dialog is open, it will cover the whole window including the drag bar with a transparent white layer and it's hard to keep track of those things. 2. we can't do acrylic with GDI So I found another method, which is to instead put a "drag window" exactly where the drag bar is, but on top of the XAML islands window (in Z order). I've found that this lets us receive the `WM_LBUTTONDOWN` messages. --- >8 --- Dustin's notes: I've based this on the implementation of the input sink window in the UWP application frame host. Tested manually in all configurations (debug, release) with snap, drag, move, double-click and double-click on the resize handle. Tested at 200% scale. Closes #4744 Closes #2100 Closes #4778 (superseded.)
2020-04-25 00:22:40 +02:00
{
std::optional<UINT> nonClientMessage{ std::nullopt };
// translate WM_ messages on the window to WM_NC* on the top level window
switch (message)
{
case WM_LBUTTONDOWN:
nonClientMessage = WM_NCLBUTTONDOWN;
break;
case WM_LBUTTONDBLCLK:
nonClientMessage = WM_NCLBUTTONDBLCLK;
break;
case WM_LBUTTONUP:
nonClientMessage = WM_NCLBUTTONUP;
break;
case WM_RBUTTONDOWN:
nonClientMessage = WM_NCRBUTTONDOWN;
break;
case WM_RBUTTONDBLCLK:
nonClientMessage = WM_NCRBUTTONDBLCLK;
break;
case WM_RBUTTONUP:
nonClientMessage = WM_NCRBUTTONUP;
break;
}
if (nonClientMessage.has_value())
{
const POINT clientPt{ GET_X_LPARAM(lparam), GET_Y_LPARAM(lparam) };
POINT screenPt{ clientPt };
if (ClientToScreen(_dragBarWindow.get(), &screenPt))
{
auto parentWindow{ GetHandle() };
Replace the HRGN-based titlebar cutout with an overlay window (#5485) Also known as "Kill HRGN II: Kills Regions Dead (#5485)" Copying the description from @greg904 in #4778. --- 8< --- My understanding is that the XAML framework uses another way of getting mouse input that doesn't work with `WM_SYSCOMMAND` with `SC_MOVE`. It looks like it "steals" our mouse messages like `WM_LBUTTONDOWN`. Before, we were cutting (with `HRGN`s) the drag bar part of the XAML islands window in order to catch mouse messages and be able to implement the drag bar that can move the window. However this "cut" doesn't only apply to input (mouse messages) but also to the graphics so we had to paint behind with the same color as the drag bar using GDI to hide the fact that we were cutting the window. The main issue with this is that we have to replicate exactly the rendering on the XAML drag bar using GDI and this is bad because: 1. it's hard to keep track of the right color: if a dialog is open, it will cover the whole window including the drag bar with a transparent white layer and it's hard to keep track of those things. 2. we can't do acrylic with GDI So I found another method, which is to instead put a "drag window" exactly where the drag bar is, but on top of the XAML islands window (in Z order). I've found that this lets us receive the `WM_LBUTTONDOWN` messages. --- >8 --- Dustin's notes: I've based this on the implementation of the input sink window in the UWP application frame host. Tested manually in all configurations (debug, release) with snap, drag, move, double-click and double-click on the resize handle. Tested at 200% scale. Closes #4744 Closes #2100 Closes #4778 (superseded.)
2020-04-25 00:22:40 +02:00
const LPARAM newLparam = MAKELPARAM(screenPt.x, screenPt.y);
Replace the HRGN-based titlebar cutout with an overlay window (#5485) Also known as "Kill HRGN II: Kills Regions Dead (#5485)" Copying the description from @greg904 in #4778. --- 8< --- My understanding is that the XAML framework uses another way of getting mouse input that doesn't work with `WM_SYSCOMMAND` with `SC_MOVE`. It looks like it "steals" our mouse messages like `WM_LBUTTONDOWN`. Before, we were cutting (with `HRGN`s) the drag bar part of the XAML islands window in order to catch mouse messages and be able to implement the drag bar that can move the window. However this "cut" doesn't only apply to input (mouse messages) but also to the graphics so we had to paint behind with the same color as the drag bar using GDI to hide the fact that we were cutting the window. The main issue with this is that we have to replicate exactly the rendering on the XAML drag bar using GDI and this is bad because: 1. it's hard to keep track of the right color: if a dialog is open, it will cover the whole window including the drag bar with a transparent white layer and it's hard to keep track of those things. 2. we can't do acrylic with GDI So I found another method, which is to instead put a "drag window" exactly where the drag bar is, but on top of the XAML islands window (in Z order). I've found that this lets us receive the `WM_LBUTTONDOWN` messages. --- >8 --- Dustin's notes: I've based this on the implementation of the input sink window in the UWP application frame host. Tested manually in all configurations (debug, release) with snap, drag, move, double-click and double-click on the resize handle. Tested at 200% scale. Closes #4744 Closes #2100 Closes #4778 (superseded.)
2020-04-25 00:22:40 +02:00
// Hit test the parent window at the screen coordinates the user clicked in the drag input sink window,
// then pass that click through as an NC click in that location.
const LRESULT hitTest{ SendMessage(parentWindow, WM_NCHITTEST, 0, newLparam) };
SendMessage(parentWindow, nonClientMessage.value(), hitTest, newLparam);
Replace the HRGN-based titlebar cutout with an overlay window (#5485) Also known as "Kill HRGN II: Kills Regions Dead (#5485)" Copying the description from @greg904 in #4778. --- 8< --- My understanding is that the XAML framework uses another way of getting mouse input that doesn't work with `WM_SYSCOMMAND` with `SC_MOVE`. It looks like it "steals" our mouse messages like `WM_LBUTTONDOWN`. Before, we were cutting (with `HRGN`s) the drag bar part of the XAML islands window in order to catch mouse messages and be able to implement the drag bar that can move the window. However this "cut" doesn't only apply to input (mouse messages) but also to the graphics so we had to paint behind with the same color as the drag bar using GDI to hide the fact that we were cutting the window. The main issue with this is that we have to replicate exactly the rendering on the XAML drag bar using GDI and this is bad because: 1. it's hard to keep track of the right color: if a dialog is open, it will cover the whole window including the drag bar with a transparent white layer and it's hard to keep track of those things. 2. we can't do acrylic with GDI So I found another method, which is to instead put a "drag window" exactly where the drag bar is, but on top of the XAML islands window (in Z order). I've found that this lets us receive the `WM_LBUTTONDOWN` messages. --- >8 --- Dustin's notes: I've based this on the implementation of the input sink window in the UWP application frame host. Tested manually in all configurations (debug, release) with snap, drag, move, double-click and double-click on the resize handle. Tested at 200% scale. Closes #4744 Closes #2100 Closes #4778 (superseded.)
2020-04-25 00:22:40 +02:00
return 0;
}
}
return DefWindowProc(_dragBarWindow.get(), message, wparam, lparam);
}
// Method Description:
// - Resizes and shows/hides the drag bar input sink window.
// This window is used to capture clicks on the non-client area.
void NonClientIslandWindow::_ResizeDragBarWindow() noexcept
{
const til::rectangle rect{ _GetDragAreaRect() };
if (_IsTitlebarVisible() && rect.size().area() > 0)
{
SetWindowPos(_dragBarWindow.get(),
HWND_TOP,
rect.left<int>(),
rect.top<int>() + _GetTopBorderHeight(),
rect.width<int>(),
rect.height<int>(),
SWP_NOACTIVATE | SWP_SHOWWINDOW);
SetLayeredWindowAttributes(_dragBarWindow.get(), 0, 255, LWA_ALPHA);
}
else
{
SetWindowPos(_dragBarWindow.get(), HWND_BOTTOM, 0, 0, 0, 0, SWP_HIDEWINDOW | SWP_NOMOVE | SWP_NOSIZE);
}
}
// Method Description:
// - Called when the app's size changes. When that happens, the size of the drag
// bar may have changed. If it has, we'll need to update the WindowRgn of the
// interop window.
// Arguments:
// - <unused>
// Return Value:
// - <none>
void NonClientIslandWindow::_OnDragBarSizeChanged(winrt::Windows::Foundation::IInspectable /*sender*/,
Replace the HRGN-based titlebar cutout with an overlay window (#5485) Also known as "Kill HRGN II: Kills Regions Dead (#5485)" Copying the description from @greg904 in #4778. --- 8< --- My understanding is that the XAML framework uses another way of getting mouse input that doesn't work with `WM_SYSCOMMAND` with `SC_MOVE`. It looks like it "steals" our mouse messages like `WM_LBUTTONDOWN`. Before, we were cutting (with `HRGN`s) the drag bar part of the XAML islands window in order to catch mouse messages and be able to implement the drag bar that can move the window. However this "cut" doesn't only apply to input (mouse messages) but also to the graphics so we had to paint behind with the same color as the drag bar using GDI to hide the fact that we were cutting the window. The main issue with this is that we have to replicate exactly the rendering on the XAML drag bar using GDI and this is bad because: 1. it's hard to keep track of the right color: if a dialog is open, it will cover the whole window including the drag bar with a transparent white layer and it's hard to keep track of those things. 2. we can't do acrylic with GDI So I found another method, which is to instead put a "drag window" exactly where the drag bar is, but on top of the XAML islands window (in Z order). I've found that this lets us receive the `WM_LBUTTONDOWN` messages. --- >8 --- Dustin's notes: I've based this on the implementation of the input sink window in the UWP application frame host. Tested manually in all configurations (debug, release) with snap, drag, move, double-click and double-click on the resize handle. Tested at 200% scale. Closes #4744 Closes #2100 Closes #4778 (superseded.)
2020-04-25 00:22:40 +02:00
winrt::Windows::UI::Xaml::SizeChangedEventArgs /*eventArgs*/)
{
Replace the HRGN-based titlebar cutout with an overlay window (#5485) Also known as "Kill HRGN II: Kills Regions Dead (#5485)" Copying the description from @greg904 in #4778. --- 8< --- My understanding is that the XAML framework uses another way of getting mouse input that doesn't work with `WM_SYSCOMMAND` with `SC_MOVE`. It looks like it "steals" our mouse messages like `WM_LBUTTONDOWN`. Before, we were cutting (with `HRGN`s) the drag bar part of the XAML islands window in order to catch mouse messages and be able to implement the drag bar that can move the window. However this "cut" doesn't only apply to input (mouse messages) but also to the graphics so we had to paint behind with the same color as the drag bar using GDI to hide the fact that we were cutting the window. The main issue with this is that we have to replicate exactly the rendering on the XAML drag bar using GDI and this is bad because: 1. it's hard to keep track of the right color: if a dialog is open, it will cover the whole window including the drag bar with a transparent white layer and it's hard to keep track of those things. 2. we can't do acrylic with GDI So I found another method, which is to instead put a "drag window" exactly where the drag bar is, but on top of the XAML islands window (in Z order). I've found that this lets us receive the `WM_LBUTTONDOWN` messages. --- >8 --- Dustin's notes: I've based this on the implementation of the input sink window in the UWP application frame host. Tested manually in all configurations (debug, release) with snap, drag, move, double-click and double-click on the resize handle. Tested at 200% scale. Closes #4744 Closes #2100 Closes #4778 (superseded.)
2020-04-25 00:22:40 +02:00
_ResizeDragBarWindow();
}
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 NonClientIslandWindow::OnAppInitialized()
{
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
IslandWindow::OnAppInitialized();
}
void NonClientIslandWindow::Initialize()
{
IslandWindow::Initialize();
_UpdateFrameMargins();
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
// Set up our grid of content. We'll use _rootGrid as our root element.
// There will be two children of this grid - the TitlebarControl, and the
// "client content"
_rootGrid.Children().Clear();
Controls::RowDefinition titlebarRow{};
Controls::RowDefinition contentRow{};
titlebarRow.Height(GridLengthHelper::Auto());
_rootGrid.RowDefinitions().Append(titlebarRow);
_rootGrid.RowDefinitions().Append(contentRow);
// Create our titlebar control
_titlebar = winrt::TerminalApp::TitlebarControl{ reinterpret_cast<uint64_t>(GetHandle()) };
_dragBar = _titlebar.DragBar();
_dragBar.SizeChanged({ this, &NonClientIslandWindow::_OnDragBarSizeChanged });
_rootGrid.SizeChanged({ this, &NonClientIslandWindow::_OnDragBarSizeChanged });
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(_titlebar);
Controls::Grid::SetRow(_titlebar, 0);
// GH#3440 - When the titlebar is loaded (officially added to our UI tree),
// then make sure to update it's visual state to reflect if we're in the
// maximized state on launch.
_titlebar.Loaded([this](auto&&, auto&&) { _OnMaximizeChange(); });
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:
// - Set the content of the "client area" of our window to the given content.
// Arguments:
// - content: the new UI element to use as the client content
// Return Value:
// - <none>
void NonClientIslandWindow::SetContent(winrt::Windows::UI::Xaml::UIElement content)
{
_clientContent = content;
_rootGrid.Children().Append(content);
// SetRow only works on FrameworkElement's, so cast it to a FWE before
// calling. We know that our content is a Grid, so we don't need to worry
// about this.
const auto fwe = content.try_as<winrt::Windows::UI::Xaml::FrameworkElement>();
if (fwe)
{
Controls::Grid::SetRow(fwe, 1);
}
}
// Method Description:
// - Set the content of the "titlebar area" of our window to the given content.
// Arguments:
// - content: the new UI element to use as the titlebar content
// Return Value:
// - <none>
void NonClientIslandWindow::SetTitlebarContent(winrt::Windows::UI::Xaml::UIElement content)
{
_titlebar.Content(content);
// GH#4288 - add a SizeChanged handler to this content. It's possible that
// this element's size will change after the dragbar's. When that happens,
// the drag bar won't send another SizeChanged event, because the dragbar's
// _size_ didn't change, only it's position.
const auto fwe = content.try_as<winrt::Windows::UI::Xaml::FrameworkElement>();
if (fwe)
{
fwe.SizeChanged({ this, &NonClientIslandWindow::_OnDragBarSizeChanged });
}
}
// Method Description:
// - This method computes the height of the little border above the title bar
// and returns it. If the border is disabled, then this method will return 0.
// Return Value:
// - the height of the border above the title bar or 0 if it's disabled
int NonClientIslandWindow::_GetTopBorderHeight() const noexcept
{
7012: top margin disappears upon resize in focus mode (#8140) <!-- 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 In the focus mode the top border disappears upon resize. While this behavior is expected in the maximized / full screen mode, it should not happen in the focus mode. <!-- 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 https://github.com/microsoft/terminal/issues/7012 * [x] CLA signed * [ ] Tests added/passed - nope, only manual testing * [ ] Documentation updated - irrelevant * [ ] Schema updated - irrelevant * [ ] 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 _GetTopBorderHeight method returns 0 when maximized or no title bar is visible. However the existence of top border has nothing to do with whether the title bar is visible. We want to leave the border as long as the window is not in some form of maximizing (maximized / full screen) <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed * Manual - dragging, resizing, maximizing both in focus and non focus modes + full screen testing
2020-11-03 18:40:02 +01:00
// No border when maximized or fullscreen.
// Yet we still need it in the focus mode to allow dragging (GH#7012)
if (_isMaximized || _fullscreen)
{
return 0;
}
return topBorderVisibleHeight;
}
RECT NonClientIslandWindow::_GetDragAreaRect() const noexcept
{
Replace the HRGN-based titlebar cutout with an overlay window (#5485) Also known as "Kill HRGN II: Kills Regions Dead (#5485)" Copying the description from @greg904 in #4778. --- 8< --- My understanding is that the XAML framework uses another way of getting mouse input that doesn't work with `WM_SYSCOMMAND` with `SC_MOVE`. It looks like it "steals" our mouse messages like `WM_LBUTTONDOWN`. Before, we were cutting (with `HRGN`s) the drag bar part of the XAML islands window in order to catch mouse messages and be able to implement the drag bar that can move the window. However this "cut" doesn't only apply to input (mouse messages) but also to the graphics so we had to paint behind with the same color as the drag bar using GDI to hide the fact that we were cutting the window. The main issue with this is that we have to replicate exactly the rendering on the XAML drag bar using GDI and this is bad because: 1. it's hard to keep track of the right color: if a dialog is open, it will cover the whole window including the drag bar with a transparent white layer and it's hard to keep track of those things. 2. we can't do acrylic with GDI So I found another method, which is to instead put a "drag window" exactly where the drag bar is, but on top of the XAML islands window (in Z order). I've found that this lets us receive the `WM_LBUTTONDOWN` messages. --- >8 --- Dustin's notes: I've based this on the implementation of the input sink window in the UWP application frame host. Tested manually in all configurations (debug, release) with snap, drag, move, double-click and double-click on the resize handle. Tested at 200% scale. Closes #4744 Closes #2100 Closes #4778 (superseded.)
2020-04-25 00:22:40 +02:00
if (_dragBar && _dragBar.Visibility() == Visibility::Visible)
{
const auto scale = GetCurrentDpiScale();
const auto transform = _dragBar.TransformToVisual(_rootGrid);
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
const auto logicalDragBarRect = winrt::Windows::Foundation::Rect{
0.0f,
0.0f,
static_cast<float>(_dragBar.ActualWidth()),
static_cast<float>(_dragBar.ActualHeight())
};
const auto clientDragBarRect = transform.TransformBounds(logicalDragBarRect);
RECT dragBarRect = {
static_cast<LONG>(clientDragBarRect.X * scale),
static_cast<LONG>(clientDragBarRect.Y * scale),
static_cast<LONG>((clientDragBarRect.Width + clientDragBarRect.X) * scale),
static_cast<LONG>((clientDragBarRect.Height + clientDragBarRect.Y) * scale),
};
return dragBarRect;
}
return RECT{};
}
// Method Description:
// - Called when the size of the window changes for any reason. Updates the
// XAML island to match our new sizing and also updates the maximize icon
// if the window went from maximized to restored or the opposite.
void NonClientIslandWindow::OnSize(const UINT width, const UINT height)
{
_UpdateMaximizedState();
if (_interopWindowHandle)
{
_UpdateIslandPosition(width, height);
}
// GH#11367: We need to do this,
// otherwise the titlebar may still be partially visible
// when we move between different DPI monitors.
RefreshCurrentDPI();
_UpdateFrameMargins();
}
// Method Description:
// - Checks if the window has been maximized or restored since the last time.
// If it has been maximized or restored, then it updates the _isMaximized
// flags and notifies of the change by calling
// NonClientIslandWindow::_OnMaximizeChange.
void NonClientIslandWindow::_UpdateMaximizedState()
{
const auto windowStyle = GetWindowStyle(_window.get());
const auto newIsMaximized = WI_IsFlagSet(windowStyle, WS_MAXIMIZE);
if (_isMaximized != newIsMaximized)
{
_isMaximized = newIsMaximized;
_OnMaximizeChange();
}
}
// Method Description:
// - Called when the the windows goes from restored to maximized or from
// maximized to restored. Updates the maximize button's icon and the frame
// margins.
void NonClientIslandWindow::_OnMaximizeChange() noexcept
{
if (_titlebar)
{
const auto windowStyle = GetWindowStyle(_window.get());
const auto isIconified = WI_IsFlagSet(windowStyle, WS_ICONIC);
const auto state = _isMaximized ? winrt::TerminalApp::WindowVisualState::WindowVisualStateMaximized :
isIconified ? winrt::TerminalApp::WindowVisualState::WindowVisualStateIconified :
winrt::TerminalApp::WindowVisualState::WindowVisualStateNormal;
try
{
_titlebar.SetWindowVisualState(state);
}
CATCH_LOG();
}
// no frame margin when maximized
_UpdateFrameMargins();
}
// Method Description:
// - Called when the size of the window changes for any reason. Updates the
// sizes of our child XAML Islands to match our new sizing.
void NonClientIslandWindow::_UpdateIslandPosition(const UINT windowWidth, const UINT windowHeight)
{
const auto originalTopHeight = _GetTopBorderHeight();
// GH#7422
// !! BODGY !!
//
// For inexplicable reasons, the top row of pixels on our tabs, new tab
// button, and caption buttons is totally un-clickable. The mouse simply
// refuses to interact with them. So when we're maximized, on certain
// monitor configurations, this results in the top row of pixels not
// reacting to clicks at all. To obey Fitt's Law, we're gonna shift
// the entire island up one pixel. That will result in the top row of pixels
// in the window actually being the _second_ row of pixels for those
// buttons, which will make them clickable. It's perhaps not the right fix,
// but it works.
// _GetTopBorderHeight() returns 0 when we're maximized.
const short topBorderHeight = ::base::saturated_cast<short>((originalTopHeight == 0) ? -1 : originalTopHeight);
const COORD newIslandPos = { 0, topBorderHeight };
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
winrt::check_bool(SetWindowPos(_interopWindowHandle,
HWND_BOTTOM,
newIslandPos.X,
newIslandPos.Y,
windowWidth,
windowHeight - topBorderHeight,
SWP_SHOWWINDOW | SWP_NOACTIVATE));
// This happens when we go from maximized to restored or the opposite
// because topBorderHeight changes.
if (!_oldIslandPos.has_value() || _oldIslandPos.value() != newIslandPos)
{
// The drag bar's position changed compared to the client area because
// the island moved but we will not be notified about this in the
// NonClientIslandWindow::OnDragBarSizeChanged method because this
// method is only called when the position of the drag bar changes
// **inside** the island which is not the case here.
Replace the HRGN-based titlebar cutout with an overlay window (#5485) Also known as "Kill HRGN II: Kills Regions Dead (#5485)" Copying the description from @greg904 in #4778. --- 8< --- My understanding is that the XAML framework uses another way of getting mouse input that doesn't work with `WM_SYSCOMMAND` with `SC_MOVE`. It looks like it "steals" our mouse messages like `WM_LBUTTONDOWN`. Before, we were cutting (with `HRGN`s) the drag bar part of the XAML islands window in order to catch mouse messages and be able to implement the drag bar that can move the window. However this "cut" doesn't only apply to input (mouse messages) but also to the graphics so we had to paint behind with the same color as the drag bar using GDI to hide the fact that we were cutting the window. The main issue with this is that we have to replicate exactly the rendering on the XAML drag bar using GDI and this is bad because: 1. it's hard to keep track of the right color: if a dialog is open, it will cover the whole window including the drag bar with a transparent white layer and it's hard to keep track of those things. 2. we can't do acrylic with GDI So I found another method, which is to instead put a "drag window" exactly where the drag bar is, but on top of the XAML islands window (in Z order). I've found that this lets us receive the `WM_LBUTTONDOWN` messages. --- >8 --- Dustin's notes: I've based this on the implementation of the input sink window in the UWP application frame host. Tested manually in all configurations (debug, release) with snap, drag, move, double-click and double-click on the resize handle. Tested at 200% scale. Closes #4744 Closes #2100 Closes #4778 (superseded.)
2020-04-25 00:22:40 +02:00
_ResizeDragBarWindow();
_oldIslandPos = { newIslandPos };
}
}
// Method Description:
// - Returns the height of the little space at the top of the window used to
// resize the window.
// Return Value:
// - the height of the window's top resize handle
int NonClientIslandWindow::_GetResizeHandleHeight() const noexcept
{
// there isn't a SM_CYPADDEDBORDER for the Y axis
return ::GetSystemMetricsForDpi(SM_CXPADDEDBORDER, _currentDpi) +
::GetSystemMetricsForDpi(SM_CYSIZEFRAME, _currentDpi);
}
// Method Description:
// - Responds to the WM_NCCALCSIZE message by calculating and creating the new
// window frame.
[[nodiscard]] LRESULT NonClientIslandWindow::_OnNcCalcSize(const WPARAM wParam, const LPARAM lParam) noexcept
{
Optimize booleans (#6548) <!-- 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 Many places in this codebase has an equality comparison to the boolean FALSE. This adds unneeded complexity as C and C++ has a NOT operand for use of these in if statements. This makes the code more readable in those areas. <!-- 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] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [X] Tests added/passed * [ ] Requires documentation to be updated * [ ] 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 One boolean being compared to FALSE was only used once, with the boolean name being "b", so it is better off not existing at all. <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed Unit Testing passed, compiler refactoring
2020-06-22 23:51:34 +02:00
if (!wParam)
{
return 0;
}
NCCALCSIZE_PARAMS* params = reinterpret_cast<NCCALCSIZE_PARAMS*>(lParam);
// Store the original top before the default window proc applies the
// default frame.
const auto originalTop = params->rgrc[0].top;
const auto originalSize = params->rgrc[0];
// apply the default frame
Optimize booleans (#6548) <!-- 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 Many places in this codebase has an equality comparison to the boolean FALSE. This adds unneeded complexity as C and C++ has a NOT operand for use of these in if statements. This makes the code more readable in those areas. <!-- 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] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [X] Tests added/passed * [ ] Requires documentation to be updated * [ ] 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 One boolean being compared to FALSE was only used once, with the boolean name being "b", so it is better off not existing at all. <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed Unit Testing passed, compiler refactoring
2020-06-22 23:51:34 +02:00
const auto ret = DefWindowProc(_window.get(), WM_NCCALCSIZE, wParam, lParam);
if (ret != 0)
{
return ret;
}
auto newSize = params->rgrc[0];
// Re-apply the original top from before the size of the default frame was applied.
newSize.top = originalTop;
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
// WM_NCCALCSIZE is called before WM_SIZE
_UpdateMaximizedState();
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
// We don't need this correction when we're fullscreen. We will have the
// WS_POPUP size, so we don't have to worry about borders, and the default
// frame will be fine.
if (_isMaximized && !_fullscreen)
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
{
// When a window is maximized, its size is actually a little bit more
// than the monitor's work area. The window is positioned and sized in
// such a way that the resize handles are outside of the monitor and
// then the window is clipped to the monitor so that the resize handle
// do not appear because you don't need them (because you can't resize
// a window when it's maximized unless you restore it).
newSize.top += _GetResizeHandleHeight();
}
// GH#1438 - Attempt to detect if there's an autohide taskbar, and if there
// is, reduce our size a bit on the side with the taskbar, so the user can
// still mouse-over the taskbar to reveal it.
// GH#5209 - make sure to use MONITOR_DEFAULTTONEAREST, so that this will
// still find the right monitor even when we're restoring from minimized.
HMONITOR hMon = MonitorFromWindow(_window.get(), MONITOR_DEFAULTTONEAREST);
if (hMon && (_isMaximized || _fullscreen))
{
MONITORINFO monInfo{ 0 };
monInfo.cbSize = sizeof(MONITORINFO);
GetMonitorInfo(hMon, &monInfo);
// First, check if we have an auto-hide taskbar at all:
APPBARDATA autohide{ 0 };
autohide.cbSize = sizeof(autohide);
UINT state = (UINT)SHAppBarMessage(ABM_GETSTATE, &autohide);
if (WI_IsFlagSet(state, ABS_AUTOHIDE))
{
// This helper can be used to determine if there's a auto-hide
// taskbar on the given edge of the monitor we're currently on.
auto hasAutohideTaskbar = [&monInfo](const UINT edge) -> bool {
APPBARDATA data{ 0 };
data.cbSize = sizeof(data);
data.uEdge = edge;
data.rc = monInfo.rcMonitor;
HWND hTaskbar = (HWND)SHAppBarMessage(ABM_GETAUTOHIDEBAREX, &data);
return hTaskbar != nullptr;
};
const bool onTop = hasAutohideTaskbar(ABE_TOP);
const bool onBottom = hasAutohideTaskbar(ABE_BOTTOM);
const bool onLeft = hasAutohideTaskbar(ABE_LEFT);
const bool onRight = hasAutohideTaskbar(ABE_RIGHT);
// If there's a taskbar on any side of the monitor, reduce our size
// a little bit on that edge.
//
// Note to future code archeologists:
// This doesn't seem to work for fullscreen on the primary display.
// However, testing a bunch of other apps with fullscreen modes
// and an auto-hiding taskbar has shown that _none_ of them
// reveal the taskbar from fullscreen mode. This includes Edge,
// Firefox, Chrome, Sublime Text, PowerPoint - none seemed to
// support this.
//
// This does however work fine for maximized.
if (onTop)
{
// Peculiarly, when we're fullscreen,
newSize.top += AutohideTaskbarSize;
}
if (onBottom)
{
newSize.bottom -= AutohideTaskbarSize;
}
if (onLeft)
{
newSize.left += AutohideTaskbarSize;
}
if (onRight)
{
newSize.right -= AutohideTaskbarSize;
}
}
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
}
params->rgrc[0] = newSize;
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
return 0;
}
// Method Description:
// - Hit test the frame for resizing and moving.
// Arguments:
// - ptMouse: the mouse point being tested, in absolute (NOT WINDOW) coordinates.
// Return Value:
// - one of the values from
// https://docs.microsoft.com/en-us/windows/desktop/inputdev/wm-nchittest#return-value
// corresponding to the area of the window that was hit
[[nodiscard]] LRESULT NonClientIslandWindow::_OnNcHitTest(POINT ptMouse) const noexcept
{
// This will handle the left, right and bottom parts of the frame because
// we didn't change them.
LPARAM lParam = MAKELONG(ptMouse.x, ptMouse.y);
const auto originalRet = DefWindowProc(_window.get(), WM_NCHITTEST, 0, lParam);
if (originalRet != HTCLIENT)
{
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.
2021-04-26 21:36:23 +02:00
// 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;
}
// At this point, we know that the cursor is inside the client area so it
// has to be either the little border at the top of our custom title bar,
// the drag bar or something else in the XAML island. But the XAML Island
// handles WM_NCHITTEST on its own so actually it cannot be the XAML
// Island. Then it must be the drag bar or the little border at the top
// which the user can use to move or resize the window.
RECT rcWindow;
winrt::check_bool(::GetWindowRect(_window.get(), &rcWindow));
const auto resizeBorderHeight = _GetResizeHandleHeight();
const auto isOnResizeBorder = ptMouse.y < rcWindow.top + resizeBorderHeight;
// the top of the drag bar is used to resize the window
if (!_isMaximized && isOnResizeBorder)
{
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.
2021-04-26 21:36:23 +02:00
// 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;
}
Replace the HRGN-based titlebar cutout with an overlay window (#5485) Also known as "Kill HRGN II: Kills Regions Dead (#5485)" Copying the description from @greg904 in #4778. --- 8< --- My understanding is that the XAML framework uses another way of getting mouse input that doesn't work with `WM_SYSCOMMAND` with `SC_MOVE`. It looks like it "steals" our mouse messages like `WM_LBUTTONDOWN`. Before, we were cutting (with `HRGN`s) the drag bar part of the XAML islands window in order to catch mouse messages and be able to implement the drag bar that can move the window. However this "cut" doesn't only apply to input (mouse messages) but also to the graphics so we had to paint behind with the same color as the drag bar using GDI to hide the fact that we were cutting the window. The main issue with this is that we have to replicate exactly the rendering on the XAML drag bar using GDI and this is bad because: 1. it's hard to keep track of the right color: if a dialog is open, it will cover the whole window including the drag bar with a transparent white layer and it's hard to keep track of those things. 2. we can't do acrylic with GDI So I found another method, which is to instead put a "drag window" exactly where the drag bar is, but on top of the XAML islands window (in Z order). I've found that this lets us receive the `WM_LBUTTONDOWN` messages. --- >8 --- Dustin's notes: I've based this on the implementation of the input sink window in the UWP application frame host. Tested manually in all configurations (debug, release) with snap, drag, move, double-click and double-click on the resize handle. Tested at 200% scale. Closes #4744 Closes #2100 Closes #4778 (superseded.)
2020-04-25 00:22:40 +02:00
// Method Description:
// - Sets the cursor to the sizing cursor when we hit-test the top sizing border.
// We need to do this because we've covered it up with a child window.
[[nodiscard]] LRESULT NonClientIslandWindow::_OnSetCursor(WPARAM wParam, LPARAM lParam) const noexcept
{
if (LOWORD(lParam) == HTCLIENT)
{
// Get the cursor position from the _last message_ and not from
// `GetCursorPos` (which returns the cursor position _at the
// moment_) because if we're lagging behind the cursor's position,
// we still want to get the cursor position that was associated
// with that message at the time it was sent to handle the message
// correctly.
const auto screenPtLparam{ GetMessagePos() };
const LRESULT hitTest{ SendMessage(GetHandle(), WM_NCHITTEST, 0, screenPtLparam) };
Replace the HRGN-based titlebar cutout with an overlay window (#5485) Also known as "Kill HRGN II: Kills Regions Dead (#5485)" Copying the description from @greg904 in #4778. --- 8< --- My understanding is that the XAML framework uses another way of getting mouse input that doesn't work with `WM_SYSCOMMAND` with `SC_MOVE`. It looks like it "steals" our mouse messages like `WM_LBUTTONDOWN`. Before, we were cutting (with `HRGN`s) the drag bar part of the XAML islands window in order to catch mouse messages and be able to implement the drag bar that can move the window. However this "cut" doesn't only apply to input (mouse messages) but also to the graphics so we had to paint behind with the same color as the drag bar using GDI to hide the fact that we were cutting the window. The main issue with this is that we have to replicate exactly the rendering on the XAML drag bar using GDI and this is bad because: 1. it's hard to keep track of the right color: if a dialog is open, it will cover the whole window including the drag bar with a transparent white layer and it's hard to keep track of those things. 2. we can't do acrylic with GDI So I found another method, which is to instead put a "drag window" exactly where the drag bar is, but on top of the XAML islands window (in Z order). I've found that this lets us receive the `WM_LBUTTONDOWN` messages. --- >8 --- Dustin's notes: I've based this on the implementation of the input sink window in the UWP application frame host. Tested manually in all configurations (debug, release) with snap, drag, move, double-click and double-click on the resize handle. Tested at 200% scale. Closes #4744 Closes #2100 Closes #4778 (superseded.)
2020-04-25 00:22:40 +02:00
if (hitTest == HTTOP)
{
// We have to set the vertical resize cursor manually on
// the top resize handle because Windows thinks that the
// cursor is on the client area because it asked the asked
// the drag window with `WM_NCHITTEST` and it returned
// `HTCLIENT`.
// We don't want to modify the drag window's `WM_NCHITTEST`
// handling to return `HTTOP` because otherwise, the system
// would resize the drag window instead of the top level
// window!
SetCursor(LoadCursor(nullptr, IDC_SIZENS));
return TRUE;
}
else
{
// reset cursor
SetCursor(LoadCursor(nullptr, IDC_ARROW));
return TRUE;
}
}
return DefWindowProc(GetHandle(), WM_SETCURSOR, wParam, lParam);
Replace the HRGN-based titlebar cutout with an overlay window (#5485) Also known as "Kill HRGN II: Kills Regions Dead (#5485)" Copying the description from @greg904 in #4778. --- 8< --- My understanding is that the XAML framework uses another way of getting mouse input that doesn't work with `WM_SYSCOMMAND` with `SC_MOVE`. It looks like it "steals" our mouse messages like `WM_LBUTTONDOWN`. Before, we were cutting (with `HRGN`s) the drag bar part of the XAML islands window in order to catch mouse messages and be able to implement the drag bar that can move the window. However this "cut" doesn't only apply to input (mouse messages) but also to the graphics so we had to paint behind with the same color as the drag bar using GDI to hide the fact that we were cutting the window. The main issue with this is that we have to replicate exactly the rendering on the XAML drag bar using GDI and this is bad because: 1. it's hard to keep track of the right color: if a dialog is open, it will cover the whole window including the drag bar with a transparent white layer and it's hard to keep track of those things. 2. we can't do acrylic with GDI So I found another method, which is to instead put a "drag window" exactly where the drag bar is, but on top of the XAML islands window (in Z order). I've found that this lets us receive the `WM_LBUTTONDOWN` messages. --- >8 --- Dustin's notes: I've based this on the implementation of the input sink window in the UWP application frame host. Tested manually in all configurations (debug, release) with snap, drag, move, double-click and double-click on the resize handle. Tested at 200% scale. Closes #4744 Closes #2100 Closes #4778 (superseded.)
2020-04-25 00:22:40 +02:00
}
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:
// - Get the dimensions of our non-client area, as a rect where each component
// represents that side.
// - The .left will be a negative number, to represent that the actual side of
// the non-client area is outside the border of our window. It's roughly 8px (
// * DPI scaling) to the left of the visible border.
// - The .right component will be positive, indicating that the nonclient border
// is in the positive-x direction from the edge of our client area.
// - This DOES NOT include our titlebar! It's in the client area for us.
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
// Arguments:
// - dpi: the scaling that we should use to calculate the border sizes.
// Return Value:
// - a RECT whose components represent the margins of the nonclient area,
// relative to the client area.
RECT NonClientIslandWindow::GetNonClientFrame(UINT dpi) const noexcept
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
{
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));
islandFrame.top = -topBorderVisibleHeight;
return islandFrame;
}
// 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 NonClientIslandWindow::GetTotalNonClientExclusiveSize(UINT dpi) const noexcept
{
const auto islandFrame{ GetNonClientFrame(dpi) };
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
// If we have a titlebar, this is being called after we've initialized, and
// we can just ask that titlebar how big it wants to be.
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
const auto titleBarHeight = _titlebar ? static_cast<LONG>(_titlebar.ActualHeight()) : 0;
return {
islandFrame.right - islandFrame.left,
islandFrame.bottom - islandFrame.top + titleBarHeight
};
}
// Method Description:
// - Updates the borders of our window frame, using DwmExtendFrameIntoClientArea.
// Arguments:
// - <none>
// Return Value:
// - the HRESULT returned by DwmExtendFrameIntoClientArea.
void NonClientIslandWindow::_UpdateFrameMargins() const noexcept
{
MARGINS margins = { 0, 0, 0, 0 };
// GH#603: When we're in Focus Mode, hide the titlebar, by setting it to a single
// pixel tall. Otherwise, the titlebar will be visible underneath controls with
// vintage opacity set.
//
// We can't set it to all 0's unfortunately.
if (_borderless)
{
margins.cyTopHeight = 1;
}
else if (_GetTopBorderHeight() != 0)
{
RECT frame = {};
winrt::check_bool(::AdjustWindowRectExForDpi(&frame, GetWindowStyle(_window.get()), FALSE, 0, _currentDpi));
// We removed the whole top part of the frame (see handling of
// WM_NCCALCSIZE) so the top border is missing now. We add it back here.
// Note #1: You might wonder why we don't remove just the title bar instead
// of removing the whole top part of the frame and then adding the little
// top border back. I tried to do this but it didn't work: DWM drew the
// whole title bar anyways on top of the window. It seems that DWM only
// wants to draw either nothing or the whole top part of the frame.
// Note #2: For some reason if you try to set the top margin to just the
// top border height (what we want to do), then there is a transparency
// bug when the window is inactive, so I've decided to add the whole top
// part of the frame instead and then we will hide everything that we
// don't need (that is, the whole thing but the little 1 pixel wide border
// at the top) in the WM_PAINT handler. This eliminates the transparency
// bug and it's what a lot of Win32 apps that customize the title bar do
// so it should work fine.
margins.cyTopHeight = -frame.top;
}
// Extend the frame into the client area. microsoft/terminal#2735 - Just log
// the failure here, don't crash. If DWM crashes for any reason, calling
// THROW_IF_FAILED() will cause us to take a trip upstate. Just log, and
// we'll fix ourselves when DWM comes back.
LOG_IF_FAILED(DwmExtendFrameIntoClientArea(_window.get(), &margins));
}
// Method Description:
// - Handle window messages from the message loop.
// Arguments:
// - message: A window message ID identifying the message.
// - wParam: The contents of this parameter depend on the value of the message parameter.
// - lParam: The contents of this parameter depend on the value of the message parameter.
// Return Value:
// - The return value is the result of the message processing and depends on the
// message sent.
[[nodiscard]] LRESULT NonClientIslandWindow::MessageHandler(UINT const message,
WPARAM const wParam,
LPARAM const lParam) noexcept
{
switch (message)
{
Replace the HRGN-based titlebar cutout with an overlay window (#5485) Also known as "Kill HRGN II: Kills Regions Dead (#5485)" Copying the description from @greg904 in #4778. --- 8< --- My understanding is that the XAML framework uses another way of getting mouse input that doesn't work with `WM_SYSCOMMAND` with `SC_MOVE`. It looks like it "steals" our mouse messages like `WM_LBUTTONDOWN`. Before, we were cutting (with `HRGN`s) the drag bar part of the XAML islands window in order to catch mouse messages and be able to implement the drag bar that can move the window. However this "cut" doesn't only apply to input (mouse messages) but also to the graphics so we had to paint behind with the same color as the drag bar using GDI to hide the fact that we were cutting the window. The main issue with this is that we have to replicate exactly the rendering on the XAML drag bar using GDI and this is bad because: 1. it's hard to keep track of the right color: if a dialog is open, it will cover the whole window including the drag bar with a transparent white layer and it's hard to keep track of those things. 2. we can't do acrylic with GDI So I found another method, which is to instead put a "drag window" exactly where the drag bar is, but on top of the XAML islands window (in Z order). I've found that this lets us receive the `WM_LBUTTONDOWN` messages. --- >8 --- Dustin's notes: I've based this on the implementation of the input sink window in the UWP application frame host. Tested manually in all configurations (debug, release) with snap, drag, move, double-click and double-click on the resize handle. Tested at 200% scale. Closes #4744 Closes #2100 Closes #4778 (superseded.)
2020-04-25 00:22:40 +02:00
case WM_SETCURSOR:
return _OnSetCursor(wParam, lParam);
case WM_DISPLAYCHANGE:
// GH#4166: When the DPI of the monitor changes out from underneath us,
// resize our drag bar, to reflect its newly scaled size.
Replace the HRGN-based titlebar cutout with an overlay window (#5485) Also known as "Kill HRGN II: Kills Regions Dead (#5485)" Copying the description from @greg904 in #4778. --- 8< --- My understanding is that the XAML framework uses another way of getting mouse input that doesn't work with `WM_SYSCOMMAND` with `SC_MOVE`. It looks like it "steals" our mouse messages like `WM_LBUTTONDOWN`. Before, we were cutting (with `HRGN`s) the drag bar part of the XAML islands window in order to catch mouse messages and be able to implement the drag bar that can move the window. However this "cut" doesn't only apply to input (mouse messages) but also to the graphics so we had to paint behind with the same color as the drag bar using GDI to hide the fact that we were cutting the window. The main issue with this is that we have to replicate exactly the rendering on the XAML drag bar using GDI and this is bad because: 1. it's hard to keep track of the right color: if a dialog is open, it will cover the whole window including the drag bar with a transparent white layer and it's hard to keep track of those things. 2. we can't do acrylic with GDI So I found another method, which is to instead put a "drag window" exactly where the drag bar is, but on top of the XAML islands window (in Z order). I've found that this lets us receive the `WM_LBUTTONDOWN` messages. --- >8 --- Dustin's notes: I've based this on the implementation of the input sink window in the UWP application frame host. Tested manually in all configurations (debug, release) with snap, drag, move, double-click and double-click on the resize handle. Tested at 200% scale. Closes #4744 Closes #2100 Closes #4778 (superseded.)
2020-04-25 00:22:40 +02:00
_ResizeDragBarWindow();
return 0;
case WM_NCCALCSIZE:
return _OnNcCalcSize(wParam, lParam);
case WM_NCHITTEST:
return _OnNcHitTest({ GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) });
case WM_PAINT:
return _OnPaint();
case WM_NCRBUTTONUP:
// The `DefWindowProc` function doesn't open the system menu for some
// reason so we have to do it ourselves.
if (wParam == HTCAPTION)
{
OpenSystemMenu(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
}
break;
}
return IslandWindow::MessageHandler(message, wParam, lParam);
}
// Method Description:
Replace the HRGN-based titlebar cutout with an overlay window (#5485) Also known as "Kill HRGN II: Kills Regions Dead (#5485)" Copying the description from @greg904 in #4778. --- 8< --- My understanding is that the XAML framework uses another way of getting mouse input that doesn't work with `WM_SYSCOMMAND` with `SC_MOVE`. It looks like it "steals" our mouse messages like `WM_LBUTTONDOWN`. Before, we were cutting (with `HRGN`s) the drag bar part of the XAML islands window in order to catch mouse messages and be able to implement the drag bar that can move the window. However this "cut" doesn't only apply to input (mouse messages) but also to the graphics so we had to paint behind with the same color as the drag bar using GDI to hide the fact that we were cutting the window. The main issue with this is that we have to replicate exactly the rendering on the XAML drag bar using GDI and this is bad because: 1. it's hard to keep track of the right color: if a dialog is open, it will cover the whole window including the drag bar with a transparent white layer and it's hard to keep track of those things. 2. we can't do acrylic with GDI So I found another method, which is to instead put a "drag window" exactly where the drag bar is, but on top of the XAML islands window (in Z order). I've found that this lets us receive the `WM_LBUTTONDOWN` messages. --- >8 --- Dustin's notes: I've based this on the implementation of the input sink window in the UWP application frame host. Tested manually in all configurations (debug, release) with snap, drag, move, double-click and double-click on the resize handle. Tested at 200% scale. Closes #4744 Closes #2100 Closes #4778 (superseded.)
2020-04-25 00:22:40 +02:00
// - This method is called when the window receives the WM_PAINT message.
// - It paints the client area with the color of the title bar to hide the
// system's title bar behind the XAML Islands window during a resize.
// Indeed, the XAML Islands window doesn't resize at the same time than
// the top level window
// (see https://github.com/microsoft/microsoft-ui-xaml/issues/759).
// Return Value:
// - The value returned from the window proc.
[[nodiscard]] LRESULT NonClientIslandWindow::_OnPaint() noexcept
{
if (!_titlebar)
{
return 0;
}
PAINTSTRUCT ps{ 0 };
const auto hdc = wil::BeginPaint(_window.get(), &ps);
if (!hdc)
{
return 0;
}
const auto topBorderHeight = _GetTopBorderHeight();
if (ps.rcPaint.top < topBorderHeight)
{
RECT rcTopBorder = ps.rcPaint;
rcTopBorder.bottom = topBorderHeight;
// To show the original top border, we have to paint on top of it with
// the alpha component set to 0. This page recommends to paint the area
// in black using the stock BLACK_BRUSH to do this:
// https://docs.microsoft.com/en-us/windows/win32/dwm/customframe#extending-the-client-frame
::FillRect(hdc.get(), &rcTopBorder, GetStockBrush(BLACK_BRUSH));
}
if (ps.rcPaint.bottom > topBorderHeight)
{
RECT rcRest = ps.rcPaint;
rcRest.top = topBorderHeight;
const auto backgroundBrush = _titlebar.Background();
const auto backgroundSolidBrush = backgroundBrush.try_as<Media::SolidColorBrush>();
const auto backgroundAcrylicBrush = backgroundBrush.try_as<Media::AcrylicBrush>();
til::color backgroundColor = Colors::Black();
if (backgroundSolidBrush)
{
backgroundColor = backgroundSolidBrush.Color();
}
else if (backgroundAcrylicBrush)
{
backgroundColor = backgroundAcrylicBrush.FallbackColor();
}
if (!_backgroundBrush || backgroundColor != _backgroundBrushColor)
{
// Create brush for titlebar color.
_backgroundBrush = wil::unique_hbrush(CreateSolidBrush(backgroundColor));
}
// To hide the original title bar, we have to paint on top of it with
// the alpha component set to 255. This is a hack to do it with GDI.
// See NonClientIslandWindow::_UpdateFrameMargins for more information.
HDC opaqueDc;
BP_PAINTPARAMS params = { sizeof(params), BPPF_NOCLIP | BPPF_ERASE };
HPAINTBUFFER buf = BeginBufferedPaint(hdc.get(), &rcRest, BPBF_TOPDOWNDIB, &params, &opaqueDc);
if (!buf || !opaqueDc)
{
// MSFT:34673647 - BeginBufferedPaint can fail, but it probably
// shouldn't bring the whole Terminal down with it. So don't
// throw_last_error here.
LOG_LAST_ERROR();
return 0;
}
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
::FillRect(opaqueDc, &rcRest, _backgroundBrush.get());
::BufferedPaintSetAlpha(buf, nullptr, 255);
::EndBufferedPaint(buf, TRUE);
}
return 0;
}
// Method Description:
// - This method is called when the window receives the WM_NCCREATE message.
// Return Value:
// - The value returned from the window proc.
[[nodiscard]] LRESULT NonClientIslandWindow::_OnNcCreate(WPARAM wParam, LPARAM lParam) noexcept
{
const auto ret = IslandWindow::_OnNcCreate(wParam, lParam);
Optimize booleans (#6548) <!-- 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 Many places in this codebase has an equality comparison to the boolean FALSE. This adds unneeded complexity as C and C++ has a NOT operand for use of these in if statements. This makes the code more readable in those areas. <!-- 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] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [X] Tests added/passed * [ ] Requires documentation to be updated * [ ] 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 One boolean being compared to FALSE was only used once, with the boolean name being "b", so it is better off not existing at all. <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed Unit Testing passed, compiler refactoring
2020-06-22 23:51:34 +02:00
if (!ret)
{
Optimize booleans (#6548) <!-- 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 Many places in this codebase has an equality comparison to the boolean FALSE. This adds unneeded complexity as C and C++ has a NOT operand for use of these in if statements. This makes the code more readable in those areas. <!-- 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] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [X] Tests added/passed * [ ] Requires documentation to be updated * [ ] 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 One boolean being compared to FALSE was only used once, with the boolean name being "b", so it is better off not existing at all. <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed Unit Testing passed, compiler refactoring
2020-06-22 23:51:34 +02:00
return FALSE;
}
// This is a hack to make the window borders dark instead of light.
// It must be done before WM_NCPAINT so that the borders are rendered with
// the correct theme.
// For more information, see GH#6620.
LOG_IF_FAILED(TerminalTrySetDarkTheme(_window.get(), true));
return TRUE;
}
// Method Description:
// - Called when the app wants to change its theme. We'll update the frame
// theme to match the new theme.
// Arguments:
// - requestedTheme: the ElementTheme to use as the new theme for the UI
// Return Value:
// - <none>
void NonClientIslandWindow::OnApplicationThemeChanged(const ElementTheme& requestedTheme)
{
IslandWindow::OnApplicationThemeChanged(requestedTheme);
_theme = requestedTheme;
}
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:
// - Enable or disable borderless mode. When entering borderless mode, we'll
// need to manually hide the entire titlebar.
// - See also IslandWindow::_SetIsBorderless, which does similar, but different work.
// Arguments:
// - borderlessEnabled: If true, we're entering borderless mode. If false, we're leaving.
// Return Value:
// - <none>
void NonClientIslandWindow::_SetIsBorderless(const bool borderlessEnabled)
{
_borderless = borderlessEnabled;
// Explicitly _don't_ call IslandWindow::_SetIsBorderless. That version will
// change the window styles appropriately for the window with the default
// titlebar, but for the tabs-in-titlebar mode, we can just get rid of the
// title bar entirely.
if (_titlebar)
{
_titlebar.Visibility(_IsTitlebarVisible() ? Visibility::Visible : Visibility::Collapsed);
}
// Update the margins when entering/leaving focus mode, so we can prevent
// the titlebar from showing through transparent terminal controls
_UpdateFrameMargins();
// GH#4224 - When the auto-hide taskbar setting is enabled, then we don't
// always get another window message to trigger us to remove the drag bar.
// So, make sure to update the size of the drag region here, so that it
// _definitely_ goes away.
_ResizeDragBarWindow();
// 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>(),
windowPos.top<int>(),
windowPos.width<int>(),
windowPos.height<int>(),
SWP_SHOWWINDOW | SWP_FRAMECHANGED | SWP_NOACTIVATE);
}
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:
// - Enable or disable fullscreen mode. When entering fullscreen mode, we'll
// need to manually hide the entire titlebar.
// - See also IslandWindow::_SetIsFullscreen, which does additional work.
// Arguments:
// - fullscreenEnabled: If true, we're entering fullscreen mode. If false, we're leaving.
// Return Value:
// - <none>
void NonClientIslandWindow::_SetIsFullscreen(const bool fullscreenEnabled)
{
IslandWindow::_SetIsFullscreen(fullscreenEnabled);
if (_titlebar)
{
_titlebar.Visibility(_IsTitlebarVisible() ? Visibility::Visible : Visibility::Collapsed);
}
// GH#4224 - When the auto-hide taskbar setting is enabled, then we don't
// always get another window message to trigger us to remove the drag bar.
// So, make sure to update the size of the drag region here, so that it
// _definitely_ goes away.
Replace the HRGN-based titlebar cutout with an overlay window (#5485) Also known as "Kill HRGN II: Kills Regions Dead (#5485)" Copying the description from @greg904 in #4778. --- 8< --- My understanding is that the XAML framework uses another way of getting mouse input that doesn't work with `WM_SYSCOMMAND` with `SC_MOVE`. It looks like it "steals" our mouse messages like `WM_LBUTTONDOWN`. Before, we were cutting (with `HRGN`s) the drag bar part of the XAML islands window in order to catch mouse messages and be able to implement the drag bar that can move the window. However this "cut" doesn't only apply to input (mouse messages) but also to the graphics so we had to paint behind with the same color as the drag bar using GDI to hide the fact that we were cutting the window. The main issue with this is that we have to replicate exactly the rendering on the XAML drag bar using GDI and this is bad because: 1. it's hard to keep track of the right color: if a dialog is open, it will cover the whole window including the drag bar with a transparent white layer and it's hard to keep track of those things. 2. we can't do acrylic with GDI So I found another method, which is to instead put a "drag window" exactly where the drag bar is, but on top of the XAML islands window (in Z order). I've found that this lets us receive the `WM_LBUTTONDOWN` messages. --- >8 --- Dustin's notes: I've based this on the implementation of the input sink window in the UWP application frame host. Tested manually in all configurations (debug, release) with snap, drag, move, double-click and double-click on the resize handle. Tested at 200% scale. Closes #4744 Closes #2100 Closes #4778 (superseded.)
2020-04-25 00:22:40 +02:00
_ResizeDragBarWindow();
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:
// - Returns true if the titlebar is visible. For things like fullscreen mode,
// borderless mode (aka "focus mode"), this will return 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
// Arguments:
// - <none>
// Return Value:
// - true iff the titlebar is visible
bool NonClientIslandWindow::_IsTitlebarVisible() const
{
return !(_fullscreen || _borderless);
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
}