diff options
Diffstat (limited to 'views/widget')
-rw-r--r-- | views/widget/native_widget.h | 11 | ||||
-rw-r--r-- | views/widget/native_widget_delegate.h | 29 | ||||
-rw-r--r-- | views/widget/native_widget_gtk.cc | 33 | ||||
-rw-r--r-- | views/widget/native_widget_gtk.h | 3 | ||||
-rw-r--r-- | views/widget/native_widget_test_utils_gtk.cc | 2 | ||||
-rw-r--r-- | views/widget/native_widget_test_utils_win.cc | 2 | ||||
-rw-r--r-- | views/widget/native_widget_view.cc | 2 | ||||
-rw-r--r-- | views/widget/native_widget_views.cc | 14 | ||||
-rw-r--r-- | views/widget/native_widget_views.h | 3 | ||||
-rw-r--r-- | views/widget/native_widget_win.cc | 361 | ||||
-rw-r--r-- | views/widget/native_widget_win.h | 35 | ||||
-rw-r--r-- | views/widget/widget.cc | 149 | ||||
-rw-r--r-- | views/widget/widget.h | 51 | ||||
-rw-r--r-- | views/widget/widget_delegate.cc | 7 | ||||
-rw-r--r-- | views/widget/widget_delegate.h | 5 |
15 files changed, 661 insertions, 46 deletions
diff --git a/views/widget/native_widget.h b/views/widget/native_widget.h index 6cb4147..3534f26 100644 --- a/views/widget/native_widget.h +++ b/views/widget/native_widget.h @@ -152,9 +152,11 @@ class NativeWidget { virtual void SetAccessibleRole(ui::AccessibilityTypes::Role role) = 0; virtual void SetAccessibleState(ui::AccessibilityTypes::State state) = 0; - protected: - friend class Widget; - friend class NativeWidgetViews; + enum ShowState { + SHOW_RESTORED, + SHOW_MAXIMIZED, + SHOW_INACTIVE + }; // Returns a handle for the underlying native widget that can be used for // accelerated drawing. @@ -164,6 +166,7 @@ class NativeWidget { // See method documentation in Widget. virtual gfx::Rect GetWindowScreenBounds() const = 0; virtual gfx::Rect GetClientAreaScreenBounds() const = 0; + virtual gfx::Rect GetRestoredBounds() const = 0; virtual void SetBounds(const gfx::Rect& bounds) = 0; virtual void SetSize(const gfx::Size& size) = 0; virtual void SetBoundsConstrained(const gfx::Rect& bounds, @@ -172,8 +175,10 @@ class NativeWidget { virtual void SetShape(gfx::NativeRegion shape) = 0; virtual void Close() = 0; virtual void CloseNow() = 0; + virtual void EnableClose(bool enable) = 0; virtual void Show() = 0; virtual void Hide() = 0; + virtual void ShowNativeWidget(ShowState state) = 0; virtual bool IsVisible() const = 0; virtual void Activate() = 0; virtual void Deactivate() = 0; diff --git a/views/widget/native_widget_delegate.h b/views/widget/native_widget_delegate.h index d39bd58..2417b9e 100644 --- a/views/widget/native_widget_delegate.h +++ b/views/widget/native_widget_delegate.h @@ -24,6 +24,15 @@ class NativeWidgetDelegate { public: virtual ~NativeWidgetDelegate() {} + // Returns true if the window can be activated. + virtual bool CanActivate() const = 0; + + virtual bool IsInactiveRenderingDisabled() const = 0; + virtual void EnableInactiveRendering() = 0; + + // Called when the activation state of a window has changed. + virtual void OnNativeWidgetActivationChanged(bool active) = 0; + // Called when native focus moves from one native view to another. virtual void OnNativeFocus(gfx::NativeView focused_view) = 0; virtual void OnNativeBlur(gfx::NativeView focused_view) = 0; @@ -31,11 +40,22 @@ class NativeWidgetDelegate { // Called when the native widget is created. virtual void OnNativeWidgetCreated() = 0; + // Called just before the native widget is destroyed. This is the delegate's + // last chance to do anything with the native widget handle. + virtual void OnNativeWidgetDestroying() = 0; + // Called just after the native widget is destroyed. virtual void OnNativeWidgetDestroyed() = 0; + // Returns the smallest size the window can be resized to by the user. + virtual gfx::Size GetMinimumSize() = 0; + // Called when the NativeWidget changed size to |new_size|. - virtual void OnSizeChanged(const gfx::Size& new_size) = 0; + virtual void OnNativeWidgetSizeChanged(const gfx::Size& new_size) = 0; + + // Called when the user begins/ends to change the bounds of the window. + virtual void OnNativeWidgetBeginUserBoundsChange() = 0; + virtual void OnNativeWidgetEndUserBoundsChange() = 0; // Returns true if the delegate has a FocusManager. virtual bool HasFocusManager() const = 0; @@ -49,11 +69,18 @@ class NativeWidgetDelegate { // tree if necessary when accelerated painting is enabled. virtual void OnNativeWidgetPaint(gfx::Canvas* canvas) = 0; + // Returns the non-client component (see views/window/hit_test.h) containing + // |point|, in client coordinates. + virtual int GetNonClientComponent(const gfx::Point& point) = 0; + // Mouse and key event handlers. virtual bool OnKeyEvent(const KeyEvent& event) = 0; virtual bool OnMouseEvent(const MouseEvent& event) = 0; virtual void OnMouseCaptureLost() = 0; + // Runs the specified native command. Returns true if the command is handled. + virtual bool ExecuteCommand(int command_id) = 0; + // virtual Widget* AsWidget() = 0; virtual const Widget* AsWidget() const = 0; diff --git a/views/widget/native_widget_gtk.cc b/views/widget/native_widget_gtk.cc index 91af0e3..801a8ec 100644 --- a/views/widget/native_widget_gtk.cc +++ b/views/widget/native_widget_gtk.cc @@ -445,7 +445,7 @@ void NativeWidgetGtk::DoDrag(const OSExchangeData& data, int operation) { } void NativeWidgetGtk::IsActiveChanged() { - GetWidget()->widget_delegate()->OnWidgetActivated(IsActive()); + delegate_->OnNativeWidgetActivationChanged(IsActive()); } void NativeWidgetGtk::SetInitialFocus() { @@ -927,6 +927,11 @@ gfx::Rect NativeWidgetGtk::GetClientAreaScreenBounds() const { return gfx::Rect(x, y, w, h); } +gfx::Rect NativeWidgetGtk::GetRestoredBounds() const { + // We currently don't support tiling, so this doesn't matter. + return GetWindowScreenBounds(); +} + void NativeWidgetGtk::SetBounds(const gfx::Rect& bounds) { if (child_) { GtkWidget* parent = gtk_widget_get_parent(widget_); @@ -1020,6 +1025,10 @@ void NativeWidgetGtk::CloseNow() { } } +void NativeWidgetGtk::EnableClose(bool enable) { + gtk_window_set_deletable(GetNativeWindow(), enable); +} + void NativeWidgetGtk::Show() { if (widget_) { gtk_widget_show(widget_); @@ -1036,6 +1045,13 @@ void NativeWidgetGtk::Hide() { } } +void NativeWidgetGtk::ShowNativeWidget(ShowState state) { + // No concept of maximization (yet) on ChromeOS. + if (state == NativeWidget::SHOW_INACTIVE) + gtk_window_set_focus_on_map(GetNativeWindow(), false); + gtk_widget_show(GetNativeView()); +} + bool NativeWidgetGtk::IsVisible() const { return GTK_WIDGET_VISIBLE(GetNativeView()); } @@ -1077,10 +1093,14 @@ bool NativeWidgetGtk::IsMinimized() const { } void NativeWidgetGtk::Restore() { - if (IsMaximized()) - gtk_window_unmaximize(GetNativeWindow()); - else if (IsMinimized()) - gtk_window_deiconify(GetNativeWindow()); + if (IsFullscreen()) { + SetFullscreen(false); + } else { + if (IsMaximized()) + gtk_window_unmaximize(GetNativeWindow()); + else if (IsMinimized()) + gtk_window_deiconify(GetNativeWindow()); + } } void NativeWidgetGtk::SetFullscreen(bool fullscreen) { @@ -1174,7 +1194,7 @@ void NativeWidgetGtk::OnSizeAllocate(GtkWidget* widget, if (new_size == size_) return; size_ = new_size; - delegate_->OnSizeChanged(size_); + delegate_->OnNativeWidgetSizeChanged(size_); } gboolean NativeWidgetGtk::OnPaint(GtkWidget* widget, GdkEventExpose* event) { @@ -1440,6 +1460,7 @@ void NativeWidgetGtk::OnGrabNotify(GtkWidget* widget, gboolean was_grabbed) { } void NativeWidgetGtk::OnDestroy(GtkWidget* object) { + delegate_->OnNativeWidgetDestroying(); if (!child_) ActiveWindowWatcherX::RemoveObserver(this); // Note that this handler is hooked to GtkObject::destroy. diff --git a/views/widget/native_widget_gtk.h b/views/widget/native_widget_gtk.h index f080b10..f641c64 100644 --- a/views/widget/native_widget_gtk.h +++ b/views/widget/native_widget_gtk.h @@ -190,6 +190,7 @@ class NativeWidgetGtk : public NativeWidget, virtual void SetAccessibleState(ui::AccessibilityTypes::State state) OVERRIDE; virtual gfx::Rect GetWindowScreenBounds() const OVERRIDE; virtual gfx::Rect GetClientAreaScreenBounds() const OVERRIDE; + virtual gfx::Rect GetRestoredBounds() const OVERRIDE; virtual void SetBounds(const gfx::Rect& bounds) OVERRIDE; virtual void SetSize(const gfx::Size& size) OVERRIDE; virtual void SetBoundsConstrained(const gfx::Rect& bounds, @@ -198,8 +199,10 @@ class NativeWidgetGtk : public NativeWidget, virtual void SetShape(gfx::NativeRegion shape) OVERRIDE; virtual void Close() OVERRIDE; virtual void CloseNow() OVERRIDE; + virtual void EnableClose(bool enable) OVERRIDE; virtual void Show() OVERRIDE; virtual void Hide() OVERRIDE; + virtual void ShowNativeWidget(ShowState state) OVERRIDE; virtual bool IsVisible() const OVERRIDE; virtual void Activate() OVERRIDE; virtual void Deactivate() OVERRIDE; diff --git a/views/widget/native_widget_test_utils_gtk.cc b/views/widget/native_widget_test_utils_gtk.cc index 2f93ea6..cd84b56 100644 --- a/views/widget/native_widget_test_utils_gtk.cc +++ b/views/widget/native_widget_test_utils_gtk.cc @@ -17,7 +17,7 @@ NativeWidget* CreateNativeWidget() { NativeWidget* CreateNativeWidgetWithContents(View* contents_view) { Widget* widget = new Widget; - Widget::InitParams params(Widget::InitParams::TYPE_WINDOW); + Widget::InitParams params(Widget::InitParams::TYPE_POPUP); params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; params.bounds = gfx::Rect(10, 10, 200, 200); widget->Init(params); diff --git a/views/widget/native_widget_test_utils_win.cc b/views/widget/native_widget_test_utils_win.cc index 8963f48..49cd063 100644 --- a/views/widget/native_widget_test_utils_win.cc +++ b/views/widget/native_widget_test_utils_win.cc @@ -17,7 +17,7 @@ NativeWidget* CreateNativeWidget() { NativeWidget* CreateNativeWidgetWithContents(View* contents_view) { Widget* widget = new Widget; - Widget::InitParams params(Widget::InitParams::TYPE_WINDOW); + Widget::InitParams params(Widget::InitParams::TYPE_POPUP); params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; params.bounds = gfx::Rect(10, 10, 200, 200); widget->Init(params); diff --git a/views/widget/native_widget_view.cc b/views/widget/native_widget_view.cc index daaf2cc..75de2c1 100644 --- a/views/widget/native_widget_view.cc +++ b/views/widget/native_widget_view.cc @@ -36,7 +36,7 @@ void NativeWidgetView::ViewHierarchyChanged(bool is_add, View* parent, } void NativeWidgetView::OnBoundsChanged(const gfx::Rect& previous_bounds) { - delegate()->OnSizeChanged(size()); + delegate()->OnNativeWidgetSizeChanged(size()); } void NativeWidgetView::OnPaint(gfx::Canvas* canvas) { diff --git a/views/widget/native_widget_views.cc b/views/widget/native_widget_views.cc index d0eebe4..d2fa54f 100644 --- a/views/widget/native_widget_views.cc +++ b/views/widget/native_widget_views.cc @@ -80,11 +80,11 @@ gfx::NativeWindow NativeWidgetViews::GetNativeWindow() const { } Window* NativeWidgetViews::GetContainingWindow() { - return view_->GetWindow(); + return view_->GetWidget()->AsWindow(); } const Window* NativeWidgetViews::GetContainingWindow() const { - return view_->GetWindow(); + return view_->GetWidget()->AsWindow(); } void NativeWidgetViews::ViewRemoved(View* view) { @@ -183,6 +183,10 @@ gfx::Rect NativeWidgetViews::GetClientAreaScreenBounds() const { return GetWindowScreenBounds(); } +gfx::Rect NativeWidgetViews::GetRestoredBounds() const { + return GetWindowScreenBounds(); +} + void NativeWidgetViews::SetBounds(const gfx::Rect& bounds) { // |bounds| are supplied in the coordinates of the parent. view_->SetBoundsRect(bounds); @@ -219,6 +223,9 @@ void NativeWidgetViews::CloseNow() { delete view_; } +void NativeWidgetViews::EnableClose(bool enable) { +} + void NativeWidgetViews::Show() { view_->SetVisible(true); } @@ -227,6 +234,9 @@ void NativeWidgetViews::Hide() { view_->SetVisible(false); } +void NativeWidgetViews::ShowNativeWidget(ShowState state) { +} + bool NativeWidgetViews::IsVisible() const { return view_->IsVisible(); } diff --git a/views/widget/native_widget_views.h b/views/widget/native_widget_views.h index f6d445d..f8ab599 100644 --- a/views/widget/native_widget_views.h +++ b/views/widget/native_widget_views.h @@ -71,6 +71,7 @@ class NativeWidgetViews : public NativeWidget { virtual gfx::AcceleratedWidget GetAcceleratedWidget() OVERRIDE; virtual gfx::Rect GetWindowScreenBounds() const OVERRIDE; virtual gfx::Rect GetClientAreaScreenBounds() const OVERRIDE; + virtual gfx::Rect GetRestoredBounds() const OVERRIDE; virtual void SetBounds(const gfx::Rect& bounds) OVERRIDE; virtual void SetSize(const gfx::Size& size) OVERRIDE; virtual void SetBoundsConstrained(const gfx::Rect& bounds, @@ -79,8 +80,10 @@ class NativeWidgetViews : public NativeWidget { virtual void SetShape(gfx::NativeRegion shape) OVERRIDE; virtual void Close() OVERRIDE; virtual void CloseNow() OVERRIDE; + virtual void EnableClose(bool enable) OVERRIDE; virtual void Show() OVERRIDE; virtual void Hide() OVERRIDE; + virtual void ShowNativeWidget(ShowState state) OVERRIDE; virtual bool IsVisible() const OVERRIDE; virtual void Activate() OVERRIDE; virtual void Deactivate() OVERRIDE; diff --git a/views/widget/native_widget_win.cc b/views/widget/native_widget_win.cc index cd6fc64..fe4d885 100644 --- a/views/widget/native_widget_win.cc +++ b/views/widget/native_widget_win.cc @@ -183,6 +183,22 @@ void SendFrameChanged(HWND window) { SWP_NOSENDCHANGING | SWP_NOSIZE | SWP_NOZORDER); } +// Enables or disables the menu item for the specified command and menu. +void EnableMenuItem(HMENU menu, UINT command, bool enabled) { + UINT flags = MF_BYCOMMAND | (enabled ? MF_ENABLED : MF_DISABLED | MF_GRAYED); + EnableMenuItem(menu, command, flags); +} + +BOOL CALLBACK EnumChildWindowsForRedraw(HWND hwnd, LPARAM lparam) { + DWORD process_id; + GetWindowThreadProcessId(hwnd, &process_id); + int flags = RDW_INVALIDATE | RDW_NOCHILDREN | RDW_FRAME; + if (process_id == GetCurrentProcessId()) + flags |= RDW_UPDATENOW; + RedrawWindow(hwnd, NULL, NULL, flags); + return TRUE; +} + // Links the HWND to its NativeWidget. const char* const kNativeWidgetKey = "__VIEWS_NATIVE_WIDGET__"; @@ -202,6 +218,46 @@ const int kDragFrameWindowAlpha = 200; // static bool NativeWidgetWin::screen_reader_active_ = false; +// A scoping class that prevents a window from being able to redraw in response +// to invalidations that may occur within it for the lifetime of the object. +// +// Why would we want such a thing? Well, it turns out Windows has some +// "unorthodox" behavior when it comes to painting its non-client areas. +// Occasionally, Windows will paint portions of the default non-client area +// right over the top of the custom frame. This is not simply fixed by handling +// WM_NCPAINT/WM_PAINT, with some investigation it turns out that this +// rendering is being done *inside* the default implementation of some message +// handlers and functions: +// . WM_SETTEXT +// . WM_SETICON +// . WM_NCLBUTTONDOWN +// . EnableMenuItem, called from our WM_INITMENU handler +// The solution is to handle these messages and call DefWindowProc ourselves, +// but prevent the window from being able to update itself for the duration of +// the call. We do this with this class, which automatically calls its +// associated Window's lock and unlock functions as it is created and destroyed. +// See documentation in those methods for the technique used. +// +// IMPORTANT: Do not use this scoping object for large scopes or periods of +// time! IT WILL PREVENT THE WINDOW FROM BEING REDRAWN! (duh). +// +// I would love to hear Raymond Chen's explanation for all this. And maybe a +// list of other messages that this applies to ;-) +class NativeWidgetWin::ScopedRedrawLock { + public: + explicit ScopedRedrawLock(NativeWidgetWin* widget) : widget_(widget) { + widget_->LockUpdates(); + } + + ~ScopedRedrawLock() { + widget_->UnlockUpdates(); + } + + private: + // The widget having its style changed. + NativeWidgetWin* widget_; +}; + //////////////////////////////////////////////////////////////////////////////// // NativeWidgetWin, public: @@ -222,7 +278,9 @@ NativeWidgetWin::NativeWidgetWin(internal::NativeWidgetDelegate* delegate) previous_cursor_(NULL), is_input_method_win_(false), fullscreen_(false), - force_hidden_count_(0) { + force_hidden_count_(0), + lock_updates_(false), + saved_window_style_(0) { } NativeWidgetWin::~NativeWidgetWin() { @@ -242,6 +300,29 @@ bool NativeWidgetWin::IsAeroGlassEnabled() { return SUCCEEDED(DwmIsCompositionEnabled(&enabled)) && enabled; } +void NativeWidgetWin::Show(int show_state) { + ShowWindow(show_state); + // When launched from certain programs like bash and Windows Live Messenger, + // show_state is set to SW_HIDE, so we need to correct that condition. We + // don't just change show_state to SW_SHOWNORMAL because MSDN says we must + // always first call ShowWindow with the specified value from STARTUPINFO, + // otherwise all future ShowWindow calls will be ignored (!!#@@#!). Instead, + // we call ShowWindow again in this case. + if (show_state == SW_HIDE) { + show_state = SW_SHOWNORMAL; + ShowWindow(show_state); + } + + // We need to explicitly activate the window if we've been shown with a state + // that should activate, because if we're opened from a desktop shortcut while + // an existing window is already running it doesn't seem to be enough to use + // one of these flags to activate the window. + if (show_state == SW_SHOWNORMAL || show_state == SW_SHOWMAXIMIZED) + Activate(); + + SetInitialFocus(); +} + View* NativeWidgetWin::GetAccessibilityViewEventAt(int id) { // Convert from MSAA child id. id = -(id + 1); @@ -550,6 +631,17 @@ gfx::Rect NativeWidgetWin::GetClientAreaScreenBounds() const { return gfx::Rect(point.x, point.y, r.right - r.left, r.bottom - r.top); } +gfx::Rect NativeWidgetWin::GetRestoredBounds() const { + // If we're in fullscreen mode, we've changed the normal bounds to the monitor + // rect, so return the saved bounds instead. + if (IsFullscreen()) + return gfx::Rect(saved_window_info_.window_rect); + + gfx::Rect bounds; + GetWindowBoundsAndMaximizedState(&bounds, NULL); + return bounds; +} + void NativeWidgetWin::SetBounds(const gfx::Rect& bounds) { LONG style = GetWindowLong(GWL_STYLE); if (style & WS_MAXIMIZE) @@ -627,6 +719,13 @@ void NativeWidgetWin::CloseNow() { DestroyWindow(hwnd()); } +void NativeWidgetWin::EnableClose(bool enable) { + // Disable the native frame's close button regardless of whether or not the + // native frame is in use, since this also affects the system menu. + EnableMenuItem(GetSystemMenu(GetNativeView(), false), SC_CLOSE, enable); + SendFrameChanged(GetNativeView()); +} + void NativeWidgetWin::Show() { if (!IsWindow()) return; @@ -647,6 +746,22 @@ void NativeWidgetWin::Hide() { } } +void NativeWidgetWin::ShowNativeWidget(ShowState state) { + DWORD native_show_state; + switch (state) { + case SHOW_INACTIVE: + native_show_state = SW_SHOWNOACTIVATE; + break; + case SHOW_MAXIMIZED: + native_show_state = SW_SHOWMAXIMIZED; + break; + default: + native_show_state = GetShowState(); + break; + } + Show(native_show_state); +} + bool NativeWidgetWin::IsVisible() const { return !!::IsWindowVisible(hwnd()); } @@ -881,7 +996,15 @@ void NativeWidgetWin::OnActivate(UINT action, BOOL minimized, HWND window) { } void NativeWidgetWin::OnActivateApp(BOOL active, DWORD thread_id) { - SetMsgHandled(FALSE); + if (GetWidget()->non_client_view() && !active && + thread_id != GetCurrentThreadId()) { + // Another application was activated, we should reset any state that + // disables inactive rendering now. + delegate_->EnableInactiveRendering(); + // Update the native frame too, since it could be rendering the non-client + // area. + CallDefaultNCActivateHandler(FALSE); + } } LRESULT NativeWidgetWin::OnAppCommand(HWND window, @@ -974,6 +1097,7 @@ LRESULT NativeWidgetWin::OnCreate(CREATESTRUCT* create_struct) { } void NativeWidgetWin::OnDestroy() { + delegate_->OnNativeWidgetDestroying(); if (drop_target_.get()) { RevokeDragDrop(hwnd()); drop_target_ = NULL; @@ -989,7 +1113,18 @@ void NativeWidgetWin::OnDisplayChange(UINT bits_per_pixel, CSize screen_size) { LRESULT NativeWidgetWin::OnDwmCompositionChanged(UINT msg, WPARAM w_param, LPARAM l_param) { - SetMsgHandled(FALSE); + if (!GetWidget()->non_client_view()) { + SetMsgHandled(FALSE); + return 0; + } + + // For some reason, we need to hide the window while we're changing the frame + // type only when we're changing it in response to WM_DWMCOMPOSITIONCHANGED. + // If we don't, the client area will be filled with black. I'm suspecting + // something skia-ey. + // Frame type toggling caused by the user (e.g. switching theme) doesn't seem + // to have this requirement. + FrameTypeChanged(); return 0; } @@ -998,6 +1133,7 @@ void NativeWidgetWin::OnEndSession(BOOL ending, UINT logoff) { } void NativeWidgetWin::OnEnterSizeMove() { + delegate_->OnNativeWidgetBeginUserBoundsChange(); SetMsgHandled(FALSE); } @@ -1011,6 +1147,7 @@ void NativeWidgetWin::OnExitMenuLoop(BOOL is_track_popup_menu) { } void NativeWidgetWin::OnExitSizeMove() { + delegate_->OnNativeWidgetEndUserBoundsChange(); SetMsgHandled(FALSE); } @@ -1044,6 +1181,9 @@ LRESULT NativeWidgetWin::OnGetObject(UINT uMsg, } void NativeWidgetWin::OnGetMinMaxInfo(MINMAXINFO* minmax_info) { + gfx::Size min_window_size(delegate_->GetMinimumSize()); + minmax_info->ptMinTrackSize.x = min_window_size.width(); + minmax_info->ptMinTrackSize.y = min_window_size.height(); SetMsgHandled(FALSE); } @@ -1095,7 +1235,29 @@ LRESULT NativeWidgetWin::OnImeMessages(UINT message, } void NativeWidgetWin::OnInitMenu(HMENU menu) { - SetMsgHandled(FALSE); + // We only need to manually enable the system menu if we're not using a native + // frame. + if (GetWidget()->ShouldUseNativeFrame()) { + SetMsgHandled(FALSE); + return; + } + + bool is_fullscreen = IsFullscreen(); + bool is_minimized = IsMinimized(); + bool is_maximized = IsMaximized(); + bool is_restored = !is_fullscreen && !is_minimized && !is_maximized; + + ScopedRedrawLock lock(this); + EnableMenuItem(menu, SC_RESTORE, is_minimized || is_maximized); + EnableMenuItem(menu, SC_MOVE, is_restored); + EnableMenuItem(menu, SC_SIZE, + GetWidget()->widget_delegate()->CanResize() && is_restored); + EnableMenuItem(menu, SC_MAXIMIZE, + GetWidget()->widget_delegate()->CanMaximize() && + !is_fullscreen && !is_maximized); + EnableMenuItem(menu, SC_MINIMIZE, + GetWidget()->widget_delegate()->CanMaximize() && + !is_minimized); } void NativeWidgetWin::OnInitMenuPopup(HMENU menu, @@ -1134,6 +1296,10 @@ void NativeWidgetWin::OnKillFocus(HWND focused_window) { LRESULT NativeWidgetWin::OnMouseActivate(UINT message, WPARAM w_param, LPARAM l_param) { + // TODO(beng): resolve this with the GetWindowLong() check on the subsequent + // line. + if (GetWidget()->non_client_view()) + return delegate_->CanActivate() ? MA_ACTIVATE : MA_NOACTIVATEANDEAT; if (GetWindowLong(GWL_EXSTYLE) & WS_EX_NOACTIVATE) return MA_NOACTIVATE; SetMsgHandled(FALSE); @@ -1183,8 +1349,40 @@ void NativeWidgetWin::OnMoving(UINT param, const LPRECT new_bounds) { } LRESULT NativeWidgetWin::OnNCActivate(BOOL active) { - SetMsgHandled(FALSE); - return 0; + if (!GetWidget()->non_client_view()) { + SetMsgHandled(FALSE); + return 0; + } + + if (!delegate_->CanActivate()) + return TRUE; + + delegate_->OnNativeWidgetActivationChanged(!!active); + + // The frame may need to redraw as a result of the activation change. + // We can get WM_NCACTIVATE before we're actually visible. If we're not + // visible, no need to paint. + if (IsVisible()) + GetWidget()->non_client_view()->SchedulePaint(); + + if (!GetWidget()->ShouldUseNativeFrame()) { + // TODO(beng, et al): Hack to redraw this window and child windows + // synchronously upon activation. Not all child windows are redrawing + // themselves leading to issues like http://crbug.com/74604 + // We redraw out-of-process HWNDs asynchronously to avoid hanging the + // whole app if a child HWND belonging to a hung plugin is encountered. + RedrawWindow(GetNativeView(), NULL, NULL, + RDW_NOCHILDREN | RDW_INVALIDATE | RDW_UPDATENOW); + EnumChildWindows(GetNativeView(), EnumChildWindowsForRedraw, NULL); + } + + // If we're active again, we should be allowed to render as inactive, so + // tell the non-client view. + bool inactive_rendering_disabled = delegate_->IsInactiveRenderingDisabled(); + if (IsActive()) + delegate_->EnableInactiveRendering(); + + return CallDefaultNCActivateHandler(inactive_rendering_disabled || active); } LRESULT NativeWidgetWin::OnNCCalcSize(BOOL w_param, LPARAM l_param) { @@ -1192,7 +1390,32 @@ LRESULT NativeWidgetWin::OnNCCalcSize(BOOL w_param, LPARAM l_param) { return 0; } -LRESULT NativeWidgetWin::OnNCHitTest(const CPoint& pt) { +LRESULT NativeWidgetWin::OnNCHitTest(const CPoint& point) { + if (!GetWidget()->non_client_view()) { + SetMsgHandled(FALSE); + return 0; + } + + // If the DWM is rendering the window controls, we need to give the DWM's + // default window procedure first chance to handle hit testing. + if (GetWidget()->ShouldUseNativeFrame()) { + LRESULT result; + if (DwmDefWindowProc(GetNativeView(), WM_NCHITTEST, 0, + MAKELPARAM(point.x, point.y), &result)) { + return result; + } + } + + // First, give the NonClientView a chance to test the point to see if it + // provides any of the non-client area. + POINT temp = point; + MapWindowPoints(HWND_DESKTOP, GetNativeView(), &temp, 1); + int component = delegate_->GetNonClientComponent(gfx::Point(temp)); + if (component != HTNOWHERE) + return component; + + // Otherwise, we let Windows do all the native frame non-client handling for + // us. SetMsgHandled(FALSE); return 0; } @@ -1204,14 +1427,18 @@ void NativeWidgetWin::OnNCPaint(HRGN rgn) { LRESULT NativeWidgetWin::OnNCUAHDrawCaption(UINT msg, WPARAM w_param, LPARAM l_param) { - SetMsgHandled(FALSE); + // See comment in widget_win.h at the definition of WM_NCUAHDRAWCAPTION for + // an explanation about why we need to handle this message. + SetMsgHandled(!GetWidget()->ShouldUseNativeFrame()); return 0; } LRESULT NativeWidgetWin::OnNCUAHDrawFrame(UINT msg, WPARAM w_param, LPARAM l_param) { - SetMsgHandled(FALSE); + // See comment in widget_win.h at the definition of WM_NCUAHDRAWCAPTION for + // an explanation about why we need to handle this message. + SetMsgHandled(!GetWidget()->ShouldUseNativeFrame()); return 0; } @@ -1263,8 +1490,9 @@ LRESULT NativeWidgetWin::OnReflectedMessage(UINT msg, LRESULT NativeWidgetWin::OnSetCursor(UINT message, WPARAM w_param, LPARAM l_param) { - SetMsgHandled(FALSE); - return 0; + // This shouldn't hurt even if we're using the native frame. + ScopedRedrawLock lock(this); + return DefWindowProc(GetNativeView(), message, w_param, l_param); } void NativeWidgetWin::OnSetFocus(HWND focused_window) { @@ -1275,13 +1503,17 @@ void NativeWidgetWin::OnSetFocus(HWND focused_window) { } LRESULT NativeWidgetWin::OnSetIcon(UINT size_type, HICON new_icon) { - SetMsgHandled(FALSE); - return 0; + // This shouldn't hurt even if we're using the native frame. + ScopedRedrawLock lock(this); + return DefWindowProc(GetNativeView(), WM_SETICON, size_type, + reinterpret_cast<LPARAM>(new_icon)); } LRESULT NativeWidgetWin::OnSetText(const wchar_t* text) { - SetMsgHandled(FALSE); - return 0; + // This shouldn't hurt even if we're using the native frame. + ScopedRedrawLock lock(this); + return DefWindowProc(GetNativeView(), WM_SETTEXT, NULL, + reinterpret_cast<LPARAM>(text)); } void NativeWidgetWin::OnSettingChange(UINT flags, const wchar_t* section) { @@ -1301,12 +1533,59 @@ void NativeWidgetWin::OnSettingChange(UINT flags, const wchar_t* section) { } void NativeWidgetWin::OnSize(UINT param, const CSize& size) { + RedrawWindow(GetNativeView(), NULL, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN); // ResetWindowRegion is going to trigger WM_NCPAINT. By doing it after we've // invoked OnSize we ensure the RootView has been laid out. ResetWindowRegion(false); } void NativeWidgetWin::OnSysCommand(UINT notification_code, CPoint click) { + if (!GetWidget()->non_client_view()) + return; + + // Windows uses the 4 lower order bits of |notification_code| for type- + // specific information so we must exclude this when comparing. + static const int sc_mask = 0xFFF0; + // Ignore size/move/maximize in fullscreen mode. + if (IsFullscreen() && + (((notification_code & sc_mask) == SC_SIZE) || + ((notification_code & sc_mask) == SC_MOVE) || + ((notification_code & sc_mask) == SC_MAXIMIZE))) + return; + if (!GetWidget()->ShouldUseNativeFrame()) { + if ((notification_code & sc_mask) == SC_MINIMIZE || + (notification_code & sc_mask) == SC_MAXIMIZE || + (notification_code & sc_mask) == SC_RESTORE) { + GetWidget()->non_client_view()->ResetWindowControls(); + } else if ((notification_code & sc_mask) == SC_MOVE || + (notification_code & sc_mask) == SC_SIZE) { + if (lock_updates_) { + // We were locked, before entering a resize or move modal loop. Now that + // we've begun to move the window, we need to unlock updates so that the + // sizing/moving feedback can be continuous. + UnlockUpdates(); + } + } + } + + // Handle SC_KEYMENU, which means that the user has pressed the ALT + // key and released it, so we should focus the menu bar. + if ((notification_code & sc_mask) == SC_KEYMENU && click.x == 0) { + // Retrieve the status of shift and control keys to prevent consuming + // shift+alt keys, which are used by Windows to change input languages. + Accelerator accelerator(ui::KeyboardCodeForWindowsKeyCode(VK_MENU), + !!(GetKeyState(VK_SHIFT) & 0x8000), + !!(GetKeyState(VK_CONTROL) & 0x8000), + false); + GetWidget()->GetFocusManager()->ProcessAccelerator(accelerator); + return; + } + + // If the delegate can't handle it, the system implementation will be called. + if (!delegate_->ExecuteCommand(notification_code)) { + DefWindowProc(GetNativeView(), WM_SYSCOMMAND, notification_code, + MAKELPARAM(click.x, click.y)); + } } void NativeWidgetWin::OnThemeChanged() { @@ -1345,6 +1624,37 @@ void NativeWidgetWin::OnFinalMessage(HWND window) { //////////////////////////////////////////////////////////////////////////////// // NativeWidgetWin, protected: +int NativeWidgetWin::GetShowState() const { + return SW_SHOWNORMAL; +} + +gfx::Insets NativeWidgetWin::GetClientAreaInsets() const { + // Returning an empty Insets object causes the default handling in + // NativeWidgetWin::OnNCCalcSize() to be invoked. + if (GetWidget()->ShouldUseNativeFrame()) + return gfx::Insets(); + + if (IsMaximized()) { + // Windows automatically adds a standard width border to all sides when a + // window is maximized. + int border_thickness = GetSystemMetrics(SM_CXSIZEFRAME); + return gfx::Insets(border_thickness, border_thickness, border_thickness, + border_thickness); + } + // This is weird, but highly essential. If we don't offset the bottom edge + // of the client rect, the window client area and window area will match, + // and when returning to glass rendering mode from non-glass, the client + // area will not paint black as transparent. This is because (and I don't + // know why) the client area goes from matching the window rect to being + // something else. If the client area is not the window rect in both + // modes, the blackness doesn't occur. Because of this, we need to tell + // the RootView to lay out to fit the window rect, rather than the client + // rect when using the opaque frame. + // Note: this is only required for non-fullscreen windows. Note that + // fullscreen windows are in restored state, not maximized. + return gfx::Insets(0, 0, IsFullscreen() ? 0 : 1, 0); +} + void NativeWidgetWin::TrackMouseEvents(DWORD mouse_tracking_flags) { // Begin tracking mouse events for this HWND so that we get WM_MOUSELEAVE // when the user moves the mouse outside this HWND's bounds. @@ -1525,6 +1835,17 @@ void NativeWidgetWin::RedrawLayeredWindowContents() { skia::EndPlatformPaint(layered_window_contents_.get()); } +void NativeWidgetWin::LockUpdates() { + lock_updates_ = true; + saved_window_style_ = GetWindowLong(GWL_STYLE); + SetWindowLong(GWL_STYLE, saved_window_style_ & ~WS_VISIBLE); +} + +void NativeWidgetWin::UnlockUpdates() { + SetWindowLong(GWL_STYLE, saved_window_style_); + lock_updates_ = false; +} + void NativeWidgetWin::ClientAreaSizeChanged() { RECT r; Window* window = GetWidget()->GetContainingWindow(); @@ -1534,7 +1855,7 @@ void NativeWidgetWin::ClientAreaSizeChanged() { GetWindowRect(&r); gfx::Size s(std::max(0, static_cast<int>(r.right - r.left)), std::max(0, static_cast<int>(r.bottom - r.top))); - delegate_->OnSizeChanged(s); + delegate_->OnNativeWidgetSizeChanged(s); if (use_layered_buffer_) { layered_window_contents_.reset( new gfx::CanvasSkia(s.width(), s.height(), false)); @@ -1584,6 +1905,14 @@ void NativeWidgetWin::ResetWindowRegion(bool force) { DeleteObject(current_rgn); } +LRESULT NativeWidgetWin::CallDefaultNCActivateHandler(BOOL active) { + // The DefWindowProc handling for WM_NCACTIVATE renders the classic-look + // window title bar directly, so we need to use a redraw lock here to prevent + // it from doing so. + ScopedRedrawLock lock(this); + return DefWindowProc(GetNativeView(), WM_NCACTIVATE, active, 0); +} + gfx::AcceleratedWidget NativeWidgetWin::GetAcceleratedWidget() { #if defined(VIEWS_COMPOSITOR) return hwnd(); diff --git a/views/widget/native_widget_win.h b/views/widget/native_widget_win.h index 7dd4995..3d98b24 100644 --- a/views/widget/native_widget_win.h +++ b/views/widget/native_widget_win.h @@ -88,6 +88,9 @@ class NativeWidgetWin : public ui::WindowImpl, // enabled. static bool IsAeroGlassEnabled(); + // Show the window with the specified show command. + void Show(int show_state); + // Disable Layered Window updates by setting to false. void set_can_update_layered_window(bool can_update_layered_window) { can_update_layered_window_ = can_update_layered_window; @@ -211,6 +214,7 @@ class NativeWidgetWin : public ui::WindowImpl, virtual void SetAccessibleState(ui::AccessibilityTypes::State state) OVERRIDE; virtual gfx::Rect GetWindowScreenBounds() const OVERRIDE; virtual gfx::Rect GetClientAreaScreenBounds() const OVERRIDE; + virtual gfx::Rect GetRestoredBounds() const OVERRIDE; virtual void SetBounds(const gfx::Rect& bounds) OVERRIDE; virtual void SetSize(const gfx::Size& size) OVERRIDE; virtual void SetBoundsConstrained(const gfx::Rect& bounds, @@ -219,8 +223,10 @@ class NativeWidgetWin : public ui::WindowImpl, virtual void SetShape(gfx::NativeRegion shape) OVERRIDE; virtual void Close() OVERRIDE; virtual void CloseNow() OVERRIDE; + virtual void EnableClose(bool enable) OVERRIDE; virtual void Show() OVERRIDE; virtual void Hide() OVERRIDE; + virtual void ShowNativeWidget(ShowState state) OVERRIDE; virtual bool IsVisible() const OVERRIDE; virtual void Activate() OVERRIDE; virtual void Deactivate() OVERRIDE; @@ -418,6 +424,18 @@ class NativeWidgetWin : public ui::WindowImpl, // behavior. virtual void OnFinalMessage(HWND window); + // Retrieve the show state of the window. This is one of the SW_SHOW* flags + // passed into Windows' ShowWindow method. For normal windows this defaults + // to SW_SHOWNORMAL, however windows (e.g. the main window) can override this + // method to provide different values (e.g. retrieve the user's specified + // show state from the shortcut starutp info). + virtual int GetShowState() const; + + // Returns the insets of the client area relative to the non-client area of + // the window. Override this function instead of OnNCCalcSize, which is + // crazily complicated. + virtual gfx::Insets GetClientAreaInsets() const; + // Start tracking all mouse events so that this window gets sent mouse leave // messages too. void TrackMouseEvents(DWORD mouse_tracking_flags); @@ -475,6 +493,12 @@ class NativeWidgetWin : public ui::WindowImpl, // layered windows only. void RedrawLayeredWindowContents(); + // Lock or unlock the window from being able to redraw itself in response to + // updates to its invalid region. + class ScopedRedrawLock; + void LockUpdates(); + void UnlockUpdates(); + // Responds to the client area changing size, either at window creation time // or subsequently. void ClientAreaSizeChanged(); @@ -484,6 +508,11 @@ class NativeWidgetWin : public ui::WindowImpl, // frame windows. void ResetWindowRegion(bool force); + // Calls the default WM_NCACTIVATE handler with the specified activation + // value, safely wrapping the call in a ScopedRedrawLock to prevent frame + // flicker. + LRESULT CallDefaultNCActivateHandler(BOOL active); + // Overridden from NativeWidget. virtual gfx::AcceleratedWidget GetAcceleratedWidget() OVERRIDE; @@ -590,6 +619,12 @@ class NativeWidgetWin : public ui::WindowImpl, DWORD drag_frame_saved_window_style_; DWORD drag_frame_saved_window_ex_style_; + // True if updates to this window are currently locked. + bool lock_updates_; + + // The window styles of the window before updates were locked. + DWORD saved_window_style_; + DISALLOW_COPY_AND_ASSIGN(NativeWidgetWin); }; diff --git a/views/widget/widget.cc b/views/widget/widget.cc index e2b2202..eeff786 100644 --- a/views/widget/widget.cc +++ b/views/widget/widget.cc @@ -6,6 +6,7 @@ #include "base/logging.h" #include "base/message_loop.h" +#include "base/utf_string_conversions.h" #include "ui/gfx/compositor/compositor.h" #include "views/focus/view_storage.h" #include "views/ime/input_method.h" @@ -90,13 +91,14 @@ Widget::Widget() : is_mouse_button_pressed_(false), last_mouse_event_was_move_(false), native_widget_(NULL), - type_(InitParams::TYPE_WINDOW), widget_delegate_(NULL), non_client_view_(NULL), dragged_view_(NULL), ownership_(InitParams::NATIVE_WIDGET_OWNS_WIDGET), is_secondary_widget_(true), - frame_type_(FRAME_TYPE_DEFAULT) { + frame_type_(FRAME_TYPE_DEFAULT), + disable_inactive_rendering_(false), + widget_closed_(false) { } Widget::~Widget() { @@ -124,7 +126,6 @@ Widget* Widget::GetWidgetForNativeView(gfx::NativeView native_view) { } void Widget::Init(const InitParams& params) { - type_ = params.type; widget_delegate_ = params.delegate ? params.delegate : new DefaultWidgetDelegate; ownership_ = params.ownership; @@ -136,9 +137,13 @@ void Widget::Init(const InitParams& params) { if (params.type == InitParams::TYPE_MENU) is_mouse_button_pressed_ = native_widget_->IsMouseButtonDown(); native_widget_->InitNativeWidget(params); - if (type_ == InitParams::TYPE_WINDOW) { + if (params.type == InitParams::TYPE_WINDOW) { non_client_view_ = new NonClientView; non_client_view_->SetFrameView(CreateNonClientFrameView()); + // Create the ClientView, add it to the NonClientView and add the + // NonClientView to the RootView. This will cause everything to be parented. + non_client_view_->set_client_view(widget_delegate_->CreateClientView(this)); + SetContentsView(non_client_view_); } } @@ -189,6 +194,14 @@ void Widget::NotifyNativeViewHierarchyChanged(bool attached, root_view_->NotifyNativeViewHierarchyChanged(attached, native_view); } +Window* Widget::AsWindow() { + return NULL; +} + +const Window* Widget::AsWindow() const { + return NULL; +} + // Converted methods (see header) ---------------------------------------------- Widget* Widget::GetTopLevelWidget() { @@ -214,6 +227,10 @@ gfx::Rect Widget::GetClientAreaScreenBounds() const { return native_widget_->GetClientAreaScreenBounds(); } +gfx::Rect Widget::GetRestoredBounds() const { + return native_widget_->GetRestoredBounds(); +} + void Widget::SetBounds(const gfx::Rect& bounds) { native_widget_->SetBounds(bounds); } @@ -240,13 +257,32 @@ void Widget::SetShape(gfx::NativeRegion shape) { } void Widget::Close() { - native_widget_->Close(); + if (widget_closed_) { + // It appears we can hit this code path if you close a modal dialog then + // close the last browser before the destructor is hit, which triggers + // invoking Close again. + return; + } + + bool can_close = true; + if (non_client_view_) + can_close = non_client_view_->CanClose(); + if (can_close) { + SaveWindowPosition(); + native_widget_->Close(); + widget_closed_ = true; + } } void Widget::CloseNow() { native_widget_->CloseNow(); } +void Widget::EnableClose(bool enable) { + non_client_view_->EnableClose(enable); + native_widget_->EnableClose(enable); +} + void Widget::Show() { native_widget_->Show(); } @@ -255,6 +291,10 @@ void Widget::Hide() { native_widget_->Hide(); } +void Widget::ShowInactive() { + native_widget_->ShowNativeWidget(NativeWidget::SHOW_INACTIVE); +} + void Widget::Activate() { native_widget_->Activate(); } @@ -267,6 +307,11 @@ bool Widget::IsActive() const { return native_widget_->IsActive(); } +void Widget::DisableInactiveRendering() { + disable_inactive_rendering_ = true; + non_client_view_->DisableInactiveRendering(disable_inactive_rendering_); +} + void Widget::SetAlwaysOnTop(bool on_top) { native_widget_->SetAlwaysOnTop(on_top); } @@ -387,6 +432,29 @@ void Widget::ResetLastMouseMoveFlag() { last_mouse_event_was_move_ = false; } +void Widget::UpdateWindowTitle() { + // If the non-client view is rendering its own title, it'll need to relayout + // now. + non_client_view_->Layout(); + + // Update the native frame's text. We do this regardless of whether or not + // the native frame is being used, since this also updates the taskbar, etc. + string16 window_title; + if (native_widget_->IsScreenReaderActive()) { + window_title = WideToUTF16(widget_delegate_->GetAccessibleWindowTitle()); + } else { + window_title = WideToUTF16(widget_delegate_->GetWindowTitle()); + } + base::i18n::AdjustStringForLocaleDirection(&window_title); + native_widget_->SetWindowTitle(UTF16ToWide(window_title)); +} + +void Widget::UpdateWindowIcon() { + non_client_view_->UpdateWindowIcon(); + native_widget_->SetWindowIcons(widget_delegate_->GetWindowIcon(), + widget_delegate_->GetWindowAppIcon()); +} + FocusTraversable* Widget::GetFocusTraversable() { return static_cast<internal::RootView*>(root_view_.get()); } @@ -454,6 +522,28 @@ void Widget::NotifyAccessibilityEvent( //////////////////////////////////////////////////////////////////////////////// // Widget, NativeWidgetDelegate implementation: +bool Widget::CanActivate() const { + return widget_delegate_->CanActivate(); +} + +bool Widget::IsInactiveRenderingDisabled() const { + return disable_inactive_rendering_; +} + +void Widget::EnableInactiveRendering() { + disable_inactive_rendering_ = false; + non_client_view_->DisableInactiveRendering(false); +} + +void Widget::OnNativeWidgetActivationChanged(bool active) { + if (!active) + SaveWindowPosition(); + + // TODO(beng): merge these two. + widget_delegate_->OnWidgetActivated(active); + widget_delegate_->OnWindowActivationChanged(active); +} + void Widget::OnNativeFocus(gfx::NativeView focused_view) { GetFocusManager()->GetWidgetFocusManager()->OnWidgetFocusEvent( focused_view, @@ -473,6 +563,17 @@ void Widget::OnNativeWidgetCreated() { focus_manager_.reset(new FocusManager(this)); } EnsureCompositor(); + + native_widget_->SetAccessibleRole( + widget_delegate_->GetAccessibleWindowRole()); + native_widget_->SetAccessibleState( + widget_delegate_->GetAccessibleWindowState()); +} + +void Widget::OnNativeWidgetDestroying() { + if (non_client_view_) + non_client_view_->WindowClosing(); + widget_delegate_->WindowClosing(); } void Widget::OnNativeWidgetDestroyed() { @@ -480,10 +581,22 @@ void Widget::OnNativeWidgetDestroyed() { widget_delegate_ = NULL; } -void Widget::OnSizeChanged(const gfx::Size& new_size) { +gfx::Size Widget::GetMinimumSize() { + return non_client_view_->GetMinimumSize(); +} + +void Widget::OnNativeWidgetSizeChanged(const gfx::Size& new_size) { root_view_->SetSize(new_size); } +void Widget::OnNativeWidgetBeginUserBoundsChange() { + widget_delegate_->OnWindowBeginUserBoundsChange(); +} + +void Widget::OnNativeWidgetEndUserBoundsChange() { + widget_delegate_->OnWindowEndUserBoundsChange(); +} + bool Widget::HasFocusManager() const { return !!focus_manager_.get(); } @@ -514,6 +627,10 @@ void Widget::OnNativeWidgetPaint(gfx::Canvas* canvas) { #endif } +int Widget::GetNonClientComponent(const gfx::Point& point) { + return non_client_view_->NonClientHitTest(point); +} + bool Widget::OnKeyEvent(const KeyEvent& event) { return static_cast<internal::RootView*>(GetRootView())->OnKeyEvent(event); } @@ -570,6 +687,10 @@ void Widget::OnMouseCaptureLost() { is_mouse_button_pressed_ = false; } +bool Widget::ExecuteCommand(int command_id) { + return widget_delegate_->ExecuteWindowsCommand(command_id); +} + Widget* Widget::AsWidget() { return this; } @@ -642,4 +763,20 @@ bool Widget::ShouldReleaseCaptureOnMouseReleased() const { return true; } +void Widget::SaveWindowPosition() { + // The window delegate does the actual saving for us. It seems like (judging + // by go/crash) that in some circumstances we can end up here after + // WM_DESTROY, at which point the window delegate is likely gone. So just + // bail. + if (!widget_delegate_) + return; + + bool maximized; + gfx::Rect bounds; + native_widget_->GetWindowBoundsAndMaximizedState(&bounds, &maximized); + widget_delegate_->SaveWindowPlacement(bounds, maximized); +} + + + } // namespace views diff --git a/views/widget/widget.h b/views/widget/widget.h index 19952eb..b2699de 100644 --- a/views/widget/widget.h +++ b/views/widget/widget.h @@ -220,6 +220,9 @@ class Widget : public internal::NativeWidgetDelegate, // Returns the bounds of the Widget's client area in screen coordinates. gfx::Rect GetClientAreaScreenBounds() const; + // Retrieves the restored bounds for the window. + gfx::Rect GetRestoredBounds() const; + // Sizes and/or places the widget to the specified bounds, size or position. void SetBounds(const gfx::Rect& bounds); void SetSize(const gfx::Size& size); @@ -247,10 +250,17 @@ class Widget : public internal::NativeWidgetDelegate, // any code that expects it to be valid beyond this call. void CloseNow(); + // Toggles the enable state for the Close button (and the Close menu item in + // the system menu). + void EnableClose(bool enable); + // Shows or hides the widget, without changing activation state. virtual void Show(); void Hide(); + // Like Show(), but does not activate the window. + void ShowInactive(); + // Activates the widget, assuming it already exists and is visible. void Activate(); @@ -261,6 +271,12 @@ class Widget : public internal::NativeWidgetDelegate, // Returns whether the Widget is the currently active window. virtual bool IsActive() const; + // Prevents the window from being rendered as deactivated the next time it is. + // This state is reset automatically as soon as the window becomes activated + // again. There is no ability to control the state through this API as this + // leads to sync problems. + void DisableInactiveRendering(); + // Sets the widget to be on top of all other widgets in the windowing system. void SetAlwaysOnTop(bool on_top); @@ -349,6 +365,12 @@ class Widget : public internal::NativeWidgetDelegate, // to cause the close button to highlight. void ResetLastMouseMoveFlag(); + // Tell the window to update its title from the delegate. + void UpdateWindowTitle(); + + // Tell the window to update its icon from the delegate. + void UpdateWindowIcon(); + // Retrieves the focus traversable for this widget. FocusTraversable* GetFocusTraversable(); @@ -418,19 +440,33 @@ class Widget : public internal::NativeWidgetDelegate, const NativeWidget* native_widget() const { return native_widget_; } NativeWidget* native_widget() { return native_widget_; } + // TODO(beng): remove once Window is folded in. + virtual Window* AsWindow(); + virtual const Window* AsWindow() const; + // Overridden from NativeWidgetDelegate: + virtual bool CanActivate() const OVERRIDE; + virtual bool IsInactiveRenderingDisabled() const OVERRIDE; + virtual void EnableInactiveRendering() OVERRIDE; + virtual void OnNativeWidgetActivationChanged(bool active) OVERRIDE; virtual void OnNativeFocus(gfx::NativeView focused_view) OVERRIDE; virtual void OnNativeBlur(gfx::NativeView focused_view) OVERRIDE; virtual void OnNativeWidgetCreated() OVERRIDE; + virtual void OnNativeWidgetDestroying() OVERRIDE; virtual void OnNativeWidgetDestroyed() OVERRIDE; - virtual void OnSizeChanged(const gfx::Size& new_size) OVERRIDE; + virtual gfx::Size GetMinimumSize() OVERRIDE; + virtual void OnNativeWidgetSizeChanged(const gfx::Size& new_size) OVERRIDE; + virtual void OnNativeWidgetBeginUserBoundsChange() OVERRIDE; + virtual void OnNativeWidgetEndUserBoundsChange() OVERRIDE; virtual bool HasFocusManager() const OVERRIDE; virtual bool OnNativeWidgetPaintAccelerated( const gfx::Rect& dirty_region) OVERRIDE; virtual void OnNativeWidgetPaint(gfx::Canvas* canvas) OVERRIDE; + virtual int GetNonClientComponent(const gfx::Point& point) OVERRIDE; virtual bool OnKeyEvent(const KeyEvent& event) OVERRIDE; virtual bool OnMouseEvent(const MouseEvent& event) OVERRIDE; virtual void OnMouseCaptureLost() OVERRIDE; + virtual bool ExecuteCommand(int command_id) OVERRIDE; virtual Widget* AsWidget() OVERRIDE; virtual const Widget* AsWidget() const OVERRIDE; @@ -476,9 +512,11 @@ class Widget : public internal::NativeWidgetDelegate, // Returns whether capture should be released on mouse release. virtual bool ShouldReleaseCaptureOnMouseReleased() const; - NativeWidget* native_widget_; + // Persists the window's restored position and maximized state using the + // window delegate. + void SaveWindowPosition(); - InitParams::Type type_; + NativeWidget* native_widget_; // Non-owned pointer to the Widget's delegate. May be NULL if no delegate is // being used. @@ -521,6 +559,13 @@ class Widget : public internal::NativeWidgetDelegate, // FRAME_TYPE_DEFAULT. FrameType frame_type_; + // True when the window should be rendered as active, regardless of whether + // or not it actually is. + bool disable_inactive_rendering_; + + // Set to true if the widget is in the process of closing. + bool widget_closed_; + DISALLOW_COPY_AND_ASSIGN(Widget); }; diff --git a/views/widget/widget_delegate.cc b/views/widget/widget_delegate.cc index e63cbbb..f58e891 100644 --- a/views/widget/widget_delegate.cc +++ b/views/widget/widget_delegate.cc @@ -99,7 +99,6 @@ std::wstring WidgetDelegate::GetWindowName() const { void WidgetDelegate::SaveWindowPlacement(const gfx::Rect& bounds, bool maximized) { - DCHECK(window_); std::wstring window_name = GetWindowName(); if (!ViewsDelegate::views_delegate || window_name.empty()) return; @@ -133,11 +132,11 @@ bool WidgetDelegate::ShouldRestoreWindowSize() const { } View* WidgetDelegate::GetContentsView() { - return NULL; + return new View; } -ClientView* WidgetDelegate::CreateClientView(Window* window) { - return new ClientView(window, GetContentsView()); +ClientView* WidgetDelegate::CreateClientView(Widget* widget) { + return new ClientView(widget, GetContentsView()); } NonClientFrameView* WidgetDelegate::CreateNonClientFrameView() { diff --git a/views/widget/widget_delegate.h b/views/widget/widget_delegate.h index 0e34e5b..a985051 100644 --- a/views/widget/widget_delegate.h +++ b/views/widget/widget_delegate.h @@ -22,6 +22,7 @@ class ClientView; class DialogDelegate; class NonClientFrameView; class View; +class Widget; class Window; // WidgetDelegate interface @@ -137,8 +138,8 @@ class WidgetDelegate { virtual View* GetContentsView(); // Called by the Window to create the Client View used to host the contents - // of the window. - virtual ClientView* CreateClientView(Window* window); + // of the widget. + virtual ClientView* CreateClientView(Widget* widget); // Called by the Widget to create the NonClient Frame View for this widget. // Return NULL to use the default one. |