1// Copyright 2013 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 "mojo/services/native_viewport/native_viewport.h"
6
7#include "ui/events/event.h"
8#include "ui/gfx/win/msg_util.h"
9#include "ui/gfx/win/window_impl.h"
10
11namespace mojo {
12namespace services {
13namespace {
14
15gfx::Rect GetWindowBoundsForClientBounds(DWORD style, DWORD ex_style,
16                                         const gfx::Rect& bounds) {
17  RECT wr;
18  wr.left = bounds.x();
19  wr.top = bounds.y();
20  wr.right = bounds.x() + bounds.width();
21  wr.bottom = bounds.y() + bounds.height();
22  AdjustWindowRectEx(&wr, style, FALSE, ex_style);
23
24  // Make sure to keep the window onscreen, as AdjustWindowRectEx() may have
25  // moved part of it offscreen.
26  gfx::Rect window_bounds(wr.left, wr.top,
27                          wr.right - wr.left, wr.bottom - wr.top);
28  window_bounds.set_x(std::max(0, window_bounds.x()));
29  window_bounds.set_y(std::max(0, window_bounds.y()));
30  return window_bounds;
31}
32
33}
34
35class NativeViewportWin : public gfx::WindowImpl,
36                          public NativeViewport {
37 public:
38  explicit NativeViewportWin(NativeViewportDelegate* delegate)
39      : delegate_(delegate) {
40  }
41  virtual ~NativeViewportWin() {
42    if (IsWindow(hwnd()))
43      DestroyWindow(hwnd());
44  }
45
46 private:
47  // Overridden from NativeViewport:
48  virtual void Init(const gfx::Rect& bounds) OVERRIDE {
49    gfx::Rect window_bounds = GetWindowBoundsForClientBounds(
50        WS_OVERLAPPEDWINDOW, window_ex_style(), bounds);
51    gfx::WindowImpl::Init(NULL, window_bounds);
52    SetWindowText(hwnd(), L"native_viewport::NativeViewportWin!");
53  }
54
55  virtual void Show() OVERRIDE {
56    ShowWindow(hwnd(), SW_SHOWNORMAL);
57  }
58
59  virtual void Hide() OVERRIDE {
60    ShowWindow(hwnd(), SW_HIDE);
61  }
62
63  virtual void Close() OVERRIDE {
64    DestroyWindow(hwnd());
65  }
66
67  virtual gfx::Size GetSize() OVERRIDE {
68    RECT cr;
69    GetClientRect(hwnd(), &cr);
70    return gfx::Size(cr.right - cr.left, cr.bottom - cr.top);
71  }
72
73  virtual void SetBounds(const gfx::Rect& bounds) OVERRIDE {
74    gfx::Rect window_bounds = GetWindowBoundsForClientBounds(
75        GetWindowLong(hwnd(), GWL_STYLE),
76        GetWindowLong(hwnd(), GWL_EXSTYLE),
77        bounds);
78    SetWindowPos(hwnd(), NULL, window_bounds.x(), window_bounds.y(),
79                 window_bounds.width(), window_bounds.height(),
80                 SWP_NOREPOSITION);
81  }
82
83  virtual void SetCapture() OVERRIDE {
84    DCHECK(::GetCapture() != hwnd());
85    ::SetCapture(hwnd());
86  }
87
88  virtual void ReleaseCapture() OVERRIDE {
89    if (::GetCapture() == hwnd())
90      ::ReleaseCapture();
91  }
92
93  CR_BEGIN_MSG_MAP_EX(NativeViewportWin)
94    CR_MESSAGE_RANGE_HANDLER_EX(WM_MOUSEFIRST, WM_MOUSELAST, OnMouseRange)
95
96    CR_MESSAGE_HANDLER_EX(WM_KEYDOWN, OnKeyEvent)
97    CR_MESSAGE_HANDLER_EX(WM_KEYUP, OnKeyEvent)
98    CR_MESSAGE_HANDLER_EX(WM_SYSKEYDOWN, OnKeyEvent)
99    CR_MESSAGE_HANDLER_EX(WM_SYSKEYUP, OnKeyEvent)
100    CR_MESSAGE_HANDLER_EX(WM_CHAR, OnKeyEvent)
101    CR_MESSAGE_HANDLER_EX(WM_SYSCHAR, OnKeyEvent)
102    CR_MESSAGE_HANDLER_EX(WM_IME_CHAR, OnKeyEvent)
103
104    CR_MSG_WM_CREATE(OnCreate)
105    CR_MSG_WM_DESTROY(OnDestroy)
106    CR_MSG_WM_PAINT(OnPaint)
107    CR_MSG_WM_WINDOWPOSCHANGED(OnWindowPosChanged)
108  CR_END_MSG_MAP()
109
110  LRESULT OnMouseRange(UINT message, WPARAM w_param, LPARAM l_param) {
111    MSG msg = { hwnd(), message, w_param, l_param, 0,
112                { CR_GET_X_LPARAM(l_param), CR_GET_Y_LPARAM(l_param) } };
113    ui::MouseEvent event(msg);
114    SetMsgHandled(delegate_->OnEvent(&event));
115    return 0;
116  }
117  LRESULT OnKeyEvent(UINT message, WPARAM w_param, LPARAM l_param) {
118    MSG msg = { hwnd(), message, w_param, l_param };
119    ui::KeyEvent event(msg, message == WM_CHAR);
120    SetMsgHandled(delegate_->OnEvent(&event));
121    return 0;
122  }
123  LRESULT OnCreate(CREATESTRUCT* create_struct) {
124    delegate_->OnAcceleratedWidgetAvailable(hwnd());
125    return 0;
126  }
127  void OnDestroy() {
128    delegate_->OnDestroyed();
129  }
130  void OnPaint(HDC) {
131    RECT cr;
132    GetClientRect(hwnd(), &cr);
133
134    PAINTSTRUCT ps;
135    HDC dc = BeginPaint(hwnd(), &ps);
136    HBRUSH red_brush = CreateSolidBrush(RGB(255, 0, 0));
137    HGDIOBJ old_object = SelectObject(dc, red_brush);
138    Rectangle(dc, cr.left, cr.top, cr.right, cr.bottom);
139    SelectObject(dc, old_object);
140    DeleteObject(red_brush);
141    EndPaint(hwnd(), &ps);
142  }
143  void OnWindowPosChanged(WINDOWPOS* window_pos) {
144    if (!(window_pos->flags & SWP_NOSIZE) ||
145        !(window_pos->flags & SWP_NOMOVE)) {
146      RECT cr;
147      GetClientRect(hwnd(), &cr);
148      delegate_->OnBoundsChanged(
149          gfx::Rect(window_pos->x, window_pos->y,
150                    cr.right - cr.left, cr.bottom - cr.top));
151    }
152  }
153
154  NativeViewportDelegate* delegate_;
155
156  DISALLOW_COPY_AND_ASSIGN(NativeViewportWin);
157};
158
159// static
160scoped_ptr<NativeViewport> NativeViewport::Create(
161    shell::Context* context,
162    NativeViewportDelegate* delegate) {
163  return scoped_ptr<NativeViewport>(new NativeViewportWin(delegate)).Pass();
164}
165
166}  // namespace services
167}  // namespace mojo
168