Skip to content

Commit

Permalink
Clean up
Browse files Browse the repository at this point in the history
* Don't recreate the window every time; it's possible to use
  SetWindowPos and show/hide it on-demand
* WIL-ize and document a couple things
* make the class registration a static inline
* make class reg/creation happen as part of MakeWindow
* remove the entire tabview color key (let it fall back to the actual
  color specified in MUX)
  • Loading branch information
DHowett committed Apr 23, 2020
1 parent ca4625c commit f343e24
Show file tree
Hide file tree
Showing 7 changed files with 81 additions and 83 deletions.
6 changes: 5 additions & 1 deletion .github/actions/spell-check/dictionary/apis.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
IMap
ICustom
IMap
IObject
LCID
NCHITTEST
NCLBUTTONDBLCLK
NCRBUTTONDBLCLK
NOREDIRECTIONBITMAP
rfind
SIZENS

This file was deleted.

2 changes: 0 additions & 2 deletions .github/actions/spell-check/whitelist/whitelist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1106,7 +1106,6 @@ ime
Imm
IMouse
impl
implementingtextandtextrange
inbox
inclusivity
INCONTEXT
Expand Down Expand Up @@ -2815,7 +2814,6 @@ xvalue
XVIRTUALSCREEN
XWalk
xy
xxxx
yact
YAML
YCast
Expand Down
2 changes: 1 addition & 1 deletion src/cascadia/WindowsTerminal/IslandWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class IslandWindow :
IslandWindow() noexcept;
virtual ~IslandWindow() override;

void MakeWindow() noexcept;
virtual void MakeWindow() noexcept;
void Close();
virtual void OnSize(const UINT width, const UINT height);

Expand Down
141 changes: 72 additions & 69 deletions src/cascadia/WindowsTerminal/NonClientIslandWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@
#include "../types/inc/utils.hpp"
#include "TerminalThemeHelpers.h"

extern "C" IMAGE_DOS_HEADER __ImageBase;

using namespace winrt::Windows::UI;
using namespace winrt::Windows::UI::Composition;
using namespace winrt::Windows::UI::Xaml;
Expand All @@ -20,8 +18,6 @@ using namespace ::Microsoft::Console::Types;

static constexpr int AutohideTaskbarSize = 2;

ATOM NonClientIslandWindow::_dragBarWindowClass = 0;

NonClientIslandWindow::NonClientIslandWindow(const ElementTheme& requestedTheme) noexcept :
IslandWindow{},
_backgroundBrushColor{ RGB(0, 0, 0) },
Expand All @@ -34,6 +30,45 @@ NonClientIslandWindow::~NonClientIslandWindow()
{
}

