1// Copyright (c) 2012 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/views/widget/desktop_aura/desktop_window_tree_host_win.h"
6
7#include "base/win/metro.h"
8#include "third_party/skia/include/core/SkPath.h"
9#include "third_party/skia/include/core/SkRegion.h"
10#include "ui/aura/client/aura_constants.h"
11#include "ui/aura/client/cursor_client.h"
12#include "ui/aura/client/focus_client.h"
13#include "ui/aura/window_event_dispatcher.h"
14#include "ui/aura/window_property.h"
15#include "ui/base/cursor/cursor_loader_win.h"
16#include "ui/base/ime/input_method.h"
17#include "ui/base/win/shell.h"
18#include "ui/compositor/compositor_constants.h"
19#include "ui/gfx/insets.h"
20#include "ui/gfx/native_widget_types.h"
21#include "ui/gfx/path.h"
22#include "ui/gfx/path_win.h"
23#include "ui/gfx/vector2d.h"
24#include "ui/gfx/win/dpi.h"
25#include "ui/native_theme/native_theme_aura.h"
26#include "ui/native_theme/native_theme_win.h"
27#include "ui/views/corewm/tooltip_win.h"
28#include "ui/views/ime/input_method_bridge.h"
29#include "ui/views/widget/desktop_aura/desktop_cursor_loader_updater.h"
30#include "ui/views/widget/desktop_aura/desktop_drag_drop_client_win.h"
31#include "ui/views/widget/desktop_aura/desktop_native_cursor_manager.h"
32#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
33#include "ui/views/widget/root_view.h"
34#include "ui/views/widget/widget_delegate.h"
35#include "ui/views/widget/widget_hwnd_utils.h"
36#include "ui/views/win/fullscreen_handler.h"
37#include "ui/views/win/hwnd_message_handler.h"
38#include "ui/wm/core/compound_event_filter.h"
39#include "ui/wm/core/input_method_event_filter.h"
40#include "ui/wm/core/window_animations.h"
41#include "ui/wm/public/scoped_tooltip_disabler.h"
42
43namespace views {
44
45namespace {
46
47gfx::Size GetExpandedWindowSize(DWORD window_style, gfx::Size size) {
48  if (!(window_style & WS_EX_COMPOSITED) || !ui::win::IsAeroGlassEnabled())
49    return size;
50
51  // Some AMD drivers can't display windows that are less than 64x64 pixels,
52  // so expand them to be at least that size. http://crbug.com/286609
53  gfx::Size expanded(std::max(size.width(), 64), std::max(size.height(), 64));
54  return expanded;
55}
56
57void InsetBottomRight(gfx::Rect* rect, gfx::Vector2d vector) {
58  rect->Inset(0, 0, vector.x(), vector.y());
59}
60
61}  // namespace
62
63DEFINE_WINDOW_PROPERTY_KEY(aura::Window*, kContentWindowForRootWindow, NULL);
64
65// Identifies the DesktopWindowTreeHostWin associated with the
66// WindowEventDispatcher.
67DEFINE_WINDOW_PROPERTY_KEY(DesktopWindowTreeHostWin*, kDesktopWindowTreeHostKey,
68                           NULL);
69
70////////////////////////////////////////////////////////////////////////////////
71// DesktopWindowTreeHostWin, public:
72
73bool DesktopWindowTreeHostWin::is_cursor_visible_ = true;
74
75DesktopWindowTreeHostWin::DesktopWindowTreeHostWin(
76    internal::NativeWidgetDelegate* native_widget_delegate,
77    DesktopNativeWidgetAura* desktop_native_widget_aura)
78    : message_handler_(new HWNDMessageHandler(this)),
79      native_widget_delegate_(native_widget_delegate),
80      desktop_native_widget_aura_(desktop_native_widget_aura),
81      content_window_(NULL),
82      drag_drop_client_(NULL),
83      should_animate_window_close_(false),
84      pending_close_(false),
85      has_non_client_view_(false),
86      tooltip_(NULL),
87      need_synchronous_paint_(false),
88      in_sizing_loop_(false) {
89}
90
91DesktopWindowTreeHostWin::~DesktopWindowTreeHostWin() {
92  // WARNING: |content_window_| has been destroyed by the time we get here.
93  desktop_native_widget_aura_->OnDesktopWindowTreeHostDestroyed(this);
94  DestroyDispatcher();
95}
96
97// static
98aura::Window* DesktopWindowTreeHostWin::GetContentWindowForHWND(HWND hwnd) {
99  aura::WindowTreeHost* host =
100      aura::WindowTreeHost::GetForAcceleratedWidget(hwnd);
101  return host ? host->window()->GetProperty(kContentWindowForRootWindow) : NULL;
102}
103
104// static
105ui::NativeTheme* DesktopWindowTreeHost::GetNativeTheme(aura::Window* window) {
106  // Use NativeThemeWin for windows shown on the desktop, those not on the
107  // desktop come from Ash and get NativeThemeAura.
108  aura::WindowTreeHost* host = window ? window->GetHost() : NULL;
109  if (host) {
110    HWND host_hwnd = host->GetAcceleratedWidget();
111    if (host_hwnd &&
112        DesktopWindowTreeHostWin::GetContentWindowForHWND(host_hwnd)) {
113      return ui::NativeThemeWin::instance();
114    }
115  }
116  return ui::NativeThemeAura::instance();
117}
118
119////////////////////////////////////////////////////////////////////////////////
120// DesktopWindowTreeHostWin, DesktopWindowTreeHost implementation:
121
122void DesktopWindowTreeHostWin::Init(aura::Window* content_window,
123                                    const Widget::InitParams& params) {
124  // TODO(beng): SetInitParams().
125  content_window_ = content_window;
126
127  aura::client::SetAnimationHost(content_window_, this);
128
129  ConfigureWindowStyles(message_handler_.get(), params,
130                        GetWidget()->widget_delegate(),
131                        native_widget_delegate_);
132
133  HWND parent_hwnd = NULL;
134  if (params.parent && params.parent->GetHost())
135    parent_hwnd = params.parent->GetHost()->GetAcceleratedWidget();
136
137  message_handler_->set_remove_standard_frame(params.remove_standard_frame);
138
139  has_non_client_view_ = Widget::RequiresNonClientView(params.type);
140
141  gfx::Rect pixel_bounds = gfx::win::DIPToScreenRect(params.bounds);
142  message_handler_->Init(parent_hwnd, pixel_bounds);
143  if (params.type == Widget::InitParams::TYPE_MENU) {
144    ::SetProp(GetAcceleratedWidget(),
145              kForceSoftwareCompositor,
146              reinterpret_cast<HANDLE>(true));
147  }
148  CreateCompositor(GetAcceleratedWidget());
149}
150
151void DesktopWindowTreeHostWin::OnNativeWidgetCreated(
152    const Widget::InitParams& params) {
153  // The cursor is not necessarily visible when the root window is created.
154  aura::client::CursorClient* cursor_client =
155      aura::client::GetCursorClient(window());
156  if (cursor_client)
157    is_cursor_visible_ = cursor_client->IsCursorVisible();
158
159  window()->SetProperty(kContentWindowForRootWindow, content_window_);
160  window()->SetProperty(kDesktopWindowTreeHostKey, this);
161
162  should_animate_window_close_ =
163      content_window_->type() != ui::wm::WINDOW_TYPE_NORMAL &&
164      !wm::WindowAnimationsDisabled(content_window_);
165
166// TODO this is not invoked *after* Init(), but should be ok.
167  SetWindowTransparency();
168}
169
170scoped_ptr<corewm::Tooltip> DesktopWindowTreeHostWin::CreateTooltip() {
171  DCHECK(!tooltip_);
172  tooltip_ = new corewm::TooltipWin(GetAcceleratedWidget());
173  return scoped_ptr<corewm::Tooltip>(tooltip_);
174}
175
176scoped_ptr<aura::client::DragDropClient>
177DesktopWindowTreeHostWin::CreateDragDropClient(
178    DesktopNativeCursorManager* cursor_manager) {
179  drag_drop_client_ = new DesktopDragDropClientWin(window(), GetHWND());
180  return scoped_ptr<aura::client::DragDropClient>(drag_drop_client_).Pass();
181}
182
183void DesktopWindowTreeHostWin::Close() {
184  // TODO(beng): Move this entire branch to DNWA so it can be shared with X11.
185  if (should_animate_window_close_) {
186    pending_close_ = true;
187    const bool is_animating =
188        content_window_->layer()->GetAnimator()->IsAnimatingProperty(
189            ui::LayerAnimationElement::VISIBILITY);
190    // Animation may not start for a number of reasons.
191    if (!is_animating)
192      message_handler_->Close();
193    // else case, OnWindowHidingAnimationCompleted does the actual Close.
194  } else {
195    message_handler_->Close();
196  }
197}
198
199void DesktopWindowTreeHostWin::CloseNow() {
200  message_handler_->CloseNow();
201}
202
203aura::WindowTreeHost* DesktopWindowTreeHostWin::AsWindowTreeHost() {
204  return this;
205}
206
207void DesktopWindowTreeHostWin::ShowWindowWithState(
208    ui::WindowShowState show_state) {
209  message_handler_->ShowWindowWithState(show_state);
210}
211
212void DesktopWindowTreeHostWin::ShowMaximizedWithBounds(
213    const gfx::Rect& restored_bounds) {
214  gfx::Rect pixel_bounds = gfx::win::DIPToScreenRect(restored_bounds);
215  message_handler_->ShowMaximizedWithBounds(pixel_bounds);
216}
217
218bool DesktopWindowTreeHostWin::IsVisible() const {
219  return message_handler_->IsVisible();
220}
221
222void DesktopWindowTreeHostWin::SetSize(const gfx::Size& size) {
223  gfx::Size size_in_pixels = gfx::win::DIPToScreenSize(size);
224  gfx::Size expanded = GetExpandedWindowSize(
225      message_handler_->window_ex_style(), size_in_pixels);
226  window_enlargement_ =
227      gfx::Vector2d(expanded.width() - size_in_pixels.width(),
228                    expanded.height() - size_in_pixels.height());
229  message_handler_->SetSize(expanded);
230}
231
232void DesktopWindowTreeHostWin::StackAtTop() {
233  message_handler_->StackAtTop();
234}
235
236void DesktopWindowTreeHostWin::CenterWindow(const gfx::Size& size) {
237  gfx::Size size_in_pixels = gfx::win::DIPToScreenSize(size);
238  gfx::Size expanded_size;
239  expanded_size = GetExpandedWindowSize(message_handler_->window_ex_style(),
240                                        size_in_pixels);
241  window_enlargement_ =
242      gfx::Vector2d(expanded_size.width() - size_in_pixels.width(),
243                    expanded_size.height() - size_in_pixels.height());
244  message_handler_->CenterWindow(expanded_size);
245}
246
247void DesktopWindowTreeHostWin::GetWindowPlacement(
248    gfx::Rect* bounds,
249    ui::WindowShowState* show_state) const {
250  message_handler_->GetWindowPlacement(bounds, show_state);
251  InsetBottomRight(bounds, window_enlargement_);
252  *bounds = gfx::win::ScreenToDIPRect(*bounds);
253}
254
255gfx::Rect DesktopWindowTreeHostWin::GetWindowBoundsInScreen() const {
256  gfx::Rect pixel_bounds = message_handler_->GetWindowBoundsInScreen();
257  InsetBottomRight(&pixel_bounds, window_enlargement_);
258  return gfx::win::ScreenToDIPRect(pixel_bounds);
259}
260
261gfx::Rect DesktopWindowTreeHostWin::GetClientAreaBoundsInScreen() const {
262  gfx::Rect pixel_bounds = message_handler_->GetClientAreaBoundsInScreen();
263  InsetBottomRight(&pixel_bounds, window_enlargement_);
264  return gfx::win::ScreenToDIPRect(pixel_bounds);
265}
266
267gfx::Rect DesktopWindowTreeHostWin::GetRestoredBounds() const {
268  gfx::Rect pixel_bounds = message_handler_->GetRestoredBounds();
269  InsetBottomRight(&pixel_bounds, window_enlargement_);
270  return gfx::win::ScreenToDIPRect(pixel_bounds);
271}
272
273gfx::Rect DesktopWindowTreeHostWin::GetWorkAreaBoundsInScreen() const {
274  MONITORINFO monitor_info;
275  monitor_info.cbSize = sizeof(monitor_info);
276  GetMonitorInfo(MonitorFromWindow(message_handler_->hwnd(),
277                                   MONITOR_DEFAULTTONEAREST),
278                 &monitor_info);
279  gfx::Rect pixel_bounds = gfx::Rect(monitor_info.rcWork);
280  return gfx::win::ScreenToDIPRect(pixel_bounds);
281}
282
283void DesktopWindowTreeHostWin::SetShape(gfx::NativeRegion native_region) {
284  if (native_region) {
285    // TODO(wez): This would be a lot simpler if we were passed an SkPath.
286    // See crbug.com/410593.
287    gfx::NativeRegion shape = native_region;
288    SkRegion device_region;
289    if (gfx::IsInHighDPIMode()) {
290      shape = &device_region;
291      const float& scale = gfx::GetDPIScale();
292      std::vector<SkIRect> rects;
293      for (SkRegion::Iterator it(*native_region); !it.done(); it.next()) {
294        const SkIRect& rect = it.rect();
295        SkRect scaled_rect =
296            SkRect::MakeLTRB(rect.left() * scale, rect.top() * scale,
297                             rect.right() * scale, rect.bottom() * scale);
298        SkIRect rounded_scaled_rect;
299        scaled_rect.roundOut(&rounded_scaled_rect);
300        rects.push_back(rounded_scaled_rect);
301      }
302      if (!rects.empty())
303        device_region.setRects(&rects[0], rects.size());
304    }
305
306    message_handler_->SetRegion(gfx::CreateHRGNFromSkRegion(*shape));
307  } else {
308    message_handler_->SetRegion(NULL);
309  }
310
311  delete native_region;
312}
313
314void DesktopWindowTreeHostWin::Activate() {
315  message_handler_->Activate();
316}
317
318void DesktopWindowTreeHostWin::Deactivate() {
319  message_handler_->Deactivate();
320}
321
322bool DesktopWindowTreeHostWin::IsActive() const {
323  return message_handler_->IsActive();
324}
325
326void DesktopWindowTreeHostWin::Maximize() {
327  message_handler_->Maximize();
328}
329
330void DesktopWindowTreeHostWin::Minimize() {
331  message_handler_->Minimize();
332}
333
334void DesktopWindowTreeHostWin::Restore() {
335  message_handler_->Restore();
336}
337
338bool DesktopWindowTreeHostWin::IsMaximized() const {
339  return message_handler_->IsMaximized();
340}
341
342bool DesktopWindowTreeHostWin::IsMinimized() const {
343  return message_handler_->IsMinimized();
344}
345
346bool DesktopWindowTreeHostWin::HasCapture() const {
347  return message_handler_->HasCapture();
348}
349
350void DesktopWindowTreeHostWin::SetAlwaysOnTop(bool always_on_top) {
351  message_handler_->SetAlwaysOnTop(always_on_top);
352}
353
354bool DesktopWindowTreeHostWin::IsAlwaysOnTop() const {
355  return message_handler_->IsAlwaysOnTop();
356}
357
358void DesktopWindowTreeHostWin::SetVisibleOnAllWorkspaces(bool always_visible) {
359  // Windows does not have the concept of workspaces.
360}
361
362bool DesktopWindowTreeHostWin::SetWindowTitle(const base::string16& title) {
363  return message_handler_->SetTitle(title);
364}
365
366void DesktopWindowTreeHostWin::ClearNativeFocus() {
367  message_handler_->ClearNativeFocus();
368}
369
370Widget::MoveLoopResult DesktopWindowTreeHostWin::RunMoveLoop(
371    const gfx::Vector2d& drag_offset,
372    Widget::MoveLoopSource source,
373    Widget::MoveLoopEscapeBehavior escape_behavior) {
374  const bool hide_on_escape =
375      escape_behavior == Widget::MOVE_LOOP_ESCAPE_BEHAVIOR_HIDE;
376  return message_handler_->RunMoveLoop(drag_offset, hide_on_escape) ?
377      Widget::MOVE_LOOP_SUCCESSFUL : Widget::MOVE_LOOP_CANCELED;
378}
379
380void DesktopWindowTreeHostWin::EndMoveLoop() {
381  message_handler_->EndMoveLoop();
382}
383
384void DesktopWindowTreeHostWin::SetVisibilityChangedAnimationsEnabled(
385    bool value) {
386  message_handler_->SetVisibilityChangedAnimationsEnabled(value);
387  content_window_->SetProperty(aura::client::kAnimationsDisabledKey, !value);
388}
389
390bool DesktopWindowTreeHostWin::ShouldUseNativeFrame() const {
391  return IsTranslucentWindowOpacitySupported();
392}
393
394bool DesktopWindowTreeHostWin::ShouldWindowContentsBeTransparent() const {
395  // If the window has a native frame, we assume it is an Aero Glass window, and
396  // is therefore transparent. Note: This is not equivalent to calling
397  // IsAeroGlassEnabled, because ShouldUseNativeFrame is overridden in a
398  // subclass.
399  return ShouldUseNativeFrame();
400}
401
402void DesktopWindowTreeHostWin::FrameTypeChanged() {
403  message_handler_->FrameTypeChanged();
404  SetWindowTransparency();
405}
406
407void DesktopWindowTreeHostWin::SetFullscreen(bool fullscreen) {
408  message_handler_->SetFullscreen(fullscreen);
409  // TODO(sky): workaround for ScopedFullscreenVisibility showing window
410  // directly. Instead of this should listen for visibility changes and then
411  // update window.
412  if (message_handler_->IsVisible() && !content_window_->TargetVisibility())
413    content_window_->Show();
414  SetWindowTransparency();
415}
416
417bool DesktopWindowTreeHostWin::IsFullscreen() const {
418  return message_handler_->fullscreen_handler()->fullscreen();
419}
420
421void DesktopWindowTreeHostWin::SetOpacity(unsigned char opacity) {
422  message_handler_->SetOpacity(static_cast<BYTE>(opacity));
423  content_window_->layer()->SetOpacity(opacity / 255.0);
424}
425
426void DesktopWindowTreeHostWin::SetWindowIcons(
427    const gfx::ImageSkia& window_icon, const gfx::ImageSkia& app_icon) {
428  message_handler_->SetWindowIcons(window_icon, app_icon);
429}
430
431void DesktopWindowTreeHostWin::InitModalType(ui::ModalType modal_type) {
432  message_handler_->InitModalType(modal_type);
433}
434
435void DesktopWindowTreeHostWin::FlashFrame(bool flash_frame) {
436  message_handler_->FlashFrame(flash_frame);
437}
438
439void DesktopWindowTreeHostWin::OnRootViewLayout() {
440}
441
442void DesktopWindowTreeHostWin::OnNativeWidgetFocus() {
443  // HWNDMessageHandler will perform the proper updating on its own.
444}
445
446void DesktopWindowTreeHostWin::OnNativeWidgetBlur() {
447}
448
449bool DesktopWindowTreeHostWin::IsAnimatingClosed() const {
450  return pending_close_;
451}
452
453bool DesktopWindowTreeHostWin::IsTranslucentWindowOpacitySupported() const {
454  return ui::win::IsAeroGlassEnabled();
455}
456
457void DesktopWindowTreeHostWin::SizeConstraintsChanged() {
458  message_handler_->SizeConstraintsChanged();
459}
460
461////////////////////////////////////////////////////////////////////////////////
462// DesktopWindowTreeHostWin, WindowTreeHost implementation:
463
464ui::EventSource* DesktopWindowTreeHostWin::GetEventSource() {
465  return this;
466}
467
468gfx::AcceleratedWidget DesktopWindowTreeHostWin::GetAcceleratedWidget() {
469  return message_handler_->hwnd();
470}
471
472void DesktopWindowTreeHostWin::Show() {
473  message_handler_->Show();
474}
475
476void DesktopWindowTreeHostWin::Hide() {
477  if (!pending_close_)
478    message_handler_->Hide();
479}
480
481// GetBounds and SetBounds work in pixel coordinates, whereas other get/set
482// methods work in DIP.
483
484gfx::Rect DesktopWindowTreeHostWin::GetBounds() const {
485  gfx::Rect bounds(message_handler_->GetClientAreaBounds());
486  // If the window bounds were expanded we need to return the original bounds
487  // To achieve this we do the reverse of the expansion, i.e. add the
488  // window_expansion_top_left_delta_ to the origin and subtract the
489  // window_expansion_bottom_right_delta_ from the width and height.
490  gfx::Rect without_expansion(
491      bounds.x() + window_expansion_top_left_delta_.x(),
492      bounds.y() + window_expansion_top_left_delta_.y(),
493      bounds.width() - window_expansion_bottom_right_delta_.x() -
494          window_enlargement_.x(),
495      bounds.height() - window_expansion_bottom_right_delta_.y() -
496          window_enlargement_.y());
497  return without_expansion;
498}
499
500void DesktopWindowTreeHostWin::SetBounds(const gfx::Rect& bounds) {
501  // If the window bounds have to be expanded we need to subtract the
502  // window_expansion_top_left_delta_ from the origin and add the
503  // window_expansion_bottom_right_delta_ to the width and height
504  gfx::Size old_hwnd_size(message_handler_->GetClientAreaBounds().size());
505  gfx::Size old_content_size = GetBounds().size();
506
507  gfx::Rect expanded(
508      bounds.x() - window_expansion_top_left_delta_.x(),
509      bounds.y() - window_expansion_top_left_delta_.y(),
510      bounds.width() + window_expansion_bottom_right_delta_.x(),
511      bounds.height() + window_expansion_bottom_right_delta_.y());
512
513  gfx::Rect new_expanded(
514      expanded.origin(),
515      GetExpandedWindowSize(message_handler_->window_ex_style(),
516                            expanded.size()));
517  window_enlargement_ =
518      gfx::Vector2d(new_expanded.width() - expanded.width(),
519                    new_expanded.height() - expanded.height());
520  message_handler_->SetBounds(new_expanded, old_content_size != bounds.size());
521}
522
523gfx::Point DesktopWindowTreeHostWin::GetLocationOnNativeScreen() const {
524  return GetBounds().origin();
525}
526
527void DesktopWindowTreeHostWin::SetCapture() {
528  message_handler_->SetCapture();
529}
530
531void DesktopWindowTreeHostWin::ReleaseCapture() {
532  message_handler_->ReleaseCapture();
533}
534
535void DesktopWindowTreeHostWin::PostNativeEvent(
536    const base::NativeEvent& native_event) {
537}
538
539void DesktopWindowTreeHostWin::SetCursorNative(gfx::NativeCursor cursor) {
540  ui::CursorLoaderWin cursor_loader;
541  cursor_loader.SetPlatformCursor(&cursor);
542
543  message_handler_->SetCursor(cursor.platform());
544}
545
546void DesktopWindowTreeHostWin::OnCursorVisibilityChangedNative(bool show) {
547  if (is_cursor_visible_ == show)
548    return;
549  is_cursor_visible_ = show;
550  ::ShowCursor(!!show);
551}
552
553void DesktopWindowTreeHostWin::MoveCursorToNative(const gfx::Point& location) {
554  POINT cursor_location = location.ToPOINT();
555  ::ClientToScreen(GetHWND(), &cursor_location);
556  ::SetCursorPos(cursor_location.x, cursor_location.y);
557}
558
559////////////////////////////////////////////////////////////////////////////////
560// DesktopWindowTreeHostWin, ui::EventSource implementation:
561
562ui::EventProcessor* DesktopWindowTreeHostWin::GetEventProcessor() {
563  return dispatcher();
564}
565
566////////////////////////////////////////////////////////////////////////////////
567// DesktopWindowTreeHostWin, aura::AnimationHost implementation:
568
569void DesktopWindowTreeHostWin::SetHostTransitionOffsets(
570    const gfx::Vector2d& top_left_delta,
571    const gfx::Vector2d& bottom_right_delta) {
572  gfx::Rect bounds_without_expansion = GetBounds();
573  window_expansion_top_left_delta_ = top_left_delta;
574  window_expansion_bottom_right_delta_ = bottom_right_delta;
575  SetBounds(bounds_without_expansion);
576}
577
578void DesktopWindowTreeHostWin::OnWindowHidingAnimationCompleted() {
579  if (pending_close_)
580    message_handler_->Close();
581}
582
583////////////////////////////////////////////////////////////////////////////////
584// DesktopWindowTreeHostWin, HWNDMessageHandlerDelegate implementation:
585
586bool DesktopWindowTreeHostWin::IsWidgetWindow() const {
587  return has_non_client_view_;
588}
589
590bool DesktopWindowTreeHostWin::IsUsingCustomFrame() const {
591  return !GetWidget()->ShouldUseNativeFrame();
592}
593
594void DesktopWindowTreeHostWin::SchedulePaint() {
595  GetWidget()->GetRootView()->SchedulePaint();
596}
597
598void DesktopWindowTreeHostWin::EnableInactiveRendering() {
599  native_widget_delegate_->EnableInactiveRendering();
600}
601
602bool DesktopWindowTreeHostWin::IsInactiveRenderingDisabled() {
603  return native_widget_delegate_->IsInactiveRenderingDisabled();
604}
605
606bool DesktopWindowTreeHostWin::CanResize() const {
607  return GetWidget()->widget_delegate()->CanResize();
608}
609
610bool DesktopWindowTreeHostWin::CanMaximize() const {
611  return GetWidget()->widget_delegate()->CanMaximize();
612}
613
614bool DesktopWindowTreeHostWin::CanMinimize() const {
615  return GetWidget()->widget_delegate()->CanMinimize();
616}
617
618bool DesktopWindowTreeHostWin::CanActivate() const {
619  if (IsModalWindowActive())
620    return true;
621  return native_widget_delegate_->CanActivate();
622}
623
624bool DesktopWindowTreeHostWin::WidgetSizeIsClientSize() const {
625  const Widget* widget = GetWidget()->GetTopLevelWidget();
626  return IsMaximized() || (widget && widget->ShouldUseNativeFrame());
627}
628
629bool DesktopWindowTreeHostWin::IsModal() const {
630  return native_widget_delegate_->IsModal();
631}
632
633int DesktopWindowTreeHostWin::GetInitialShowState() const {
634  return CanActivate() ? SW_SHOWNORMAL : SW_SHOWNOACTIVATE;
635}
636
637bool DesktopWindowTreeHostWin::WillProcessWorkAreaChange() const {
638  return GetWidget()->widget_delegate()->WillProcessWorkAreaChange();
639}
640
641int DesktopWindowTreeHostWin::GetNonClientComponent(
642    const gfx::Point& point) const {
643  gfx::Point dip_position = gfx::win::ScreenToDIPPoint(point);
644  return native_widget_delegate_->GetNonClientComponent(dip_position);
645}
646
647void DesktopWindowTreeHostWin::GetWindowMask(const gfx::Size& size,
648                                             gfx::Path* path) {
649  if (GetWidget()->non_client_view()) {
650    GetWidget()->non_client_view()->GetWindowMask(size, path);
651  } else if (!window_enlargement_.IsZero()) {
652    gfx::Rect bounds(WidgetSizeIsClientSize()
653                         ? message_handler_->GetClientAreaBoundsInScreen()
654                         : message_handler_->GetWindowBoundsInScreen());
655    InsetBottomRight(&bounds, window_enlargement_);
656    path->addRect(SkRect::MakeXYWH(0, 0, bounds.width(), bounds.height()));
657  }
658}
659
660bool DesktopWindowTreeHostWin::GetClientAreaInsets(gfx::Insets* insets) const {
661  return false;
662}
663
664void DesktopWindowTreeHostWin::GetMinMaxSize(gfx::Size* min_size,
665                                             gfx::Size* max_size) const {
666  *min_size = native_widget_delegate_->GetMinimumSize();
667  *max_size = native_widget_delegate_->GetMaximumSize();
668}
669
670gfx::Size DesktopWindowTreeHostWin::GetRootViewSize() const {
671  return GetWidget()->GetRootView()->size();
672}
673
674void DesktopWindowTreeHostWin::ResetWindowControls() {
675  GetWidget()->non_client_view()->ResetWindowControls();
676}
677
678void DesktopWindowTreeHostWin::PaintLayeredWindow(gfx::Canvas* canvas) {
679  GetWidget()->GetRootView()->Paint(canvas, views::CullSet());
680}
681
682gfx::NativeViewAccessible DesktopWindowTreeHostWin::GetNativeViewAccessible() {
683  return GetWidget()->GetRootView()->GetNativeViewAccessible();
684}
685
686InputMethod* DesktopWindowTreeHostWin::GetInputMethod() {
687  return GetWidget()->GetInputMethodDirect();
688}
689
690bool DesktopWindowTreeHostWin::ShouldHandleSystemCommands() const {
691  return GetWidget()->widget_delegate()->ShouldHandleSystemCommands();
692}
693
694void DesktopWindowTreeHostWin::HandleAppDeactivated() {
695  native_widget_delegate_->EnableInactiveRendering();
696}
697
698void DesktopWindowTreeHostWin::HandleActivationChanged(bool active) {
699  // This can be invoked from HWNDMessageHandler::Init(), at which point we're
700  // not in a good state and need to ignore it.
701  // TODO(beng): Do we need this still now the host owns the dispatcher?
702  if (!dispatcher())
703    return;
704
705  if (active)
706    OnHostActivated();
707  desktop_native_widget_aura_->HandleActivationChanged(active);
708}
709
710bool DesktopWindowTreeHostWin::HandleAppCommand(short command) {
711  // We treat APPCOMMAND ids as an extension of our command namespace, and just
712  // let the delegate figure out what to do...
713  return GetWidget()->widget_delegate() &&
714      GetWidget()->widget_delegate()->ExecuteWindowsCommand(command);
715}
716
717void DesktopWindowTreeHostWin::HandleCancelMode() {
718  dispatcher()->DispatchCancelModeEvent();
719}
720
721void DesktopWindowTreeHostWin::HandleCaptureLost() {
722  OnHostLostWindowCapture();
723}
724
725void DesktopWindowTreeHostWin::HandleClose() {
726  GetWidget()->Close();
727}
728
729bool DesktopWindowTreeHostWin::HandleCommand(int command) {
730  // Windows uses the 4 lower order bits of |notification_code| for type-
731  // specific information so we must exclude this when comparing.
732  static const int sc_mask = 0xFFF0;
733  switch (command & sc_mask) {
734    case SC_RESTORE:
735    case SC_MAXIMIZE:
736      need_synchronous_paint_ = true;
737      break;
738
739    case SC_SIZE:
740      in_sizing_loop_ = true;
741      break;
742
743    default:
744      break;
745  }
746  return GetWidget()->widget_delegate()->ExecuteWindowsCommand(command);
747}
748
749void DesktopWindowTreeHostWin::HandleAccelerator(
750    const ui::Accelerator& accelerator) {
751  GetWidget()->GetFocusManager()->ProcessAccelerator(accelerator);
752}
753
754void DesktopWindowTreeHostWin::HandleCreate() {
755  native_widget_delegate_->OnNativeWidgetCreated(true);
756}
757
758void DesktopWindowTreeHostWin::HandleDestroying() {
759  drag_drop_client_->OnNativeWidgetDestroying(GetHWND());
760  native_widget_delegate_->OnNativeWidgetDestroying();
761
762  // Destroy the compositor before destroying the HWND since shutdown
763  // may try to swap to the window.
764  DestroyCompositor();
765}
766
767void DesktopWindowTreeHostWin::HandleDestroyed() {
768  desktop_native_widget_aura_->OnHostClosed();
769}
770
771bool DesktopWindowTreeHostWin::HandleInitialFocus(
772    ui::WindowShowState show_state) {
773  return GetWidget()->SetInitialFocus(show_state);
774}
775
776void DesktopWindowTreeHostWin::HandleDisplayChange() {
777  GetWidget()->widget_delegate()->OnDisplayChanged();
778}
779
780void DesktopWindowTreeHostWin::HandleBeginWMSizeMove() {
781  if (in_sizing_loop_)
782    need_synchronous_paint_ = true;
783  native_widget_delegate_->OnNativeWidgetBeginUserBoundsChange();
784}
785
786void DesktopWindowTreeHostWin::HandleEndWMSizeMove() {
787  if (in_sizing_loop_) {
788    need_synchronous_paint_ = false;
789    in_sizing_loop_ = false;
790  }
791  native_widget_delegate_->OnNativeWidgetEndUserBoundsChange();
792}
793
794void DesktopWindowTreeHostWin::HandleMove() {
795  native_widget_delegate_->OnNativeWidgetMove();
796  OnHostMoved(GetBounds().origin());
797}
798
799void DesktopWindowTreeHostWin::HandleWorkAreaChanged() {
800  GetWidget()->widget_delegate()->OnWorkAreaChanged();
801}
802
803void DesktopWindowTreeHostWin::HandleVisibilityChanging(bool visible) {
804  native_widget_delegate_->OnNativeWidgetVisibilityChanging(visible);
805}
806
807void DesktopWindowTreeHostWin::HandleVisibilityChanged(bool visible) {
808  native_widget_delegate_->OnNativeWidgetVisibilityChanged(visible);
809}
810
811void DesktopWindowTreeHostWin::HandleClientSizeChanged(
812    const gfx::Size& new_size) {
813  if (dispatcher())
814    OnHostResized(new_size);
815}
816
817void DesktopWindowTreeHostWin::HandleFrameChanged() {
818  SetWindowTransparency();
819  // Replace the frame and layout the contents.
820  GetWidget()->non_client_view()->UpdateFrame();
821}
822
823void DesktopWindowTreeHostWin::HandleNativeFocus(HWND last_focused_window) {
824  // TODO(beng): inform the native_widget_delegate_.
825  InputMethod* input_method = GetInputMethod();
826  if (input_method)
827    input_method->OnFocus();
828}
829
830void DesktopWindowTreeHostWin::HandleNativeBlur(HWND focused_window) {
831  // TODO(beng): inform the native_widget_delegate_.
832  InputMethod* input_method = GetInputMethod();
833  if (input_method)
834    input_method->OnBlur();
835}
836
837bool DesktopWindowTreeHostWin::HandleMouseEvent(const ui::MouseEvent& event) {
838  SendEventToProcessor(const_cast<ui::MouseEvent*>(&event));
839  return event.handled();
840}
841
842bool DesktopWindowTreeHostWin::HandleKeyEvent(const ui::KeyEvent& event) {
843  return false;
844}
845
846bool DesktopWindowTreeHostWin::HandleUntranslatedKeyEvent(
847    const ui::KeyEvent& event) {
848  ui::KeyEvent duplicate_event(event);
849  SendEventToProcessor(&duplicate_event);
850  return duplicate_event.handled();
851}
852
853void DesktopWindowTreeHostWin::HandleTouchEvent(
854    const ui::TouchEvent& event) {
855  // HWNDMessageHandler asynchronously processes touch events. Because of this
856  // it's possible for the aura::WindowEventDispatcher to have been destroyed
857  // by the time we attempt to process them.
858  if (!GetWidget()->GetNativeView())
859    return;
860
861  // Currently we assume the window that has capture gets touch events too.
862  aura::WindowTreeHost* host =
863      aura::WindowTreeHost::GetForAcceleratedWidget(GetCapture());
864  if (host) {
865    DesktopWindowTreeHostWin* target =
866        host->window()->GetProperty(kDesktopWindowTreeHostKey);
867    if (target && target->HasCapture() && target != this) {
868      POINT target_location(event.location().ToPOINT());
869      ClientToScreen(GetHWND(), &target_location);
870      ScreenToClient(target->GetHWND(), &target_location);
871      ui::TouchEvent target_event(event, static_cast<View*>(NULL),
872                                  static_cast<View*>(NULL));
873      target_event.set_location(gfx::Point(target_location));
874      target_event.set_root_location(target_event.location());
875      target->SendEventToProcessor(&target_event);
876      return;
877    }
878  }
879  SendEventToProcessor(const_cast<ui::TouchEvent*>(&event));
880}
881
882bool DesktopWindowTreeHostWin::HandleIMEMessage(UINT message,
883                                                WPARAM w_param,
884                                                LPARAM l_param,
885                                                LRESULT* result) {
886  MSG msg = {};
887  msg.hwnd = GetHWND();
888  msg.message = message;
889  msg.wParam = w_param;
890  msg.lParam = l_param;
891  return desktop_native_widget_aura_->input_method_event_filter()->
892      input_method()->OnUntranslatedIMEMessage(msg, result);
893}
894
895void DesktopWindowTreeHostWin::HandleInputLanguageChange(
896    DWORD character_set,
897    HKL input_language_id) {
898  desktop_native_widget_aura_->input_method_event_filter()->
899      input_method()->OnInputLocaleChanged();
900}
901
902bool DesktopWindowTreeHostWin::HandlePaintAccelerated(
903    const gfx::Rect& invalid_rect) {
904  return native_widget_delegate_->OnNativeWidgetPaintAccelerated(invalid_rect);
905}
906
907void DesktopWindowTreeHostWin::HandlePaint(gfx::Canvas* canvas) {
908  // It appears possible to get WM_PAINT after WM_DESTROY.
909  if (compositor())
910    compositor()->ScheduleRedrawRect(gfx::Rect());
911}
912
913bool DesktopWindowTreeHostWin::HandleTooltipNotify(int w_param,
914                                                   NMHDR* l_param,
915                                                   LRESULT* l_result) {
916  return tooltip_ && tooltip_->HandleNotify(w_param, l_param, l_result);
917}
918
919void DesktopWindowTreeHostWin::HandleMenuLoop(bool in_menu_loop) {
920  if (in_menu_loop) {
921    tooltip_disabler_.reset(
922        new aura::client::ScopedTooltipDisabler(window()));
923  } else {
924    tooltip_disabler_.reset();
925  }
926}
927
928bool DesktopWindowTreeHostWin::PreHandleMSG(UINT message,
929                                            WPARAM w_param,
930                                            LPARAM l_param,
931                                            LRESULT* result) {
932  return false;
933}
934
935void DesktopWindowTreeHostWin::PostHandleMSG(UINT message,
936                                             WPARAM w_param,
937                                             LPARAM l_param) {
938}
939
940bool DesktopWindowTreeHostWin::HandleScrollEvent(
941    const ui::ScrollEvent& event) {
942  SendEventToProcessor(const_cast<ui::ScrollEvent*>(&event));
943  return event.handled();
944}
945
946void DesktopWindowTreeHostWin::HandleWindowSizeChanging() {
947  if (compositor() && need_synchronous_paint_) {
948    compositor()->FinishAllRendering();
949    // If we received the window size changing notification due to a restore or
950    // maximize operation, then we can reset the need_synchronous_paint_ flag
951    // here. For a sizing operation, the flag will be reset at the end of the
952    // operation.
953    if (!in_sizing_loop_)
954      need_synchronous_paint_ = false;
955  }
956}
957
958////////////////////////////////////////////////////////////////////////////////
959// DesktopWindowTreeHostWin, private:
960
961Widget* DesktopWindowTreeHostWin::GetWidget() {
962  return native_widget_delegate_->AsWidget();
963}
964
965const Widget* DesktopWindowTreeHostWin::GetWidget() const {
966  return native_widget_delegate_->AsWidget();
967}
968
969HWND DesktopWindowTreeHostWin::GetHWND() const {
970  return message_handler_->hwnd();
971}
972
973void DesktopWindowTreeHostWin::SetWindowTransparency() {
974  bool transparent = ShouldUseNativeFrame() && !IsFullscreen();
975  compositor()->SetHostHasTransparentBackground(transparent);
976  window()->SetTransparent(transparent);
977  content_window_->SetTransparent(transparent);
978}
979
980bool DesktopWindowTreeHostWin::IsModalWindowActive() const {
981  // This function can get called during window creation which occurs before
982  // dispatcher() has been created.
983  if (!dispatcher())
984    return false;
985
986  aura::Window::Windows::const_iterator index;
987  for (index = window()->children().begin();
988       index != window()->children().end();
989       ++index) {
990    if ((*index)->GetProperty(aura::client::kModalKey) !=
991        ui:: MODAL_TYPE_NONE && (*index)->TargetVisibility())
992      return true;
993  }
994  return false;
995}
996
997////////////////////////////////////////////////////////////////////////////////
998// DesktopWindowTreeHost, public:
999
1000// static
1001DesktopWindowTreeHost* DesktopWindowTreeHost::Create(
1002    internal::NativeWidgetDelegate* native_widget_delegate,
1003    DesktopNativeWidgetAura* desktop_native_widget_aura) {
1004  return new DesktopWindowTreeHostWin(native_widget_delegate,
1005                                      desktop_native_widget_aura);
1006}
1007
1008}  // namespace views
1009