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