summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorerg@google.com <erg@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-05-19 23:30:27 +0000
committererg@google.com <erg@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-05-19 23:30:27 +0000
commit98f5ea69fed3f2f39646acdffd76baeac4a6a7df (patch)
treee6f4525d1daf154b650df2c503a5d52445a3eecb /chrome
parentfd81a10dc199076671eab98cc5722522004a84d5 (diff)
downloadchromium_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.cc6
-rw-r--r--chrome/browser/gtk/status_bubble_gtk.cc126
-rw-r--r--chrome/browser/gtk/status_bubble_gtk.h54
-rw-r--r--chrome/browser/gtk/tab_contents_container_gtk.cc55
-rw-r--r--chrome/browser/gtk/tab_contents_container_gtk.h25
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);
};