15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/gtk/bookmarks/bookmark_bar_gtk.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/debug/trace_event.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/metrics/histogram.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/pickle.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/prefs/pref_service.h"
14868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/bookmarks/bookmark_model.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/bookmarks/bookmark_model_factory.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/bookmarks/bookmark_node_data.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/bookmarks/bookmark_utils.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/browser_shutdown.h"
207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/browser/chrome_notification_types.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/extension_service.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/themes/theme_properties.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/bookmarks/bookmark_bar_constants.h"
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/bookmarks/bookmark_drag_drop.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/bookmarks/bookmark_utils.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/browser.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/chrome_pages.h"
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/gtk/bookmarks/bookmark_bar_instructions_gtk.h"
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/gtk/bookmarks/bookmark_menu_controller_gtk.h"
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/gtk/bookmarks/bookmark_utils_gtk.h"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/gtk/browser_window_gtk.h"
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/gtk/custom_button.h"
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/gtk/event_utils.h"
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/gtk/gtk_chrome_button.h"
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/gtk/gtk_theme_service.h"
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/gtk/gtk_util.h"
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/gtk/hover_controller_gtk.h"
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/gtk/menu_gtk.h"
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/gtk/rounded_window.h"
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/gtk/tabstrip_origin_provider.h"
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/gtk/view_id_util.h"
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/ntp_background_util.h"
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/tabs/tab_strip_model.h"
45558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch#include "chrome/browser/ui/webui/ntp/core_app_launcher_handler.h"
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/extensions/extension_constants.h"
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/pref_names.h"
487dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/common/url_constants.h"
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_details.h"
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_source.h"
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/user_metrics.h"
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/web_contents.h"
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/web_contents_view.h"
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/generated_resources.h"
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/theme_resources.h"
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/ui_resources.h"
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/dragdrop/drag_drop_types.h"
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/dragdrop/gtk_dnd_util.h"
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/gtk/gtk_compat.h"
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/l10n/l10n_util.h"
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/resource/resource_bundle.h"
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/canvas_skia_paint.h"
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/gtk_util.h"
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/image/cairo_cached_surface.h"
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/image/image.h"
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::PageNavigator;
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::UserMetricsAction;
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::WebContents;
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The showing height of the bar.
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kBookmarkBarHeight = 29;
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Padding for when the bookmark bar is detached.
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kTopBottomNTPPadding = 12;
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kLeftRightNTPPadding = 8;
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Padding around the bar's content area when the bookmark bar is detached.
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kNTPPadding = 2;
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The number of pixels of rounding on the corners of the bookmark bar content
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// area when in detached mode.
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kNTPRoundedness = 3;
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The height of the bar when it is "hidden". It is usually not completely
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// hidden because even when it is closed it forms the bottom few pixels of
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the toolbar.
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kBookmarkBarMinimumHeight = 3;
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Left-padding for the instructional text.
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kInstructionsPadding = 6;
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Padding around the "Other Bookmarks" button.
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kOtherBookmarksPaddingHorizontal = 2;
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kOtherBookmarksPaddingVertical = 1;
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The targets accepted by the toolbar and folder buttons for DnD.
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kDestTargetList[] = { ui::CHROME_BOOKMARK_ITEM,
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                ui::CHROME_NAMED_URL,
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                ui::TEXT_URI_LIST,
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                ui::NETSCAPE_URL,
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                ui::TEXT_PLAIN, -1 };
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Acceptable drag actions for the bookmark bar drag destinations.
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const GdkDragAction kDragAction =
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GdkDragAction(GDK_ACTION_MOVE | GDK_ACTION_COPY);
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SetToolBarStyle() {
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static bool style_was_set = false;
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (style_was_set)
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  style_was_set = true;
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_rc_parse_string(
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "style \"chrome-bookmark-toolbar\" {"
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "  xthickness = 0\n"
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "  ythickness = 0\n"
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "  GtkWidget::focus-padding = 0\n"
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "  GtkContainer::border-width = 0\n"
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "  GtkToolbar::internal-padding = 1\n"
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "  GtkToolbar::shadow-type = GTK_SHADOW_NONE\n"
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "}\n"
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "widget \"*chrome-bookmark-toolbar\" style \"chrome-bookmark-toolbar\"");
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void RecordAppLaunch(Profile* profile, const GURL& url) {
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(profile->GetExtensionService());
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const extensions::Extension* extension =
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      profile->GetExtensionService()->GetInstalledApp(url);
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!extension)
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
136558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  CoreAppLauncherHandler::RecordAppLaunchType(
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      extension_misc::APP_LAUNCH_BOOKMARK_BAR,
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      extension->GetType());
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BookmarkBarGtk::BookmarkBarGtk(BrowserWindowGtk* window,
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               Browser* browser,
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               TabstripOriginProvider* tabstrip_origin_provider)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : page_navigator_(NULL),
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      browser_(browser),
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      window_(window),
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      tabstrip_origin_provider_(tabstrip_origin_provider),
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      model_(NULL),
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      instructions_(NULL),
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      dragged_node_(NULL),
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      drag_icon_(NULL),
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      toolbar_drop_item_(NULL),
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      theme_service_(GtkThemeService::GetFrom(browser->profile())),
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      show_instructions_(true),
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      menu_bar_helper_(this),
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      slide_animation_(this),
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      last_allocation_width_(-1),
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      throbbing_widget_(NULL),
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      weak_factory_(this),
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bookmark_bar_state_(BookmarkBar::DETACHED),
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      max_height_(0) {
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Init();
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Force an update by simulating being in the wrong state.
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // BrowserWindowGtk sets our true state after we're created.
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetBookmarkBarState(BookmarkBar::SHOW,
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      BookmarkBar::DONT_ANIMATE_STATE_CHANGE);
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  registrar_.Add(this, chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 content::Source<ThemeService>(theme_service_));
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1737dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  apps_shortcut_visible_.Init(
1747dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      prefs::kShowAppsShortcutInBookmarkBar,
1757dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      browser_->profile()->GetPrefs(),
1767dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      base::Bind(&BookmarkBarGtk::OnAppsPageShortcutVisibilityChanged,
1777dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                 base::Unretained(this)));
1787dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1797dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  OnAppsPageShortcutVisibilityChanged();
1807dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  edit_bookmarks_enabled_.Init(
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      prefs::kEditBookmarksEnabled,
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      browser_->profile()->GetPrefs(),
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&BookmarkBarGtk::OnEditBookmarksEnabledChanged,
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 base::Unretained(this)));
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OnEditBookmarksEnabledChanged();
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BookmarkBarGtk::~BookmarkBarGtk() {
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RemoveAllButtons();
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bookmark_toolbar_.Destroy();
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  event_box_.Destroy();
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkBarGtk::SetPageNavigator(PageNavigator* navigator) {
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  page_navigator_ = navigator;
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkBarGtk::Init() {
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  event_box_.Own(gtk_event_box_new());
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_signal_connect(event_box_.get(), "destroy",
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   G_CALLBACK(&OnEventBoxDestroyThunk), this);
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_signal_connect(event_box_.get(), "button-press-event",
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   G_CALLBACK(&OnButtonPressedThunk), this);
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ntp_padding_box_ = gtk_alignment_new(0, 0, 1, 1);
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_container_add(GTK_CONTAINER(event_box_.get()), ntp_padding_box_);
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  paint_box_ = gtk_event_box_new();
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_container_add(GTK_CONTAINER(ntp_padding_box_), paint_box_);
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GdkColor paint_box_color =
2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      theme_service_->GetGdkColor(ThemeProperties::COLOR_TOOLBAR);
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_widget_modify_bg(paint_box_, GTK_STATE_NORMAL, &paint_box_color);
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_widget_add_events(paint_box_, GDK_POINTER_MOTION_MASK |
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    GDK_BUTTON_PRESS_MASK);
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bookmark_hbox_ = gtk_hbox_new(FALSE, 0);
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_container_add(GTK_CONTAINER(paint_box_), bookmark_hbox_);
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2217dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  apps_shortcut_button_ = theme_service_->BuildChromeButton();
2227dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  bookmark_utils::ConfigureAppsShortcutButton(apps_shortcut_button_,
2237dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                              theme_service_);
2247dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  g_signal_connect(apps_shortcut_button_, "clicked",
2257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                   G_CALLBACK(OnAppsButtonClickedThunk), this);
2267dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // Accept middle mouse clicking.
2277dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  gtk_util::SetButtonClickableByMouseButtons(
2287dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      apps_shortcut_button_, true, true, false);
2297dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  gtk_box_pack_start(GTK_BOX(bookmark_hbox_), apps_shortcut_button_,
2307dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                     FALSE, FALSE, 0);
2317dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  instructions_ = gtk_alignment_new(0, 0, 1, 1);
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_alignment_set_padding(GTK_ALIGNMENT(instructions_), 0, 0,
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            kInstructionsPadding, 0);
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Profile* profile = browser_->profile();
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  instructions_gtk_.reset(new BookmarkBarInstructionsGtk(this, profile));
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_container_add(GTK_CONTAINER(instructions_), instructions_gtk_->widget());
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_box_pack_start(GTK_BOX(bookmark_hbox_), instructions_,
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     TRUE, TRUE, 0);
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_drag_dest_set(instructions_,
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GtkDestDefaults(GTK_DEST_DEFAULT_DROP | GTK_DEST_DEFAULT_MOTION),
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NULL, 0, kDragAction);
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ui::SetDestTargetList(instructions_, kDestTargetList);
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_signal_connect(instructions_, "drag-data-received",
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   G_CALLBACK(&OnDragReceivedThunk), this);
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_signal_connect(event_box_.get(), "expose-event",
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   G_CALLBACK(&OnEventBoxExposeThunk), this);
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdateEventBoxPaintability();
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bookmark_toolbar_.Own(gtk_toolbar_new());
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetToolBarStyle();
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_widget_set_name(bookmark_toolbar_.get(), "chrome-bookmark-toolbar");
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_util::SuppressDefaultPainting(bookmark_toolbar_.get());
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_signal_connect(bookmark_toolbar_.get(), "size-allocate",
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   G_CALLBACK(&OnToolbarSizeAllocateThunk), this);
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_box_pack_start(GTK_BOX(bookmark_hbox_), bookmark_toolbar_.get(),
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     TRUE, TRUE, 0);
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  overflow_button_ = theme_service_->BuildChromeButton();
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_object_set_data(G_OBJECT(overflow_button_), "left-align-popup",
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    reinterpret_cast<void*>(true));
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetOverflowButtonAppearance();
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ConnectFolderButtonEvents(overflow_button_, false);
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_box_pack_start(GTK_BOX(bookmark_hbox_), overflow_button_,
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     FALSE, FALSE, 0);
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_drag_dest_set(bookmark_toolbar_.get(), GTK_DEST_DEFAULT_DROP,
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    NULL, 0, kDragAction);
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ui::SetDestTargetList(bookmark_toolbar_.get(), kDestTargetList);
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_signal_connect(bookmark_toolbar_.get(), "drag-motion",
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   G_CALLBACK(&OnToolbarDragMotionThunk), this);
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_signal_connect(bookmark_toolbar_.get(), "drag-leave",
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   G_CALLBACK(&OnDragLeaveThunk), this);
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_signal_connect(bookmark_toolbar_.get(), "drag-data-received",
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   G_CALLBACK(&OnDragReceivedThunk), this);
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  other_bookmarks_separator_ = theme_service_->CreateToolbarSeparator();
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_box_pack_start(GTK_BOX(bookmark_hbox_), other_bookmarks_separator_,
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     FALSE, FALSE, 0);
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We pack the button manually (rather than using gtk_button_set_*) so that
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // we can have finer control over its label.
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  other_bookmarks_button_ = theme_service_->BuildChromeButton();
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_widget_show_all(other_bookmarks_button_);
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ConnectFolderButtonEvents(other_bookmarks_button_, false);
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  other_padding_ = gtk_alignment_new(0, 0, 1, 1);
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_alignment_set_padding(GTK_ALIGNMENT(other_padding_),
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            kOtherBookmarksPaddingVertical,
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            kOtherBookmarksPaddingVertical,
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            kOtherBookmarksPaddingHorizontal,
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            kOtherBookmarksPaddingHorizontal);
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_container_add(GTK_CONTAINER(other_padding_), other_bookmarks_button_);
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_box_pack_start(GTK_BOX(bookmark_hbox_), other_padding_,
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     FALSE, FALSE, 0);
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_widget_set_no_show_all(other_padding_, TRUE);
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_widget_set_size_request(event_box_.get(), -1, kBookmarkBarMinimumHeight);
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ViewIDUtil::SetID(other_bookmarks_button_, VIEW_ID_OTHER_BOOKMARKS);
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ViewIDUtil::SetID(widget(), VIEW_ID_BOOKMARK_BAR);
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_widget_show_all(widget());
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_widget_hide(widget());
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddCoreButtons();
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(erg): Handle extensions
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  model_ = BookmarkModelFactory::GetForProfile(profile);
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  model_->AddObserver(this);
311b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (model_->loaded())
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Loaded(model_, false);
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // else case: we'll receive notification back from the BookmarkModel when done
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // loading, then we'll populate the bar.
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkBarGtk::SetBookmarkBarState(
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BookmarkBar::State state,
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BookmarkBar::AnimateChangeType animate_type) {
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TRACE_EVENT0("ui::gtk", "BookmarkBarGtk::SetBookmarkBarState");
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (animate_type == BookmarkBar::ANIMATE_STATE_CHANGE &&
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (state == BookmarkBar::DETACHED ||
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       bookmark_bar_state_ == BookmarkBar::DETACHED)) {
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(estade): animate the transition between detached and non or remove
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // detached entirely.
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    animate_type = BookmarkBar::DONT_ANIMATE_STATE_CHANGE;
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BookmarkBar::State old_state = bookmark_bar_state_;
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bookmark_bar_state_ = state;
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state == BookmarkBar::SHOW || state == BookmarkBar::DETACHED)
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Show(old_state, animate_type);
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Hide(old_state, animate_type);
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int BookmarkBarGtk::GetHeight() {
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GtkAllocation allocation;
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_widget_get_allocation(event_box_.get(), &allocation);
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return allocation.height - kBookmarkBarMinimumHeight;
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BookmarkBarGtk::IsAnimating() {
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return slide_animation_.is_animating();
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkBarGtk::CalculateMaxHeight() {
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (theme_service_->UsingNativeTheme()) {
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Get the requisition of our single child instead of the event box itself
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // because the event box probably already has a size request.
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GtkRequisition req;
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gtk_widget_size_request(ntp_padding_box_, &req);
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    max_height_ = req.height;
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    max_height_ = (bookmark_bar_state_ == BookmarkBar::DETACHED) ?
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  chrome::kNTPBookmarkBarHeight : kBookmarkBarHeight;
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkBarGtk::AnimationProgressed(const ui::Animation* animation) {
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(animation, &slide_animation_);
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gint height =
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      static_cast<gint>(animation->GetCurrentValue() *
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        (max_height_ - kBookmarkBarMinimumHeight)) +
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      kBookmarkBarMinimumHeight;
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_widget_set_size_request(event_box_.get(), -1, height);
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkBarGtk::AnimationEnded(const ui::Animation* animation) {
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(animation, &slide_animation_);
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!slide_animation_.IsShowing()) {
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gtk_widget_hide(bookmark_hbox_);
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We can be windowless during unit tests.
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (window_) {
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Because of our constant resizing and our toolbar/bookmark bar overlap
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // shenanigans, gtk+ gets confused, partially draws parts of the bookmark
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // bar into the toolbar and than doesn't queue a redraw to fix it. So do
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // it manually by telling the toolbar area to redraw itself.
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      window_->QueueToolbarRedraw();
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// MenuBarHelper::Delegate implementation --------------------------------------
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkBarGtk::PopupForButton(GtkWidget* button) {
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const BookmarkNode* node = GetNodeForToolButton(button);
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(node);
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(page_navigator_);
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int first_hidden = GetFirstHiddenBookmark(0, NULL);
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (first_hidden == -1) {
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // No overflow exists: don't show anything for the overflow button.
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (button == overflow_button_)
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Overflow exists: don't show anything for an overflowed folder button.
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (button != overflow_button_ && button != other_bookmarks_button_ &&
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        node->parent()->GetIndexOf(node) >= first_hidden) {
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  current_menu_.reset(
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      new BookmarkMenuController(browser_, page_navigator_,
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          GTK_WINDOW(gtk_widget_get_toplevel(button)),
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          node,
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          button == overflow_button_ ? first_hidden : 0));
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  menu_bar_helper_.MenuStartedShowing(button, current_menu_->widget());
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GdkEvent* event = gtk_get_current_event();
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  current_menu_->Popup(button, event->button.button, event->button.time);
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gdk_event_free(event);
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkBarGtk::PopupForButtonNextTo(GtkWidget* button,
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          GtkMenuDirectionType dir) {
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const BookmarkNode* relative_node = GetNodeForToolButton(button);
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(relative_node);
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Find out the order of the buttons.
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<GtkWidget*> folder_list;
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const int first_hidden = GetFirstHiddenBookmark(0, &folder_list);
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (first_hidden != -1)
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    folder_list.push_back(overflow_button_);
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  folder_list.push_back(other_bookmarks_button_);
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Find the position of |button|.
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int button_idx = -1;
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < folder_list.size(); ++i) {
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (folder_list[i] == button) {
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      button_idx = i;
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_NE(button_idx, -1);
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Find the GtkWidget* for the actual target button.
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int shift = dir == GTK_MENU_DIR_PARENT ? -1 : 1;
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  button_idx = (button_idx + shift + folder_list.size()) % folder_list.size();
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PopupForButton(folder_list[button_idx]);
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkBarGtk::CloseMenu() {
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  current_context_menu_->Cancel();
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkBarGtk::Show(BookmarkBar::State old_state,
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          BookmarkBar::AnimateChangeType animate_type) {
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_widget_show_all(widget());
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdateDetachedState(old_state);
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CalculateMaxHeight();
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (animate_type == BookmarkBar::ANIMATE_STATE_CHANGE) {
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    slide_animation_.Show();
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    slide_animation_.Reset(1);
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AnimationProgressed(&slide_animation_);
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
460b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (model_ && model_->loaded())
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UpdateOtherBookmarksVisibility();
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Hide out behind the findbar. This is rather fragile code, it could
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // probably be improved.
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (bookmark_bar_state_ == BookmarkBar::DETACHED) {
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (theme_service_->UsingNativeTheme()) {
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GtkWidget* parent = gtk_widget_get_parent(event_box_.get());
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (gtk_widget_get_realized(parent))
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        gdk_window_lower(gtk_widget_get_window(parent));
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (gtk_widget_get_realized(event_box_.get()))
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        gdk_window_lower(gtk_widget_get_window(event_box_.get()));
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {  // Chromium theme mode.
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (gtk_widget_get_realized(paint_box_)) {
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        gdk_window_lower(gtk_widget_get_window(paint_box_));
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // The event box won't stay below its children's GdkWindows unless we
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // toggle the above-child property here. If the event box doesn't stay
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // below its children then events will be routed to it rather than the
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // children.
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        gtk_event_box_set_above_child(GTK_EVENT_BOX(event_box_.get()), TRUE);
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        gtk_event_box_set_above_child(GTK_EVENT_BOX(event_box_.get()), FALSE);
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Maybe show the instructions
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_widget_set_visible(bookmark_toolbar_.get(), !show_instructions_);
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_widget_set_visible(instructions_, show_instructions_);
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetChevronState();
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkBarGtk::Hide(BookmarkBar::State old_state,
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          BookmarkBar::AnimateChangeType animate_type) {
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdateDetachedState(old_state);
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // After coming out of fullscreen, the browser window sets the bookmark bar
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // to the "hidden" state, which means we need to show our minimum height.
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!window_->IsFullscreen())
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gtk_widget_show(widget());
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CalculateMaxHeight();
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Sometimes we get called without a matching call to open. If that happens
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // then force hide.
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (slide_animation_.IsShowing() &&
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      animate_type == BookmarkBar::ANIMATE_STATE_CHANGE) {
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    slide_animation_.Hide();
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gtk_widget_hide(bookmark_hbox_);
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    slide_animation_.Reset(0);
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AnimationProgressed(&slide_animation_);
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkBarGtk::SetInstructionState() {
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (model_)
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    show_instructions_ = model_->bookmark_bar_node()->empty();
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_widget_set_visible(bookmark_toolbar_.get(), !show_instructions_);
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_widget_set_visible(instructions_, show_instructions_);
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkBarGtk::SetChevronState() {
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!gtk_widget_get_visible(bookmark_hbox_))
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (show_instructions_) {
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gtk_widget_hide(overflow_button_);
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int extra_space = 0;
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (gtk_widget_get_visible(overflow_button_)) {
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GtkAllocation allocation;
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gtk_widget_get_allocation(overflow_button_, &allocation);
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    extra_space = allocation.width;
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int overflow_idx = GetFirstHiddenBookmark(extra_space, NULL);
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (overflow_idx == -1)
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gtk_widget_hide(overflow_button_);
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gtk_widget_show_all(overflow_button_);
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkBarGtk::UpdateOtherBookmarksVisibility() {
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool has_other_children = !model_->other_node()->empty();
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_widget_set_visible(other_padding_, has_other_children);
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_widget_set_visible(other_bookmarks_separator_, has_other_children);
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkBarGtk::RemoveAllButtons() {
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_util::RemoveAllChildren(bookmark_toolbar_.get());
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  menu_bar_helper_.Clear();
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkBarGtk::AddCoreButtons() {
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  menu_bar_helper_.Add(other_bookmarks_button_);
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  menu_bar_helper_.Add(overflow_button_);
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkBarGtk::ResetButtons() {
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RemoveAllButtons();
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AddCoreButtons();
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const BookmarkNode* bar = model_->bookmark_bar_node();
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(bar && model_->other_node());
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create a button for each of the children on the bookmark bar.
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < bar->child_count(); ++i) {
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const BookmarkNode* node = bar->GetChild(i);
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GtkToolItem* item = CreateBookmarkToolItem(node);
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gtk_toolbar_insert(GTK_TOOLBAR(bookmark_toolbar_.get()), item, -1);
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (node->is_folder())
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      menu_bar_helper_.Add(gtk_bin_get_child(GTK_BIN(item)));
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bookmark_utils::ConfigureButtonForNode(model_->other_node(),
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      model_, other_bookmarks_button_, theme_service_);
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetInstructionState();
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetChevronState();
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int BookmarkBarGtk::GetBookmarkButtonCount() {
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GList* children = gtk_container_get_children(
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GTK_CONTAINER(bookmark_toolbar_.get()));
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int count = g_list_length(children);
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_list_free(children);
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return count;
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bookmark_utils::BookmarkLaunchLocation
5932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    BookmarkBarGtk::GetBookmarkLaunchLocation() const {
5942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return bookmark_bar_state_ == BookmarkBar::DETACHED ?
5952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      bookmark_utils::LAUNCH_DETACHED_BAR :
5962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      bookmark_utils::LAUNCH_ATTACHED_BAR;
5972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkBarGtk::SetOverflowButtonAppearance() {
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GtkWidget* former_child = gtk_bin_get_child(GTK_BIN(overflow_button_));
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (former_child)
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gtk_widget_destroy(former_child);
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GtkWidget* new_child;
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (theme_service_->UsingNativeTheme()) {
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    new_child = gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_NONE);
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const gfx::Image& image = ui::ResourceBundle::GetSharedInstance().
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        GetNativeImageNamed(IDR_BOOKMARK_BAR_CHEVRONS,
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            ui::ResourceBundle::RTL_ENABLED);
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    new_child = gtk_image_new_from_pixbuf(image.ToGdkPixbuf());
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_container_add(GTK_CONTAINER(overflow_button_), new_child);
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetChevronState();
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int BookmarkBarGtk::GetFirstHiddenBookmark(int extra_space,
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<GtkWidget*>* showing_folders) {
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int rv = 0;
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We're going to keep track of how much width we've used as we move along
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the bookmark bar. If we ever surpass the width of the bookmark bar, we'll
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // know that's the first hidden bookmark.
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int width_used = 0;
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // GTK appears to require one pixel of padding to the side of the first and
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // last buttons on the bar.
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(gideonwald): figure out the precise source of these extra two pixels
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // and make this calculation more reliable.
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GtkAllocation allocation;
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_widget_get_allocation(bookmark_toolbar_.get(), &allocation);
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int total_width = allocation.width - 2;
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool overflow = false;
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GtkRequisition requested_size_;
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GList* toolbar_items =
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gtk_container_get_children(GTK_CONTAINER(bookmark_toolbar_.get()));
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (GList* iter = toolbar_items; iter; iter = g_list_next(iter)) {
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GtkWidget* tool_item = reinterpret_cast<GtkWidget*>(iter->data);
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gtk_widget_size_request(tool_item, &requested_size_);
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    width_used += requested_size_.width;
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // |extra_space| is available if we can remove the chevron, which happens
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // only if there are no more potential overflow bookmarks after this one.
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    overflow = width_used > total_width + (g_list_next(iter) ? 0 : extra_space);
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (overflow)
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (showing_folders &&
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        model_->bookmark_bar_node()->GetChild(rv)->is_folder()) {
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      showing_folders->push_back(gtk_bin_get_child(GTK_BIN(tool_item)));
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    rv++;
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_list_free(toolbar_items);
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!overflow)
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return -1;
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return rv;
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkBarGtk::UpdateDetachedState(BookmarkBar::State old_state) {
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool old_detached = old_state == BookmarkBar::DETACHED;
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool detached = bookmark_bar_state_ == BookmarkBar::DETACHED;
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (detached == old_detached)
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (detached) {
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gtk_event_box_set_visible_window(GTK_EVENT_BOX(paint_box_), TRUE);
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GdkColor stroke_color = theme_service_->UsingNativeTheme() ?
6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        theme_service_->GetBorderColor() :
6712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        theme_service_->GetGdkColor(ThemeProperties::COLOR_NTP_HEADER);
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gtk_util::ActAsRoundedWindow(paint_box_, stroke_color, kNTPRoundedness,
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 gtk_util::ROUNDED_ALL, gtk_util::BORDER_ALL);
6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gtk_alignment_set_padding(GTK_ALIGNMENT(ntp_padding_box_),
6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        kTopBottomNTPPadding, kTopBottomNTPPadding,
6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        kLeftRightNTPPadding, kLeftRightNTPPadding);
6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gtk_container_set_border_width(GTK_CONTAINER(bookmark_hbox_), kNTPPadding);
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gtk_util::StopActingAsRoundedWindow(paint_box_);
6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gtk_event_box_set_visible_window(GTK_EVENT_BOX(paint_box_), FALSE);
6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gtk_alignment_set_padding(GTK_ALIGNMENT(ntp_padding_box_), 0, 0, 0, 0);
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gtk_container_set_border_width(GTK_CONTAINER(bookmark_hbox_), 0);
6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdateEventBoxPaintability();
6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // |window_| can be NULL during testing.
6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Listen for parent size allocations. Only connect once.
6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (window_ && detached) {
6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GtkWidget* parent = gtk_widget_get_parent(widget());
6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (parent &&
6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        g_signal_handler_find(parent, G_SIGNAL_MATCH_FUNC,
6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            0, 0, NULL, reinterpret_cast<gpointer>(OnParentSizeAllocateThunk),
6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            NULL) == 0) {
6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      g_signal_connect(parent, "size-allocate",
6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       G_CALLBACK(OnParentSizeAllocateThunk), this);
6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkBarGtk::UpdateEventBoxPaintability() {
7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_widget_set_app_paintable(
7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      event_box_.get(),
7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (!theme_service_->UsingNativeTheme() ||
7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       bookmark_bar_state_ == BookmarkBar::DETACHED));
7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // When using the GTK+ theme, we need to have the event box be visible so
7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // buttons don't get a halo color from the background.  When using Chromium
7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // themes, we want to let the background show through the toolbar.
7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_event_box_set_visible_window(GTK_EVENT_BOX(event_box_.get()),
7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   theme_service_->UsingNativeTheme());
7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkBarGtk::PaintEventBox() {
7152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  gfx::Size web_contents_size;
7162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (GetWebContentsSize(&web_contents_size) &&
7172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      web_contents_size != last_web_contents_size_) {
7182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    last_web_contents_size_ = web_contents_size;
7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gtk_widget_queue_draw(event_box_.get());
7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool BookmarkBarGtk::GetWebContentsSize(gfx::Size* size) {
7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Browser* browser = browser_;
7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!browser) {
7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  WebContents* web_contents =
7302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      browser->tab_strip_model()->GetActiveWebContents();
7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!web_contents) {
7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // It is possible to have a browser but no WebContents while under testing,
7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // so don't NOTREACHED() and error the program.
7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!web_contents->GetView()) {
7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *size = web_contents->GetView()->GetContainerSize();
7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkBarGtk::StartThrobbingAfterAllocation(GtkWidget* item) {
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_signal_connect_after(
7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      item, "size-allocate", G_CALLBACK(OnItemAllocateThunk), this);
7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkBarGtk::OnItemAllocate(GtkWidget* item,
7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    GtkAllocation* allocation) {
7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We only want to fire on the item's first allocation.
7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_signal_handlers_disconnect_by_func(
7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      item, reinterpret_cast<gpointer>(&OnItemAllocateThunk), this);
7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GtkWidget* button = gtk_bin_get_child(GTK_BIN(item));
7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const BookmarkNode* node = GetNodeForToolButton(button);
7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (node)
7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    StartThrobbing(node);
7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkBarGtk::StartThrobbing(const BookmarkNode* node) {
7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const BookmarkNode* parent_on_bb = NULL;
7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (const BookmarkNode* parent = node; parent;
7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       parent = parent->parent()) {
7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (parent->parent() == model_->bookmark_bar_node()) {
7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      parent_on_bb = parent;
7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GtkWidget* widget_to_throb = NULL;
7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!parent_on_bb) {
7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Descendant of "Other Bookmarks".
7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    widget_to_throb = other_bookmarks_button_;
7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int hidden = GetFirstHiddenBookmark(0, NULL);
7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int idx = model_->bookmark_bar_node()->GetIndexOf(parent_on_bb);
7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (hidden >= 0 && hidden <= idx) {
7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      widget_to_throb = overflow_button_;
7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      widget_to_throb = gtk_bin_get_child(GTK_BIN(gtk_toolbar_get_nth_item(
7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          GTK_TOOLBAR(bookmark_toolbar_.get()), idx)));
7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetThrobbingWidget(widget_to_throb);
7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkBarGtk::SetThrobbingWidget(GtkWidget* widget) {
7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (throbbing_widget_) {
7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HoverControllerGtk* hover_controller =
7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        HoverControllerGtk::GetHoverControllerGtk(throbbing_widget_);
7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (hover_controller)
7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      hover_controller->StartThrobbing(0);
7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    g_signal_handlers_disconnect_by_func(
7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        throbbing_widget_,
8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        reinterpret_cast<gpointer>(OnThrobbingWidgetDestroyThunk),
8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        this);
8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    g_object_unref(throbbing_widget_);
8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    throbbing_widget_ = NULL;
8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (widget) {
8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    throbbing_widget_ = widget;
8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    g_object_ref(throbbing_widget_);
8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    g_signal_connect(throbbing_widget_, "destroy",
8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     G_CALLBACK(OnThrobbingWidgetDestroyThunk), this);
8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HoverControllerGtk* hover_controller =
8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        HoverControllerGtk::GetHoverControllerGtk(throbbing_widget_);
8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (hover_controller)
8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      hover_controller->StartThrobbing(4);
8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gboolean BookmarkBarGtk::ItemDraggedOverToolbar(GdkDragContext* context,
8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                int index,
8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                guint time) {
8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!edit_bookmarks_enabled_.GetValue())
8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return FALSE;
8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GdkAtom target_type =
8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gtk_drag_dest_find_target(bookmark_toolbar_.get(), context, NULL);
8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (target_type == GDK_NONE) {
8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We shouldn't act like a drop target when something that we can't deal
8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // with is dragged over the toolbar.
8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return FALSE;
8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!toolbar_drop_item_) {
8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (dragged_node_) {
8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      toolbar_drop_item_ = CreateBookmarkToolItem(dragged_node_);
8355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      g_object_ref_sink(GTK_OBJECT(toolbar_drop_item_));
8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
8375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Create a fake item the size of other_node().
8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      //
8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // TODO(erg): Maybe somehow figure out the real size for the drop target?
8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      toolbar_drop_item_ =
8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          CreateBookmarkToolItem(model_->other_node());
8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      g_object_ref_sink(GTK_OBJECT(toolbar_drop_item_));
8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_toolbar_set_drop_highlight_item(GTK_TOOLBAR(bookmark_toolbar_.get()),
8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      GTK_TOOL_ITEM(toolbar_drop_item_),
8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      index);
8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (target_type == ui::GetAtomForTarget(ui::CHROME_BOOKMARK_ITEM)) {
8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gdk_drag_status(context, GDK_ACTION_MOVE, time);
8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gdk_drag_status(context, GDK_ACTION_COPY, time);
8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return TRUE;
8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int BookmarkBarGtk::GetToolbarIndexForDragOverFolder(GtkWidget* button,
8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                     gint x) {
8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GtkAllocation allocation;
8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_widget_get_allocation(button, &allocation);
8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int margin = std::min(15, static_cast<int>(0.3 * allocation.width));
8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (x > margin && x < (allocation.width - margin))
8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return -1;
8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GtkWidget* parent = gtk_widget_get_parent(button);
8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gint index = gtk_toolbar_get_item_index(GTK_TOOLBAR(bookmark_toolbar_.get()),
8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          GTK_TOOL_ITEM(parent));
8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (x > margin)
8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    index++;
8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return index;
8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkBarGtk::ClearToolbarDropHighlighting() {
8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (toolbar_drop_item_) {
8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    g_object_unref(toolbar_drop_item_);
8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    toolbar_drop_item_ = NULL;
8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_toolbar_set_drop_highlight_item(GTK_TOOLBAR(bookmark_toolbar_.get()),
8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      NULL, 0);
8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkBarGtk::Loaded(BookmarkModel* model, bool ids_reassigned) {
8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If |instructions_| has been nulled, we are in the middle of browser
8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // shutdown. Do nothing.
8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!instructions_)
8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdateOtherBookmarksVisibility();
8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ResetButtons();
8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkBarGtk::BookmarkModelBeingDeleted(BookmarkModel* model) {
8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The bookmark model should never be deleted before us. This code exists
8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // to check for regressions in shutdown code and not crash.
8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!browser_shutdown::ShuttingDownWithoutClosingBrowsers())
8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Do minimal cleanup, presumably we'll be deleted shortly.
9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  model_->RemoveObserver(this);
9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  model_ = NULL;
9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkBarGtk::BookmarkNodeMoved(BookmarkModel* model,
9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       const BookmarkNode* old_parent,
9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       int old_index,
9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       const BookmarkNode* new_parent,
9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       int new_index) {
9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const BookmarkNode* node = new_parent->GetChild(new_index);
9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BookmarkNodeRemoved(model, old_parent, old_index, node);
9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BookmarkNodeAdded(model, new_parent, new_index);
9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkBarGtk::BookmarkNodeAdded(BookmarkModel* model,
9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       const BookmarkNode* parent,
9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       int index) {
9195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdateOtherBookmarksVisibility();
9205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const BookmarkNode* node = parent->GetChild(index);
9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (parent != model_->bookmark_bar_node()) {
9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    StartThrobbing(node);
9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
9255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(index >= 0 && index <= GetBookmarkButtonCount());
9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GtkToolItem* item = CreateBookmarkToolItem(node);
9295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_toolbar_insert(GTK_TOOLBAR(bookmark_toolbar_.get()),
9305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     item, index);
9315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (node->is_folder())
9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    menu_bar_helper_.Add(gtk_bin_get_child(GTK_BIN(item)));
9335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetInstructionState();
9355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetChevronState();
9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StartThrobbingAfterAllocation(GTK_WIDGET(item));
9385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkBarGtk::BookmarkNodeRemoved(BookmarkModel* model,
9415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         const BookmarkNode* parent,
9425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         int old_index,
9435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         const BookmarkNode* node) {
9445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdateOtherBookmarksVisibility();
9455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (parent != model_->bookmark_bar_node()) {
9475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We only care about nodes on the bookmark bar.
9485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
9495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(old_index >= 0 && old_index < GetBookmarkButtonCount());
9515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GtkWidget* to_remove = GTK_WIDGET(gtk_toolbar_get_nth_item(
9535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GTK_TOOLBAR(bookmark_toolbar_.get()), old_index));
9545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (node->is_folder())
9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    menu_bar_helper_.Remove(gtk_bin_get_child(GTK_BIN(to_remove)));
9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_container_remove(GTK_CONTAINER(bookmark_toolbar_.get()),
9575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       to_remove);
9585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetInstructionState();
9605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetChevronState();
9615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
963c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void BookmarkBarGtk::BookmarkAllNodesRemoved(BookmarkModel* model) {
964c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  UpdateOtherBookmarksVisibility();
965c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ResetButtons();
966c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
967c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
9685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkBarGtk::BookmarkNodeChanged(BookmarkModel* model,
9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         const BookmarkNode* node) {
9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (node->parent() != model_->bookmark_bar_node()) {
9715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We only care about nodes on the bookmark bar.
9725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
9735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int index = model_->bookmark_bar_node()->GetIndexOf(node);
9755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(index != -1);
9765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GtkToolItem* item = gtk_toolbar_get_nth_item(
9785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GTK_TOOLBAR(bookmark_toolbar_.get()), index);
9795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GtkWidget* button = gtk_bin_get_child(GTK_BIN(item));
9805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bookmark_utils::ConfigureButtonForNode(node, model, button, theme_service_);
9815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetChevronState();
9825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkBarGtk::BookmarkNodeFaviconChanged(BookmarkModel* model,
9855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                const BookmarkNode* node) {
9865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BookmarkNodeChanged(model, node);
9875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkBarGtk::BookmarkNodeChildrenReordered(BookmarkModel* model,
9905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                   const BookmarkNode* node) {
9915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (node != model_->bookmark_bar_node())
9925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;  // We only care about reordering of the bookmark bar node.
9935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ResetButtons();
9955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkBarGtk::Observe(int type,
9985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             const content::NotificationSource& source,
9995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             const content::NotificationDetails& details) {
10005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (type == chrome::NOTIFICATION_BROWSER_THEME_CHANGED) {
1001b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if (model_ && model_->loaded()) {
10025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Regenerate the bookmark bar with all new objects with their theme
10035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // properties set correctly for the new theme.
10045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ResetButtons();
10055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
10065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Resize the bookmark bar since the target height may have changed.
10085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CalculateMaxHeight();
10095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AnimationProgressed(&slide_animation_);
10105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UpdateEventBoxPaintability();
10125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GdkColor paint_box_color =
10142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        theme_service_->GetGdkColor(ThemeProperties::COLOR_TOOLBAR);
10155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gtk_widget_modify_bg(paint_box_, GTK_STATE_NORMAL, &paint_box_color);
10165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (bookmark_bar_state_ == BookmarkBar::DETACHED) {
10185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GdkColor stroke_color = theme_service_->UsingNativeTheme() ?
10195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          theme_service_->GetBorderColor() :
10202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          theme_service_->GetGdkColor(ThemeProperties::COLOR_NTP_HEADER);
10215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gtk_util::SetRoundedWindowBorderColor(paint_box_, stroke_color);
10225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
10235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetOverflowButtonAppearance();
10255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GtkWidget* BookmarkBarGtk::CreateBookmarkButton(const BookmarkNode* node) {
10295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GtkWidget* button = theme_service_->BuildChromeButton();
10305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bookmark_utils::ConfigureButtonForNode(node, model_, button, theme_service_);
10315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The tool item is also a source for dragging
10335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_drag_source_set(button, GDK_BUTTON1_MASK, NULL, 0,
10345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      static_cast<GdkDragAction>(GDK_ACTION_MOVE | GDK_ACTION_COPY));
10355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int target_mask = bookmark_utils::GetCodeMask(node->is_folder());
10365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ui::SetSourceTargetListFromCodeMask(button, target_mask);
10375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_signal_connect(button, "drag-begin",
10385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   G_CALLBACK(&OnButtonDragBeginThunk), this);
10395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_signal_connect(button, "drag-end",
10405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   G_CALLBACK(&OnButtonDragEndThunk), this);
10415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_signal_connect(button, "drag-data-get",
10425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   G_CALLBACK(&OnButtonDragGetThunk), this);
10435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We deliberately don't connect to "drag-data-delete" because the action of
10445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // moving a button will regenerate all the contents of the bookmarks bar
10455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // anyway.
10465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (node->is_url()) {
10485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Connect to 'button-release-event' instead of 'clicked' because we need
10495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // access to the modifier keys and we do different things on each
10505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // button.
10515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    g_signal_connect(button, "button-press-event",
10525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     G_CALLBACK(OnButtonPressedThunk), this);
10535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    g_signal_connect(button, "clicked",
10545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     G_CALLBACK(OnClickedThunk), this);
10555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gtk_util::SetButtonTriggersNavigation(button);
10565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
10575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ConnectFolderButtonEvents(button, true);
10585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return button;
10615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GtkToolItem* BookmarkBarGtk::CreateBookmarkToolItem(const BookmarkNode* node) {
10645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GtkWidget* button = CreateBookmarkButton(node);
10655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_object_set_data(G_OBJECT(button), "left-align-popup",
10665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    reinterpret_cast<void*>(true));
10675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GtkToolItem* item = gtk_tool_item_new();
10695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_container_add(GTK_CONTAINER(item), button);
10705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_widget_show_all(GTK_WIDGET(item));
10715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return item;
10735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
10745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkBarGtk::ConnectFolderButtonEvents(GtkWidget* widget,
10765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               bool is_tool_item) {
10775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // For toolbar items (i.e. not the overflow button or other bookmarks
10785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // button), we handle motion and highlighting manually.
10795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_drag_dest_set(widget,
10805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    is_tool_item ? GTK_DEST_DEFAULT_DROP :
10815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   GTK_DEST_DEFAULT_ALL,
10825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    NULL,
10835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    0,
10845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    kDragAction);
10855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ui::SetDestTargetList(widget, kDestTargetList);
10865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_signal_connect(widget, "drag-data-received",
10875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   G_CALLBACK(&OnDragReceivedThunk), this);
10885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (is_tool_item) {
10895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    g_signal_connect(widget, "drag-motion",
10905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     G_CALLBACK(&OnFolderDragMotionThunk), this);
10915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    g_signal_connect(widget, "drag-leave",
10925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     G_CALLBACK(&OnDragLeaveThunk), this);
10935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
10945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_signal_connect(widget, "button-press-event",
10965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   G_CALLBACK(OnButtonPressedThunk), this);
10975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_signal_connect(widget, "clicked",
10985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   G_CALLBACK(OnFolderClickedThunk), this);
10995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Accept middle mouse clicking (which opens all). This must be called after
11015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // connecting to "button-press-event" because the handler it attaches stops
11025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the propagation of that signal.
11035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_util::SetButtonClickableByMouseButtons(widget, true, true, false);
11045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const BookmarkNode* BookmarkBarGtk::GetNodeForToolButton(GtkWidget* widget) {
11075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // First check to see if |button| is special cased.
11085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (widget == other_bookmarks_button_)
11095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return model_->other_node();
11105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else if (widget == event_box_.get() || widget == overflow_button_)
11115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return model_->bookmark_bar_node();
11125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Search the contents of |bookmark_toolbar_| for the corresponding widget
11145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // and find its index.
11155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GtkWidget* item_to_find = gtk_widget_get_parent(widget);
11165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int index_to_use = -1;
11175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int index = 0;
11185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GList* children = gtk_container_get_children(
11195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GTK_CONTAINER(bookmark_toolbar_.get()));
11205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (GList* item = children; item; item = item->next, index++) {
11215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (item->data == item_to_find) {
11225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      index_to_use = index;
11235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
11245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
11255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_list_free(children);
11275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (index_to_use != -1)
11295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return model_->bookmark_bar_node()->GetChild(index_to_use);
11305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return NULL;
11325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkBarGtk::PopupMenuForNode(GtkWidget* sender,
11355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      const BookmarkNode* node,
11365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      GdkEventButton* event) {
1137b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  if (!model_->loaded()) {
11385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Don't do anything if the model isn't loaded.
11395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
11405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const BookmarkNode* parent = NULL;
11435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<const BookmarkNode*> nodes;
11445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (sender == other_bookmarks_button_) {
11455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    nodes.push_back(node);
11465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parent = model_->bookmark_bar_node();
11475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (sender != bookmark_toolbar_.get()) {
11485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    nodes.push_back(node);
11495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parent = node->parent();
11505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
11515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    parent = model_->bookmark_bar_node();
11525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    nodes.push_back(parent);
11535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GtkWindow* window = GTK_WINDOW(gtk_widget_get_toplevel(sender));
11565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  current_context_menu_controller_.reset(
11575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      new BookmarkContextMenuController(
11585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          window, this, browser_, browser_->profile(), page_navigator_, parent,
11595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          nodes));
11605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  current_context_menu_.reset(
11615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      new MenuGtk(NULL, current_context_menu_controller_->menu_model()));
11625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  current_context_menu_->PopupAsContext(
11635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gfx::Point(event->x_root, event->y_root),
11645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      event->time);
11655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gboolean BookmarkBarGtk::OnButtonPressed(GtkWidget* sender,
11685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         GdkEventButton* event) {
11695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  last_pressed_coordinates_ = gfx::Point(event->x, event->y);
11705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (event->button == 3 && gtk_widget_get_visible(bookmark_hbox_)) {
11725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const BookmarkNode* node = GetNodeForToolButton(sender);
11735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(node);
11745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(page_navigator_);
11755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PopupMenuForNode(sender, node, event);
11765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
11775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return FALSE;
11795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkBarGtk::OnClicked(GtkWidget* sender) {
11825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const BookmarkNode* node = GetNodeForToolButton(sender);
11835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(node);
11845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(node->is_url());
11855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(page_navigator_);
11865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RecordAppLaunch(browser_->profile(), node->url());
11885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  chrome::OpenAll(window_->GetNativeWindow(), page_navigator_, node,
11892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                  event_utils::DispositionForCurrentButtonPressEvent(),
11902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                  browser_->profile());
11915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bookmark_utils::RecordBookmarkLaunch(GetBookmarkLaunchLocation());
11935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
11945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkBarGtk::OnButtonDragBegin(GtkWidget* button,
11965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       GdkDragContext* drag_context) {
11975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GtkWidget* button_parent = gtk_widget_get_parent(button);
11985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The parent tool item might be removed during the drag. Ref it so |button|
12005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // won't get destroyed.
12015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_object_ref(button_parent);
12025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const BookmarkNode* node = GetNodeForToolButton(button);
12045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!dragged_node_);
12055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dragged_node_ = node;
12065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(dragged_node_);
12075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  drag_icon_ = bookmark_utils::GetDragRepresentationForNode(
12095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      node, model_, theme_service_);
12105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We have to jump through some hoops to get the drag icon to line up because
12125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // it is a different size than the button.
12135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GtkRequisition req;
12145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_widget_size_request(drag_icon_, &req);
12155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Rect button_rect = gtk_util::WidgetBounds(button);
12165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::Point drag_icon_relative =
12175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gfx::Rect(req.width, req.height).CenterPoint() +
12185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (last_pressed_coordinates_ - button_rect.CenterPoint());
12195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_drag_set_icon_widget(drag_context, drag_icon_,
12205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           drag_icon_relative.x(),
12215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           drag_icon_relative.y());
12225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Hide our node, but reserve space for it on the toolbar.
12245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int index = gtk_toolbar_get_item_index(GTK_TOOLBAR(bookmark_toolbar_.get()),
12255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         GTK_TOOL_ITEM(button_parent));
12265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_widget_hide(button);
12275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  toolbar_drop_item_ = CreateBookmarkToolItem(dragged_node_);
12285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_object_ref_sink(GTK_OBJECT(toolbar_drop_item_));
12295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_toolbar_set_drop_highlight_item(GTK_TOOLBAR(bookmark_toolbar_.get()),
12305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      GTK_TOOL_ITEM(toolbar_drop_item_), index);
12315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make sure it stays hidden for the duration of the drag.
12325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_widget_set_no_show_all(button, TRUE);
12335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkBarGtk::OnButtonDragEnd(GtkWidget* button,
12365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     GdkDragContext* drag_context) {
12375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_widget_show(button);
12385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_widget_set_no_show_all(button, FALSE);
12395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ClearToolbarDropHighlighting();
12415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(dragged_node_);
12435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dragged_node_ = NULL;
12445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(drag_icon_);
12465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_widget_destroy(drag_icon_);
12475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  drag_icon_ = NULL;
12485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_object_unref(gtk_widget_get_parent(button));
12505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkBarGtk::OnButtonDragGet(GtkWidget* widget,
12535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     GdkDragContext* context,
12545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     GtkSelectionData* selection_data,
12555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     guint target_type,
12565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     guint time) {
12575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const BookmarkNode* node = bookmark_utils::BookmarkNodeForWidget(widget);
12585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bookmark_utils::WriteBookmarkToSelection(node, selection_data, target_type,
12595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           browser_->profile());
12605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12627dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid BookmarkBarGtk::OnAppsButtonClicked(GtkWidget* sender) {
12637dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  content::OpenURLParams params(
12647dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      GURL(chrome::kChromeUIAppsURL),
12657dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      content::Referrer(),
12667dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      event_utils::DispositionForCurrentButtonPressEvent(),
12677dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      content::PAGE_TRANSITION_AUTO_BOOKMARK,
12687dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      false);
12697dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  browser_->OpenURL(params);
12707dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  bookmark_utils::RecordAppsPageOpen(GetBookmarkLaunchLocation());
12717dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
12727dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
12735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkBarGtk::OnFolderClicked(GtkWidget* sender) {
12745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Stop its throbbing, if any.
12755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HoverControllerGtk* hover_controller =
12765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      HoverControllerGtk::GetHoverControllerGtk(sender);
12775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (hover_controller)
12785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    hover_controller->StartThrobbing(0);
12795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GdkEvent* event = gtk_get_current_event();
12815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (event->button.button == 1 ||
12825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (event->button.button == 2 && sender == overflow_button_)) {
12832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bookmark_utils::RecordBookmarkFolderOpen(GetBookmarkLaunchLocation());
12845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PopupForButton(sender);
12855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (event->button.button == 2) {
12865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const BookmarkNode* node = GetNodeForToolButton(sender);
12875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    chrome::OpenAll(window_->GetNativeWindow(), page_navigator_, node,
12882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    NEW_BACKGROUND_TAB, browser_->profile());
12895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1290c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  gdk_event_free(event);
12915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
12925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
12935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gboolean BookmarkBarGtk::OnToolbarDragMotion(GtkWidget* toolbar,
12945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             GdkDragContext* context,
12955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             gint x,
12965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             gint y,
12975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             guint time) {
12985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gint index = gtk_toolbar_get_drop_index(GTK_TOOLBAR(toolbar), x, y);
12995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ItemDraggedOverToolbar(context, index, time);
13005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkBarGtk::OnToolbarSizeAllocate(GtkWidget* widget,
13035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                           GtkAllocation* allocation) {
13045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (allocation->width == last_allocation_width_) {
13055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If the width hasn't changed, then the visibility of the chevron
13065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // doesn't need to change. This check prevents us from getting stuck in a
13075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // loop where allocates are queued indefinitely while the visibility of
13085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // overflow chevron toggles without actual resizes of the toolbar.
13095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
13105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
13115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  last_allocation_width_ = allocation->width;
13125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetChevronState();
13145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkBarGtk::OnDragReceived(GtkWidget* widget,
13175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    GdkDragContext* context,
13185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    gint x, gint y,
13195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    GtkSelectionData* selection_data,
13205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    guint target_type, guint time) {
13215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!edit_bookmarks_enabled_.GetValue()) {
13225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gtk_drag_finish(context, FALSE, FALSE, time);
13235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
13245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
13255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gboolean dnd_success = FALSE;
13275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gboolean delete_selection_data = FALSE;
13285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const BookmarkNode* dest_node = model_->bookmark_bar_node();
13305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gint index;
13315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (widget == bookmark_toolbar_.get()) {
13325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    index = gtk_toolbar_get_drop_index(
13335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GTK_TOOLBAR(bookmark_toolbar_.get()), x, y);
13345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (widget == instructions_) {
13355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dest_node = model_->bookmark_bar_node();
13365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    index = 0;
13375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
13385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    index = GetToolbarIndexForDragOverFolder(widget, x);
13395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (index < 0) {
13405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      dest_node = GetNodeForToolButton(widget);
13415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      index = dest_node->child_count();
13425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
13435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
13445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (target_type) {
13465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case ui::CHROME_BOOKMARK_ITEM: {
13475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gint length = gtk_selection_data_get_length(selection_data);
13485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Pickle pickle(reinterpret_cast<const char*>(
13495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          gtk_selection_data_get_data(selection_data)), length);
13505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BookmarkNodeData drag_data;
13515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (drag_data.ReadFromPickle(&pickle)) {
13522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        dnd_success = chrome::DropBookmarks(browser_->profile(),
13532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            drag_data, dest_node, index) != ui::DragDropTypes::DRAG_NONE;
13545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
13555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
13565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
13575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case ui::CHROME_NAMED_URL: {
13595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      dnd_success = bookmark_utils::CreateNewBookmarkFromNamedUrl(
13605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          selection_data, model_, dest_node, index);
13615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
13625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
13635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case ui::TEXT_URI_LIST: {
13655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      dnd_success = bookmark_utils::CreateNewBookmarksFromURIList(
13665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          selection_data, model_, dest_node, index);
13675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
13685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
13695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case ui::NETSCAPE_URL: {
13715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      dnd_success = bookmark_utils::CreateNewBookmarkFromNetscapeURL(
13725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          selection_data, model_, dest_node, index);
13735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
13745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
13755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case ui::TEXT_PLAIN: {
13775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      guchar* text = gtk_selection_data_get_text(selection_data);
13785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!text)
13795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
13805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GURL url(reinterpret_cast<char*>(text));
13815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      g_free(text);
13825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // TODO(estade): It would be nice to head this case off at drag motion,
13835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // so that it doesn't look like we can drag onto the bookmark bar.
13845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!url.is_valid())
13855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
13865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      string16 title = bookmark_utils::GetNameForURL(url);
13875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      model_->AddURL(dest_node, index, title, url);
13885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      dnd_success = TRUE;
13895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
13905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
13915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
13925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_drag_finish(context, dnd_success, delete_selection_data, time);
13945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
13955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkBarGtk::OnDragLeave(GtkWidget* sender,
13975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 GdkDragContext* context,
13985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 guint time) {
13995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (GTK_IS_BUTTON(sender))
14005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gtk_drag_unhighlight(sender);
14015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ClearToolbarDropHighlighting();
14035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gboolean BookmarkBarGtk::OnFolderDragMotion(GtkWidget* button,
14065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            GdkDragContext* context,
14075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            gint x,
14085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            gint y,
14095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            guint time) {
14105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!edit_bookmarks_enabled_.GetValue())
14115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return FALSE;
14125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GdkAtom target_type = gtk_drag_dest_find_target(button, context, NULL);
14135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (target_type == GDK_NONE)
14145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return FALSE;
14155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int index = GetToolbarIndexForDragOverFolder(button, x);
14175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (index < 0) {
14185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ClearToolbarDropHighlighting();
14195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Drag is over middle of folder.
14215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gtk_drag_highlight(button);
14225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (target_type == ui::GetAtomForTarget(ui::CHROME_BOOKMARK_ITEM)) {
14235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gdk_drag_status(context, GDK_ACTION_MOVE, time);
14245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
14255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      gdk_drag_status(context, GDK_ACTION_COPY, time);
14265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
14275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return TRUE;
14295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Remove previous highlighting.
14325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_drag_unhighlight(button);
14335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ItemDraggedOverToolbar(context, index, time);
14345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gboolean BookmarkBarGtk::OnEventBoxExpose(GtkWidget* widget,
14375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          GdkEventExpose* event) {
14385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TRACE_EVENT0("ui::gtk", "BookmarkBarGtk::OnEventBoxExpose");
14395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GtkThemeService* theme_provider = theme_service_;
14405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We don't need to render the toolbar image in GTK mode, except when
14425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // detached.
14435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (theme_provider->UsingNativeTheme() &&
14445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bookmark_bar_state_ != BookmarkBar::DETACHED)
14455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return FALSE;
14465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (bookmark_bar_state_ != BookmarkBar::DETACHED) {
14485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cairo_t* cr = gdk_cairo_create(gtk_widget_get_window(widget));
14495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gdk_cairo_rectangle(cr, &event->area);
14505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cairo_clip(cr);
14515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Paint the background theme image.
14535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gfx::Point tabstrip_origin =
14545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        tabstrip_origin_provider_->GetTabStripOriginForWidget(widget);
14555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gtk_util::DrawThemedToolbarBackground(widget, cr, event, tabstrip_origin,
14565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          theme_provider);
14575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cairo_destroy(cr);
14595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
14602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    gfx::Size web_contents_size;
14612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!GetWebContentsSize(&web_contents_size))
14625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return FALSE;
14635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gfx::CanvasSkiaPaint canvas(event, true);
14645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    GtkAllocation allocation;
14665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gtk_widget_get_allocation(widget, &allocation);
14675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    gfx::Rect area = gtk_widget_get_has_window(widget) ?
14695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     gfx::Rect(0, 0, allocation.width, allocation.height) :
14705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     gfx::Rect(allocation);
14715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NtpBackgroundUtil::PaintBackgroundDetachedMode(theme_provider, &canvas,
14722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        area, web_contents_size.height());
14735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return FALSE;  // Propagate expose to children.
14765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkBarGtk::OnEventBoxDestroy(GtkWidget* widget) {
14795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (model_)
14805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    model_->RemoveObserver(this);
14815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkBarGtk::OnParentSizeAllocate(GtkWidget* widget,
14845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          GtkAllocation* allocation) {
14855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // In detached mode, our layout depends on the size of the tab contents.
14865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We get the size-allocate signal before the tab contents does, hence we
14875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // need to post a delayed task so we will paint correctly. Note that
14885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // gtk_widget_queue_draw by itself does not work, despite that it claims to
14895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // be asynchronous.
14905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (bookmark_bar_state_ == BookmarkBar::DETACHED) {
1491b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    base::MessageLoop::current()->PostTask(
14925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE,
14935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&BookmarkBarGtk::PaintEventBox, weak_factory_.GetWeakPtr()));
14945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
14955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
14965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkBarGtk::OnThrobbingWidgetDestroy(GtkWidget* widget) {
14985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetThrobbingWidget(NULL);
14995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
15005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkBarGtk::ShowImportDialog() {
15025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  chrome::ShowImportDialog(browser_);
15035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
15045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15057dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid BookmarkBarGtk::OnAppsPageShortcutVisibilityChanged() {
15067dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  const bool visible =
15077dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      chrome::ShouldShowAppsShortcutInBookmarkBar(browser_->profile());
15087dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  gtk_widget_set_visible(apps_shortcut_button_, visible);
15097dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  gtk_widget_set_no_show_all(apps_shortcut_button_, !visible);
15107dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
15117dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
15125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BookmarkBarGtk::OnEditBookmarksEnabledChanged() {
15135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GtkDestDefaults dest_defaults =
15145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *edit_bookmarks_enabled_ ? GTK_DEST_DEFAULT_ALL :
15155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 GTK_DEST_DEFAULT_DROP;
15165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_drag_dest_set(overflow_button_, dest_defaults, NULL, 0, kDragAction);
15175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gtk_drag_dest_set(other_bookmarks_button_, dest_defaults,
15185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    NULL, 0, kDragAction);
15195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ui::SetDestTargetList(overflow_button_, kDestTargetList);
15205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ui::SetDestTargetList(other_bookmarks_button_, kDestTargetList);
15215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1522