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.
5 #ifndef UI_VIEWS_WIN_HWND_MESSAGE_HANDLER_H_
6 #define UI_VIEWS_WIN_HWND_MESSAGE_HANDLER_H_
16 #include "base/basictypes.h"
17 #include "base/compiler_specific.h"
18 #include "base/memory/scoped_ptr.h"
19 #include "base/memory/weak_ptr.h"
20 #include "base/message_loop/message_loop.h"
21 #include "base/strings/string16.h"
22 #include "base/win/win_util.h"
23 #include "ui/base/accessibility/accessibility_types.h"
24 #include "ui/base/ui_base_types.h"
25 #include "ui/events/event.h"
26 #include "ui/gfx/rect.h"
27 #include "ui/gfx/sequential_id_generator.h"
28 #include "ui/gfx/win/window_impl.h"
29 #include "ui/views/ime/input_method_delegate.h"
30 #include "ui/views/views_export.h"
40 class FullscreenHandler;
41 class HWNDMessageHandlerDelegate;
44 // These two messages aren't defined in winuser.h, but they are sent to windows
45 // with captions. They appear to paint the window caption and frame.
46 // Unfortunately if you override the standard non-client rendering as we do
47 // with CustomFrameWindow, sometimes Windows (not deterministically
48 // reproducibly but definitely frequently) will send these messages to the
49 // window and paint the standard caption/title over the top of the custom one.
50 // So we need to handle these messages in CustomFrameWindow to prevent this
52 const int WM_NCUAHDRAWCAPTION = 0xAE;
53 const int WM_NCUAHDRAWFRAME = 0xAF;
55 // IsMsgHandled() and BEGIN_SAFE_MSG_MAP_EX are a modified version of
56 // BEGIN_MSG_MAP_EX. The main difference is it adds a WeakPtrFactory member
57 // (|weak_factory_|) that is used in _ProcessWindowMessage() and changing
58 // IsMsgHandled() from a member function to a define that checks if the weak
59 // factory is still valid in addition to the member. Together these allow for
60 // |this| to be deleted during dispatch.
61 #define IsMsgHandled() !ref.get() || msg_handled_
63 #define BEGIN_SAFE_MSG_MAP_EX(the_class) \
65 base::WeakPtrFactory<the_class> weak_factory_; \
69 /* "handled" management for cracked handlers */ \
70 void SetMsgHandled(BOOL handled) { \
71 msg_handled_ = handled; \
73 BOOL ProcessWindowMessage(HWND hwnd, \
78 DWORD msg_map_id = 0) { \
79 BOOL old_msg_handled = msg_handled_; \
80 BOOL ret = _ProcessWindowMessage(hwnd, msg, w_param, l_param, l_result, \
82 msg_handled_ = old_msg_handled; \
85 BOOL _ProcessWindowMessage(HWND hWnd, \
91 base::WeakPtr<HWNDMessageHandler> ref(weak_factory_.GetWeakPtr()); \
92 BOOL bHandled = TRUE; \
99 switch(dwMsgMapID) { \
102 // An object that handles messages for a HWND that implements the views
103 // "Custom Frame" look. The purpose of this class is to isolate the windows-
104 // specific message handling from the code that wraps it. It is intended to be
105 // used by both a views::NativeWidget and an aura::RootWindowHost
107 // TODO(beng): This object should eventually *become* the WindowImpl.
108 class VIEWS_EXPORT HWNDMessageHandler :
109 public gfx::WindowImpl,
110 public internal::InputMethodDelegate,
111 public base::MessageLoopForUI::Observer {
113 explicit HWNDMessageHandler(HWNDMessageHandlerDelegate* delegate);
114 ~HWNDMessageHandler();
116 void Init(HWND parent, const gfx::Rect& bounds);
117 void InitModalType(ui::ModalType modal_type);
122 gfx::Rect GetWindowBoundsInScreen() const;
123 gfx::Rect GetClientAreaBoundsInScreen() const;
124 gfx::Rect GetRestoredBounds() const;
125 void GetWindowPlacement(gfx::Rect* bounds,
126 ui::WindowShowState* show_state) const;
128 void SetBounds(const gfx::Rect& bounds_in_pixels);
129 void SetSize(const gfx::Size& size);
130 void CenterWindow(const gfx::Size& size);
132 void SetRegion(HRGN rgn);
134 void StackAbove(HWND other_hwnd);
138 void ShowWindowWithState(ui::WindowShowState show_state);
139 // TODO(beng): distinguish from ShowWindowWithState().
140 void Show(int show_state);
141 void ShowMaximizedWithBounds(const gfx::Rect& bounds);
151 void SetAlwaysOnTop(bool on_top);
153 bool IsVisible() const;
154 bool IsActive() const;
155 bool IsMinimized() const;
156 bool IsMaximized() const;
157 bool IsAlwaysOnTop() const;
159 bool RunMoveLoop(const gfx::Vector2d& drag_offset, bool hide_on_escape);
162 // Tells the HWND its client area has changed.
163 void SendFrameChanged();
165 void FlashFrame(bool flash);
167 void ClearNativeFocus();
170 void ReleaseCapture();
171 bool HasCapture() const;
173 FullscreenHandler* fullscreen_handler() { return fullscreen_handler_.get(); }
175 void SetVisibilityChangedAnimationsEnabled(bool enabled);
177 void SetTitle(const string16& title);
179 void SetCursor(HCURSOR cursor);
181 void FrameTypeChanged();
183 // Disable Layered Window updates by setting to false.
184 void set_can_update_layered_window(bool can_update_layered_window) {
185 can_update_layered_window_ = can_update_layered_window;
187 void SchedulePaintInRect(const gfx::Rect& rect);
188 void SetOpacity(BYTE opacity);
190 void SetWindowIcons(const gfx::ImageSkia& window_icon,
191 const gfx::ImageSkia& app_icon);
193 void set_remove_standard_frame(bool remove_standard_frame) {
194 remove_standard_frame_ = remove_standard_frame;
197 void set_use_system_default_icon(bool use_system_default_icon) {
198 use_system_default_icon_ = use_system_default_icon;
202 typedef std::set<DWORD> TouchIDs;
204 // Overridden from internal::InputMethodDelegate:
205 virtual void DispatchKeyEventPostIME(const ui::KeyEvent& key) OVERRIDE;
207 // Overridden from WindowImpl:
208 virtual HICON GetDefaultWindowIcon() const OVERRIDE;
209 virtual LRESULT OnWndProc(UINT message,
211 LPARAM l_param) OVERRIDE;
213 // Overridden from MessageLoopForUI::Observer:
214 virtual base::EventStatus WillProcessEvent(
215 const base::NativeEvent& event) OVERRIDE;
216 virtual void DidProcessEvent(const base::NativeEvent& event) OVERRIDE;
218 // Returns the auto-hide edges of the appbar. See Appbar::GetAutohideEdges()
219 // for details. If the edges change OnAppbarAutohideEdgesChanged() is called.
220 int GetAppbarAutohideEdges(HMONITOR monitor);
222 // Callback if the autohide edges have changed. See Appbar for details.
223 void OnAppbarAutohideEdgesChanged();
225 // Can be called after the delegate has had the opportunity to set focus and
227 void SetInitialFocus();
229 // Called after the WM_ACTIVATE message has been processed by the default
230 // windows procedure.
231 void PostProcessActivateMessage(int activation_state, bool minimized);
233 // Enables disabled owner windows that may have been disabled due to this
234 // window's modality.
235 void RestoreEnabledIfNecessary();
237 // Executes the specified SC_command.
238 void ExecuteSystemMenuCommand(int command);
240 // Start tracking all mouse events so that this window gets sent mouse leave
242 void TrackMouseEvents(DWORD mouse_tracking_flags);
244 // Responds to the client area changing size, either at window creation time
246 void ClientAreaSizeChanged();
248 // Returns the insets of the client area relative to the non-client area of
250 bool GetClientAreaInsets(gfx::Insets* insets) const;
252 // Resets the window region for the current widget bounds if necessary.
253 // If |force| is true, the window region is reset to NULL even for native
255 void ResetWindowRegion(bool force);
257 // Calls DefWindowProc, safely wrapping the call in a ScopedRedrawLock to
258 // prevent frame flicker. DefWindowProc handling can otherwise render the
259 // classic-look window title bar directly.
260 LRESULT DefWindowProcWithRedrawLock(UINT message,
264 // Notifies any owned windows that we're closing.
265 void NotifyOwnedWindowsParentClosing();
267 // Lock or unlock the window from being able to redraw itself in response to
268 // updates to its invalid region.
269 class ScopedRedrawLock;
270 void LockUpdates(bool force);
271 void UnlockUpdates(bool force);
273 // Stops ignoring SetWindowPos() requests (see below).
274 void StopIgnoringPosChanges() { ignore_window_pos_changes_ = false; }
276 // Synchronously paints the invalid contents of the Widget.
277 void RedrawInvalidRect();
279 // Synchronously updates the invalid contents of the Widget. Valid for
280 // layered windows only.
281 void RedrawLayeredWindowContents();
283 // Message Handlers ----------------------------------------------------------
285 BEGIN_SAFE_MSG_MAP_EX(HWNDMessageHandler)
286 // Range handlers must go first!
287 MESSAGE_RANGE_HANDLER_EX(WM_MOUSEFIRST, WM_MOUSELAST, OnMouseRange)
288 MESSAGE_RANGE_HANDLER_EX(WM_NCMOUSEMOVE, WM_NCXBUTTONDBLCLK, OnMouseRange)
290 // CustomFrameWindow hacks
291 MESSAGE_HANDLER_EX(WM_NCUAHDRAWCAPTION, OnNCUAHDrawCaption)
292 MESSAGE_HANDLER_EX(WM_NCUAHDRAWFRAME, OnNCUAHDrawFrame)
295 MESSAGE_HANDLER_EX(WM_DWMCOMPOSITIONCHANGED, OnDwmCompositionChanged)
297 // Non-atlcrack.h handlers
298 MESSAGE_HANDLER_EX(WM_GETOBJECT, OnGetObject)
301 MESSAGE_HANDLER_EX(WM_MOUSEACTIVATE, OnMouseActivate)
302 MESSAGE_HANDLER_EX(WM_MOUSELEAVE, OnMouseRange)
303 MESSAGE_HANDLER_EX(WM_NCMOUSELEAVE, OnMouseRange)
304 MESSAGE_HANDLER_EX(WM_SETCURSOR, OnSetCursor);
307 MESSAGE_HANDLER_EX(WM_KEYDOWN, OnKeyEvent)
308 MESSAGE_HANDLER_EX(WM_KEYUP, OnKeyEvent)
309 MESSAGE_HANDLER_EX(WM_SYSKEYDOWN, OnKeyEvent)
310 MESSAGE_HANDLER_EX(WM_SYSKEYUP, OnKeyEvent)
313 MESSAGE_HANDLER_EX(WM_IME_SETCONTEXT, OnImeMessages)
314 MESSAGE_HANDLER_EX(WM_IME_STARTCOMPOSITION, OnImeMessages)
315 MESSAGE_HANDLER_EX(WM_IME_COMPOSITION, OnImeMessages)
316 MESSAGE_HANDLER_EX(WM_IME_ENDCOMPOSITION, OnImeMessages)
317 MESSAGE_HANDLER_EX(WM_IME_REQUEST, OnImeMessages)
318 MESSAGE_HANDLER_EX(WM_IME_NOTIFY, OnImeMessages)
319 MESSAGE_HANDLER_EX(WM_CHAR, OnImeMessages)
320 MESSAGE_HANDLER_EX(WM_SYSCHAR, OnImeMessages)
321 MESSAGE_HANDLER_EX(WM_DEADCHAR, OnImeMessages)
322 MESSAGE_HANDLER_EX(WM_SYSDEADCHAR, OnImeMessages)
325 MESSAGE_HANDLER_EX(WM_TOUCH, OnTouchEvent)
327 // Uses the general handler macro since the specific handler macro
328 // MSG_WM_NCACTIVATE would convert WPARAM type to BOOL type. The high
329 // word of WPARAM could be set when the window is minimized or restored.
330 MESSAGE_HANDLER_EX(WM_NCACTIVATE, OnNCActivate)
332 // This list is in _ALPHABETICAL_ order! OR I WILL HURT YOU.
333 MSG_WM_ACTIVATEAPP(OnActivateApp)
334 MSG_WM_APPCOMMAND(OnAppCommand)
335 MSG_WM_CANCELMODE(OnCancelMode)
336 MSG_WM_CAPTURECHANGED(OnCaptureChanged)
337 MSG_WM_CLOSE(OnClose)
338 MSG_WM_COMMAND(OnCommand)
339 MSG_WM_CREATE(OnCreate)
340 MSG_WM_DESTROY(OnDestroy)
341 MSG_WM_DISPLAYCHANGE(OnDisplayChange)
342 MSG_WM_ENTERSIZEMOVE(OnEnterSizeMove)
343 MSG_WM_ERASEBKGND(OnEraseBkgnd)
344 MSG_WM_EXITSIZEMOVE(OnExitSizeMove)
345 MSG_WM_GETMINMAXINFO(OnGetMinMaxInfo)
346 MSG_WM_INITMENU(OnInitMenu)
347 MSG_WM_INPUTLANGCHANGE(OnInputLangChange)
348 MSG_WM_KILLFOCUS(OnKillFocus)
350 MSG_WM_MOVING(OnMoving)
351 MSG_WM_NCCALCSIZE(OnNCCalcSize)
352 MSG_WM_NCHITTEST(OnNCHitTest)
353 MSG_WM_NCPAINT(OnNCPaint)
354 MSG_WM_NOTIFY(OnNotify)
355 MSG_WM_PAINT(OnPaint)
356 MSG_WM_SETFOCUS(OnSetFocus)
357 MSG_WM_SETICON(OnSetIcon)
358 MSG_WM_SETTEXT(OnSetText)
359 MSG_WM_SETTINGCHANGE(OnSettingChange)
361 MSG_WM_SYSCOMMAND(OnSysCommand)
362 MSG_WM_THEMECHANGED(OnThemeChanged)
363 MSG_WM_WINDOWPOSCHANGED(OnWindowPosChanged)
364 MSG_WM_WINDOWPOSCHANGING(OnWindowPosChanging)
368 // This list is in _ALPHABETICAL_ order!
369 // TODO(beng): Once this object becomes the WindowImpl, these methods can
371 void OnActivateApp(BOOL active, DWORD thread_id);
372 // TODO(beng): return BOOL is temporary until this object becomes a
374 BOOL OnAppCommand(HWND window, short command, WORD device, int keystate);
376 void OnCaptureChanged(HWND window);
378 void OnCommand(UINT notification_code, int command, HWND window);
379 LRESULT OnCreate(CREATESTRUCT* create_struct);
381 void OnDisplayChange(UINT bits_per_pixel, const CSize& screen_size);
382 LRESULT OnDwmCompositionChanged(UINT msg, WPARAM w_param, LPARAM l_param);
383 void OnEnterSizeMove();
384 LRESULT OnEraseBkgnd(HDC dc);
385 void OnExitSizeMove();
386 void OnGetMinMaxInfo(MINMAXINFO* minmax_info);
387 LRESULT OnGetObject(UINT message, WPARAM w_param, LPARAM l_param);
388 LRESULT OnImeMessages(UINT message, WPARAM w_param, LPARAM l_param);
389 void OnInitMenu(HMENU menu);
390 void OnInputLangChange(DWORD character_set, HKL input_language_id);
391 LRESULT OnKeyEvent(UINT message, WPARAM w_param, LPARAM l_param);
392 void OnKillFocus(HWND focused_window);
393 LRESULT OnMouseActivate(UINT message, WPARAM w_param, LPARAM l_param);
394 LRESULT OnMouseRange(UINT message, WPARAM w_param, LPARAM l_param);
395 void OnMove(const CPoint& point);
396 void OnMoving(UINT param, const RECT* new_bounds);
397 LRESULT OnNCActivate(UINT message, WPARAM w_param, LPARAM l_param);
398 LRESULT OnNCCalcSize(BOOL mode, LPARAM l_param);
399 LRESULT OnNCHitTest(const CPoint& point);
400 void OnNCPaint(HRGN rgn);
401 LRESULT OnNCUAHDrawCaption(UINT message, WPARAM w_param, LPARAM l_param);
402 LRESULT OnNCUAHDrawFrame(UINT message, WPARAM w_param, LPARAM l_param);
403 LRESULT OnNotify(int w_param, NMHDR* l_param);
404 void OnPaint(HDC dc);
405 LRESULT OnReflectedMessage(UINT message, WPARAM w_param, LPARAM l_param);
406 LRESULT OnSetCursor(UINT message, WPARAM w_param, LPARAM l_param);
407 void OnSetFocus(HWND last_focused_window);
408 LRESULT OnSetIcon(UINT size_type, HICON new_icon);
409 LRESULT OnSetText(const wchar_t* text);
410 void OnSettingChange(UINT flags, const wchar_t* section);
411 void OnSize(UINT param, const CSize& size);
412 void OnSysCommand(UINT notification_code, const CPoint& point);
413 void OnThemeChanged();
414 LRESULT OnTouchEvent(UINT message, WPARAM w_param, LPARAM l_param);
415 void OnWindowPosChanging(WINDOWPOS* window_pos);
416 void OnWindowPosChanged(WINDOWPOS* window_pos);
418 typedef std::vector<ui::TouchEvent> TouchEvents;
419 // Helper to handle the list of touch events passed in. We need this because
420 // touch events on windows don't fire if we enter a modal loop in the context
422 void HandleTouchEvents(const TouchEvents& touch_events);
424 HWNDMessageHandlerDelegate* delegate_;
426 scoped_ptr<FullscreenHandler> fullscreen_handler_;
428 // Set to true in Close() and false is CloseNow().
429 bool waiting_for_close_now_;
431 bool remove_standard_frame_;
433 bool use_system_default_icon_;
435 // Whether the focus should be restored next time we get enabled. Needed to
436 // restore focus correctly when Windows modal dialogs are displayed.
437 bool restore_focus_when_enabled_;
439 // Whether all ancestors have been enabled. This is only used if is_modal_ is
441 bool restored_enabled_;
443 // The last cursor that was active before the current one was selected. Saved
444 // so that we can restore it.
445 HCURSOR previous_cursor_;
447 // Event handling ------------------------------------------------------------
449 // The flags currently being used with TrackMouseEvent to track mouse
450 // messages. 0 if there is no active tracking. The value of this member is
451 // used when tracking is canceled.
452 DWORD active_mouse_tracking_flags_;
454 // Set to true when the user presses the right mouse button on the caption
455 // area. We need this so we can correctly show the context menu on mouse-up.
456 bool is_right_mouse_pressed_on_caption_;
458 // The set of touch devices currently down.
461 // ScopedRedrawLock ----------------------------------------------------------
463 // Represents the number of ScopedRedrawLocks active against this widget.
464 // If this is greater than zero, the widget should be locked against updates.
465 int lock_updates_count_;
467 // Window resizing -----------------------------------------------------------
469 // When true, this flag makes us discard incoming SetWindowPos() requests that
470 // only change our position/size. (We still allow changes to Z-order,
472 bool ignore_window_pos_changes_;
474 // The last-seen monitor containing us, and its rect and work area. These are
475 // used to catch updates to the rect and work area and react accordingly.
476 HMONITOR last_monitor_;
477 gfx::Rect last_monitor_rect_, last_work_area_;
479 // Layered windows -----------------------------------------------------------
481 // Should we keep an off-screen buffer? This is false by default, set to true
482 // when WS_EX_LAYERED is specified before the native window is created.
484 // NOTE: this is intended to be used with a layered window (a window with an
485 // extended window style of WS_EX_LAYERED). If you are using a layered window
486 // and NOT changing the layered alpha or anything else, then leave this value
487 // alone. OTOH if you are invoking SetLayeredWindowAttributes then you'll
488 // most likely want to set this to false, or after changing the alpha toggle
489 // the extended style bit to false than back to true. See MSDN for more
491 bool use_layered_buffer_;
493 // The default alpha to be applied to the layered window.
496 // A canvas that contains the window contents in the case of a layered
498 scoped_ptr<gfx::Canvas> layered_window_contents_;
500 // We must track the invalid rect ourselves, for two reasons:
501 // For layered windows, Windows will not do this properly with
502 // InvalidateRect()/GetUpdateRect(). (In fact, it'll return misleading
503 // information from GetUpdateRect()).
504 // We also need to keep track of the invalid rectangle for the RootView should
505 // we need to paint the non-client area. The data supplied to WM_NCPAINT seems
506 // to be insufficient.
507 gfx::Rect invalid_rect_;
509 // Set to true when waiting for RedrawLayeredWindowContents().
510 bool waiting_for_redraw_layered_window_contents_;
512 // True if we are allowed to update the layered window from the DIB backing
513 // store if necessary.
514 bool can_update_layered_window_;
516 // True the first time nccalc is called on a sizable widget
517 bool is_first_nccalc_;
519 // A factory used to lookup appbar autohide edges.
520 base::WeakPtrFactory<HWNDMessageHandler> autohide_factory_;
522 // Generates touch-ids for touch-events.
523 ui::SequentialIDGenerator id_generator_;
525 DISALLOW_COPY_AND_ASSIGN(HWNDMessageHandler);
530 #endif // UI_VIEWS_WIN_HWND_MESSAGE_HANDLER_H_