Home | History | Annotate | Download | only in win
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "ui/views/win/hwnd_message_handler.h"
      6 
      7 #include <dwmapi.h>
      8 #include <shellapi.h>
      9 #include <wtsapi32.h>
     10 #pragma comment(lib, "wtsapi32.lib")
     11 
     12 #include "base/bind.h"
     13 #include "base/debug/trace_event.h"
     14 #include "base/win/win_util.h"
     15 #include "base/win/windows_version.h"
     16 #include "ui/base/touch/touch_enabled.h"
     17 #include "ui/base/win/lock_state.h"
     18 #include "ui/base/win/mouse_wheel_util.h"
     19 #include "ui/base/win/shell.h"
     20 #include "ui/base/win/touch_input.h"
     21 #include "ui/events/event.h"
     22 #include "ui/events/event_utils.h"
     23 #include "ui/events/gestures/gesture_sequence.h"
     24 #include "ui/events/keycodes/keyboard_code_conversion_win.h"
     25 #include "ui/gfx/canvas.h"
     26 #include "ui/gfx/canvas_skia_paint.h"
     27 #include "ui/gfx/icon_util.h"
     28 #include "ui/gfx/insets.h"
     29 #include "ui/gfx/path.h"
     30 #include "ui/gfx/path_win.h"
     31 #include "ui/gfx/screen.h"
     32 #include "ui/gfx/win/dpi.h"
     33 #include "ui/gfx/win/hwnd_util.h"
     34 #include "ui/native_theme/native_theme_win.h"
     35 #include "ui/views/views_delegate.h"
     36 #include "ui/views/widget/monitor_win.h"
     37 #include "ui/views/widget/native_widget_win.h"
     38 #include "ui/views/widget/widget_hwnd_utils.h"
     39 #include "ui/views/win/appbar.h"
     40 #include "ui/views/win/fullscreen_handler.h"
     41 #include "ui/views/win/hwnd_message_handler_delegate.h"
     42 #include "ui/views/win/scoped_fullscreen_visibility.h"
     43 
     44 #if !defined(USE_AURA)
     45 #include "ui/views/accessibility/native_view_accessibility_win.h"
     46 #include "ui/views/widget/child_window_message_processor.h"
     47 #endif
     48 
     49 namespace views {
     50 namespace {
     51 
     52 // MoveLoopMouseWatcher is used to determine if the user canceled or completed a
     53 // move. win32 doesn't appear to offer a way to determine the result of a move,
     54 // so we install hooks to determine if we got a mouse up and assume the move
     55 // completed.
     56 class MoveLoopMouseWatcher {
     57  public:
     58   MoveLoopMouseWatcher(HWNDMessageHandler* host, bool hide_on_escape);
     59   ~MoveLoopMouseWatcher();
     60 
     61   // Returns true if the mouse is up, or if we couldn't install the hook.
     62   bool got_mouse_up() const { return got_mouse_up_; }
     63 
     64  private:
     65   // Instance that owns the hook. We only allow one instance to hook the mouse
     66   // at a time.
     67   static MoveLoopMouseWatcher* instance_;
     68 
     69   // Key and mouse callbacks from the hook.
     70   static LRESULT CALLBACK MouseHook(int n_code, WPARAM w_param, LPARAM l_param);
     71   static LRESULT CALLBACK KeyHook(int n_code, WPARAM w_param, LPARAM l_param);
     72 
     73   void Unhook();
     74 
     75   // HWNDMessageHandler that created us.
     76   HWNDMessageHandler* host_;
     77 
     78   // Should the window be hidden when escape is pressed?
     79   const bool hide_on_escape_;
     80 
     81   // Did we get a mouse up?
     82   bool got_mouse_up_;
     83 
     84   // Hook identifiers.
     85   HHOOK mouse_hook_;
     86   HHOOK key_hook_;
     87 
     88   DISALLOW_COPY_AND_ASSIGN(MoveLoopMouseWatcher);
     89 };
     90 
     91 // static
     92 MoveLoopMouseWatcher* MoveLoopMouseWatcher::instance_ = NULL;
     93 
     94 MoveLoopMouseWatcher::MoveLoopMouseWatcher(HWNDMessageHandler* host,
     95                                            bool hide_on_escape)
     96     : host_(host),
     97       hide_on_escape_(hide_on_escape),
     98       got_mouse_up_(false),
     99       mouse_hook_(NULL),
    100       key_hook_(NULL) {
    101   // Only one instance can be active at a time.
    102   if (instance_)
    103     instance_->Unhook();
    104 
    105   mouse_hook_ = SetWindowsHookEx(
    106       WH_MOUSE, &MouseHook, NULL, GetCurrentThreadId());
    107   if (mouse_hook_) {
    108     instance_ = this;
    109     // We don't care if setting the key hook succeeded.
    110     key_hook_ = SetWindowsHookEx(
    111         WH_KEYBOARD, &KeyHook, NULL, GetCurrentThreadId());
    112   }
    113   if (instance_ != this) {
    114     // Failed installation. Assume we got a mouse up in this case, otherwise
    115     // we'll think all drags were canceled.
    116     got_mouse_up_ = true;
    117   }
    118 }
    119 
    120 MoveLoopMouseWatcher::~MoveLoopMouseWatcher() {
    121   Unhook();
    122 }
    123 
    124 void MoveLoopMouseWatcher::Unhook() {
    125   if (instance_ != this)
    126     return;
    127 
    128   DCHECK(mouse_hook_);
    129   UnhookWindowsHookEx(mouse_hook_);
    130   if (key_hook_)
    131     UnhookWindowsHookEx(key_hook_);
    132   key_hook_ = NULL;
    133   mouse_hook_ = NULL;
    134   instance_ = NULL;
    135 }
    136 
    137 // static
    138 LRESULT CALLBACK MoveLoopMouseWatcher::MouseHook(int n_code,
    139                                                  WPARAM w_param,
    140                                                  LPARAM l_param) {
    141   DCHECK(instance_);
    142   if (n_code == HC_ACTION && w_param == WM_LBUTTONUP)
    143     instance_->got_mouse_up_ = true;
    144   return CallNextHookEx(instance_->mouse_hook_, n_code, w_param, l_param);
    145 }
    146 
    147 // static
    148 LRESULT CALLBACK MoveLoopMouseWatcher::KeyHook(int n_code,
    149                                                WPARAM w_param,
    150                                                LPARAM l_param) {
    151   if (n_code == HC_ACTION && w_param == VK_ESCAPE) {
    152     if (base::win::GetVersion() >= base::win::VERSION_VISTA) {
    153       int value = TRUE;
    154       HRESULT result = DwmSetWindowAttribute(
    155           instance_->host_->hwnd(),
    156           DWMWA_TRANSITIONS_FORCEDISABLED,
    157           &value,
    158           sizeof(value));
    159     }
    160     if (instance_->hide_on_escape_)
    161       instance_->host_->Hide();
    162   }
    163   return CallNextHookEx(instance_->key_hook_, n_code, w_param, l_param);
    164 }
    165 
    166 // Called from OnNCActivate.
    167 BOOL CALLBACK EnumChildWindowsForRedraw(HWND hwnd, LPARAM lparam) {
    168   DWORD process_id;
    169   GetWindowThreadProcessId(hwnd, &process_id);
    170   int flags = RDW_INVALIDATE | RDW_NOCHILDREN | RDW_FRAME;
    171   if (process_id == GetCurrentProcessId())
    172     flags |= RDW_UPDATENOW;
    173   RedrawWindow(hwnd, NULL, NULL, flags);
    174   return TRUE;
    175 }
    176 
    177 bool GetMonitorAndRects(const RECT& rect,
    178                         HMONITOR* monitor,
    179                         gfx::Rect* monitor_rect,
    180                         gfx::Rect* work_area) {
    181   DCHECK(monitor);
    182   DCHECK(monitor_rect);
    183   DCHECK(work_area);
    184   *monitor = MonitorFromRect(&rect, MONITOR_DEFAULTTONULL);
    185   if (!*monitor)
    186     return false;
    187   MONITORINFO monitor_info = { 0 };
    188   monitor_info.cbSize = sizeof(monitor_info);
    189   base::win::GetMonitorInfoWrapper(*monitor, &monitor_info);
    190   *monitor_rect = gfx::Rect(monitor_info.rcMonitor);
    191   *work_area = gfx::Rect(monitor_info.rcWork);
    192   return true;
    193 }
    194 
    195 struct FindOwnedWindowsData {
    196   HWND window;
    197   std::vector<Widget*> owned_widgets;
    198 };
    199 
    200 BOOL CALLBACK FindOwnedWindowsCallback(HWND hwnd, LPARAM param) {
    201   // TODO(beng): resolve wrt aura.
    202 #if !defined(USE_AURA)
    203   FindOwnedWindowsData* data = reinterpret_cast<FindOwnedWindowsData*>(param);
    204   if (GetWindow(hwnd, GW_OWNER) == data->window) {
    205     Widget* widget = Widget::GetWidgetForNativeView(hwnd);
    206     if (widget)
    207       data->owned_widgets.push_back(widget);
    208   }
    209 #endif
    210   return TRUE;
    211 }
    212 
    213 // Enables or disables the menu item for the specified command and menu.
    214 void EnableMenuItemByCommand(HMENU menu, UINT command, bool enabled) {
    215   UINT flags = MF_BYCOMMAND | (enabled ? MF_ENABLED : MF_DISABLED | MF_GRAYED);
    216   EnableMenuItem(menu, command, flags);
    217 }
    218 
    219 // Callback used to notify child windows that the top level window received a
    220 // DWMCompositionChanged message.
    221 BOOL CALLBACK SendDwmCompositionChanged(HWND window, LPARAM param) {
    222   SendMessage(window, WM_DWMCOMPOSITIONCHANGED, 0, 0);
    223   return TRUE;
    224 }
    225 
    226 // See comments in OnNCPaint() for details of this struct.
    227 struct ClipState {
    228   // The window being painted.
    229   HWND parent;
    230 
    231   // DC painting to.
    232   HDC dc;
    233 
    234   // Origin of the window in terms of the screen.
    235   int x;
    236   int y;
    237 };
    238 
    239 // See comments in OnNCPaint() for details of this function.
    240 static BOOL CALLBACK ClipDCToChild(HWND window, LPARAM param) {
    241   ClipState* clip_state = reinterpret_cast<ClipState*>(param);
    242   if (GetParent(window) == clip_state->parent && IsWindowVisible(window)) {
    243     RECT bounds;
    244     GetWindowRect(window, &bounds);
    245     ExcludeClipRect(clip_state->dc,
    246       bounds.left - clip_state->x,
    247       bounds.top - clip_state->y,
    248       bounds.right - clip_state->x,
    249       bounds.bottom - clip_state->y);
    250   }
    251   return TRUE;
    252 }
    253 
    254 #if !defined(USE_AURA)
    255 
    256 // Get the source HWND of the specified message. Depending on the message, the
    257 // source HWND is encoded in either the WPARAM or the LPARAM value.
    258 HWND GetControlHWNDForMessage(UINT message, WPARAM w_param, LPARAM l_param) {
    259   // Each of the following messages can be sent by a child HWND and must be
    260   // forwarded to its associated NativeControlWin for handling.
    261   switch (message) {
    262     case WM_NOTIFY:
    263       return reinterpret_cast<NMHDR*>(l_param)->hwndFrom;
    264     case WM_COMMAND:
    265       return reinterpret_cast<HWND>(l_param);
    266     case WM_CONTEXTMENU:
    267       return reinterpret_cast<HWND>(w_param);
    268     case WM_CTLCOLORBTN:
    269     case WM_CTLCOLORSTATIC:
    270       return reinterpret_cast<HWND>(l_param);
    271   }
    272   return NULL;
    273 }
    274 
    275 // Some messages may be sent to us by a child HWND. If this is the case, this
    276 // function will forward those messages on to the object associated with the
    277 // source HWND and return true, in which case the window procedure must not do
    278 // any further processing of the message. If there is no associated
    279 // ChildWindowMessageProcessor, the return value will be false and the WndProc
    280 // can continue processing the message normally.  |l_result| contains the result
    281 // of the message processing by the control and must be returned by the WndProc
    282 // if the return value is true.
    283 bool ProcessChildWindowMessage(UINT message,
    284                                WPARAM w_param,
    285                                LPARAM l_param,
    286                                LRESULT* l_result) {
    287   *l_result = 0;
    288 
    289   HWND control_hwnd = GetControlHWNDForMessage(message, w_param, l_param);
    290   if (IsWindow(control_hwnd)) {
    291     ChildWindowMessageProcessor* processor =
    292         ChildWindowMessageProcessor::Get(control_hwnd);
    293     if (processor)
    294       return processor->ProcessMessage(message, w_param, l_param, l_result);
    295   }
    296 
    297   return false;
    298 }
    299 
    300 #endif
    301 
    302 // The thickness of an auto-hide taskbar in pixels.
    303 const int kAutoHideTaskbarThicknessPx = 2;
    304 
    305 bool IsTopLevelWindow(HWND window) {
    306   long style = ::GetWindowLong(window, GWL_STYLE);
    307   if (!(style & WS_CHILD))
    308     return true;
    309   HWND parent = ::GetParent(window);
    310   return !parent || (parent == ::GetDesktopWindow());
    311 }
    312 
    313 void AddScrollStylesToWindow(HWND window) {
    314   if (::IsWindow(window)) {
    315     long current_style = ::GetWindowLong(window, GWL_STYLE);
    316     ::SetWindowLong(window, GWL_STYLE,
    317                     current_style | WS_VSCROLL | WS_HSCROLL);
    318   }
    319 }
    320 
    321 }  // namespace
    322 
    323 // A scoping class that prevents a window from being able to redraw in response
    324 // to invalidations that may occur within it for the lifetime of the object.
    325 //
    326 // Why would we want such a thing? Well, it turns out Windows has some
    327 // "unorthodox" behavior when it comes to painting its non-client areas.
    328 // Occasionally, Windows will paint portions of the default non-client area
    329 // right over the top of the custom frame. This is not simply fixed by handling
    330 // WM_NCPAINT/WM_PAINT, with some investigation it turns out that this
    331 // rendering is being done *inside* the default implementation of some message
    332 // handlers and functions:
    333 //  . WM_SETTEXT
    334 //  . WM_SETICON
    335 //  . WM_NCLBUTTONDOWN
    336 //  . EnableMenuItem, called from our WM_INITMENU handler
    337 // The solution is to handle these messages and call DefWindowProc ourselves,
    338 // but prevent the window from being able to update itself for the duration of
    339 // the call. We do this with this class, which automatically calls its
    340 // associated Window's lock and unlock functions as it is created and destroyed.
    341 // See documentation in those methods for the technique used.
    342 //
    343 // The lock only has an effect if the window was visible upon lock creation, as
    344 // it doesn't guard against direct visiblility changes, and multiple locks may
    345 // exist simultaneously to handle certain nested Windows messages.
    346 //
    347 // IMPORTANT: Do not use this scoping object for large scopes or periods of
    348 //            time! IT WILL PREVENT THE WINDOW FROM BEING REDRAWN! (duh).
    349 //
    350 // I would love to hear Raymond Chen's explanation for all this. And maybe a
    351 // list of other messages that this applies to ;-)
    352 class HWNDMessageHandler::ScopedRedrawLock {
    353  public:
    354   explicit ScopedRedrawLock(HWNDMessageHandler* owner)
    355     : owner_(owner),
    356       hwnd_(owner_->hwnd()),
    357       was_visible_(owner_->IsVisible()),
    358       cancel_unlock_(false),
    359       force_(!(GetWindowLong(hwnd_, GWL_STYLE) & WS_CAPTION)) {
    360     if (was_visible_ && ::IsWindow(hwnd_))
    361       owner_->LockUpdates(force_);
    362   }
    363 
    364   ~ScopedRedrawLock() {
    365     if (!cancel_unlock_ && was_visible_ && ::IsWindow(hwnd_))
    366       owner_->UnlockUpdates(force_);
    367   }
    368 
    369   // Cancel the unlock operation, call this if the Widget is being destroyed.
    370   void CancelUnlockOperation() { cancel_unlock_ = true; }
    371 
    372  private:
    373   // The owner having its style changed.
    374   HWNDMessageHandler* owner_;
    375   // The owner's HWND, cached to avoid action after window destruction.
    376   HWND hwnd_;
    377   // Records the HWND visibility at the time of creation.
    378   bool was_visible_;
    379   // A flag indicating that the unlock operation was canceled.
    380   bool cancel_unlock_;
    381   // If true, perform the redraw lock regardless of Aero state.
    382   bool force_;
    383 
    384   DISALLOW_COPY_AND_ASSIGN(ScopedRedrawLock);
    385 };
    386 
    387 ////////////////////////////////////////////////////////////////////////////////
    388 // HWNDMessageHandler, public:
    389 
    390 HWNDMessageHandler::HWNDMessageHandler(HWNDMessageHandlerDelegate* delegate)
    391     : delegate_(delegate),
    392       fullscreen_handler_(new FullscreenHandler),
    393       weak_factory_(this),
    394       waiting_for_close_now_(false),
    395       remove_standard_frame_(false),
    396       use_system_default_icon_(false),
    397       restore_focus_when_enabled_(false),
    398       restored_enabled_(false),
    399       current_cursor_(NULL),
    400       previous_cursor_(NULL),
    401       active_mouse_tracking_flags_(0),
    402       is_right_mouse_pressed_on_caption_(false),
    403       lock_updates_count_(0),
    404       ignore_window_pos_changes_(false),
    405       last_monitor_(NULL),
    406       use_layered_buffer_(false),
    407       layered_alpha_(255),
    408       waiting_for_redraw_layered_window_contents_(false),
    409       is_first_nccalc_(true),
    410       autohide_factory_(this),
    411       id_generator_(0),
    412       needs_scroll_styles_(false),
    413       in_size_loop_(false) {
    414 }
    415 
    416 HWNDMessageHandler::~HWNDMessageHandler() {
    417   delegate_ = NULL;
    418   // Prevent calls back into this class via WNDPROC now that we've been
    419   // destroyed.
    420   ClearUserData();
    421 }
    422 
    423 void HWNDMessageHandler::Init(HWND parent, const gfx::Rect& bounds) {
    424   TRACE_EVENT0("views", "HWNDMessageHandler::Init");
    425   GetMonitorAndRects(bounds.ToRECT(), &last_monitor_, &last_monitor_rect_,
    426                      &last_work_area_);
    427 
    428   // Create the window.
    429   WindowImpl::Init(parent, bounds);
    430 
    431 #if defined(USE_AURA)
    432   // Certain trackpad drivers on Windows have bugs where in they don't generate
    433   // WM_MOUSEWHEEL messages for the trackpoint and trackpad scrolling gestures
    434   // unless there is an entry for Chrome with the class name of the Window.
    435   // These drivers check if the window under the trackpoint has the WS_VSCROLL/
    436   // WS_HSCROLL style and if yes they generate the legacy WM_VSCROLL/WM_HSCROLL
    437   // messages. We add these styles to ensure that trackpad/trackpoint scrolling
    438   // work.
    439   // TODO(ananta)
    440   // Look into moving the WS_VSCROLL and WS_HSCROLL style setting logic to the
    441   // CalculateWindowStylesFromInitParams function. Doing it there seems to
    442   // cause some interactive tests to fail. Investigation needed.
    443   if (IsTopLevelWindow(hwnd())) {
    444     long current_style = ::GetWindowLong(hwnd(), GWL_STYLE);
    445     if (!(current_style & WS_POPUP)) {
    446       AddScrollStylesToWindow(hwnd());
    447       needs_scroll_styles_ = true;
    448     }
    449   }
    450 #endif
    451 }
    452 
    453 void HWNDMessageHandler::InitModalType(ui::ModalType modal_type) {
    454   if (modal_type == ui::MODAL_TYPE_NONE)
    455     return;
    456   // We implement modality by crawling up the hierarchy of windows starting
    457   // at the owner, disabling all of them so that they don't receive input
    458   // messages.
    459   HWND start = ::GetWindow(hwnd(), GW_OWNER);
    460   while (start) {
    461     ::EnableWindow(start, FALSE);
    462     start = ::GetParent(start);
    463   }
    464 }
    465 
    466 void HWNDMessageHandler::Close() {
    467   if (!IsWindow(hwnd()))
    468     return;  // No need to do anything.
    469 
    470   // Let's hide ourselves right away.
    471   Hide();
    472 
    473   // Modal dialog windows disable their owner windows; re-enable them now so
    474   // they can activate as foreground windows upon this window's destruction.
    475   RestoreEnabledIfNecessary();
    476 
    477   if (!waiting_for_close_now_) {
    478     // And we delay the close so that if we are called from an ATL callback,
    479     // we don't destroy the window before the callback returned (as the caller
    480     // may delete ourselves on destroy and the ATL callback would still
    481     // dereference us when the callback returns).
    482     waiting_for_close_now_ = true;
    483     base::MessageLoop::current()->PostTask(
    484         FROM_HERE,
    485         base::Bind(&HWNDMessageHandler::CloseNow, weak_factory_.GetWeakPtr()));
    486   }
    487 }
    488 
    489 void HWNDMessageHandler::CloseNow() {
    490   // We may already have been destroyed if the selection resulted in a tab
    491   // switch which will have reactivated the browser window and closed us, so
    492   // we need to check to see if we're still a window before trying to destroy
    493   // ourself.
    494   waiting_for_close_now_ = false;
    495   if (IsWindow(hwnd()))
    496     DestroyWindow(hwnd());
    497 }
    498 
    499 gfx::Rect HWNDMessageHandler::GetWindowBoundsInScreen() const {
    500   RECT r;
    501   GetWindowRect(hwnd(), &r);
    502   return gfx::Rect(r);
    503 }
    504 
    505 gfx::Rect HWNDMessageHandler::GetClientAreaBoundsInScreen() const {
    506   RECT r;
    507   GetClientRect(hwnd(), &r);
    508   POINT point = { r.left, r.top };
    509   ClientToScreen(hwnd(), &point);
    510   return gfx::Rect(point.x, point.y, r.right - r.left, r.bottom - r.top);
    511 }
    512 
    513 gfx::Rect HWNDMessageHandler::GetRestoredBounds() const {
    514   // If we're in fullscreen mode, we've changed the normal bounds to the monitor
    515   // rect, so return the saved bounds instead.
    516   if (fullscreen_handler_->fullscreen())
    517     return fullscreen_handler_->GetRestoreBounds();
    518 
    519   gfx::Rect bounds;
    520   GetWindowPlacement(&bounds, NULL);
    521   return bounds;
    522 }
    523 
    524 gfx::Rect HWNDMessageHandler::GetClientAreaBounds() const {
    525   if (IsMinimized())
    526     return gfx::Rect();
    527   if (delegate_->WidgetSizeIsClientSize())
    528     return GetClientAreaBoundsInScreen();
    529   return GetWindowBoundsInScreen();
    530 }
    531 
    532 void HWNDMessageHandler::GetWindowPlacement(
    533     gfx::Rect* bounds,
    534     ui::WindowShowState* show_state) const {
    535   WINDOWPLACEMENT wp;
    536   wp.length = sizeof(wp);
    537   const bool succeeded = !!::GetWindowPlacement(hwnd(), &wp);
    538   DCHECK(succeeded);
    539 
    540   if (bounds != NULL) {
    541     if (wp.showCmd == SW_SHOWNORMAL) {
    542       // GetWindowPlacement can return misleading position if a normalized
    543       // window was resized using Aero Snap feature (see comment 9 in bug
    544       // 36421). As a workaround, using GetWindowRect for normalized windows.
    545       const bool succeeded = GetWindowRect(hwnd(), &wp.rcNormalPosition) != 0;
    546       DCHECK(succeeded);
    547 
    548       *bounds = gfx::Rect(wp.rcNormalPosition);
    549     } else {
    550       MONITORINFO mi;
    551       mi.cbSize = sizeof(mi);
    552       const bool succeeded = base::win::GetMonitorInfoWrapper(
    553           MonitorFromWindow(hwnd(), MONITOR_DEFAULTTONEAREST), &mi) != 0;
    554       DCHECK(succeeded);
    555 
    556       *bounds = gfx::Rect(wp.rcNormalPosition);
    557       // Convert normal position from workarea coordinates to screen
    558       // coordinates.
    559       bounds->Offset(mi.rcWork.left - mi.rcMonitor.left,
    560                      mi.rcWork.top - mi.rcMonitor.top);
    561     }
    562   }
    563 
    564   if (show_state) {
    565     if (wp.showCmd == SW_SHOWMAXIMIZED)
    566       *show_state = ui::SHOW_STATE_MAXIMIZED;
    567     else if (wp.showCmd == SW_SHOWMINIMIZED)
    568       *show_state = ui::SHOW_STATE_MINIMIZED;
    569     else
    570       *show_state = ui::SHOW_STATE_NORMAL;
    571   }
    572 }
    573 
    574 void HWNDMessageHandler::SetBounds(const gfx::Rect& bounds_in_pixels) {
    575   LONG style = GetWindowLong(hwnd(), GWL_STYLE);
    576   if (style & WS_MAXIMIZE)
    577     SetWindowLong(hwnd(), GWL_STYLE, style & ~WS_MAXIMIZE);
    578   SetWindowPos(hwnd(), NULL, bounds_in_pixels.x(), bounds_in_pixels.y(),
    579                bounds_in_pixels.width(), bounds_in_pixels.height(),
    580                SWP_NOACTIVATE | SWP_NOZORDER);
    581 }
    582 
    583 void HWNDMessageHandler::SetSize(const gfx::Size& size) {
    584   SetWindowPos(hwnd(), NULL, 0, 0, size.width(), size.height(),
    585                SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE);
    586 }
    587 
    588 void HWNDMessageHandler::CenterWindow(const gfx::Size& size) {
    589   HWND parent = GetParent(hwnd());
    590   if (!IsWindow(hwnd()))
    591     parent = ::GetWindow(hwnd(), GW_OWNER);
    592   gfx::CenterAndSizeWindow(parent, hwnd(), size);
    593 }
    594 
    595 void HWNDMessageHandler::SetRegion(HRGN region) {
    596   custom_window_region_.Set(region);
    597   ResetWindowRegion(false, true);
    598   UpdateDwmNcRenderingPolicy();
    599 }
    600 
    601 void HWNDMessageHandler::StackAbove(HWND other_hwnd) {
    602   SetWindowPos(hwnd(), other_hwnd, 0, 0, 0, 0,
    603                SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
    604 }
    605 
    606 void HWNDMessageHandler::StackAtTop() {
    607   SetWindowPos(hwnd(), HWND_TOP, 0, 0, 0, 0,
    608                SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
    609 }
    610 
    611 void HWNDMessageHandler::Show() {
    612   if (IsWindow(hwnd()))
    613     ShowWindowWithState(ui::SHOW_STATE_INACTIVE);
    614 }
    615 
    616 void HWNDMessageHandler::ShowWindowWithState(ui::WindowShowState show_state) {
    617   TRACE_EVENT0("views", "HWNDMessageHandler::ShowWindowWithState");
    618   DWORD native_show_state;
    619   switch (show_state) {
    620     case ui::SHOW_STATE_INACTIVE:
    621       native_show_state = SW_SHOWNOACTIVATE;
    622       break;
    623     case ui::SHOW_STATE_MAXIMIZED:
    624       native_show_state = SW_SHOWMAXIMIZED;
    625       break;
    626     case ui::SHOW_STATE_MINIMIZED:
    627       native_show_state = SW_SHOWMINIMIZED;
    628       break;
    629     default:
    630       native_show_state = delegate_->GetInitialShowState();
    631       break;
    632   }
    633   Show(native_show_state);
    634 }
    635 
    636 void HWNDMessageHandler::Show(int show_state) {
    637   ShowWindow(hwnd(), show_state);
    638   // When launched from certain programs like bash and Windows Live Messenger,
    639   // show_state is set to SW_HIDE, so we need to correct that condition. We
    640   // don't just change show_state to SW_SHOWNORMAL because MSDN says we must
    641   // always first call ShowWindow with the specified value from STARTUPINFO,
    642   // otherwise all future ShowWindow calls will be ignored (!!#@@#!). Instead,
    643   // we call ShowWindow again in this case.
    644   if (show_state == SW_HIDE) {
    645     show_state = SW_SHOWNORMAL;
    646     ShowWindow(hwnd(), show_state);
    647   }
    648 
    649   // We need to explicitly activate the window if we've been shown with a state
    650   // that should activate, because if we're opened from a desktop shortcut while
    651   // an existing window is already running it doesn't seem to be enough to use
    652   // one of these flags to activate the window.
    653   if (show_state == SW_SHOWNORMAL || show_state == SW_SHOWMAXIMIZED)
    654     Activate();
    655 
    656   if (!delegate_->HandleInitialFocus())
    657     SetInitialFocus();
    658 }
    659 
    660 void HWNDMessageHandler::ShowMaximizedWithBounds(const gfx::Rect& bounds) {
    661   WINDOWPLACEMENT placement = { 0 };
    662   placement.length = sizeof(WINDOWPLACEMENT);
    663   placement.showCmd = SW_SHOWMAXIMIZED;
    664   placement.rcNormalPosition = bounds.ToRECT();
    665   SetWindowPlacement(hwnd(), &placement);
    666 }
    667 
    668 void HWNDMessageHandler::Hide() {
    669   if (IsWindow(hwnd())) {
    670     // NOTE: Be careful not to activate any windows here (for example, calling
    671     // ShowWindow(SW_HIDE) will automatically activate another window).  This
    672     // code can be called while a window is being deactivated, and activating
    673     // another window will screw up the activation that is already in progress.
    674     SetWindowPos(hwnd(), NULL, 0, 0, 0, 0,
    675                  SWP_HIDEWINDOW | SWP_NOACTIVATE | SWP_NOMOVE |
    676                  SWP_NOREPOSITION | SWP_NOSIZE | SWP_NOZORDER);
    677 
    678     if (!GetParent(hwnd()))
    679       NotifyOwnedWindowsParentClosing();
    680   }
    681 }
    682 
    683 void HWNDMessageHandler::Maximize() {
    684   ExecuteSystemMenuCommand(SC_MAXIMIZE);
    685 }
    686 
    687 void HWNDMessageHandler::Minimize() {
    688   ExecuteSystemMenuCommand(SC_MINIMIZE);
    689   delegate_->HandleNativeBlur(NULL);
    690 }
    691 
    692 void HWNDMessageHandler::Restore() {
    693   ExecuteSystemMenuCommand(SC_RESTORE);
    694 }
    695 
    696 void HWNDMessageHandler::Activate() {
    697   if (IsMinimized())
    698     ::ShowWindow(hwnd(), SW_RESTORE);
    699   ::SetWindowPos(hwnd(), HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
    700   SetForegroundWindow(hwnd());
    701 }
    702 
    703 void HWNDMessageHandler::Deactivate() {
    704   HWND next_hwnd = ::GetNextWindow(hwnd(), GW_HWNDNEXT);
    705   while (next_hwnd) {
    706     if (::IsWindowVisible(next_hwnd)) {
    707       ::SetForegroundWindow(next_hwnd);
    708       return;
    709     }
    710     next_hwnd = ::GetNextWindow(next_hwnd, GW_HWNDNEXT);
    711   }
    712 }
    713 
    714 void HWNDMessageHandler::SetAlwaysOnTop(bool on_top) {
    715   ::SetWindowPos(hwnd(), on_top ? HWND_TOPMOST : HWND_NOTOPMOST,
    716                  0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
    717 }
    718 
    719 bool HWNDMessageHandler::IsVisible() const {
    720   return !!::IsWindowVisible(hwnd());
    721 }
    722 
    723 bool HWNDMessageHandler::IsActive() const {
    724   return GetActiveWindow() == hwnd();
    725 }
    726 
    727 bool HWNDMessageHandler::IsMinimized() const {
    728   return !!::IsIconic(hwnd());
    729 }
    730 
    731 bool HWNDMessageHandler::IsMaximized() const {
    732   return !!::IsZoomed(hwnd());
    733 }
    734 
    735 bool HWNDMessageHandler::IsAlwaysOnTop() const {
    736   return (GetWindowLong(hwnd(), GWL_EXSTYLE) & WS_EX_TOPMOST) != 0;
    737 }
    738 
    739 bool HWNDMessageHandler::RunMoveLoop(const gfx::Vector2d& drag_offset,
    740                                      bool hide_on_escape) {
    741   ReleaseCapture();
    742   MoveLoopMouseWatcher watcher(this, hide_on_escape);
    743 #if defined(USE_AURA)
    744   // In Aura, we handle touch events asynchronously. So we need to allow nested
    745   // tasks while in windows move loop.
    746   base::MessageLoop::ScopedNestableTaskAllower allow_nested(
    747       base::MessageLoop::current());
    748 #endif
    749   SendMessage(hwnd(), WM_SYSCOMMAND, SC_MOVE | 0x0002, GetMessagePos());
    750   // Windows doesn't appear to offer a way to determine whether the user
    751   // canceled the move or not. We assume if the user released the mouse it was
    752   // successful.
    753   return watcher.got_mouse_up();
    754 }
    755 
    756 void HWNDMessageHandler::EndMoveLoop() {
    757   SendMessage(hwnd(), WM_CANCELMODE, 0, 0);
    758 }
    759 
    760 void HWNDMessageHandler::SendFrameChanged() {
    761   SetWindowPos(hwnd(), NULL, 0, 0, 0, 0,
    762       SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOCOPYBITS |
    763       SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOREPOSITION |
    764       SWP_NOSENDCHANGING | SWP_NOSIZE | SWP_NOZORDER);
    765 }
    766 
    767 void HWNDMessageHandler::FlashFrame(bool flash) {
    768   FLASHWINFO fwi;
    769   fwi.cbSize = sizeof(fwi);
    770   fwi.hwnd = hwnd();
    771   if (flash) {
    772     fwi.dwFlags = FLASHW_ALL;
    773     fwi.uCount = 4;
    774     fwi.dwTimeout = 0;
    775   } else {
    776     fwi.dwFlags = FLASHW_STOP;
    777   }
    778   FlashWindowEx(&fwi);
    779 }
    780 
    781 void HWNDMessageHandler::ClearNativeFocus() {
    782   ::SetFocus(hwnd());
    783 }
    784 
    785 void HWNDMessageHandler::SetCapture() {
    786   DCHECK(!HasCapture());
    787   ::SetCapture(hwnd());
    788 }
    789 
    790 void HWNDMessageHandler::ReleaseCapture() {
    791   if (HasCapture())
    792     ::ReleaseCapture();
    793 }
    794 
    795 bool HWNDMessageHandler::HasCapture() const {
    796   return ::GetCapture() == hwnd();
    797 }
    798 
    799 void HWNDMessageHandler::SetVisibilityChangedAnimationsEnabled(bool enabled) {
    800   if (base::win::GetVersion() >= base::win::VERSION_VISTA) {
    801     int dwm_value = enabled ? FALSE : TRUE;
    802     DwmSetWindowAttribute(
    803         hwnd(), DWMWA_TRANSITIONS_FORCEDISABLED, &dwm_value, sizeof(dwm_value));
    804   }
    805 }
    806 
    807 bool HWNDMessageHandler::SetTitle(const string16& title) {
    808   string16 current_title;
    809   size_t len_with_null = GetWindowTextLength(hwnd()) + 1;
    810   if (len_with_null == 1 && title.length() == 0)
    811     return false;
    812   if (len_with_null - 1 == title.length() &&
    813       GetWindowText(
    814           hwnd(), WriteInto(&current_title, len_with_null), len_with_null) &&
    815       current_title == title)
    816     return false;
    817   SetWindowText(hwnd(), title.c_str());
    818   return true;
    819 }
    820 
    821 void HWNDMessageHandler::SetCursor(HCURSOR cursor) {
    822   if (cursor) {
    823     previous_cursor_ = ::SetCursor(cursor);
    824     current_cursor_ = cursor;
    825   } else if (previous_cursor_) {
    826     ::SetCursor(previous_cursor_);
    827     previous_cursor_ = NULL;
    828   }
    829 }
    830 
    831 void HWNDMessageHandler::FrameTypeChanged() {
    832   // Called when the frame type could possibly be changing (theme change or
    833   // DWM composition change).
    834 
    835   // Don't redraw the window here, because we need to hide and show the window
    836   // which will also trigger a redraw.
    837   ResetWindowRegion(true, false);
    838 
    839   // The non-client view needs to update too.
    840   delegate_->HandleFrameChanged();
    841 
    842   if (IsVisible() && !delegate_->IsUsingCustomFrame()) {
    843     // For some reason, we need to hide the window after we change from a custom
    844     // frame to a native frame.  If we don't, the client area will be filled
    845     // with black.  This seems to be related to an interaction between DWM and
    846     // SetWindowRgn, but the details aren't clear. Additionally, we need to
    847     // specify SWP_NOZORDER here, otherwise if you have multiple chrome windows
    848     // open they will re-appear with a non-deterministic Z-order.
    849     UINT flags = SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER;
    850     SetWindowPos(hwnd(), NULL, 0, 0, 0, 0, flags | SWP_HIDEWINDOW);
    851     SetWindowPos(hwnd(), NULL, 0, 0, 0, 0, flags | SWP_SHOWWINDOW);
    852 
    853     UpdateWindow(hwnd());
    854   }
    855 
    856   // WM_DWMCOMPOSITIONCHANGED is only sent to top level windows, however we want
    857   // to notify our children too, since we can have MDI child windows who need to
    858   // update their appearance.
    859   EnumChildWindows(hwnd(), &SendDwmCompositionChanged, NULL);
    860 }
    861 
    862 void HWNDMessageHandler::SchedulePaintInRect(const gfx::Rect& rect) {
    863   if (use_layered_buffer_) {
    864     // We must update the back-buffer immediately, since Windows' handling of
    865     // invalid rects is somewhat mysterious.
    866     invalid_rect_.Union(rect);
    867 
    868     // In some situations, such as drag and drop, when Windows itself runs a
    869     // nested message loop our message loop appears to be starved and we don't
    870     // receive calls to DidProcessMessage(). This only seems to affect layered
    871     // windows, so we schedule a redraw manually using a task, since those never
    872     // seem to be starved. Also, wtf.
    873     if (!waiting_for_redraw_layered_window_contents_) {
    874       waiting_for_redraw_layered_window_contents_ = true;
    875       base::MessageLoop::current()->PostTask(
    876           FROM_HERE,
    877           base::Bind(&HWNDMessageHandler::RedrawLayeredWindowContents,
    878                      weak_factory_.GetWeakPtr()));
    879     }
    880   } else {
    881     // InvalidateRect() expects client coordinates.
    882     RECT r = rect.ToRECT();
    883     InvalidateRect(hwnd(), &r, FALSE);
    884   }
    885 }
    886 
    887 void HWNDMessageHandler::SetOpacity(BYTE opacity) {
    888   layered_alpha_ = opacity;
    889 }
    890 
    891 void HWNDMessageHandler::SetWindowIcons(const gfx::ImageSkia& window_icon,
    892                                         const gfx::ImageSkia& app_icon) {
    893   if (!window_icon.isNull()) {
    894     HICON windows_icon = IconUtil::CreateHICONFromSkBitmap(
    895         *window_icon.bitmap());
    896     // We need to make sure to destroy the previous icon, otherwise we'll leak
    897     // these GDI objects until we crash!
    898     HICON old_icon = reinterpret_cast<HICON>(
    899         SendMessage(hwnd(), WM_SETICON, ICON_SMALL,
    900                     reinterpret_cast<LPARAM>(windows_icon)));
    901     if (old_icon)
    902       DestroyIcon(old_icon);
    903   }
    904   if (!app_icon.isNull()) {
    905     HICON windows_icon = IconUtil::CreateHICONFromSkBitmap(*app_icon.bitmap());
    906     HICON old_icon = reinterpret_cast<HICON>(
    907         SendMessage(hwnd(), WM_SETICON, ICON_BIG,
    908                     reinterpret_cast<LPARAM>(windows_icon)));
    909     if (old_icon)
    910       DestroyIcon(old_icon);
    911   }
    912 }
    913 
    914 ////////////////////////////////////////////////////////////////////////////////
    915 // HWNDMessageHandler, InputMethodDelegate implementation:
    916 
    917 void HWNDMessageHandler::DispatchKeyEventPostIME(const ui::KeyEvent& key) {
    918   SetMsgHandled(delegate_->HandleKeyEvent(key));
    919 }
    920 
    921 ////////////////////////////////////////////////////////////////////////////////
    922 // HWNDMessageHandler, gfx::WindowImpl overrides:
    923 
    924 HICON HWNDMessageHandler::GetDefaultWindowIcon() const {
    925   if (use_system_default_icon_)
    926     return NULL;
    927   return ViewsDelegate::views_delegate ?
    928       ViewsDelegate::views_delegate->GetDefaultWindowIcon() : NULL;
    929 }
    930 
    931 LRESULT HWNDMessageHandler::OnWndProc(UINT message,
    932                                       WPARAM w_param,
    933                                       LPARAM l_param) {
    934   HWND window = hwnd();
    935   LRESULT result = 0;
    936 
    937   if (delegate_ && delegate_->PreHandleMSG(message, w_param, l_param, &result))
    938     return result;
    939 
    940 #if !defined(USE_AURA)
    941   // First allow messages sent by child controls to be processed directly by
    942   // their associated views. If such a view is present, it will handle the
    943   // message *instead of* this NativeWidgetWin.
    944   if (ProcessChildWindowMessage(message, w_param, l_param, &result))
    945     return result;
    946 #endif
    947 
    948   // Otherwise we handle everything else.
    949   // NOTE: We inline ProcessWindowMessage() as 'this' may be destroyed during
    950   // dispatch and ProcessWindowMessage() doesn't deal with that well.
    951   const BOOL old_msg_handled = msg_handled_;
    952   base::WeakPtr<HWNDMessageHandler> ref(weak_factory_.GetWeakPtr());
    953   const BOOL processed =
    954       _ProcessWindowMessage(window, message, w_param, l_param, result, 0);
    955   if (!ref)
    956     return 0;
    957   msg_handled_ = old_msg_handled;
    958 
    959   if (!processed)
    960     result = DefWindowProc(window, message, w_param, l_param);
    961 
    962   // DefWindowProc() may have destroyed the window in a nested message loop.
    963   if (!::IsWindow(window))
    964     return result;
    965 
    966   if (delegate_)
    967     delegate_->PostHandleMSG(message, w_param, l_param);
    968   if (message == WM_NCDESTROY) {
    969 #if !defined(USE_AURA)
    970     base::MessageLoopForUI::current()->RemoveObserver(this);
    971 #endif
    972     if (delegate_)
    973       delegate_->HandleDestroyed();
    974   }
    975 
    976   // Only top level widget should store/restore focus.
    977   if (message == WM_ACTIVATE && delegate_->CanSaveFocus())
    978     PostProcessActivateMessage(LOWORD(w_param), !!HIWORD(w_param));
    979 
    980   if (message == WM_ENABLE && restore_focus_when_enabled_) {
    981     // This path should be executed only for top level as
    982     // restore_focus_when_enabled_ is set in PostProcessActivateMessage.
    983     DCHECK(delegate_->CanSaveFocus());
    984     restore_focus_when_enabled_ = false;
    985     delegate_->RestoreFocusOnEnable();
    986   }
    987   return result;
    988 }
    989 
    990 ////////////////////////////////////////////////////////////////////////////////
    991 // HWNDMessageHandler, MessageLoopForUI::Observer implementation:
    992 
    993 base::EventStatus HWNDMessageHandler::WillProcessEvent(
    994       const base::NativeEvent& event) {
    995   return base::EVENT_CONTINUE;
    996 }
    997 
    998 void HWNDMessageHandler::DidProcessEvent(const base::NativeEvent& event) {
    999   RedrawInvalidRect();
   1000 }
   1001 
   1002 ////////////////////////////////////////////////////////////////////////////////
   1003 // HWNDMessageHandler, private:
   1004 
   1005 int HWNDMessageHandler::GetAppbarAutohideEdges(HMONITOR monitor) {
   1006   autohide_factory_.InvalidateWeakPtrs();
   1007   return Appbar::instance()->GetAutohideEdges(
   1008       monitor,
   1009       base::Bind(&HWNDMessageHandler::OnAppbarAutohideEdgesChanged,
   1010                  autohide_factory_.GetWeakPtr()));
   1011 }
   1012 
   1013 void HWNDMessageHandler::OnAppbarAutohideEdgesChanged() {
   1014   // This triggers querying WM_NCCALCSIZE again.
   1015   RECT client;
   1016   GetWindowRect(hwnd(), &client);
   1017   SetWindowPos(hwnd(), NULL, client.left, client.top,
   1018                client.right - client.left, client.bottom - client.top,
   1019                SWP_FRAMECHANGED);
   1020 }
   1021 
   1022 void HWNDMessageHandler::SetInitialFocus() {
   1023   if (!(GetWindowLong(hwnd(), GWL_EXSTYLE) & WS_EX_TRANSPARENT) &&
   1024       !(GetWindowLong(hwnd(), GWL_EXSTYLE) & WS_EX_NOACTIVATE)) {
   1025     // The window does not get keyboard messages unless we focus it.
   1026     SetFocus(hwnd());
   1027   }
   1028 }
   1029 
   1030 void HWNDMessageHandler::PostProcessActivateMessage(int activation_state,
   1031                                                     bool minimized) {
   1032   DCHECK(delegate_->CanSaveFocus());
   1033 
   1034   bool active = activation_state != WA_INACTIVE && !minimized;
   1035   if (delegate_->CanActivate())
   1036     delegate_->HandleActivationChanged(active);
   1037 
   1038   if (!active) {
   1039     // We might get activated/inactivated without being enabled, so we need to
   1040     // clear restore_focus_when_enabled_.
   1041     restore_focus_when_enabled_ = false;
   1042     delegate_->SaveFocusOnDeactivate();
   1043   } else {
   1044     // We must restore the focus after the message has been DefProc'ed as it
   1045     // does set the focus to the last focused HWND.
   1046     // Note that if the window is not enabled, we cannot restore the focus as
   1047     // calling ::SetFocus on a child of the non-enabled top-window would fail.
   1048     // This is the case when showing a modal dialog (such as 'open file',
   1049     // 'print'...) from a different thread.
   1050     // In that case we delay the focus restoration to when the window is enabled
   1051     // again.
   1052     if (!IsWindowEnabled(hwnd())) {
   1053       DCHECK(!restore_focus_when_enabled_);
   1054       restore_focus_when_enabled_ = true;
   1055       return;
   1056     }
   1057     delegate_->RestoreFocusOnActivate();
   1058   }
   1059 }
   1060 
   1061 void HWNDMessageHandler::RestoreEnabledIfNecessary() {
   1062   if (delegate_->IsModal() && !restored_enabled_) {
   1063     restored_enabled_ = true;
   1064     // If we were run modally, we need to undo the disabled-ness we inflicted on
   1065     // the owner's parent hierarchy.
   1066     HWND start = ::GetWindow(hwnd(), GW_OWNER);
   1067     while (start) {
   1068       ::EnableWindow(start, TRUE);
   1069       start = ::GetParent(start);
   1070     }
   1071   }
   1072 }
   1073 
   1074 void HWNDMessageHandler::ExecuteSystemMenuCommand(int command) {
   1075   if (command)
   1076     SendMessage(hwnd(), WM_SYSCOMMAND, command, 0);
   1077 }
   1078 
   1079 void HWNDMessageHandler::TrackMouseEvents(DWORD mouse_tracking_flags) {
   1080   // Begin tracking mouse events for this HWND so that we get WM_MOUSELEAVE
   1081   // when the user moves the mouse outside this HWND's bounds.
   1082   if (active_mouse_tracking_flags_ == 0 || mouse_tracking_flags & TME_CANCEL) {
   1083     if (mouse_tracking_flags & TME_CANCEL) {
   1084       // We're about to cancel active mouse tracking, so empty out the stored
   1085       // state.
   1086       active_mouse_tracking_flags_ = 0;
   1087     } else {
   1088       active_mouse_tracking_flags_ = mouse_tracking_flags;
   1089     }
   1090 
   1091     TRACKMOUSEEVENT tme;
   1092     tme.cbSize = sizeof(tme);
   1093     tme.dwFlags = mouse_tracking_flags;
   1094     tme.hwndTrack = hwnd();
   1095     tme.dwHoverTime = 0;
   1096     TrackMouseEvent(&tme);
   1097   } else if (mouse_tracking_flags != active_mouse_tracking_flags_) {
   1098     TrackMouseEvents(active_mouse_tracking_flags_ | TME_CANCEL);
   1099     TrackMouseEvents(mouse_tracking_flags);
   1100   }
   1101 }
   1102 
   1103 void HWNDMessageHandler::ClientAreaSizeChanged() {
   1104   gfx::Size s = GetClientAreaBounds().size();
   1105   delegate_->HandleClientSizeChanged(s);
   1106   if (use_layered_buffer_)
   1107     layered_window_contents_.reset(new gfx::Canvas(s, 1.0f, false));
   1108 }
   1109 
   1110 bool HWNDMessageHandler::GetClientAreaInsets(gfx::Insets* insets) const {
   1111   if (delegate_->GetClientAreaInsets(insets))
   1112     return true;
   1113   DCHECK(insets->empty());
   1114 
   1115   // Returning false causes the default handling in OnNCCalcSize() to
   1116   // be invoked.
   1117   if (!delegate_->IsWidgetWindow() ||
   1118       (!delegate_->IsUsingCustomFrame() && !remove_standard_frame_)) {
   1119     return false;
   1120   }
   1121 
   1122   if (IsMaximized()) {
   1123     // Windows automatically adds a standard width border to all sides when a
   1124     // window is maximized.
   1125     int border_thickness = GetSystemMetrics(SM_CXSIZEFRAME);
   1126     if (remove_standard_frame_)
   1127       border_thickness -= 1;
   1128     *insets = gfx::Insets(
   1129         border_thickness, border_thickness, border_thickness, border_thickness);
   1130     return true;
   1131   }
   1132 
   1133   *insets = gfx::Insets();
   1134   return true;
   1135 }
   1136 
   1137 void HWNDMessageHandler::ResetWindowRegion(bool force, bool redraw) {
   1138   // A native frame uses the native window region, and we don't want to mess
   1139   // with it.
   1140   // WS_EX_COMPOSITED is used instead of WS_EX_LAYERED under aura. WS_EX_LAYERED
   1141   // automatically makes clicks on transparent pixels fall through, that isn't
   1142   // the case with WS_EX_COMPOSITED. So, we route WS_EX_COMPOSITED through to
   1143   // the delegate to allow for a custom hit mask.
   1144   if ((window_ex_style() & WS_EX_COMPOSITED) == 0 && !custom_window_region_ &&
   1145       (!delegate_->IsUsingCustomFrame() || !delegate_->IsWidgetWindow())) {
   1146     if (force)
   1147       SetWindowRgn(hwnd(), NULL, redraw);
   1148     return;
   1149   }
   1150 
   1151   // Changing the window region is going to force a paint. Only change the
   1152   // window region if the region really differs.
   1153   HRGN current_rgn = CreateRectRgn(0, 0, 0, 0);
   1154   int current_rgn_result = GetWindowRgn(hwnd(), current_rgn);
   1155 
   1156   CRect window_rect;
   1157   GetWindowRect(hwnd(), &window_rect);
   1158   HRGN new_region;
   1159   if (custom_window_region_) {
   1160     new_region = ::CreateRectRgn(0, 0, 0, 0);
   1161     ::CombineRgn(new_region, custom_window_region_.Get(), NULL, RGN_COPY);
   1162   } else if (IsMaximized()) {
   1163     HMONITOR monitor = MonitorFromWindow(hwnd(), MONITOR_DEFAULTTONEAREST);
   1164     MONITORINFO mi;
   1165     mi.cbSize = sizeof mi;
   1166     base::win::GetMonitorInfoWrapper(monitor, &mi);
   1167     CRect work_rect = mi.rcWork;
   1168     work_rect.OffsetRect(-window_rect.left, -window_rect.top);
   1169     new_region = CreateRectRgnIndirect(&work_rect);
   1170   } else {
   1171     gfx::Path window_mask;
   1172     delegate_->GetWindowMask(
   1173         gfx::Size(window_rect.Width(), window_rect.Height()), &window_mask);
   1174     new_region = gfx::CreateHRGNFromSkPath(window_mask);
   1175   }
   1176 
   1177   if (current_rgn_result == ERROR || !EqualRgn(current_rgn, new_region)) {
   1178     // SetWindowRgn takes ownership of the HRGN created by CreateNativeRegion.
   1179     SetWindowRgn(hwnd(), new_region, redraw);
   1180   } else {
   1181     DeleteObject(new_region);
   1182   }
   1183 
   1184   DeleteObject(current_rgn);
   1185 }
   1186 
   1187 void HWNDMessageHandler::UpdateDwmNcRenderingPolicy() {
   1188   if (base::win::GetVersion() < base::win::VERSION_VISTA)
   1189     return;
   1190   DWMNCRENDERINGPOLICY policy = custom_window_region_ ? DWMNCRP_DISABLED
   1191                                                       : DWMNCRP_USEWINDOWSTYLE;
   1192   DwmSetWindowAttribute(hwnd(), DWMWA_NCRENDERING_POLICY,
   1193                         &policy, sizeof(DWMNCRENDERINGPOLICY));
   1194 }
   1195 
   1196 LRESULT HWNDMessageHandler::DefWindowProcWithRedrawLock(UINT message,
   1197                                                         WPARAM w_param,
   1198                                                         LPARAM l_param) {
   1199   ScopedRedrawLock lock(this);
   1200   // The Widget and HWND can be destroyed in the call to DefWindowProc, so use
   1201   // the WeakPtrFactory to avoid unlocking (and crashing) after destruction.
   1202   base::WeakPtr<HWNDMessageHandler> ref(weak_factory_.GetWeakPtr());
   1203   LRESULT result = DefWindowProc(hwnd(), message, w_param, l_param);
   1204   if (!ref)
   1205     lock.CancelUnlockOperation();
   1206   return result;
   1207 }
   1208 
   1209 void HWNDMessageHandler::NotifyOwnedWindowsParentClosing() {
   1210   FindOwnedWindowsData data;
   1211   data.window = hwnd();
   1212   EnumThreadWindows(GetCurrentThreadId(), FindOwnedWindowsCallback,
   1213                     reinterpret_cast<LPARAM>(&data));
   1214   for (size_t i = 0; i < data.owned_widgets.size(); ++i)
   1215     data.owned_widgets[i]->OnOwnerClosing();
   1216 }
   1217 
   1218 void HWNDMessageHandler::LockUpdates(bool force) {
   1219   // We skip locked updates when Aero is on for two reasons:
   1220   // 1. Because it isn't necessary
   1221   // 2. Because toggling the WS_VISIBLE flag may occur while the GPU process is
   1222   //    attempting to present a child window's backbuffer onscreen. When these
   1223   //    two actions race with one another, the child window will either flicker
   1224   //    or will simply stop updating entirely.
   1225   if ((force || !ui::win::IsAeroGlassEnabled()) && ++lock_updates_count_ == 1) {
   1226     SetWindowLong(hwnd(), GWL_STYLE,
   1227                   GetWindowLong(hwnd(), GWL_STYLE) & ~WS_VISIBLE);
   1228   }
   1229 }
   1230 
   1231 void HWNDMessageHandler::UnlockUpdates(bool force) {
   1232   if ((force || !ui::win::IsAeroGlassEnabled()) && --lock_updates_count_ <= 0) {
   1233     SetWindowLong(hwnd(), GWL_STYLE,
   1234                   GetWindowLong(hwnd(), GWL_STYLE) | WS_VISIBLE);
   1235     lock_updates_count_ = 0;
   1236   }
   1237 }
   1238 
   1239 void HWNDMessageHandler::RedrawInvalidRect() {
   1240 // TODO(cpu): Remove the caller and this class as a message loop observer
   1241 // because we don't need agressive repaints via RDW_UPDATENOW in Aura. The
   1242 // general tracking bug for repaint issues is 177115.
   1243 #if !defined(USE_AURA)
   1244   if (!use_layered_buffer_) {
   1245     RECT r = { 0, 0, 0, 0 };
   1246     if (GetUpdateRect(hwnd(), &r, FALSE) && !IsRectEmpty(&r)) {
   1247       RedrawWindow(hwnd(), &r, NULL,
   1248                    RDW_INVALIDATE | RDW_UPDATENOW | RDW_NOCHILDREN);
   1249     }
   1250   }
   1251 #endif
   1252 }
   1253 
   1254 void HWNDMessageHandler::RedrawLayeredWindowContents() {
   1255   waiting_for_redraw_layered_window_contents_ = false;
   1256   if (invalid_rect_.IsEmpty())
   1257     return;
   1258 
   1259   // We need to clip to the dirty rect ourselves.
   1260   layered_window_contents_->sk_canvas()->save(SkCanvas::kClip_SaveFlag);
   1261   double scale = gfx::win::GetDeviceScaleFactor();
   1262   layered_window_contents_->sk_canvas()->scale(
   1263       SkScalar(scale),SkScalar(scale));
   1264   layered_window_contents_->ClipRect(invalid_rect_);
   1265   delegate_->PaintLayeredWindow(layered_window_contents_.get());
   1266   layered_window_contents_->sk_canvas()->scale(
   1267       SkScalar(1.0/scale),SkScalar(1.0/scale));
   1268   layered_window_contents_->sk_canvas()->restore();
   1269 
   1270   RECT wr;
   1271   GetWindowRect(hwnd(), &wr);
   1272   SIZE size = {wr.right - wr.left, wr.bottom - wr.top};
   1273   POINT position = {wr.left, wr.top};
   1274   HDC dib_dc = skia::BeginPlatformPaint(layered_window_contents_->sk_canvas());
   1275   POINT zero = {0, 0};
   1276   BLENDFUNCTION blend = {AC_SRC_OVER, 0, layered_alpha_, AC_SRC_ALPHA};
   1277   UpdateLayeredWindow(hwnd(), NULL, &position, &size, dib_dc, &zero,
   1278                       RGB(0xFF, 0xFF, 0xFF), &blend, ULW_ALPHA);
   1279   invalid_rect_.SetRect(0, 0, 0, 0);
   1280   skia::EndPlatformPaint(layered_window_contents_->sk_canvas());
   1281 }
   1282 
   1283 void HWNDMessageHandler::ForceRedrawWindow(int attempts) {
   1284   if (ui::IsWorkstationLocked()) {
   1285     // Presents will continue to fail as long as the input desktop is
   1286     // unavailable.
   1287     if (--attempts <= 0)
   1288       return;
   1289     base::MessageLoop::current()->PostDelayedTask(
   1290         FROM_HERE,
   1291         base::Bind(&HWNDMessageHandler::ForceRedrawWindow,
   1292                    weak_factory_.GetWeakPtr(),
   1293                    attempts),
   1294         base::TimeDelta::FromMilliseconds(500));
   1295     return;
   1296   }
   1297   InvalidateRect(hwnd(), NULL, FALSE);
   1298 }
   1299 
   1300 // Message handlers ------------------------------------------------------------
   1301 
   1302 void HWNDMessageHandler::OnActivateApp(BOOL active, DWORD thread_id) {
   1303   if (delegate_->IsWidgetWindow() && !active &&
   1304       thread_id != GetCurrentThreadId()) {
   1305     delegate_->HandleAppDeactivated();
   1306     // Also update the native frame if it is rendering the non-client area.
   1307     if (!remove_standard_frame_ && !delegate_->IsUsingCustomFrame())
   1308       DefWindowProcWithRedrawLock(WM_NCACTIVATE, FALSE, 0);
   1309   }
   1310 }
   1311 
   1312 BOOL HWNDMessageHandler::OnAppCommand(HWND window,
   1313                                       short command,
   1314                                       WORD device,
   1315                                       int keystate) {
   1316   BOOL handled = !!delegate_->HandleAppCommand(command);
   1317   SetMsgHandled(handled);
   1318   // Make sure to return TRUE if the event was handled or in some cases the
   1319   // system will execute the default handler which can cause bugs like going
   1320   // forward or back two pages instead of one.
   1321   return handled;
   1322 }
   1323 
   1324 void HWNDMessageHandler::OnCancelMode() {
   1325   delegate_->HandleCancelMode();
   1326   // Need default handling, otherwise capture and other things aren't canceled.
   1327   SetMsgHandled(FALSE);
   1328 }
   1329 
   1330 void HWNDMessageHandler::OnCaptureChanged(HWND window) {
   1331   delegate_->HandleCaptureLost();
   1332 }
   1333 
   1334 void HWNDMessageHandler::OnClose() {
   1335   delegate_->HandleClose();
   1336 }
   1337 
   1338 void HWNDMessageHandler::OnCommand(UINT notification_code,
   1339                                    int command,
   1340                                    HWND window) {
   1341   // If the notification code is > 1 it means it is control specific and we
   1342   // should ignore it.
   1343   if (notification_code > 1 || delegate_->HandleAppCommand(command))
   1344     SetMsgHandled(FALSE);
   1345 }
   1346 
   1347 LRESULT HWNDMessageHandler::OnCreate(CREATESTRUCT* create_struct) {
   1348   use_layered_buffer_ = !!(window_ex_style() & WS_EX_LAYERED);
   1349 
   1350 #if defined(USE_AURA)
   1351   if (window_ex_style() &  WS_EX_COMPOSITED) {
   1352     if (base::win::GetVersion() >= base::win::VERSION_VISTA) {
   1353       // This is part of the magic to emulate layered windows with Aura
   1354       // see the explanation elsewere when we set WS_EX_COMPOSITED style.
   1355       MARGINS margins = {-1,-1,-1,-1};
   1356       DwmExtendFrameIntoClientArea(hwnd(), &margins);
   1357     }
   1358   }
   1359 #endif
   1360 
   1361   fullscreen_handler_->set_hwnd(hwnd());
   1362 
   1363   // This message initializes the window so that focus border are shown for
   1364   // windows.
   1365   SendMessage(hwnd(),
   1366               WM_CHANGEUISTATE,
   1367               MAKELPARAM(UIS_CLEAR, UISF_HIDEFOCUS),
   1368               0);
   1369 
   1370   if (remove_standard_frame_) {
   1371     SetWindowLong(hwnd(), GWL_STYLE,
   1372                   GetWindowLong(hwnd(), GWL_STYLE) & ~WS_CAPTION);
   1373     SendFrameChanged();
   1374   }
   1375 
   1376   // Get access to a modifiable copy of the system menu.
   1377   GetSystemMenu(hwnd(), false);
   1378 
   1379   if (base::win::GetVersion() >= base::win::VERSION_WIN7 &&
   1380       ui::AreTouchEventsEnabled())
   1381     RegisterTouchWindow(hwnd(), TWF_WANTPALM);
   1382 
   1383   // We need to allow the delegate to size its contents since the window may not
   1384   // receive a size notification when its initial bounds are specified at window
   1385   // creation time.
   1386   ClientAreaSizeChanged();
   1387 
   1388 #if !defined(USE_AURA)
   1389   // We need to add ourselves as a message loop observer so that we can repaint
   1390   // aggressively if the contents of our window become invalid. Unfortunately
   1391   // WM_PAINT messages are starved and we get flickery redrawing when resizing
   1392   // if we do not do this.
   1393   base::MessageLoopForUI::current()->AddObserver(this);
   1394 #endif
   1395 
   1396   delegate_->HandleCreate();
   1397 
   1398   WTSRegisterSessionNotification(hwnd(), NOTIFY_FOR_THIS_SESSION);
   1399 
   1400   // TODO(beng): move more of NWW::OnCreate here.
   1401   return 0;
   1402 }
   1403 
   1404 void HWNDMessageHandler::OnDestroy() {
   1405   WTSUnRegisterSessionNotification(hwnd());
   1406   delegate_->HandleDestroying();
   1407 }
   1408 
   1409 void HWNDMessageHandler::OnDisplayChange(UINT bits_per_pixel,
   1410                                          const CSize& screen_size) {
   1411   delegate_->HandleDisplayChange();
   1412 }
   1413 
   1414 LRESULT HWNDMessageHandler::OnDwmCompositionChanged(UINT msg,
   1415                                                     WPARAM w_param,
   1416                                                     LPARAM l_param) {
   1417   if (!delegate_->IsWidgetWindow()) {
   1418     SetMsgHandled(FALSE);
   1419     return 0;
   1420   }
   1421 
   1422   FrameTypeChanged();
   1423   return 0;
   1424 }
   1425 
   1426 void HWNDMessageHandler::OnEnterSizeMove() {
   1427   // Please refer to the comments in the OnSize function about the scrollbar
   1428   // hack.
   1429   // Hide the Windows scrollbar if the scroll styles are present to ensure
   1430   // that a paint flicker does not occur while sizing.
   1431   if (in_size_loop_ && needs_scroll_styles_)
   1432     ShowScrollBar(hwnd(), SB_BOTH, FALSE);
   1433 
   1434   delegate_->HandleBeginWMSizeMove();
   1435   SetMsgHandled(FALSE);
   1436 }
   1437 
   1438 LRESULT HWNDMessageHandler::OnEraseBkgnd(HDC dc) {
   1439   // Needed to prevent resize flicker.
   1440   return 1;
   1441 }
   1442 
   1443 void HWNDMessageHandler::OnExitSizeMove() {
   1444   delegate_->HandleEndWMSizeMove();
   1445   SetMsgHandled(FALSE);
   1446   // Please refer to the notes in the OnSize function for information about
   1447   // the scrolling hack.
   1448   // We hide the Windows scrollbar in the OnEnterSizeMove function. We need
   1449   // to add the scroll styles back to ensure that scrolling works in legacy
   1450   // trackpoint drivers.
   1451   if (in_size_loop_ && needs_scroll_styles_)
   1452     AddScrollStylesToWindow(hwnd());
   1453 }
   1454 
   1455 void HWNDMessageHandler::OnGetMinMaxInfo(MINMAXINFO* minmax_info) {
   1456   gfx::Size min_window_size;
   1457   gfx::Size max_window_size;
   1458   delegate_->GetMinMaxSize(&min_window_size, &max_window_size);
   1459 
   1460   // Add the native frame border size to the minimum and maximum size if the
   1461   // view reports its size as the client size.
   1462   if (delegate_->WidgetSizeIsClientSize()) {
   1463     CRect client_rect, window_rect;
   1464     GetClientRect(hwnd(), &client_rect);
   1465     GetWindowRect(hwnd(), &window_rect);
   1466     window_rect -= client_rect;
   1467     min_window_size.Enlarge(window_rect.Width(), window_rect.Height());
   1468     if (!max_window_size.IsEmpty())
   1469       max_window_size.Enlarge(window_rect.Width(), window_rect.Height());
   1470   }
   1471   minmax_info->ptMinTrackSize.x = min_window_size.width();
   1472   minmax_info->ptMinTrackSize.y = min_window_size.height();
   1473   if (max_window_size.width() || max_window_size.height()) {
   1474     if (!max_window_size.width())
   1475       max_window_size.set_width(GetSystemMetrics(SM_CXMAXTRACK));
   1476     if (!max_window_size.height())
   1477       max_window_size.set_height(GetSystemMetrics(SM_CYMAXTRACK));
   1478     minmax_info->ptMaxTrackSize.x = max_window_size.width();
   1479     minmax_info->ptMaxTrackSize.y = max_window_size.height();
   1480   }
   1481   SetMsgHandled(FALSE);
   1482 }
   1483 
   1484 LRESULT HWNDMessageHandler::OnGetObject(UINT message,
   1485                                         WPARAM w_param,
   1486                                         LPARAM l_param) {
   1487   LRESULT reference_result = static_cast<LRESULT>(0L);
   1488 
   1489   // Accessibility readers will send an OBJID_CLIENT message
   1490   if (OBJID_CLIENT == l_param) {
   1491     // Retrieve MSAA dispatch object for the root view.
   1492     base::win::ScopedComPtr<IAccessible> root(
   1493         delegate_->GetNativeViewAccessible());
   1494 
   1495     // Create a reference that MSAA will marshall to the client.
   1496     reference_result = LresultFromObject(IID_IAccessible, w_param,
   1497         static_cast<IAccessible*>(root.Detach()));
   1498   }
   1499 
   1500   return reference_result;
   1501 }
   1502 
   1503 LRESULT HWNDMessageHandler::OnImeMessages(UINT message,
   1504                                           WPARAM w_param,
   1505                                           LPARAM l_param) {
   1506   LRESULT result = 0;
   1507   SetMsgHandled(delegate_->HandleIMEMessage(
   1508       message, w_param, l_param, &result));
   1509   return result;
   1510 }
   1511 
   1512 void HWNDMessageHandler::OnInitMenu(HMENU menu) {
   1513   bool is_fullscreen = fullscreen_handler_->fullscreen();
   1514   bool is_minimized = IsMinimized();
   1515   bool is_maximized = IsMaximized();
   1516   bool is_restored = !is_fullscreen && !is_minimized && !is_maximized;
   1517 
   1518   ScopedRedrawLock lock(this);
   1519   EnableMenuItemByCommand(menu, SC_RESTORE, is_minimized || is_maximized);
   1520   EnableMenuItemByCommand(menu, SC_MOVE, is_restored);
   1521   EnableMenuItemByCommand(menu, SC_SIZE, delegate_->CanResize() && is_restored);
   1522   EnableMenuItemByCommand(menu, SC_MAXIMIZE, delegate_->CanMaximize() &&
   1523                           !is_fullscreen && !is_maximized);
   1524   EnableMenuItemByCommand(menu, SC_MINIMIZE, delegate_->CanMaximize() &&
   1525                           !is_minimized);
   1526 }
   1527 
   1528 void HWNDMessageHandler::OnInputLangChange(DWORD character_set,
   1529                                            HKL input_language_id) {
   1530   delegate_->HandleInputLanguageChange(character_set, input_language_id);
   1531 }
   1532 
   1533 LRESULT HWNDMessageHandler::OnKeyEvent(UINT message,
   1534                                        WPARAM w_param,
   1535                                        LPARAM l_param) {
   1536   MSG msg = { hwnd(), message, w_param, l_param, GetMessageTime() };
   1537   ui::KeyEvent key(msg, message == WM_CHAR);
   1538   if (!delegate_->HandleUntranslatedKeyEvent(key))
   1539     DispatchKeyEventPostIME(key);
   1540   return 0;
   1541 }
   1542 
   1543 void HWNDMessageHandler::OnKillFocus(HWND focused_window) {
   1544   delegate_->HandleNativeBlur(focused_window);
   1545   SetMsgHandled(FALSE);
   1546 }
   1547 
   1548 LRESULT HWNDMessageHandler::OnMouseActivate(UINT message,
   1549                                             WPARAM w_param,
   1550                                             LPARAM l_param) {
   1551 #if defined(USE_AURA)
   1552   // On Windows, if we select the menu item by touch and if the window at the
   1553   // location is another window on the same thread, that window gets a
   1554   // WM_MOUSEACTIVATE message and ends up activating itself, which is not
   1555   // correct. We workaround this by setting a property on the window at the
   1556   // current cursor location. We check for this property in our
   1557   // WM_MOUSEACTIVATE handler and don't activate the window if the property is
   1558   // set.
   1559   if (::GetProp(hwnd(), kIgnoreTouchMouseActivateForWindow)) {
   1560     ::RemoveProp(hwnd(), kIgnoreTouchMouseActivateForWindow);
   1561     return MA_NOACTIVATE;
   1562   }
   1563   // A child window activation should be treated as if we lost activation.
   1564   POINT cursor_pos = {0};
   1565   ::GetCursorPos(&cursor_pos);
   1566   ::ScreenToClient(hwnd(), &cursor_pos);
   1567   HWND child = ::RealChildWindowFromPoint(hwnd(), cursor_pos);
   1568   if (::IsWindow(child) && child != hwnd() && ::IsWindowVisible(child))
   1569     PostProcessActivateMessage(WA_INACTIVE, false);
   1570 #endif
   1571   // TODO(beng): resolve this with the GetWindowLong() check on the subsequent
   1572   //             line.
   1573   if (delegate_->IsWidgetWindow())
   1574     return delegate_->CanActivate() ? MA_ACTIVATE : MA_NOACTIVATEANDEAT;
   1575   if (GetWindowLong(hwnd(), GWL_EXSTYLE) & WS_EX_NOACTIVATE)
   1576     return MA_NOACTIVATE;
   1577   SetMsgHandled(FALSE);
   1578   return MA_ACTIVATE;
   1579 }
   1580 
   1581 LRESULT HWNDMessageHandler::OnMouseRange(UINT message,
   1582                                          WPARAM w_param,
   1583                                          LPARAM l_param) {
   1584 #if defined(USE_AURA)
   1585   if (!touch_ids_.empty())
   1586     return 0;
   1587   // We handle touch events on Windows Aura. Windows generates synthesized
   1588   // mouse messages in response to touch which we should ignore. However touch
   1589   // messages are only received for the client area. We need to ignore the
   1590   // synthesized mouse messages for all points in the client area and places
   1591   // which return HTNOWHERE.
   1592   if (ui::IsMouseEventFromTouch(message)) {
   1593     LPARAM l_param_ht = l_param;
   1594     // For mouse events (except wheel events), location is in window coordinates
   1595     // and should be converted to screen coordinates for WM_NCHITTEST.
   1596     if (message != WM_MOUSEWHEEL && message != WM_MOUSEHWHEEL) {
   1597       CPoint screen_point(l_param_ht);
   1598       MapWindowPoints(hwnd(), HWND_DESKTOP, &screen_point, 1);
   1599       l_param_ht = MAKELPARAM(screen_point.x, screen_point.y);
   1600     }
   1601     LRESULT hittest = SendMessage(hwnd(), WM_NCHITTEST, 0, l_param_ht);
   1602     if (hittest == HTCLIENT || hittest == HTNOWHERE)
   1603       return 0;
   1604   }
   1605 #endif
   1606   if (message == WM_RBUTTONUP && is_right_mouse_pressed_on_caption_) {
   1607     is_right_mouse_pressed_on_caption_ = false;
   1608     ReleaseCapture();
   1609     // |point| is in window coordinates, but WM_NCHITTEST and TrackPopupMenu()
   1610     // expect screen coordinates.
   1611     CPoint screen_point(l_param);
   1612     MapWindowPoints(hwnd(), HWND_DESKTOP, &screen_point, 1);
   1613     w_param = SendMessage(hwnd(), WM_NCHITTEST, 0,
   1614                           MAKELPARAM(screen_point.x, screen_point.y));
   1615     if (w_param == HTCAPTION || w_param == HTSYSMENU) {
   1616       gfx::ShowSystemMenuAtPoint(hwnd(), gfx::Point(screen_point));
   1617       return 0;
   1618     }
   1619   } else if (message == WM_NCLBUTTONDOWN && delegate_->IsUsingCustomFrame()) {
   1620     switch (w_param) {
   1621       case HTCLOSE:
   1622       case HTMINBUTTON:
   1623       case HTMAXBUTTON: {
   1624         // When the mouse is pressed down in these specific non-client areas,
   1625         // we need to tell the RootView to send the mouse pressed event (which
   1626         // sets capture, allowing subsequent WM_LBUTTONUP (note, _not_
   1627         // WM_NCLBUTTONUP) to fire so that the appropriate WM_SYSCOMMAND can be
   1628         // sent by the applicable button's ButtonListener. We _have_ to do this
   1629         // way rather than letting Windows just send the syscommand itself (as
   1630         // would happen if we never did this dance) because for some insane
   1631         // reason DefWindowProc for WM_NCLBUTTONDOWN also renders the pressed
   1632         // window control button appearance, in the Windows classic style, over
   1633         // our view! Ick! By handling this message we prevent Windows from
   1634         // doing this undesirable thing, but that means we need to roll the
   1635         // sys-command handling ourselves.
   1636         // Combine |w_param| with common key state message flags.
   1637         w_param |= base::win::IsCtrlPressed() ? MK_CONTROL : 0;
   1638         w_param |= base::win::IsShiftPressed() ? MK_SHIFT : 0;
   1639       }
   1640     }
   1641   } else if (message == WM_NCRBUTTONDOWN &&
   1642       (w_param == HTCAPTION || w_param == HTSYSMENU)) {
   1643     is_right_mouse_pressed_on_caption_ = true;
   1644     // We SetCapture() to ensure we only show the menu when the button
   1645     // down and up are both on the caption. Note: this causes the button up to
   1646     // be WM_RBUTTONUP instead of WM_NCRBUTTONUP.
   1647     SetCapture();
   1648   }
   1649 
   1650   MSG msg = { hwnd(), message, w_param, l_param, GetMessageTime(),
   1651               { GET_X_LPARAM(l_param), GET_Y_LPARAM(l_param) } };
   1652   ui::MouseEvent event(msg);
   1653   if (!touch_ids_.empty() || ui::IsMouseEventFromTouch(message))
   1654     event.set_flags(event.flags() | ui::EF_FROM_TOUCH);
   1655 
   1656   if (!(event.flags() & ui::EF_IS_NON_CLIENT))
   1657     delegate_->HandleTooltipMouseMove(message, w_param, l_param);
   1658 
   1659   if (event.type() == ui::ET_MOUSE_MOVED && !HasCapture()) {
   1660     // Windows only fires WM_MOUSELEAVE events if the application begins
   1661     // "tracking" mouse events for a given HWND during WM_MOUSEMOVE events.
   1662     // We need to call |TrackMouseEvents| to listen for WM_MOUSELEAVE.
   1663     TrackMouseEvents((message == WM_NCMOUSEMOVE) ?
   1664         TME_NONCLIENT | TME_LEAVE : TME_LEAVE);
   1665   } else if (event.type() == ui::ET_MOUSE_EXITED) {
   1666     // Reset our tracking flags so future mouse movement over this
   1667     // NativeWidgetWin results in a new tracking session. Fall through for
   1668     // OnMouseEvent.
   1669     active_mouse_tracking_flags_ = 0;
   1670   } else if (event.type() == ui::ET_MOUSEWHEEL) {
   1671     // Reroute the mouse wheel to the window under the pointer if applicable.
   1672     return (ui::RerouteMouseWheel(hwnd(), w_param, l_param) ||
   1673             delegate_->HandleMouseEvent(ui::MouseWheelEvent(msg))) ? 0 : 1;
   1674   }
   1675 
   1676   // There are cases where the code handling the message destroys the window,
   1677   // so use the weak ptr to check if destruction occured or not.
   1678   base::WeakPtr<HWNDMessageHandler> ref(weak_factory_.GetWeakPtr());
   1679   bool handled = delegate_->HandleMouseEvent(event);
   1680   if (!ref.get())
   1681     return 0;
   1682   if (!handled && message == WM_NCLBUTTONDOWN && w_param != HTSYSMENU &&
   1683       delegate_->IsUsingCustomFrame()) {
   1684     // TODO(msw): Eliminate undesired painting, or re-evaluate this workaround.
   1685     // DefWindowProc for WM_NCLBUTTONDOWN does weird non-client painting, so we
   1686     // need to call it inside a ScopedRedrawLock. This may cause other negative
   1687     // side-effects (ex/ stifling non-client mouse releases).
   1688     DefWindowProcWithRedrawLock(message, w_param, l_param);
   1689     handled = true;
   1690   }
   1691 
   1692   if (ref.get())
   1693     SetMsgHandled(handled);
   1694   return 0;
   1695 }
   1696 
   1697 void HWNDMessageHandler::OnMove(const CPoint& point) {
   1698   delegate_->HandleMove();
   1699   SetMsgHandled(FALSE);
   1700 }
   1701 
   1702 void HWNDMessageHandler::OnMoving(UINT param, const RECT* new_bounds) {
   1703   delegate_->HandleMove();
   1704 }
   1705 
   1706 LRESULT HWNDMessageHandler::OnNCActivate(UINT message,
   1707                                          WPARAM w_param,
   1708                                          LPARAM l_param) {
   1709   // Per MSDN, w_param is either TRUE or FALSE. However, MSDN also hints that:
   1710   // "If the window is minimized when this message is received, the application
   1711   // should pass the message to the DefWindowProc function."
   1712   // It is found out that the high word of w_param might be set when the window
   1713   // is minimized or restored. To handle this, w_param's high word should be
   1714   // cleared before it is converted to BOOL.
   1715   BOOL active = static_cast<BOOL>(LOWORD(w_param));
   1716 
   1717   bool inactive_rendering_disabled = delegate_->IsInactiveRenderingDisabled();
   1718 
   1719   if (!delegate_->IsWidgetWindow()) {
   1720     SetMsgHandled(FALSE);
   1721     return 0;
   1722   }
   1723 
   1724   if (!delegate_->CanActivate())
   1725     return TRUE;
   1726 
   1727   // On activation, lift any prior restriction against rendering as inactive.
   1728   if (active && inactive_rendering_disabled)
   1729     delegate_->EnableInactiveRendering();
   1730 
   1731   if (delegate_->IsUsingCustomFrame()) {
   1732     // TODO(beng, et al): Hack to redraw this window and child windows
   1733     //     synchronously upon activation. Not all child windows are redrawing
   1734     //     themselves leading to issues like http://crbug.com/74604
   1735     //     We redraw out-of-process HWNDs asynchronously to avoid hanging the
   1736     //     whole app if a child HWND belonging to a hung plugin is encountered.
   1737     RedrawWindow(hwnd(), NULL, NULL,
   1738                  RDW_NOCHILDREN | RDW_INVALIDATE | RDW_UPDATENOW);
   1739     EnumChildWindows(hwnd(), EnumChildWindowsForRedraw, NULL);
   1740   }
   1741 
   1742   // The frame may need to redraw as a result of the activation change.
   1743   // We can get WM_NCACTIVATE before we're actually visible. If we're not
   1744   // visible, no need to paint.
   1745   if (IsVisible())
   1746     delegate_->SchedulePaint();
   1747 
   1748   // Avoid DefWindowProc non-client rendering over our custom frame on newer
   1749   // Windows versions only (breaks taskbar activation indication on XP/Vista).
   1750   if (delegate_->IsUsingCustomFrame() &&
   1751       base::win::GetVersion() > base::win::VERSION_VISTA) {
   1752     SetMsgHandled(TRUE);
   1753     return TRUE;
   1754   }
   1755 
   1756   return DefWindowProcWithRedrawLock(
   1757       WM_NCACTIVATE, inactive_rendering_disabled || active, 0);
   1758 }
   1759 
   1760 LRESULT HWNDMessageHandler::OnNCCalcSize(BOOL mode, LPARAM l_param) {
   1761   // We only override the default handling if we need to specify a custom
   1762   // non-client edge width. Note that in most cases "no insets" means no
   1763   // custom width, but in fullscreen mode or when the NonClientFrameView
   1764   // requests it, we want a custom width of 0.
   1765 
   1766   // Let User32 handle the first nccalcsize for captioned windows
   1767   // so it updates its internal structures (specifically caption-present)
   1768   // Without this Tile & Cascade windows won't work.
   1769   // See http://code.google.com/p/chromium/issues/detail?id=900
   1770   if (is_first_nccalc_) {
   1771     is_first_nccalc_ = false;
   1772     if (GetWindowLong(hwnd(), GWL_STYLE) & WS_CAPTION) {
   1773       SetMsgHandled(FALSE);
   1774       return 0;
   1775     }
   1776   }
   1777 
   1778   gfx::Insets insets;
   1779   bool got_insets = GetClientAreaInsets(&insets);
   1780   if (!got_insets && !fullscreen_handler_->fullscreen() &&
   1781       !(mode && remove_standard_frame_)) {
   1782     SetMsgHandled(FALSE);
   1783     return 0;
   1784   }
   1785 
   1786   RECT* client_rect = mode ?
   1787       &(reinterpret_cast<NCCALCSIZE_PARAMS*>(l_param)->rgrc[0]) :
   1788       reinterpret_cast<RECT*>(l_param);
   1789   client_rect->left += insets.left();
   1790   client_rect->top += insets.top();
   1791   client_rect->bottom -= insets.bottom();
   1792   client_rect->right -= insets.right();
   1793   if (IsMaximized()) {
   1794     // Find all auto-hide taskbars along the screen edges and adjust in by the
   1795     // thickness of the auto-hide taskbar on each such edge, so the window isn't
   1796     // treated as a "fullscreen app", which would cause the taskbars to
   1797     // disappear.
   1798     HMONITOR monitor = MonitorFromWindow(hwnd(), MONITOR_DEFAULTTONULL);
   1799     if (!monitor) {
   1800       // We might end up here if the window was previously minimized and the
   1801       // user clicks on the taskbar button to restore it in the previously
   1802       // maximized position. In that case WM_NCCALCSIZE is sent before the
   1803       // window coordinates are restored to their previous values, so our
   1804       // (left,top) would probably be (-32000,-32000) like all minimized
   1805       // windows. So the above MonitorFromWindow call fails, but if we check
   1806       // the window rect given with WM_NCCALCSIZE (which is our previous
   1807       // restored window position) we will get the correct monitor handle.
   1808       monitor = MonitorFromRect(client_rect, MONITOR_DEFAULTTONULL);
   1809       if (!monitor) {
   1810         // This is probably an extreme case that we won't hit, but if we don't
   1811         // intersect any monitor, let us not adjust the client rect since our
   1812         // window will not be visible anyway.
   1813         return 0;
   1814       }
   1815     }
   1816     const int autohide_edges = GetAppbarAutohideEdges(monitor);
   1817     if (autohide_edges & Appbar::EDGE_LEFT)
   1818       client_rect->left += kAutoHideTaskbarThicknessPx;
   1819     if (autohide_edges & Appbar::EDGE_TOP) {
   1820       if (!delegate_->IsUsingCustomFrame()) {
   1821         // Tricky bit.  Due to a bug in DwmDefWindowProc()'s handling of
   1822         // WM_NCHITTEST, having any nonclient area atop the window causes the
   1823         // caption buttons to draw onscreen but not respond to mouse
   1824         // hover/clicks.
   1825         // So for a taskbar at the screen top, we can't push the
   1826         // client_rect->top down; instead, we move the bottom up by one pixel,
   1827         // which is the smallest change we can make and still get a client area
   1828         // less than the screen size. This is visibly ugly, but there seems to
   1829         // be no better solution.
   1830         --client_rect->bottom;
   1831       } else {
   1832         client_rect->top += kAutoHideTaskbarThicknessPx;
   1833       }
   1834     }
   1835     if (autohide_edges & Appbar::EDGE_RIGHT)
   1836       client_rect->right -= kAutoHideTaskbarThicknessPx;
   1837     if (autohide_edges & Appbar::EDGE_BOTTOM)
   1838       client_rect->bottom -= kAutoHideTaskbarThicknessPx;
   1839 
   1840     // We cannot return WVR_REDRAW when there is nonclient area, or Windows
   1841     // exhibits bugs where client pixels and child HWNDs are mispositioned by
   1842     // the width/height of the upper-left nonclient area.
   1843     return 0;
   1844   }
   1845 
   1846   // If the window bounds change, we're going to relayout and repaint anyway.
   1847   // Returning WVR_REDRAW avoids an extra paint before that of the old client
   1848   // pixels in the (now wrong) location, and thus makes actions like resizing a
   1849   // window from the left edge look slightly less broken.
   1850   // We special case when left or top insets are 0, since these conditions
   1851   // actually require another repaint to correct the layout after glass gets
   1852   // turned on and off.
   1853   if (insets.left() == 0 || insets.top() == 0)
   1854     return 0;
   1855   return mode ? WVR_REDRAW : 0;
   1856 }
   1857 
   1858 LRESULT HWNDMessageHandler::OnNCHitTest(const CPoint& point) {
   1859   if (!delegate_->IsWidgetWindow()) {
   1860     SetMsgHandled(FALSE);
   1861     return 0;
   1862   }
   1863 
   1864   // If the DWM is rendering the window controls, we need to give the DWM's
   1865   // default window procedure first chance to handle hit testing.
   1866   if (!remove_standard_frame_ && !delegate_->IsUsingCustomFrame()) {
   1867     LRESULT result;
   1868     if (DwmDefWindowProc(hwnd(), WM_NCHITTEST, 0,
   1869                          MAKELPARAM(point.x, point.y), &result)) {
   1870       return result;
   1871     }
   1872   }
   1873 
   1874   // First, give the NonClientView a chance to test the point to see if it
   1875   // provides any of the non-client area.
   1876   POINT temp = point;
   1877   MapWindowPoints(HWND_DESKTOP, hwnd(), &temp, 1);
   1878   int component = delegate_->GetNonClientComponent(gfx::Point(temp));
   1879   if (component != HTNOWHERE)
   1880     return component;
   1881 
   1882   // Otherwise, we let Windows do all the native frame non-client handling for
   1883   // us.
   1884 #if defined(USE_AURA)
   1885   LRESULT hit_test_code = DefWindowProc(hwnd(), WM_NCHITTEST, 0,
   1886                                         MAKELPARAM(point.x, point.y));
   1887   if (needs_scroll_styles_) {
   1888     switch (hit_test_code) {
   1889       // If we faked the WS_VSCROLL and WS_HSCROLL styles for this window, then
   1890       // Windows returns the HTVSCROLL or HTHSCROLL hit test codes if we hover
   1891       // or click on the non client portions of the window where the OS
   1892       // scrollbars would be drawn. These hittest codes are returned even when
   1893       // the scrollbars are hidden, which is the case in Aura. We fake the
   1894       // hittest code as HTCLIENT in this case to ensure that we receive client
   1895       // mouse messages as opposed to non client mouse messages.
   1896       case HTVSCROLL:
   1897       case HTHSCROLL:
   1898         hit_test_code = HTCLIENT;
   1899         break;
   1900 
   1901       case HTBOTTOMRIGHT: {
   1902         // Normally the HTBOTTOMRIGHT hittest code is received when we hover
   1903         // near the bottom right of the window. However due to our fake scroll
   1904         // styles, we get this code even when we hover around the area where
   1905         // the vertical scrollar down arrow would be drawn.
   1906         // We check if the hittest coordinates lie in this region and if yes
   1907         // we return HTCLIENT.
   1908         int border_width = ::GetSystemMetrics(SM_CXSIZEFRAME);
   1909         int border_height = ::GetSystemMetrics(SM_CYSIZEFRAME);
   1910         int scroll_width = ::GetSystemMetrics(SM_CXVSCROLL);
   1911         int scroll_height = ::GetSystemMetrics(SM_CYVSCROLL);
   1912         RECT window_rect;
   1913         ::GetWindowRect(hwnd(), &window_rect);
   1914         window_rect.bottom -= border_height;
   1915         window_rect.right -= border_width;
   1916         window_rect.left = window_rect.right - scroll_width;
   1917         window_rect.top = window_rect.bottom - scroll_height;
   1918         POINT pt;
   1919         pt.x = point.x;
   1920         pt.y = point.y;
   1921         if (::PtInRect(&window_rect, pt))
   1922           hit_test_code = HTCLIENT;
   1923         break;
   1924       }
   1925 
   1926       default:
   1927         break;
   1928     }
   1929   }
   1930   return hit_test_code;
   1931 #else
   1932   SetMsgHandled(FALSE);
   1933 #endif
   1934 }
   1935 
   1936 void HWNDMessageHandler::OnNCPaint(HRGN rgn) {
   1937   // We only do non-client painting if we're not using the native frame.
   1938   // It's required to avoid some native painting artifacts from appearing when
   1939   // the window is resized.
   1940   if (!delegate_->IsWidgetWindow() || !delegate_->IsUsingCustomFrame()) {
   1941     SetMsgHandled(FALSE);
   1942     return;
   1943   }
   1944 
   1945   // We have an NC region and need to paint it. We expand the NC region to
   1946   // include the dirty region of the root view. This is done to minimize
   1947   // paints.
   1948   CRect window_rect;
   1949   GetWindowRect(hwnd(), &window_rect);
   1950 
   1951   gfx::Size root_view_size = delegate_->GetRootViewSize();
   1952   if (gfx::Size(window_rect.Width(), window_rect.Height()) != root_view_size) {
   1953     // If the size of the window differs from the size of the root view it
   1954     // means we're being asked to paint before we've gotten a WM_SIZE. This can
   1955     // happen when the user is interactively resizing the window. To avoid
   1956     // mass flickering we don't do anything here. Once we get the WM_SIZE we'll
   1957     // reset the region of the window which triggers another WM_NCPAINT and
   1958     // all is well.
   1959     return;
   1960   }
   1961 
   1962   CRect dirty_region;
   1963   // A value of 1 indicates paint all.
   1964   if (!rgn || rgn == reinterpret_cast<HRGN>(1)) {
   1965     dirty_region = CRect(0, 0, window_rect.Width(), window_rect.Height());
   1966   } else {
   1967     RECT rgn_bounding_box;
   1968     GetRgnBox(rgn, &rgn_bounding_box);
   1969     if (!IntersectRect(&dirty_region, &rgn_bounding_box, &window_rect))
   1970       return;  // Dirty region doesn't intersect window bounds, bale.
   1971 
   1972     // rgn_bounding_box is in screen coordinates. Map it to window coordinates.
   1973     OffsetRect(&dirty_region, -window_rect.left, -window_rect.top);
   1974   }
   1975 
   1976   // In theory GetDCEx should do what we want, but I couldn't get it to work.
   1977   // In particular the docs mentiond DCX_CLIPCHILDREN, but as far as I can tell
   1978   // it doesn't work at all. So, instead we get the DC for the window then
   1979   // manually clip out the children.
   1980   HDC dc = GetWindowDC(hwnd());
   1981   ClipState clip_state;
   1982   clip_state.x = window_rect.left;
   1983   clip_state.y = window_rect.top;
   1984   clip_state.parent = hwnd();
   1985   clip_state.dc = dc;
   1986   EnumChildWindows(hwnd(), &ClipDCToChild,
   1987                    reinterpret_cast<LPARAM>(&clip_state));
   1988 
   1989   gfx::Rect old_paint_region = invalid_rect_;
   1990   if (!old_paint_region.IsEmpty()) {
   1991     // The root view has a region that needs to be painted. Include it in the
   1992     // region we're going to paint.
   1993 
   1994     CRect old_paint_region_crect = old_paint_region.ToRECT();
   1995     CRect tmp = dirty_region;
   1996     UnionRect(&dirty_region, &tmp, &old_paint_region_crect);
   1997   }
   1998 
   1999   SchedulePaintInRect(gfx::Rect(dirty_region));
   2000 
   2001   // gfx::CanvasSkiaPaint's destructor does the actual painting. As such, wrap
   2002   // the following in a block to force paint to occur so that we can release
   2003   // the dc.
   2004   if (!delegate_->HandlePaintAccelerated(gfx::Rect(dirty_region))) {
   2005     gfx::CanvasSkiaPaint canvas(dc, true, dirty_region.left,
   2006                                 dirty_region.top, dirty_region.Width(),
   2007                                 dirty_region.Height());
   2008     delegate_->HandlePaint(&canvas);
   2009   }
   2010 
   2011   ReleaseDC(hwnd(), dc);
   2012   // When using a custom frame, we want to avoid calling DefWindowProc() since
   2013   // that may render artifacts.
   2014   SetMsgHandled(delegate_->IsUsingCustomFrame());
   2015 }
   2016 
   2017 LRESULT HWNDMessageHandler::OnNCUAHDrawCaption(UINT message,
   2018                                                WPARAM w_param,
   2019                                                LPARAM l_param) {
   2020   // See comment in widget_win.h at the definition of WM_NCUAHDRAWCAPTION for
   2021   // an explanation about why we need to handle this message.
   2022   SetMsgHandled(delegate_->IsUsingCustomFrame());
   2023   return 0;
   2024 }
   2025 
   2026 LRESULT HWNDMessageHandler::OnNCUAHDrawFrame(UINT message,
   2027                                              WPARAM w_param,
   2028                                              LPARAM l_param) {
   2029   // See comment in widget_win.h at the definition of WM_NCUAHDRAWCAPTION for
   2030   // an explanation about why we need to handle this message.
   2031   SetMsgHandled(delegate_->IsUsingCustomFrame());
   2032   return 0;
   2033 }
   2034 
   2035 LRESULT HWNDMessageHandler::OnNotify(int w_param, NMHDR* l_param) {
   2036   LRESULT l_result = 0;
   2037   SetMsgHandled(delegate_->HandleTooltipNotify(w_param, l_param, &l_result));
   2038   return l_result;
   2039 }
   2040 
   2041 void HWNDMessageHandler::OnPaint(HDC dc) {
   2042   // Call BeginPaint()/EndPaint() around the paint handling, as that seems
   2043   // to do more to actually validate the window's drawing region. This only
   2044   // appears to matter for Windows that have the WS_EX_COMPOSITED style set
   2045   // but will be valid in general too.
   2046   PAINTSTRUCT ps;
   2047   HDC display_dc = BeginPaint(hwnd(), &ps);
   2048   CHECK(display_dc);
   2049 
   2050   // Try to paint accelerated first.
   2051   if (!IsRectEmpty(&ps.rcPaint) &&
   2052       !delegate_->HandlePaintAccelerated(gfx::Rect(ps.rcPaint))) {
   2053 #if defined(USE_AURA)
   2054     delegate_->HandlePaint(NULL);
   2055 #else
   2056     scoped_ptr<gfx::CanvasSkiaPaint> canvas(
   2057         new gfx::CanvasSkiaPaint(hwnd(), display_dc, ps));
   2058     delegate_->HandlePaint(canvas.get());
   2059 #endif
   2060   }
   2061 
   2062   EndPaint(hwnd(), &ps);
   2063 }
   2064 
   2065 LRESULT HWNDMessageHandler::OnReflectedMessage(UINT message,
   2066                                                WPARAM w_param,
   2067                                                LPARAM l_param) {
   2068   SetMsgHandled(FALSE);
   2069   return 0;
   2070 }
   2071 
   2072 LRESULT HWNDMessageHandler::OnScrollMessage(UINT message,
   2073                                             WPARAM w_param,
   2074                                             LPARAM l_param) {
   2075   MSG msg = { hwnd(), message, w_param, l_param, GetMessageTime() };
   2076   ui::ScrollEvent event(msg);
   2077   delegate_->HandleScrollEvent(event);
   2078   return 0;
   2079 }
   2080 
   2081 void HWNDMessageHandler::OnSessionChange(WPARAM status_code,
   2082                                          PWTSSESSION_NOTIFICATION session_id) {
   2083   // Direct3D presents are ignored while the screen is locked, so force the
   2084   // window to be redrawn on unlock.
   2085   if (status_code == WTS_SESSION_UNLOCK)
   2086     ForceRedrawWindow(10);
   2087 
   2088   SetMsgHandled(FALSE);
   2089 }
   2090 
   2091 LRESULT HWNDMessageHandler::OnSetCursor(UINT message,
   2092                                         WPARAM w_param,
   2093                                         LPARAM l_param) {
   2094   // Reimplement the necessary default behavior here. Calling DefWindowProc can
   2095   // trigger weird non-client painting for non-glass windows with custom frames.
   2096   // Using a ScopedRedrawLock to prevent caption rendering artifacts may allow
   2097   // content behind this window to incorrectly paint in front of this window.
   2098   // Invalidating the window to paint over either set of artifacts is not ideal.
   2099   wchar_t* cursor = IDC_ARROW;
   2100   switch (LOWORD(l_param)) {
   2101     case HTSIZE:
   2102       cursor = IDC_SIZENWSE;
   2103       break;
   2104     case HTLEFT:
   2105     case HTRIGHT:
   2106       cursor = IDC_SIZEWE;
   2107       break;
   2108     case HTTOP:
   2109     case HTBOTTOM:
   2110       cursor = IDC_SIZENS;
   2111       break;
   2112     case HTTOPLEFT:
   2113     case HTBOTTOMRIGHT:
   2114       cursor = IDC_SIZENWSE;
   2115       break;
   2116     case HTTOPRIGHT:
   2117     case HTBOTTOMLEFT:
   2118       cursor = IDC_SIZENESW;
   2119       break;
   2120     case HTCLIENT:
   2121       SetCursor(current_cursor_);
   2122       return 1;
   2123     default:
   2124       // Use the default value, IDC_ARROW.
   2125       break;
   2126   }
   2127   ::SetCursor(LoadCursor(NULL, cursor));
   2128   return 1;
   2129 }
   2130 
   2131 void HWNDMessageHandler::OnSetFocus(HWND last_focused_window) {
   2132   delegate_->HandleNativeFocus(last_focused_window);
   2133   SetMsgHandled(FALSE);
   2134 }
   2135 
   2136 LRESULT HWNDMessageHandler::OnSetIcon(UINT size_type, HICON new_icon) {
   2137   // Use a ScopedRedrawLock to avoid weird non-client painting.
   2138   return DefWindowProcWithRedrawLock(WM_SETICON, size_type,
   2139                                      reinterpret_cast<LPARAM>(new_icon));
   2140 }
   2141 
   2142 LRESULT HWNDMessageHandler::OnSetText(const wchar_t* text) {
   2143   // Use a ScopedRedrawLock to avoid weird non-client painting.
   2144   return DefWindowProcWithRedrawLock(WM_SETTEXT, NULL,
   2145                                      reinterpret_cast<LPARAM>(text));
   2146 }
   2147 
   2148 void HWNDMessageHandler::OnSettingChange(UINT flags, const wchar_t* section) {
   2149   if (!GetParent(hwnd()) && (flags == SPI_SETWORKAREA) &&
   2150       !delegate_->WillProcessWorkAreaChange()) {
   2151     // Fire a dummy SetWindowPos() call, so we'll trip the code in
   2152     // OnWindowPosChanging() below that notices work area changes.
   2153     ::SetWindowPos(hwnd(), 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
   2154         SWP_NOZORDER | SWP_NOREDRAW | SWP_NOACTIVATE | SWP_NOOWNERZORDER);
   2155     SetMsgHandled(TRUE);
   2156   } else {
   2157     if (flags == SPI_SETWORKAREA)
   2158       delegate_->HandleWorkAreaChanged();
   2159     SetMsgHandled(FALSE);
   2160   }
   2161 }
   2162 
   2163 void HWNDMessageHandler::OnSize(UINT param, const CSize& size) {
   2164   RedrawWindow(hwnd(), NULL, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN);
   2165   // ResetWindowRegion is going to trigger WM_NCPAINT. By doing it after we've
   2166   // invoked OnSize we ensure the RootView has been laid out.
   2167   ResetWindowRegion(false, true);
   2168 
   2169 #if defined(USE_AURA)
   2170   // We add the WS_VSCROLL and WS_HSCROLL styles to top level windows to ensure
   2171   // that legacy trackpad/trackpoint drivers generate the WM_VSCROLL and
   2172   // WM_HSCROLL messages and scrolling works.
   2173   // We want the scroll styles to be present on the window. However we don't
   2174   // want Windows to draw the scrollbars. To achieve this we hide the scroll
   2175   // bars and readd them to the window style in a posted task to ensure that we
   2176   // don't get nested WM_SIZE messages.
   2177   if (needs_scroll_styles_ && !in_size_loop_) {
   2178     ShowScrollBar(hwnd(), SB_BOTH, FALSE);
   2179     base::MessageLoop::current()->PostTask(
   2180         FROM_HERE, base::Bind(&AddScrollStylesToWindow, hwnd()));
   2181   }
   2182 #endif
   2183 }
   2184 
   2185 void HWNDMessageHandler::OnSysCommand(UINT notification_code,
   2186                                       const CPoint& point) {
   2187   if (!delegate_->ShouldHandleSystemCommands())
   2188     return;
   2189 
   2190   // Windows uses the 4 lower order bits of |notification_code| for type-
   2191   // specific information so we must exclude this when comparing.
   2192   static const int sc_mask = 0xFFF0;
   2193   // Ignore size/move/maximize in fullscreen mode.
   2194   if (fullscreen_handler_->fullscreen() &&
   2195       (((notification_code & sc_mask) == SC_SIZE) ||
   2196        ((notification_code & sc_mask) == SC_MOVE) ||
   2197        ((notification_code & sc_mask) == SC_MAXIMIZE)))
   2198     return;
   2199   if (delegate_->IsUsingCustomFrame()) {
   2200     if ((notification_code & sc_mask) == SC_MINIMIZE ||
   2201         (notification_code & sc_mask) == SC_MAXIMIZE ||
   2202         (notification_code & sc_mask) == SC_RESTORE) {
   2203       delegate_->ResetWindowControls();
   2204     } else if ((notification_code & sc_mask) == SC_MOVE ||
   2205                (notification_code & sc_mask) == SC_SIZE) {
   2206       if (!IsVisible()) {
   2207         // Circumvent ScopedRedrawLocks and force visibility before entering a
   2208         // resize or move modal loop to get continuous sizing/moving feedback.
   2209         SetWindowLong(hwnd(), GWL_STYLE,
   2210                       GetWindowLong(hwnd(), GWL_STYLE) | WS_VISIBLE);
   2211       }
   2212     }
   2213   }
   2214 
   2215   // Handle SC_KEYMENU, which means that the user has pressed the ALT
   2216   // key and released it, so we should focus the menu bar.
   2217   if ((notification_code & sc_mask) == SC_KEYMENU && point.x == 0) {
   2218     int modifiers = ui::EF_NONE;
   2219     if (base::win::IsShiftPressed())
   2220       modifiers |= ui::EF_SHIFT_DOWN;
   2221     if (base::win::IsCtrlPressed())
   2222       modifiers |= ui::EF_CONTROL_DOWN;
   2223     // Retrieve the status of shift and control keys to prevent consuming
   2224     // shift+alt keys, which are used by Windows to change input languages.
   2225     ui::Accelerator accelerator(ui::KeyboardCodeForWindowsKeyCode(VK_MENU),
   2226                                 modifiers);
   2227     delegate_->HandleAccelerator(accelerator);
   2228     return;
   2229   }
   2230 
   2231   // If the delegate can't handle it, the system implementation will be called.
   2232   if (!delegate_->HandleCommand(notification_code)) {
   2233     // If the window is being resized by dragging the borders of the window
   2234     // with the mouse/touch/keyboard, we flag as being in a size loop.
   2235     if ((notification_code & sc_mask) == SC_SIZE)
   2236       in_size_loop_ = true;
   2237     DefWindowProc(hwnd(), WM_SYSCOMMAND, notification_code,
   2238                   MAKELPARAM(point.x, point.y));
   2239     in_size_loop_ = false;
   2240   }
   2241 }
   2242 
   2243 void HWNDMessageHandler::OnThemeChanged() {
   2244   ui::NativeThemeWin::instance()->CloseHandles();
   2245 }
   2246 
   2247 LRESULT HWNDMessageHandler::OnTouchEvent(UINT message,
   2248                                          WPARAM w_param,
   2249                                          LPARAM l_param) {
   2250   // Handle touch events only on Aura for now.
   2251 #if !defined(USE_AURA)
   2252   SetMsgHandled(FALSE);
   2253   return 0;
   2254 #endif
   2255   int num_points = LOWORD(w_param);
   2256   scoped_ptr<TOUCHINPUT[]> input(new TOUCHINPUT[num_points]);
   2257   if (ui::GetTouchInputInfoWrapper(reinterpret_cast<HTOUCHINPUT>(l_param),
   2258                                    num_points, input.get(),
   2259                                    sizeof(TOUCHINPUT))) {
   2260     TouchEvents touch_events;
   2261     for (int i = 0; i < num_points; ++i) {
   2262       ui::EventType touch_event_type = ui::ET_UNKNOWN;
   2263 
   2264       if (input[i].dwFlags & TOUCHEVENTF_DOWN) {
   2265         touch_ids_.insert(input[i].dwID);
   2266         touch_event_type = ui::ET_TOUCH_PRESSED;
   2267       } else if (input[i].dwFlags & TOUCHEVENTF_UP) {
   2268         touch_ids_.erase(input[i].dwID);
   2269         touch_event_type = ui::ET_TOUCH_RELEASED;
   2270       } else if (input[i].dwFlags & TOUCHEVENTF_MOVE) {
   2271         touch_event_type = ui::ET_TOUCH_MOVED;
   2272       }
   2273       if (touch_event_type != ui::ET_UNKNOWN) {
   2274         POINT point;
   2275         point.x = TOUCH_COORD_TO_PIXEL(input[i].x) /
   2276             gfx::win::GetUndocumentedDPITouchScale();
   2277         point.y = TOUCH_COORD_TO_PIXEL(input[i].y) /
   2278             gfx::win::GetUndocumentedDPITouchScale();
   2279 
   2280         ScreenToClient(hwnd(), &point);
   2281 
   2282         ui::TouchEvent event(
   2283             touch_event_type,
   2284             gfx::Point(point.x, point.y),
   2285             id_generator_.GetGeneratedID(input[i].dwID),
   2286             base::TimeDelta::FromMilliseconds(input[i].dwTime));
   2287         touch_events.push_back(event);
   2288         if (touch_event_type == ui::ET_TOUCH_RELEASED)
   2289           id_generator_.ReleaseNumber(input[i].dwID);
   2290       }
   2291     }
   2292     // Handle the touch events asynchronously. We need this because touch
   2293     // events on windows don't fire if we enter a modal loop in the context of
   2294     // a touch event.
   2295     base::MessageLoop::current()->PostTask(
   2296         FROM_HERE,
   2297         base::Bind(&HWNDMessageHandler::HandleTouchEvents,
   2298                    weak_factory_.GetWeakPtr(), touch_events));
   2299   }
   2300   CloseTouchInputHandle(reinterpret_cast<HTOUCHINPUT>(l_param));
   2301   SetMsgHandled(FALSE);
   2302   return 0;
   2303 }
   2304 
   2305 void HWNDMessageHandler::OnWindowPosChanging(WINDOWPOS* window_pos) {
   2306   if (ignore_window_pos_changes_) {
   2307     // If somebody's trying to toggle our visibility, change the nonclient area,
   2308     // change our Z-order, or activate us, we should probably let it go through.
   2309     if (!(window_pos->flags & ((IsVisible() ? SWP_HIDEWINDOW : SWP_SHOWWINDOW) |
   2310         SWP_FRAMECHANGED)) &&
   2311         (window_pos->flags & (SWP_NOZORDER | SWP_NOACTIVATE))) {
   2312       // Just sizing/moving the window; ignore.
   2313       window_pos->flags |= SWP_NOSIZE | SWP_NOMOVE | SWP_NOREDRAW;
   2314       window_pos->flags &= ~(SWP_SHOWWINDOW | SWP_HIDEWINDOW);
   2315     }
   2316   } else if (!GetParent(hwnd())) {
   2317     CRect window_rect;
   2318     HMONITOR monitor;
   2319     gfx::Rect monitor_rect, work_area;
   2320     if (GetWindowRect(hwnd(), &window_rect) &&
   2321         GetMonitorAndRects(window_rect, &monitor, &monitor_rect, &work_area)) {
   2322       bool work_area_changed = (monitor_rect == last_monitor_rect_) &&
   2323                                (work_area != last_work_area_);
   2324       if (monitor && (monitor == last_monitor_) &&
   2325           ((fullscreen_handler_->fullscreen() &&
   2326             !fullscreen_handler_->metro_snap()) ||
   2327             work_area_changed)) {
   2328         // A rect for the monitor we're on changed.  Normally Windows notifies
   2329         // us about this (and thus we're reaching here due to the SetWindowPos()
   2330         // call in OnSettingChange() above), but with some software (e.g.
   2331         // nVidia's nView desktop manager) the work area can change asynchronous
   2332         // to any notification, and we're just sent a SetWindowPos() call with a
   2333         // new (frequently incorrect) position/size.  In either case, the best
   2334         // response is to throw away the existing position/size information in
   2335         // |window_pos| and recalculate it based on the new work rect.
   2336         gfx::Rect new_window_rect;
   2337         if (fullscreen_handler_->fullscreen()) {
   2338           new_window_rect = monitor_rect;
   2339         } else if (IsMaximized()) {
   2340           new_window_rect = work_area;
   2341           int border_thickness = GetSystemMetrics(SM_CXSIZEFRAME);
   2342           new_window_rect.Inset(-border_thickness, -border_thickness);
   2343         } else {
   2344           new_window_rect = gfx::Rect(window_rect);
   2345           new_window_rect.AdjustToFit(work_area);
   2346         }
   2347         window_pos->x = new_window_rect.x();
   2348         window_pos->y = new_window_rect.y();
   2349         window_pos->cx = new_window_rect.width();
   2350         window_pos->cy = new_window_rect.height();
   2351         // WARNING!  Don't set SWP_FRAMECHANGED here, it breaks moving the child
   2352         // HWNDs for some reason.
   2353         window_pos->flags &= ~(SWP_NOSIZE | SWP_NOMOVE | SWP_NOREDRAW);
   2354         window_pos->flags |= SWP_NOCOPYBITS;
   2355 
   2356         // Now ignore all immediately-following SetWindowPos() changes.  Windows
   2357         // likes to (incorrectly) recalculate what our position/size should be
   2358         // and send us further updates.
   2359         ignore_window_pos_changes_ = true;
   2360         base::MessageLoop::current()->PostTask(
   2361             FROM_HERE,
   2362             base::Bind(&HWNDMessageHandler::StopIgnoringPosChanges,
   2363                        weak_factory_.GetWeakPtr()));
   2364       }
   2365       last_monitor_ = monitor;
   2366       last_monitor_rect_ = monitor_rect;
   2367       last_work_area_ = work_area;
   2368     }
   2369   }
   2370 
   2371   if (ScopedFullscreenVisibility::IsHiddenForFullscreen(hwnd())) {
   2372     // Prevent the window from being made visible if we've been asked to do so.
   2373     // See comment in header as to why we might want this.
   2374     window_pos->flags &= ~SWP_SHOWWINDOW;
   2375   }
   2376 
   2377   if (window_pos->flags & SWP_SHOWWINDOW)
   2378     delegate_->HandleVisibilityChanging(true);
   2379   else if (window_pos->flags & SWP_HIDEWINDOW)
   2380     delegate_->HandleVisibilityChanging(false);
   2381 
   2382   SetMsgHandled(FALSE);
   2383 }
   2384 
   2385 void HWNDMessageHandler::OnWindowPosChanged(WINDOWPOS* window_pos) {
   2386   if (DidClientAreaSizeChange(window_pos))
   2387     ClientAreaSizeChanged();
   2388   if (remove_standard_frame_ && window_pos->flags & SWP_FRAMECHANGED &&
   2389       ui::win::IsAeroGlassEnabled() &&
   2390       (window_ex_style() & WS_EX_COMPOSITED) == 0) {
   2391     MARGINS m = {10, 10, 10, 10};
   2392     DwmExtendFrameIntoClientArea(hwnd(), &m);
   2393   }
   2394   if (window_pos->flags & SWP_SHOWWINDOW)
   2395     delegate_->HandleVisibilityChanged(true);
   2396   else if (window_pos->flags & SWP_HIDEWINDOW)
   2397     delegate_->HandleVisibilityChanged(false);
   2398   SetMsgHandled(FALSE);
   2399 }
   2400 
   2401 void HWNDMessageHandler::HandleTouchEvents(const TouchEvents& touch_events) {
   2402   base::WeakPtr<HWNDMessageHandler> ref(weak_factory_.GetWeakPtr());
   2403   for (size_t i = 0; i < touch_events.size() && ref; ++i)
   2404     delegate_->HandleTouchEvent(touch_events[i]);
   2405 }
   2406 
   2407 }  // namespace views
   2408