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