diff options
author | erg@google.com <erg@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-19 23:30:27 +0000 |
---|---|---|
committer | erg@google.com <erg@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-19 23:30:27 +0000 |
commit | 98f5ea69fed3f2f39646acdffd76baeac4a6a7df (patch) | |
tree | e6f4525d1daf154b650df2c503a5d52445a3eecb /chrome | |
parent | fd81a10dc199076671eab98cc5722522004a84d5 (diff) | |
download | chromium_src-98f5ea69fed3f2f39646acdffd76baeac4a6a7df.zip chromium_src-98f5ea69fed3f2f39646acdffd76baeac4a6a7df.tar.gz chromium_src-98f5ea69fed3f2f39646acdffd76baeac4a6a7df.tar.bz2 |
Quick reimplementation of StatusBubbleGtk to not suck as much.
The TabContentsContainerGtk now uses a GtkFixed to store its
children, and the status bubble is now a child of that GtkFixed
so that it can be absolutely positioned on top of the rendered
data. Since it is no longer a GTK_WINDOW_POPUP, all the weird
stuff related to different window managers goes away.
http://crbug.com/11635
Review URL: http://codereview.chromium.org/113590
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@16433 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r-- | chrome/browser/gtk/browser_window_gtk.cc | 6 | ||||
-rw-r--r-- | chrome/browser/gtk/status_bubble_gtk.cc | 126 | ||||
-rw-r--r-- | chrome/browser/gtk/status_bubble_gtk.h | 54 | ||||
-rw-r--r-- | chrome/browser/gtk/tab_contents_container_gtk.cc | 55 | ||||
-rw-r--r-- | chrome/browser/gtk/tab_contents_container_gtk.h | 25 |
5 files changed, 197 insertions, 69 deletions
diff --git a/chrome/browser/gtk/browser_window_gtk.cc b/chrome/browser/gtk/browser_window_gtk.cc index 8417e64..51c2f23 100644 --- a/chrome/browser/gtk/browser_window_gtk.cc +++ b/chrome/browser/gtk/browser_window_gtk.cc @@ -326,7 +326,9 @@ BrowserWindowGtk::BrowserWindowGtk(Browser* browser) infobar_container_->widget(), FALSE, FALSE, 0); - contents_container_.reset(new TabContentsContainerGtk()); + status_bubble_.reset(new StatusBubbleGtk()); + + contents_container_.reset(new TabContentsContainerGtk(status_bubble_.get())); contents_container_->AddContainerToBox(render_area_vbox_); // Note that calling this the first time is necessary to get the @@ -334,8 +336,6 @@ BrowserWindowGtk::BrowserWindowGtk(Browser* browser) // TODO(port): make this a pref. SetCustomFrame(false); - status_bubble_.reset(new StatusBubbleGtk(window_)); - GtkWidget* event_box = gtk_event_box_new(); gtk_container_add(GTK_CONTAINER(event_box), render_area_vbox_); gtk_container_add(GTK_CONTAINER(content_vbox_), event_box); diff --git a/chrome/browser/gtk/status_bubble_gtk.cc b/chrome/browser/gtk/status_bubble_gtk.cc index abb7a0d..1034bf9 100644 --- a/chrome/browser/gtk/status_bubble_gtk.cc +++ b/chrome/browser/gtk/status_bubble_gtk.cc @@ -4,19 +4,35 @@ #include "chrome/browser/gtk/status_bubble_gtk.h" +#include <gtk/gtk.h> + +#include "base/gfx/gtk_util.h" #include "base/string_util.h" +#include "chrome/browser/gtk/slide_animator_gtk.h" +#include "chrome/common/gtk_util.h" #include "googleurl/src/gurl.h" -// NOTE: this code is probably the wrong approach for the status bubble. -// Talk to evanm before you attempt to fix bugs in it -- we're probably -// better off restructuring it. +namespace { + +const GdkColor kBackgroundColor = GDK_COLOR_RGB(0xe6, 0xed, 0xf4); +const GdkColor kFrameBorderColor = GDK_COLOR_RGB(0xbe, 0xc8, 0xd4); + +// Inner padding between the border and the text label. +const int kInternalTopBottomPadding = 1; +const int kInternalLeftRightPadding = 2; -StatusBubbleGtk::StatusBubbleGtk(GtkWindow* parent) - : parent_(parent), window_(NULL) { +// Border of color kFrameBorderColor around the status bubble. +const int kBorderPadding = 1; + +} // namespace + +StatusBubbleGtk::StatusBubbleGtk() + : parent_(NULL) { + InitWidgets(); } StatusBubbleGtk::~StatusBubbleGtk() { - Hide(); + container_.Destroy(); } void StatusBubbleGtk::SetStatus(const std::string& status) { @@ -25,55 +41,89 @@ void StatusBubbleGtk::SetStatus(const std::string& status) { return; } - if (!window_) - Create(); - gtk_label_set_text(GTK_LABEL(label_), status.c_str()); - Reposition(); - gtk_widget_show(window_); + + Show(); } void StatusBubbleGtk::SetStatus(const std::wstring& status) { SetStatus(WideToUTF8(status)); } +void StatusBubbleGtk::SetParentAllocation( + GtkWidget* parent, GtkAllocation* allocation) { + parent_ = parent; + parent_allocation_ = *allocation; + SetStatusBubbleSize(); +} + void StatusBubbleGtk::SetURL(const GURL& url, const std::wstring& languages) { SetStatus(url.possibly_invalid_spec()); } +void StatusBubbleGtk::Show() { + SetStatusBubbleSize(); + gtk_widget_show_all(container_.get()); + + if (container_.get()->window) + gdk_window_raise(container_.get()->window); +} + void StatusBubbleGtk::Hide() { - if (!window_) - return; - gtk_widget_destroy(window_); - window_ = NULL; + gtk_widget_hide_all(container_.get()); +} + +void StatusBubbleGtk::SetStatusBubbleSize() { + if (parent_) { + GtkRequisition requisition; + gtk_widget_size_request(container_.get(), &requisition); + + // TODO(erg): Previously, I put a call to gtk_fixed_put() here. It appears + // that doing this sets off a size-allocate storm, since gtk_fixed_put() + // calls gtk_widget_queue_resize on the GtkFixed that caused this message. + // The real solution may be creating a subclass of GtkVBox that has extra + // code to deal with floating widgets, but this hack is good enough for + // Friday. evanm says that there's a a GtkFixed subclass in test_shell that + // we'll be stealing for plugin support anyway that should also do the same + // task. + + GtkAllocation widget_allocation; + int child_y = std::max( + parent_allocation_.y + parent_allocation_.height - requisition.height, + 0); + widget_allocation.x = 0; + widget_allocation.y = child_y; + widget_allocation.width = std::min(requisition.width, + parent_allocation_.width); + widget_allocation.height = requisition.height; + gtk_widget_size_allocate(container_.get(), &widget_allocation); + } } void StatusBubbleGtk::MouseMoved() { - if (!window_) - return; - // We ignore for now. - // TODO(port): the fancy sliding behavior. + // We can't do that fancy sliding behaviour where the status bubble slides + // out of the window because the window manager gets in the way. So totally + // ignore this message for now. + // + // TODO(erg): At least get some sliding behaviour so that it slides out of + // the way to hide the status bubble on mouseover. } -void StatusBubbleGtk::Create() { - if (window_) - return; +void StatusBubbleGtk::InitWidgets() { + label_ = gtk_label_new(NULL); - window_ = gtk_window_new(GTK_WINDOW_POPUP); - gtk_window_set_transient_for(GTK_WINDOW(window_), parent_); - gtk_container_set_border_width(GTK_CONTAINER(window_), 2); - label_ = gtk_label_new(""); - gtk_widget_show(label_); - gtk_container_add(GTK_CONTAINER(window_), label_); -} + GtkWidget* padding = gtk_alignment_new(0, 0, 1, 1); + gtk_alignment_set_padding(GTK_ALIGNMENT(padding), + kInternalTopBottomPadding, kInternalTopBottomPadding, + kInternalLeftRightPadding, kInternalLeftRightPadding); + gtk_container_add(GTK_CONTAINER(padding), label_); + + GtkWidget* bg_box = gtk_event_box_new(); + gtk_container_add(GTK_CONTAINER(bg_box), padding); + gtk_widget_modify_bg(bg_box, GTK_STATE_NORMAL, &kBackgroundColor); -void StatusBubbleGtk::Reposition() { - int x, y, width, parent_height; - gdk_window_get_position(GTK_WIDGET(parent_)->window, &x, &y); - gtk_window_get_size(parent_, &width, &parent_height); - GtkRequisition requisition; - gtk_widget_size_request(window_, &requisition); - // TODO(port): RTL positioning. - gtk_window_move(GTK_WINDOW(window_), x, - y + parent_height - requisition.height); + container_.Own(gtk_util::CreateGtkBorderBin(bg_box, &kFrameBorderColor, + kBorderPadding, kBorderPadding, kBorderPadding, kBorderPadding)); + gtk_widget_set_name(container_.get(), "status-bubble"); + gtk_widget_set_app_paintable(container_.get(), TRUE); } diff --git a/chrome/browser/gtk/status_bubble_gtk.h b/chrome/browser/gtk/status_bubble_gtk.h index 83488f2..db8044c 100644 --- a/chrome/browser/gtk/status_bubble_gtk.h +++ b/chrome/browser/gtk/status_bubble_gtk.h @@ -5,17 +5,23 @@ #ifndef CHROME_BROWSER_GTK_STATUS_BUBBLE_GTK_H_ #define CHROME_BROWSER_GTK_STATUS_BUBBLE_GTK_H_ -#include <string> - #include <gtk/gtk.h> +#include <string> + +#include "base/scoped_ptr.h" #include "chrome/browser/status_bubble.h" +#include "chrome/common/owned_widget_gtk.h" class GURL; +// GTK implementation of StatusBubble. Unlike Windows, our status bubble +// doesn't have the nice leave-the-window effect since we can't rely on the +// window manager to not try to be "helpful" and center our popups, etc. +// We therefore position it absolutely in a GtkFixed, that we don't own. class StatusBubbleGtk : public StatusBubble { public: - StatusBubbleGtk(GtkWindow* parent); + StatusBubbleGtk(); virtual ~StatusBubbleGtk(); // StatusBubble implementation. @@ -26,22 +32,42 @@ class StatusBubbleGtk : public StatusBubble { void SetStatus(const std::string& status_utf8); + // Notification from our parent GtkFixed about its size. |allocation| is the + // size of our |parent| GtkFixed, and we use it to position our status bubble + // directly on top of the current render view. + void SetParentAllocation(GtkWidget* parent, GtkAllocation* allocation); + + // Top of the widget hierarchy for a StatusBubble. This top level widget is + // guarenteed to have its gtk_widget_name set to "status-bubble" for + // identification. + GtkWidget* widget() { return container_.get(); } + private: - // Construct the window/widget. - void Create(); + // Sets the status bubble's location in the parent GtkFixed, shows the widget + // and makes sure that the status bubble has the highest z-order. + void Show(); - // Reposition ourselves atop our parent window. - void Reposition(); + // Builds the widgets, containers, etc. + void InitWidgets(); - // The window we display on top of. - GtkWindow* parent_; + // An ad hoc, informally-specified, bug-ridden, slow implementation of half + // of GTK's requisition/allocation system. We use this to position the status + // bubble on top of our parent GtkFixed. + void SetStatusBubbleSize(); - // The top-level (popup) window we own. - // NULL when we're not showing. - GtkWidget* window_; + // A GtkAlignment that is the child of |slide_widget_|. + OwnedWidgetGtk container_; - // The GtkLabel holding the text./ + // The GtkLabel holding the text. GtkWidget* label_; + + // Our parent GtkFixed. (We don't own this; we only keep a reference as we + // set our own size by notifying |parent_| of our desired size.) + GtkWidget* parent_; + + // |parent_|'s GtkAllocation. We make sure that |container_| lives along the + // bottom of this and doesn't protrude. + GtkAllocation parent_allocation_; }; -#endif // #ifndef CHROME_BROWSER_GTK_STATUS_BUBBLE_GTK_H_ +#endif // CHROME_BROWSER_GTK_STATUS_BUBBLE_GTK_H_ diff --git a/chrome/browser/gtk/tab_contents_container_gtk.cc b/chrome/browser/gtk/tab_contents_container_gtk.cc index be8fe19..02f635f 100644 --- a/chrome/browser/gtk/tab_contents_container_gtk.cc +++ b/chrome/browser/gtk/tab_contents_container_gtk.cc @@ -5,14 +5,35 @@ #include "chrome/browser/gtk/tab_contents_container_gtk.h" #include "base/gfx/native_widget_types.h" +#include "chrome/browser/gtk/status_bubble_gtk.h" #include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/browser/renderer_host/render_widget_host_view_gtk.h" #include "chrome/common/notification_service.h" -TabContentsContainerGtk::TabContentsContainerGtk() +namespace { + +// Allocates all normal tab contents views to the size of the passed in +// |allocation|. Ignores StatusBubbles, which are handled separately. +void ChildrenSizeAllocate(GtkWidget* widget, void* param) { + GtkAllocation* allocation = reinterpret_cast<GtkAllocation*>(param); + + if (strcmp(gtk_widget_get_name(widget), "status-bubble") != 0) { + gtk_widget_size_allocate(widget, allocation); + } +} + +} // namespace + +TabContentsContainerGtk::TabContentsContainerGtk(StatusBubbleGtk* status_bubble) : tab_contents_(NULL), - vbox_(gtk_vbox_new(FALSE, 0)) { - gtk_widget_show_all(vbox_); + status_bubble_(status_bubble), + fixed_(gtk_fixed_new()) { + gtk_fixed_put(GTK_FIXED(fixed_), status_bubble->widget(), 0, 0); + + g_signal_connect(fixed_, "size-allocate", + G_CALLBACK(OnFixedSizeAllocate), this); + + gtk_widget_show(fixed_); } TabContentsContainerGtk::~TabContentsContainerGtk() { @@ -21,7 +42,7 @@ TabContentsContainerGtk::~TabContentsContainerGtk() { } void TabContentsContainerGtk::AddContainerToBox(GtkWidget* box) { - gtk_box_pack_start(GTK_BOX(box), vbox_, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(box), fixed_, TRUE, TRUE, 0); } void TabContentsContainerGtk::SetTabContents(TabContents* tab_contents) { @@ -44,9 +65,8 @@ void TabContentsContainerGtk::SetTabContents(TabContents* tab_contents) { gfx::NativeView widget = tab_contents_->GetNativeView(); if (widget) { - // Pack it into |vbox_| if it isn't already. - if (widget->parent != vbox_) - gtk_box_pack_end(GTK_BOX(vbox_), widget, TRUE, TRUE, 0); + if (widget->parent != fixed_) + gtk_fixed_put(GTK_FIXED(fixed_), widget, 0, 0); gtk_widget_show(widget); } @@ -64,9 +84,11 @@ void TabContentsContainerGtk::SetTabContents(TabContents* tab_contents) { void TabContentsContainerGtk::DetachTabContents(TabContents* tab_contents) { gfx::NativeView widget = tab_contents_->GetNativeView(); - if (widget) { - DCHECK_EQ(widget->parent, vbox_); - gtk_container_remove(GTK_CONTAINER(vbox_), widget); + // It is possible to detach an unrealized, unparented TabContents if you + // slow things down enough in valgrind. Might happen in the real world, too. + if (widget && widget->parent) { + DCHECK_EQ(widget->parent, fixed_); + gtk_container_remove(GTK_CONTAINER(fixed_), widget); } } @@ -129,3 +151,16 @@ void TabContentsContainerGtk::TabContentsDestroyed(TabContents* contents) { DCHECK(contents == tab_contents_); SetTabContents(NULL); } + +// static +void TabContentsContainerGtk::OnFixedSizeAllocate( + GtkWidget* fixed, + GtkAllocation* allocation, + TabContentsContainerGtk* container) { + // Set all the tab contents GtkWidgets to the size of the allocation. + gtk_container_foreach(GTK_CONTAINER(fixed), ChildrenSizeAllocate, + allocation); + + // Tell the status bubble about how large it can be. + container->status_bubble_->SetParentAllocation(fixed, allocation); +} diff --git a/chrome/browser/gtk/tab_contents_container_gtk.h b/chrome/browser/gtk/tab_contents_container_gtk.h index 1cb72e5..8915b67 100644 --- a/chrome/browser/gtk/tab_contents_container_gtk.h +++ b/chrome/browser/gtk/tab_contents_container_gtk.h @@ -11,11 +11,12 @@ #include "chrome/common/notification_observer.h" class RenderViewHost; +class StatusBubbleGtk; class TabContents; class TabContentsContainerGtk : public NotificationObserver { public: - TabContentsContainerGtk(); + explicit TabContentsContainerGtk(StatusBubbleGtk* status_bubble); ~TabContentsContainerGtk(); // Inserts our GtkWidget* hierarchy into a GtkBox managed by our owner. @@ -48,13 +49,29 @@ class TabContentsContainerGtk : public NotificationObserver { // get notified. void TabContentsDestroyed(TabContents* contents); + // Implements our hack around a GtkFixed. The entire size of the GtkFixed is + // allocated to normal tab contents views, while the status bubble is + // informed of its parent and its parent's allocation (it makes a decision + // about layout later.) + static void OnFixedSizeAllocate( + GtkWidget* fixed, + GtkAllocation* allocation, + TabContentsContainerGtk* container); + // The currently visible TabContents. TabContents* tab_contents_; - // We keep a GtkVBox which is inserted into this object's owner's GtkWidget + // The status bubble manager. Always non-NULL. + StatusBubbleGtk* status_bubble_; + + // We keep a GtkFixed which is inserted into this object's owner's GtkWidget // hierarchy. We then insert and remove TabContents GtkWidgets into this - // vbox_. - GtkWidget* vbox_; + // fixed_. This should not be a GtkVBox since there were errors with timing + // where the vbox was horizontally split with the top half displaying the + // current TabContents and bottom half displaying the loading page. In + // addition, we need to position the status bubble on top of the currently + // displayed TabContents so we put that in this part of the hierarchy. + GtkWidget* fixed_; DISALLOW_COPY_AND_ASSIGN(TabContentsContainerGtk); }; |