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

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

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

Powered by Google App Engine
This is Rietveld 408576698