<commit_before>// 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 "base/logging.h"
#include "base/message_loop.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/gtk/location_bar_view_gtk.h"
#include "chrome/common/l10n_util.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"

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),
      state_(BS_NORMAL),
      go_(IDR_GO, IDR_GO_P, IDR_GO_H, 0),
      stop_(IDR_STOP, IDR_STOP_P, IDR_STOP_H, 0),
      widget_(gtk_button_new()) {
  gtk_widget_set_size_request(widget_.get(),
                              gdk_pixbuf_get_width(go_.pixbufs(0)),
                              gdk_pixbuf_get_height(go_.pixbufs(0)));

  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);

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

  SetTooltip();
}

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 || (state() != BS_HOT) || ((mode == MODE_STOP) ?
      stop_timer_.empty() : (visible_mode_ != MODE_STOP))) {
    stop_timer_.RevokeAll();
    gtk_widget_queue_draw(widget_.get());
    SetTooltip();
    visible_mode_ = mode;
  }
}

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->visible_mode_ == MODE_GO) {
    return button->go_.OnExpose(widget, e);
  } else {
    return button->stop_.OnExpose(widget, e);
  }
}

// static
gboolean GoButtonGtk::OnEnter(GtkButton* widget, GoButtonGtk* button) {
  DCHECK_EQ(BS_NORMAL, button->state());
  button->state_ = BS_HOT;
  return TRUE;
}

// static
gboolean GoButtonGtk::OnLeave(GtkButton* widget, GoButtonGtk* button) {
  DCHECK_EQ(BS_HOT, button->state());
  button->state_ = BS_NORMAL;
  button->ChangeMode(button->intended_mode_, true);
  return TRUE;
}

// 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.<commit_msg>Linux: Stop hitting a DCHECK in GoButtonGtk on shutdown. Turns out we can get 2 gtk leave events in a row on shutdown, if the cursor is already hovering over the go button. BUG=10851<commit_after>// 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 "base/logging.h"
#include "base/message_loop.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/gtk/location_bar_view_gtk.h"
#include "chrome/common/l10n_util.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"

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),
      state_(BS_NORMAL),
      go_(IDR_GO, IDR_GO_P, IDR_GO_H, 0),
      stop_(IDR_STOP, IDR_STOP_P, IDR_STOP_H, 0),
      widget_(gtk_button_new()) {
  gtk_widget_set_size_request(widget_.get(),
                              gdk_pixbuf_get_width(go_.pixbufs(0)),
                              gdk_pixbuf_get_height(go_.pixbufs(0)));

  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);

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

  SetTooltip();
}

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 || (state() != BS_HOT) || ((mode == MODE_STOP) ?
      stop_timer_.empty() : (visible_mode_ != MODE_STOP))) {
    stop_timer_.RevokeAll();
    gtk_widget_queue_draw(widget_.get());
    SetTooltip();
    visible_mode_ = mode;
  }
}

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->visible_mode_ == MODE_GO) {
    return button->go_.OnExpose(widget, e);
  } else {
    return button->stop_.OnExpose(widget, e);
  }
}

// static
gboolean GoButtonGtk::OnEnter(GtkButton* widget, GoButtonGtk* button) {
  DCHECK_EQ(BS_NORMAL, button->state());
  button->state_ = BS_HOT;
  return TRUE;
}

// static
gboolean GoButtonGtk::OnLeave(GtkButton* widget, GoButtonGtk* button) {
  // It's possible on shutdown for a "leave" event to be emitted twice in a row
  // for this button.  I'm not sure if this is a gtk quirk or something wrong
  // with our usage, but it's harmless.  I'm commenting out this DCHECK for now.
  // and adding a LOG(WARNING) instead.
  // See http://www.crbug.com/10851 for details.
  // DCHECK_EQ(BS_HOT, button->state());
  if (button->state() != BS_HOT)
    LOG(WARNING) << "Button state should be BS_HOT when leaving.";
  button->state_ = BS_NORMAL;
  button->ChangeMode(button->intended_mode_, true);
  return TRUE;
}

// 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.
{'fraction_non_alphanumeric': 0.12429305912596401, 'fraction_numerical': 0.004241645244215938, 'mean_word_length': 3.6232917409387997, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 30, 'https://': 0, 'lorem ipsum': 0, 'www.': 1, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4720747', 'n_tokens_mistral': 2661, 'n_tokens_neox': 2595, 'n_words': 583}