diff options
author | jianli@chromium.org <jianli@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-05 22:27:26 +0000 |
---|---|---|
committer | jianli@chromium.org <jianli@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-05 22:27:26 +0000 |
commit | fcbbd1fdf87fee30fca225b5bfb2ae7d52227058 (patch) | |
tree | 29f70359c1a5b1474c758f31b82567ca9936c57c | |
parent | aaa70a4e4256fc2c96ce550b773ff00e5cd99e30 (diff) | |
download | chromium_src-fcbbd1fdf87fee30fca225b5bfb2ae7d52227058.zip chromium_src-fcbbd1fdf87fee30fca225b5bfb2ae7d52227058.tar.gz chromium_src-fcbbd1fdf87fee30fca225b5bfb2ae7d52227058.tar.bz2 |
Change the visual appearance of panel on GTK per new UI design.
In order not to add more panel specific stuff to BrowserTitlebar, I decided to
put all titlebar painting and handling logic in PanelBrowserTitlebarGtk. This
is also needed for the ongoing effort to strip out the BrowserWindow dependency
from panel implementation.
I also moved throbber logic out of BrowserTitlebar into a separate class so that
the code can be shared between BrowserTitlebar and PanelBrowserTitlebarGtk.
BUG=none
TEST=existing tests
Review URL: https://chromiumcodereview.appspot.com/10483010
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@140636 0039d316-1c4b-4281-b951-d872f2087c98
18 files changed, 748 insertions, 484 deletions
diff --git a/chrome/browser/ui/gtk/browser_titlebar.cc b/chrome/browser/ui/gtk/browser_titlebar.cc index 06596f1..cea3903 100644 --- a/chrome/browser/ui/gtk/browser_titlebar.cc +++ b/chrome/browser/ui/gtk/browser_titlebar.cc @@ -56,7 +56,6 @@ #include "ui/base/x/active_window_watcher_x.h" #include "ui/gfx/gtk_util.h" #include "ui/gfx/image/image.h" -#include "ui/gfx/skbitmap_operations.h" using content::WebContents; @@ -477,10 +476,10 @@ GtkWidget* BrowserTitlebar::GetButtonHBox(bool left_side) { titlebar_right_buttons_vbox_; GtkWidget* top_padding = gtk_fixed_new(); - gtk_widget_set_size_request(top_padding, -1, GetButtonOuterPadding()); + gtk_widget_set_size_request(top_padding, -1, kButtonOuterPadding); gtk_box_pack_start(GTK_BOX(vbox), top_padding, FALSE, FALSE, 0); - GtkWidget* buttons_hbox = gtk_hbox_new(FALSE, GetButtonSpacing()); + GtkWidget* buttons_hbox = gtk_hbox_new(FALSE, kButtonSpacing); gtk_box_pack_start(GTK_BOX(vbox), buttons_hbox, FALSE, FALSE, 0); if (left_side) { @@ -494,14 +493,6 @@ GtkWidget* BrowserTitlebar::GetButtonHBox(bool left_side) { return buttons_hbox; } -int BrowserTitlebar::GetButtonOuterPadding() const { - return kButtonOuterPadding; -} - -int BrowserTitlebar::GetButtonSpacing() const { - return kButtonSpacing; -} - CustomDrawButton* BrowserTitlebar::CreateTitlebarButton( const std::string& button_name, bool left_side) { int normal_image_id; @@ -707,10 +698,10 @@ void BrowserTitlebar::UpdateTitlebarAlignment() { GtkRequisition minimize_button_req = minimize_button_req_; GtkRequisition restore_button_req = restore_button_req_; if (using_custom_frame_ && browser_window_->IsMaximized()) { - close_button_req.width += GetButtonOuterPadding(); - close_button_req.height += GetButtonOuterPadding(); - minimize_button_req.height += GetButtonOuterPadding(); - restore_button_req.height += GetButtonOuterPadding(); + close_button_req.width += kButtonOuterPadding; + close_button_req.height += kButtonOuterPadding; + minimize_button_req.height += kButtonOuterPadding; + restore_button_req.height += kButtonOuterPadding; if (top_padding_left_) gtk_widget_hide(top_padding_left_); if (top_padding_right_) @@ -837,17 +828,6 @@ void BrowserTitlebar::UpdateAvatar() { avatar_button_->set_menu_arrow_location(arrow_location); } -void BrowserTitlebar::ShowFaviconMenu(GdkEventButton* event) { - if (!favicon_menu_model_.get()) { - favicon_menu_model_.reset( - new PopupPageMenuModel(this, browser_window_->browser())); - - favicon_menu_.reset(new MenuGtk(NULL, favicon_menu_model_.get())); - } - - favicon_menu_->PopupForWidget(app_mode_favicon_, event->button, event->time); -} - void BrowserTitlebar::MaximizeButtonClicked() { GdkEvent* event = gtk_get_current_event(); if (event->button.button == 1) { @@ -915,10 +895,6 @@ gboolean BrowserTitlebar::OnScroll(GtkWidget* widget, GdkEventScroll* event) { } void BrowserTitlebar::OnButtonClicked(GtkWidget* button) { - HandleButtonClick(button); -} - -void BrowserTitlebar::HandleButtonClick(GtkWidget* button) { if (close_button_.get() && close_button_->widget() == button) { browser_window_->Close(); } else if (restore_button_.get() && restore_button_->widget() == button) { @@ -935,7 +911,15 @@ gboolean BrowserTitlebar::OnFaviconMenuButtonPressed(GtkWidget* widget, if (event->button != 1) return FALSE; - ShowFaviconMenu(event); + if (!favicon_menu_model_.get()) { + favicon_menu_model_.reset( + new PopupPageMenuModel(this, browser_window_->browser())); + + favicon_menu_.reset(new MenuGtk(NULL, favicon_menu_model_.get())); + } + + favicon_menu_->PopupForWidget(app_mode_favicon_, event->button, event->time); + return TRUE; } @@ -1053,60 +1037,16 @@ bool BrowserTitlebar::IsOffTheRecord() { return browser_window_->browser()->profile()->IsOffTheRecord(); } -/////////////////////////////////////////////////////////////////////////////// -// BrowserTitlebar::Throbber implementation -// TODO(tc): Handle anti-clockwise spinning when waiting for a connection. - -// We don't bother to clean up these or the pixbufs they contain when we exit. -static std::vector<GdkPixbuf*>* g_throbber_frames = NULL; -static std::vector<GdkPixbuf*>* g_throbber_waiting_frames = NULL; - -// Load |resource_id| from the ResourceBundle and split it into a series of -// square GdkPixbufs that get stored in |frames|. -static void MakeThrobberFrames(int resource_id, - std::vector<GdkPixbuf*>* frames) { - ui::ResourceBundle &rb = ui::ResourceBundle::GetSharedInstance(); - SkBitmap* frame_strip = rb.GetBitmapNamed(resource_id); - - // 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; - - // Make a separate GdkPixbuf for each frame of the animation. - for (size_t i = 0; i < num_frames; ++i) { - SkBitmap frame = SkBitmapOperations::CreateTiledBitmap(*frame_strip, - i * frame_size, 0, frame_size, frame_size); - frames->push_back(gfx::GdkPixbufFromSkBitmap(frame)); - } +GtkWidget* BrowserTitlebar::widget() const { + return container_; } -GdkPixbuf* BrowserTitlebar::Throbber::GetNextFrame(bool is_waiting) { - Throbber::InitFrames(); - if (is_waiting) { - return (*g_throbber_waiting_frames)[current_waiting_frame_++ % - g_throbber_waiting_frames->size()]; - } else { - return (*g_throbber_frames)[current_frame_++ % g_throbber_frames->size()]; - } -} - -void BrowserTitlebar::Throbber::Reset() { - current_frame_ = 0; - current_waiting_frame_ = 0; +void BrowserTitlebar::set_window(GtkWindow* window) { + window_ = window; } -// static -void BrowserTitlebar::Throbber::InitFrames() { - if (g_throbber_frames) - return; - - // We load the light version of the throbber since it'll be in the titlebar. - g_throbber_frames = new std::vector<GdkPixbuf*>; - MakeThrobberFrames(IDR_THROBBER_LIGHT, g_throbber_frames); - - g_throbber_waiting_frames = new std::vector<GdkPixbuf*>; - MakeThrobberFrames(IDR_THROBBER_WAITING_LIGHT, g_throbber_waiting_frames); +AvatarMenuButtonGtk* BrowserTitlebar::avatar_button() const { + return avatar_button_.get(); } BrowserTitlebar::ContextMenuModel::ContextMenuModel( diff --git a/chrome/browser/ui/gtk/browser_titlebar.h b/chrome/browser/ui/gtk/browser_titlebar.h index 0ed05f0..2ffeb88 100644 --- a/chrome/browser/ui/gtk/browser_titlebar.h +++ b/chrome/browser/ui/gtk/browser_titlebar.h @@ -16,6 +16,8 @@ #include "base/compiler_specific.h" #include "base/memory/scoped_ptr.h" #include "chrome/browser/prefs/pref_member.h" +#include "chrome/browser/ui/gtk/browser_titlebar_base.h" +#include "chrome/browser/ui/gtk/titlebar_throb_animation.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" #include "ui/base/gtk/gtk_signal.h" @@ -33,7 +35,8 @@ namespace content { class WebContents; } -class BrowserTitlebar : public content::NotificationObserver, +class BrowserTitlebar : public BrowserTitlebarBase, + public content::NotificationObserver, public ui::ActiveWindowWatcherXObserver, public ui::SimpleMenuModel::Delegate { public: @@ -44,71 +47,36 @@ class BrowserTitlebar : public content::NotificationObserver, BrowserTitlebar(BrowserWindowGtk* browser_window, GtkWindow* window); virtual ~BrowserTitlebar(); - // Updates the theme supplied background color and image. - virtual void UpdateButtonBackground(CustomDrawButton* button); - - // Updates the title and icon when in app or popup/panel mode (no tabstrip). - virtual void UpdateTitleAndIcon(); - - GtkWidget* widget() { - return container_; - } - - void set_window(GtkWindow* window) { window_ = window; } - - // Build the titlebar, the space above the tab strip, and (maybe) the min, - // max, close buttons. |container_| is the gtk container that we put the - // widget into. - void Init(); - // Builds the buttons based on the metacity |button_string|. void BuildButtons(const std::string& button_string); - // Update the appearance of the title bar based on whether we're showing a - // custom frame or not. If |use_custom_frame| is true, we show an extra - // tall titlebar and the min/max/close buttons. - void UpdateCustomFrame(bool use_custom_frame); - - // Called by the browser asking us to update the loading throbber. - // |web_contents| is the tab that is associated with the window throbber. - // |web_contents| can be null. - void UpdateThrobber(content::WebContents* web_contents); + // Overriden from BrowserTitlebarBase. + virtual void Init() OVERRIDE; + virtual void UpdateTitleAndIcon() OVERRIDE; + virtual void UpdateCustomFrame(bool use_custom_frame) OVERRIDE; + virtual void UpdateThrobber(content::WebContents* web_contents) OVERRIDE; + virtual void ShowContextMenu(GdkEventButton* event) OVERRIDE; + virtual GtkWidget* widget() const OVERRIDE; + virtual void set_window(GtkWindow* window) OVERRIDE; + virtual AvatarMenuButtonGtk* avatar_button() const OVERRIDE; - // 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(GdkEventButton* event); - - AvatarMenuButtonGtk* avatar_button() { return avatar_button_.get(); } + private: + class ContextMenuModel : public ui::SimpleMenuModel { + public: + explicit ContextMenuModel(ui::SimpleMenuModel::Delegate* delegate); + }; - protected: // Builds the button as denoted by |button_token|. Returns true if the button // is created successfully. - virtual bool BuildButton(const std::string& button_token, bool left_side); + bool BuildButton(const std::string& button_token, bool left_side); // Retrieves the 3 image ids (IDR_) and a tooltip id (IDS) for the purpose of // painting a CustomDraw button. - virtual void GetButtonResources(const std::string& button_name, - int* normal_image_id, - int* pressed_image_id, - int* hover_image_id, - int* tooltip_id) const; - - // Returns the spacing around outside of titlebar buttons. - virtual int GetButtonOuterPadding() const; - - // Returns the spacing between buttons of the titlebar. - virtual int GetButtonSpacing() const; - - // Called when a button is clicked. - virtual void HandleButtonClick(GtkWidget* button); - - // Show the menu that the user gets from left-clicking the favicon. - virtual void ShowFaviconMenu(GdkEventButton* event); - - // Updates the color of the title bar. Called whenever we have a state - // change in the window. - virtual void UpdateTextColor(); + void GetButtonResources(const std::string& button_name, + int* normal_image_id, + int* pressed_image_id, + int* hover_image_id, + int* tooltip_id) const; // Constructs a CustomDraw button given button name and left or right side of // the titlebar where the button is placed. @@ -121,40 +89,12 @@ class BrowserTitlebar : public content::NotificationObserver, // settings to get absolutely horrid combinations of buttons on both sides. GtkWidget* GetButtonHBox(bool left_side); - CustomDrawButton* minimize_button() const { return minimize_button_.get(); } - CustomDrawButton* maximize_button() const { return maximize_button_.get(); } - CustomDrawButton* restore_button() const { return restore_button_.get(); } - CustomDrawButton* close_button() const { return close_button_.get(); } - GtkWidget* app_mode_title() const { return app_mode_title_; } - - GtkThemeService* theme_service() const { return theme_service_; } - - private: - // A helper class to keep track of which frame of the throbber animation - // we're showing. - class Throbber { - public: - Throbber() : current_frame_(0), current_waiting_frame_(0) {} - - // Get the next frame in the animation. The image is owned by the throbber - // so the caller doesn't need to unref. |is_waiting| is true if we're - // still waiting for a response. - GdkPixbuf* GetNextFrame(bool is_waiting); - - // Reset back to the first frame. - void Reset(); - private: - // Make sure the frames are loaded. - static void InitFrames(); - - int current_frame_; - int current_waiting_frame_; - }; + // Updates the theme supplied background color and image. + void UpdateButtonBackground(CustomDrawButton* button); - class ContextMenuModel : public ui::SimpleMenuModel { - public: - explicit ContextMenuModel(ui::SimpleMenuModel::Delegate* delegate); - }; + // Updates the color of the title bar. Called whenever we have a state + // change in the window. + void UpdateTextColor(); // Update the titlebar spacing based on the custom frame and maximized state. void UpdateTitlebarAlignment(); @@ -287,7 +227,7 @@ class BrowserTitlebar : public content::NotificationObserver, scoped_ptr<PopupPageMenuModel> favicon_menu_model_; // The throbber used when the window is in app mode or popup window mode. - Throbber throbber_; + TitlebarThrobAnimation throbber_; // The avatar button. scoped_ptr<AvatarMenuButtonGtk> avatar_button_; diff --git a/chrome/browser/ui/gtk/browser_titlebar_base.h b/chrome/browser/ui/gtk/browser_titlebar_base.h new file mode 100644 index 0000000..f8c8843 --- /dev/null +++ b/chrome/browser/ui/gtk/browser_titlebar_base.h @@ -0,0 +1,50 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_GTK_BROWSER_TITLEBAR_BASE_H_ +#define CHROME_BROWSER_UI_GTK_BROWSER_TITLEBAR_BASE_H_ +#pragma once + +#include <gtk/gtk.h> + +#include "base/compiler_specific.h" + +class AvatarMenuButtonGtk; + +namespace content { +class WebContents; +} + +class BrowserTitlebarBase { + public: + virtual ~BrowserTitlebarBase() { } + + // Build the titlebar, the space above the tab strip, and (maybe) the min, + // max, close buttons. + virtual void Init() = 0; + + // Updates the title and icon when in app or popup/panel mode (no tabstrip). + virtual void UpdateTitleAndIcon() = 0; + + // Update the appearance of the title bar based on whether we're showing a + // custom frame or not. If |use_custom_frame| is true, we show an extra + // tall titlebar and the min/max/close buttons. + virtual void UpdateCustomFrame(bool use_custom_frame) = 0; + + // Called by the browser asking us to update the loading throbber. + // |web_contents| is the tab that is associated with the window throbber. + // |web_contents| can be null. + virtual void UpdateThrobber(content::WebContents* web_contents) = 0; + + // 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. + virtual void ShowContextMenu(GdkEventButton* event) = 0; + + virtual GtkWidget* widget() const = 0; + virtual void set_window(GtkWindow* window) = 0; + virtual AvatarMenuButtonGtk* avatar_button() const = 0; +}; + +#endif // CHROME_BROWSER_UI_GTK_BROWSER_TITLEBAR_BASE_H_ diff --git a/chrome/browser/ui/gtk/browser_window_gtk.cc b/chrome/browser/ui/gtk/browser_window_gtk.cc index 76e5af1..3a1c75f 100644 --- a/chrome/browser/ui/gtk/browser_window_gtk.cc +++ b/chrome/browser/ui/gtk/browser_window_gtk.cc @@ -437,7 +437,11 @@ void BrowserWindowGtk::Init() { gboolean BrowserWindowGtk::OnCustomFrameExpose(GtkWidget* widget, GdkEventExpose* event) { TRACE_EVENT0("ui::gtk", "BrowserWindowGtk::OnCustomFrameExpose"); + DrawFrame(widget, event); + return FALSE; // Allow subwidgets to paint. +} +void BrowserWindowGtk::DrawFrame(GtkWidget* widget, GdkEventExpose* event) { // Draw the default background. cairo_t* cr = gdk_cairo_create(gtk_widget_get_window(widget)); gdk_cairo_rectangle(cr, &event->area); @@ -455,8 +459,6 @@ gboolean BrowserWindowGtk::OnCustomFrameExpose(GtkWidget* widget, if (UseCustomFrame() && !IsMaximized()) DrawCustomFrameBorder(widget); - - return FALSE; // Allow subwidgets to paint. } void BrowserWindowGtk::DrawCustomFrameBorder(GtkWidget* widget) { @@ -2476,7 +2478,7 @@ bool BrowserWindowGtk::UsingCustomPopupFrame() const { return !theme_provider->UsingNativeTheme() && browser()->is_type_popup(); } -BrowserTitlebar* BrowserWindowGtk::CreateBrowserTitlebar() { +BrowserTitlebarBase* BrowserWindowGtk::CreateBrowserTitlebar() { return new BrowserTitlebar(this, window_); } diff --git a/chrome/browser/ui/gtk/browser_window_gtk.h b/chrome/browser/ui/gtk/browser_window_gtk.h index 7a89a51..b16b4a7 100644 --- a/chrome/browser/ui/gtk/browser_window_gtk.h +++ b/chrome/browser/ui/gtk/browser_window_gtk.h @@ -27,7 +27,7 @@ class BookmarkBarGtk; class Browser; -class BrowserTitlebar; +class BrowserTitlebarBase; class BrowserToolbarGtk; class DownloadShelfGtk; class ExtensionKeybindingRegistryGtk; @@ -61,11 +61,6 @@ class BrowserWindowGtk : public BrowserWindow, // functions during initialization. virtual void Init(); - // Returns whether to draw the content drop shadow on the sides and bottom - // of the browser window. When false, we still draw a shadow on the top of - // the toolbar (under the tab strip), but do not round the top corners. - virtual bool ShouldDrawContentDropShadow() const; - // Overridden from BrowserWindow: virtual void Show() OVERRIDE; virtual void ShowInactive() OVERRIDE; @@ -217,6 +212,11 @@ class BrowserWindowGtk : public BrowserWindow, // onbeforeunload handler that prevents us from closing. bool CanClose() const; + // Returns whether to draw the content drop shadow on the sides and bottom + // of the browser window. When false, we still draw a shadow on the top of + // the toolbar (under the tab strip), but do not round the top corners. + bool ShouldDrawContentDropShadow() const; + bool ShouldShowWindowIcon() const; // Add the find bar widget to the window hierarchy. @@ -238,7 +238,7 @@ class BrowserWindowGtk : public BrowserWindow, GtkWindow* window() const { return window_; } - BrowserTitlebar* titlebar() const { return titlebar_.get(); } + BrowserTitlebarBase* titlebar() const { return titlebar_.get(); } GtkWidget* titlebar_widget() const; @@ -263,8 +263,8 @@ class BrowserWindowGtk : public BrowserWindow, protected: virtual void DestroyBrowser() OVERRIDE; - // Returns an instance of |BrowserTitlebar| to be used for this window. - virtual BrowserTitlebar* CreateBrowserTitlebar(); + // Returns an instance of |BrowserTitlebarBase| to be used for this window. + virtual BrowserTitlebarBase* CreateBrowserTitlebar(); // Checks to see if the mouse pointer at |x|, |y| is over the border of the // custom frame (a spot that should trigger a window resize). Returns true if @@ -276,8 +276,8 @@ class BrowserWindowGtk : public BrowserWindow, // returned. virtual GdkRegion* GetWindowShape(int width, int height) const; - // Draws the border, including resizable corners, for the custom frame. - virtual void DrawCustomFrameBorder(GtkWidget* widget); + // Draws the frame, including background, border and drop shadow. + virtual void DrawFrame(GtkWidget* widget, GdkEventExpose* event); virtual bool HandleTitleBarLeftMousePress(GdkEventButton* event, guint32 last_click_time, @@ -298,21 +298,9 @@ class BrowserWindowGtk : public BrowserWindow, // Returns |true| if we should use the custom frame. virtual bool UseCustomFrame() const; - // Whether we should draw the tab background instead of the theme_frame - // background because this window is a popup. - virtual bool UsingCustomPopupFrame() const; - // Called when the window size changed. virtual void OnSizeChanged(int width, int height); - // Draws the normal custom frame using theme_frame. - virtual void DrawCustomFrame(cairo_t* cr, GtkWidget* widget, - GdkEventExpose* event); - - // Draws the tab image as the frame so we can write legible text. - virtual void DrawPopupFrame(cairo_t* cr, GtkWidget* widget, - GdkEventExpose* event); - // 'focus-in-event' handler. virtual void HandleFocusIn(GtkWidget* widget, GdkEventFocus* event); @@ -362,6 +350,19 @@ class BrowserWindowGtk : public BrowserWindow, // ctrl-l, etc.). void ConnectAccelerators(); + // Whether we should draw the tab background instead of the theme_frame + // background because this window is a popup. + bool UsingCustomPopupFrame() const; + + // Draws the normal custom frame using theme_frame. + void DrawCustomFrame(cairo_t* cr, GtkWidget* widget, GdkEventExpose* event); + + // Draws the tab image as the frame so we can write legible text. + void DrawPopupFrame(cairo_t* cr, GtkWidget* widget, GdkEventExpose* event); + + // Draws the border, including resizable corners, for the custom frame. + void DrawCustomFrameBorder(GtkWidget* widget); + // Change whether we're showing the custom blue frame. // Must be called once at startup. // Triggers relayout of the content. @@ -488,7 +489,7 @@ class BrowserWindowGtk : public BrowserWindow, scoped_ptr<GlobalMenuBar> global_menu_bar_; // The container for the titlebar + tab strip. - scoped_ptr<BrowserTitlebar> titlebar_; + scoped_ptr<BrowserTitlebarBase> titlebar_; // The object that manages all of the widgets in the toolbar. scoped_ptr<BrowserToolbarGtk> toolbar_; diff --git a/chrome/browser/ui/gtk/titlebar_throb_animation.cc b/chrome/browser/ui/gtk/titlebar_throb_animation.cc new file mode 100644 index 0000000..4b90974 --- /dev/null +++ b/chrome/browser/ui/gtk/titlebar_throb_animation.cc @@ -0,0 +1,71 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/gtk/titlebar_throb_animation.h" +#include "grit/theme_resources.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/gfx/skbitmap_operations.h" + +namespace { + +// We don't bother to clean up these or the pixbufs they contain when we exit. +std::vector<GdkPixbuf*>* g_throbber_frames = NULL; +std::vector<GdkPixbuf*>* g_throbber_waiting_frames = NULL; + +// Load |resource_id| from the ResourceBundle and split it into a series of +// square GdkPixbufs that get stored in |frames|. +void MakeThrobberFrames(int resource_id, std::vector<GdkPixbuf*>* frames) { + ui::ResourceBundle &rb = ui::ResourceBundle::GetSharedInstance(); + SkBitmap* frame_strip = rb.GetBitmapNamed(resource_id); + + // 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; + + // Make a separate GdkPixbuf for each frame of the animation. + for (size_t i = 0; i < num_frames; ++i) { + SkBitmap frame = SkBitmapOperations::CreateTiledBitmap(*frame_strip, + i * frame_size, 0, frame_size, frame_size); + frames->push_back(gfx::GdkPixbufFromSkBitmap(frame)); + } +} + +} // namespace + +// TODO(tc): Handle anti-clockwise spinning when waiting for a connection. + +TitlebarThrobAnimation::TitlebarThrobAnimation() + : current_frame_(0), + current_waiting_frame_(0) { +} + +GdkPixbuf* TitlebarThrobAnimation::GetNextFrame(bool is_waiting) { + InitFrames(); + if (is_waiting) { + return (*g_throbber_waiting_frames)[current_waiting_frame_++ % + g_throbber_waiting_frames->size()]; + } else { + return (*g_throbber_frames)[current_frame_++ % g_throbber_frames->size()]; + } +} + +void TitlebarThrobAnimation::Reset() { + current_frame_ = 0; + current_waiting_frame_ = 0; +} + +// static +void TitlebarThrobAnimation::InitFrames() { + if (g_throbber_frames) + return; + + // We load the light version of the throbber since it'll be in the titlebar. + g_throbber_frames = new std::vector<GdkPixbuf*>; + MakeThrobberFrames(IDR_THROBBER_LIGHT, g_throbber_frames); + + g_throbber_waiting_frames = new std::vector<GdkPixbuf*>; + MakeThrobberFrames(IDR_THROBBER_WAITING_LIGHT, g_throbber_waiting_frames); +} diff --git a/chrome/browser/ui/gtk/titlebar_throb_animation.h b/chrome/browser/ui/gtk/titlebar_throb_animation.h new file mode 100644 index 0000000..8540d02 --- /dev/null +++ b/chrome/browser/ui/gtk/titlebar_throb_animation.h @@ -0,0 +1,37 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_GTK_TITLEBAR_THROB_ANIMATION_H_ +#define CHROME_BROWSER_UI_GTK_TITLEBAR_THROB_ANIMATION_H_ +#pragma once + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "ui/gfx/gtk_util.h" + +// A helper class to keep track of which frame of the throbber animation +// we're showing. +class TitlebarThrobAnimation { + public: + TitlebarThrobAnimation(); + + // Get the next frame in the animation. The image is owned by the throbber + // so the caller doesn't need to unref. |is_waiting| is true if we're + // still waiting for a response. + GdkPixbuf* GetNextFrame(bool is_waiting); + + // Reset back to the first frame. + void Reset(); + + private: + // Make sure the frames are loaded. + static void InitFrames(); + + int current_frame_; + int current_waiting_frame_; + + DISALLOW_COPY_AND_ASSIGN(TitlebarThrobAnimation); +}; + +#endif // CHROME_BROWSER_UI_GTK_TITLEBAR_THROB_ANIMATION_H_ diff --git a/chrome/browser/ui/panels/detached_panel_browsertest.cc b/chrome/browser/ui/panels/detached_panel_browsertest.cc index e84d269..feec61f 100644 --- a/chrome/browser/ui/panels/detached_panel_browsertest.cc +++ b/chrome/browser/ui/panels/detached_panel_browsertest.cc @@ -25,11 +25,9 @@ IN_PROC_BROWSER_TEST_F(DetachedPanelBrowserTest, CheckDetachedPanelProperties) { EXPECT_FALSE(panel->always_on_top()); - EXPECT_TRUE(panel_testing->IsButtonVisible(NativePanelTesting::CLOSE_BUTTON)); - EXPECT_FALSE(panel_testing->IsButtonVisible( - NativePanelTesting::MINIMIZE_BUTTON)); - EXPECT_FALSE(panel_testing->IsButtonVisible( - NativePanelTesting::RESTORE_BUTTON)); + EXPECT_TRUE(panel_testing->IsButtonVisible(panel::CLOSE_BUTTON)); + EXPECT_FALSE(panel_testing->IsButtonVisible(panel::MINIMIZE_BUTTON)); + EXPECT_FALSE(panel_testing->IsButtonVisible(panel::RESTORE_BUTTON)); EXPECT_EQ(panel::RESIZABLE_ALL_SIDES, panel->CanResizeByMouse()); diff --git a/chrome/browser/ui/panels/native_panel.h b/chrome/browser/ui/panels/native_panel.h index 61d1ff9..527fbba 100644 --- a/chrome/browser/ui/panels/native_panel.h +++ b/chrome/browser/ui/panels/native_panel.h @@ -101,12 +101,6 @@ class NativePanel { // native panel used only by test automation. class NativePanelTesting { public: - enum TitlebarButtonType { - CLOSE_BUTTON, - MINIMIZE_BUTTON, - RESTORE_BUTTON - }; - static NativePanelTesting* Create(NativePanel* native_panel); virtual ~NativePanelTesting() {} @@ -136,7 +130,7 @@ class NativePanelTesting { virtual bool IsWindowSizeKnown() const = 0; virtual bool IsAnimatingBounds() const = 0; - virtual bool IsButtonVisible(TitlebarButtonType button_type) const = 0; + virtual bool IsButtonVisible(panel::TitlebarButtonType button_type) const = 0; }; #endif // CHROME_BROWSER_UI_PANELS_NATIVE_PANEL_H_ diff --git a/chrome/browser/ui/panels/panel_browser_titlebar_gtk.cc b/chrome/browser/ui/panels/panel_browser_titlebar_gtk.cc index 83b8e20..1962037 100644 --- a/chrome/browser/ui/panels/panel_browser_titlebar_gtk.cc +++ b/chrome/browser/ui/panels/panel_browser_titlebar_gtk.cc @@ -9,149 +9,270 @@ #include "chrome/browser/ui/gtk/custom_button.h" #include "chrome/browser/ui/gtk/gtk_theme_service.h" #include "chrome/browser/ui/gtk/gtk_util.h" +#include "chrome/browser/ui/gtk/gtk_theme_service.h" #include "chrome/browser/ui/panels/panel.h" #include "chrome/browser/ui/panels/panel_browser_window_gtk.h" +#include "chrome/common/chrome_notification_types.h" +#include "content/public/browser/notification_service.h" +#include "content/public/browser/web_contents.h" #include "grit/generated_resources.h" #include "grit/theme_resources.h" +#include "third_party/skia/include/core/SkBitmap.h" #include "ui/base/gtk/gtk_compat.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/resource/resource_bundle.h" #include "ui/gfx/skia_utils_gtk.h" namespace { -// Spacing between buttons of panel's titlebar. -const int kPanelButtonSpacing = 7; - -// Spacing around outside of panel's titlebar buttons. -const int kPanelButtonOuterPadding = 7; +// Padding around the titlebar. +const int kPanelTitlebarPaddingTop = 7; +const int kPanelTitlebarPaddingBottom = 7; +const int kPanelTitlebarPaddingLeft = 4; +const int kPanelTitlebarPaddingRight = 9; -// Markup for painting title as bold. -const char* const kTitleMarkupPrefix = "<span font_weight='bold'>"; -const char* const kTitleMarkupSuffix = "</span>"; +// Spacing between buttons of panel's titlebar. +const int kPanelButtonSpacing = 9; -// Colors used to draw title in attention mode. -const SkColor kAttentionTitleTextDefaultColor = SK_ColorWHITE; +// Spacing between the icon and the title text. +const int kPanelIconTitleSpacing = 9; -// Alpha value used in drawing inactive titlebar under non-default theme. -const U8CPU kInactiveAlphaBlending = 0x80; +// Color used to draw title text under default theme. +const SkColor kTitleTextDefaultColor = SkColorSetRGB(0xf9, 0xf9, 0xf9); -SkColor BlendSkColorWithAlpha(SkColor fg_color, SkColor bg_color, U8CPU alpha) { - if (alpha == 255) - return fg_color; - double fg_ratio = alpha / 255.0; - double bg_ratio = 1.0 - fg_ratio; - return SkColorSetRGB( - (SkColorGetR(fg_color) * fg_ratio + SkColorGetR(bg_color) * bg_ratio), - (SkColorGetG(fg_color) * fg_ratio + SkColorGetG(bg_color) * bg_ratio), - (SkColorGetB(fg_color) * fg_ratio + SkColorGetB(bg_color) * bg_ratio)); -} +// Markup used to paint the title with the desired font. +const char* const kTitleMarkupPrefix = "<span face='Arial' size='11264'>"; +const char* const kTitleMarkupSuffix = "</span>"; } // namespace PanelBrowserTitlebarGtk::PanelBrowserTitlebarGtk( PanelBrowserWindowGtk* browser_window, GtkWindow* window) - : BrowserTitlebar(browser_window, window), - browser_window_(browser_window) { + : browser_window_(browser_window), + window_(window), + container_(NULL), + titlebar_right_buttons_vbox_(NULL), + titlebar_right_buttons_hbox_(NULL), + icon_(NULL), + title_(NULL), + theme_service_(NULL) { } PanelBrowserTitlebarGtk::~PanelBrowserTitlebarGtk() { } +void PanelBrowserTitlebarGtk::Init() { + container_ = gtk_event_box_new(); + gtk_widget_set_name(container_, "chrome-panel-titlebar"); + gtk_event_box_set_visible_window(GTK_EVENT_BOX(container_), FALSE); + + // We use an alignment to control the titlebar paddings. + GtkWidget* container_alignment = gtk_alignment_new(0.0, 0.0, 1.0, 1.0); + gtk_container_add(GTK_CONTAINER(container_), container_alignment); + gtk_alignment_set_padding(GTK_ALIGNMENT(container_alignment), + kPanelTitlebarPaddingTop, + kPanelTitlebarPaddingBottom, + kPanelTitlebarPaddingLeft, + kPanelTitlebarPaddingRight); + + // Add a container box. + GtkWidget* container_hbox = gtk_hbox_new(FALSE, 0); + gtk_container_add(GTK_CONTAINER(container_alignment), container_hbox); + + g_signal_connect(window_, "window-state-event", + G_CALLBACK(OnWindowStateChangedThunk), this); + + // Add minimize/restore and close buttons. Panel buttons are always placed + // on the right part of the titlebar. + titlebar_right_buttons_vbox_ = gtk_vbox_new(FALSE, 0); + gtk_box_pack_end(GTK_BOX(container_hbox), titlebar_right_buttons_vbox_, + FALSE, FALSE, 0); + BuildButtons(); + + // Add hbox for holding icon and title. + GtkWidget* icon_title_hbox = gtk_hbox_new(FALSE, kPanelIconTitleSpacing); + gtk_box_pack_start(GTK_BOX(container_hbox), icon_title_hbox, TRUE, TRUE, 0); + + // Add icon. We use the app logo as a placeholder image so the title doesn't + // jump around. + ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); + icon_ = gtk_image_new_from_pixbuf(rb.GetNativeImageNamed( + IDR_PRODUCT_LOGO_16, ui::ResourceBundle::RTL_ENABLED).ToGdkPixbuf()); + g_object_set_data(G_OBJECT(icon_), "left-align-popup", + reinterpret_cast<void*>(true)); + gtk_box_pack_start(GTK_BOX(icon_title_hbox), icon_, FALSE, FALSE, 0); + + // Add title. + title_ = gtk_label_new(NULL); + gtk_label_set_ellipsize(GTK_LABEL(title_), PANGO_ELLIPSIZE_END); + gtk_misc_set_alignment(GTK_MISC(title_), 0.0, 0.5); + gtk_box_pack_start(GTK_BOX(icon_title_hbox), title_, TRUE, TRUE, 0); + + UpdateTitleAndIcon(); + + theme_service_ = GtkThemeService::GetFrom( + browser_window_->panel()->profile()); + registrar_.Add(this, chrome::NOTIFICATION_BROWSER_THEME_CHANGED, + content::Source<ThemeService>(theme_service_)); + theme_service_->InitThemesFor(this); + + gtk_widget_show_all(container_); +} + SkColor PanelBrowserTitlebarGtk::GetTextColor() const { - PanelBrowserWindowGtk::PaintState paint_state = - browser_window_->GetPaintState(); - if (paint_state == PanelBrowserWindowGtk::PAINT_FOR_ATTENTION) - return kAttentionTitleTextDefaultColor; + if (browser_window_->UsingDefaultTheme()) + return kTitleTextDefaultColor; + return theme_service_->GetColor(browser_window_->paint_state() == + PanelBrowserWindowGtk::PAINT_AS_ACTIVE ? + ThemeService::COLOR_TAB_TEXT : + ThemeService::COLOR_BACKGROUND_TAB_TEXT); +} - return paint_state == PanelBrowserWindowGtk::PAINT_AS_ACTIVE ? - theme_service()->GetColor(ThemeService::COLOR_TAB_TEXT) : - BlendSkColorWithAlpha( - theme_service()->GetColor(ThemeService::COLOR_BACKGROUND_TAB_TEXT), - theme_service()->GetColor(ThemeService::COLOR_TOOLBAR), - kInactiveAlphaBlending); +void PanelBrowserTitlebarGtk::BuildButtons() { + minimize_button_.reset(CreateButton(panel::MINIMIZE_BUTTON)); + restore_button_.reset(CreateButton(panel::RESTORE_BUTTON)); + close_button_.reset(CreateButton(panel::CLOSE_BUTTON)); + + // We control visibility of minimize and restore buttons. + gtk_widget_set_no_show_all(minimize_button_->widget(), TRUE); + gtk_widget_set_no_show_all(restore_button_->widget(), TRUE); + + // Now show the correct widgets in the two hierarchies. + UpdateMinimizeRestoreButtonVisibility(); } -void PanelBrowserTitlebarGtk::UpdateButtonBackground(CustomDrawButton* button) { - // Don't need to update background since we're using transparent background. +CustomDrawButton* PanelBrowserTitlebarGtk::CreateButton( + panel::TitlebarButtonType button_type) { + int normal_image_id; + int pressed_image_id; + int hover_image_id; + int tooltip_id; + GetButtonResources(button_type, &normal_image_id, &pressed_image_id, + &hover_image_id, &tooltip_id); + + CustomDrawButton* button = new CustomDrawButton(normal_image_id, + pressed_image_id, + hover_image_id, + 0); + gtk_widget_add_events(GTK_WIDGET(button->widget()), GDK_POINTER_MOTION_MASK); + g_signal_connect(button->widget(), "clicked", + G_CALLBACK(OnButtonClickedThunk), this); + + std::string localized_tooltip = l10n_util::GetStringUTF8(tooltip_id); + gtk_widget_set_tooltip_text(button->widget(), + localized_tooltip.c_str()); + + GtkWidget* box = GetButtonHBox(); + gtk_box_pack_start(GTK_BOX(box), button->widget(), FALSE, FALSE, 0); + return button; } -void PanelBrowserTitlebarGtk::UpdateTitleAndIcon() { - DCHECK(app_mode_title()); +void PanelBrowserTitlebarGtk::GetButtonResources( + panel::TitlebarButtonType button_type, + int* normal_image_id, + int* pressed_image_id, + int* hover_image_id, + int* tooltip_id) const { + switch (button_type) { + case panel::CLOSE_BUTTON: + *normal_image_id = IDR_PANEL_CLOSE; + *pressed_image_id = IDR_PANEL_CLOSE_C; + *hover_image_id = IDR_PANEL_CLOSE_H; + *tooltip_id = IDS_PANEL_CLOSE_TOOLTIP; + break; + case panel::MINIMIZE_BUTTON: + *normal_image_id = IDR_PANEL_MINIMIZE; + *pressed_image_id = IDR_PANEL_MINIMIZE_C; + *hover_image_id = IDR_PANEL_MINIMIZE_H; + *tooltip_id = IDS_PANEL_MINIMIZE_TOOLTIP; + break; + case panel::RESTORE_BUTTON: + *normal_image_id = IDR_PANEL_RESTORE; + *pressed_image_id = IDR_PANEL_RESTORE_C; + *hover_image_id = IDR_PANEL_RESTORE_H; + *tooltip_id = IDS_PANEL_RESTORE_TOOLTIP; + break; + } +} - std::string title = UTF16ToUTF8(browser_window_->panel()->GetWindowTitle()); +GtkWidget* PanelBrowserTitlebarGtk::GetButtonHBox() { + if (!titlebar_right_buttons_hbox_) { + // We put the minimize/restore/close buttons in a vbox so they are top + // aligned (up to padding) and don't vertically stretch. + titlebar_right_buttons_hbox_ = gtk_hbox_new(FALSE, kPanelButtonSpacing); + gtk_box_pack_start(GTK_BOX(titlebar_right_buttons_vbox_), + titlebar_right_buttons_hbox_, FALSE, FALSE, 0); + } - // Add the markup to show the title as bold. - gchar* escaped_title = g_markup_escape_text(title.c_str(), -1); - gchar* title_with_markup = g_strconcat(kTitleMarkupPrefix, - escaped_title, - kTitleMarkupSuffix, - NULL); - gtk_label_set_markup(GTK_LABEL(app_mode_title()), title_with_markup); - g_free(escaped_title); - g_free(title_with_markup); + return titlebar_right_buttons_hbox_; } -bool PanelBrowserTitlebarGtk::BuildButton(const std::string& button_token, - bool left_side) { - // Panel only shows close and minimize/restore buttons. - if (button_token != "close" && button_token != "minimize") - return false; - - if (!BrowserTitlebar::BuildButton(button_token, left_side)) - return false; +void PanelBrowserTitlebarGtk::UpdateCustomFrame(bool use_custom_frame) { + // Nothing to do. +} - if (button_token == "minimize") { - // Create unminimze button, used to expand the minimized panel. - unminimize_button_.reset(CreateTitlebarButton("unminimize", left_side)); +void PanelBrowserTitlebarGtk::UpdateTitleAndIcon() { + std::string title_text = + UTF16ToUTF8(browser_window_->panel()->GetWindowTitle()); + + // Add the markup to show the title in the desired font. + gchar* escaped_title_text = g_markup_escape_text(title_text.c_str(), -1); + gchar* title_text_with_markup = g_strconcat(kTitleMarkupPrefix, + escaped_title_text, + kTitleMarkupSuffix, + NULL); + gtk_label_set_markup(GTK_LABEL(title_), title_text_with_markup); + g_free(escaped_title_text); + g_free(title_text_with_markup); +} - // We control visibility of minimize and unminimize buttons. - gtk_widget_set_no_show_all(minimize_button()->widget(), TRUE); - gtk_widget_set_no_show_all(unminimize_button_->widget(), TRUE); - } - return true; -} - -void PanelBrowserTitlebarGtk::GetButtonResources(const std::string& button_name, - int* normal_image_id, - int* pressed_image_id, - int* hover_image_id, - int* tooltip_id) const { - if (button_name == "close") { - *normal_image_id = IDR_PANEL_CLOSE; - *pressed_image_id = 0; - *hover_image_id = IDR_PANEL_CLOSE_H; - *tooltip_id = IDS_PANEL_CLOSE_TOOLTIP; - } else if (button_name == "minimize") { - *normal_image_id = IDR_PANEL_MINIMIZE; - *pressed_image_id = 0; - *hover_image_id = IDR_PANEL_MINIMIZE_H; - *tooltip_id = IDS_PANEL_MINIMIZE_TOOLTIP; - } else if (button_name == "unminimize") { - *normal_image_id = IDR_PANEL_RESTORE; - *pressed_image_id = 0; - *hover_image_id = IDR_PANEL_RESTORE_H; - *tooltip_id = IDS_PANEL_RESTORE_TOOLTIP; +void PanelBrowserTitlebarGtk::UpdateThrobber( + content::WebContents* web_contents) { + if (web_contents && web_contents->IsLoading()) { + GdkPixbuf* icon_pixbuf = + throbber_.GetNextFrame(web_contents->IsWaitingForResponse()); + gtk_image_set_from_pixbuf(GTK_IMAGE(icon_), icon_pixbuf); + } else { + ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); + + SkBitmap icon = browser_window_->panel()->GetCurrentPageIcon(); + if (icon.empty()) { + // Fallback to the Chromium icon if the page has no icon. + gtk_image_set_from_pixbuf(GTK_IMAGE(icon_), + rb.GetNativeImageNamed(IDR_PRODUCT_LOGO_16).ToGdkPixbuf()); + } else { + GdkPixbuf* icon_pixbuf = gfx::GdkPixbufFromSkBitmap(icon); + gtk_image_set_from_pixbuf(GTK_IMAGE(icon_), icon_pixbuf); + g_object_unref(icon_pixbuf); + } + + throbber_.Reset(); } } -int PanelBrowserTitlebarGtk::GetButtonOuterPadding() const { - return kPanelButtonOuterPadding; +void PanelBrowserTitlebarGtk::ShowContextMenu(GdkEventButton* event) { + // Panel does not show any context menu. } -int PanelBrowserTitlebarGtk::GetButtonSpacing() const { - return kPanelButtonSpacing; +void PanelBrowserTitlebarGtk::UpdateTextColor() { + GdkColor text_color = gfx::SkColorToGdkColor(GetTextColor()); + gtk_util::SetLabelColor(title_, &text_color); } void PanelBrowserTitlebarGtk::UpdateMinimizeRestoreButtonVisibility() { - if (!unminimize_button_.get() || !minimize_button()) - return; - Panel* panel = browser_window_->panel(); - gtk_widget_set_visible(minimize_button()->widget(), panel->CanMinimize()); - gtk_widget_set_visible(unminimize_button_->widget(), panel->CanRestore()); + gtk_widget_set_visible(minimize_button_->widget(), panel->CanMinimize()); + gtk_widget_set_visible(restore_button_->widget(), panel->CanRestore()); } -void PanelBrowserTitlebarGtk::HandleButtonClick(GtkWidget* button) { - if (close_button() && close_button()->widget() == button) { +gboolean PanelBrowserTitlebarGtk::OnWindowStateChanged( + GtkWindow* window, GdkEventWindowState* event) { + UpdateTextColor(); + return FALSE; +} + +void PanelBrowserTitlebarGtk::OnButtonClicked(GtkWidget* button) { + if (close_button_->widget() == button) { browser_window_->panel()->Close(); return; } @@ -159,12 +280,11 @@ void PanelBrowserTitlebarGtk::HandleButtonClick(GtkWidget* button) { GdkEvent* event = gtk_get_current_event(); DCHECK(event && event->type == GDK_BUTTON_RELEASE); - if (minimize_button() && minimize_button()->widget() == button) { + if (minimize_button_->widget() == button) { browser_window_->panel()->OnMinimizeButtonClicked( (event->button.state & GDK_CONTROL_MASK) ? panel::APPLY_TO_ALL : panel::NO_MODIFIER); - } else if (unminimize_button_.get() && - unminimize_button_->widget() == button) { + } else if (restore_button_->widget() == button) { browser_window_->panel()->OnRestoreButtonClicked( (event->button.state & GDK_CONTROL_MASK) ? panel::APPLY_TO_ALL : panel::NO_MODIFIER); @@ -173,15 +293,17 @@ void PanelBrowserTitlebarGtk::HandleButtonClick(GtkWidget* button) { gdk_event_free(event); } -void PanelBrowserTitlebarGtk::ShowFaviconMenu(GdkEventButton* event) { - // Favicon menu is not supported in panels. -} - -void PanelBrowserTitlebarGtk::UpdateTextColor() { - DCHECK(app_mode_title()); - - GdkColor text_color = gfx::SkColorToGdkColor(GetTextColor()); - gtk_util::SetLabelColor(app_mode_title(), &text_color); +void PanelBrowserTitlebarGtk::Observe( + int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) { + switch (type) { + case chrome::NOTIFICATION_BROWSER_THEME_CHANGED: + UpdateTextColor(); + break; + default: + NOTREACHED(); + } } void PanelBrowserTitlebarGtk::SendEnterNotifyToCloseButtonIfUnderMouse() { @@ -224,3 +346,16 @@ void PanelBrowserTitlebarGtk::SendEnterNotifyToCloseButtonIfUnderMouse() { "enter-notify-event", event, &return_value); } + +GtkWidget* PanelBrowserTitlebarGtk::widget() const { + return container_; +} + +void PanelBrowserTitlebarGtk::set_window(GtkWindow* window) { + window_ = window; +} + +AvatarMenuButtonGtk* PanelBrowserTitlebarGtk::avatar_button() const { + // Not supported in panel. + return NULL; +} diff --git a/chrome/browser/ui/panels/panel_browser_titlebar_gtk.h b/chrome/browser/ui/panels/panel_browser_titlebar_gtk.h index feaa725..954d762 100644 --- a/chrome/browser/ui/panels/panel_browser_titlebar_gtk.h +++ b/chrome/browser/ui/panels/panel_browser_titlebar_gtk.h @@ -5,17 +5,34 @@ #ifndef CHROME_BROWSER_UI_PANELS_PANEL_BROWSER_TITLEBAR_GTK_H_ #define CHROME_BROWSER_UI_PANELS_PANEL_BROWSER_TITLEBAR_GTK_H_ -#include "chrome/browser/ui/gtk/browser_titlebar.h" +#include <gtk/gtk.h> + +#include "base/compiler_specific.h" +#include "base/memory/scoped_ptr.h" +#include "chrome/browser/ui/gtk/browser_titlebar_base.h" +#include "chrome/browser/ui/gtk/titlebar_throb_animation.h" +#include "chrome/browser/ui/panels/panel_constants.h" +#include "content/public/browser/notification_observer.h" +#include "content/public/browser/notification_registrar.h" +#include "ui/base/gtk/gtk_signal.h" #include "ui/gfx/skia_util.h" +class CustomDrawButton; +class GtkThemeService; class PanelBrowserWindowGtk; -class PanelBrowserTitlebarGtk : public BrowserTitlebar { +namespace content { +class WebContents; +} + +class PanelBrowserTitlebarGtk : public BrowserTitlebarBase, + public content::NotificationObserver { public: PanelBrowserTitlebarGtk(PanelBrowserWindowGtk* browser_window, GtkWindow* window); virtual ~PanelBrowserTitlebarGtk(); + void UpdateTextColor(); void UpdateMinimizeRestoreButtonVisibility(); // When a panel appears in the same position as the one of the panel being @@ -30,41 +47,72 @@ class PanelBrowserTitlebarGtk : public BrowserTitlebar { // https://bugzilla.gnome.org/show_bug.cgi?id=667841 void SendEnterNotifyToCloseButtonIfUnderMouse(); - // Overridden from BrowserTitlebar: - virtual void UpdateButtonBackground(CustomDrawButton* button) OVERRIDE; + // Overriden from BrowserTitlebarBase. + virtual void Init() OVERRIDE; virtual void UpdateTitleAndIcon() OVERRIDE; - virtual void UpdateTextColor() OVERRIDE; - - protected: - // Overridden from BrowserTitlebar: - virtual bool BuildButton(const std::string& button_token, - bool left_side) OVERRIDE; - virtual void GetButtonResources(const std::string& button_name, - int* normal_image_id, - int* pressed_image_id, - int* hover_image_id, - int* tooltip_id) const OVERRIDE; - virtual int GetButtonOuterPadding() const OVERRIDE; - virtual int GetButtonSpacing() const OVERRIDE; - virtual void HandleButtonClick(GtkWidget* button) OVERRIDE; - virtual void ShowFaviconMenu(GdkEventButton* event) OVERRIDE; + virtual void UpdateCustomFrame(bool use_custom_frame) OVERRIDE; + virtual void UpdateThrobber(content::WebContents* web_contents) OVERRIDE; + virtual void ShowContextMenu(GdkEventButton* event) OVERRIDE; + virtual GtkWidget* widget() const OVERRIDE; + virtual void set_window(GtkWindow* window) OVERRIDE; + virtual AvatarMenuButtonGtk* avatar_button() const OVERRIDE; private: friend class NativePanelTestingGtk; - CustomDrawButton* unminimize_button() const { - return unminimize_button_.get(); - } + // Overridden from content::NotificationObserver: + virtual void Observe(int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) OVERRIDE; + + void BuildButtons(); + CustomDrawButton* CreateButton(panel::TitlebarButtonType button_type); + void GetButtonResources(panel::TitlebarButtonType button_type, + int* normal_image_id, + int* pressed_image_id, + int* hover_image_id, + int* tooltip_id) const; + GtkWidget* GetButtonHBox(); + + // Callback for changes to window state. This includes minimizing/restoring + // the window. + CHROMEG_CALLBACK_1(PanelBrowserTitlebarGtk, gboolean, OnWindowStateChanged, + GtkWindow*, GdkEventWindowState*); + + // Callback for minimize/restore/close buttons. + CHROMEGTK_CALLBACK_0(PanelBrowserTitlebarGtk, void, OnButtonClicked); + + CustomDrawButton* close_button() const { return close_button_.get(); } + CustomDrawButton* minimize_button() const { return minimize_button_.get(); } + CustomDrawButton* restore_button() const { return restore_button_.get(); } SkColor GetTextColor() const; + // Pointers to the browser window that owns us and its GtkWindow. PanelBrowserWindowGtk* browser_window_; + GtkWindow* window_; + + // The container widget the holds the hbox which contains the whole titlebar. + GtkWidget* container_; + + // VBoxes that holds the minimize/restore/close buttons box. + GtkWidget* titlebar_right_buttons_vbox_; + + // HBoxes that contains the actual min/max/close buttons. + GtkWidget* titlebar_right_buttons_hbox_; + + // The icon and page title. + GtkWidget* icon_; + GtkWidget* title_; + + // The buttons. + scoped_ptr<CustomDrawButton> close_button_; + scoped_ptr<CustomDrawButton> minimize_button_; + scoped_ptr<CustomDrawButton> restore_button_; - // All other buttons, including close and minimize buttons, are defined in - // the base class BrowserTitlebar. This is indeed our restore button. But - // we name it differently to avoid the confusion with restore_button defined - // in the base class and used for unmaximize purpose. - scoped_ptr<CustomDrawButton> unminimize_button_; + TitlebarThrobAnimation throbber_; + GtkThemeService* theme_service_; + content::NotificationRegistrar registrar_; DISALLOW_COPY_AND_ASSIGN(PanelBrowserTitlebarGtk); }; diff --git a/chrome/browser/ui/panels/panel_browser_view.cc b/chrome/browser/ui/panels/panel_browser_view.cc index e063b96..5d0631b 100644 --- a/chrome/browser/ui/panels/panel_browser_view.cc +++ b/chrome/browser/ui/panels/panel_browser_view.cc @@ -630,7 +630,8 @@ class NativePanelTestingWin : public NativePanelTesting { virtual bool VerifyActiveState(bool is_active) OVERRIDE; virtual bool IsWindowSizeKnown() const OVERRIDE; virtual bool IsAnimatingBounds() const OVERRIDE; - virtual bool IsButtonVisible(TitlebarButtonType button_type) const OVERRIDE; + virtual bool IsButtonVisible( + panel::TitlebarButtonType button_type) const OVERRIDE; PanelBrowserView* panel_browser_view_; }; @@ -690,15 +691,15 @@ bool NativePanelTestingWin::IsAnimatingBounds() const { } bool NativePanelTestingWin::IsButtonVisible( - TitlebarButtonType button_type) const { + panel::TitlebarButtonType button_type) const { PanelBrowserFrameView* frame_view = panel_browser_view_->GetFrameView(); switch (button_type) { - case CLOSE_BUTTON: + case panel::CLOSE_BUTTON: return frame_view->close_button_->visible(); - case MINIMIZE_BUTTON: + case panel::MINIMIZE_BUTTON: return frame_view->minimize_button_->visible(); - case RESTORE_BUTTON: + case panel::RESTORE_BUTTON: return frame_view->restore_button_->visible(); default: NOTREACHED(); diff --git a/chrome/browser/ui/panels/panel_browser_window_cocoa.mm b/chrome/browser/ui/panels/panel_browser_window_cocoa.mm index e9ceeed..0483825 100644 --- a/chrome/browser/ui/panels/panel_browser_window_cocoa.mm +++ b/chrome/browser/ui/panels/panel_browser_window_cocoa.mm @@ -364,7 +364,8 @@ class NativePanelTestingCocoa : public NativePanelTesting { virtual bool VerifyActiveState(bool is_active) OVERRIDE; virtual bool IsWindowSizeKnown() const OVERRIDE; virtual bool IsAnimatingBounds() const OVERRIDE; - virtual bool IsButtonVisible(TitlebarButtonType button_type) const OVERRIDE; + virtual bool IsButtonVisible( + panel::TitlebarButtonType button_type) const OVERRIDE; private: PanelTitlebarViewCocoa* titlebar() const; @@ -438,13 +439,13 @@ bool NativePanelTestingCocoa::IsAnimatingBounds() const { } bool NativePanelTestingCocoa::IsButtonVisible( - TitlebarButtonType button_type) const { + panel::TitlebarButtonType button_type) const { switch (button_type) { - case CLOSE_BUTTON: + case panel::CLOSE_BUTTON: return ![[titlebar() closeButton] isHidden]; - case MINIMIZE_BUTTON: + case panel::MINIMIZE_BUTTON: return ![[titlebar() minimizeButton] isHidden]; - case RESTORE_BUTTON: + case panel::RESTORE_BUTTON: return ![[titlebar() restoreButton] isHidden]; default: NOTREACHED(); diff --git a/chrome/browser/ui/panels/panel_browser_window_gtk.cc b/chrome/browser/ui/panels/panel_browser_window_gtk.cc index ca21de9..dd74253 100644 --- a/chrome/browser/ui/panels/panel_browser_window_gtk.cc +++ b/chrome/browser/ui/panels/panel_browser_window_gtk.cc @@ -11,10 +11,10 @@ #include "chrome/browser/ui/gtk/browser_titlebar.h" #include "chrome/browser/ui/gtk/custom_button.h" #include "chrome/browser/ui/gtk/gtk_theme_service.h" -#include "chrome/browser/ui/gtk/nine_box.h" #include "chrome/browser/ui/panels/panel.h" #include "chrome/browser/ui/panels/panel_bounds_animation.h" #include "chrome/browser/ui/panels/panel_browser_titlebar_gtk.h" +#include "chrome/browser/ui/panels/panel_constants.h" #include "chrome/browser/ui/panels/panel_drag_gtk.h" #include "chrome/browser/ui/panels/panel_manager.h" #include "chrome/browser/ui/panels/panel_strip.h" @@ -23,49 +23,61 @@ #include "content/public/browser/notification_service.h" #include "grit/theme_resources_standard.h" #include "grit/ui_resources.h" -#include "third_party/skia/include/core/SkShader.h" +#include "ui/base/gtk/gtk_compat.h" #include "ui/gfx/canvas.h" #include "ui/gfx/image/cairo_cached_surface.h" #include "ui/gfx/image/image.h" -#include "ui/gfx/skia_util.h" using content::NativeWebKeyboardEvent; using content::WebContents; namespace { -// Colors used to draw titlebar and frame for drawing attention under default -// theme. It is also used in non-default theme since attention color is not -// defined in the theme. -const SkColor kAttentionBackgroundColorStart = SkColorSetRGB(0xff, 0xab, 0x57); -const SkColor kAttentionBackgroundColorEnd = SkColorSetRGB(0xe6, 0x9a, 0x4e); +// Colors used to draw frame background under default theme. +const SkColor kActiveBackgroundDefaultColor = SkColorSetRGB(0x3a, 0x3c, 0x3c); +const SkColor kInactiveBackgroundDefaultColor = SkColorSetRGB(0x7a, 0x7c, 0x7c); +const SkColor kAttentionBackgroundDefaultColor = + SkColorSetRGB(0xff, 0xab, 0x57); +const SkColor kMinimizeBackgroundDefaultColor = SkColorSetRGB(0xf5, 0xf4, 0xf0); +const SkColor kMinimizeBorderDefaultColor = SkColorSetRGB(0xc9, 0xc9, 0xc9); + +// Color used to draw the divider line between the titlebar and the client area. +const SkColor kDividerColor = SkColorSetRGB(0x5a, 0x5c, 0x5c); // Set minimium width for window really small. const int kMinWindowWidth = 26; -gfx::Image* CreateGradientImage(SkColor start_color, SkColor end_color) { - // Though the height of titlebar, used for creating gradient, cannot be - // pre-determined, we use a reasonably bigger value that is obtained from - // the experimentation and should work for most cases. - const int gradient_size = 32; - SkShader* shader = gfx::CreateGradientShader( - 0, gradient_size, start_color, end_color); - SkPaint paint; - paint.setStyle(SkPaint::kFill_Style); - paint.setAntiAlias(true); - paint.setShader(shader); - shader->unref(); - gfx::Canvas canvas(gfx::Size(1, gradient_size), true); - canvas.DrawRect(gfx::Rect(0, 0, 1, gradient_size), paint); +gfx::Image* CreateImageForColor(SkColor color) { + gfx::Canvas canvas(gfx::Size(1, 1), true); + canvas.DrawColor(color); return new gfx::Image(canvas.ExtractBitmap()); } -gfx::Image* GetAttentionBackgroundImage() { +const gfx::Image* GetActiveBackgroundDefaultImage() { static gfx::Image* image = NULL; - if (!image) { - image = CreateGradientImage(kAttentionBackgroundColorStart, - kAttentionBackgroundColorEnd); - } + if (!image) + image = CreateImageForColor(kActiveBackgroundDefaultColor); + return image; +} + +const gfx::Image* GetInactiveBackgroundDefaultImage() { + static gfx::Image* image = NULL; + if (!image) + image = CreateImageForColor(kInactiveBackgroundDefaultColor); + return image; +} + +const gfx::Image* GetAttentionBackgroundDefaultImage() { + static gfx::Image* image = NULL; + if (!image) + image = CreateImageForColor(kAttentionBackgroundDefaultColor); + return image; +} + +const gfx::Image* GetMinimizeBackgroundDefaultImage() { + static gfx::Image* image = NULL; + if (!image) + image = CreateImageForColor(kMinimizeBackgroundDefaultColor); return image; } @@ -85,6 +97,7 @@ PanelBrowserWindowGtk::PanelBrowserWindowGtk(Browser* browser, : BrowserWindowGtk(browser), panel_(panel), bounds_(bounds), + paint_state_(PAINT_AS_INACTIVE), is_drawing_attention_(false) { } @@ -116,11 +129,7 @@ void PanelBrowserWindowGtk::Init() { content::Source<GtkWindow>(window())); } -bool PanelBrowserWindowGtk::ShouldDrawContentDropShadow() const { - return !panel_->IsMinimized(); -} - -BrowserTitlebar* PanelBrowserWindowGtk::CreateBrowserTitlebar() { +BrowserTitlebarBase* PanelBrowserWindowGtk::CreateBrowserTitlebar() { return new PanelBrowserTitlebarGtk(this, window()); } @@ -128,10 +137,13 @@ PanelBrowserTitlebarGtk* PanelBrowserWindowGtk::GetPanelTitlebar() const { return static_cast<PanelBrowserTitlebarGtk*>(titlebar()); } -PanelBrowserWindowGtk::PaintState PanelBrowserWindowGtk::GetPaintState() const { - if (is_drawing_attention_) - return PAINT_FOR_ATTENTION; - return IsActive() ? PAINT_AS_ACTIVE : PAINT_AS_INACTIVE; +bool PanelBrowserWindowGtk::UsingDefaultTheme() const { + // No theme is provided for attention painting. + if (paint_state_ == PAINT_FOR_ATTENTION) + return true; + + GtkThemeService* theme_provider = GtkThemeService::GetFrom(panel_->profile()); + return theme_provider->UsingDefaultTheme(); } bool PanelBrowserWindowGtk::GetWindowEdge(int x, int y, GdkWindowEdge* edge) { @@ -171,20 +183,70 @@ GdkRegion* PanelBrowserWindowGtk::GetWindowShape(int width, int height) const { return mask; } -void PanelBrowserWindowGtk::DrawCustomFrameBorder(GtkWidget* widget) { - static NineBox* custom_frame_border = NULL; - if (!custom_frame_border) { - custom_frame_border = new NineBox(IDR_WINDOW_TOP_LEFT_CORNER, - IDR_WINDOW_TOP_CENTER, - IDR_WINDOW_TOP_RIGHT_CORNER, - IDR_WINDOW_LEFT_SIDE, - 0, - IDR_WINDOW_RIGHT_SIDE, - IDR_PANEL_BOTTOM_LEFT_CORNER, - IDR_WINDOW_BOTTOM_CENTER, - IDR_PANEL_BOTTOM_RIGHT_CORNER); +bool PanelBrowserWindowGtk::UseCustomFrame() const { + // We always use custom frame for panels. + return true; +} + +void PanelBrowserWindowGtk::DrawFrame(GtkWidget* widget, + GdkEventExpose* event) { + cairo_t* cr = gdk_cairo_create(gtk_widget_get_window(widget)); + gdk_cairo_rectangle(cr, &event->area); + cairo_clip(cr); + + // Update the painting state. + int window_height = gdk_window_get_height(gtk_widget_get_window(widget)); + if (is_drawing_attention_) + paint_state_ = PAINT_FOR_ATTENTION; + else if (window_height <= panel::kMinimizedPanelHeight) + paint_state_ = PAINT_AS_MINIMIZED; + else if (IsActive()) + paint_state_ = PAINT_AS_ACTIVE; + else + paint_state_ = PAINT_AS_INACTIVE; + + // Draw the background. + gfx::CairoCachedSurface* surface = GetFrameBackground()->ToCairo(); + surface->SetSource(cr, widget, 0, 0); + cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_REPEAT); + cairo_rectangle(cr, event->area.x, event->area.y, + event->area.width, event->area.height); + cairo_fill(cr); + + // Draw the divider only if we're showing more than titlebar. + if (window_height > panel::kTitlebarHeight) { + cairo_set_source_rgb(cr, + SkColorGetR(kDividerColor) / 255.0, + SkColorGetG(kDividerColor) / 255.0, + SkColorGetB(kDividerColor) / 255.0); + cairo_rectangle(cr, 0, panel::kTitlebarHeight - 1, bounds_.width(), 1); + cairo_fill(cr); } - custom_frame_border->RenderToWidget(widget); + + // Draw the border for the minimized panel only. + if (paint_state_ == PAINT_AS_MINIMIZED) { + cairo_move_to(cr, 0, 3); + cairo_line_to(cr, 1, 2); + cairo_line_to(cr, 1, 1); + cairo_line_to(cr, 2, 1); + cairo_line_to(cr, 3, 0); + cairo_line_to(cr, event->area.width - 3, 0); + cairo_line_to(cr, event->area.width - 2, 1); + cairo_line_to(cr, event->area.width - 1, 1); + cairo_line_to(cr, event->area.width - 1, 2); + cairo_line_to(cr, event->area.width - 1, 3); + cairo_line_to(cr, event->area.width - 1, event->area.height - 1); + cairo_line_to(cr, 0, event->area.height - 1); + cairo_close_path(cr); + cairo_set_source_rgb(cr, + SkColorGetR(kMinimizeBorderDefaultColor) / 255.0, + SkColorGetG(kMinimizeBorderDefaultColor) / 255.0, + SkColorGetB(kMinimizeBorderDefaultColor) / 255.0); + cairo_set_line_width(cr, 1.0); + cairo_stroke(cr); + } + + cairo_destroy(cr); } void PanelBrowserWindowGtk::EnsureDragHelperCreated() { @@ -270,51 +332,31 @@ void PanelBrowserWindowGtk::OnSizeChanged(int width, int height) { content::NotificationService::NoDetails()); } -bool PanelBrowserWindowGtk::UseCustomFrame() const { - // We always use custom frame for panels. - return true; -} - -bool PanelBrowserWindowGtk::UsingCustomPopupFrame() const { - // We do not draw custom popup frame. - return false; -} - -void PanelBrowserWindowGtk::DrawPopupFrame(cairo_t* cr, - GtkWidget* widget, - GdkEventExpose* event) { - NOTREACHED(); +const gfx::Image* PanelBrowserWindowGtk::GetFrameBackground() const { + return UsingDefaultTheme() ? + GetDefaultFrameBackground() : GetThemedFrameBackground(); } -const gfx::Image* PanelBrowserWindowGtk::GetThemeFrameImage() const { - PaintState paint_state = GetPaintState(); - if (paint_state == PAINT_FOR_ATTENTION) - return GetAttentionBackgroundImage(); - - GtkThemeService* theme_provider = GtkThemeService::GetFrom( - GetPanelBrowser()->profile()); - if (theme_provider->UsingDefaultTheme()) { - // We choose to use the window frame theme to paint panels for the default - // theme. This is because the default tab theme does not work well for the - // user to recognize active and inactive panels. - return theme_provider->GetImageNamed(paint_state == PAINT_AS_ACTIVE ? - IDR_THEME_FRAME : IDR_THEME_FRAME_INACTIVE); +const gfx::Image* PanelBrowserWindowGtk::GetDefaultFrameBackground() const { + switch (paint_state_) { + case PAINT_AS_INACTIVE: + return GetInactiveBackgroundDefaultImage(); + case PAINT_AS_ACTIVE: + return GetActiveBackgroundDefaultImage(); + case PAINT_AS_MINIMIZED: + return GetMinimizeBackgroundDefaultImage(); + case PAINT_FOR_ATTENTION: + return GetAttentionBackgroundDefaultImage(); + default: + NOTREACHED(); + return GetInactiveBackgroundDefaultImage(); } - - return theme_provider->GetImageNamed(paint_state == PAINT_AS_ACTIVE ? - IDR_THEME_TOOLBAR : IDR_THEME_TAB_BACKGROUND); } -void PanelBrowserWindowGtk::DrawCustomFrame(cairo_t* cr, - GtkWidget* widget, - GdkEventExpose* event) { - gfx::CairoCachedSurface* surface = GetThemeFrameImage()->ToCairo(); - - surface->SetSource(cr, widget, 0, 0); - cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_REPEAT); - cairo_rectangle(cr, event->area.x, event->area.y, - event->area.width, event->area.height); - cairo_fill(cr); +const gfx::Image* PanelBrowserWindowGtk::GetThemedFrameBackground() const { + GtkThemeService* theme_provider = GtkThemeService::GetFrom(panel_->profile()); + return theme_provider->GetImageNamed(paint_state_ == PAINT_AS_ACTIVE ? + IDR_THEME_TOOLBAR : IDR_THEME_TAB_BACKGROUND); } void PanelBrowserWindowGtk::ActiveWindowChanged(GdkWindow* active_window) { @@ -324,6 +366,7 @@ void PanelBrowserWindowGtk::ActiveWindowChanged(GdkWindow* active_window) { if (!window() || was_active == is_active) // State didn't change. return; + GetPanelTitlebar()->UpdateTextColor(); panel_->OnActiveStateChanged(is_active); } @@ -600,7 +643,8 @@ class NativePanelTestingGtk : public NativePanelTesting { virtual void WaitForWindowCreationToComplete() const OVERRIDE; virtual bool IsWindowSizeKnown() const OVERRIDE; virtual bool IsAnimatingBounds() const OVERRIDE; - virtual bool IsButtonVisible(TitlebarButtonType button_type) const OVERRIDE; + virtual bool IsButtonVisible( + panel::TitlebarButtonType button_type) const OVERRIDE; PanelBrowserWindowGtk* panel_browser_window_gtk_; }; @@ -703,19 +747,19 @@ bool NativePanelTestingGtk::IsAnimatingBounds() const { } bool NativePanelTestingGtk::IsButtonVisible( - TitlebarButtonType button_type) const { + panel::TitlebarButtonType button_type) const { PanelBrowserTitlebarGtk* titlebar = panel_browser_window_gtk_->GetPanelTitlebar(); CustomDrawButton* button; switch (button_type) { - case CLOSE_BUTTON: + case panel::CLOSE_BUTTON: button = titlebar->close_button(); break; - case MINIMIZE_BUTTON: + case panel::MINIMIZE_BUTTON: button = titlebar->minimize_button(); break; - case RESTORE_BUTTON: - button = titlebar->unminimize_button(); + case panel::RESTORE_BUTTON: + button = titlebar->restore_button(); break; default: NOTREACHED(); diff --git a/chrome/browser/ui/panels/panel_browser_window_gtk.h b/chrome/browser/ui/panels/panel_browser_window_gtk.h index 911259b..d19089c 100644 --- a/chrome/browser/ui/panels/panel_browser_window_gtk.h +++ b/chrome/browser/ui/panels/panel_browser_window_gtk.h @@ -28,6 +28,7 @@ class PanelBrowserWindowGtk : public BrowserWindowGtk, enum PaintState { PAINT_AS_ACTIVE, PAINT_AS_INACTIVE, + PAINT_AS_MINIMIZED, PAINT_FOR_ATTENTION }; @@ -37,7 +38,6 @@ class PanelBrowserWindowGtk : public BrowserWindowGtk, // BrowserWindowGtk override virtual void Init() OVERRIDE; - virtual bool ShouldDrawContentDropShadow() const OVERRIDE; // BrowserWindow overrides virtual void SetBounds(const gfx::Rect& bounds) OVERRIDE; @@ -47,16 +47,16 @@ class PanelBrowserWindowGtk : public BrowserWindowGtk, const content::NotificationSource& source, const content::NotificationDetails& details) OVERRIDE; - PaintState GetPaintState() const; + bool UsingDefaultTheme() const; Panel* panel() const { return panel_.get(); } + PaintState paint_state() const { return paint_state_; } protected: // BrowserWindowGtk overrides - virtual BrowserTitlebar* CreateBrowserTitlebar() OVERRIDE; + virtual BrowserTitlebarBase* CreateBrowserTitlebar() OVERRIDE; virtual bool GetWindowEdge(int x, int y, GdkWindowEdge* edge) OVERRIDE; virtual GdkRegion* GetWindowShape(int width, int height) const OVERRIDE; - virtual void DrawCustomFrameBorder(GtkWidget* widget) OVERRIDE; virtual bool HandleTitleBarLeftMousePress( GdkEventButton* event, guint32 last_click_time, @@ -68,12 +68,8 @@ class PanelBrowserWindowGtk : public BrowserWindowGtk, virtual void SaveWindowPosition() OVERRIDE; virtual void SetGeometryHints() OVERRIDE; virtual bool UseCustomFrame() const OVERRIDE; - virtual bool UsingCustomPopupFrame() const OVERRIDE; + virtual void DrawFrame(GtkWidget* widget, GdkEventExpose* event) OVERRIDE; virtual void OnSizeChanged(int width, int height) OVERRIDE; - virtual void DrawCustomFrame(cairo_t* cr, GtkWidget* widget, - GdkEventExpose* event) OVERRIDE; - virtual void DrawPopupFrame(cairo_t* cr, GtkWidget* widget, - GdkEventExpose* event) OVERRIDE; virtual void ActiveWindowChanged(GdkWindow* active_window) OVERRIDE; // Overridden from NativePanel: @@ -138,8 +134,10 @@ class PanelBrowserWindowGtk : public BrowserWindowGtk, PanelBrowserTitlebarGtk* GetPanelTitlebar() const; - // Returns the theme image to paint the frame. - const gfx::Image* GetThemeFrameImage() const; + // Returns the image to paint the frame. + const gfx::Image* GetFrameBackground() const; + const gfx::Image* GetDefaultFrameBackground() const; + const gfx::Image* GetThemedFrameBackground() const; CHROMEGTK_CALLBACK_1(PanelBrowserWindowGtk, gboolean, OnTitlebarButtonReleaseEvent, GdkEventButton*); @@ -152,6 +150,9 @@ class PanelBrowserWindowGtk : public BrowserWindowGtk, // Size of window frame. Empty until the window has been allocated and sized. gfx::Size frame_size_; + // Indicates different painting state, active, drawing attention or else. + PaintState paint_state_; + // Indicates that the panel is currently drawing attention. bool is_drawing_attention_; diff --git a/chrome/browser/ui/panels/panel_browsertest.cc b/chrome/browser/ui/panels/panel_browsertest.cc index 0ac8e14..0595764 100644 --- a/chrome/browser/ui/panels/panel_browsertest.cc +++ b/chrome/browser/ui/panels/panel_browsertest.cc @@ -291,26 +291,17 @@ IN_PROC_BROWSER_TEST_F(PanelBrowserTest, CheckDockedPanelProperties) { EXPECT_TRUE(panel2->always_on_top()); EXPECT_TRUE(panel3->always_on_top()); - EXPECT_TRUE(panel1_testing->IsButtonVisible( - NativePanelTesting::CLOSE_BUTTON)); - EXPECT_TRUE(panel2_testing->IsButtonVisible( - NativePanelTesting::CLOSE_BUTTON)); - EXPECT_TRUE(panel3_testing->IsButtonVisible( - NativePanelTesting::CLOSE_BUTTON)); - - EXPECT_TRUE(panel1_testing->IsButtonVisible( - NativePanelTesting::MINIMIZE_BUTTON)); - EXPECT_FALSE(panel2_testing->IsButtonVisible( - NativePanelTesting::MINIMIZE_BUTTON)); - EXPECT_FALSE(panel3_testing->IsButtonVisible( - NativePanelTesting::MINIMIZE_BUTTON)); - - EXPECT_FALSE(panel1_testing->IsButtonVisible( - NativePanelTesting::RESTORE_BUTTON)); - EXPECT_TRUE(panel2_testing->IsButtonVisible( - NativePanelTesting::RESTORE_BUTTON)); - EXPECT_TRUE(panel3_testing->IsButtonVisible( - NativePanelTesting::RESTORE_BUTTON)); + EXPECT_TRUE(panel1_testing->IsButtonVisible(panel::CLOSE_BUTTON)); + EXPECT_TRUE(panel2_testing->IsButtonVisible(panel::CLOSE_BUTTON)); + EXPECT_TRUE(panel3_testing->IsButtonVisible(panel::CLOSE_BUTTON)); + + EXPECT_TRUE(panel1_testing->IsButtonVisible(panel::MINIMIZE_BUTTON)); + EXPECT_FALSE(panel2_testing->IsButtonVisible(panel::MINIMIZE_BUTTON)); + EXPECT_FALSE(panel3_testing->IsButtonVisible(panel::MINIMIZE_BUTTON)); + + EXPECT_FALSE(panel1_testing->IsButtonVisible(panel::RESTORE_BUTTON)); + EXPECT_TRUE(panel2_testing->IsButtonVisible(panel::RESTORE_BUTTON)); + EXPECT_TRUE(panel3_testing->IsButtonVisible(panel::RESTORE_BUTTON)); EXPECT_EQ(panel::RESIZABLE_ALL_SIDES_EXCEPT_BOTTOM, panel1->CanResizeByMouse()); diff --git a/chrome/browser/ui/panels/panel_constants.h b/chrome/browser/ui/panels/panel_constants.h index f51b7b5..d805c69 100644 --- a/chrome/browser/ui/panels/panel_constants.h +++ b/chrome/browser/ui/panels/panel_constants.h @@ -25,6 +25,13 @@ static const int kMinimizedPanelHeight = 4; // The height in pixels of the titlebar. static const int kTitlebarHeight = 32; +// Different types of buttons that can be shown on panel's titlebar. +enum TitlebarButtonType { + CLOSE_BUTTON, + MINIMIZE_BUTTON, + RESTORE_BUTTON +}; + // Different platforms use different modifier keys to change the behavior // of a mouse click. This enum captures the meaning of the modifier rather // than the actual modifier key to generalize across platforms. diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index ebe7c97..59e0ffb 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -2892,6 +2892,7 @@ 'browser/ui/gtk/browser_actions_toolbar_gtk.h', 'browser/ui/gtk/browser_titlebar.cc', 'browser/ui/gtk/browser_titlebar.h', + 'browser/ui/gtk/browser_titlebar_base.h', 'browser/ui/gtk/browser_toolbar_gtk.cc', 'browser/ui/gtk/browser_toolbar_gtk.h', 'browser/ui/gtk/browser_window_gtk.cc', @@ -3092,6 +3093,8 @@ 'browser/ui/gtk/task_manager_gtk.h', 'browser/ui/gtk/throbber_gtk.cc', 'browser/ui/gtk/throbber_gtk.h', + 'browser/ui/gtk/titlebar_throb_animation.cc', + 'browser/ui/gtk/titlebar_throb_animation.h', 'browser/ui/gtk/unity_service.cc', 'browser/ui/gtk/unity_service.h', 'browser/ui/gtk/update_recommended_dialog.cc', @@ -3155,10 +3158,10 @@ 'browser/ui/panels/panel_bounds_animation.h', 'browser/ui/panels/panel_browser_frame_view.cc', 'browser/ui/panels/panel_browser_frame_view.h', - 'browser/ui/panels/panel_browser_view.cc', - 'browser/ui/panels/panel_browser_view.h', 'browser/ui/panels/panel_browser_titlebar_gtk.cc', 'browser/ui/panels/panel_browser_titlebar_gtk.h', + 'browser/ui/panels/panel_browser_view.cc', + 'browser/ui/panels/panel_browser_view.h', 'browser/ui/panels/panel_browser_window.cc', 'browser/ui/panels/panel_browser_window.h', 'browser/ui/panels/panel_browser_window_cocoa.h', |