aboutsummaryrefslogtreecommitdiff
path: root/src/win/gui/Window.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/win/gui/Window.cpp')
-rw-r--r--src/win/gui/Window.cpp593
1 files changed, 0 insertions, 593 deletions
diff --git a/src/win/gui/Window.cpp b/src/win/gui/Window.cpp
deleted file mode 100644
index cc2038ec..00000000
--- a/src/win/gui/Window.cpp
+++ /dev/null
@@ -1,593 +0,0 @@
-#include "cru/win/gui/Window.h"
-
-#include "WindowManager.h"
-#include "cru/common/log/Logger.h"
-#include "cru/platform/Check.h"
-#include "cru/platform/graphics/NullPainter.h"
-#include "cru/platform/gui/Base.h"
-#include "cru/platform/gui/DebugFlags.h"
-#include "cru/platform/gui/Window.h"
-#include "cru/win/graphics/direct/WindowPainter.h"
-#include "cru/win/gui/Cursor.h"
-#include "cru/win/gui/Exception.h"
-#include "cru/win/gui/InputMethod.h"
-#include "cru/win/gui/Keyboard.h"
-#include "cru/win/gui/UiApplication.h"
-#include "cru/win/gui/WindowClass.h"
-
-#include <windowsx.h>
-#include <winuser.h>
-#include <memory>
-
-namespace cru::platform::gui::win {
-namespace {
-inline int DipToPixel(const float dip, const float dpi) {
- return static_cast<int>(dip * dpi / 96.0f);
-}
-
-inline float PixelToDip(const int pixel, const float dpi) {
- return static_cast<float>(pixel) * 96.0f / dpi;
-}
-
-DWORD CalcWindowStyle(WindowStyleFlag flag) {
- return flag & WindowStyleFlags::NoCaptionAndBorder ? WS_POPUP
- : WS_OVERLAPPEDWINDOW;
-}
-
-Rect CalcWindowRectFromClient(const Rect& rect, WindowStyleFlag style_flag,
- float dpi) {
- RECT r;
- r.left = DipToPixel(rect.left, dpi);
- r.top = DipToPixel(rect.top, dpi);
- r.right = DipToPixel(rect.GetRight(), dpi);
- r.bottom = DipToPixel(rect.GetBottom(), dpi);
- if (!AdjustWindowRectEx(&r, CalcWindowStyle(style_flag), FALSE, 0))
- throw Win32Error(::GetLastError(), u"Failed to invoke AdjustWindowRectEx.");
-
- Rect result =
- Rect::FromVertices(PixelToDip(r.left, dpi), PixelToDip(r.top, dpi),
- PixelToDip(r.right, dpi), PixelToDip(r.bottom, dpi));
- return result;
-}
-
-Rect CalcClientRectFromWindow(const Rect& rect, WindowStyleFlag style_flag,
- float dpi) {
- RECT o{100, 100, 500, 500};
- RECT s = o;
- if (!AdjustWindowRectEx(&s, CalcWindowStyle(style_flag), FALSE, 0))
- throw Win32Error(::GetLastError(), u"Failed to invoke AdjustWindowRectEx.");
-
- Rect result = rect;
- result.Shrink(Thickness(PixelToDip(s.left - o.left, dpi),
- PixelToDip(o.top - s.top, dpi),
- PixelToDip(s.right - o.right, dpi),
- PixelToDip(s.bottom - o.bottom, dpi)));
-
- return result;
-}
-} // namespace
-
-WinNativeWindow::WinNativeWindow(WinUiApplication* application)
- : application_(application) {
- Expects(application); // application can't be null.
-}
-
-WinNativeWindow::~WinNativeWindow() { Close(); }
-
-void WinNativeWindow::Close() {
- if (hwnd_) ::DestroyWindow(hwnd_);
-}
-
-void WinNativeWindow::SetParent(INativeWindow* parent) {
- auto p = CheckPlatform<WinNativeWindow>(parent, GetPlatformId());
- parent_window_ = p;
-
- if (hwnd_) {
- ::SetParent(hwnd_, parent_window_->hwnd_);
- }
-}
-
-String WinNativeWindow::GetTitle() { return title_; }
-
-void WinNativeWindow::SetTitle(String title) {
- title_ = title;
-
- if (hwnd_) {
- ::SetWindowTextW(hwnd_, title_.WinCStr());
- }
-}
-
-void WinNativeWindow::SetStyleFlag(WindowStyleFlag flag) {
- if (flag == style_flag_) return;
-
- style_flag_ = flag;
- if (hwnd_) {
- SetWindowLongPtrW(hwnd_, GWL_STYLE,
- static_cast<LONG_PTR>(CalcWindowStyle(style_flag_)));
- }
-}
-
-void WinNativeWindow::SetVisibility(WindowVisibilityType visibility) {
- if (visibility == visibility_) return;
- visibility_ = visibility;
-
- if (!hwnd_) {
- RecreateWindow();
- }
-
- if (visibility == WindowVisibilityType::Show) {
- ShowWindow(hwnd_, SW_SHOWNORMAL);
- } else if (visibility == WindowVisibilityType::Hide) {
- ShowWindow(hwnd_, SW_HIDE);
- } else if (visibility == WindowVisibilityType::Minimize) {
- ShowWindow(hwnd_, SW_MINIMIZE);
- }
-}
-
-Size WinNativeWindow::GetClientSize() { return GetClientRect().GetSize(); }
-
-void WinNativeWindow::SetClientSize(const Size& size) {
- client_rect_.SetSize(size);
-
- if (hwnd_) {
- RECT rect =
- DipToPixel(CalcWindowRectFromClient(client_rect_, style_flag_, dpi_));
-
- if (!SetWindowPos(hwnd_, nullptr, 0, 0, rect.right - rect.left,
- rect.bottom - rect.top, SWP_NOZORDER | SWP_NOMOVE))
- throw Win32Error(::GetLastError(), u"Failed to invoke SetWindowPos.");
- }
-}
-
-Rect WinNativeWindow::GetClientRect() { return client_rect_; }
-
-void WinNativeWindow::SetClientRect(const Rect& rect) {
- client_rect_ = rect;
-
- if (hwnd_) {
- RECT r =
- DipToPixel(CalcWindowRectFromClient(client_rect_, style_flag_, dpi_));
-
- if (!SetWindowPos(hwnd_, nullptr, 0, 0, r.right - r.left, r.bottom - r.top,
- SWP_NOZORDER | SWP_NOMOVE))
- throw Win32Error(::GetLastError(), u"Failed to invoke SetWindowPos.");
- }
-}
-
-Rect WinNativeWindow::GetWindowRect() {
- if (hwnd_) {
- RECT rect;
- if (!::GetWindowRect(hwnd_, &rect))
- throw Win32Error(::GetLastError(), u"Failed to invoke GetWindowRect.");
-
- return Rect::FromVertices(PixelToDip(rect.left), PixelToDip(rect.top),
- PixelToDip(rect.right), PixelToDip(rect.bottom));
- } else {
- return CalcWindowRectFromClient(client_rect_, style_flag_, dpi_);
- }
-}
-
-void WinNativeWindow::SetWindowRect(const Rect& rect) {
- client_rect_ = CalcClientRectFromWindow(rect, style_flag_, dpi_);
-
- if (hwnd_) {
- if (!SetWindowPos(hwnd_, nullptr, DipToPixel(rect.left),
- DipToPixel(rect.top), DipToPixel(rect.GetRight()),
- DipToPixel(rect.GetBottom()), SWP_NOZORDER))
- throw Win32Error(::GetLastError(), u"Failed to invoke SetWindowPos.");
- }
-}
-
-bool WinNativeWindow::RequestFocus() {
- if (hwnd_) {
- SetFocus(hwnd_);
- return true;
- }
- return false;
-}
-
-Point WinNativeWindow::GetMousePosition() {
- POINT p;
- if (!::GetCursorPos(&p))
- throw Win32Error(::GetLastError(), u"Failed to get cursor position.");
- if (!::ScreenToClient(hwnd_, &p))
- throw Win32Error(::GetLastError(), u"Failed to call ScreenToClient.");
- return PixelToDip(p);
-}
-
-bool WinNativeWindow::CaptureMouse() {
- ::SetCapture(hwnd_);
- return true;
-}
-
-bool WinNativeWindow::ReleaseMouse() {
- const auto result = ::ReleaseCapture();
- return result != 0;
-}
-
-void WinNativeWindow::RequestRepaint() {
- if constexpr (DebugFlags::paint) {
- CRU_LOG_DEBUG(u"A repaint is requested.");
- }
- if (!::InvalidateRect(hwnd_, nullptr, FALSE))
- throw Win32Error(::GetLastError(), u"Failed to invalidate window.");
- if (!::UpdateWindow(hwnd_))
- throw Win32Error(::GetLastError(), u"Failed to update window.");
-}
-
-std::unique_ptr<graphics::IPainter> WinNativeWindow::BeginPaint() {
- if (hwnd_)
- return std::make_unique<graphics::win::direct::D2DWindowPainter>(
- window_render_target_.get());
- else
- return std::make_unique<graphics::NullPainter>();
-}
-
-void WinNativeWindow::SetCursor(std::shared_ptr<ICursor> cursor) {
- if (cursor == nullptr) {
- throw std::runtime_error("Can't use a nullptr as cursor.");
- }
-
- cursor_ = CheckPlatform<WinCursor>(cursor, GetPlatformId());
-
- if (hwnd_) return;
-
- if (!::SetClassLongPtrW(hwnd_, GCLP_HCURSOR,
- reinterpret_cast<LONG_PTR>(cursor_->GetHandle()))) {
- CRU_LOG_WARN(
- u"Failed to set cursor because failed to set class long. Last "
- u"error code: {}.",
- ::GetLastError());
- return;
- }
-
- if (GetVisibility() != WindowVisibilityType::Show) return;
-
- auto lg = [](StringView reason) {
- CRU_LOG_WARN(
-
- u"Failed to set cursor because {} when window is visible. (We need to "
- u"update cursor if it is inside the window.) Last error code: {}.",
- reason, ::GetLastError());
- };
-
- ::POINT point;
- if (!::GetCursorPos(&point)) {
- lg(u"failed to get cursor pos");
- return;
- }
-
- ::RECT rect;
- if (!::GetClientRect(hwnd_, &rect)) {
- lg(u"failed to get window's client rect");
- return;
- }
-
- ::POINT lefttop{rect.left, rect.top};
- ::POINT rightbottom{rect.right, rect.bottom};
- if (!::ClientToScreen(hwnd_, &lefttop)) {
- lg(u"failed to call ClientToScreen on lefttop");
- return;
- }
-
- if (!::ClientToScreen(hwnd_, &rightbottom)) {
- lg(u"failed to call ClientToScreen on rightbottom");
- return;
- }
-
- if (point.x >= lefttop.x && point.y >= lefttop.y &&
- point.x <= rightbottom.x && point.y <= rightbottom.y) {
- ::SetCursor(cursor_->GetHandle());
- }
-}
-
-void WinNativeWindow::SetToForeground() {
- if (hwnd_) {
- if (!::SetForegroundWindow(hwnd_))
- throw Win32Error(::GetLastError(),
- u"Failed to set window to foreground.");
- }
-}
-
-IInputMethodContext* WinNativeWindow::GetInputMethodContext() {
- return static_cast<IInputMethodContext*>(input_method_context_.get());
-}
-
-bool WinNativeWindow::HandleNativeWindowMessage(HWND hwnd, UINT msg,
- WPARAM w_param, LPARAM l_param,
- LRESULT* result) {
- WindowNativeMessageEventArgs args{
- WindowNativeMessage{hwnd, msg, w_param, l_param}};
- native_message_event_.Raise(args);
- if (args.IsHandled()) {
- *result = args.GetResult();
- return true;
- }
-
- switch (msg) {
- case WM_PAINT:
- OnPaintInternal();
- *result = 0;
- return true;
- case WM_ERASEBKGND:
- *result = 1;
- return true;
- case WM_SETFOCUS:
- OnSetFocusInternal();
- *result = 0;
- return true;
- case WM_KILLFOCUS:
- OnKillFocusInternal();
- *result = 0;
- return true;
- case WM_MOUSEMOVE: {
- POINT point;
- point.x = GET_X_LPARAM(l_param);
- point.y = GET_Y_LPARAM(l_param);
- OnMouseMoveInternal(point);
- *result = 0;
- return true;
- }
- case WM_LBUTTONDOWN: {
- POINT point;
- point.x = GET_X_LPARAM(l_param);
- point.y = GET_Y_LPARAM(l_param);
- OnMouseDownInternal(platform::gui::mouse_buttons::left, point);
- *result = 0;
- return true;
- }
- case WM_LBUTTONUP: {
- POINT point;
- point.x = GET_X_LPARAM(l_param);
- point.y = GET_Y_LPARAM(l_param);
- OnMouseUpInternal(platform::gui::mouse_buttons::left, point);
- *result = 0;
- return true;
- }
- case WM_RBUTTONDOWN: {
- POINT point;
- point.x = GET_X_LPARAM(l_param);
- point.y = GET_Y_LPARAM(l_param);
- OnMouseDownInternal(platform::gui::mouse_buttons::right, point);
- *result = 0;
- return true;
- }
- case WM_RBUTTONUP: {
- POINT point;
- point.x = GET_X_LPARAM(l_param);
- point.y = GET_Y_LPARAM(l_param);
- OnMouseUpInternal(platform::gui::mouse_buttons::right, point);
- *result = 0;
- return true;
- }
- case WM_MBUTTONDOWN: {
- POINT point;
- point.x = GET_X_LPARAM(l_param);
- point.y = GET_Y_LPARAM(l_param);
- OnMouseDownInternal(platform::gui::mouse_buttons::middle, point);
- *result = 0;
- return true;
- }
- case WM_MBUTTONUP: {
- POINT point;
- point.x = GET_X_LPARAM(l_param);
- point.y = GET_Y_LPARAM(l_param);
- OnMouseUpInternal(platform::gui::mouse_buttons::middle, point);
- *result = 0;
- return true;
- }
- case WM_MOUSEWHEEL:
- POINT point;
- point.x = GET_X_LPARAM(l_param);
- point.y = GET_Y_LPARAM(l_param);
- ScreenToClient(hwnd, &point);
- OnMouseWheelInternal(GET_WHEEL_DELTA_WPARAM(w_param), point);
- *result = 0;
- return true;
- case WM_KEYDOWN:
- OnKeyDownInternal(static_cast<int>(w_param));
- *result = 0;
- return true;
- case WM_KEYUP:
- OnKeyUpInternal(static_cast<int>(w_param));
- *result = 0;
- return true;
- case WM_SYSKEYDOWN:
- if (l_param & (1 << 29)) {
- OnKeyDownInternal(static_cast<int>(w_param));
- *result = 0;
- return true;
- }
- return false;
- case WM_SYSKEYUP:
- if (l_param & (1 << 29)) {
- OnKeyUpInternal(static_cast<int>(w_param));
- *result = 0;
- return true;
- }
- return false;
- case WM_CREATE:
- OnCreateInternal();
- *result = 0;
- return true;
- case WM_MOVE:
- OnMoveInternal(LOWORD(l_param), HIWORD(l_param));
- *result = 0;
- return true;
- case WM_SIZE:
- OnResizeInternal(LOWORD(l_param), HIWORD(l_param));
- *result = 0;
- return true;
- case WM_ACTIVATE:
- if (w_param == WA_ACTIVE || w_param == WA_CLICKACTIVE)
- OnActivatedInternal();
- else if (w_param == WA_INACTIVE)
- OnDeactivatedInternal();
- *result = 0;
- return true;
- case WM_DESTROY:
- OnDestroyInternal();
- *result = 0;
- return true;
- case WM_IME_SETCONTEXT:
- l_param &= ~ISC_SHOWUICOMPOSITIONWINDOW;
- *result = ::DefWindowProcW(hwnd, msg, w_param, l_param);
- return true;
- // We must block these message from DefWindowProc or it will create
- // an ugly composition window.
- case WM_IME_STARTCOMPOSITION:
- case WM_IME_COMPOSITION:
- *result = 0;
- return true;
- case WM_DPICHANGED: {
- dpi_ = static_cast<float>(LOWORD(w_param));
- const RECT* suggest_rect = reinterpret_cast<const RECT*>(l_param);
- window_render_target_->SetDpi(dpi_, dpi_);
- SetWindowPos(hwnd_, NULL, suggest_rect->left, suggest_rect->top,
- suggest_rect->right - suggest_rect->left,
- suggest_rect->bottom - suggest_rect->top,
- SWP_NOZORDER | SWP_NOACTIVATE);
- }
- default:
- return false;
- }
-}
-
-RECT WinNativeWindow::GetClientRectPixel() {
- RECT rect;
- if (!::GetClientRect(hwnd_, &rect))
- throw Win32Error(::GetLastError(), u"Failed to invoke GetClientRect.");
- return rect;
-}
-
-void WinNativeWindow::RecreateWindow() {
- const auto window_manager = application_->GetWindowManager();
- auto window_class = window_manager->GetGeneralWindowClass();
-
- hwnd_ = CreateWindowExW(
- 0, window_class->GetName(), L"", CalcWindowStyle(style_flag_),
- CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
- parent_window_ == nullptr ? nullptr : parent_window_->GetWindowHandle(),
- nullptr, application_->GetInstanceHandle(), nullptr);
-
- if (hwnd_ == nullptr)
- throw Win32Error(::GetLastError(), u"Failed to create window.");
-
- auto dpi = ::GetDpiForWindow(hwnd_);
- if (dpi == 0)
- throw Win32Error(::GetLastError(), u"Failed to get dpi of window.");
- dpi_ = static_cast<float>(dpi);
- CRU_LOG_DEBUG(u"Dpi of window is {}.", dpi_);
-
- window_manager->RegisterWindow(hwnd_, this);
-
- SetCursor(application_->GetCursorManager()->GetSystemCursor(
- cru::platform::gui::SystemCursorType::Arrow));
-
- ::SetWindowTextW(hwnd_, title_.WinCStr());
-
- window_render_target_ =
- std::make_unique<graphics::win::direct::D2DWindowRenderTarget>(
- application_->GetDirectFactory(), hwnd_);
- window_render_target_->SetDpi(dpi_, dpi_);
-
- input_method_context_ = std::make_unique<WinInputMethodContext>(this);
- input_method_context_->DisableIME();
-}
-
-void WinNativeWindow::OnCreateInternal() { create_event_.Raise(nullptr); }
-
-void WinNativeWindow::OnDestroyInternal() {
- destroy_event_.Raise(nullptr);
- application_->GetWindowManager()->UnregisterWindow(hwnd_);
- hwnd_ = nullptr;
-}
-
-void WinNativeWindow::OnPaintInternal() {
- paint_event_.Raise(nullptr);
- ValidateRect(hwnd_, nullptr);
- if constexpr (DebugFlags::paint) {
- CRU_LOG_DEBUG(u"A repaint is finished.");
- }
-}
-
-void WinNativeWindow::OnMoveInternal(const int new_left, const int new_top) {
- client_rect_.left = PixelToDip(new_left);
- client_rect_.top = PixelToDip(new_top);
-}
-
-void WinNativeWindow::OnResizeInternal(const int new_width,
- const int new_height) {
- client_rect_.width = PixelToDip(new_width);
- client_rect_.height = PixelToDip(new_height);
- if (!(new_width == 0 && new_height == 0)) {
- window_render_target_->ResizeBuffer(new_width, new_height);
- resize_event_.Raise(Size{PixelToDip(new_width), PixelToDip(new_height)});
- }
-}
-
-void WinNativeWindow::OnSetFocusInternal() {
- has_focus_ = true;
- focus_event_.Raise(FocusChangeType::Gain);
-}
-
-void WinNativeWindow::OnKillFocusInternal() {
- has_focus_ = false;
- focus_event_.Raise(FocusChangeType::Lose);
-}
-
-void WinNativeWindow::OnMouseMoveInternal(const POINT point) {
- // when mouse was previous outside the window
- if (!is_mouse_in_) {
- // invoke TrackMouseEvent to have WM_MOUSELEAVE sent.
- TRACKMOUSEEVENT tme;
- tme.cbSize = sizeof tme;
- tme.dwFlags = TME_LEAVE;
- tme.hwndTrack = hwnd_;
-
- TrackMouseEvent(&tme);
-
- is_mouse_in_ = true;
- mouse_enter_leave_event_.Raise(MouseEnterLeaveType::Enter);
- }
-
- mouse_move_event_.Raise(PixelToDip(point));
-}
-
-void WinNativeWindow::OnMouseLeaveInternal() {
- is_mouse_in_ = false;
- mouse_enter_leave_event_.Raise(MouseEnterLeaveType::Leave);
-}
-
-void WinNativeWindow::OnMouseDownInternal(platform::gui::MouseButton button,
- POINT point) {
- const auto dip_point = PixelToDip(point);
- mouse_down_event_.Raise({button, dip_point, RetrieveKeyMofifier()});
-}
-
-void WinNativeWindow::OnMouseUpInternal(platform::gui::MouseButton button,
- POINT point) {
- const auto dip_point = PixelToDip(point);
- mouse_up_event_.Raise({button, dip_point, RetrieveKeyMofifier()});
-}
-
-void WinNativeWindow::OnMouseWheelInternal(short delta, POINT point) {
- const auto dip_point = PixelToDip(point);
- const float d = -((float)delta / 120.f);
- mouse_wheel_event_.Raise({d, dip_point, RetrieveKeyMofifier()});
-}
-
-void WinNativeWindow::OnKeyDownInternal(int virtual_code) {
- key_down_event_.Raise(
- {VirtualKeyToKeyCode(virtual_code), RetrieveKeyMofifier()});
-}
-
-void WinNativeWindow::OnKeyUpInternal(int virtual_code) {
- key_up_event_.Raise(
- {VirtualKeyToKeyCode(virtual_code), RetrieveKeyMofifier()});
-}
-
-void WinNativeWindow::OnActivatedInternal() {}
-
-void WinNativeWindow::OnDeactivatedInternal() {}
-} // namespace cru::platform::gui::win