Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(409)

Side by Side Diff: ui/views/widget/native_widget_win.cc

Issue 8547015: Revert 110949 - views: Move widget/ directory to ui/views. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 9 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « ui/views/widget/native_widget_win.h ('k') | ui/views/widget/native_widget_win_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2011 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/native_widget_win.h"
6
7 #include <dwmapi.h>
8 #include <shellapi.h>
9
10 #include <algorithm>
11
12 #include "base/bind.h"
13 #include "base/string_util.h"
14 #include "base/system_monitor/system_monitor.h"
15 #include "base/win/scoped_gdi_object.h"
16 #include "base/win/win_util.h"
17 #include "base/win/windows_version.h"
18 #include "ui/base/dragdrop/drag_drop_types.h"
19 #include "ui/base/dragdrop/drag_source.h"
20 #include "ui/base/dragdrop/os_exchange_data.h"
21 #include "ui/base/dragdrop/os_exchange_data_provider_win.h"
22 #include "ui/base/keycodes/keyboard_code_conversion_win.h"
23 #include "ui/base/l10n/l10n_util_win.h"
24 #include "ui/base/theme_provider.h"
25 #include "ui/base/view_prop.h"
26 #include "ui/base/win/hwnd_util.h"
27 #include "ui/base/win/mouse_wheel_util.h"
28 #include "ui/gfx/canvas_skia.h"
29 #include "ui/gfx/canvas_skia_paint.h"
30 #include "ui/gfx/compositor/compositor.h"
31 #include "ui/gfx/icon_util.h"
32 #include "ui/gfx/native_theme_win.h"
33 #include "ui/gfx/path.h"
34 #include "ui/gfx/screen.h"
35 #include "ui/views/accessibility/native_view_accessibility_win.h"
36 #include "ui/views/focus/accelerator_handler.h"
37 #include "ui/views/focus/view_storage.h"
38 #include "ui/views/ime/input_method_win.h"
39 #include "ui/views/widget/aero_tooltip_manager.h"
40 #include "ui/views/widget/aero_tooltip_manager.h"
41 #include "ui/views/widget/child_window_message_processor.h"
42 #include "ui/views/widget/child_window_message_processor.h"
43 #include "ui/views/widget/drop_target_win.h"
44 #include "ui/views/widget/drop_target_win.h"
45 #include "ui/views/widget/monitor_win.h"
46 #include "ui/views/widget/monitor_win.h"
47 #include "ui/views/widget/native_widget_delegate.h"
48 #include "ui/views/widget/native_widget_delegate.h"
49 #include "ui/views/widget/root_view.h"
50 #include "ui/views/widget/root_view.h"
51 #include "ui/views/widget/widget_delegate.h"
52 #include "ui/views/widget/widget_delegate.h"
53 #include "ui/views/window/native_frame_view.h"
54 #include "views/controls/native_control_win.h"
55 #include "views/controls/textfield/native_textfield_views.h"
56 #include "views/views_delegate.h"
57
58 #pragma comment(lib, "dwmapi.lib")
59
60 using ui::ViewProp;
61
62 namespace views {
63
64 namespace {
65
66 // Get the source HWND of the specified message. Depending on the message, the
67 // source HWND is encoded in either the WPARAM or the LPARAM value.
68 HWND GetControlHWNDForMessage(UINT message, WPARAM w_param, LPARAM l_param) {
69 // Each of the following messages can be sent by a child HWND and must be
70 // forwarded to its associated NativeControlWin for handling.
71 switch (message) {
72 case WM_NOTIFY:
73 return reinterpret_cast<NMHDR*>(l_param)->hwndFrom;
74 case WM_COMMAND:
75 return reinterpret_cast<HWND>(l_param);
76 case WM_CONTEXTMENU:
77 return reinterpret_cast<HWND>(w_param);
78 case WM_CTLCOLORBTN:
79 case WM_CTLCOLORSTATIC:
80 return reinterpret_cast<HWND>(l_param);
81 }
82 return NULL;
83 }
84
85 // Some messages may be sent to us by a child HWND. If this is the case, this
86 // function will forward those messages on to the object associated with the
87 // source HWND and return true, in which case the window procedure must not do
88 // any further processing of the message. If there is no associated
89 // ChildWindowMessageProcessor, the return value will be false and the WndProc
90 // can continue processing the message normally. |l_result| contains the result
91 // of the message processing by the control and must be returned by the WndProc
92 // if the return value is true.
93 bool ProcessChildWindowMessage(UINT message,
94 WPARAM w_param,
95 LPARAM l_param,
96 LRESULT* l_result) {
97 *l_result = 0;
98
99 HWND control_hwnd = GetControlHWNDForMessage(message, w_param, l_param);
100 if (IsWindow(control_hwnd)) {
101 ChildWindowMessageProcessor* processor =
102 ChildWindowMessageProcessor::Get(control_hwnd);
103 if (processor)
104 return processor->ProcessMessage(message, w_param, l_param, l_result);
105 }
106
107 return false;
108 }
109
110 // Enumeration callback for NativeWidget::GetAllChildWidgets(). Called for each
111 // child HWND beneath the original HWND.
112 BOOL CALLBACK EnumerateChildWindowsForNativeWidgets(HWND hwnd, LPARAM l_param) {
113 Widget* widget = Widget::GetWidgetForNativeView(hwnd);
114 if (widget) {
115 Widget::Widgets* widgets = reinterpret_cast<Widget::Widgets*>(l_param);
116 widgets->insert(widget);
117 }
118 return TRUE;
119 }
120
121 // Returns true if the WINDOWPOS data provided indicates the client area of
122 // the window may have changed size. This can be caused by the window being
123 // resized or its frame changing.
124 bool DidClientAreaSizeChange(const WINDOWPOS* window_pos) {
125 return !(window_pos->flags & SWP_NOSIZE) ||
126 window_pos->flags & SWP_FRAMECHANGED;
127 }
128
129 // Callback used to notify child windows that the top level window received a
130 // DWMCompositionChanged message.
131 BOOL CALLBACK SendDwmCompositionChanged(HWND window, LPARAM param) {
132 SendMessage(window, WM_DWMCOMPOSITIONCHANGED, 0, 0);
133 return TRUE;
134 }
135
136 // Tells the window its frame (non-client area) has changed.
137 void SendFrameChanged(HWND window) {
138 SetWindowPos(window, NULL, 0, 0, 0, 0,
139 SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOCOPYBITS |
140 SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOREPOSITION |
141 SWP_NOSENDCHANGING | SWP_NOSIZE | SWP_NOZORDER);
142 }
143
144 // Enables or disables the menu item for the specified command and menu.
145 void EnableMenuItem(HMENU menu, UINT command, bool enabled) {
146 UINT flags = MF_BYCOMMAND | (enabled ? MF_ENABLED : MF_DISABLED | MF_GRAYED);
147 EnableMenuItem(menu, command, flags);
148 }
149
150 BOOL CALLBACK EnumChildWindowsForRedraw(HWND hwnd, LPARAM lparam) {
151 DWORD process_id;
152 GetWindowThreadProcessId(hwnd, &process_id);
153 int flags = RDW_INVALIDATE | RDW_NOCHILDREN | RDW_FRAME;
154 if (process_id == GetCurrentProcessId())
155 flags |= RDW_UPDATENOW;
156 RedrawWindow(hwnd, NULL, NULL, flags);
157 return TRUE;
158 }
159
160 // See comments in OnNCPaint() for details of this struct.
161 struct ClipState {
162 // The window being painted.
163 HWND parent;
164
165 // DC painting to.
166 HDC dc;
167
168 // Origin of the window in terms of the screen.
169 int x;
170 int y;
171 };
172
173 // See comments in OnNCPaint() for details of this function.
174 static BOOL CALLBACK ClipDCToChild(HWND window, LPARAM param) {
175 ClipState* clip_state = reinterpret_cast<ClipState*>(param);
176 if (GetParent(window) == clip_state->parent && IsWindowVisible(window)) {
177 RECT bounds;
178 GetWindowRect(window, &bounds);
179 ExcludeClipRect(clip_state->dc,
180 bounds.left - clip_state->x,
181 bounds.top - clip_state->y,
182 bounds.right - clip_state->x,
183 bounds.bottom - clip_state->y);
184 }
185 return TRUE;
186 }
187
188 // The thickness of an auto-hide taskbar in pixels.
189 static const int kAutoHideTaskbarThicknessPx = 2;
190
191 bool GetMonitorAndRects(const RECT& rect,
192 HMONITOR* monitor,
193 gfx::Rect* monitor_rect,
194 gfx::Rect* work_area) {
195 DCHECK(monitor);
196 DCHECK(monitor_rect);
197 DCHECK(work_area);
198 *monitor = MonitorFromRect(&rect, MONITOR_DEFAULTTONULL);
199 if (!*monitor)
200 return false;
201 MONITORINFO monitor_info = { 0 };
202 monitor_info.cbSize = sizeof(monitor_info);
203 GetMonitorInfo(*monitor, &monitor_info);
204 *monitor_rect = monitor_info.rcMonitor;
205 *work_area = monitor_info.rcWork;
206 return true;
207 }
208
209 // Links the HWND to its NativeWidget.
210 const char* const kNativeWidgetKey = "__VIEWS_NATIVE_WIDGET__";
211
212 // A custom MSAA object id used to determine if a screen reader is actively
213 // listening for MSAA events.
214 const int kCustomObjectID = 1;
215
216 const int kDragFrameWindowAlpha = 200;
217
218 } // namespace
219
220 // static
221 bool NativeWidgetWin::screen_reader_active_ = false;
222
223 // A scoping class that prevents a window from being able to redraw in response
224 // to invalidations that may occur within it for the lifetime of the object.
225 //
226 // Why would we want such a thing? Well, it turns out Windows has some
227 // "unorthodox" behavior when it comes to painting its non-client areas.
228 // Occasionally, Windows will paint portions of the default non-client area
229 // right over the top of the custom frame. This is not simply fixed by handling
230 // WM_NCPAINT/WM_PAINT, with some investigation it turns out that this
231 // rendering is being done *inside* the default implementation of some message
232 // handlers and functions:
233 // . WM_SETTEXT
234 // . WM_SETICON
235 // . WM_NCLBUTTONDOWN
236 // . EnableMenuItem, called from our WM_INITMENU handler
237 // The solution is to handle these messages and call DefWindowProc ourselves,
238 // but prevent the window from being able to update itself for the duration of
239 // the call. We do this with this class, which automatically calls its
240 // associated Window's lock and unlock functions as it is created and destroyed.
241 // See documentation in those methods for the technique used.
242 //
243 // The lock only has an effect if the window was visible upon lock creation, as
244 // it doesn't guard against direct visiblility changes, and multiple locks may
245 // exist simultaneously to handle certain nested Windows messages.
246 //
247 // IMPORTANT: Do not use this scoping object for large scopes or periods of
248 // time! IT WILL PREVENT THE WINDOW FROM BEING REDRAWN! (duh).
249 //
250 // I would love to hear Raymond Chen's explanation for all this. And maybe a
251 // list of other messages that this applies to ;-)
252 class NativeWidgetWin::ScopedRedrawLock {
253 public:
254 explicit ScopedRedrawLock(NativeWidgetWin* widget)
255 : widget_(widget),
256 native_view_(widget_->GetNativeView()),
257 was_visible_(widget_->IsVisible()),
258 cancel_unlock_(false) {
259 if (was_visible_ && ::IsWindow(native_view_))
260 widget_->LockUpdates();
261 }
262
263 ~ScopedRedrawLock() {
264 if (!cancel_unlock_ && was_visible_ && ::IsWindow(native_view_))
265 widget_->UnlockUpdates();
266 }
267
268 // Cancel the unlock operation, call this if the Widget is being destroyed.
269 void CancelUnlockOperation() { cancel_unlock_ = true; }
270
271 private:
272 // The widget having its style changed.
273 NativeWidgetWin* widget_;
274 // The widget's native view, cached to avoid action after window destruction.
275 gfx::NativeView native_view_;
276 // Records the widget visibility at the time of creation.
277 bool was_visible_;
278 // A flag indicating that the unlock operation was canceled.
279 bool cancel_unlock_;
280 };
281
282 ////////////////////////////////////////////////////////////////////////////////
283 // NativeWidgetWin, public:
284
285 NativeWidgetWin::NativeWidgetWin(internal::NativeWidgetDelegate* delegate)
286 : delegate_(delegate),
287 ALLOW_THIS_IN_INITIALIZER_LIST(close_widget_factory_(this)),
288 active_mouse_tracking_flags_(0),
289 use_layered_buffer_(false),
290 layered_alpha_(255),
291 ALLOW_THIS_IN_INITIALIZER_LIST(paint_layered_window_factory_(this)),
292 ownership_(Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET),
293 can_update_layered_window_(true),
294 restore_focus_when_enabled_(false),
295 accessibility_view_events_index_(-1),
296 accessibility_view_events_(kMaxAccessibilityViewEvents),
297 previous_cursor_(NULL),
298 fullscreen_(false),
299 force_hidden_count_(0),
300 lock_updates_count_(0),
301 saved_window_style_(0),
302 ignore_window_pos_changes_(false),
303 ALLOW_THIS_IN_INITIALIZER_LIST(ignore_pos_changes_factory_(this)),
304 last_monitor_(NULL),
305 is_right_mouse_pressed_on_caption_(false),
306 restored_enabled_(false),
307 destroyed_(NULL),
308 has_non_client_view_(false) {
309 }
310
311 NativeWidgetWin::~NativeWidgetWin() {
312 if (destroyed_ != NULL)
313 *destroyed_ = true;
314
315 if (ownership_ == Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET)
316 delete delegate_;
317 else
318 CloseNow();
319 }
320
321 // static
322 bool NativeWidgetWin::IsAeroGlassEnabled() {
323 if (base::win::GetVersion() < base::win::VERSION_VISTA)
324 return false;
325 // If composition is not enabled, we behave like on XP.
326 BOOL enabled = FALSE;
327 return SUCCEEDED(DwmIsCompositionEnabled(&enabled)) && enabled;
328 }
329
330 // static
331 gfx::Font NativeWidgetWin::GetWindowTitleFont() {
332 NONCLIENTMETRICS ncm;
333 base::win::GetNonClientMetrics(&ncm);
334 l10n_util::AdjustUIFont(&(ncm.lfCaptionFont));
335 base::win::ScopedHFONT caption_font(CreateFontIndirect(&(ncm.lfCaptionFont)));
336 return gfx::Font(caption_font);
337 }
338
339 void NativeWidgetWin::Show(int show_state) {
340 ShowWindow(show_state);
341 // When launched from certain programs like bash and Windows Live Messenger,
342 // show_state is set to SW_HIDE, so we need to correct that condition. We
343 // don't just change show_state to SW_SHOWNORMAL because MSDN says we must
344 // always first call ShowWindow with the specified value from STARTUPINFO,
345 // otherwise all future ShowWindow calls will be ignored (!!#@@#!). Instead,
346 // we call ShowWindow again in this case.
347 if (show_state == SW_HIDE) {
348 show_state = SW_SHOWNORMAL;
349 ShowWindow(show_state);
350 }
351
352 // We need to explicitly activate the window if we've been shown with a state
353 // that should activate, because if we're opened from a desktop shortcut while
354 // an existing window is already running it doesn't seem to be enough to use
355 // one of these flags to activate the window.
356 if (show_state == SW_SHOWNORMAL || show_state == SW_SHOWMAXIMIZED)
357 Activate();
358
359 SetInitialFocus();
360 }
361
362 View* NativeWidgetWin::GetAccessibilityViewEventAt(int id) {
363 // Convert from MSAA child id.
364 id = -(id + 1);
365 DCHECK(id >= 0 && id < kMaxAccessibilityViewEvents);
366 return accessibility_view_events_[id];
367 }
368
369 int NativeWidgetWin::AddAccessibilityViewEvent(View* view) {
370 accessibility_view_events_index_ =
371 (accessibility_view_events_index_ + 1) % kMaxAccessibilityViewEvents;
372 accessibility_view_events_[accessibility_view_events_index_] = view;
373
374 // Convert to MSAA child id.
375 return -(accessibility_view_events_index_ + 1);
376 }
377
378 void NativeWidgetWin::ClearAccessibilityViewEvent(View* view) {
379 for (std::vector<View*>::iterator it = accessibility_view_events_.begin();
380 it != accessibility_view_events_.end();
381 ++it) {
382 if (*it == view)
383 *it = NULL;
384 }
385 }
386
387 void NativeWidgetWin::PushForceHidden() {
388 if (force_hidden_count_++ == 0)
389 Hide();
390 }
391
392 void NativeWidgetWin::PopForceHidden() {
393 if (--force_hidden_count_ <= 0) {
394 force_hidden_count_ = 0;
395 ShowWindow(SW_SHOW);
396 }
397 }
398
399 ////////////////////////////////////////////////////////////////////////////////
400 // NativeWidgetWin, CompositorDelegate implementation:
401
402 void NativeWidgetWin::ScheduleDraw() {
403 RECT rect;
404 ::GetClientRect(GetNativeView(), &rect);
405 InvalidateRect(GetNativeView(), &rect, FALSE);
406 }
407
408 ////////////////////////////////////////////////////////////////////////////////
409 // NativeWidgetWin, NativeWidget implementation:
410
411 void NativeWidgetWin::InitNativeWidget(const Widget::InitParams& params) {
412 SetInitParams(params);
413
414 GetMonitorAndRects(params.bounds.ToRECT(), &last_monitor_,
415 &last_monitor_rect_, &last_work_area_);
416
417 // Create the window.
418 WindowImpl::Init(params.GetParent(), params.bounds);
419 }
420
421 NonClientFrameView* NativeWidgetWin::CreateNonClientFrameView() {
422 return GetWidget()->ShouldUseNativeFrame() ?
423 new NativeFrameView(GetWidget()) : NULL;
424 }
425
426 void NativeWidgetWin::UpdateFrameAfterFrameChange() {
427 // We've either gained or lost a custom window region, so reset it now.
428 ResetWindowRegion(true);
429 }
430
431 bool NativeWidgetWin::ShouldUseNativeFrame() const {
432 return IsAeroGlassEnabled();
433 }
434
435 void NativeWidgetWin::FrameTypeChanged() {
436 // Called when the frame type could possibly be changing (theme change or
437 // DWM composition change).
438 if (base::win::GetVersion() >= base::win::VERSION_VISTA) {
439 // We need to toggle the rendering policy of the DWM/glass frame as we
440 // change from opaque to glass. "Non client rendering enabled" means that
441 // the DWM's glass non-client rendering is enabled, which is why
442 // DWMNCRP_ENABLED is used for the native frame case. _DISABLED means the
443 // DWM doesn't render glass, and so is used in the custom frame case.
444 DWMNCRENDERINGPOLICY policy = GetWidget()->ShouldUseNativeFrame() ?
445 DWMNCRP_ENABLED : DWMNCRP_DISABLED;
446 DwmSetWindowAttribute(GetNativeView(), DWMWA_NCRENDERING_POLICY,
447 &policy, sizeof(DWMNCRENDERINGPOLICY));
448 }
449
450 // Send a frame change notification, since the non-client metrics have
451 // changed.
452 SendFrameChanged(GetNativeView());
453
454 // Update the non-client view with the correct frame view for the active frame
455 // type.
456 GetWidget()->non_client_view()->UpdateFrame();
457
458 // WM_DWMCOMPOSITIONCHANGED is only sent to top level windows, however we want
459 // to notify our children too, since we can have MDI child windows who need to
460 // update their appearance.
461 EnumChildWindows(GetNativeView(), &SendDwmCompositionChanged, NULL);
462 }
463
464 Widget* NativeWidgetWin::GetWidget() {
465 return delegate_->AsWidget();
466 }
467
468 const Widget* NativeWidgetWin::GetWidget() const {
469 return delegate_->AsWidget();
470 }
471
472 gfx::NativeView NativeWidgetWin::GetNativeView() const {
473 return WindowImpl::hwnd();
474 }
475
476 gfx::NativeWindow NativeWidgetWin::GetNativeWindow() const {
477 return WindowImpl::hwnd();
478 }
479
480 Widget* NativeWidgetWin::GetTopLevelWidget() {
481 NativeWidgetPrivate* native_widget = GetTopLevelNativeWidget(GetNativeView());
482 return native_widget ? native_widget->GetWidget() : NULL;
483 }
484
485 const ui::Compositor* NativeWidgetWin::GetCompositor() const {
486 return compositor_.get();
487 }
488
489 ui::Compositor* NativeWidgetWin::GetCompositor() {
490 return compositor_.get();
491 }
492
493 void NativeWidgetWin::CalculateOffsetToAncestorWithLayer(
494 gfx::Point* offset,
495 ui::Layer** layer_parent) {
496 }
497
498 void NativeWidgetWin::ReorderLayers() {
499 }
500
501 void NativeWidgetWin::ViewRemoved(View* view) {
502 if (drop_target_.get())
503 drop_target_->ResetTargetViewIfEquals(view);
504
505 ClearAccessibilityViewEvent(view);
506 }
507
508 void NativeWidgetWin::SetNativeWindowProperty(const char* name, void* value) {
509 // Remove the existing property (if any).
510 for (ViewProps::iterator i = props_.begin(); i != props_.end(); ++i) {
511 if ((*i)->Key() == name) {
512 props_.erase(i);
513 break;
514 }
515 }
516
517 if (value)
518 props_.push_back(new ViewProp(hwnd(), name, value));
519 }
520
521 void* NativeWidgetWin::GetNativeWindowProperty(const char* name) const {
522 return ViewProp::GetValue(hwnd(), name);
523 }
524
525 TooltipManager* NativeWidgetWin::GetTooltipManager() const {
526 return tooltip_manager_.get();
527 }
528
529 bool NativeWidgetWin::IsScreenReaderActive() const {
530 return screen_reader_active_;
531 }
532
533 void NativeWidgetWin::SendNativeAccessibilityEvent(
534 View* view,
535 ui::AccessibilityTypes::Event event_type) {
536 // Now call the Windows-specific method to notify MSAA clients of this
537 // event. The widget gives us a temporary unique child ID to associate
538 // with this view so that clients can call get_accChild in
539 // NativeViewAccessibilityWin to retrieve the IAccessible associated
540 // with this view.
541 int child_id = AddAccessibilityViewEvent(view);
542 ::NotifyWinEvent(NativeViewAccessibilityWin::MSAAEvent(event_type),
543 GetNativeView(), OBJID_CLIENT, child_id);
544 }
545
546 void NativeWidgetWin::SetMouseCapture() {
547 DCHECK(!HasMouseCapture());
548 SetCapture(hwnd());
549 }
550
551 void NativeWidgetWin::ReleaseMouseCapture() {
552 ReleaseCapture();
553 }
554
555 bool NativeWidgetWin::HasMouseCapture() const {
556 return GetCapture() == hwnd();
557 }
558
559 InputMethod* NativeWidgetWin::CreateInputMethod() {
560 if (views::Widget::IsPureViews()) {
561 InputMethod* input_method = new InputMethodWin(this);
562 input_method->Init(GetWidget());
563 return input_method;
564 }
565 return NULL;
566 }
567
568 void NativeWidgetWin::CenterWindow(const gfx::Size& size) {
569 HWND parent = GetParent();
570 if (!IsWindow())
571 parent = ::GetWindow(GetNativeView(), GW_OWNER);
572 ui::CenterAndSizeWindow(parent, GetNativeView(), size, false);
573 }
574
575 void NativeWidgetWin::GetWindowPlacement(
576 gfx::Rect* bounds,
577 ui::WindowShowState* show_state) const {
578 WINDOWPLACEMENT wp;
579 wp.length = sizeof(wp);
580 const bool succeeded = !!::GetWindowPlacement(GetNativeView(), &wp);
581 DCHECK(succeeded);
582
583 if (bounds != NULL) {
584 MONITORINFO mi;
585 mi.cbSize = sizeof(mi);
586 const bool succeeded = !!GetMonitorInfo(
587 MonitorFromWindow(GetNativeView(), MONITOR_DEFAULTTONEAREST), &mi);
588 DCHECK(succeeded);
589 *bounds = gfx::Rect(wp.rcNormalPosition);
590 // Convert normal position from workarea coordinates to screen coordinates.
591 bounds->Offset(mi.rcWork.left - mi.rcMonitor.left,
592 mi.rcWork.top - mi.rcMonitor.top);
593 }
594
595 if (show_state != NULL) {
596 if (wp.showCmd == SW_SHOWMAXIMIZED)
597 *show_state = ui::SHOW_STATE_MAXIMIZED;
598 else if (wp.showCmd == SW_SHOWMINIMIZED)
599 *show_state = ui::SHOW_STATE_MINIMIZED;
600 else
601 *show_state = ui::SHOW_STATE_NORMAL;
602 }
603 }
604
605 void NativeWidgetWin::SetWindowTitle(const string16& title) {
606 SetWindowText(GetNativeView(), title.c_str());
607 SetAccessibleName(title);
608 }
609
610 void NativeWidgetWin::SetWindowIcons(const SkBitmap& window_icon,
611 const SkBitmap& app_icon) {
612 if (!window_icon.isNull()) {
613 HICON windows_icon = IconUtil::CreateHICONFromSkBitmap(window_icon);
614 // We need to make sure to destroy the previous icon, otherwise we'll leak
615 // these GDI objects until we crash!
616 HICON old_icon = reinterpret_cast<HICON>(
617 SendMessage(GetNativeView(), WM_SETICON, ICON_SMALL,
618 reinterpret_cast<LPARAM>(windows_icon)));
619 if (old_icon)
620 DestroyIcon(old_icon);
621 }
622 if (!app_icon.isNull()) {
623 HICON windows_icon = IconUtil::CreateHICONFromSkBitmap(app_icon);
624 HICON old_icon = reinterpret_cast<HICON>(
625 SendMessage(GetNativeView(), WM_SETICON, ICON_BIG,
626 reinterpret_cast<LPARAM>(windows_icon)));
627 if (old_icon)
628 DestroyIcon(old_icon);
629 }
630 }
631
632 void NativeWidgetWin::SetAccessibleName(const string16& name) {
633 base::win::ScopedComPtr<IAccPropServices> pAccPropServices;
634 HRESULT hr = CoCreateInstance(CLSID_AccPropServices, NULL, CLSCTX_SERVER,
635 IID_IAccPropServices, reinterpret_cast<void**>(&pAccPropServices));
636 if (SUCCEEDED(hr))
637 hr = pAccPropServices->SetHwndPropStr(GetNativeView(), OBJID_CLIENT,
638 CHILDID_SELF, PROPID_ACC_NAME,
639 name.c_str());
640 }
641
642 void NativeWidgetWin::SetAccessibleRole(ui::AccessibilityTypes::Role role) {
643 base::win::ScopedComPtr<IAccPropServices> pAccPropServices;
644 HRESULT hr = CoCreateInstance(CLSID_AccPropServices, NULL, CLSCTX_SERVER,
645 IID_IAccPropServices, reinterpret_cast<void**>(&pAccPropServices));
646 if (SUCCEEDED(hr)) {
647 VARIANT var;
648 if (role) {
649 var.vt = VT_I4;
650 var.lVal = NativeViewAccessibilityWin::MSAARole(role);
651 hr = pAccPropServices->SetHwndProp(GetNativeView(), OBJID_CLIENT,
652 CHILDID_SELF, PROPID_ACC_ROLE, var);
653 }
654 }
655 }
656
657 void NativeWidgetWin::SetAccessibleState(ui::AccessibilityTypes::State state) {
658 base::win::ScopedComPtr<IAccPropServices> pAccPropServices;
659 HRESULT hr = CoCreateInstance(CLSID_AccPropServices, NULL, CLSCTX_SERVER,
660 IID_IAccPropServices, reinterpret_cast<void**>(&pAccPropServices));
661 if (SUCCEEDED(hr)) {
662 VARIANT var;
663 if (state) {
664 var.vt = VT_I4;
665 var.lVal = NativeViewAccessibilityWin::MSAAState(state);
666 hr = pAccPropServices->SetHwndProp(GetNativeView(), OBJID_CLIENT,
667 CHILDID_SELF, PROPID_ACC_STATE, var);
668 }
669 }
670 }
671
672 void NativeWidgetWin::BecomeModal() {
673 // We implement modality by crawling up the hierarchy of windows starting
674 // at the owner, disabling all of them so that they don't receive input
675 // messages.
676 HWND start = ::GetWindow(GetNativeView(), GW_OWNER);
677 while (start) {
678 ::EnableWindow(start, FALSE);
679 start = ::GetParent(start);
680 }
681 }
682
683 gfx::Rect NativeWidgetWin::GetWindowScreenBounds() const {
684 RECT r;
685 GetWindowRect(&r);
686 return gfx::Rect(r);
687 }
688
689 gfx::Rect NativeWidgetWin::GetClientAreaScreenBounds() const {
690 RECT r;
691 GetClientRect(&r);
692 POINT point = { r.left, r.top };
693 ClientToScreen(hwnd(), &point);
694 return gfx::Rect(point.x, point.y, r.right - r.left, r.bottom - r.top);
695 }
696
697 gfx::Rect NativeWidgetWin::GetRestoredBounds() const {
698 // If we're in fullscreen mode, we've changed the normal bounds to the monitor
699 // rect, so return the saved bounds instead.
700 if (IsFullscreen())
701 return gfx::Rect(saved_window_info_.window_rect);
702
703 gfx::Rect bounds;
704 GetWindowPlacement(&bounds, NULL);
705 return bounds;
706 }
707
708 void NativeWidgetWin::SetBounds(const gfx::Rect& bounds) {
709 LONG style = GetWindowLong(GWL_STYLE);
710 if (style & WS_MAXIMIZE)
711 SetWindowLong(GWL_STYLE, style & ~WS_MAXIMIZE);
712 SetWindowPos(NULL, bounds.x(), bounds.y(), bounds.width(), bounds.height(),
713 SWP_NOACTIVATE | SWP_NOZORDER);
714 }
715
716 void NativeWidgetWin::SetSize(const gfx::Size& size) {
717 SetWindowPos(NULL, 0, 0, size.width(), size.height(),
718 SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE);
719 }
720
721 void NativeWidgetWin::MoveAbove(gfx::NativeView native_view) {
722 SetWindowPos(native_view, 0, 0, 0, 0,
723 SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
724 }
725
726 void NativeWidgetWin::MoveToTop() {
727 NOTIMPLEMENTED();
728 }
729
730 void NativeWidgetWin::SetShape(gfx::NativeRegion region) {
731 SetWindowRgn(region, TRUE);
732 }
733
734 void NativeWidgetWin::Close() {
735 if (!IsWindow())
736 return; // No need to do anything.
737
738 // Let's hide ourselves right away.
739 Hide();
740
741 // Modal dialog windows disable their owner windows; re-enable them now so
742 // they can activate as foreground windows upon this window's destruction.
743 RestoreEnabledIfNecessary();
744
745 if (!close_widget_factory_.HasWeakPtrs()) {
746 // And we delay the close so that if we are called from an ATL callback,
747 // we don't destroy the window before the callback returned (as the caller
748 // may delete ourselves on destroy and the ATL callback would still
749 // dereference us when the callback returns).
750 MessageLoop::current()->PostTask(
751 FROM_HERE,
752 base::Bind(&NativeWidgetWin::CloseNow,
753 close_widget_factory_.GetWeakPtr()));
754 }
755 }
756
757 void NativeWidgetWin::CloseNow() {
758 // We may already have been destroyed if the selection resulted in a tab
759 // switch which will have reactivated the browser window and closed us, so
760 // we need to check to see if we're still a window before trying to destroy
761 // ourself.
762 if (IsWindow())
763 DestroyWindow(hwnd());
764 }
765
766 void NativeWidgetWin::EnableClose(bool enable) {
767 // Disable the native frame's close button regardless of whether or not the
768 // native frame is in use, since this also affects the system menu.
769 EnableMenuItem(GetSystemMenu(GetNativeView(), false), SC_CLOSE, enable);
770 SendFrameChanged(GetNativeView());
771 }
772
773 void NativeWidgetWin::Show() {
774 if (!IsWindow())
775 return;
776
777 ShowWindow(SW_SHOWNOACTIVATE);
778 SetInitialFocus();
779 }
780
781 void NativeWidgetWin::Hide() {
782 if (IsWindow()) {
783 // NOTE: Be careful not to activate any windows here (for example, calling
784 // ShowWindow(SW_HIDE) will automatically activate another window). This
785 // code can be called while a window is being deactivated, and activating
786 // another window will screw up the activation that is already in progress.
787 SetWindowPos(NULL, 0, 0, 0, 0,
788 SWP_HIDEWINDOW | SWP_NOACTIVATE | SWP_NOMOVE |
789 SWP_NOREPOSITION | SWP_NOSIZE | SWP_NOZORDER);
790 }
791 }
792
793 void NativeWidgetWin::ShowMaximizedWithBounds(
794 const gfx::Rect& restored_bounds) {
795 WINDOWPLACEMENT placement = { 0 };
796 placement.length = sizeof(WINDOWPLACEMENT);
797 placement.showCmd = SW_SHOWMAXIMIZED;
798 placement.rcNormalPosition = restored_bounds.ToRECT();
799 SetWindowPlacement(hwnd(), &placement);
800 }
801
802 void NativeWidgetWin::ShowWithWindowState(ui::WindowShowState show_state) {
803 DWORD native_show_state;
804 switch (show_state) {
805 case ui::SHOW_STATE_INACTIVE:
806 native_show_state = SW_SHOWNOACTIVATE;
807 break;
808 case ui::SHOW_STATE_MAXIMIZED:
809 native_show_state = SW_SHOWMAXIMIZED;
810 break;
811 case ui::SHOW_STATE_MINIMIZED:
812 native_show_state = SW_SHOWMINIMIZED;
813 break;
814 default:
815 native_show_state = GetShowState();
816 break;
817 }
818 Show(native_show_state);
819 }
820
821 bool NativeWidgetWin::IsVisible() const {
822 return !!::IsWindowVisible(hwnd());
823 }
824
825 void NativeWidgetWin::Activate() {
826 if (IsMinimized())
827 ::ShowWindow(GetNativeView(), SW_RESTORE);
828 ::SetWindowPos(GetNativeView(), HWND_TOP, 0, 0, 0, 0,
829 SWP_NOSIZE | SWP_NOMOVE);
830 SetForegroundWindow(GetNativeView());
831 }
832
833 void NativeWidgetWin::Deactivate() {
834 HWND hwnd = ::GetNextWindow(GetNativeView(), GW_HWNDNEXT);
835 if (hwnd)
836 ::SetForegroundWindow(hwnd);
837 }
838
839 bool NativeWidgetWin::IsActive() const {
840 return GetActiveWindow() == hwnd();
841 }
842
843 void NativeWidgetWin::SetAlwaysOnTop(bool on_top) {
844 ::SetWindowPos(GetNativeView(), on_top ? HWND_TOPMOST : HWND_NOTOPMOST,
845 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
846 }
847
848 void NativeWidgetWin::Maximize() {
849 ExecuteSystemMenuCommand(SC_MAXIMIZE);
850 }
851
852 void NativeWidgetWin::Minimize() {
853 ExecuteSystemMenuCommand(SC_MINIMIZE);
854
855 delegate_->OnNativeBlur(NULL);
856 }
857
858 bool NativeWidgetWin::IsMaximized() const {
859 return !!::IsZoomed(GetNativeView());
860 }
861
862 bool NativeWidgetWin::IsMinimized() const {
863 return !!::IsIconic(GetNativeView());
864 }
865
866 void NativeWidgetWin::Restore() {
867 ExecuteSystemMenuCommand(SC_RESTORE);
868 }
869
870 void NativeWidgetWin::SetFullscreen(bool fullscreen) {
871 if (fullscreen_ == fullscreen)
872 return; // Nothing to do.
873
874 // Reduce jankiness during the following position changes by hiding the window
875 // until it's in the final position.
876 PushForceHidden();
877
878 // Size/position/style window appropriately.
879 if (!fullscreen_) {
880 // Save current window information. We force the window into restored mode
881 // before going fullscreen because Windows doesn't seem to hide the
882 // taskbar if the window is in the maximized state.
883 saved_window_info_.maximized = IsMaximized();
884 if (saved_window_info_.maximized)
885 Restore();
886 saved_window_info_.style = GetWindowLong(GWL_STYLE);
887 saved_window_info_.ex_style = GetWindowLong(GWL_EXSTYLE);
888 GetWindowRect(&saved_window_info_.window_rect);
889 }
890
891 fullscreen_ = fullscreen;
892
893 if (fullscreen_) {
894 // Set new window style and size.
895 MONITORINFO monitor_info;
896 monitor_info.cbSize = sizeof(monitor_info);
897 GetMonitorInfo(MonitorFromWindow(GetNativeView(), MONITOR_DEFAULTTONEAREST),
898 &monitor_info);
899 gfx::Rect monitor_rect(monitor_info.rcMonitor);
900 SetWindowLong(GWL_STYLE,
901 saved_window_info_.style & ~(WS_CAPTION | WS_THICKFRAME));
902 SetWindowLong(GWL_EXSTYLE,
903 saved_window_info_.ex_style & ~(WS_EX_DLGMODALFRAME |
904 WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE));
905 SetWindowPos(NULL, monitor_rect.x(), monitor_rect.y(),
906 monitor_rect.width(), monitor_rect.height(),
907 SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
908 } else {
909 // Reset original window style and size. The multiple window size/moves
910 // here are ugly, but if SetWindowPos() doesn't redraw, the taskbar won't be
911 // repainted. Better-looking methods welcome.
912 gfx::Rect new_rect(saved_window_info_.window_rect);
913 SetWindowLong(GWL_STYLE, saved_window_info_.style);
914 SetWindowLong(GWL_EXSTYLE, saved_window_info_.ex_style);
915 SetWindowPos(NULL, new_rect.x(), new_rect.y(), new_rect.width(),
916 new_rect.height(),
917 SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
918 if (saved_window_info_.maximized)
919 Maximize();
920 }
921
922 // Undo our anti-jankiness hacks.
923 PopForceHidden();
924 }
925
926 bool NativeWidgetWin::IsFullscreen() const {
927 return fullscreen_;
928 }
929
930 void NativeWidgetWin::SetOpacity(unsigned char opacity) {
931 layered_alpha_ = static_cast<BYTE>(opacity);
932 }
933
934 void NativeWidgetWin::SetUseDragFrame(bool use_drag_frame) {
935 if (use_drag_frame) {
936 // Make the frame slightly transparent during the drag operation.
937 drag_frame_saved_window_style_ = GetWindowLong(GWL_STYLE);
938 drag_frame_saved_window_ex_style_ = GetWindowLong(GWL_EXSTYLE);
939 SetWindowLong(GWL_EXSTYLE,
940 drag_frame_saved_window_ex_style_ | WS_EX_LAYERED);
941 // Remove the captions tyle so the window doesn't have window controls for a
942 // more "transparent" look.
943 SetWindowLong(GWL_STYLE, drag_frame_saved_window_style_ & ~WS_CAPTION);
944 SetLayeredWindowAttributes(GetNativeWindow(), RGB(0xFF, 0xFF, 0xFF),
945 kDragFrameWindowAlpha, LWA_ALPHA);
946 } else {
947 SetWindowLong(GWL_STYLE, drag_frame_saved_window_style_);
948 SetWindowLong(GWL_EXSTYLE, drag_frame_saved_window_ex_style_);
949 }
950 }
951
952 bool NativeWidgetWin::IsAccessibleWidget() const {
953 return screen_reader_active_;
954 }
955
956 void NativeWidgetWin::RunShellDrag(View* view,
957 const ui::OSExchangeData& data,
958 int operation) {
959 scoped_refptr<ui::DragSource> drag_source(new ui::DragSource);
960 DWORD effects;
961 DoDragDrop(ui::OSExchangeDataProviderWin::GetIDataObject(data), drag_source,
962 ui::DragDropTypes::DragOperationToDropEffect(operation), &effects);
963 }
964
965 void NativeWidgetWin::SchedulePaintInRect(const gfx::Rect& rect) {
966 if (use_layered_buffer_) {
967 // We must update the back-buffer immediately, since Windows' handling of
968 // invalid rects is somewhat mysterious.
969 invalid_rect_ = invalid_rect_.Union(rect);
970
971 // In some situations, such as drag and drop, when Windows itself runs a
972 // nested message loop our message loop appears to be starved and we don't
973 // receive calls to DidProcessMessage(). This only seems to affect layered
974 // windows, so we schedule a redraw manually using a task, since those never
975 // seem to be starved. Also, wtf.
976 if (!paint_layered_window_factory_.HasWeakPtrs()) {
977 MessageLoop::current()->PostTask(
978 FROM_HERE,
979 base::Bind(&NativeWidgetWin::RedrawLayeredWindowContents,
980 paint_layered_window_factory_.GetWeakPtr()));
981 }
982 } else {
983 // InvalidateRect() expects client coordinates.
984 RECT r = rect.ToRECT();
985 InvalidateRect(hwnd(), &r, FALSE);
986 }
987 }
988
989 void NativeWidgetWin::SetCursor(gfx::NativeCursor cursor) {
990 if (cursor) {
991 previous_cursor_ = ::SetCursor(cursor);
992 } else if (previous_cursor_) {
993 ::SetCursor(previous_cursor_);
994 previous_cursor_ = NULL;
995 }
996 }
997
998 void NativeWidgetWin::ClearNativeFocus() {
999 ::SetFocus(GetNativeView());
1000 }
1001
1002 void NativeWidgetWin::FocusNativeView(gfx::NativeView native_view) {
1003 // Only reset focus if hwnd is not already focused.
1004 if (native_view && ::GetFocus() != native_view)
1005 ::SetFocus(native_view);
1006 }
1007
1008 bool NativeWidgetWin::ConvertPointFromAncestor(
1009 const Widget* ancestor, gfx::Point* point) const {
1010 NOTREACHED();
1011 return false;
1012 }
1013
1014 gfx::Rect NativeWidgetWin::GetWorkAreaBoundsInScreen() const {
1015 return gfx::Screen::GetMonitorWorkAreaNearestWindow(GetNativeView());
1016 }
1017
1018 void NativeWidgetWin::SetInactiveRenderingDisabled(bool value) {
1019 }
1020
1021 ////////////////////////////////////////////////////////////////////////////////
1022 // NativeWidgetWin, MessageLoop::Observer implementation:
1023
1024 base::EventStatus NativeWidgetWin::WillProcessEvent(
1025 const base::NativeEvent& event) {
1026 return base::EVENT_CONTINUE;
1027 }
1028
1029 void NativeWidgetWin::DidProcessEvent(const base::NativeEvent& event) {
1030 RedrawInvalidRect();
1031 }
1032
1033 ////////////////////////////////////////////////////////////////////////////////
1034 // NativeWidgetWin, WindowImpl overrides:
1035
1036 HICON NativeWidgetWin::GetDefaultWindowIcon() const {
1037 if (ViewsDelegate::views_delegate)
1038 return ViewsDelegate::views_delegate->GetDefaultWindowIcon();
1039 return NULL;
1040 }
1041
1042 LRESULT NativeWidgetWin::OnWndProc(UINT message, WPARAM w_param,
1043 LPARAM l_param) {
1044 HWND window = hwnd();
1045 LRESULT result = 0;
1046
1047 // First allow messages sent by child controls to be processed directly by
1048 // their associated views. If such a view is present, it will handle the
1049 // message *instead of* this NativeWidgetWin.
1050 if (ProcessChildWindowMessage(message, w_param, l_param, &result))
1051 return result;
1052
1053 // Otherwise we handle everything else.
1054 if (!ProcessWindowMessage(window, message, w_param, l_param, result))
1055 result = DefWindowProc(window, message, w_param, l_param);
1056 if (message == WM_NCDESTROY) {
1057 MessageLoopForUI::current()->RemoveObserver(this);
1058 OnFinalMessage(window);
1059 }
1060
1061 // Only top level widget should store/restore focus.
1062 if (message == WM_ACTIVATE && GetWidget()->is_top_level())
1063 PostProcessActivateMessage(this, LOWORD(w_param));
1064 if (message == WM_ENABLE && restore_focus_when_enabled_) {
1065 // This path should be executed only for top level as
1066 // restore_focus_when_enabled_ is set in PostProcessActivateMessage.
1067 DCHECK(GetWidget()->is_top_level());
1068 restore_focus_when_enabled_ = false;
1069 GetWidget()->GetFocusManager()->RestoreFocusedView();
1070 }
1071 return result;
1072 }
1073
1074 ////////////////////////////////////////////////////////////////////////////////
1075 // NativeWidgetWin, protected:
1076
1077 // Message handlers ------------------------------------------------------------
1078
1079 void NativeWidgetWin::OnActivate(UINT action, BOOL minimized, HWND window) {
1080 SetMsgHandled(FALSE);
1081 }
1082
1083 void NativeWidgetWin::OnActivateApp(BOOL active, DWORD thread_id) {
1084 if (GetWidget()->non_client_view() && !active &&
1085 thread_id != GetCurrentThreadId()) {
1086 // Another application was activated, we should reset any state that
1087 // disables inactive rendering now.
1088 delegate_->EnableInactiveRendering();
1089 // Also update the native frame if it is rendering the non-client area.
1090 if (GetWidget()->ShouldUseNativeFrame())
1091 DefWindowProcWithRedrawLock(WM_NCACTIVATE, FALSE, 0);
1092 }
1093 }
1094
1095 LRESULT NativeWidgetWin::OnAppCommand(HWND window,
1096 short app_command,
1097 WORD device,
1098 int keystate) {
1099 // We treat APPCOMMAND ids as an extension of our command namespace, and just
1100 // let the delegate figure out what to do...
1101 BOOL is_handled = (GetWidget()->widget_delegate() &&
1102 GetWidget()->widget_delegate()->ExecuteWindowsCommand(app_command)) ?
1103 TRUE : FALSE;
1104 SetMsgHandled(is_handled);
1105 // Make sure to return TRUE if the event was handled or in some cases the
1106 // system will execute the default handler which can cause bugs like going
1107 // forward or back two pages instead of one.
1108 return is_handled;
1109 }
1110
1111 void NativeWidgetWin::OnCancelMode() {
1112 SetMsgHandled(FALSE);
1113 }
1114
1115 void NativeWidgetWin::OnCaptureChanged(HWND hwnd) {
1116 delegate_->OnMouseCaptureLost();
1117 }
1118
1119 void NativeWidgetWin::OnClose() {
1120 GetWidget()->Close();
1121 }
1122
1123 void NativeWidgetWin::OnCommand(UINT notification_code,
1124 int command_id,
1125 HWND window) {
1126 // If the notification code is > 1 it means it is control specific and we
1127 // should ignore it.
1128 if (notification_code > 1 ||
1129 GetWidget()->widget_delegate()->ExecuteWindowsCommand(command_id)) {
1130 SetMsgHandled(FALSE);
1131 }
1132 }
1133
1134 LRESULT NativeWidgetWin::OnCreate(CREATESTRUCT* create_struct) {
1135 SetNativeWindowProperty(kNativeWidgetKey, this);
1136 CHECK_EQ(this, GetNativeWidgetForNativeView(hwnd()));
1137
1138 use_layered_buffer_ = !!(window_ex_style() & WS_EX_LAYERED);
1139
1140 // Attempt to detect screen readers by sending an event with our custom id.
1141 if (!IsAccessibleWidget())
1142 NotifyWinEvent(EVENT_SYSTEM_ALERT, hwnd(), kCustomObjectID, CHILDID_SELF);
1143
1144 props_.push_back(ui::SetWindowSupportsRerouteMouseWheel(hwnd()));
1145
1146 drop_target_ = new DropTargetWin(
1147 static_cast<internal::RootView*>(GetWidget()->GetRootView()));
1148
1149 // We need to add ourselves as a message loop observer so that we can repaint
1150 // aggressively if the contents of our window become invalid. Unfortunately
1151 // WM_PAINT messages are starved and we get flickery redrawing when resizing
1152 // if we do not do this.
1153 MessageLoopForUI::current()->AddObserver(this);
1154
1155 // Windows special DWM window frame requires a special tooltip manager so
1156 // that window controls in Chrome windows don't flicker when you move your
1157 // mouse over them. See comment in aero_tooltip_manager.h.
1158 Widget* widget = GetWidget()->GetTopLevelWidget();
1159 if (widget && widget->ShouldUseNativeFrame()) {
1160 tooltip_manager_.reset(new AeroTooltipManager(GetWidget()));
1161 } else {
1162 tooltip_manager_.reset(new TooltipManagerWin(GetWidget()));
1163 }
1164 if (!tooltip_manager_->Init()) {
1165 // There was a problem creating the TooltipManager. Common error is 127.
1166 // See 82193 for details.
1167 LOG_GETLASTERROR(WARNING) << "tooltip creation failed, disabling tooltips";
1168 tooltip_manager_.reset();
1169 }
1170
1171 // This message initializes the window so that focus border are shown for
1172 // windows.
1173 SendMessage(
1174 hwnd(), WM_CHANGEUISTATE, MAKELPARAM(UIS_CLEAR, UISF_HIDEFOCUS), 0);
1175
1176 // Bug 964884: detach the IME attached to this window.
1177 // We should attach IMEs only when we need to input CJK strings.
1178 ImmAssociateContextEx(hwnd(), NULL, 0);
1179
1180 // We need to allow the delegate to size its contents since the window may not
1181 // receive a size notification when its initial bounds are specified at window
1182 // creation time.
1183 ClientAreaSizeChanged();
1184
1185 #if defined(VIEWS_COMPOSITOR)
1186 if (View::get_use_acceleration_when_possible()) {
1187 if (ui::Compositor::compositor_factory()) {
1188 compositor_ = (*Widget::compositor_factory())(this);
1189 } else {
1190 CRect window_rect;
1191 GetClientRect(&window_rect);
1192 compositor_ = ui::Compositor::Create(this,
1193 hwnd(),
1194 gfx::Size(window_rect.Width(), window_rect.Height()));
1195 }
1196 if (compositor_.get()) {
1197 delegate_->AsWidget()->GetRootView()->SetPaintToLayer(true);
1198 compositor_->SetRootLayer(delegate_->AsWidget()->GetRootView()->layer());
1199 }
1200 }
1201 #endif
1202
1203 delegate_->OnNativeWidgetCreated();
1204
1205 // Get access to a modifiable copy of the system menu.
1206 GetSystemMenu(hwnd(), false);
1207 return 0;
1208 }
1209
1210 void NativeWidgetWin::OnDestroy() {
1211 delegate_->OnNativeWidgetDestroying();
1212 if (drop_target_.get()) {
1213 RevokeDragDrop(hwnd());
1214 drop_target_ = NULL;
1215 }
1216 }
1217
1218 void NativeWidgetWin::OnDisplayChange(UINT bits_per_pixel, CSize screen_size) {
1219 GetWidget()->widget_delegate()->OnDisplayChanged();
1220 }
1221
1222 LRESULT NativeWidgetWin::OnDwmCompositionChanged(UINT msg,
1223 WPARAM w_param,
1224 LPARAM l_param) {
1225 if (!GetWidget()->non_client_view()) {
1226 SetMsgHandled(FALSE);
1227 return 0;
1228 }
1229
1230 // For some reason, we need to hide the window while we're changing the frame
1231 // type only when we're changing it in response to WM_DWMCOMPOSITIONCHANGED.
1232 // If we don't, the client area will be filled with black. I'm suspecting
1233 // something skia-ey.
1234 // Frame type toggling caused by the user (e.g. switching theme) doesn't seem
1235 // to have this requirement.
1236 FrameTypeChanged();
1237 return 0;
1238 }
1239
1240 void NativeWidgetWin::OnEndSession(BOOL ending, UINT logoff) {
1241 SetMsgHandled(FALSE);
1242 }
1243
1244 void NativeWidgetWin::OnEnterSizeMove() {
1245 delegate_->OnNativeWidgetBeginUserBoundsChange();
1246 SetMsgHandled(FALSE);
1247 }
1248
1249 LRESULT NativeWidgetWin::OnEraseBkgnd(HDC dc) {
1250 // This is needed for magical win32 flicker ju-ju.
1251 return 1;
1252 }
1253
1254 void NativeWidgetWin::OnExitMenuLoop(BOOL is_track_popup_menu) {
1255 SetMsgHandled(FALSE);
1256 }
1257
1258 void NativeWidgetWin::OnExitSizeMove() {
1259 delegate_->OnNativeWidgetEndUserBoundsChange();
1260 SetMsgHandled(FALSE);
1261 }
1262
1263 LRESULT NativeWidgetWin::OnGetObject(UINT uMsg,
1264 WPARAM w_param,
1265 LPARAM l_param) {
1266 LRESULT reference_result = static_cast<LRESULT>(0L);
1267
1268 // Accessibility readers will send an OBJID_CLIENT message
1269 if (OBJID_CLIENT == l_param) {
1270 // Retrieve MSAA dispatch object for the root view.
1271 base::win::ScopedComPtr<IAccessible> root(
1272 GetWidget()->GetRootView()->GetNativeViewAccessible());
1273
1274 // Create a reference that MSAA will marshall to the client.
1275 reference_result = LresultFromObject(IID_IAccessible, w_param,
1276 static_cast<IAccessible*>(root.Detach()));
1277 }
1278
1279 if (kCustomObjectID == l_param) {
1280 // An MSAA client requestes our custom id. Assume that we have detected an
1281 // active windows screen reader.
1282 OnScreenReaderDetected();
1283
1284 // Return with failure.
1285 return static_cast<LRESULT>(0L);
1286 }
1287
1288 return reference_result;
1289 }
1290
1291 void NativeWidgetWin::OnGetMinMaxInfo(MINMAXINFO* minmax_info) {
1292 gfx::Size min_window_size(delegate_->GetMinimumSize());
1293 // Add the native frame border size to the minimum size if the view reports
1294 // its size as the client size.
1295 if (WidgetSizeIsClientSize()) {
1296 CRect client_rect, window_rect;
1297 GetClientRect(&client_rect);
1298 GetWindowRect(&window_rect);
1299 window_rect -= client_rect;
1300 min_window_size.Enlarge(window_rect.Width(), window_rect.Height());
1301 }
1302 minmax_info->ptMinTrackSize.x = min_window_size.width();
1303 minmax_info->ptMinTrackSize.y = min_window_size.height();
1304 SetMsgHandled(FALSE);
1305 }
1306
1307 void NativeWidgetWin::OnHScroll(int scroll_type,
1308 short position,
1309 HWND scrollbar) {
1310 SetMsgHandled(FALSE);
1311 }
1312
1313 LRESULT NativeWidgetWin::OnImeMessages(UINT message,
1314 WPARAM w_param,
1315 LPARAM l_param) {
1316 InputMethod* input_method = GetWidget()->GetInputMethodDirect();
1317 if (!input_method || input_method->IsMock()) {
1318 SetMsgHandled(FALSE);
1319 return 0;
1320 }
1321
1322 InputMethodWin* ime_win = static_cast<InputMethodWin*>(input_method);
1323 BOOL handled = FALSE;
1324 LRESULT result = ime_win->OnImeMessages(message, w_param, l_param, &handled);
1325
1326 SetMsgHandled(handled);
1327 return result;
1328 }
1329
1330 void NativeWidgetWin::OnInitMenu(HMENU menu) {
1331 bool is_fullscreen = IsFullscreen();
1332 bool is_minimized = IsMinimized();
1333 bool is_maximized = IsMaximized();
1334 bool is_restored = !is_fullscreen && !is_minimized && !is_maximized;
1335
1336 ScopedRedrawLock lock(this);
1337 EnableMenuItem(menu, SC_RESTORE, is_minimized || is_maximized);
1338 EnableMenuItem(menu, SC_MOVE, is_restored);
1339 EnableMenuItem(menu, SC_SIZE,
1340 GetWidget()->widget_delegate()->CanResize() && is_restored);
1341 EnableMenuItem(menu, SC_MAXIMIZE,
1342 GetWidget()->widget_delegate()->CanMaximize() &&
1343 !is_fullscreen && !is_maximized);
1344 EnableMenuItem(menu, SC_MINIMIZE,
1345 GetWidget()->widget_delegate()->CanMaximize() &&
1346 !is_minimized);
1347 }
1348
1349 void NativeWidgetWin::OnInitMenuPopup(HMENU menu,
1350 UINT position,
1351 BOOL is_system_menu) {
1352 SetMsgHandled(FALSE);
1353 }
1354
1355 void NativeWidgetWin::OnInputLangChange(DWORD character_set,
1356 HKL input_language_id) {
1357 InputMethod* input_method = GetWidget()->GetInputMethodDirect();
1358
1359 if (input_method && !input_method->IsMock()) {
1360 static_cast<InputMethodWin*>(input_method)->OnInputLangChange(
1361 character_set, input_language_id);
1362 }
1363 }
1364
1365 LRESULT NativeWidgetWin::OnKeyEvent(UINT message,
1366 WPARAM w_param,
1367 LPARAM l_param) {
1368 MSG msg = { hwnd(), message, w_param, l_param };
1369 KeyEvent key(msg);
1370 InputMethod* input_method = GetWidget()->GetInputMethodDirect();
1371 if (input_method)
1372 input_method->DispatchKeyEvent(key);
1373 else
1374 DispatchKeyEventPostIME(key);
1375 return 0;
1376 }
1377
1378 void NativeWidgetWin::OnKillFocus(HWND focused_window) {
1379 delegate_->OnNativeBlur(focused_window);
1380 InputMethod* input_method = GetWidget()->GetInputMethodDirect();
1381 if (input_method)
1382 input_method->OnBlur();
1383 SetMsgHandled(FALSE);
1384 }
1385
1386 LRESULT NativeWidgetWin::OnMouseActivate(UINT message,
1387 WPARAM w_param,
1388 LPARAM l_param) {
1389 // TODO(beng): resolve this with the GetWindowLong() check on the subsequent
1390 // line.
1391 if (GetWidget()->non_client_view())
1392 return delegate_->CanActivate() ? MA_ACTIVATE : MA_NOACTIVATEANDEAT;
1393 if (GetWindowLong(GWL_EXSTYLE) & WS_EX_NOACTIVATE)
1394 return MA_NOACTIVATE;
1395 SetMsgHandled(FALSE);
1396 return MA_ACTIVATE;
1397 }
1398
1399 LRESULT NativeWidgetWin::OnMouseRange(UINT message,
1400 WPARAM w_param,
1401 LPARAM l_param) {
1402 if (message == WM_RBUTTONUP && is_right_mouse_pressed_on_caption_) {
1403 is_right_mouse_pressed_on_caption_ = false;
1404 ReleaseCapture();
1405 // |point| is in window coordinates, but WM_NCHITTEST and TrackPopupMenu()
1406 // expect screen coordinates.
1407 CPoint screen_point(l_param);
1408 MapWindowPoints(GetNativeView(), HWND_DESKTOP, &screen_point, 1);
1409 w_param = SendMessage(GetNativeView(), WM_NCHITTEST, 0,
1410 MAKELPARAM(screen_point.x, screen_point.y));
1411 if (w_param == HTCAPTION || w_param == HTSYSMENU) {
1412 ui::ShowSystemMenu(GetNativeView(), screen_point.x, screen_point.y);
1413 return 0;
1414 }
1415 } else if (message == WM_NCLBUTTONDOWN &&
1416 !GetWidget()->ShouldUseNativeFrame()) {
1417 switch (w_param) {
1418 case HTCLOSE:
1419 case HTMINBUTTON:
1420 case HTMAXBUTTON: {
1421 // When the mouse is pressed down in these specific non-client areas,
1422 // we need to tell the RootView to send the mouse pressed event (which
1423 // sets capture, allowing subsequent WM_LBUTTONUP (note, _not_
1424 // WM_NCLBUTTONUP) to fire so that the appropriate WM_SYSCOMMAND can be
1425 // sent by the applicable button's ButtonListener. We _have_ to do this
1426 // way rather than letting Windows just send the syscommand itself (as
1427 // would happen if we never did this dance) because for some insane
1428 // reason DefWindowProc for WM_NCLBUTTONDOWN also renders the pressed
1429 // window control button appearance, in the Windows classic style, over
1430 // our view! Ick! By handling this message we prevent Windows from
1431 // doing this undesirable thing, but that means we need to roll the
1432 // sys-command handling ourselves.
1433 // Combine |w_param| with common key state message flags.
1434 w_param |= ((GetKeyState(VK_CONTROL) & 0x80) == 0x80)? MK_CONTROL : 0;
1435 w_param |= ((GetKeyState(VK_SHIFT) & 0x80) == 0x80)? MK_SHIFT : 0;
1436 }
1437 }
1438 } else if (message == WM_NCRBUTTONDOWN &&
1439 (w_param == HTCAPTION || w_param == HTSYSMENU)) {
1440 is_right_mouse_pressed_on_caption_ = true;
1441 // We SetMouseCapture() to ensure we only show the menu when the button
1442 // down and up are both on the caption. Note: this causes the button up to
1443 // be WM_RBUTTONUP instead of WM_NCRBUTTONUP.
1444 SetMouseCapture();
1445 }
1446
1447 MSG msg = { hwnd(), message, w_param, l_param, 0,
1448 { GET_X_LPARAM(l_param), GET_Y_LPARAM(l_param) } };
1449 MouseEvent event(msg);
1450
1451 if (!(event.flags() & ui::EF_IS_NON_CLIENT))
1452 if (tooltip_manager_.get())
1453 tooltip_manager_->OnMouse(message, w_param, l_param);
1454
1455 if (event.type() == ui::ET_MOUSE_MOVED && !HasMouseCapture()) {
1456 // Windows only fires WM_MOUSELEAVE events if the application begins
1457 // "tracking" mouse events for a given HWND during WM_MOUSEMOVE events.
1458 // We need to call |TrackMouseEvents| to listen for WM_MOUSELEAVE.
1459 TrackMouseEvents((message == WM_NCMOUSEMOVE) ?
1460 TME_NONCLIENT | TME_LEAVE : TME_LEAVE);
1461 } else if (event.type() == ui::ET_MOUSE_EXITED) {
1462 // Reset our tracking flags so future mouse movement over this
1463 // NativeWidgetWin results in a new tracking session. Fall through for
1464 // OnMouseEvent.
1465 active_mouse_tracking_flags_ = 0;
1466 } else if (event.type() == ui::ET_MOUSEWHEEL) {
1467 // Reroute the mouse wheel to the window under the pointer if applicable.
1468 return (ui::RerouteMouseWheel(hwnd(), w_param, l_param) ||
1469 delegate_->OnMouseEvent(MouseWheelEvent(msg))) ? 0 : 1;
1470 }
1471
1472 bool handled = delegate_->OnMouseEvent(event);
1473
1474 if (!handled && message == WM_NCLBUTTONDOWN && w_param != HTSYSMENU &&
1475 !GetWidget()->ShouldUseNativeFrame()) {
1476 // TODO(msw): Eliminate undesired painting, or re-evaluate this workaround.
1477 // DefWindowProc for WM_NCLBUTTONDOWN does weird non-client painting, so we
1478 // need to call it inside a ScopedRedrawLock. This may cause other negative
1479 // side-effects (ex/ stifling non-client mouse releases).
1480 DefWindowProcWithRedrawLock(message, w_param, l_param);
1481 handled = true;
1482 }
1483
1484 SetMsgHandled(handled);
1485 return 0;
1486 }
1487
1488 void NativeWidgetWin::OnMove(const CPoint& point) {
1489 // TODO(beng): move to Widget.
1490 GetWidget()->widget_delegate()->OnWidgetMove();
1491 SetMsgHandled(FALSE);
1492 }
1493
1494 void NativeWidgetWin::OnMoving(UINT param, const LPRECT new_bounds) {
1495 // TODO(beng): move to Widget.
1496 GetWidget()->widget_delegate()->OnWidgetMove();
1497 }
1498
1499 LRESULT NativeWidgetWin::OnNCActivate(BOOL active) {
1500 if (delegate_->CanActivate())
1501 delegate_->OnNativeWidgetActivationChanged(!!active);
1502
1503 if (!GetWidget()->non_client_view()) {
1504 SetMsgHandled(FALSE);
1505 return 0;
1506 }
1507
1508 if (!delegate_->CanActivate())
1509 return TRUE;
1510
1511 // The frame may need to redraw as a result of the activation change.
1512 // We can get WM_NCACTIVATE before we're actually visible. If we're not
1513 // visible, no need to paint.
1514 if (IsVisible())
1515 GetWidget()->non_client_view()->SchedulePaint();
1516
1517 if (!GetWidget()->ShouldUseNativeFrame()) {
1518 // TODO(beng, et al): Hack to redraw this window and child windows
1519 // synchronously upon activation. Not all child windows are redrawing
1520 // themselves leading to issues like http://crbug.com/74604
1521 // We redraw out-of-process HWNDs asynchronously to avoid hanging the
1522 // whole app if a child HWND belonging to a hung plugin is encountered.
1523 RedrawWindow(GetNativeView(), NULL, NULL,
1524 RDW_NOCHILDREN | RDW_INVALIDATE | RDW_UPDATENOW);
1525 EnumChildWindows(GetNativeView(), EnumChildWindowsForRedraw, NULL);
1526 }
1527
1528 // If we're active again, we should be allowed to render as inactive, so
1529 // tell the non-client view.
1530 bool inactive_rendering_disabled = delegate_->IsInactiveRenderingDisabled();
1531 if (IsActive())
1532 delegate_->EnableInactiveRendering();
1533
1534 // Avoid DefWindowProc non-client rendering over our custom frame.
1535 if (!GetWidget()->ShouldUseNativeFrame()) {
1536 SetMsgHandled(TRUE);
1537 return TRUE;
1538 }
1539
1540 return DefWindowProcWithRedrawLock(WM_NCACTIVATE,
1541 inactive_rendering_disabled || active, 0);
1542 }
1543
1544 LRESULT NativeWidgetWin::OnNCCalcSize(BOOL mode, LPARAM l_param) {
1545 // We only override the default handling if we need to specify a custom
1546 // non-client edge width. Note that in most cases "no insets" means no
1547 // custom width, but in fullscreen mode we want a custom width of 0.
1548 gfx::Insets insets = GetClientAreaInsets();
1549 if (insets.empty() && !IsFullscreen()) {
1550 SetMsgHandled(FALSE);
1551 return 0;
1552 }
1553
1554 RECT* client_rect = mode ?
1555 &(reinterpret_cast<NCCALCSIZE_PARAMS*>(l_param)->rgrc[0]) :
1556 reinterpret_cast<RECT*>(l_param);
1557 client_rect->left += insets.left();
1558 client_rect->top += insets.top();
1559 client_rect->bottom -= insets.bottom();
1560 client_rect->right -= insets.right();
1561 if (IsMaximized()) {
1562 // Find all auto-hide taskbars along the screen edges and adjust in by the
1563 // thickness of the auto-hide taskbar on each such edge, so the window isn't
1564 // treated as a "fullscreen app", which would cause the taskbars to
1565 // disappear.
1566 HMONITOR monitor = MonitorFromWindow(GetNativeView(),
1567 MONITOR_DEFAULTTONULL);
1568 if (!monitor) {
1569 // We might end up here if the window was previously minimized and the
1570 // user clicks on the taskbar button to restore it in the previously
1571 // maximized position. In that case WM_NCCALCSIZE is sent before the
1572 // window coordinates are restored to their previous values, so our
1573 // (left,top) would probably be (-32000,-32000) like all minimized
1574 // windows. So the above MonitorFromWindow call fails, but if we check
1575 // the window rect given with WM_NCCALCSIZE (which is our previous
1576 // restored window position) we will get the correct monitor handle.
1577 monitor = MonitorFromRect(client_rect, MONITOR_DEFAULTTONULL);
1578 if (!monitor) {
1579 // This is probably an extreme case that we won't hit, but if we don't
1580 // intersect any monitor, let us not adjust the client rect since our
1581 // window will not be visible anyway.
1582 return 0;
1583 }
1584 }
1585 if (GetTopmostAutoHideTaskbarForEdge(ABE_LEFT, monitor))
1586 client_rect->left += kAutoHideTaskbarThicknessPx;
1587 if (GetTopmostAutoHideTaskbarForEdge(ABE_TOP, monitor)) {
1588 if (GetWidget()->ShouldUseNativeFrame()) {
1589 // Tricky bit. Due to a bug in DwmDefWindowProc()'s handling of
1590 // WM_NCHITTEST, having any nonclient area atop the window causes the
1591 // caption buttons to draw onscreen but not respond to mouse
1592 // hover/clicks.
1593 // So for a taskbar at the screen top, we can't push the
1594 // client_rect->top down; instead, we move the bottom up by one pixel,
1595 // which is the smallest change we can make and still get a client area
1596 // less than the screen size. This is visibly ugly, but there seems to
1597 // be no better solution.
1598 --client_rect->bottom;
1599 } else {
1600 client_rect->top += kAutoHideTaskbarThicknessPx;
1601 }
1602 }
1603 if (GetTopmostAutoHideTaskbarForEdge(ABE_RIGHT, monitor))
1604 client_rect->right -= kAutoHideTaskbarThicknessPx;
1605 if (GetTopmostAutoHideTaskbarForEdge(ABE_BOTTOM, monitor))
1606 client_rect->bottom -= kAutoHideTaskbarThicknessPx;
1607
1608 // We cannot return WVR_REDRAW when there is nonclient area, or Windows
1609 // exhibits bugs where client pixels and child HWNDs are mispositioned by
1610 // the width/height of the upper-left nonclient area.
1611 return 0;
1612 }
1613
1614 // If the window bounds change, we're going to relayout and repaint anyway.
1615 // Returning WVR_REDRAW avoids an extra paint before that of the old client
1616 // pixels in the (now wrong) location, and thus makes actions like resizing a
1617 // window from the left edge look slightly less broken.
1618 // We special case when left or top insets are 0, since these conditions
1619 // actually require another repaint to correct the layout after glass gets
1620 // turned on and off.
1621 if (insets.left() == 0 || insets.top() == 0)
1622 return 0;
1623 return mode ? WVR_REDRAW : 0;
1624 }
1625
1626 LRESULT NativeWidgetWin::OnNCHitTest(const CPoint& point) {
1627 if (!GetWidget()->non_client_view()) {
1628 SetMsgHandled(FALSE);
1629 return 0;
1630 }
1631
1632 // If the DWM is rendering the window controls, we need to give the DWM's
1633 // default window procedure first chance to handle hit testing.
1634 if (GetWidget()->ShouldUseNativeFrame()) {
1635 LRESULT result;
1636 if (DwmDefWindowProc(GetNativeView(), WM_NCHITTEST, 0,
1637 MAKELPARAM(point.x, point.y), &result)) {
1638 return result;
1639 }
1640 }
1641
1642 // First, give the NonClientView a chance to test the point to see if it
1643 // provides any of the non-client area.
1644 POINT temp = point;
1645 MapWindowPoints(HWND_DESKTOP, GetNativeView(), &temp, 1);
1646 int component = delegate_->GetNonClientComponent(gfx::Point(temp));
1647 if (component != HTNOWHERE)
1648 return component;
1649
1650 // Otherwise, we let Windows do all the native frame non-client handling for
1651 // us.
1652 SetMsgHandled(FALSE);
1653 return 0;
1654 }
1655
1656 void NativeWidgetWin::OnNCPaint(HRGN rgn) {
1657 // We only do non-client painting if we're not using the native frame.
1658 // It's required to avoid some native painting artifacts from appearing when
1659 // the window is resized.
1660 if (!GetWidget()->non_client_view() || GetWidget()->ShouldUseNativeFrame()) {
1661 SetMsgHandled(FALSE);
1662 return;
1663 }
1664
1665 // We have an NC region and need to paint it. We expand the NC region to
1666 // include the dirty region of the root view. This is done to minimize
1667 // paints.
1668 CRect window_rect;
1669 GetWindowRect(&window_rect);
1670
1671 if (window_rect.Width() != GetWidget()->GetRootView()->width() ||
1672 window_rect.Height() != GetWidget()->GetRootView()->height()) {
1673 // If the size of the window differs from the size of the root view it
1674 // means we're being asked to paint before we've gotten a WM_SIZE. This can
1675 // happen when the user is interactively resizing the window. To avoid
1676 // mass flickering we don't do anything here. Once we get the WM_SIZE we'll
1677 // reset the region of the window which triggers another WM_NCPAINT and
1678 // all is well.
1679 return;
1680 }
1681
1682 CRect dirty_region;
1683 // A value of 1 indicates paint all.
1684 if (!rgn || rgn == reinterpret_cast<HRGN>(1)) {
1685 dirty_region = CRect(0, 0, window_rect.Width(), window_rect.Height());
1686 } else {
1687 RECT rgn_bounding_box;
1688 GetRgnBox(rgn, &rgn_bounding_box);
1689 if (!IntersectRect(&dirty_region, &rgn_bounding_box, &window_rect))
1690 return; // Dirty region doesn't intersect window bounds, bale.
1691
1692 // rgn_bounding_box is in screen coordinates. Map it to window coordinates.
1693 OffsetRect(&dirty_region, -window_rect.left, -window_rect.top);
1694 }
1695
1696 // In theory GetDCEx should do what we want, but I couldn't get it to work.
1697 // In particular the docs mentiond DCX_CLIPCHILDREN, but as far as I can tell
1698 // it doesn't work at all. So, instead we get the DC for the window then
1699 // manually clip out the children.
1700 HDC dc = GetWindowDC(GetNativeView());
1701 ClipState clip_state;
1702 clip_state.x = window_rect.left;
1703 clip_state.y = window_rect.top;
1704 clip_state.parent = GetNativeView();
1705 clip_state.dc = dc;
1706 EnumChildWindows(GetNativeView(), &ClipDCToChild,
1707 reinterpret_cast<LPARAM>(&clip_state));
1708
1709 gfx::Rect old_paint_region = invalid_rect();
1710
1711 if (!old_paint_region.IsEmpty()) {
1712 // The root view has a region that needs to be painted. Include it in the
1713 // region we're going to paint.
1714
1715 CRect old_paint_region_crect = old_paint_region.ToRECT();
1716 CRect tmp = dirty_region;
1717 UnionRect(&dirty_region, &tmp, &old_paint_region_crect);
1718 }
1719
1720 GetWidget()->GetRootView()->SchedulePaintInRect(gfx::Rect(dirty_region));
1721
1722 // gfx::CanvasSkiaPaint's destructor does the actual painting. As such, wrap
1723 // the following in a block to force paint to occur so that we can release
1724 // the dc.
1725 {
1726 gfx::CanvasSkiaPaint canvas(dc, true, dirty_region.left,
1727 dirty_region.top, dirty_region.Width(),
1728 dirty_region.Height());
1729 delegate_->OnNativeWidgetPaint(&canvas);
1730 }
1731
1732 ReleaseDC(GetNativeView(), dc);
1733 // When using a custom frame, we want to avoid calling DefWindowProc() since
1734 // that may render artifacts.
1735 SetMsgHandled(!GetWidget()->ShouldUseNativeFrame());
1736 }
1737
1738 LRESULT NativeWidgetWin::OnNCUAHDrawCaption(UINT msg,
1739 WPARAM w_param,
1740 LPARAM l_param) {
1741 // See comment in widget_win.h at the definition of WM_NCUAHDRAWCAPTION for
1742 // an explanation about why we need to handle this message.
1743 SetMsgHandled(!GetWidget()->ShouldUseNativeFrame());
1744 return 0;
1745 }
1746
1747 LRESULT NativeWidgetWin::OnNCUAHDrawFrame(UINT msg,
1748 WPARAM w_param,
1749 LPARAM l_param) {
1750 // See comment in widget_win.h at the definition of WM_NCUAHDRAWCAPTION for
1751 // an explanation about why we need to handle this message.
1752 SetMsgHandled(!GetWidget()->ShouldUseNativeFrame());
1753 return 0;
1754 }
1755
1756 LRESULT NativeWidgetWin::OnNotify(int w_param, NMHDR* l_param) {
1757 // We can be sent this message before the tooltip manager is created, if a
1758 // subclass overrides OnCreate and creates some kind of Windows control there
1759 // that sends WM_NOTIFY messages.
1760 if (tooltip_manager_.get()) {
1761 bool handled;
1762 LRESULT result = tooltip_manager_->OnNotify(w_param, l_param, &handled);
1763 SetMsgHandled(handled);
1764 return result;
1765 }
1766 SetMsgHandled(FALSE);
1767 return 0;
1768 }
1769
1770 void NativeWidgetWin::OnPaint(HDC dc) {
1771 RECT dirty_rect;
1772 // Try to paint accelerated first.
1773 if (GetUpdateRect(hwnd(), &dirty_rect, FALSE) &&
1774 !IsRectEmpty(&dirty_rect)) {
1775 if (delegate_->OnNativeWidgetPaintAccelerated(
1776 gfx::Rect(dirty_rect))) {
1777 ValidateRect(hwnd(), NULL);
1778 } else {
1779 scoped_ptr<gfx::CanvasPaint> canvas(
1780 gfx::CanvasPaint::CreateCanvasPaint(hwnd()));
1781 delegate_->OnNativeWidgetPaint(canvas->AsCanvas());
1782 }
1783 } else {
1784 // TODO(msw): Find a better solution for this crbug.com/93530 workaround.
1785 // Some scenarios otherwise fail to validate minimized app/popup windows.
1786 ValidateRect(hwnd(), NULL);
1787 }
1788 }
1789
1790 LRESULT NativeWidgetWin::OnPowerBroadcast(DWORD power_event, DWORD data) {
1791 base::SystemMonitor* monitor = base::SystemMonitor::Get();
1792 if (monitor)
1793 monitor->ProcessWmPowerBroadcastMessage(power_event);
1794 SetMsgHandled(FALSE);
1795 return 0;
1796 }
1797
1798 LRESULT NativeWidgetWin::OnReflectedMessage(UINT msg,
1799 WPARAM w_param,
1800 LPARAM l_param) {
1801 SetMsgHandled(FALSE);
1802 return 0;
1803 }
1804
1805 LRESULT NativeWidgetWin::OnSetCursor(UINT message,
1806 WPARAM w_param,
1807 LPARAM l_param) {
1808 // Using ScopedRedrawLock here frequently allows content behind this window to
1809 // paint in front of this window, causing glaring rendering artifacts.
1810 // If omitting ScopedRedrawLock here triggers caption rendering artifacts via
1811 // DefWindowProc message handling, we'll need to find a better solution.
1812 SetMsgHandled(FALSE);
1813 return 0;
1814 }
1815
1816 void NativeWidgetWin::OnSetFocus(HWND focused_window) {
1817 delegate_->OnNativeFocus(focused_window);
1818 InputMethod* input_method = GetWidget()->GetInputMethodDirect();
1819 if (input_method)
1820 input_method->OnFocus();
1821 SetMsgHandled(FALSE);
1822 }
1823
1824 LRESULT NativeWidgetWin::OnSetIcon(UINT size_type, HICON new_icon) {
1825 // This shouldn't hurt even if we're using the native frame.
1826 return DefWindowProcWithRedrawLock(WM_SETICON, size_type,
1827 reinterpret_cast<LPARAM>(new_icon));
1828 }
1829
1830 LRESULT NativeWidgetWin::OnSetText(const wchar_t* text) {
1831 // This shouldn't hurt even if we're using the native frame.
1832 return DefWindowProcWithRedrawLock(WM_SETTEXT, NULL,
1833 reinterpret_cast<LPARAM>(text));
1834 }
1835
1836 void NativeWidgetWin::OnSettingChange(UINT flags, const wchar_t* section) {
1837 if (!GetParent() && (flags == SPI_SETWORKAREA) &&
1838 !GetWidget()->widget_delegate()->WillProcessWorkAreaChange()) {
1839 // Fire a dummy SetWindowPos() call, so we'll trip the code in
1840 // OnWindowPosChanging() below that notices work area changes.
1841 ::SetWindowPos(GetNativeView(), 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
1842 SWP_NOZORDER | SWP_NOREDRAW | SWP_NOACTIVATE | SWP_NOOWNERZORDER);
1843 SetMsgHandled(TRUE);
1844 } else {
1845 // TODO(beng): move to Widget.
1846 if (flags == SPI_SETWORKAREA)
1847 GetWidget()->widget_delegate()->OnWorkAreaChanged();
1848 SetMsgHandled(FALSE);
1849 }
1850 }
1851
1852 void NativeWidgetWin::OnSize(UINT param, const CSize& size) {
1853 RedrawWindow(GetNativeView(), NULL, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN);
1854 // ResetWindowRegion is going to trigger WM_NCPAINT. By doing it after we've
1855 // invoked OnSize we ensure the RootView has been laid out.
1856 ResetWindowRegion(false);
1857 }
1858
1859 void NativeWidgetWin::OnSysCommand(UINT notification_code, CPoint click) {
1860 if (!GetWidget()->non_client_view())
1861 return;
1862
1863 // Windows uses the 4 lower order bits of |notification_code| for type-
1864 // specific information so we must exclude this when comparing.
1865 static const int sc_mask = 0xFFF0;
1866 // Ignore size/move/maximize in fullscreen mode.
1867 if (IsFullscreen() &&
1868 (((notification_code & sc_mask) == SC_SIZE) ||
1869 ((notification_code & sc_mask) == SC_MOVE) ||
1870 ((notification_code & sc_mask) == SC_MAXIMIZE)))
1871 return;
1872 if (!GetWidget()->ShouldUseNativeFrame()) {
1873 if ((notification_code & sc_mask) == SC_MINIMIZE ||
1874 (notification_code & sc_mask) == SC_MAXIMIZE ||
1875 (notification_code & sc_mask) == SC_RESTORE) {
1876 GetWidget()->non_client_view()->ResetWindowControls();
1877 } else if ((notification_code & sc_mask) == SC_MOVE ||
1878 (notification_code & sc_mask) == SC_SIZE) {
1879 if (!IsVisible()) {
1880 // Circumvent ScopedRedrawLocks and force visibility before entering a
1881 // resize or move modal loop to get continuous sizing/moving feedback.
1882 SetWindowLong(GWL_STYLE, GetWindowLong(GWL_STYLE) | WS_VISIBLE);
1883 }
1884 }
1885 }
1886
1887 // Handle SC_KEYMENU, which means that the user has pressed the ALT
1888 // key and released it, so we should focus the menu bar.
1889 if ((notification_code & sc_mask) == SC_KEYMENU && click.x == 0) {
1890 // Retrieve the status of shift and control keys to prevent consuming
1891 // shift+alt keys, which are used by Windows to change input languages.
1892 ui::Accelerator accelerator(ui::KeyboardCodeForWindowsKeyCode(VK_MENU),
1893 !!(GetKeyState(VK_SHIFT) & 0x8000),
1894 !!(GetKeyState(VK_CONTROL) & 0x8000),
1895 false);
1896 GetWidget()->GetFocusManager()->ProcessAccelerator(accelerator);
1897 return;
1898 }
1899
1900 // If the delegate can't handle it, the system implementation will be called.
1901 if (!delegate_->ExecuteCommand(notification_code)) {
1902 DefWindowProc(GetNativeView(), WM_SYSCOMMAND, notification_code,
1903 MAKELPARAM(click.x, click.y));
1904 }
1905 }
1906
1907 void NativeWidgetWin::OnThemeChanged() {
1908 // Notify NativeThemeWin.
1909 gfx::NativeThemeWin::instance()->CloseHandles();
1910 }
1911
1912 void NativeWidgetWin::OnVScroll(int scroll_type,
1913 short position,
1914 HWND scrollbar) {
1915 SetMsgHandled(FALSE);
1916 }
1917
1918 void NativeWidgetWin::OnWindowPosChanging(WINDOWPOS* window_pos) {
1919 if (ignore_window_pos_changes_) {
1920 // If somebody's trying to toggle our visibility, change the nonclient area,
1921 // change our Z-order, or activate us, we should probably let it go through.
1922 if (!(window_pos->flags & ((IsVisible() ? SWP_HIDEWINDOW : SWP_SHOWWINDOW) |
1923 SWP_FRAMECHANGED)) &&
1924 (window_pos->flags & (SWP_NOZORDER | SWP_NOACTIVATE))) {
1925 // Just sizing/moving the window; ignore.
1926 window_pos->flags |= SWP_NOSIZE | SWP_NOMOVE | SWP_NOREDRAW;
1927 window_pos->flags &= ~(SWP_SHOWWINDOW | SWP_HIDEWINDOW);
1928 }
1929 } else if (!GetParent()) {
1930 CRect window_rect;
1931 HMONITOR monitor;
1932 gfx::Rect monitor_rect, work_area;
1933 if (GetWindowRect(&window_rect) &&
1934 GetMonitorAndRects(window_rect, &monitor, &monitor_rect, &work_area)) {
1935 if (monitor && (monitor == last_monitor_) &&
1936 (IsFullscreen() || ((monitor_rect == last_monitor_rect_) &&
1937 (work_area != last_work_area_)))) {
1938 // A rect for the monitor we're on changed. Normally Windows notifies
1939 // us about this (and thus we're reaching here due to the SetWindowPos()
1940 // call in OnSettingChange() above), but with some software (e.g.
1941 // nVidia's nView desktop manager) the work area can change asynchronous
1942 // to any notification, and we're just sent a SetWindowPos() call with a
1943 // new (frequently incorrect) position/size. In either case, the best
1944 // response is to throw away the existing position/size information in
1945 // |window_pos| and recalculate it based on the new work rect.
1946 gfx::Rect new_window_rect;
1947 if (IsFullscreen()) {
1948 new_window_rect = monitor_rect;
1949 } else if (IsZoomed()) {
1950 new_window_rect = work_area;
1951 int border_thickness = GetSystemMetrics(SM_CXSIZEFRAME);
1952 new_window_rect.Inset(-border_thickness, -border_thickness);
1953 } else {
1954 new_window_rect = gfx::Rect(window_rect).AdjustToFit(work_area);
1955 }
1956 window_pos->x = new_window_rect.x();
1957 window_pos->y = new_window_rect.y();
1958 window_pos->cx = new_window_rect.width();
1959 window_pos->cy = new_window_rect.height();
1960 // WARNING! Don't set SWP_FRAMECHANGED here, it breaks moving the child
1961 // HWNDs for some reason.
1962 window_pos->flags &= ~(SWP_NOSIZE | SWP_NOMOVE | SWP_NOREDRAW);
1963 window_pos->flags |= SWP_NOCOPYBITS;
1964
1965 // Now ignore all immediately-following SetWindowPos() changes. Windows
1966 // likes to (incorrectly) recalculate what our position/size should be
1967 // and send us further updates.
1968 ignore_window_pos_changes_ = true;
1969 DCHECK(!ignore_pos_changes_factory_.HasWeakPtrs());
1970 MessageLoop::current()->PostTask(
1971 FROM_HERE,
1972 base::Bind(&NativeWidgetWin::StopIgnoringPosChanges,
1973 ignore_pos_changes_factory_.GetWeakPtr()));
1974 }
1975 last_monitor_ = monitor;
1976 last_monitor_rect_ = monitor_rect;
1977 last_work_area_ = work_area;
1978 }
1979 }
1980
1981 if (force_hidden_count_) {
1982 // Prevent the window from being made visible if we've been asked to do so.
1983 // See comment in header as to why we might want this.
1984 window_pos->flags &= ~SWP_SHOWWINDOW;
1985 }
1986
1987 // When WM_WINDOWPOSCHANGING message is handled by DefWindowProc, it will
1988 // enforce (cx, cy) not to be smaller than (6, 6) for any non-popup window.
1989 // We work around this by changing cy back to our intended value.
1990 if (!GetParent() && ~(window_pos->flags & SWP_NOSIZE) && window_pos->cy < 6) {
1991 LONG old_cy = window_pos->cy;
1992 DefWindowProc(GetNativeView(), WM_WINDOWPOSCHANGING, 0,
1993 reinterpret_cast<LPARAM>(window_pos));
1994 window_pos->cy = old_cy;
1995 SetMsgHandled(TRUE);
1996 return;
1997 }
1998
1999 SetMsgHandled(FALSE);
2000 }
2001
2002 void NativeWidgetWin::OnWindowPosChanged(WINDOWPOS* window_pos) {
2003 if (DidClientAreaSizeChange(window_pos))
2004 ClientAreaSizeChanged();
2005 if (window_pos->flags & SWP_SHOWWINDOW)
2006 delegate_->OnNativeWidgetVisibilityChanged(true);
2007 else if (window_pos->flags & SWP_HIDEWINDOW)
2008 delegate_->OnNativeWidgetVisibilityChanged(false);
2009 SetMsgHandled(FALSE);
2010 }
2011
2012 void NativeWidgetWin::OnFinalMessage(HWND window) {
2013 // We don't destroy props in WM_DESTROY as we may still get messages after
2014 // WM_DESTROY that assume the properties are still valid (such as WM_CLOSE).
2015 props_.reset();
2016 delegate_->OnNativeWidgetDestroyed();
2017 if (ownership_ == Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET)
2018 delete this;
2019 }
2020
2021 ////////////////////////////////////////////////////////////////////////////////
2022 // NativeWidgetWin, protected:
2023
2024 int NativeWidgetWin::GetShowState() const {
2025 return SW_SHOWNORMAL;
2026 }
2027
2028 gfx::Insets NativeWidgetWin::GetClientAreaInsets() const {
2029 // Returning an empty Insets object causes the default handling in
2030 // NativeWidgetWin::OnNCCalcSize() to be invoked.
2031 if (!has_non_client_view_ || GetWidget()->ShouldUseNativeFrame())
2032 return gfx::Insets();
2033
2034 if (IsMaximized()) {
2035 // Windows automatically adds a standard width border to all sides when a
2036 // window is maximized.
2037 int border_thickness = GetSystemMetrics(SM_CXSIZEFRAME);
2038 return gfx::Insets(border_thickness, border_thickness, border_thickness,
2039 border_thickness);
2040 }
2041 // This is weird, but highly essential. If we don't offset the bottom edge
2042 // of the client rect, the window client area and window area will match,
2043 // and when returning to glass rendering mode from non-glass, the client
2044 // area will not paint black as transparent. This is because (and I don't
2045 // know why) the client area goes from matching the window rect to being
2046 // something else. If the client area is not the window rect in both
2047 // modes, the blackness doesn't occur. Because of this, we need to tell
2048 // the RootView to lay out to fit the window rect, rather than the client
2049 // rect when using the opaque frame.
2050 // Note: this is only required for non-fullscreen windows. Note that
2051 // fullscreen windows are in restored state, not maximized.
2052 return gfx::Insets(0, 0, IsFullscreen() ? 0 : 1, 0);
2053 }
2054
2055 void NativeWidgetWin::TrackMouseEvents(DWORD mouse_tracking_flags) {
2056 // Begin tracking mouse events for this HWND so that we get WM_MOUSELEAVE
2057 // when the user moves the mouse outside this HWND's bounds.
2058 if (active_mouse_tracking_flags_ == 0 || mouse_tracking_flags & TME_CANCEL) {
2059 if (mouse_tracking_flags & TME_CANCEL) {
2060 // We're about to cancel active mouse tracking, so empty out the stored
2061 // state.
2062 active_mouse_tracking_flags_ = 0;
2063 } else {
2064 active_mouse_tracking_flags_ = mouse_tracking_flags;
2065 }
2066
2067 TRACKMOUSEEVENT tme;
2068 tme.cbSize = sizeof(tme);
2069 tme.dwFlags = mouse_tracking_flags;
2070 tme.hwndTrack = hwnd();
2071 tme.dwHoverTime = 0;
2072 TrackMouseEvent(&tme);
2073 } else if (mouse_tracking_flags != active_mouse_tracking_flags_) {
2074 TrackMouseEvents(active_mouse_tracking_flags_ | TME_CANCEL);
2075 TrackMouseEvents(mouse_tracking_flags);
2076 }
2077 }
2078
2079 void NativeWidgetWin::OnScreenReaderDetected() {
2080 screen_reader_active_ = true;
2081 }
2082
2083 void NativeWidgetWin::SetInitialFocus() {
2084 if (!GetWidget()->SetInitialFocus() &&
2085 !(GetWindowLong(GWL_EXSTYLE) & WS_EX_TRANSPARENT) &&
2086 !(GetWindowLong(GWL_EXSTYLE) & WS_EX_NOACTIVATE)) {
2087 // The window does not get keyboard messages unless we focus it.
2088 SetFocus(GetNativeView());
2089 }
2090 }
2091
2092 void NativeWidgetWin::ExecuteSystemMenuCommand(int command) {
2093 if (command)
2094 SendMessage(GetNativeView(), WM_SYSCOMMAND, command, 0);
2095 }
2096
2097 ////////////////////////////////////////////////////////////////////////////////
2098 // NativeWidgetWin, private:
2099
2100 // static
2101 void NativeWidgetWin::PostProcessActivateMessage(NativeWidgetWin* widget,
2102 int activation_state) {
2103 DCHECK(widget->GetWidget()->is_top_level());
2104 FocusManager* focus_manager = widget->GetWidget()->GetFocusManager();
2105 if (WA_INACTIVE == activation_state) {
2106 // We might get activated/inactivated without being enabled, so we need to
2107 // clear restore_focus_when_enabled_.
2108 widget->restore_focus_when_enabled_ = false;
2109 focus_manager->StoreFocusedView();
2110 } else {
2111 // We must restore the focus after the message has been DefProc'ed as it
2112 // does set the focus to the last focused HWND.
2113 // Note that if the window is not enabled, we cannot restore the focus as
2114 // calling ::SetFocus on a child of the non-enabled top-window would fail.
2115 // This is the case when showing a modal dialog (such as 'open file',
2116 // 'print'...) from a different thread.
2117 // In that case we delay the focus restoration to when the window is enabled
2118 // again.
2119 if (!IsWindowEnabled(widget->GetNativeView())) {
2120 DCHECK(!widget->restore_focus_when_enabled_);
2121 widget->restore_focus_when_enabled_ = true;
2122 return;
2123 }
2124 focus_manager->RestoreFocusedView();
2125 }
2126 }
2127
2128 void NativeWidgetWin::SetInitParams(const Widget::InitParams& params) {
2129 // Set non-style attributes.
2130 ownership_ = params.ownership;
2131
2132 DWORD style = WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
2133 DWORD ex_style = 0;
2134 DWORD class_style = CS_DBLCLKS;
2135
2136 // Set type-independent style attributes.
2137 if (params.child)
2138 style |= WS_CHILD;
2139 if (params.show_state == ui::SHOW_STATE_MAXIMIZED)
2140 style |= WS_MAXIMIZE;
2141 if (params.show_state == ui::SHOW_STATE_MINIMIZED)
2142 style |= WS_MINIMIZE;
2143 if (!params.accept_events)
2144 ex_style |= WS_EX_TRANSPARENT;
2145 if (!params.can_activate)
2146 ex_style |= WS_EX_NOACTIVATE;
2147 if (params.keep_on_top)
2148 ex_style |= WS_EX_TOPMOST;
2149 if (params.mirror_origin_in_rtl)
2150 ex_style |= l10n_util::GetExtendedTooltipStyles();
2151 if (params.transparent)
2152 ex_style |= WS_EX_LAYERED;
2153 if (params.has_dropshadow) {
2154 class_style |= (base::win::GetVersion() < base::win::VERSION_XP) ?
2155 0 : CS_DROPSHADOW;
2156 }
2157
2158 // Set type-dependent style attributes.
2159 switch (params.type) {
2160 case Widget::InitParams::TYPE_WINDOW: {
2161 style |= WS_SYSMENU | WS_CAPTION;
2162 bool can_resize = GetWidget()->widget_delegate()->CanResize();
2163 bool can_maximize = GetWidget()->widget_delegate()->CanMaximize();
2164 if (can_maximize) {
2165 style |= WS_OVERLAPPEDWINDOW;
2166 } else if (can_resize) {
2167 style |= WS_OVERLAPPED | WS_THICKFRAME;
2168 }
2169 if (delegate_->IsDialogBox()) {
2170 style |= DS_MODALFRAME;
2171 // NOTE: Turning this off means we lose the close button, which is bad.
2172 // Turning it on though means the user can maximize or size the window
2173 // from the system menu, which is worse. We may need to provide our own
2174 // menu to get the close button to appear properly.
2175 // style &= ~WS_SYSMENU;
2176
2177 // Set the WS_POPUP style for modal dialogs. This ensures that the owner
2178 // window is activated on destruction. This style should not be set for
2179 // non-modal non-top-level dialogs like constrained windows.
2180 style |= delegate_->IsModal() ? WS_POPUP : 0;
2181 }
2182 ex_style |= delegate_->IsDialogBox() ? WS_EX_DLGMODALFRAME : 0;
2183 break;
2184 }
2185 case Widget::InitParams::TYPE_CONTROL:
2186 style |= WS_VISIBLE;
2187 break;
2188 case Widget::InitParams::TYPE_WINDOW_FRAMELESS:
2189 style |= WS_POPUP;
2190 break;
2191 case Widget::InitParams::TYPE_BUBBLE:
2192 style |= WS_POPUP;
2193 style |= WS_CLIPCHILDREN;
2194 break;
2195 case Widget::InitParams::TYPE_POPUP:
2196 style |= WS_POPUP;
2197 ex_style |= WS_EX_TOOLWINDOW;
2198 break;
2199 case Widget::InitParams::TYPE_MENU:
2200 style |= WS_POPUP;
2201 break;
2202 default:
2203 NOTREACHED();
2204 }
2205
2206 set_initial_class_style(class_style);
2207 set_window_style(window_style() | style);
2208 set_window_ex_style(window_ex_style() | ex_style);
2209
2210 has_non_client_view_ = Widget::RequiresNonClientView(params.type);
2211 }
2212
2213 void NativeWidgetWin::RedrawInvalidRect() {
2214 if (!use_layered_buffer_) {
2215 RECT r = { 0, 0, 0, 0 };
2216 if (GetUpdateRect(hwnd(), &r, FALSE) && !IsRectEmpty(&r)) {
2217 RedrawWindow(hwnd(), &r, NULL,
2218 RDW_INVALIDATE | RDW_UPDATENOW | RDW_NOCHILDREN);
2219 }
2220 }
2221 }
2222
2223 void NativeWidgetWin::RedrawLayeredWindowContents() {
2224 if (invalid_rect_.IsEmpty())
2225 return;
2226
2227 // We need to clip to the dirty rect ourselves.
2228 layered_window_contents_->sk_canvas()->save(SkCanvas::kClip_SaveFlag);
2229 layered_window_contents_->ClipRect(invalid_rect_);
2230 GetWidget()->GetRootView()->Paint(layered_window_contents_.get());
2231 layered_window_contents_->sk_canvas()->restore();
2232
2233 RECT wr;
2234 GetWindowRect(&wr);
2235 SIZE size = {wr.right - wr.left, wr.bottom - wr.top};
2236 POINT position = {wr.left, wr.top};
2237 HDC dib_dc = skia::BeginPlatformPaint(layered_window_contents_->sk_canvas());
2238 POINT zero = {0, 0};
2239 BLENDFUNCTION blend = {AC_SRC_OVER, 0, layered_alpha_, AC_SRC_ALPHA};
2240 UpdateLayeredWindow(hwnd(), NULL, &position, &size, dib_dc, &zero,
2241 RGB(0xFF, 0xFF, 0xFF), &blend, ULW_ALPHA);
2242 invalid_rect_.SetRect(0, 0, 0, 0);
2243 skia::EndPlatformPaint(layered_window_contents_->sk_canvas());
2244 }
2245
2246 void NativeWidgetWin::LockUpdates() {
2247 // We skip locked updates when Aero is on for two reasons:
2248 // 1. Because it isn't necessary
2249 // 2. Because toggling the WS_VISIBLE flag may occur while the GPU process is
2250 // attempting to present a child window's backbuffer onscreen. When these
2251 // two actions race with one another, the child window will either flicker
2252 // or will simply stop updating entirely.
2253 if (!IsAeroGlassEnabled() && ++lock_updates_count_ == 1) {
2254 SetWindowLong(GWL_STYLE, GetWindowLong(GWL_STYLE) & ~WS_VISIBLE);
2255 }
2256 // TODO(msw): Remove nested LockUpdates VLOG info for crbug.com/93530.
2257 VLOG_IF(1, (lock_updates_count_ > 1)) << "Nested LockUpdates call: "
2258 << lock_updates_count_ << " locks for widget " << this;
2259 }
2260
2261 void NativeWidgetWin::UnlockUpdates() {
2262 // TODO(msw): Remove nested LockUpdates VLOG info for crbug.com/93530.
2263 VLOG_IF(1, (lock_updates_count_ > 1)) << "Nested UnlockUpdates call: "
2264 << lock_updates_count_ << " locks for widget " << this;
2265 if (!IsAeroGlassEnabled() && --lock_updates_count_ <= 0) {
2266 SetWindowLong(GWL_STYLE, GetWindowLong(GWL_STYLE) | WS_VISIBLE);
2267 lock_updates_count_ = 0;
2268 }
2269 }
2270
2271 bool NativeWidgetWin::WidgetSizeIsClientSize() const {
2272 const Widget* widget = GetWidget()->GetTopLevelWidget();
2273 return IsZoomed() || (widget && widget->ShouldUseNativeFrame());
2274 }
2275
2276 void NativeWidgetWin::ClientAreaSizeChanged() {
2277 RECT r;
2278 if (WidgetSizeIsClientSize())
2279 GetClientRect(&r);
2280 else
2281 GetWindowRect(&r);
2282 gfx::Size s(std::max(0, static_cast<int>(r.right - r.left)),
2283 std::max(0, static_cast<int>(r.bottom - r.top)));
2284 if (compositor_.get())
2285 compositor_->WidgetSizeChanged(s);
2286 delegate_->OnNativeWidgetSizeChanged(s);
2287 if (use_layered_buffer_) {
2288 layered_window_contents_.reset(
2289 new gfx::CanvasSkia(s.width(), s.height(), false));
2290 }
2291 }
2292
2293 void NativeWidgetWin::ResetWindowRegion(bool force) {
2294 // A native frame uses the native window region, and we don't want to mess
2295 // with it.
2296 if (GetWidget()->ShouldUseNativeFrame() || !GetWidget()->non_client_view()) {
2297 if (force)
2298 SetWindowRgn(NULL, TRUE);
2299 return;
2300 }
2301
2302 // Changing the window region is going to force a paint. Only change the
2303 // window region if the region really differs.
2304 HRGN current_rgn = CreateRectRgn(0, 0, 0, 0);
2305 int current_rgn_result = GetWindowRgn(GetNativeView(), current_rgn);
2306
2307 CRect window_rect;
2308 GetWindowRect(&window_rect);
2309 HRGN new_region;
2310 if (IsMaximized()) {
2311 HMONITOR monitor =
2312 MonitorFromWindow(GetNativeView(), MONITOR_DEFAULTTONEAREST);
2313 MONITORINFO mi;
2314 mi.cbSize = sizeof mi;
2315 GetMonitorInfo(monitor, &mi);
2316 CRect work_rect = mi.rcWork;
2317 work_rect.OffsetRect(-window_rect.left, -window_rect.top);
2318 new_region = CreateRectRgnIndirect(&work_rect);
2319 } else {
2320 gfx::Path window_mask;
2321 GetWidget()->non_client_view()->GetWindowMask(
2322 gfx::Size(window_rect.Width(), window_rect.Height()), &window_mask);
2323 new_region = window_mask.CreateNativeRegion();
2324 }
2325
2326 if (current_rgn_result == ERROR || !EqualRgn(current_rgn, new_region)) {
2327 // SetWindowRgn takes ownership of the HRGN created by CreateNativeRegion.
2328 SetWindowRgn(new_region, TRUE);
2329 } else {
2330 DeleteObject(new_region);
2331 }
2332
2333 DeleteObject(current_rgn);
2334 }
2335
2336 LRESULT NativeWidgetWin::DefWindowProcWithRedrawLock(UINT message,
2337 WPARAM w_param,
2338 LPARAM l_param) {
2339 ScopedRedrawLock lock(this);
2340 // The Widget and HWND can be destroyed in the call to DefWindowProc, so use
2341 // the |destroyed_| flag to avoid unlocking (and crashing) after destruction.
2342 bool destroyed = false;
2343 destroyed_ = &destroyed;
2344 LRESULT result = DefWindowProc(GetNativeView(), message, w_param, l_param);
2345 if (destroyed)
2346 lock.CancelUnlockOperation();
2347 else
2348 destroyed_ = NULL;
2349 return result;
2350 }
2351
2352 void NativeWidgetWin::RestoreEnabledIfNecessary() {
2353 if (delegate_->IsModal() && !restored_enabled_) {
2354 restored_enabled_ = true;
2355 // If we were run modally, we need to undo the disabled-ness we inflicted on
2356 // the owner's parent hierarchy.
2357 HWND start = ::GetWindow(GetNativeView(), GW_OWNER);
2358 while (start) {
2359 ::EnableWindow(start, TRUE);
2360 start = ::GetParent(start);
2361 }
2362 }
2363 }
2364
2365 void NativeWidgetWin::DispatchKeyEventPostIME(const KeyEvent& key) {
2366 SetMsgHandled(delegate_->OnKeyEvent(key));
2367 }
2368
2369 ////////////////////////////////////////////////////////////////////////////////
2370 // Widget, public:
2371
2372 // static
2373 void Widget::NotifyLocaleChanged() {
2374 NOTIMPLEMENTED();
2375 }
2376
2377 namespace {
2378 BOOL CALLBACK WindowCallbackProc(HWND hwnd, LPARAM lParam) {
2379 Widget* widget = Widget::GetWidgetForNativeView(hwnd);
2380 if (widget && widget->is_secondary_widget())
2381 widget->Close();
2382 return TRUE;
2383 }
2384 } // namespace
2385
2386 // static
2387 void Widget::CloseAllSecondaryWidgets() {
2388 EnumThreadWindows(GetCurrentThreadId(), WindowCallbackProc, 0);
2389 }
2390
2391 bool Widget::ConvertRect(const Widget* source,
2392 const Widget* target,
2393 gfx::Rect* rect) {
2394 DCHECK(source);
2395 DCHECK(target);
2396 DCHECK(rect);
2397
2398 HWND source_hwnd = source->GetNativeView();
2399 HWND target_hwnd = target->GetNativeView();
2400 if (source_hwnd == target_hwnd)
2401 return true;
2402
2403 RECT win_rect = rect->ToRECT();
2404 if (::MapWindowPoints(source_hwnd, target_hwnd,
2405 reinterpret_cast<LPPOINT>(&win_rect),
2406 sizeof(RECT)/sizeof(POINT))) {
2407 *rect = win_rect;
2408 return true;
2409 }
2410 return false;
2411 }
2412
2413 namespace internal {
2414
2415 ////////////////////////////////////////////////////////////////////////////////
2416 // internal::NativeWidgetPrivate, public:
2417
2418 // static
2419 NativeWidgetPrivate* NativeWidgetPrivate::CreateNativeWidget(
2420 internal::NativeWidgetDelegate* delegate) {
2421 return new NativeWidgetWin(delegate);
2422 }
2423
2424 // static
2425 NativeWidgetPrivate* NativeWidgetPrivate::GetNativeWidgetForNativeView(
2426 gfx::NativeView native_view) {
2427 return reinterpret_cast<NativeWidgetWin*>(
2428 ViewProp::GetValue(native_view, kNativeWidgetKey));
2429 }
2430
2431 // static
2432 NativeWidgetPrivate* NativeWidgetPrivate::GetNativeWidgetForNativeWindow(
2433 gfx::NativeWindow native_window) {
2434 return GetNativeWidgetForNativeView(native_window);
2435 }
2436
2437 // static
2438 NativeWidgetPrivate* NativeWidgetPrivate::GetTopLevelNativeWidget(
2439 gfx::NativeView native_view) {
2440 if (!native_view)
2441 return NULL;
2442
2443 // First, check if the top-level window is a Widget.
2444 HWND root = ::GetAncestor(native_view, GA_ROOT);
2445 if (!root)
2446 return NULL;
2447
2448 NativeWidgetPrivate* widget = GetNativeWidgetForNativeView(root);
2449 if (widget)
2450 return widget;
2451
2452 // Second, try to locate the last Widget window in the parent hierarchy.
2453 HWND parent_hwnd = native_view;
2454 // If we fail to find the native widget pointer for the root then it probably
2455 // means that the root belongs to a different process in which case we walk up
2456 // the native view chain looking for a parent window which corresponds to a
2457 // valid native widget. We only do this if we fail to find the native widget
2458 // for the current native view which means it is being destroyed.
2459 if (!widget && !GetNativeWidgetForNativeView(native_view)) {
2460 parent_hwnd = ::GetAncestor(parent_hwnd, GA_PARENT);
2461 if (!parent_hwnd)
2462 return NULL;
2463 }
2464 NativeWidgetPrivate* parent_widget;
2465 do {
2466 parent_widget = GetNativeWidgetForNativeView(parent_hwnd);
2467 if (parent_widget) {
2468 widget = parent_widget;
2469 parent_hwnd = ::GetAncestor(parent_hwnd, GA_PARENT);
2470 }
2471 } while (parent_hwnd != NULL && parent_widget != NULL);
2472
2473 return widget;
2474 }
2475
2476 // static
2477 void NativeWidgetPrivate::GetAllChildWidgets(gfx::NativeView native_view,
2478 Widget::Widgets* children) {
2479 if (!native_view)
2480 return;
2481
2482 Widget* widget = Widget::GetWidgetForNativeView(native_view);
2483 if (widget)
2484 children->insert(widget);
2485 EnumChildWindows(native_view, EnumerateChildWindowsForNativeWidgets,
2486 reinterpret_cast<LPARAM>(children));
2487 }
2488
2489 // static
2490 void NativeWidgetPrivate::ReparentNativeView(gfx::NativeView native_view,
2491 gfx::NativeView new_parent) {
2492 if (!native_view)
2493 return;
2494
2495 HWND previous_parent = ::GetParent(native_view);
2496 if (previous_parent == new_parent)
2497 return;
2498
2499 Widget::Widgets widgets;
2500 GetAllChildWidgets(native_view, &widgets);
2501
2502 // First notify all the widgets that they are being disassociated
2503 // from their previous parent.
2504 for (Widget::Widgets::iterator it = widgets.begin();
2505 it != widgets.end(); ++it) {
2506 // TODO(beng): Rename this notification to NotifyNativeViewChanging()
2507 // and eliminate the bool parameter.
2508 (*it)->NotifyNativeViewHierarchyChanged(false, previous_parent);
2509 }
2510
2511 ::SetParent(native_view, new_parent);
2512
2513 // And now, notify them that they have a brand new parent.
2514 for (Widget::Widgets::iterator it = widgets.begin();
2515 it != widgets.end(); ++it) {
2516 (*it)->NotifyNativeViewHierarchyChanged(true, new_parent);
2517 }
2518 }
2519
2520 // static
2521 bool NativeWidgetPrivate::IsMouseButtonDown() {
2522 return (GetKeyState(VK_LBUTTON) & 0x80) ||
2523 (GetKeyState(VK_RBUTTON) & 0x80) ||
2524 (GetKeyState(VK_MBUTTON) & 0x80) ||
2525 (GetKeyState(VK_XBUTTON1) & 0x80) ||
2526 (GetKeyState(VK_XBUTTON2) & 0x80);
2527 }
2528
2529 } // namespace internal
2530
2531 } // namespace views
OLDNEW
« no previous file with comments | « ui/views/widget/native_widget_win.h ('k') | ui/views/widget/native_widget_win_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698