summaryrefslogtreecommitdiffstats
path: root/ui/views/widget/widget_hwnd_utils.cc
blob: 53588c25e5e62a0deea8dbcfb7975f25fe82eb8c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/views/widget/widget_hwnd_utils.h"

#include <dwmapi.h>

#include "base/command_line.h"
#include "base/win/windows_version.h"
#include "ui/base/l10n/l10n_util_win.h"
#include "ui/base/ui_base_switches.h"
#include "ui/views/widget/widget_delegate.h"
#include "ui/views/win/hwnd_message_handler.h"

#if defined(OS_WIN)
#include "ui/base/win/shell.h"
#endif

namespace views {

namespace {

void CalculateWindowStylesFromInitParams(
    const Widget::InitParams& params,
    WidgetDelegate* widget_delegate,
    internal::NativeWidgetDelegate* native_widget_delegate,
    DWORD* style,
    DWORD* ex_style,
    DWORD* class_style) {
  *style = WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
  *ex_style = 0;
  *class_style = CS_DBLCLKS;

  // Set type-independent style attributes.
  if (params.child)
    *style |= WS_CHILD;
  if (params.show_state == ui::SHOW_STATE_MAXIMIZED)
    *style |= WS_MAXIMIZE;
  if (params.show_state == ui::SHOW_STATE_MINIMIZED)
    *style |= WS_MINIMIZE;
  if (!params.accept_events)
    *ex_style |= WS_EX_TRANSPARENT;
  if (!params.can_activate)
    *ex_style |= WS_EX_NOACTIVATE;
  if (params.keep_on_top)
    *ex_style |= WS_EX_TOPMOST;
  if (params.mirror_origin_in_rtl)
    *ex_style |= l10n_util::GetExtendedTooltipStyles();
  // Layered windows do not work with Aura. They are basically incompatible
  // with Direct3D surfaces. Officially, it should be impossible to achieve
  // per-pixel alpha compositing with the desktop and 3D acceleration but it
  // has been discovered that since Vista There is a secret handshake between
  // user32 and the DMW. If things are set up just right DMW gets out of the
  // way; it does not create a backbuffer and simply blends our D3D surface
  // and the desktop background. The handshake is as follows:
  // 1- Use D3D9Ex to create device/swapchain, etc. You need D3DFMT_A8R8G8B8.
  // 2- The window must have WS_EX_COMPOSITED in the extended style.
  // 3- The window must have WS_POPUP in its style.
  // 4- The windows must not have WM_SIZEBOX, WS_THICKFRAME or WS_CAPTION in its
  //    style.
  // 5- When the window is created but before it is presented, call
  //    DwmExtendFrameIntoClientArea passing -1 as the margins.
  if (params.opacity == Widget::InitParams::TRANSLUCENT_WINDOW) {
#if defined(USE_AURA)
    if (ui::win::IsAeroGlassEnabled())
      *ex_style |= WS_EX_COMPOSITED;
#else
    *ex_style |= WS_EX_LAYERED;
#endif
  }
  if (params.has_dropshadow) {
    *class_style |= (base::win::GetVersion() < base::win::VERSION_XP) ?
        0 : CS_DROPSHADOW;
  }

  // Set type-dependent style attributes.
  switch (params.type) {
    case Widget::InitParams::TYPE_PANEL:
      *ex_style |= WS_EX_TOPMOST;
      if (params.remove_standard_frame) {
        *style |= WS_POPUP;
        break;
      }
      // Else, no break. Fall through to TYPE_WINDOW.
    case Widget::InitParams::TYPE_WINDOW: {
      *style |= WS_SYSMENU | WS_CAPTION;
      bool can_resize = widget_delegate->CanResize();
      bool can_maximize = widget_delegate->CanMaximize();
      if (can_maximize) {
        *style |= WS_OVERLAPPEDWINDOW;
      } else if (can_resize || params.remove_standard_frame) {
        *style |= WS_OVERLAPPED | WS_THICKFRAME;
      }
      if (native_widget_delegate->IsDialogBox()) {
        *style |= DS_MODALFRAME;
        // NOTE: Turning this off means we lose the close button, which is bad.
        // Turning it on though means the user can maximize or size the window
        // from the system menu, which is worse. We may need to provide our own
        // menu to get the close button to appear properly.
        // style &= ~WS_SYSMENU;

        // Set the WS_POPUP style for modal dialogs. This ensures that the owner
        // window is activated on destruction. This style should not be set for
        // non-modal non-top-level dialogs like constrained windows.
        *style |= native_widget_delegate->IsModal() ? WS_POPUP : 0;
      }
      *ex_style |=
          native_widget_delegate->IsDialogBox() ? WS_EX_DLGMODALFRAME : 0;

      // See layered window comment above.
      if (*ex_style & WS_EX_COMPOSITED)
        *style &= ~(WS_THICKFRAME | WS_CAPTION);
      break;
    }
    case Widget::InitParams::TYPE_CONTROL:
      *style |= WS_VISIBLE;
      break;
    case Widget::InitParams::TYPE_WINDOW_FRAMELESS:
      *style |= WS_POPUP;
      break;
    case Widget::InitParams::TYPE_BUBBLE:
      *style |= WS_POPUP;
      *style |= WS_CLIPCHILDREN;
      break;
    case Widget::InitParams::TYPE_POPUP:
      *style |= WS_POPUP;
      *ex_style |= WS_EX_TOOLWINDOW;
      break;
    case Widget::InitParams::TYPE_MENU:
      *style |= WS_POPUP;
      break;
    default:
      NOTREACHED();
  }
}

}  // namespace

bool DidClientAreaSizeChange(const WINDOWPOS* window_pos) {
  return !(window_pos->flags & SWP_NOSIZE) ||
         window_pos->flags & SWP_FRAMECHANGED;
}

void ConfigureWindowStyles(
    HWNDMessageHandler* handler,
    const Widget::InitParams& params,
    WidgetDelegate* widget_delegate,
    internal::NativeWidgetDelegate* native_widget_delegate) {
  // Configure the HWNDMessageHandler with the appropriate
  DWORD style = 0;
  DWORD ex_style = 0;
  DWORD class_style = 0;
  CalculateWindowStylesFromInitParams(params, widget_delegate,
                                      native_widget_delegate, &style, &ex_style,
                                      &class_style);
  handler->set_initial_class_style(class_style);
  handler->set_window_style(handler->window_style() | style);
  handler->set_window_ex_style(handler->window_ex_style() | ex_style);
}

}  // namespace views