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 "chrome/browser/ui/views/apps/glass_app_window_frame_view_win.h"
6
7#include "extensions/browser/app_window/native_app_window.h"
8#include "ui/base/hit_test.h"
9#include "ui/gfx/win/dpi.h"
10#include "ui/views/widget/widget.h"
11#include "ui/views/widget/widget_delegate.h"
12
13namespace {
14
15const int kResizeAreaCornerSize = 16;
16
17}  // namespace
18
19const char GlassAppWindowFrameViewWin::kViewClassName[] =
20    "ui/views/apps/GlassAppWindowFrameViewWin";
21
22GlassAppWindowFrameViewWin::GlassAppWindowFrameViewWin(
23    extensions::NativeAppWindow* window,
24    views::Widget* widget)
25    : window_(window), widget_(widget) {
26}
27
28GlassAppWindowFrameViewWin::~GlassAppWindowFrameViewWin() {
29}
30
31gfx::Insets GlassAppWindowFrameViewWin::GetGlassInsets() const {
32  // If 1 is not subtracted, they are too big. There is possibly some reason
33  // for that.
34  // Also make sure the insets don't go below 1, as bad things happen when they
35  // do.
36  int caption_height = std::max(0,
37      gfx::win::GetSystemMetricsInDIP(SM_CYSMICON) +
38          gfx::win::GetSystemMetricsInDIP(SM_CYSIZEFRAME) - 1);
39  int frame_size =
40      std::max(1, gfx::win::GetSystemMetricsInDIP(SM_CXSIZEFRAME) - 1);
41  return gfx::Insets(
42      frame_size + caption_height, frame_size, frame_size, frame_size);
43}
44
45gfx::Rect GlassAppWindowFrameViewWin::GetBoundsForClientView() const {
46  if (widget_->IsFullscreen())
47    return bounds();
48
49  gfx::Insets insets = GetGlassInsets();
50  return gfx::Rect(insets.left(),
51                   insets.top(),
52                   std::max(0, width() - insets.left() - insets.right()),
53                   std::max(0, height() - insets.top() - insets.bottom()));
54}
55
56gfx::Rect GlassAppWindowFrameViewWin::GetWindowBoundsForClientBounds(
57    const gfx::Rect& client_bounds) const {
58  gfx::Insets insets = GetGlassInsets();
59  // Our bounds are not the same as the window's due to the offset added by
60  // AppWindowDesktopWindowTreeHostWin::GetClientAreaInsets. So account for it
61  // here.
62  insets += gfx::Insets(0, 0, 1, 1);
63  return gfx::Rect(client_bounds.x() - insets.left(),
64                   client_bounds.y() - insets.top(),
65                   client_bounds.width() + insets.left() + insets.right(),
66                   client_bounds.height() + insets.top() + insets.bottom());
67}
68
69int GlassAppWindowFrameViewWin::NonClientHitTest(const gfx::Point& point) {
70  if (widget_->IsFullscreen())
71    return HTCLIENT;
72
73  if (!bounds().Contains(point))
74    return HTNOWHERE;
75
76  // Check the frame first, as we allow a small area overlapping the contents
77  // to be used for resize handles.
78  bool can_ever_resize = widget_->widget_delegate()
79                             ? widget_->widget_delegate()->CanResize()
80                             : false;
81  // Don't allow overlapping resize handles when the window is maximized or
82  // fullscreen, as it can't be resized in those states.
83  int resize_border = gfx::win::GetSystemMetricsInDIP(SM_CXSIZEFRAME);
84  int frame_component =
85      GetHTComponentForFrame(point,
86                             resize_border,
87                             resize_border,
88                             kResizeAreaCornerSize - resize_border,
89                             kResizeAreaCornerSize - resize_border,
90                             can_ever_resize);
91  if (frame_component != HTNOWHERE)
92    return frame_component;
93
94  int client_component = widget_->client_view()->NonClientHitTest(point);
95  if (client_component != HTNOWHERE)
96    return client_component;
97
98  // Caption is a safe default.
99  return HTCAPTION;
100}
101
102void GlassAppWindowFrameViewWin::GetWindowMask(const gfx::Size& size,
103                                               gfx::Path* window_mask) {
104  // We got nothing to say about no window mask.
105}
106
107gfx::Size GlassAppWindowFrameViewWin::GetPreferredSize() const {
108  gfx::Size pref = widget_->client_view()->GetPreferredSize();
109  gfx::Rect bounds(0, 0, pref.width(), pref.height());
110  return widget_->non_client_view()
111      ->GetWindowBoundsForClientBounds(bounds)
112      .size();
113}
114
115const char* GlassAppWindowFrameViewWin::GetClassName() const {
116  return kViewClassName;
117}
118
119gfx::Size GlassAppWindowFrameViewWin::GetMinimumSize() const {
120  gfx::Size min_size = widget_->client_view()->GetMinimumSize();
121
122  gfx::Rect client_bounds = GetBoundsForClientView();
123  min_size.Enlarge(width() - client_bounds.width(),
124                   height() - client_bounds.height());
125  return min_size;
126}
127
128gfx::Size GlassAppWindowFrameViewWin::GetMaximumSize() const {
129  gfx::Size max_size = widget_->client_view()->GetMaximumSize();
130
131  // Add to the client maximum size the height of any title bar and borders.
132  gfx::Size client_size = GetBoundsForClientView().size();
133  if (max_size.width())
134    max_size.Enlarge(width() - client_size.width(), 0);
135  if (max_size.height())
136    max_size.Enlarge(0, height() - client_size.height());
137
138  return max_size;
139}
140