From 2cb5b91effa942fa165eb847c295ddc883ab70df Mon Sep 17 00:00:00 2001 From: "sky@chromium.org" Date: Wed, 7 Oct 2009 03:30:22 +0000 Subject: Converts info bubbles on views/gtk from popups to normal windows to avoid the focus problems. BUG=none TEST=none Review URL: http://codereview.chromium.org/246099 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@28228 0039d316-1c4b-4281-b951-d872f2087c98 --- views/widget/widget_gtk.cc | 39 +++++++++++++++++++++++++++++++++++---- views/widget/widget_gtk.h | 27 ++++++++++++++++++++++++++- views/window/window.h | 13 +++++++------ views/window/window_gtk.cc | 26 ++------------------------ views/window/window_gtk.h | 16 +--------------- 5 files changed, 71 insertions(+), 50 deletions(-) (limited to 'views') diff --git a/views/widget/widget_gtk.cc b/views/widget/widget_gtk.cc index 734ea02..299eea5 100644 --- a/views/widget/widget_gtk.cc +++ b/views/widget/widget_gtk.cc @@ -108,7 +108,9 @@ WidgetGtk::WidgetGtk(Type type) ignore_drag_leave_(false), opacity_(255), drag_data_(NULL), - in_paint_now_(false) { + in_paint_now_(false), + is_active_(false), + transient_to_parent_(false) { static bool installed_message_loop_observer = false; if (!installed_message_loop_observer) { installed_message_loop_observer = true; @@ -122,6 +124,8 @@ WidgetGtk::WidgetGtk(Type type) } WidgetGtk::~WidgetGtk() { + if (type_ != TYPE_CHILD) + ActiveWindowWatcherX::RemoveObserver(this); MessageLoopForUI::current()->RemoveObserver(this); } @@ -190,11 +194,37 @@ void WidgetGtk::DoDrag(const OSExchangeData& data, int operation) { drag_data_ = NULL; } +void WidgetGtk::ActiveWindowChanged(GdkWindow* active_window) { + if (!GetNativeView()) + return; + + bool was_active = IsActive(); + is_active_ = (active_window == GTK_WIDGET(GetNativeView())->window); + if (!is_active_ && active_window && type_ != TYPE_CHILD) { + // We're not active, but the force the window to be rendered as active if + // a child window is transient to us. + GtkWidget* widget = NULL; + gdk_window_get_user_data(active_window, + reinterpret_cast(&widget)); + is_active_ = + (widget && GTK_IS_WINDOW(widget) && + gtk_window_get_transient_for(GTK_WINDOW(widget)) == GTK_WINDOW( + widget_)); + } + if (was_active != IsActive()) + IsActiveChanged(); +} + +void WidgetGtk::IsActiveChanged() { +} + //////////////////////////////////////////////////////////////////////////////// // WidgetGtk, Widget implementation: void WidgetGtk::Init(GtkWidget* parent, const gfx::Rect& bounds) { + if (type_ != TYPE_CHILD) + ActiveWindowWatcherX::AddObserver(this); // Force creation of the RootView if it hasn't been created yet. GetRootView(); @@ -433,9 +463,8 @@ bool WidgetGtk::IsVisible() const { } bool WidgetGtk::IsActive() const { - // If this only applies to windows, it shouldn't be in widget. - DCHECK(GTK_IS_WINDOW(widget_)); - return gtk_window_is_active(GTK_WINDOW(widget_)); + DCHECK(type_ != TYPE_CHILD); + return is_active_; } void WidgetGtk::GenerateMousePressedForView(View* view, @@ -558,6 +587,8 @@ void WidgetGtk::CreateGtkWidget(GtkWidget* parent, const gfx::Rect& bounds) { widget_ = gtk_window_new( (type_ == TYPE_WINDOW || type_ == TYPE_DECORATED_WINDOW) ? GTK_WINDOW_TOPLEVEL : GTK_WINDOW_POPUP); + if (transient_to_parent_) + gtk_window_set_transient_for(GTK_WINDOW(widget_), GTK_WINDOW(parent)); GTK_WIDGET_UNSET_FLAGS(widget_, GTK_DOUBLE_BUFFERED); if (!bounds.size().IsEmpty()) { diff --git a/views/widget/widget_gtk.h b/views/widget/widget_gtk.h index 8009f89..f91befa 100644 --- a/views/widget/widget_gtk.h +++ b/views/widget/widget_gtk.h @@ -7,6 +7,7 @@ #include +#include "app/active_window_watcher_x.h" #include "base/message_loop.h" #include "views/focus/focus_manager.h" #include "views/widget/widget.h" @@ -30,7 +31,8 @@ class WindowGtk; class WidgetGtk : public Widget, public MessageLoopForUI::Observer, - public FocusTraversable { + public FocusTraversable, + public ActiveWindowWatcherX::Observer { public: // Type of widget. enum Type { @@ -48,6 +50,17 @@ class WidgetGtk explicit WidgetGtk(Type type); virtual ~WidgetGtk(); + // Marks this window as transient to its parent. A window that is transient + // to its parent results in the parent rendering active when the child is + // active. + // This must be invoked before Init. This is only used for types other than + // TYPE_CHILD. The default is false. + // See gtk_window_set_transient_for for details. + void make_transient_to_parent() { + DCHECK(!widget_); + transient_to_parent_ = true; + } + // Makes the background of the window totally transparent. This must be // invoked before Init. This does a couple of checks and returns true if // the window can be made transparent. The actual work of making the window @@ -88,6 +101,12 @@ class WidgetGtk // used for. bool in_paint_now() const { return in_paint_now_; } + // Invoked when the active status changes. + virtual void IsActiveChanged(); + + // Overriden from ActiveWindowWatcherX::Observer. + virtual void ActiveWindowChanged(GdkWindow* active_window); + // Overridden from Widget: virtual void Init(gfx::NativeView parent, const gfx::Rect& bounds); virtual void SetContentsView(View* view); @@ -384,6 +403,12 @@ class WidgetGtk // See description above getter for details. bool in_paint_now_; + // Are we active? + bool is_active_; + + // See make_transient_to_parent for a description. + bool transient_to_parent_; + DISALLOW_COPY_AND_ASSIGN(WidgetGtk); }; diff --git a/views/window/window.h b/views/window/window.h index dc7a8e3..8983972 100644 --- a/views/window/window.h +++ b/views/window/window.h @@ -82,6 +82,13 @@ class Window { // Decrements the force hidden count, showing the window if we have reached // the top of the stack. See PushForceHidden. virtual void PopForceHidden() = 0; + + // 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. + // For Gtk use WidgetGtk::make_transient_to_parent. + virtual void DisableInactiveRendering() = 0; #endif // Activate the window, assuming it already exists and is visible. @@ -121,12 +128,6 @@ class Window { // the system menu). virtual void EnableClose(bool enable) = 0; - // 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. - virtual void DisableInactiveRendering() = 0; - // Tell the window to update its title from the delegate. virtual void UpdateWindowTitle() = 0; diff --git a/views/window/window_gtk.cc b/views/window/window_gtk.cc index 2a9fd97..9c3cba6 100644 --- a/views/window/window_gtk.cc +++ b/views/window/window_gtk.cc @@ -76,7 +76,6 @@ GdkCursorType HitTestCodeToGdkCursorType(int hittest_code) { namespace views { WindowGtk::~WindowGtk() { - ActiveWindowWatcherX::RemoveObserver(this); } // static @@ -159,7 +158,7 @@ void WindowGtk::Restore() { } bool WindowGtk::IsActive() const { - return is_active_; + return WidgetGtk::IsActive(); } bool WindowGtk::IsVisible() const { @@ -189,11 +188,6 @@ void WindowGtk::EnableClose(bool enable) { gtk_window_set_deletable(GetNativeWindow(), enable); } -void WindowGtk::DisableInactiveRendering() { - // TODO(sky): this doesn't make sense as bubbles are popups, which don't - // trigger a change in active status. -} - void WindowGtk::UpdateWindowTitle() { // If the non-client view is rendering its own title, it'll need to relayout // now. @@ -338,19 +332,6 @@ gboolean WindowGtk::OnWindowStateEvent(GtkWidget* widget, return FALSE; } -void WindowGtk::ActiveWindowChanged(GdkWindow* active_window) { - if (!GetNativeWindow()) - return; - - bool was_active = IsActive(); - is_active_ = (active_window == GTK_WIDGET(GetNativeWindow())->window); - if (was_active != IsActive()) - IsActiveChanged(); -} - -void WindowGtk::IsActiveChanged() { -} - //////////////////////////////////////////////////////////////////////////////// // WindowGtk, protected: @@ -360,12 +341,9 @@ WindowGtk::WindowGtk(WindowDelegate* window_delegate) window_delegate_(window_delegate), non_client_view_(new NonClientView(this)), window_state_(GDK_WINDOW_STATE_WITHDRAWN), - window_closed_(false), - is_active_(false) { + window_closed_(false) { is_window_ = true; window_delegate_->window_.reset(this); - - ActiveWindowWatcherX::AddObserver(this); } void WindowGtk::Init(GtkWindow* parent, const gfx::Rect& bounds) { diff --git a/views/window/window_gtk.h b/views/window/window_gtk.h index 5149f60..0f496c4 100644 --- a/views/window/window_gtk.h +++ b/views/window/window_gtk.h @@ -5,7 +5,6 @@ #ifndef VIEWS_WINDOW_WINDOW_GTK_H_ #define VIEWS_WINDOW_WINDOW_GTK_H_ -#include "app/active_window_watcher_x.h" #include "base/basictypes.h" #include "views/widget/widget_gtk.h" #include "views/window/window.h" @@ -21,9 +20,7 @@ class Client; class WindowDelegate; // Window implementation for GTK. -class WindowGtk : public WidgetGtk, - public Window, - public ActiveWindowWatcherX::Observer { +class WindowGtk : public WidgetGtk, public Window { public: virtual ~WindowGtk(); @@ -46,7 +43,6 @@ class WindowGtk : public WidgetGtk, virtual void SetFullscreen(bool fullscreen); virtual bool IsFullscreen() const; virtual void EnableClose(bool enable); - virtual void DisableInactiveRendering(); virtual void UpdateWindowTitle(); virtual void UpdateWindowIcon(); virtual void SetIsAlwaysOnTop(bool always_on_top); @@ -71,13 +67,6 @@ class WindowGtk : public WidgetGtk, virtual gboolean OnWindowStateEvent(GtkWidget* widget, GdkEventWindowState* event); - // Overriden from ActiveWindowWatcherX::Observer. - virtual void ActiveWindowChanged(GdkWindow* active_window); - - // WindowGtk specific. - // Invoked when the active status changes. - virtual void IsActiveChanged(); - protected: // For the constructor. friend class Window; @@ -122,9 +111,6 @@ class WindowGtk : public WidgetGtk, // Set to true if the window is in the process of closing. bool window_closed_; - // Are we active? - bool is_active_; - DISALLOW_COPY_AND_ASSIGN(WindowGtk); }; -- cgit v1.1