summaryrefslogtreecommitdiffstats
path: root/views/widget
diff options
context:
space:
mode:
Diffstat (limited to 'views/widget')
-rw-r--r--views/widget/native_widget.h11
-rw-r--r--views/widget/native_widget_delegate.h29
-rw-r--r--views/widget/native_widget_gtk.cc33
-rw-r--r--views/widget/native_widget_gtk.h3
-rw-r--r--views/widget/native_widget_test_utils_gtk.cc2
-rw-r--r--views/widget/native_widget_test_utils_win.cc2
-rw-r--r--views/widget/native_widget_view.cc2
-rw-r--r--views/widget/native_widget_views.cc14
-rw-r--r--views/widget/native_widget_views.h3
-rw-r--r--views/widget/native_widget_win.cc361
-rw-r--r--views/widget/native_widget_win.h35
-rw-r--r--views/widget/widget.cc149
-rw-r--r--views/widget/widget.h51
-rw-r--r--views/widget/widget_delegate.cc7
-rw-r--r--views/widget/widget_delegate.h5
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.