Logo Search packages:      
Sourcecode: chromium-browser version File versions  Download package

go_button_gtk.cc

// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/gtk/go_button_gtk.h"

#include "app/l10n_util.h"
#include "base/i18n/rtl.h"
#include "base/logging.h"
#include "base/message_loop.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/gtk/gtk_chrome_button.h"
#include "chrome/browser/gtk/gtk_theme_provider.h"
#include "chrome/browser/gtk/gtk_util.h"
#include "chrome/browser/gtk/location_bar_view_gtk.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/common/notification_service.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"

// Limit the length of the tooltip text. This applies only to the text in the
// omnibox (e.g. X in "Go to X");
const size_t kMaxTooltipTextLength = 400;

GoButtonGtk::GoButtonGtk(LocationBarViewGtk* location_bar, Browser* browser)
    : location_bar_(location_bar),
      browser_(browser),
      button_delay_(0),
      stop_timer_(this),
      intended_mode_(MODE_GO),
      visible_mode_(MODE_GO),
      theme_provider_(browser ?
                      GtkThemeProvider::GetFrom(browser->profile()) : NULL),
      go_(theme_provider_, IDR_GO, IDR_GO_P, IDR_GO_H, 0, IDR_GO_MASK),
      stop_(theme_provider_, IDR_STOP, IDR_STOP_P, IDR_STOP_H, 0, IDR_GO_MASK),
      widget_(gtk_chrome_button_new()) {
  gtk_widget_set_size_request(widget_.get(), go_.Width(), go_.Height());

  gtk_widget_set_app_paintable(widget_.get(), TRUE);

  g_signal_connect(widget_.get(), "expose-event",
                   G_CALLBACK(OnExpose), this);
  g_signal_connect(widget_.get(), "leave-notify-event",
                   G_CALLBACK(OnLeave), this);
  g_signal_connect(widget_.get(), "clicked",
                   G_CALLBACK(OnClicked), this);
  GTK_WIDGET_UNSET_FLAGS(widget_.get(), GTK_CAN_FOCUS);

  gtk_widget_set_has_tooltip(widget_.get(), TRUE);
  g_signal_connect(widget_.get(), "query-tooltip",
                   G_CALLBACK(OnQueryTooltipThunk), this);

  hover_controller_.Init(widget());
  gtk_util::SetButtonTriggersNavigation(widget());

  if (theme_provider_) {
    theme_provider_->InitThemesFor(this);
    registrar_.Add(this,
                   NotificationType::BROWSER_THEME_CHANGED,
                   NotificationService::AllSources());
  }
}

GoButtonGtk::~GoButtonGtk() {
  widget_.Destroy();
}

void GoButtonGtk::ChangeMode(Mode mode, bool force) {
  intended_mode_ = mode;

  // If the change is forced, or the user isn't hovering the icon, or it's safe
  // to change it to the other image type, make the change immediately;
  // otherwise we'll let it happen later.
  if (force || GTK_WIDGET_STATE(widget()) == GTK_STATE_NORMAL ||
      ((mode == MODE_STOP) ?
        stop_timer_.empty() : (visible_mode_ != MODE_STOP))) {
    stop_timer_.RevokeAll();
    visible_mode_ = mode;
    gtk_widget_queue_draw(widget_.get());

    UpdateThemeButtons();
  }
}

void GoButtonGtk::Observe(NotificationType type,
    const NotificationSource& source, const NotificationDetails& details) {
  DCHECK(NotificationType::BROWSER_THEME_CHANGED == type);

  GtkThemeProvider* provider = static_cast<GtkThemeProvider*>(
      Source<GtkThemeProvider>(source).ptr());
  DCHECK(provider == theme_provider_);
  UpdateThemeButtons();
}

Task* GoButtonGtk::CreateButtonTimerTask() {
  return stop_timer_.NewRunnableMethod(&GoButtonGtk::OnButtonTimer);
}

void GoButtonGtk::OnButtonTimer() {
  stop_timer_.RevokeAll();
  ChangeMode(intended_mode_, true);
}

// static
gboolean GoButtonGtk::OnExpose(GtkWidget* widget,
                               GdkEventExpose* e,
                               GoButtonGtk* button) {
  if (button->theme_provider_ && button->theme_provider_->UseGtkTheme()) {
    return FALSE;
  } else {
    double hover_state = button->hover_controller_.GetCurrentValue();
    if (button->visible_mode_ == MODE_GO) {
      return button->go_.OnExpose(widget, e, hover_state);
    } else {
      return button->stop_.OnExpose(widget, e, hover_state);
    }
  }
}