static constexpr const wchar_t* dragBarClassName{ L"DRAG_BAR_WINDOW_CLASS" };
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 = _DragWindowWndProc;
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,
GetWindowHandle(),
nullptr,
wil::GetModuleInstanceHandle(),
0));
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 __stdcall NonClientIslandWindow::_DragWindowWndProc(HWND const window, UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept
{
std::optional<UINT> nonClientMessage{ std::nullopt };
Expand All @@ -42,22 +77,22 @@ LRESULT __stdcall NonClientIslandWindow::_DragWindowWndProc(HWND const window, U
switch (message)
{
case WM_LBUTTONDOWN:
nonClientMessage = { WM_NCLBUTTONDOWN };
nonClientMessage = WM_NCLBUTTONDOWN;
break;
case WM_LBUTTONDBLCLK:
nonClientMessage = { WM_NCLBUTTONDBLCLK };
nonClientMessage = WM_NCLBUTTONDBLCLK;
break;
case WM_LBUTTONUP:
nonClientMessage = { WM_NCLBUTTONUP };
nonClientMessage = WM_NCLBUTTONUP;
break;
case WM_RBUTTONDOWN:
nonClientMessage = { WM_NCRBUTTONDOWN };
nonClientMessage = WM_NCRBUTTONDOWN;
break;
case WM_RBUTTONDBLCLK:
nonClientMessage = { WM_NCRBUTTONDBLCLK };
nonClientMessage = WM_NCRBUTTONDBLCLK;
break;
case WM_RBUTTONUP:
nonClientMessage = { WM_NCRBUTTONUP };
nonClientMessage = WM_NCRBUTTONUP;
break;
}

Expand All @@ -68,11 +103,12 @@ LRESULT __stdcall NonClientIslandWindow::_DragWindowWndProc(HWND const window, U
POINT screenPt = clientPt;
if (ClientToScreen(window, &screenPt))
{
const auto parentWindow = GetAncestor(window, GA_PARENT);
WINRT_ASSERT(parentWindow != NULL);

LRESULT hitTest = SendMessage(parentWindow, WM_NCHITTEST, 0, MAKELPARAM(screenPt.x, screenPt.y));
const auto parentWindow{ GetAncestor(window, GA_PARENT) };
THROW_HR_IF_NULL(E_UNEXPECTED, parentWindow);

// 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.
LRESULT hitTest{ SendMessage(parentWindow, WM_NCHITTEST, 0, MAKELPARAM(screenPt.x, screenPt.y)) };
SendMessage(parentWindow, nonClientMessage.value(), hitTest, 0);

return 0;
Expand All @@ -83,61 +119,25 @@ LRESULT __stdcall NonClientIslandWindow::_DragWindowWndProc(HWND const window, U
}

// Method Description:
// - Create/re-creates the drag bar window.
// - 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.
// - We have to recreate it, we can't just move it. Otherwise for some reason
// it doesn't get any window message on the new resized area.
// Arguments:
// - <none>
// Return Value:
// - <none>
void NonClientIslandWindow::_RecreateDragBarWindow() noexcept
// - 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
{
constexpr const wchar_t* className = L"DRAG_BAR_WINDOW_CLASS";

if (_dragBarWindowClass == 0)
const til::rectangle rect{ _GetDragAreaRect() };
if (_IsTitlebarVisible() && rect.size().area() > 0)
{
WNDCLASS wc{};
wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
wc.hInstance = reinterpret_cast<HINSTANCE>(&__ImageBase);
wc.lpszClassName = className;
wc.style = CS_DBLCLKS;
wc.lpfnWndProc = _DragWindowWndProc;
_dragBarWindowClass = RegisterClass(&wc);
WINRT_ASSERT(_dragBarWindowClass != 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);
}

const auto dragBarRect = _GetDragAreaRect();

// delete previous window
_dragBarWindow = nullptr;

if (dragBarRect.right - dragBarRect.left > 0 &&
dragBarRect.bottom - dragBarRect.top > 0)
else
{
// WS_EX_LAYERED is required. If it is not present, then for
// some reason, the window will not receive any mouse input.
const auto ret = CreateWindowEx(WS_EX_LAYERED | WS_EX_NOREDIRECTIONBITMAP,
className,
L"",
WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS,
dragBarRect.left,
dragBarRect.top + _GetTopBorderHeight(),
dragBarRect.right - dragBarRect.left,
dragBarRect.bottom - dragBarRect.top,
GetWindowHandle(),
nullptr,
reinterpret_cast<HINSTANCE>(&__ImageBase),
0);
WINRT_ASSERT(ret != NULL);

_dragBarWindow = wil::unique_hwnd(ret);

// bring it on top of the XAML Islands window
WINRT_ASSERT(SetWindowPos(_dragBarWindow.get(), HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOREDRAW));
SetWindowPos(_dragBarWindow.get(), HWND_BOTTOM, 0, 0, 0, 0, SWP_HIDEWINDOW | SWP_NOMOVE | SWP_NOSIZE);
}
}

Expand All @@ -152,7 +152,7 @@ void NonClientIslandWindow::_RecreateDragBarWindow() noexcept
void NonClientIslandWindow::_OnDragBarSizeChanged(winrt::Windows::Foundation::IInspectable /*sender*/,
winrt::Windows::UI::Xaml::SizeChangedEventArgs /*eventArgs*/)
{
_RecreateDragBarWindow();
_ResizeDragBarWindow();
}

void NonClientIslandWindow::OnAppInitialized()
Expand Down Expand Up @@ -356,7 +356,7 @@ void NonClientIslandWindow::_UpdateIslandPosition(const UINT windowWidth, const
// 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.
_RecreateDragBarWindow();
_ResizeDragBarWindow();

_oldIslandPos = { newIslandPos };
}
Expand Down Expand Up @@ -532,6 +532,9 @@ int NonClientIslandWindow::_GetResizeHandleHeight() const noexcept
return HTCAPTION;
}

// 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)
Expand Down Expand Up @@ -659,7 +662,7 @@ void NonClientIslandWindow::_UpdateFrameMargins() const noexcept
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.
_RecreateDragBarWindow();
_ResizeDragBarWindow();
return 0;
case WM_NCCALCSIZE:
return _OnNcCalcSize(wParam, lParam);
Expand Down Expand Up @@ -820,7 +823,7 @@ void NonClientIslandWindow::_SetIsFullscreen(const bool fullscreenEnabled)
// 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.
_RecreateDragBarWindow();
_ResizeDragBarWindow();
}

// Method Description:
Expand Down
5 changes: 2 additions & 3 deletions src/cascadia/WindowsTerminal/NonClientIslandWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class NonClientIslandWindow : public IslandWindow
NonClientIslandWindow(const winrt::Windows::UI::Xaml::ElementTheme& requestedTheme) noexcept;
virtual ~NonClientIslandWindow() override;

void MakeWindow() noexcept override;
virtual void OnSize(const UINT width, const UINT height) override;

[[nodiscard]] virtual LRESULT MessageHandler(UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept override;
Expand All @@ -46,8 +47,6 @@ class NonClientIslandWindow : public IslandWindow
void OnApplicationThemeChanged(const winrt::Windows::UI::Xaml::ElementTheme& requestedTheme) override;

private:
static ATOM _dragBarWindowClass;

std::optional<COORD> _oldIslandPos;

winrt::TerminalApp::TitlebarControl _titlebar{ nullptr };
Expand All @@ -65,7 +64,7 @@ class NonClientIslandWindow : public IslandWindow

[[nodiscard]] static LRESULT __stdcall _DragWindowWndProc(HWND const window, UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept;

void _RecreateDragBarWindow() noexcept;
void _ResizeDragBarWindow() noexcept;

int _GetResizeHandleHeight() const noexcept;
RECT _GetDragAreaRect() const noexcept;
Expand Down

1 comment on commit f343e24

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New misspellings found, please review:

  • wcex
To accept these changes, run the following commands
remove_obsolete_words=$(mktemp)
echo '#!/usr/bin/perl -ni
my $re=join "|", qw('"
fdpi
NCHITTEST'ed
textblock
usr
vpack
"');
next if /^($re)(?:$| .*)/;
print;' > $remove_obsolete_words
chmod +x $remove_obsolete_words
for file in .github/actions/spell-check/whitelist/alphabet.txt .github/actions/spell-check/whitelist/web.txt .github/actions/spell-check/whitelist/whitelist.txt; do $remove_obsolete_words $file; done
rm $remove_obsolete_words
(
echo "
wcex
"
) | sort -u -f | perl -ne 'next unless /./; print' > new_whitelist.txt && mv new_whitelist.txt '.github/actions/spell-check/whitelist/f343e2476c5308df4fa4eba89d8969285c149ec6.txt'
✏️ Contributor please read this
  • If the items listed above are names, please add them to .github/actions/spell-check/dictionary/names.txt.
  • If they're APIs, you can add them to a file in .github/actions/spell-check/dictionary/.
  • If they're just things you're using, please add them to an appropriate file in .github/actions/spell-check/whitelist/.
  • If you need to use a specific token in one place and it shouldn't generally be used, you can
    add an item in an appropriate file in .github/actions/spell-check/patterns/.

See the README.md in each directory for more information.

⚠️ Reviewers

At present, the action that triggered this message will not show its ❌ in this PR unless the branch is within this repository.
Thus, you should make sure that this comment has been addressed before encouraging the merge bot to merge this PR.

Please sign in to comment.