1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "ui/platform_window/win/win_window.h"
6
7#include "ui/events/event.h"
8#include "ui/events/event_utils.h"
9#include "ui/gfx/win/msg_util.h"
10#include "ui/platform_window/platform_window_delegate.h"
11
12namespace ui {
13
14namespace {
15
16bool use_popup_as_root_window_for_test = false;
17
18gfx::Rect GetWindowBoundsForClientBounds(DWORD style, DWORD ex_style,
19                                         const gfx::Rect& bounds) {
20  RECT wr;
21  wr.left = bounds.x();
22  wr.top = bounds.y();
23  wr.right = bounds.x() + bounds.width();
24  wr.bottom = bounds.y() + bounds.height();
25  AdjustWindowRectEx(&wr, style, FALSE, ex_style);
26
27  // Make sure to keep the window onscreen, as AdjustWindowRectEx() may have
28  // moved part of it offscreen.
29  gfx::Rect window_bounds(wr.left, wr.top,
30                          wr.right - wr.left, wr.bottom - wr.top);
31  window_bounds.set_x(std::max(0, window_bounds.x()));
32  window_bounds.set_y(std::max(0, window_bounds.y()));
33  return window_bounds;
34}
35
36}  // namespace
37
38WinWindow::WinWindow(PlatformWindowDelegate* delegate,
39                     const gfx::Rect& bounds)
40    : delegate_(delegate) {
41  CHECK(delegate_);
42  if (use_popup_as_root_window_for_test)
43    set_window_style(WS_POPUP);
44  gfx::Rect window_bounds = GetWindowBoundsForClientBounds(
45      WS_OVERLAPPEDWINDOW, window_ex_style(), bounds);
46  gfx::WindowImpl::Init(NULL, window_bounds);
47  SetWindowText(hwnd(), L"WinWindow");
48}
49
50WinWindow::~WinWindow() {
51  Destroy();
52}
53
54void WinWindow::Destroy() {
55  if (IsWindow(hwnd()))
56    DestroyWindow(hwnd());
57}
58
59void WinWindow::Show() {
60  ShowWindow(hwnd(), SW_SHOWNORMAL);
61}
62
63void WinWindow::Hide() {
64  ShowWindow(hwnd(), SW_HIDE);
65}
66
67void WinWindow::Close() {
68  Destroy();
69}
70
71void WinWindow::SetBounds(const gfx::Rect& bounds) {
72  gfx::Rect window_bounds = GetWindowBoundsForClientBounds(
73      GetWindowLong(hwnd(), GWL_STYLE),
74      GetWindowLong(hwnd(), GWL_EXSTYLE),
75      bounds);
76  SetWindowPos(hwnd(), NULL, window_bounds.x(), window_bounds.y(),
77               window_bounds.width(), window_bounds.height(),
78               SWP_NOREPOSITION);
79}
80
81gfx::Rect WinWindow::GetBounds() {
82  RECT cr;
83  GetClientRect(hwnd(), &cr);
84  return gfx::Rect(cr);
85}
86
87void WinWindow::SetCapture() {
88  DCHECK(::GetCapture() != hwnd());
89  ::SetCapture(hwnd());
90}
91
92void WinWindow::ReleaseCapture() {
93  if (::GetCapture() == hwnd())
94    ::ReleaseCapture();
95}
96
97void WinWindow::ToggleFullscreen() {}
98
99void WinWindow::Maximize() {}
100
101void WinWindow::Minimize() {}
102
103void WinWindow::Restore() {}
104
105void WinWindow::SetCursor(PlatformCursor cursor) {}
106
107void WinWindow::MoveCursorTo(const gfx::Point& location) {}
108
109LRESULT WinWindow::OnMouseRange(UINT message, WPARAM w_param, LPARAM l_param) {
110  MSG msg = { hwnd(), message, w_param, l_param, 0,
111              { CR_GET_X_LPARAM(l_param), CR_GET_Y_LPARAM(l_param) } };
112  MouseEvent event(msg);
113  if (IsMouseEventFromTouch(message))
114    event.set_flags(event.flags() | EF_FROM_TOUCH);
115  if (!(event.flags() & ui::EF_IS_NON_CLIENT))
116    delegate_->DispatchEvent(&event);
117  SetMsgHandled(event.handled());
118  return 0;
119}
120
121LRESULT WinWindow::OnCaptureChanged(UINT message,
122                                    WPARAM w_param,
123                                    LPARAM l_param) {
124  delegate_->OnLostCapture();
125  return 0;
126}
127
128LRESULT WinWindow::OnKeyEvent(UINT message, WPARAM w_param, LPARAM l_param) {
129  MSG msg = { hwnd(), message, w_param, l_param };
130  KeyEvent event(msg);
131  delegate_->DispatchEvent(&event);
132  SetMsgHandled(event.handled());
133  return 0;
134}
135
136LRESULT WinWindow::OnNCActivate(UINT message, WPARAM w_param, LPARAM l_param) {
137  delegate_->OnActivationChanged(!!w_param);
138  return DefWindowProc(hwnd(), message, w_param, l_param);
139}
140
141void WinWindow::OnClose() {
142  delegate_->OnCloseRequest();
143}
144
145LRESULT WinWindow::OnCreate(CREATESTRUCT* create_struct) {
146  delegate_->OnAcceleratedWidgetAvailable(hwnd());
147  return 0;
148}
149
150void WinWindow::OnDestroy() {
151  delegate_->OnClosed();
152}
153
154void WinWindow::OnPaint(HDC) {
155  gfx::Rect damage_rect;
156  RECT update_rect = {0};
157  if (GetUpdateRect(hwnd(), &update_rect, FALSE))
158    damage_rect = gfx::Rect(update_rect);
159  delegate_->OnDamageRect(damage_rect);
160  ValidateRect(hwnd(), NULL);
161}
162
163void WinWindow::OnWindowPosChanged(WINDOWPOS* window_pos) {
164  if (!(window_pos->flags & SWP_NOSIZE) ||
165      !(window_pos->flags & SWP_NOMOVE)) {
166    RECT cr;
167    GetClientRect(hwnd(), &cr);
168    delegate_->OnBoundsChanged(
169        gfx::Rect(window_pos->x, window_pos->y,
170                  cr.right - cr.left, cr.bottom - cr.top));
171  }
172}
173
174namespace test {
175
176// static
177void SetUsePopupAsRootWindowForTest(bool use) {
178  use_popup_as_root_window_for_test = use;
179}
180
181}  // namespace test
182}  // namespace ui
183