Index: chrome/browser/gtk/bookmark_bar_gtk.cc |
=================================================================== |
--- chrome/browser/gtk/bookmark_bar_gtk.cc (revision 71352) |
+++ chrome/browser/gtk/bookmark_bar_gtk.cc (working copy) |
@@ -1,1418 +0,0 @@ |
-// Copyright (c) 2010 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/gtk/bookmark_bar_gtk.h" |
- |
-#include <vector> |
- |
-#include "app/gtk_dnd_util.h" |
-#include "app/resource_bundle.h" |
-#include "base/utf_string_conversions.h" |
-#include "chrome/browser/bookmarks/bookmark_node_data.h" |
-#include "chrome/browser/bookmarks/bookmark_model.h" |
-#include "chrome/browser/bookmarks/bookmark_utils.h" |
-#include "chrome/browser/browser_shutdown.h" |
-#include "chrome/browser/gtk/bookmark_menu_controller_gtk.h" |
-#include "chrome/browser/gtk/bookmark_tree_model.h" |
-#include "chrome/browser/gtk/bookmark_utils_gtk.h" |
-#include "chrome/browser/gtk/browser_window_gtk.h" |
-#include "chrome/browser/gtk/cairo_cached_surface.h" |
-#include "chrome/browser/gtk/custom_button.h" |
-#include "chrome/browser/gtk/gtk_chrome_button.h" |
-#include "chrome/browser/gtk/gtk_theme_provider.h" |
-#include "chrome/browser/gtk/gtk_util.h" |
-#include "chrome/browser/gtk/hover_controller_gtk.h" |
-#include "chrome/browser/gtk/import_dialog_gtk.h" |
-#include "chrome/browser/gtk/menu_gtk.h" |
-#include "chrome/browser/gtk/rounded_window.h" |
-#include "chrome/browser/gtk/tabstrip_origin_provider.h" |
-#include "chrome/browser/gtk/tabs/tab_strip_gtk.h" |
-#include "chrome/browser/gtk/view_id_util.h" |
-#include "chrome/browser/importer/importer_data_types.h" |
-#include "chrome/browser/metrics/user_metrics.h" |
-#include "chrome/browser/ntp_background_util.h" |
-#include "chrome/browser/prefs/pref_service.h" |
-#include "chrome/browser/profiles/profile.h" |
-#include "chrome/browser/sync/sync_ui_util.h" |
-#include "chrome/browser/tab_contents/tab_contents.h" |
-#include "chrome/browser/tab_contents/tab_contents_view.h" |
-#include "chrome/browser/ui/browser.h" |
-#include "chrome/common/notification_service.h" |
-#include "chrome/common/pref_names.h" |
-#include "gfx/canvas_skia_paint.h" |
-#include "gfx/gtk_util.h" |
-#include "grit/app_resources.h" |
-#include "grit/generated_resources.h" |
-#include "grit/theme_resources.h" |
-#include "ui/base/animation/slide_animation.h" |
- |
-namespace { |
- |
-// The showing height of the bar. |
-const int kBookmarkBarHeight = 29; |
- |
-// Padding for when the bookmark bar is floating. |
-const int kTopBottomNTPPadding = 12; |
-const int kLeftRightNTPPadding = 8; |
- |
-// Padding around the bar's content area when the bookmark bar is floating. |
-const int kNTPPadding = 2; |
- |
-// The number of pixels of rounding on the corners of the bookmark bar content |
-// area when in floating mode. |
-const int kNTPRoundedness = 3; |
- |
-// The height of the bar when it is "hidden". It is usually not completely |
-// hidden because even when it is closed it forms the bottom few pixels of |
-// the toolbar. |
-const int kBookmarkBarMinimumHeight = 3; |
- |
-// Left-padding for the instructional text. |
-const int kInstructionsPadding = 6; |
- |
-// Padding around the "Other Bookmarks" button. |
-const int kOtherBookmarksPaddingHorizontal = 2; |
-const int kOtherBookmarksPaddingVertical = 1; |
- |
-// The targets accepted by the toolbar and folder buttons for DnD. |
-const int kDestTargetList[] = { gtk_dnd_util::CHROME_BOOKMARK_ITEM, |
- gtk_dnd_util::CHROME_NAMED_URL, |
- gtk_dnd_util::TEXT_URI_LIST, |
- gtk_dnd_util::NETSCAPE_URL, |
- gtk_dnd_util::TEXT_PLAIN, -1 }; |
- |
-// Acceptable drag actions for the bookmark bar drag destinations. |
-const GdkDragAction kDragAction = |
- GdkDragAction(GDK_ACTION_MOVE | GDK_ACTION_COPY); |
- |
-void SetToolBarStyle() { |
- static bool style_was_set = false; |
- |
- if (style_was_set) |
- return; |
- style_was_set = true; |
- |
- gtk_rc_parse_string( |
- "style \"chrome-bookmark-toolbar\" {" |
- " xthickness = 0\n" |
- " ythickness = 0\n" |
- " GtkWidget::focus-padding = 0\n" |
- " GtkContainer::border-width = 0\n" |
- " GtkToolbar::internal-padding = 1\n" |
- " GtkToolbar::shadow-type = GTK_SHADOW_NONE\n" |
- "}\n" |
- "widget \"*chrome-bookmark-toolbar\" style \"chrome-bookmark-toolbar\""); |
-} |
- |
-} // namespace |
- |
-const int BookmarkBarGtk::kBookmarkBarNTPHeight = 57; |
- |
-BookmarkBarGtk::BookmarkBarGtk(BrowserWindowGtk* window, |
- Profile* profile, Browser* browser, |
- TabstripOriginProvider* tabstrip_origin_provider) |
- : profile_(NULL), |
- page_navigator_(NULL), |
- browser_(browser), |
- window_(window), |
- tabstrip_origin_provider_(tabstrip_origin_provider), |
- model_(NULL), |
- instructions_(NULL), |
- sync_service_(NULL), |
- dragged_node_(NULL), |
- drag_icon_(NULL), |
- toolbar_drop_item_(NULL), |
- theme_provider_(GtkThemeProvider::GetFrom(profile)), |
- show_instructions_(true), |
- menu_bar_helper_(this), |
- floating_(false), |
- last_allocation_width_(-1), |
- throbbing_widget_(NULL), |
- method_factory_(this) { |
- if (profile->GetProfileSyncService()) { |
- // Obtain a pointer to the profile sync service and add our instance as an |
- // observer. |
- sync_service_ = profile->GetProfileSyncService(); |
- sync_service_->AddObserver(this); |
- } |
- |
- Init(profile); |
- SetProfile(profile); |
- // Force an update by simulating being in the wrong state. |
- floating_ = !ShouldBeFloating(); |
- UpdateFloatingState(); |
- |
- registrar_.Add(this, NotificationType::BROWSER_THEME_CHANGED, |
- NotificationService::AllSources()); |
-} |
- |
-BookmarkBarGtk::~BookmarkBarGtk() { |
- RemoveAllBookmarkButtons(); |
- bookmark_toolbar_.Destroy(); |
- event_box_.Destroy(); |
-} |
- |
-void BookmarkBarGtk::SetProfile(Profile* profile) { |
- DCHECK(profile); |
- if (profile_ == profile) |
- return; |
- |
- RemoveAllBookmarkButtons(); |
- |
- profile_ = profile; |
- |
- if (model_) |
- model_->RemoveObserver(this); |
- |
- // TODO(erg): Handle extensions |
- |
- model_ = profile_->GetBookmarkModel(); |
- model_->AddObserver(this); |
- if (model_->IsLoaded()) |
- Loaded(model_); |
- |
- // else case: we'll receive notification back from the BookmarkModel when done |
- // loading, then we'll populate the bar. |
-} |
- |
-void BookmarkBarGtk::SetPageNavigator(PageNavigator* navigator) { |
- page_navigator_ = navigator; |
-} |
- |
-void BookmarkBarGtk::Init(Profile* profile) { |
- event_box_.Own(gtk_event_box_new()); |
- g_signal_connect(event_box_.get(), "destroy", |
- G_CALLBACK(&OnEventBoxDestroyThunk), this); |
- g_signal_connect(event_box_.get(), "button-press-event", |
- G_CALLBACK(&OnButtonPressedThunk), this); |
- |
- ntp_padding_box_ = gtk_alignment_new(0, 0, 1, 1); |
- gtk_container_add(GTK_CONTAINER(event_box_.get()), ntp_padding_box_); |
- |
- paint_box_ = gtk_event_box_new(); |
- gtk_container_add(GTK_CONTAINER(ntp_padding_box_), paint_box_); |
- GdkColor paint_box_color = |
- theme_provider_->GetGdkColor(BrowserThemeProvider::COLOR_TOOLBAR); |
- gtk_widget_modify_bg(paint_box_, GTK_STATE_NORMAL, &paint_box_color); |
- gtk_widget_add_events(paint_box_, GDK_POINTER_MOTION_MASK | |
- GDK_BUTTON_PRESS_MASK); |
- |
- bookmark_hbox_ = gtk_hbox_new(FALSE, 0); |
- gtk_container_add(GTK_CONTAINER(paint_box_), bookmark_hbox_); |
- |
- instructions_ = gtk_alignment_new(0, 0, 1, 1); |
- gtk_alignment_set_padding(GTK_ALIGNMENT(instructions_), 0, 0, |
- kInstructionsPadding, 0); |
- instructions_gtk_.reset(new BookmarkBarInstructionsGtk(this, profile)); |
- gtk_container_add(GTK_CONTAINER(instructions_), instructions_gtk_->widget()); |
- gtk_box_pack_start(GTK_BOX(bookmark_hbox_), instructions_, |
- TRUE, TRUE, 0); |
- |
- gtk_drag_dest_set(instructions_, |
- GtkDestDefaults(GTK_DEST_DEFAULT_DROP | GTK_DEST_DEFAULT_MOTION), |
- NULL, 0, kDragAction); |
- gtk_dnd_util::SetDestTargetList(instructions_, kDestTargetList); |
- g_signal_connect(instructions_, "drag-data-received", |
- G_CALLBACK(&OnDragReceivedThunk), this); |
- |
- g_signal_connect(event_box_.get(), "expose-event", |
- G_CALLBACK(&OnEventBoxExposeThunk), this); |
- UpdateEventBoxPaintability(); |
- |
- bookmark_toolbar_.Own(gtk_toolbar_new()); |
- SetToolBarStyle(); |
- gtk_widget_set_name(bookmark_toolbar_.get(), "chrome-bookmark-toolbar"); |
- gtk_util::SuppressDefaultPainting(bookmark_toolbar_.get()); |
- g_signal_connect(bookmark_toolbar_.get(), "size-allocate", |
- G_CALLBACK(&OnToolbarSizeAllocateThunk), this); |
- gtk_box_pack_start(GTK_BOX(bookmark_hbox_), bookmark_toolbar_.get(), |
- TRUE, TRUE, 0); |
- |
- overflow_button_ = theme_provider_->BuildChromeButton(); |
- g_object_set_data(G_OBJECT(overflow_button_), "left-align-popup", |
- reinterpret_cast<void*>(true)); |
- SetOverflowButtonAppearance(); |
- ConnectFolderButtonEvents(overflow_button_, false); |
- gtk_box_pack_start(GTK_BOX(bookmark_hbox_), overflow_button_, |
- FALSE, FALSE, 0); |
- |
- gtk_drag_dest_set(bookmark_toolbar_.get(), GTK_DEST_DEFAULT_DROP, |
- NULL, 0, kDragAction); |
- gtk_dnd_util::SetDestTargetList(bookmark_toolbar_.get(), kDestTargetList); |
- g_signal_connect(bookmark_toolbar_.get(), "drag-motion", |
- G_CALLBACK(&OnToolbarDragMotionThunk), this); |
- g_signal_connect(bookmark_toolbar_.get(), "drag-leave", |
- G_CALLBACK(&OnDragLeaveThunk), this); |
- g_signal_connect(bookmark_toolbar_.get(), "drag-data-received", |
- G_CALLBACK(&OnDragReceivedThunk), this); |
- |
- GtkWidget* vseparator = theme_provider_->CreateToolbarSeparator(); |
- gtk_box_pack_start(GTK_BOX(bookmark_hbox_), vseparator, |
- FALSE, FALSE, 0); |
- |
- // We pack the button manually (rather than using gtk_button_set_*) so that |
- // we can have finer control over its label. |
- other_bookmarks_button_ = theme_provider_->BuildChromeButton(); |
- ConnectFolderButtonEvents(other_bookmarks_button_, false); |
- GtkWidget* other_padding = gtk_alignment_new(0, 0, 1, 1); |
- gtk_alignment_set_padding(GTK_ALIGNMENT(other_padding), |
- kOtherBookmarksPaddingVertical, |
- kOtherBookmarksPaddingVertical, |
- kOtherBookmarksPaddingHorizontal, |
- kOtherBookmarksPaddingHorizontal); |
- gtk_container_add(GTK_CONTAINER(other_padding), other_bookmarks_button_); |
- gtk_box_pack_start(GTK_BOX(bookmark_hbox_), other_padding, |
- FALSE, FALSE, 0); |
- |
- sync_error_button_ = theme_provider_->BuildChromeButton(); |
- gtk_button_set_image( |
- GTK_BUTTON(sync_error_button_), |
- gtk_image_new_from_pixbuf( |
- ResourceBundle::GetSharedInstance().GetPixbufNamed(IDR_WARNING))); |
- g_signal_connect(sync_error_button_, "button-press-event", |
- G_CALLBACK(OnSyncErrorButtonPressedThunk), this); |
- gtk_box_pack_start(GTK_BOX(bookmark_hbox_), sync_error_button_, |
- FALSE, FALSE, 0); |
- |
- gtk_widget_set_size_request(event_box_.get(), -1, kBookmarkBarMinimumHeight); |
- |
- slide_animation_.reset(new ui::SlideAnimation(this)); |
- |
- ViewIDUtil::SetID(other_bookmarks_button_, VIEW_ID_OTHER_BOOKMARKS); |
- ViewIDUtil::SetID(widget(), VIEW_ID_BOOKMARK_BAR); |
- |
- gtk_widget_show_all(widget()); |
- gtk_widget_hide(widget()); |
-} |
- |
-void BookmarkBarGtk::Show(bool animate) { |
- gtk_widget_show_all(widget()); |
- bool old_floating = floating_; |
- UpdateFloatingState(); |
- // TODO(estade): animate the transition between floating and non. |
- animate = animate && (old_floating == floating_); |
- if (animate) { |
- slide_animation_->Show(); |
- } else { |
- slide_animation_->Reset(1); |
- AnimationProgressed(slide_animation_.get()); |
- } |
- |
- // Hide out behind the findbar. This is rather fragile code, it could |
- // probably be improved. |
- if (floating_) { |
- if (theme_provider_->UseGtkTheme()) { |
- if (GTK_WIDGET_REALIZED(event_box_->parent)) |
- gdk_window_lower(event_box_->parent->window); |
- if (GTK_WIDGET_REALIZED(event_box_.get())) |
- gdk_window_lower(event_box_->window); |
- } else { // Chromium theme mode. |
- if (GTK_WIDGET_REALIZED(paint_box_)) { |
- gdk_window_lower(paint_box_->window); |
- // The event box won't stay below its children's GdkWindows unless we |
- // toggle the above-child property here. If the event box doesn't stay |
- // below its children then events will be routed to it rather than the |
- // children. |
- gtk_event_box_set_above_child(GTK_EVENT_BOX(event_box_.get()), TRUE); |
- gtk_event_box_set_above_child(GTK_EVENT_BOX(event_box_.get()), FALSE); |
- } |
- } |
- } |
- |
- if (sync_ui_util::ShouldShowSyncErrorButton(sync_service_)) { |
- gtk_widget_show(sync_error_button_); |
- } else { |
- gtk_widget_hide(sync_error_button_); |
- } |
- |
- // Maybe show the instructions |
- if (show_instructions_) { |
- gtk_widget_hide(bookmark_toolbar_.get()); |
- gtk_widget_show(instructions_); |
- } else { |
- gtk_widget_hide(instructions_); |
- gtk_widget_show(bookmark_toolbar_.get()); |
- } |
- |
- SetChevronState(); |
-} |
- |
-void BookmarkBarGtk::Hide(bool animate) { |
- UpdateFloatingState(); |
- |
- // After coming out of fullscreen, the browser window sets the bookmark bar |
- // to the "hidden" state, which means we need to show our minimum height. |
- gtk_widget_show(widget()); |
- // Sometimes we get called without a matching call to open. If that happens |
- // then force hide. |
- if (slide_animation_->IsShowing() && animate) { |
- slide_animation_->Hide(); |
- } else { |
- gtk_widget_hide(bookmark_hbox_); |
- slide_animation_->Reset(0); |
- AnimationProgressed(slide_animation_.get()); |
- } |
-} |
- |
-void BookmarkBarGtk::OnStateChanged() { |
- if (sync_ui_util::ShouldShowSyncErrorButton(sync_service_)) { |
- gtk_widget_show(sync_error_button_); |
- } else { |
- gtk_widget_hide(sync_error_button_); |
- } |
-} |
- |
-void BookmarkBarGtk::ShowImportDialog() { |
- ImportDialogGtk::Show(window_->window(), browser_->profile(), |
- importer::FAVORITES); |
-} |
- |
-void BookmarkBarGtk::EnterFullscreen() { |
- if (ShouldBeFloating()) |
- Show(false); |
- else |
- gtk_widget_hide(widget()); |
-} |
- |
-int BookmarkBarGtk::GetHeight() { |
- return event_box_->allocation.height - kBookmarkBarMinimumHeight; |
-} |
- |
-bool BookmarkBarGtk::IsAnimating() { |
- return slide_animation_->is_animating(); |
-} |
- |
-bool BookmarkBarGtk::OnNewTabPage() { |
- return (browser_ && browser_->GetSelectedTabContents() && |
- browser_->GetSelectedTabContents()->ShouldShowBookmarkBar()); |
-} |
- |
-void BookmarkBarGtk::Loaded(BookmarkModel* model) { |
- // If |instructions_| has been nulled, we are in the middle of browser |
- // shutdown. Do nothing. |
- if (!instructions_) |
- return; |
- |
- RemoveAllBookmarkButtons(); |
- CreateAllBookmarkButtons(); |
-} |
- |
-void BookmarkBarGtk::BookmarkModelBeingDeleted(BookmarkModel* model) { |
- // The bookmark model should never be deleted before us. This code exists |
- // to check for regressions in shutdown code and not crash. |
- if (!browser_shutdown::ShuttingDownWithoutClosingBrowsers()) |
- NOTREACHED(); |
- |
- // Do minimal cleanup, presumably we'll be deleted shortly. |
- model_->RemoveObserver(this); |
- model_ = NULL; |
-} |
- |
-void BookmarkBarGtk::BookmarkNodeMoved(BookmarkModel* model, |
- const BookmarkNode* old_parent, |
- int old_index, |
- const BookmarkNode* new_parent, |
- int new_index) { |
- const BookmarkNode* node = new_parent->GetChild(new_index); |
- BookmarkNodeRemoved(model, old_parent, old_index, node); |
- BookmarkNodeAdded(model, new_parent, new_index); |
-} |
- |
-void BookmarkBarGtk::BookmarkNodeAdded(BookmarkModel* model, |
- const BookmarkNode* parent, |
- int index) { |
- const BookmarkNode* node = parent->GetChild(index); |
- if (parent != model_->GetBookmarkBarNode()) { |
- StartThrobbing(node); |
- return; |
- } |
- DCHECK(index >= 0 && index <= GetBookmarkButtonCount()); |
- |
- GtkToolItem* item = CreateBookmarkToolItem(node); |
- gtk_toolbar_insert(GTK_TOOLBAR(bookmark_toolbar_.get()), |
- item, index); |
- if (node->is_folder()) |
- menu_bar_helper_.Add(gtk_bin_get_child(GTK_BIN(item))); |
- |
- SetInstructionState(); |
- SetChevronState(); |
- |
- MessageLoop::current()->PostTask(FROM_HERE, |
- method_factory_.NewRunnableMethod( |
- &BookmarkBarGtk::StartThrobbing, node)); |
-} |
- |
-void BookmarkBarGtk::BookmarkNodeRemoved(BookmarkModel* model, |
- const BookmarkNode* parent, |
- int old_index, |
- const BookmarkNode* node) { |
- if (parent != model_->GetBookmarkBarNode()) { |
- // We only care about nodes on the bookmark bar. |
- return; |
- } |
- DCHECK(old_index >= 0 && old_index < GetBookmarkButtonCount()); |
- |
- GtkWidget* to_remove = GTK_WIDGET(gtk_toolbar_get_nth_item( |
- GTK_TOOLBAR(bookmark_toolbar_.get()), old_index)); |
- if (node->is_folder()) |
- menu_bar_helper_.Remove(gtk_bin_get_child(GTK_BIN(to_remove))); |
- gtk_container_remove(GTK_CONTAINER(bookmark_toolbar_.get()), |
- to_remove); |
- |
- SetInstructionState(); |
- SetChevronState(); |
-} |
- |
-void BookmarkBarGtk::BookmarkNodeChanged(BookmarkModel* model, |
- const BookmarkNode* node) { |
- if (node->GetParent() != model_->GetBookmarkBarNode()) { |
- // We only care about nodes on the bookmark bar. |
- return; |
- } |
- int index = model_->GetBookmarkBarNode()->IndexOfChild(node); |
- DCHECK(index != -1); |
- |
- GtkToolItem* item = gtk_toolbar_get_nth_item( |
- GTK_TOOLBAR(bookmark_toolbar_.get()), index); |
- GtkWidget* button = gtk_bin_get_child(GTK_BIN(item)); |
- bookmark_utils::ConfigureButtonForNode(node, model, button, theme_provider_); |
- SetChevronState(); |
-} |
- |
-void BookmarkBarGtk::BookmarkNodeFavIconLoaded(BookmarkModel* model, |
- const BookmarkNode* node) { |
- BookmarkNodeChanged(model, node); |
-} |
- |
-void BookmarkBarGtk::BookmarkNodeChildrenReordered(BookmarkModel* model, |
- const BookmarkNode* node) { |
- if (node != model_->GetBookmarkBarNode()) |
- return; // We only care about reordering of the bookmark bar node. |
- |
- // Purge and rebuild the bar. |
- RemoveAllBookmarkButtons(); |
- CreateAllBookmarkButtons(); |
-} |
- |
-void BookmarkBarGtk::CreateAllBookmarkButtons() { |
- const BookmarkNode* bar = model_->GetBookmarkBarNode(); |
- DCHECK(bar && model_->other_node()); |
- |
- // Create a button for each of the children on the bookmark bar. |
- for (int i = 0; i < bar->GetChildCount(); ++i) { |
- const BookmarkNode* node = bar->GetChild(i); |
- GtkToolItem* item = CreateBookmarkToolItem(node); |
- gtk_toolbar_insert(GTK_TOOLBAR(bookmark_toolbar_.get()), item, -1); |
- if (node->is_folder()) |
- menu_bar_helper_.Add(gtk_bin_get_child(GTK_BIN(item))); |
- } |
- |
- bookmark_utils::ConfigureButtonForNode(model_->other_node(), |
- model_, other_bookmarks_button_, theme_provider_); |
- |
- SetInstructionState(); |
- SetChevronState(); |
-} |
- |
-void BookmarkBarGtk::SetInstructionState() { |
- show_instructions_ = (model_->GetBookmarkBarNode()->GetChildCount() == 0); |
- if (show_instructions_) { |
- gtk_widget_hide(bookmark_toolbar_.get()); |
- gtk_widget_show_all(instructions_); |
- } else { |
- gtk_widget_hide(instructions_); |
- gtk_widget_show(bookmark_toolbar_.get()); |
- } |
-} |
- |
-void BookmarkBarGtk::SetChevronState() { |
- if (!GTK_WIDGET_VISIBLE(bookmark_hbox_)) |
- return; |
- |
- if (show_instructions_) { |
- gtk_widget_hide(overflow_button_); |
- return; |
- } |
- |
- int extra_space = 0; |
- if (GTK_WIDGET_VISIBLE(overflow_button_)) |
- extra_space = overflow_button_->allocation.width; |
- |
- int overflow_idx = GetFirstHiddenBookmark(extra_space, NULL); |
- if (overflow_idx == -1) |
- gtk_widget_hide(overflow_button_); |
- else |
- gtk_widget_show_all(overflow_button_); |
-} |
- |
-void BookmarkBarGtk::RemoveAllBookmarkButtons() { |
- gtk_util::RemoveAllChildren(bookmark_toolbar_.get()); |
- menu_bar_helper_.Clear(); |
- menu_bar_helper_.Add(other_bookmarks_button_); |
- menu_bar_helper_.Add(overflow_button_); |
-} |
- |
-int BookmarkBarGtk::GetBookmarkButtonCount() { |
- GList* children = gtk_container_get_children( |
- GTK_CONTAINER(bookmark_toolbar_.get())); |
- int count = g_list_length(children); |
- g_list_free(children); |
- return count; |
-} |
- |
-void BookmarkBarGtk::SetOverflowButtonAppearance() { |
- GtkWidget* former_child = gtk_bin_get_child(GTK_BIN(overflow_button_)); |
- if (former_child) |
- gtk_widget_destroy(former_child); |
- |
- GtkWidget* new_child = theme_provider_->UseGtkTheme() ? |
- gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_NONE) : |
- gtk_image_new_from_pixbuf(ResourceBundle::GetSharedInstance(). |
- GetRTLEnabledPixbufNamed(IDR_BOOKMARK_BAR_CHEVRONS)); |
- |
- gtk_container_add(GTK_CONTAINER(overflow_button_), new_child); |
- SetChevronState(); |
-} |
- |
-int BookmarkBarGtk::GetFirstHiddenBookmark( |
- int extra_space, std::vector<GtkWidget*>* showing_folders) { |
- int rv = 0; |
- bool overflow = false; |
- GList* toolbar_items = |
- gtk_container_get_children(GTK_CONTAINER(bookmark_toolbar_.get())); |
- for (GList* iter = toolbar_items; iter; iter = g_list_next(iter)) { |
- GtkWidget* tool_item = reinterpret_cast<GtkWidget*>(iter->data); |
- if (gtk_widget_get_direction(tool_item) == GTK_TEXT_DIR_RTL) { |
- overflow = (tool_item->allocation.x + tool_item->style->xthickness < |
- bookmark_toolbar_.get()->allocation.x - extra_space); |
- } else { |
- overflow = |
- (tool_item->allocation.x + tool_item->allocation.width + |
- tool_item->style->xthickness > |
- bookmark_toolbar_.get()->allocation.width + |
- bookmark_toolbar_.get()->allocation.x + extra_space); |
- } |
- overflow = overflow || tool_item->allocation.x == -1; |
- |
- if (overflow) |
- break; |
- |
- if (showing_folders && |
- model_->GetBookmarkBarNode()->GetChild(rv)->is_folder()) { |
- showing_folders->push_back(gtk_bin_get_child(GTK_BIN(tool_item))); |
- } |
- rv++; |
- } |
- |
- g_list_free(toolbar_items); |
- |
- if (!overflow) |
- return -1; |
- |
- return rv; |
-} |
- |
-bool BookmarkBarGtk::ShouldBeFloating() { |
- return (!IsAlwaysShown() || (window_ && window_->IsFullscreen())) && |
- window_ && window_->GetDisplayedTabContents() && |
- window_->GetDisplayedTabContents()->ShouldShowBookmarkBar(); |
-} |
- |
-void BookmarkBarGtk::UpdateFloatingState() { |
- bool old_floating = floating_; |
- floating_ = ShouldBeFloating(); |
- if (floating_ == old_floating) |
- return; |
- |
- if (floating_) { |
-#if !defined(OS_CHROMEOS) |
- gtk_event_box_set_visible_window(GTK_EVENT_BOX(paint_box_), TRUE); |
-#endif |
- GdkColor stroke_color = theme_provider_->UseGtkTheme() ? |
- theme_provider_->GetBorderColor() : |
- theme_provider_->GetGdkColor(BrowserThemeProvider::COLOR_NTP_HEADER); |
- gtk_util::ActAsRoundedWindow(paint_box_, stroke_color, kNTPRoundedness, |
- gtk_util::ROUNDED_ALL, gtk_util::BORDER_ALL); |
- |
- gtk_alignment_set_padding(GTK_ALIGNMENT(ntp_padding_box_), |
- kTopBottomNTPPadding, kTopBottomNTPPadding, |
- kLeftRightNTPPadding, kLeftRightNTPPadding); |
- gtk_container_set_border_width(GTK_CONTAINER(bookmark_hbox_), kNTPPadding); |
- } else { |
- gtk_util::StopActingAsRoundedWindow(paint_box_); |
-#if !defined(OS_CHROMEOS) |
- gtk_event_box_set_visible_window(GTK_EVENT_BOX(paint_box_), FALSE); |
-#endif |
- gtk_alignment_set_padding(GTK_ALIGNMENT(ntp_padding_box_), 0, 0, 0, 0); |
- gtk_container_set_border_width(GTK_CONTAINER(bookmark_hbox_), 0); |
- } |
- |
- UpdateEventBoxPaintability(); |
- // |window_| can be NULL during testing. |
- if (window_) { |
- window_->BookmarkBarIsFloating(floating_); |
- |
- // Listen for parent size allocations. |
- if (floating_ && widget()->parent) { |
- // Only connect once. |
- if (g_signal_handler_find(widget()->parent, G_SIGNAL_MATCH_FUNC, |
- 0, 0, NULL, reinterpret_cast<gpointer>(OnParentSizeAllocateThunk), |
- NULL) == 0) { |
- g_signal_connect(widget()->parent, "size-allocate", |
- G_CALLBACK(OnParentSizeAllocateThunk), this); |
- } |
- } |
- } |
-} |
- |
-void BookmarkBarGtk::UpdateEventBoxPaintability() { |
- gtk_widget_set_app_paintable(event_box_.get(), |
- !theme_provider_->UseGtkTheme() || floating_); |
- // When using the GTK+ theme, we need to have the event box be visible so |
- // buttons don't get a halo color from the background. When using Chromium |
- // themes, we want to let the background show through the toolbar. |
- |
-#if !defined(OS_CHROMEOS) |
- gtk_event_box_set_visible_window(GTK_EVENT_BOX(event_box_.get()), |
- theme_provider_->UseGtkTheme()); |
-#endif |
-} |
- |
-void BookmarkBarGtk::PaintEventBox() { |
- gfx::Size tab_contents_size; |
- if (GetTabContentsSize(&tab_contents_size) && |
- tab_contents_size != last_tab_contents_size_) { |
- last_tab_contents_size_ = tab_contents_size; |
- gtk_widget_queue_draw(event_box_.get()); |
- } |
-} |
- |
-bool BookmarkBarGtk::GetTabContentsSize(gfx::Size* size) { |
- Browser* browser = browser_; |
- if (!browser) { |
- NOTREACHED(); |
- return false; |
- } |
- TabContents* tab_contents = browser->GetSelectedTabContents(); |
- if (!tab_contents) { |
- // It is possible to have a browser but no TabContents while under testing, |
- // so don't NOTREACHED() and error the program. |
- return false; |
- } |
- if (!tab_contents->view()) { |
- NOTREACHED(); |
- return false; |
- } |
- *size = tab_contents->view()->GetContainerSize(); |
- return true; |
-} |
- |
-void BookmarkBarGtk::StartThrobbing(const BookmarkNode* node) { |
- const BookmarkNode* parent_on_bb = NULL; |
- for (const BookmarkNode* parent = node; parent; |
- parent = parent->GetParent()) { |
- if (parent->GetParent() == model_->GetBookmarkBarNode()) { |
- parent_on_bb = parent; |
- break; |
- } |
- } |
- |
- GtkWidget* widget_to_throb = NULL; |
- |
- if (!parent_on_bb) { |
- // Descendant of "Other Bookmarks". |
- widget_to_throb = other_bookmarks_button_; |
- } else { |
- int hidden = GetFirstHiddenBookmark(0, NULL); |
- int idx = model_->GetBookmarkBarNode()->IndexOfChild(parent_on_bb); |
- |
- if (hidden >= 0 && hidden <= idx) { |
- widget_to_throb = overflow_button_; |
- } else { |
- if (parent_on_bb->is_url()) |
- return; |
- widget_to_throb = gtk_bin_get_child(GTK_BIN(gtk_toolbar_get_nth_item( |
- GTK_TOOLBAR(bookmark_toolbar_.get()), idx))); |
- } |
- } |
- |
- SetThrobbingWidget(widget_to_throb); |
-} |
- |
-void BookmarkBarGtk::SetThrobbingWidget(GtkWidget* widget) { |
- if (throbbing_widget_) { |
- HoverControllerGtk* hover_controller = |
- HoverControllerGtk::GetHoverControllerGtk(throbbing_widget_); |
- if (hover_controller) |
- hover_controller->StartThrobbing(0); |
- |
- g_signal_handlers_disconnect_by_func( |
- throbbing_widget_, |
- reinterpret_cast<gpointer>(OnThrobbingWidgetDestroyThunk), |
- this); |
- g_object_unref(throbbing_widget_); |
- throbbing_widget_ = NULL; |
- } |
- |
- if (widget) { |
- throbbing_widget_ = widget; |
- g_object_ref(throbbing_widget_); |
- g_signal_connect(throbbing_widget_, "destroy", |
- G_CALLBACK(OnThrobbingWidgetDestroyThunk), this); |
- |
- HoverControllerGtk* hover_controller = |
- HoverControllerGtk::GetHoverControllerGtk(throbbing_widget_); |
- if (hover_controller) |
- hover_controller->StartThrobbing(4); |
- } |
-} |
- |
-bool BookmarkBarGtk::IsAlwaysShown() { |
- return profile_->GetPrefs()->GetBoolean(prefs::kShowBookmarkBar); |
-} |
- |
-void BookmarkBarGtk::AnimationProgressed(const ui::Animation* animation) { |
- DCHECK_EQ(animation, slide_animation_.get()); |
- |
- int max_height = ShouldBeFloating() ? |
- kBookmarkBarNTPHeight : kBookmarkBarHeight; |
- gint height = |
- static_cast<gint>(animation->GetCurrentValue() * |
- (max_height - kBookmarkBarMinimumHeight)) + |
- kBookmarkBarMinimumHeight; |
- gtk_widget_set_size_request(event_box_.get(), -1, height); |
-} |
- |
-void BookmarkBarGtk::AnimationEnded(const ui::Animation* animation) { |
- DCHECK_EQ(animation, slide_animation_.get()); |
- |
- if (!slide_animation_->IsShowing()) { |
- gtk_widget_hide(bookmark_hbox_); |
- |
- // We can be windowless during unit tests. |
- if (window_) { |
- // Because of our constant resizing and our toolbar/bookmark bar overlap |
- // shenanigans, gtk+ gets confused, partially draws parts of the bookmark |
- // bar into the toolbar and than doesn't queue a redraw to fix it. So do |
- // it manually by telling the toolbar area to redraw itself. |
- window_->QueueToolbarRedraw(); |
- } |
- } |
-} |
- |
-void BookmarkBarGtk::Observe(NotificationType type, |
- const NotificationSource& source, |
- const NotificationDetails& details) { |
- if (type == NotificationType::BROWSER_THEME_CHANGED) { |
- if (model_) { |
- // Regenerate the bookmark bar with all new objects with their theme |
- // properties set correctly for the new theme. |
- RemoveAllBookmarkButtons(); |
- CreateAllBookmarkButtons(); |
- } else { |
- DLOG(ERROR) << "Received a theme change notification while we " |
- << "don't have a BookmarkModel. Taking no action."; |
- } |
- |
- UpdateEventBoxPaintability(); |
- |
- GdkColor paint_box_color = |
- theme_provider_->GetGdkColor(BrowserThemeProvider::COLOR_TOOLBAR); |
- gtk_widget_modify_bg(paint_box_, GTK_STATE_NORMAL, &paint_box_color); |
- |
- if (floating_) { |
- GdkColor stroke_color = theme_provider_->UseGtkTheme() ? |
- theme_provider_->GetBorderColor() : |
- theme_provider_->GetGdkColor(BrowserThemeProvider::COLOR_NTP_HEADER); |
- gtk_util::SetRoundedWindowBorderColor(paint_box_, stroke_color); |
- } |
- |
- SetOverflowButtonAppearance(); |
- } |
-} |
- |
-GtkWidget* BookmarkBarGtk::CreateBookmarkButton(const BookmarkNode* node) { |
- GtkWidget* button = theme_provider_->BuildChromeButton(); |
- bookmark_utils::ConfigureButtonForNode(node, model_, button, theme_provider_); |
- |
- // The tool item is also a source for dragging |
- gtk_drag_source_set(button, GDK_BUTTON1_MASK, NULL, 0, |
- static_cast<GdkDragAction>(GDK_ACTION_MOVE | GDK_ACTION_COPY)); |
- int target_mask = bookmark_utils::GetCodeMask(node->is_folder()); |
- gtk_dnd_util::SetSourceTargetListFromCodeMask(button, target_mask); |
- g_signal_connect(button, "drag-begin", |
- G_CALLBACK(&OnButtonDragBeginThunk), this); |
- g_signal_connect(button, "drag-end", |
- G_CALLBACK(&OnButtonDragEndThunk), this); |
- g_signal_connect(button, "drag-data-get", |
- G_CALLBACK(&OnButtonDragGetThunk), this); |
- // We deliberately don't connect to "drag-data-delete" because the action of |
- // moving a button will regenerate all the contents of the bookmarks bar |
- // anyway. |
- |
- if (node->is_url()) { |
- // Connect to 'button-release-event' instead of 'clicked' because we need |
- // access to the modifier keys and we do different things on each |
- // button. |
- g_signal_connect(button, "button-press-event", |
- G_CALLBACK(OnButtonPressedThunk), this); |
- g_signal_connect(button, "clicked", |
- G_CALLBACK(OnClickedThunk), this); |
- gtk_util::SetButtonTriggersNavigation(button); |
- } else { |
- ConnectFolderButtonEvents(button, true); |
- } |
- |
- return button; |
-} |
- |
-GtkToolItem* BookmarkBarGtk::CreateBookmarkToolItem(const BookmarkNode* node) { |
- GtkWidget* button = CreateBookmarkButton(node); |
- g_object_set_data(G_OBJECT(button), "left-align-popup", |
- reinterpret_cast<void*>(true)); |
- |
- GtkToolItem* item = gtk_tool_item_new(); |
- gtk_container_add(GTK_CONTAINER(item), button); |
- gtk_widget_show_all(GTK_WIDGET(item)); |
- |
- return item; |
-} |
- |
-void BookmarkBarGtk::ConnectFolderButtonEvents(GtkWidget* widget, |
- bool is_tool_item) { |
- // For toolbar items (i.e. not the overflow button or other bookmarks |
- // button), we handle motion and highlighting manually. |
- gtk_drag_dest_set(widget, |
- is_tool_item ? GTK_DEST_DEFAULT_DROP : |
- GTK_DEST_DEFAULT_ALL, |
- NULL, |
- 0, |
- kDragAction); |
- gtk_dnd_util::SetDestTargetList(widget, kDestTargetList); |
- g_signal_connect(widget, "drag-data-received", |
- G_CALLBACK(&OnDragReceivedThunk), this); |
- if (is_tool_item) { |
- g_signal_connect(widget, "drag-motion", |
- G_CALLBACK(&OnFolderDragMotionThunk), this); |
- g_signal_connect(widget, "drag-leave", |
- G_CALLBACK(&OnDragLeaveThunk), this); |
- } |
- |
- g_signal_connect(widget, "button-press-event", |
- G_CALLBACK(OnButtonPressedThunk), this); |
- g_signal_connect(widget, "clicked", |
- G_CALLBACK(OnFolderClickedThunk), this); |
- |
- // Accept middle mouse clicking (which opens all). This must be called after |
- // connecting to "button-press-event" because the handler it attaches stops |
- // the propagation of that signal. |
- gtk_util::SetButtonClickableByMouseButtons(widget, true, true, false); |
-} |
- |
-const BookmarkNode* BookmarkBarGtk::GetNodeForToolButton(GtkWidget* widget) { |
- // First check to see if |button| is special cased. |
- if (widget == other_bookmarks_button_) |
- return model_->other_node(); |
- else if (widget == event_box_.get() || widget == overflow_button_) |
- return model_->GetBookmarkBarNode(); |
- |
- // Search the contents of |bookmark_toolbar_| for the corresponding widget |
- // and find its index. |
- GtkWidget* item_to_find = gtk_widget_get_parent(widget); |
- int index_to_use = -1; |
- int index = 0; |
- GList* children = gtk_container_get_children( |
- GTK_CONTAINER(bookmark_toolbar_.get())); |
- for (GList* item = children; item; item = item->next, index++) { |
- if (item->data == item_to_find) { |
- index_to_use = index; |
- break; |
- } |
- } |
- g_list_free(children); |
- |
- if (index_to_use != -1) |
- return model_->GetBookmarkBarNode()->GetChild(index_to_use); |
- |
- return NULL; |
-} |
- |
-void BookmarkBarGtk::PopupMenuForNode(GtkWidget* sender, |
- const BookmarkNode* node, |
- GdkEventButton* event) { |
- if (!model_->IsLoaded()) { |
- // Don't do anything if the model isn't loaded. |
- return; |
- } |
- |
- const BookmarkNode* parent = NULL; |
- std::vector<const BookmarkNode*> nodes; |
- if (sender == other_bookmarks_button_) { |
- nodes.push_back(node); |
- parent = model_->GetBookmarkBarNode(); |
- } else if (sender != bookmark_toolbar_.get()) { |
- nodes.push_back(node); |
- parent = node->GetParent(); |
- } else { |
- parent = model_->GetBookmarkBarNode(); |
- nodes.push_back(parent); |
- } |
- |
- GtkWindow* window = GTK_WINDOW(gtk_widget_get_toplevel(sender)); |
- current_context_menu_controller_.reset( |
- new BookmarkContextMenuController( |
- window, this, profile_, page_navigator_, parent, nodes)); |
- current_context_menu_.reset( |
- new MenuGtk(NULL, current_context_menu_controller_->menu_model())); |
- current_context_menu_->PopupAsContext(event->time); |
-} |
- |
-gboolean BookmarkBarGtk::OnButtonPressed(GtkWidget* sender, |
- GdkEventButton* event) { |
- last_pressed_coordinates_ = gfx::Point(event->x, event->y); |
- |
- if (event->button == 3 && GTK_WIDGET_VISIBLE(bookmark_hbox_)) { |
- const BookmarkNode* node = GetNodeForToolButton(sender); |
- DCHECK(node); |
- DCHECK(page_navigator_); |
- PopupMenuForNode(sender, node, event); |
- } |
- |
- return FALSE; |
-} |
- |
-gboolean BookmarkBarGtk::OnSyncErrorButtonPressed(GtkWidget* sender, |
- GdkEventButton* event) { |
- if (sender == sync_error_button_) { |
- DCHECK(sync_service_ && !sync_service_->IsManaged()); |
- sync_service_->ShowLoginDialog(NULL); |
- } |
- |
- return FALSE; |
-} |
- |
-void BookmarkBarGtk::OnClicked(GtkWidget* sender) { |
- const BookmarkNode* node = GetNodeForToolButton(sender); |
- DCHECK(node); |
- DCHECK(node->is_url()); |
- DCHECK(page_navigator_); |
- |
- page_navigator_->OpenURL( |
- node->GetURL(), GURL(), |
- gtk_util::DispositionForCurrentButtonPressEvent(), |
- PageTransition::AUTO_BOOKMARK); |
- |
- UserMetrics::RecordAction(UserMetricsAction("ClickedBookmarkBarURLButton"), |
- profile_); |
-} |
- |
-void BookmarkBarGtk::OnButtonDragBegin(GtkWidget* button, |
- GdkDragContext* drag_context) { |
- // The parent tool item might be removed during the drag. Ref it so |button| |
- // won't get destroyed. |
- g_object_ref(button->parent); |
- |
- const BookmarkNode* node = GetNodeForToolButton(button); |
- DCHECK(!dragged_node_); |
- dragged_node_ = node; |
- DCHECK(dragged_node_); |
- |
- drag_icon_ = bookmark_utils::GetDragRepresentationForNode( |
- node, model_, theme_provider_); |
- |
- // We have to jump through some hoops to get the drag icon to line up because |
- // it is a different size than the button. |
- GtkRequisition req; |
- gtk_widget_size_request(drag_icon_, &req); |
- gfx::Rect button_rect = gtk_util::WidgetBounds(button); |
- gfx::Point drag_icon_relative = |
- gfx::Rect(req.width, req.height).CenterPoint().Add( |
- (last_pressed_coordinates_.Subtract(button_rect.CenterPoint()))); |
- gtk_drag_set_icon_widget(drag_context, drag_icon_, |
- drag_icon_relative.x(), |
- drag_icon_relative.y()); |
- |
- // Hide our node, but reserve space for it on the toolbar. |
- int index = gtk_toolbar_get_item_index(GTK_TOOLBAR(bookmark_toolbar_.get()), |
- GTK_TOOL_ITEM(button->parent)); |
- gtk_widget_hide(button); |
- toolbar_drop_item_ = CreateBookmarkToolItem(dragged_node_); |
- g_object_ref_sink(GTK_OBJECT(toolbar_drop_item_)); |
- gtk_toolbar_set_drop_highlight_item(GTK_TOOLBAR(bookmark_toolbar_.get()), |
- GTK_TOOL_ITEM(toolbar_drop_item_), index); |
- // Make sure it stays hidden for the duration of the drag. |
- gtk_widget_set_no_show_all(button, TRUE); |
-} |
- |
-void BookmarkBarGtk::OnButtonDragEnd(GtkWidget* button, |
- GdkDragContext* drag_context) { |
- gtk_widget_show(button); |
- gtk_widget_set_no_show_all(button, FALSE); |
- |
- ClearToolbarDropHighlighting(); |
- |
- DCHECK(dragged_node_); |
- dragged_node_ = NULL; |
- |
- DCHECK(drag_icon_); |
- gtk_widget_destroy(drag_icon_); |
- drag_icon_ = NULL; |
- |
- g_object_unref(button->parent); |
-} |
- |
-void BookmarkBarGtk::OnButtonDragGet(GtkWidget* widget, GdkDragContext* context, |
- GtkSelectionData* selection_data, |
- guint target_type, guint time) { |
- const BookmarkNode* node = bookmark_utils::BookmarkNodeForWidget(widget); |
- bookmark_utils::WriteBookmarkToSelection(node, selection_data, target_type, |
- profile_); |
-} |
- |
-void BookmarkBarGtk::OnFolderClicked(GtkWidget* sender) { |
- // Stop its throbbing, if any. |
- HoverControllerGtk* hover_controller = |
- HoverControllerGtk::GetHoverControllerGtk(sender); |
- if (hover_controller) |
- hover_controller->StartThrobbing(0); |
- |
- GdkEvent* event = gtk_get_current_event(); |
- if (event->button.button == 1) { |
- PopupForButton(sender); |
- } else if (event->button.button == 2) { |
- const BookmarkNode* node = GetNodeForToolButton(sender); |
- bookmark_utils::OpenAll(window_->GetNativeHandle(), |
- profile_, page_navigator_, |
- node, NEW_BACKGROUND_TAB); |
- } |
-} |
- |
-gboolean BookmarkBarGtk::ItemDraggedOverToolbar(GdkDragContext* context, |
- int index, |
- guint time) { |
- GdkAtom target_type = |
- gtk_drag_dest_find_target(bookmark_toolbar_.get(), context, NULL); |
- if (target_type == GDK_NONE) { |
- // We shouldn't act like a drop target when something that we can't deal |
- // with is dragged over the toolbar. |
- return FALSE; |
- } |
- |
- if (!toolbar_drop_item_) { |
- if (dragged_node_) { |
- toolbar_drop_item_ = CreateBookmarkToolItem(dragged_node_); |
- g_object_ref_sink(GTK_OBJECT(toolbar_drop_item_)); |
- } else { |
- // Create a fake item the size of other_node(). |
- // |
- // TODO(erg): Maybe somehow figure out the real size for the drop target? |
- toolbar_drop_item_ = |
- CreateBookmarkToolItem(model_->other_node()); |
- g_object_ref_sink(GTK_OBJECT(toolbar_drop_item_)); |
- } |
- } |
- |
- gtk_toolbar_set_drop_highlight_item(GTK_TOOLBAR(bookmark_toolbar_.get()), |
- GTK_TOOL_ITEM(toolbar_drop_item_), |
- index); |
- if (target_type == |
- gtk_dnd_util::GetAtomForTarget(gtk_dnd_util::CHROME_BOOKMARK_ITEM)) { |
- gdk_drag_status(context, GDK_ACTION_MOVE, time); |
- } else { |
- gdk_drag_status(context, GDK_ACTION_COPY, time); |
- } |
- |
- return TRUE; |
-} |
- |
-gboolean BookmarkBarGtk::OnToolbarDragMotion(GtkWidget* toolbar, |
- GdkDragContext* context, |
- gint x, |
- gint y, |
- guint time) { |
- gint index = gtk_toolbar_get_drop_index(GTK_TOOLBAR(toolbar), x, y); |
- return ItemDraggedOverToolbar(context, index, time); |
-} |
- |
-int BookmarkBarGtk::GetToolbarIndexForDragOverFolder( |
- GtkWidget* button, gint x) { |
- int margin = std::min(15, static_cast<int>(0.3 * button->allocation.width)); |
- if (x > margin && x < (button->allocation.width - margin)) |
- return -1; |
- |
- gint index = gtk_toolbar_get_item_index(GTK_TOOLBAR(bookmark_toolbar_.get()), |
- GTK_TOOL_ITEM(button->parent)); |
- if (x > margin) |
- index++; |
- return index; |
-} |
- |
-gboolean BookmarkBarGtk::OnFolderDragMotion(GtkWidget* button, |
- GdkDragContext* context, |
- gint x, |
- gint y, |
- guint time) { |
- GdkAtom target_type = gtk_drag_dest_find_target(button, context, NULL); |
- if (target_type == GDK_NONE) |
- return FALSE; |
- |
- int index = GetToolbarIndexForDragOverFolder(button, x); |
- if (index < 0) { |
- ClearToolbarDropHighlighting(); |
- |
- // Drag is over middle of folder. |
- gtk_drag_highlight(button); |
- if (target_type == |
- gtk_dnd_util::GetAtomForTarget(gtk_dnd_util::CHROME_BOOKMARK_ITEM)) { |
- gdk_drag_status(context, GDK_ACTION_MOVE, time); |
- } else { |
- gdk_drag_status(context, GDK_ACTION_COPY, time); |
- } |
- |
- return TRUE; |
- } |
- |
- // Remove previous highlighting. |
- gtk_drag_unhighlight(button); |
- return ItemDraggedOverToolbar(context, index, time); |
-} |
- |
-void BookmarkBarGtk::ClearToolbarDropHighlighting() { |
- if (toolbar_drop_item_) { |
- g_object_unref(toolbar_drop_item_); |
- toolbar_drop_item_ = NULL; |
- } |
- |
- gtk_toolbar_set_drop_highlight_item(GTK_TOOLBAR(bookmark_toolbar_.get()), |
- NULL, 0); |
-} |
- |
-void BookmarkBarGtk::OnDragLeave(GtkWidget* sender, |
- GdkDragContext* context, |
- guint time) { |
- if (GTK_IS_BUTTON(sender)) |
- gtk_drag_unhighlight(sender); |
- |
- ClearToolbarDropHighlighting(); |
-} |
- |
-void BookmarkBarGtk::OnToolbarSizeAllocate(GtkWidget* widget, |
- GtkAllocation* allocation) { |
- if (bookmark_toolbar_.get()->allocation.width == |
- last_allocation_width_) { |
- // If the width hasn't changed, then the visibility of the chevron |
- // doesn't need to change. This check prevents us from getting stuck in a |
- // loop where allocates are queued indefinitely while the visibility of |
- // overflow chevron toggles without actual resizes of the toolbar. |
- return; |
- } |
- last_allocation_width_ = bookmark_toolbar_.get()->allocation.width; |
- |
- SetChevronState(); |
-} |
- |
-void BookmarkBarGtk::OnDragReceived(GtkWidget* widget, |
- GdkDragContext* context, |
- gint x, gint y, |
- GtkSelectionData* selection_data, |
- guint target_type, guint time) { |
- gboolean dnd_success = FALSE; |
- gboolean delete_selection_data = FALSE; |
- |
- const BookmarkNode* dest_node = model_->GetBookmarkBarNode(); |
- gint index; |
- if (widget == bookmark_toolbar_.get()) { |
- index = gtk_toolbar_get_drop_index( |
- GTK_TOOLBAR(bookmark_toolbar_.get()), x, y); |
- } else if (widget == instructions_) { |
- dest_node = model_->GetBookmarkBarNode(); |
- index = 0; |
- } else { |
- index = GetToolbarIndexForDragOverFolder(widget, x); |
- if (index < 0) { |
- dest_node = GetNodeForToolButton(widget); |
- index = dest_node->GetChildCount(); |
- } |
- } |
- |
- switch (target_type) { |
- case gtk_dnd_util::CHROME_BOOKMARK_ITEM: { |
- std::vector<const BookmarkNode*> nodes = |
- bookmark_utils::GetNodesFromSelection(context, selection_data, |
- target_type, |
- profile_, |
- &delete_selection_data, |
- &dnd_success); |
- DCHECK(!nodes.empty()); |
- for (std::vector<const BookmarkNode*>::iterator it = nodes.begin(); |
- it != nodes.end(); ++it) { |
- model_->Move(*it, dest_node, index); |
- index = dest_node->IndexOfChild(*it) + 1; |
- } |
- break; |
- } |
- |
- case gtk_dnd_util::CHROME_NAMED_URL: { |
- dnd_success = bookmark_utils::CreateNewBookmarkFromNamedUrl( |
- selection_data, model_, dest_node, index); |
- break; |
- } |
- |
- case gtk_dnd_util::TEXT_URI_LIST: { |
- dnd_success = bookmark_utils::CreateNewBookmarksFromURIList( |
- selection_data, model_, dest_node, index); |
- break; |
- } |
- |
- case gtk_dnd_util::NETSCAPE_URL: { |
- dnd_success = bookmark_utils::CreateNewBookmarkFromNetscapeURL( |
- selection_data, model_, dest_node, index); |
- break; |
- } |
- |
- case gtk_dnd_util::TEXT_PLAIN: { |
- guchar* text = gtk_selection_data_get_text(selection_data); |
- if (!text) |
- break; |
- GURL url(reinterpret_cast<char*>(text)); |
- g_free(text); |
- // TODO(estade): It would be nice to head this case off at drag motion, |
- // so that it doesn't look like we can drag onto the bookmark bar. |
- if (!url.is_valid()) |
- break; |
- std::string title = bookmark_utils::GetNameForURL(url); |
- model_->AddURL(dest_node, index, UTF8ToUTF16(title), url); |
- dnd_success = TRUE; |
- break; |
- } |
- } |
- |
- gtk_drag_finish(context, dnd_success, delete_selection_data, time); |
-} |
- |
-gboolean BookmarkBarGtk::OnEventBoxExpose(GtkWidget* widget, |
- GdkEventExpose* event) { |
- GtkThemeProvider* theme_provider = theme_provider_; |
- |
- // We don't need to render the toolbar image in GTK mode, except when |
- // detached. |
- if (theme_provider->UseGtkTheme() && !floating_) |
- return FALSE; |
- |
- if (!floating_) { |
- cairo_t* cr = gdk_cairo_create(GDK_DRAWABLE(widget->window)); |
- gdk_cairo_rectangle(cr, &event->area); |
- cairo_clip(cr); |
- |
- // Paint the background theme image. |
- gfx::Point tabstrip_origin = |
- tabstrip_origin_provider_->GetTabStripOriginForWidget(widget); |
- gtk_util::DrawThemedToolbarBackground(widget, cr, event, tabstrip_origin, |
- theme_provider); |
- |
- cairo_destroy(cr); |
- } else { |
- gfx::Size tab_contents_size; |
- if (!GetTabContentsSize(&tab_contents_size)) |
- return FALSE; |
- gfx::CanvasSkiaPaint canvas(event, true); |
- |
- gfx::Rect area = GTK_WIDGET_NO_WINDOW(widget) ? |
- gfx::Rect(widget->allocation) : |
- gfx::Rect(0, 0, widget->allocation.width, widget->allocation.height); |
- NtpBackgroundUtil::PaintBackgroundDetachedMode(theme_provider, &canvas, |
- area, tab_contents_size.height()); |
- } |
- |
- return FALSE; // Propagate expose to children. |
-} |
- |
-void BookmarkBarGtk::OnEventBoxDestroy(GtkWidget* widget) { |
- if (model_) |
- model_->RemoveObserver(this); |
- |
- if (sync_service_) |
- sync_service_->RemoveObserver(this); |
-} |
- |
-void BookmarkBarGtk::OnParentSizeAllocate(GtkWidget* widget, |
- GtkAllocation* allocation) { |
- // In floating mode, our layout depends on the size of the tab contents. |
- // We get the size-allocate signal before the tab contents does, hence we |
- // need to post a delayed task so we will paint correctly. Note that |
- // gtk_widget_queue_draw by itself does not work, despite that it claims to |
- // be asynchronous. |
- if (floating_) { |
- MessageLoop::current()->PostTask(FROM_HERE, |
- method_factory_.NewRunnableMethod( |
- &BookmarkBarGtk::PaintEventBox)); |
- } |
-} |
- |
-void BookmarkBarGtk::OnThrobbingWidgetDestroy(GtkWidget* widget) { |
- SetThrobbingWidget(NULL); |
-} |
- |
-// MenuBarHelper::Delegate implementation -------------------------------------- |
-void BookmarkBarGtk::PopupForButton(GtkWidget* button) { |
- const BookmarkNode* node = GetNodeForToolButton(button); |
- DCHECK(node); |
- DCHECK(page_navigator_); |
- |
- int first_hidden = GetFirstHiddenBookmark(0, NULL); |
- if (first_hidden == -1) { |
- // No overflow exists: don't show anything for the overflow button. |
- if (button == overflow_button_) |
- return; |
- } else { |
- // Overflow exists: don't show anything for an overflowed folder button. |
- if (button != overflow_button_ && button != other_bookmarks_button_ && |
- node->GetParent()->IndexOfChild(node) >= first_hidden) { |
- return; |
- } |
- } |
- |
- current_menu_.reset( |
- new BookmarkMenuController(browser_, profile_, page_navigator_, |
- GTK_WINDOW(gtk_widget_get_toplevel(button)), |
- node, |
- button == overflow_button_ ? |
- first_hidden : 0)); |
- menu_bar_helper_.MenuStartedShowing(button, current_menu_->widget()); |
- GdkEvent* event = gtk_get_current_event(); |
- current_menu_->Popup(button, event->button.button, event->button.time); |
- gdk_event_free(event); |
-} |
- |
-void BookmarkBarGtk::PopupForButtonNextTo(GtkWidget* button, |
- GtkMenuDirectionType dir) { |
- const BookmarkNode* relative_node = GetNodeForToolButton(button); |
- DCHECK(relative_node); |
- |
- // Find out the order of the buttons. |
- std::vector<GtkWidget*> folder_list; |
- const int first_hidden = GetFirstHiddenBookmark(0, &folder_list); |
- if (first_hidden != -1) |
- folder_list.push_back(overflow_button_); |
- folder_list.push_back(other_bookmarks_button_); |
- |
- // Find the position of |button|. |
- int button_idx = -1; |
- for (size_t i = 0; i < folder_list.size(); ++i) { |
- if (folder_list[i] == button) { |
- button_idx = i; |
- break; |
- } |
- } |
- DCHECK_NE(button_idx, -1); |
- |
- // Find the GtkWidget* for the actual target button. |
- int shift = dir == GTK_MENU_DIR_PARENT ? -1 : 1; |
- button_idx = (button_idx + shift + folder_list.size()) % folder_list.size(); |
- PopupForButton(folder_list[button_idx]); |
-} |
- |
-void BookmarkBarGtk::CloseMenu() { |
- current_context_menu_->Cancel(); |
-} |