// static
gboolean GoButtonGtk::OnLeave(GtkWidget* widget,
                              GdkEventCrossing* event,
                              GoButtonGtk* button) {
  button->ChangeMode(button->intended_mode_, true);
  return FALSE;
}

// static
gboolean GoButtonGtk::OnClicked(GtkButton* widget, GoButtonGtk* button) {
  if (button->visible_mode_ == MODE_STOP) {
    if (button->browser_)
      button->browser_->Stop();

    // The user has clicked, so we can feel free to update the button,
    // even if the mouse is still hovering.
    button->ChangeMode(MODE_GO, true);
  } else if (button->visible_mode_ == MODE_GO && button->stop_timer_.empty()) {
    // If the go button is visible and not within the double click timer, go.
    if (button->browser_) {
      button->browser_->ExecuteCommandWithDisposition(IDC_GO,
          gtk_util::DispositionForCurrentButtonPressEvent());
    }

    // Figure out the system double-click time.
    if (button->button_delay_ == 0) {
      GtkSettings* settings = gtk_settings_get_default();
      g_object_get(G_OBJECT(settings),
                   "gtk-double-click-time",
                   &button->button_delay_,
                   NULL);
    }

    // Stop any existing timers.
    button->stop_timer_.RevokeAll();

    // Start a timer - while this timer is running, the go button
    // cannot be changed to a stop button. We do not set intended_mode_
    // to MODE_STOP here as we want to wait for the browser to tell
    // us that it has started loading (and this may occur only after
    // some delay).
    MessageLoop::current()->PostDelayedTask(FROM_HERE,
                                            button->CreateButtonTimerTask(),
                                            button->button_delay_);
  }

  return TRUE;
}

gboolean GoButtonGtk::OnQueryTooltip(GtkTooltip* tooltip) {
  // |location_bar_| can be NULL in tests.
  if (!location_bar_)
    return FALSE;

  std::string text;
  if (visible_mode_ == MODE_GO) {
    std::wstring current_text_wstr(location_bar_->location_entry()->GetText());
    if (base::i18n::IsRTL())
      base::i18n::WrapStringWithLTRFormatting(&current_text_wstr);
    string16 current_text = WideToUTF16Hack(
        l10n_util::TruncateString(current_text_wstr, kMaxTooltipTextLength));

    AutocompleteEditModel* edit_model =
        location_bar_->location_entry()->model();
    if (edit_model->CurrentTextIsURL()) {
      text = l10n_util::GetStringFUTF8(IDS_TOOLTIP_GO_SITE, current_text);
    } else {
      std::wstring keyword(edit_model->keyword());
      TemplateURLModel* template_url_model =
          browser_->profile()->GetTemplateURLModel();
      const TemplateURL* provider =
          (keyword.empty() || edit_model->is_keyword_hint()) ?
          template_url_model->GetDefaultSearchProvider() :
          template_url_model->GetTemplateURLForKeyword(keyword);
      if (!provider)
        return FALSE;  // Don't show a tooltip.
      text = l10n_util::GetStringFUTF8(IDS_TOOLTIP_GO_SEARCH,
          WideToUTF16Hack(provider->AdjustedShortNameForLocaleDirection()),
          current_text);
    }
  } else {
    text = l10n_util::GetStringUTF8(IDS_TOOLTIP_STOP);
  }

  gtk_tooltip_set_text(tooltip, text.c_str());
  return TRUE;
}

void GoButtonGtk::UpdateThemeButtons() {
  bool use_gtk = theme_provider_ && theme_provider_->UseGtkTheme();

  if (use_gtk) {
    GdkPixbuf* pixbuf = NULL;
    if (intended_mode_ == MODE_GO) {
      pixbuf = theme_provider_->GetPixbufNamed(IDR_GO_NOBORDER_CENTER);
    } else {
      pixbuf = theme_provider_->GetPixbufNamed(IDR_STOP_NOBORDER_CENTER);
    }

    gtk_button_set_image(
        GTK_BUTTON(widget_.get()),
        gtk_image_new_from_pixbuf(pixbuf));

    gtk_widget_set_size_request(widget_.get(), -1, -1);
    gtk_widget_set_app_paintable(widget_.get(), FALSE);
    gtk_widget_set_double_buffered(widget_.get(), TRUE);
  } else {
    gtk_widget_set_size_request(widget_.get(), go_.Width(), go_.Height());

    gtk_widget_set_app_paintable(widget_.get(), TRUE);
    // We effectively double-buffer by virtue of having only one image...
    gtk_widget_set_double_buffered(widget_.get(), FALSE);
  }

  gtk_chrome_button_set_use_gtk_rendering(
      GTK_CHROME_BUTTON(widget_.get()), use_gtk);
}

Generated by  Doxygen 1.6.0   Back to index