summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authortc@google.com <tc@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-07-31 17:11:41 +0000
committertc@google.com <tc@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-07-31 17:11:41 +0000
commit6d236bc4b1e2817c1e54ffb3aad567b1bab2d9fb (patch)
treea5bd21f676a5ec1ecc15e6b0e9f653afe62c4b1f /chrome
parent028901705d7166ab35d4e01931271511abf9c7da (diff)
downloadchromium_src-6d236bc4b1e2817c1e54ffb3aad567b1bab2d9fb.zip
chromium_src-6d236bc4b1e2817c1e54ffb3aad567b1bab2d9fb.tar.gz
chromium_src-6d236bc4b1e2817c1e54ffb3aad567b1bab2d9fb.tar.bz2
Show an icon and the page title in the custom frame when it's an
app mode window or a popup window. The icon will become a clockwise spinning throbber when pages are loading. BUG=16049 TEST=Open a window using --app=http://google.com/ and click on a few links. Review URL: http://codereview.chromium.org/160427 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@22157 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/gtk/browser_titlebar.cc158
-rw-r--r--chrome/browser/gtk/browser_titlebar.h32
-rw-r--r--chrome/browser/gtk/browser_window_gtk.cc12
3 files changed, 185 insertions, 17 deletions
diff --git a/chrome/browser/gtk/browser_titlebar.cc b/chrome/browser/gtk/browser_titlebar.cc
index 9e2124d..dd4ffa9 100644
--- a/chrome/browser/gtk/browser_titlebar.cc
+++ b/chrome/browser/gtk/browser_titlebar.cc
@@ -7,9 +7,10 @@
#include <gtk/gtk.h>
#include <string>
+#include <vector>
-#include "app/resource_bundle.h"
#include "app/l10n_util.h"
+#include "app/resource_bundle.h"
#include "base/gfx/gtk_util.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/browser.h"
@@ -23,6 +24,7 @@
#include "grit/app_resources.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
+#include "skia/ext/image_operations.h"
namespace {
@@ -49,6 +51,14 @@ const int kOTRSideSpacing = 2;
// titlebar is showing.
const int kFrameBorderThickness = 4;
+// There is a 4px gap between the icon and the title text.
+const int kIconTitleSpacing = 4;
+
+// Padding around the icon when in app mode or popup mode.
+const int kAppModePaddingTop = 5;
+const int kAppModePaddingBottom = 4;
+const int kAppModePaddingLeft = 2;
+
// The left padding of the tab strip. In Views, the tab strip has a left
// margin of FrameBorderThickness + kClientEdgeThickness. This offset is to
// account for kClientEdgeThickness.
@@ -75,6 +85,8 @@ GdkPixbuf* GetOTRAvatar() {
BrowserTitlebar::BrowserTitlebar(BrowserWindowGtk* browser_window,
GtkWindow* window)
: browser_window_(browser_window), window_(window),
+ app_mode_favicon_(NULL),
+ app_mode_title_(NULL),
using_custom_frame_(false) {
Init();
}
@@ -92,6 +104,17 @@ void BrowserTitlebar::Init() {
// ||+-------+||+------------------------+||+------------------------------+||
// |+---------++--------------------------++--------------------------------+|
// +-------------------------------------------------------------------------+
+ //
+ // If we're a popup window or in app mode, we don't display the spy guy or
+ // the tab strip. Instead, put an hbox in titlebar_alignment_ in place of
+ // the tab strip.
+ // +- Alignment (titlebar_alignment_) ----------------------------+
+ // |+ HBox ------------------------------------------------------+|
+ // ||+- Image (app_mode_favicon_) -++- Label (app_mode_title_) -+||
+ // ||| favicon || page title |||
+ // ||+-----------------------------++---------------------------+||
+ // |+------------------------------------------------------------+|
+ // +--------------------------------------------------------------+
GtkWidget* container_hbox = gtk_hbox_new(FALSE, 0);
container_ = gtk_event_box_new();
@@ -104,7 +127,8 @@ void BrowserTitlebar::Init() {
g_signal_connect(window_, "window-state-event",
G_CALLBACK(OnWindowStateChanged), this);
- if (browser_window_->browser()->profile()->IsOffTheRecord()) {
+ if (browser_window_->browser()->profile()->IsOffTheRecord() &&
+ browser_window_->browser()->type() == Browser::TYPE_NORMAL) {
GtkWidget* spy_guy = gtk_image_new_from_pixbuf(GetOTRAvatar());
gtk_misc_set_alignment(GTK_MISC(spy_guy), 0.0, 1.0);
GtkWidget* spy_frame = gtk_alignment_new(0.0, 0.0, 1.0, 1.0);
@@ -119,12 +143,36 @@ void BrowserTitlebar::Init() {
// We use an alignment to control the titlebar height.
titlebar_alignment_ = gtk_alignment_new(0.0, 0.0, 1.0, 1.0);
- gtk_box_pack_start(GTK_BOX(container_hbox), titlebar_alignment_, TRUE,
- TRUE, 0);
+ if (browser_window_->browser()->type() == Browser::TYPE_NORMAL) {
+ gtk_box_pack_start(GTK_BOX(container_hbox), titlebar_alignment_, TRUE,
+ TRUE, 0);
- // Put the tab strip in the titlebar.
- gtk_container_add(GTK_CONTAINER(titlebar_alignment_),
- browser_window_->tabstrip()->widget());
+ // Put the tab strip in the titlebar.
+ gtk_container_add(GTK_CONTAINER(titlebar_alignment_),
+ browser_window_->tabstrip()->widget());
+ } else {
+ // App mode specific widgets.
+ gtk_box_pack_start(GTK_BOX(container_hbox), titlebar_alignment_, TRUE,
+ TRUE, 0);
+ GtkWidget* app_mode_hbox = gtk_hbox_new(FALSE, kIconTitleSpacing);
+ gtk_container_add(GTK_CONTAINER(titlebar_alignment_), app_mode_hbox);
+
+ // We use the app logo as a placeholder image so the title doesn't jump
+ // around.
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ // TODO(tc): Add a left click menu to this icon.
+ app_mode_favicon_ = gtk_image_new_from_pixbuf(
+ rb.GetRTLEnabledPixbufNamed(IDR_PRODUCT_LOGO_16));
+ gtk_box_pack_start(GTK_BOX(app_mode_hbox), app_mode_favicon_, FALSE,
+ FALSE, 0);
+
+ app_mode_title_ = gtk_label_new(NULL);
+ gtk_label_set_ellipsize(GTK_LABEL(app_mode_title_), PANGO_ELLIPSIZE_END);
+ gtk_misc_set_alignment(GTK_MISC(app_mode_title_), 0.0, 0.5);
+ gtk_box_pack_start(GTK_BOX(app_mode_hbox), app_mode_title_, TRUE, TRUE,
+ 0);
+ UpdateTitle();
+ }
// We put the min/max/restore/close buttons in a vbox so they are top aligned
// and don't vertically stretch.
@@ -180,13 +228,61 @@ void BrowserTitlebar::UpdateCustomFrame(bool use_custom_frame) {
UpdateTitlebarAlignment();
}
+void BrowserTitlebar::UpdateTitle() {
+ if (!app_mode_title_)
+ return;
+
+ // Get the page title and elide it to the available space.
+ string16 title = browser_window_->browser()->GetWindowTitleForCurrentTab();
+
+ // TODO(tc): Seems like this color should be themable, but it's hardcoded to
+ // white on Windows. http://crbug.com/18093
+ gchar* label_markup = g_markup_printf_escaped("<span color='white'>%s</span>",
+ UTF16ToUTF8(title).c_str());
+ gtk_label_set_markup(GTK_LABEL(app_mode_title_), label_markup);
+ g_free(label_markup);
+}
+
+void BrowserTitlebar::UpdateThrobber(bool is_loading) {
+ DCHECK(app_mode_favicon_);
+
+ if (is_loading) {
+ GdkPixbuf* icon_pixbuf = throbber_.GetNextFrame();
+ gtk_image_set_from_pixbuf(GTK_IMAGE(app_mode_favicon_), icon_pixbuf);
+ } else {
+ if (browser_window_->browser()->type() == Browser::TYPE_APP) {
+ SkBitmap icon = browser_window_->browser()->GetCurrentPageIcon();
+ if (!icon.empty()) {
+ GdkPixbuf* icon_pixbuf = gfx::GdkPixbufFromSkBitmap(&icon);
+ gtk_image_set_from_pixbuf(GTK_IMAGE(app_mode_favicon_), icon_pixbuf);
+ g_object_unref(icon_pixbuf);
+ }
+ } else {
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ gtk_image_set_from_pixbuf(GTK_IMAGE(app_mode_favicon_),
+ rb.GetPixbufNamed(IDR_PRODUCT_LOGO_16));
+ }
+ throbber_.Reset();
+ }
+}
+
void BrowserTitlebar::UpdateTitlebarAlignment() {
- if (using_custom_frame_ && !browser_window_->IsMaximized()) {
- gtk_alignment_set_padding(GTK_ALIGNMENT(titlebar_alignment_),
- kTitlebarHeight, 0, kTabStripLeftPadding, 0);
+ if (browser_window_->browser()->type() == Browser::TYPE_NORMAL) {
+ if (using_custom_frame_ && !browser_window_->IsMaximized()) {
+ gtk_alignment_set_padding(GTK_ALIGNMENT(titlebar_alignment_),
+ kTitlebarHeight, 0, kTabStripLeftPadding, 0);
+ } else {
+ gtk_alignment_set_padding(GTK_ALIGNMENT(titlebar_alignment_), 0, 0,
+ kTabStripLeftPadding, 0);
+ }
} else {
- gtk_alignment_set_padding(GTK_ALIGNMENT(titlebar_alignment_), 0, 0,
- kTabStripLeftPadding, 0);
+ if (using_custom_frame_ && !browser_window_->IsFullscreen()) {
+ gtk_alignment_set_padding(GTK_ALIGNMENT(titlebar_alignment_),
+ kAppModePaddingTop, kAppModePaddingBottom, kAppModePaddingLeft, 0);
+ gtk_widget_show(titlebar_alignment_);
+ } else {
+ gtk_widget_hide(titlebar_alignment_);
+ }
}
int close_button_width = close_button_default_width_;
@@ -310,3 +406,41 @@ void BrowserTitlebar::ExecuteCommand(int command_id) {
NOTREACHED();
}
}
+
+///////////////////////////////////////////////////////////////////////////////
+// BrowserTitlebar::Throbber implementation
+// TODO(tc): Handle anti-clockwise spinning when waiting for a connection.
+
+// We don't bother to clean this or the pixbufs it contains when we exit.
+static std::vector<GdkPixbuf*>* g_throbber_frames = NULL;
+
+GdkPixbuf* BrowserTitlebar::Throbber::GetNextFrame() {
+ Throbber::InitFrames();
+ return (*g_throbber_frames)[current_frame_++ % g_throbber_frames->size()];
+}
+
+void BrowserTitlebar::Throbber::Reset() {
+ current_frame_ = 0;
+}
+
+// static
+void BrowserTitlebar::Throbber::InitFrames() {
+ if (g_throbber_frames)
+ return;
+
+ ResourceBundle &rb = ResourceBundle::GetSharedInstance();
+ SkBitmap* frame_strip = rb.GetBitmapNamed(IDR_THROBBER_LIGHT);
+
+ // Each frame of the animation is a square, so we use the height as the
+ // frame size.
+ int frame_size = frame_strip->height();
+ size_t num_frames = frame_strip->width() / frame_size;
+ g_throbber_frames = new std::vector<GdkPixbuf*>;
+
+ // Make a separate GdkPixbuf for each frame of the animation.
+ for (size_t i = 0; i < num_frames; ++i) {
+ SkBitmap frame = skia::ImageOperations::CreateTiledBitmap(*frame_strip,
+ i * frame_size, 0, frame_size, frame_size);
+ g_throbber_frames->push_back(gfx::GdkPixbufFromSkBitmap(&frame));
+ }
+}
diff --git a/chrome/browser/gtk/browser_titlebar.h b/chrome/browser/gtk/browser_titlebar.h
index 4eadcaf..88e17af 100644
--- a/chrome/browser/gtk/browser_titlebar.h
+++ b/chrome/browser/gtk/browser_titlebar.h
@@ -33,12 +33,37 @@ class BrowserTitlebar : public MenuGtk::Delegate {
// tall titlebar and the min/max/close buttons.
void UpdateCustomFrame(bool use_custom_frame);
+ // Updates the title when in app or popup mode (no tabstrip).
+ void UpdateTitle();
+
+ // Called by the browser asking us to update the loading throbber.
+ void UpdateThrobber(bool is_loading);
+
// On Windows, right clicking in the titlebar background brings up the system
// menu. There's no such thing on linux, so we just show the menu items we
// add to the menu.
void ShowContextMenu();
private:
+ // A helper class to keep track of which frame of the throbber animation
+ // we're showing.
+ class Throbber {
+ public:
+ Throbber() : current_frame_(0) {}
+
+ // Get the next frame in the animation. The image is owned by the throbber
+ // so the caller doesn't need to unref.
+ GdkPixbuf* GetNextFrame();
+
+ // Reset back to the first frame.
+ void Reset();
+ private:
+ // Make sure the frames are loaded.
+ static void InitFrames();
+
+ int current_frame_;
+ };
+
// Build the titlebar, the space above the tab
// strip, and (maybe) the min, max, close buttons. |container| is the gtk
// continer that we put the widget into.
@@ -86,6 +111,10 @@ class BrowserTitlebar : public MenuGtk::Delegate {
// manager decorations, we draw this taller.
GtkWidget* titlebar_alignment_;
+ // The favicon and page title used when in app mode or popup mode.
+ GtkWidget* app_mode_favicon_;
+ GtkWidget* app_mode_title_;
+
// Whether we are using a custom frame.
bool using_custom_frame_;
@@ -103,6 +132,9 @@ class BrowserTitlebar : public MenuGtk::Delegate {
// The context menu.
scoped_ptr<MenuGtk> context_menu_;
+
+ // The throbber used when the window is in app mode or popup window mode.
+ Throbber throbber_;
};
#endif // CHROME_BROWSER_GTK_BROWSER_TITLEBAR_H_
diff --git a/chrome/browser/gtk/browser_window_gtk.cc b/chrome/browser/gtk/browser_window_gtk.cc
index ff0373c..f0aedb2 100644
--- a/chrome/browser/gtk/browser_window_gtk.cc
+++ b/chrome/browser/gtk/browser_window_gtk.cc
@@ -712,9 +712,8 @@ void BrowserWindowGtk::UpdateTitleBar() {
string16 title = browser_->GetWindowTitleForCurrentTab();
gtk_window_set_title(window_, UTF16ToUTF8(title).c_str());
- if (ShouldShowWindowIcon()) {
- // TODO(tc): If we're showing a title bar, we should update the app icon.
- }
+ if (ShouldShowWindowIcon())
+ titlebar_->UpdateTitle();
}
void BrowserWindowGtk::UpdateDevTools() {
@@ -753,8 +752,11 @@ void BrowserWindowGtk::LoadingAnimationCallback() {
tabstrip_->UpdateLoadingAnimations();
} else if (ShouldShowWindowIcon()) {
// ... or in the window icon area for popups and app windows.
- // http://code.google.com/p/chromium/issues/detail?id=9380
- // TODO(willchan): implement this.
+ TabContents* tab_contents = browser_->GetSelectedTabContents();
+ // GetSelectedTabContents can return NULL for example under Purify when
+ // the animations are running slowly and this function is called on
+ // a timer through LoadingAnimationCallback.
+ titlebar_->UpdateThrobber(tab_contents && tab_contents->is_loading());
}
}