<commit_before>/* GTK - The GIMP Toolkit
 * Copyright (C) 1995-1997 <NAME>, <NAME> and <NAME>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
 */

/*
 * Modified by the GTK+ Team and others 1997-2001.  See the AUTHORS
 * file for a list of people on the GTK+ Team.  See the ChangeLog
 * files for a list of changes.  These files are distributed with
 * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
 */

/**
 * SECTION:gtkbutton
 * @Short_description: A widget that emits a signal when clicked on
 * @Title: GtkButton
 *
 * The #GtkButton widget is generally used to trigger a callback function that is
 * called when the button is pressed.  The various signals and how to use them
 * are outlined below.
 *
 * The #GtkButton widget can hold any valid child widget.  That is, it can hold
 * almost any other standard #GtkWidget.  The most commonly used child is the
 * #GtkLabel.
 */

#include "config.h"

#include "gtkbutton.h"
#include "gtkbuttonprivate.h"

#include <string.h>
#include "deprecated/gtkalignment.h"
#include "gtklabel.h"
#include "gtkmain.h"
#include "gtkmarshalers.h"
#include "gtkimage.h"
#include "gtkbox.h"
#include "deprecated/gtkstock.h"
#include "deprecated/gtkactivatable.h"
#include "gtksizerequest.h"
#include "gtktypebuiltins.h"
#include "gtkwidgetprivate.h"
#include "gtkprivate.h"
#include "gtkintl.h"
#include "a11y/gtkbuttonaccessible.h"
#include "gtkapplicationprivate.h"
#include "gtkactionhelper.h"

static const GtkBorder default_default_border = { 0, 0, 0, 0 };
static const GtkBorder default_default_outside_border = { 0, 0, 0, 0 };

/* Time out before giving up on getting a key release when animating
 * the close button.
 */
#define ACTIVATE_TIMEOUT 250


enum {
  PRESSED,
  RELEASED,
  CLICKED,
  ENTER,
  LEAVE,
  ACTIVATE,
  LAST_SIGNAL
};

enum {
  PROP_0,
  PROP_LABEL,
  PROP_IMAGE,
  PROP_RELIEF,
  PROP_USE_UNDERLINE,
  PROP_USE_STOCK,
  PROP_FOCUS_ON_CLICK,
  PROP_XALIGN,
  PROP_YALIGN,
  PROP_IMAGE_POSITION,
  PROP_ALWAYS_SHOW_IMAGE,

  /* actionable properties */
  PROP_ACTION_NAME,
  PROP_ACTION_TARGET,

  /* activatable properties */
  PROP_ACTIVATABLE_RELATED_ACTION,
  PROP_ACTIVATABLE_USE_ACTION_APPEARANCE,
  LAST_PROP = PROP_ACTION_NAME
};


static void gtk_button_destroy        (GtkWidget          *widget);
static void gtk_button_dispose        (GObject            *object);
static void gtk_button_set_property   (GObject            *object,
                                       guint               prop_id,
                                       const GValue       *value,
                                       GParamSpec         *pspec);
static void gtk_button_get_property   (GObject            *object,
                                       guint               prop_id,
                                       GValue             *value,
                                       GParamSpec         *pspec);
static void gtk_button_screen_changed (GtkWidget          *widget,
				       GdkScreen          *previous_screen);
static void gtk_button_realize (GtkWidget * widget);
static void gtk_button_unrealize (GtkWidget * widget);
static void gtk_button_map (GtkWidget * widget);
static void gtk_button_unmap (GtkWidget * widget);
static void gtk_button_style_updated (GtkWidget * widget);
static void gtk_button_size_allocate (GtkWidget * widget,
				      GtkAllocation * allocation);
static gint gtk_button_draw (GtkWidget * widget, cairo_t *cr);
static gint gtk_button_grab_broken (GtkWidget * widget,
				    GdkEventGrabBroken * event);
static gint gtk_button_key_release (GtkWidget * widget, GdkEventKey * event);
static gint gtk_button_enter_notify (GtkWidget * widget,
				     GdkEventCrossing * event);
static gint gtk_button_leave_notify (GtkWidget * widget,
				     GdkEventCrossing * event);
static void gtk_real_button_pressed (GtkButton * button);
static void gtk_real_button_released (GtkButton * button);
static void gtk_real_button_clicked (GtkButton * button);
static void gtk_real_button_activate  (GtkButton          *button);
static void gtk_button_update_state   (GtkButton          *button);
static void gtk_button_enter_leave    (GtkButton          *button);
static void gtk_button_add            (GtkContainer       *container,
			               GtkWidget          *widget);
static GType gtk_button_child_type    (GtkContainer       *container);
static void gtk_button_finish_activate (GtkButton         *button,
					gboolean           do_it);

static void gtk_button_constructed (GObject *object);
static void gtk_button_construct_child (GtkButton             *button);
static void gtk_button_state_changed   (GtkWidget             *widget,
					GtkStateType           previous_state);
static void gtk_button_grab_notify     (GtkWidget             *widget,
					gboolean               was_grabbed);

static void gtk_button_actionable_iface_init     (GtkActionableInterface *iface);
static void gtk_button_activatable_interface_init(GtkActivatableIface  *iface);
static void gtk_button_update                    (GtkActivatable       *activatable,
				                  GtkAction            *action,
			                          const gchar          *property_name);
static void gtk_button_sync_action_properties    (GtkActivatable       *activatable,
                                                  GtkAction            *action);
static void gtk_button_set_related_action        (GtkButton            *button,
					          GtkAction            *action);
static void gtk_button_set_use_action_appearance (GtkButton            *button,
						  gboolean              use_appearance);

static void gtk_button_get_preferred_width             (GtkWidget           *widget,
                                                        gint                *minimum_size,
                                                        gint                *natural_size);
static void gtk_button_get_preferred_height            (GtkWidget           *widget,
                                                        gint                *minimum_size,
                                                        gint                *natural_size);
static void gtk_button_get_preferred_width_for_height  (GtkWidget           *widget,
                                                        gint                 for_size,
                                                        gint                *minimum_size,
                                                        gint                *natural_size);
static void gtk_button_get_preferred_height_for_width  (GtkWidget           *widget,
                                                        gint                 for_size,
                                                        gint                *minimum_size,
                                                        gint                *natural_size);
static void gtk_button_get_preferred_height_and_baseline_for_width (GtkWidget *widget,
								    gint       width,
								    gint      *minimum_size,
								    gint      *natural_size,
								    gint      *minimum_baseline,
								    gint      *natural_baseline);
  
static GParamSpec *props[LAST_PROP] = { NULL, };
static guint button_signals[LAST_SIGNAL] = { 0 };

G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
G_DEFINE_TYPE_WITH_CODE (GtkButton, gtk_button, GTK_TYPE_BIN,
                         G_ADD_PRIVATE (GtkButton)
                         G_IMPLEMENT_INTERFACE (GTK_TYPE_ACTIONABLE, gtk_button_actionable_iface_init)
			 G_IMPLEMENT_INTERFACE (GTK_TYPE_ACTIVATABLE,
						gtk_button_activatable_interface_init))
G_GNUC_END_IGNORE_DEPRECATIONS;

static void
gtk_button_class_init (GtkButtonClass *klass)
{
  GObjectClass *gobject_class;
  GtkWidgetClass *widget_class;
  GtkContainerClass *container_class;

  gobject_class = G_OBJECT_CLASS (klass);
  widget_class = (GtkWidgetClass*) klass;
  container_class = (GtkContainerClass*) klass;
  
  gobject_class->constructed  = gtk_button_constructed;
  gobject_class->dispose      = gtk_button_dispose;
  gobject_class->set_property = gtk_button_set_property;
  gobject_class->get_property = gtk_button_get_property;

  widget_class->get_preferred_width = gtk_button_get_preferred_width;
  widget_class->get_preferred_height = gtk_button_get_preferred_height;
  widget_class->get_preferred_width_for_height = gtk_button_get_preferred_width_for_height;
  widget_class->get_preferred_height_for_width = gtk_button_get_preferred_height_for_width;
  widget_class->get_preferred_height_and_baseline_for_width = gtk_button_get_preferred_height_and_baseline_for_width;
  widget_class->destroy = gtk_button_destroy;
  widget_class->screen_changed = gtk_button_screen_changed;
  widget_class->realize = gtk_button_realize;
  widget_class->unrealize = gtk_button_unrealize;
  widget_class->map = gtk_button_map;
  widget_class->unmap = gtk_button_unmap;
  widget_class->style_updated = gtk_button_style_updated;
  widget_class->size_allocate = gtk_button_size_allocate;
  widget_class->draw = gtk_button_draw;
  widget_class->grab_broken_event = gtk_button_grab_broken;
  widget_class->key_release_event = gtk_button_key_release;
  widget_class->enter_notify_event = gtk_button_enter_notify;
  widget_class->leave_notify_event = gtk_button_leave_notify;
  widget_class->state_changed = gtk_button_state_changed;
  widget_class->grab_notify = gtk_button_grab_notify;

  container_class->child_type = gtk_button_child_type;
  container_class->add = gtk_button_add;
  gtk_container_class_handle_border_width (container_class);

  klass->pressed = gtk_real_button_pressed;
  klass->released = gtk_real_button_released;
  klass->clicked = NULL;
  klass->enter = gtk_button_enter_leave;
  klass->leave = gtk_button_enter_leave;
  klass->activate = gtk_real_button_activate;

  props[PROP_LABEL] =
    g_param_spec_string ("label",
                         P_("Label"),
                         P_("Text of the label widget inside the button, if the button contains a label widget"),
                         NULL,
                         GTK_PARAM_READWRITE|G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY);
  
  props[PROP_USE_UNDERLINE] =
    g_param_spec_boolean ("use-underline",
                          P_("Use underline"),
                          P_("If set, an underline in the text indicates the next character should be used for the mnemonic accelerator key"),
                          FALSE,
                          GTK_PARAM_READWRITE|G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY);
  
  /**
   * GtkButton:use-stock:
   *
   * Deprecated: 3.10
   */
  props[PROP_USE_STOCK] =
    g_param_spec_boolean ("use-stock",
                          P_("Use stock"),
                          P_("If set, the label is used to pick a stock item instead of being displayed"),
                          FALSE,
                          GTK_PARAM_READWRITE|G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_DEPRECATED);
  
  props[PROP_FOCUS_ON_CLICK] =
    g_param_spec_boolean ("focus-on-click",
                          P_("Focus on click"),
                          P_("Whether the button grabs focus when it is clicked with the mouse"),
                          TRUE,
                          GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
  
  props[PROP_RELIEF] =
    g_param_spec_enum ("relief",
                       P_("Border relief"),
                       P_("The border relief style"),
                       GTK_TYPE_RELIEF_STYLE,
                       GTK_RELIEF_NORMAL,
                       GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
  
  /**
   * GtkButton:xalign:
   *
   * If the child of the button is a #GtkMisc or #GtkAlignment, this property 
   * can be used to control its horizontal alignment. 0.0 is left aligned, 
   * 1.0 is right aligned.
   *
   * Since: 2.4
   *
   * Deprecated: 3.14: Access the child widget directly if you need to control
   * its alignment.
   */
  props[PROP_XALIGN] =
    g_param_spec_float ("xalign",
                        P_("Horizontal alignment for child"),
                        P_("Horizontal position of child in available space. 0.0 is left aligned, 1.0 is right aligned"),
                        0.0, 1.0, 0.5,
                        GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_DEPRECATED);

  /**
   * GtkButton:yalign:
   *
   * If the child of the button is a #GtkMisc or #GtkAlignment, this property 
   * can be used to control its vertical alignment. 0.0 is top aligned, 
   * 1.0 is bottom aligned.
   *
   * Since: 2.4
   *
   * Deprecated: 3.14: Access the child widget directly if you need to control
   * its alignment.
   */
  props[PROP_YALIGN] =
    g_param_spec_float ("yalign",
                        P_("Vertical alignment for child"),
                        P_("Vertical position of child in available space. 0.0 is top aligned, 1.0 is bottom aligned"),
                        0.0, 1.0, 0.5,
                        GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_DEPRECATED);

  /**
   * GtkButton:image:
   *
   * The child widget to appear next to the button text.
   *
   * Since: 2.6
   */
  props[PROP_IMAGE] =
    g_param_spec_object ("image",
                         P_("Image widget"),
                         P_("Child widget to appear next to the button text"),
                         GTK_TYPE_WIDGET,
                         GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);

  /**
   * GtkButton:image-position:
   *
   * The position of the image relative to the text inside the button.
   *
   * Since: 2.10
   */
  props[PROP_IMAGE_POSITION] =
    g_param_spec_enum ("image-position",
                       P_("Image position"),
                       P_("The position of the image relative to the text"),
                       GTK_TYPE_POSITION_TYPE,
                       GTK_POS_LEFT,
                       GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);

  /**
   * GtkButton:always-show-image:
   *
   * If %TRUE, the button will ignore the #GtkSettings:gtk-button-images
   * setting and always show the image, if available.
   *
   * Use this property if the button would be useless or hard to use
   * without the image.
   *
   * Since: 3.6
   */
  props[PROP_ALWAYS_SHOW_IMAGE] =
     g_param_spec_boolean ("always-show-image",
                           P_("Always show image"),
                           P_("Whether the image will always be shown"),
                           FALSE,
                           GTK_PARAM_READWRITE|G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY);

  g_object_class_install_properties (gobject_class, LAST_PROP, props);

  g_object_class_override_property (gobject_class, PROP_ACTION_NAME, "action-name");
  g_object_class_override_property (gobject_class, PROP_ACTION_TARGET, "action-target");

  G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
  g_object_class_override_property (gobject_class, PROP_ACTIVATABLE_RELATED_ACTION, "related-action");
  g_object_class_override_property (gobject_class, PROP_ACTIVATABLE_USE_ACTION_APPEARANCE, "use-action-appearance");
  G_GNUC_END_IGNORE_DEPRECATIONS;

  /**
   * GtkButton::pressed:
   * @button: the object that received the signal
   *
   * Emitted when the button is pressed.
   *
   * Deprecated: 2.8: Use the #GtkWidget::button-press-event signal.
   */ 
  button_signals[PRESSED] =
    g_signal_new (I_("pressed"),
		  G_OBJECT_CLASS_TYPE (gobject_class),
		  G_SIGNAL_RUN_FIRST,
		  G_STRUCT_OFFSET (GtkButtonClass, pressed),
		  NULL, NULL,
		  _gtk_marshal_VOID__VOID,
		  G_TYPE_NONE, 0);

  /**
   * GtkButton::released:
   * @button: the object that received the signal
   *
   * Emitted when the button is released.
   *
   * Deprecated: 2.8: Use the #GtkWidget::button-release-event signal.
   */ 
  button_signals[RELEASED] =
    g_signal_new (I_("released"),
		  G_OBJECT_CLASS_TYPE (gobject_class),
		  G_SIGNAL_RUN_FIRST,
		  G_STRUCT_OFFSET (GtkButtonClass, released),
		  NULL, NULL,
		  _gtk_marshal_VOID__VOID,
		  G_TYPE_NONE, 0);

  /**
   * GtkButton::clicked:
   * @button: the object that received the signal
   *
   * Emitted when the button has been activated (pressed and released).
   */ 
  button_signals[CLICKED] =
    g_signal_new (I_("clicked"),
		  G_OBJECT_CLASS_TYPE (gobject_class),
		  G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
		  G_STRUCT_OFFSET (GtkButtonClass, clicked),
		  NULL, NULL,
		  _gtk_marshal_VOID__VOID,
		  G_TYPE_NONE, 0);

  /**
   * GtkButton::enter:
   * @button: the object that received the signal
   *
   * Emitted when the pointer enters the button.
   *
   * Deprecated: 2.8: Use the #GtkWidget::enter-notify-event signal.
   */ 
  button_signals[ENTER] =
    g_signal_new (I_("enter"),
		  G_OBJECT_CLASS_TYPE (gobject_class),
		  G_SIGNAL_RUN_FIRST,
		  G_STRUCT_OFFSET (GtkButtonClass, enter),
		  NULL, NULL,
		  _gtk_marshal_VOID__VOID,
		  G_TYPE_NONE, 0);

  /**
   * GtkButton::leave:
   * @button: the object that received the signal
   *
   * Emitted when the pointer leaves the button.
   *
   * Deprecated: 2.8: Use the #GtkWidget::leave-notify-event signal.
   */ 
  button_signals[LEAVE] =
    g_signal_new (I_("leave"),
		  G_OBJECT_CLASS_TYPE (gobject_class),
		  G_SIGNAL_RUN_FIRST,
		  G_STRUCT_OFFSET (GtkButtonClass, leave),
		  NULL, NULL,
		  _gtk_marshal_VOID__VOID,
		  G_TYPE_NONE, 0);

  /**
   * GtkButton::activate:
   * @widget: the object which received the signal.
   *
   * The ::activate signal on GtkButton is an action signal and
   * emitting it causes the button to animate press then release. 
   * Applications should never connect to this signal, but use the
   * #GtkButton::clicked signal.
   */
  button_signals[ACTIVATE] =
    g_signal_new (I_("activate"),
		  G_OBJECT_CLASS_TYPE (gobject_class),
		  G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
		  G_STRUCT_OFFSET (GtkButtonClass, activate),
		  NULL, NULL,
		  _gtk_marshal_VOID__VOID,
		  G_TYPE_NONE, 0);
  widget_class->activate_signal = button_signals[ACTIVATE];

  /**
   * GtkButton:default-border:
   *
   * The "default-border" style property defines the extra space to add
   * around a button that can become the default widget of its window.
   * For more information about default widgets, see gtk_widget_grab_default().
   *
   * Deprecated: 3.14: use CSS margins and padding instead.
   */

  gtk_widget_class_install_style_property (widget_class,
					   g_param_spec_boxed ("default-border",
							       P_("Default Spacing"),
							       P_("Extra space to add for GTK_CAN_DEFAULT buttons"),
							       GTK_TYPE_BORDER,
							       GTK_PARAM_READABLE|G_PARAM_DEPRECATED));

  /**
   * GtkButton:default-outside-border:
   *
   * The "default-outside-border" style property defines the extra outside
   * space to add around a button that can become the default widget of its
   * window. Extra outside space is always drawn outside the button border.
   * For more information about default widgets, see gtk_widget_grab_default().
   *
   * Deprecated: 3.14: use CSS margins and padding instead.
   */
  gtk_widget_class_install_style_property (widget_class,
					   g_param_spec_boxed ("default-outside-border",
							       P_("Default Outside Spacing"),
							       P_("Extra space to add for GTK_CAN_DEFAULT buttons that is always drawn outside the border"),
							       GTK_TYPE_BORDER,
							       GTK_PARAM_READABLE|G_PARAM_DEPRECATED));
  gtk_widget_class_install_style_property (widget_class,
					   g_param_spec_int ("child-displacement-x",
							     P_("Child X Displacement"),
							     P_("How far in the x direction to move the child when the button is depressed"),
							     G_MININT,
							     G_MAXINT,
							     0,
							     GTK_PARAM_READABLE|G_PARAM_DEPRECATED));
  gtk_widget_class_install_style_property (widget_class,
					   g_param_spec_int ("child-displacement-y",
							     P_("Child Y Displacement"),
							     P_("How far in the y direction to move the child when the button is depressed"),
							     G_MININT,
							     G_MAXINT,
							     0,
							     GTK_PARAM_READABLE|G_PARAM_DEPRECATED));

  /**
   * GtkButton:displace-focus:
   *
   * Whether the child_displacement_x/child_displacement_y properties 
   * should also affect the focus rectangle.
   *
   * Since: 2.6
   */
  gtk_widget_class_install_style_property (widget_class,
					   g_param_spec_boolean ("displace-focus",
								 P_("Displace focus"),
								 P_("Whether the child_displacement_x/_y properties should also affect the focus rectangle"),
								 FALSE,
								 GTK_PARAM_READABLE|G_PARAM_DEPRECATED));

  /**
   * GtkButton:inner-border:
   *
   * Sets the border between the button edges and child.
   *
   * Since: 2.10
   *
   * Deprecated: 3.4: Use the standard border and padding CSS properties;
   *   the value of this style property is ignored.
   */
  gtk_widget_class_install_style_property (widget_class,
					   g_param_spec_boxed ("inner-border",
                                                               P_("Inner Border"),
                                                               P_("Border between button edges and child."),
                                                               GTK_TYPE_BORDER,
                                                               GTK_PARAM_READABLE | G_PARAM_DEPRECATED));

  /**
   * GtkButton::image-spacing:
   *
   * Spacing in pixels between the image and label.
   *
   * Since: 2.10
   */
  gtk_widget_class_install_style_property (widget_class,
					   g_param_spec_int ("image-spacing",
							     P_("Image spacing"),
							     P_("Spacing in pixels between the image and label"),
							     0,
							     G_MAXINT,
							     2,
							     GTK_PARAM_READABLE));

  gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_BUTTON_ACCESSIBLE);
}

static void
multipress_pressed_cb (GtkGestureMultiPress *gesture,
                       guint                 n_press,
                       gdouble               x,
                       gdouble               y,
                       GtkWidget            *widget)
{
  GtkButton *button = GTK_BUTTON (widget);
  GtkButtonPrivate *priv = button->priv;

  if (priv->focus_on_click && !gtk_widget_has_focus (widget))
    gtk_widget_grab_focus (widget);

  priv->in_button = TRUE;
  g_signal_emit (button, button_signals[PRESSED], 0);
  gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
}

static void
multipress_released_cb (GtkGestureMultiPress *gesture,
                        guint                 n_press,
                        gdouble               x,
                        gdouble               y,
                        GtkWidget            *widget)
{
  GtkButton *button = GTK_BUTTON (widget);
  GtkButtonPrivate *priv = button->priv;
  GdkEventSequence *sequence;
  const GdkEvent *event;
  GdkDevice *source;

  sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
  event = gtk_gesture_get_last_event (GTK_GESTURE (gesture), sequence);
  if (event)
    {
      source = gdk_event_get_source_device (event);
      if (source && gdk_device_get_source (source) == GDK_SOURCE_TOUCHSCREEN)
        priv->in_button = FALSE;
    }
  g_signal_emit (button, button_signals[RELEASED], 0);
}

static void
multipress_gesture_update_cb (GtkGesture       *gesture,
                              GdkEventSequence *sequence,
                              GtkButton        *button)
{
  GtkButtonPrivate *priv = button->priv;
  GtkAllocation allocation;
  gboolean in_button;
  gdouble x, y;

  if (sequence != gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture)))
    return;
<commit_msg>button: Fix ::clicked emission on touchscreens sending pointer events<commit_after>/* GTK - The GIMP Toolkit
 * Copyright (C) 1995-1997 <NAME>, <NAME> and <NAME>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
 */

/*
 * Modified by the GTK+ Team and others 1997-2001.  See the AUTHORS
 * file for a list of people on the GTK+ Team.  See the ChangeLog
 * files for a list of changes.  These files are distributed with
 * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
 */

/**
 * SECTION:gtkbutton
 * @Short_description: A widget that emits a signal when clicked on
 * @Title: GtkButton
 *
 * The #GtkButton widget is generally used to trigger a callback function that is
 * called when the button is pressed.  The various signals and how to use them
 * are outlined below.
 *
 * The #GtkButton widget can hold any valid child widget.  That is, it can hold
 * almost any other standard #GtkWidget.  The most commonly used child is the
 * #GtkLabel.
 */

#include "config.h"

#include "gtkbutton.h"
#include "gtkbuttonprivate.h"

#include <string.h>
#include "deprecated/gtkalignment.h"
#include "gtklabel.h"
#include "gtkmain.h"
#include "gtkmarshalers.h"
#include "gtkimage.h"
#include "gtkbox.h"
#include "deprecated/gtkstock.h"
#include "deprecated/gtkactivatable.h"
#include "gtksizerequest.h"
#include "gtktypebuiltins.h"
#include "gtkwidgetprivate.h"
#include "gtkprivate.h"
#include "gtkintl.h"
#include "a11y/gtkbuttonaccessible.h"
#include "gtkapplicationprivate.h"
#include "gtkactionhelper.h"

static const GtkBorder default_default_border = { 0, 0, 0, 0 };
static const GtkBorder default_default_outside_border = { 0, 0, 0, 0 };

/* Time out before giving up on getting a key release when animating
 * the close button.
 */
#define ACTIVATE_TIMEOUT 250


enum {
  PRESSED,
  RELEASED,
  CLICKED,
  ENTER,
  LEAVE,
  ACTIVATE,
  LAST_SIGNAL
};

enum {
  PROP_0,
  PROP_LABEL,
  PROP_IMAGE,
  PROP_RELIEF,
  PROP_USE_UNDERLINE,
  PROP_USE_STOCK,
  PROP_FOCUS_ON_CLICK,
  PROP_XALIGN,
  PROP_YALIGN,
  PROP_IMAGE_POSITION,
  PROP_ALWAYS_SHOW_IMAGE,

  /* actionable properties */
  PROP_ACTION_NAME,
  PROP_ACTION_TARGET,

  /* activatable properties */
  PROP_ACTIVATABLE_RELATED_ACTION,
  PROP_ACTIVATABLE_USE_ACTION_APPEARANCE,
  LAST_PROP = PROP_ACTION_NAME
};


static void gtk_button_destroy        (GtkWidget          *widget);
static void gtk_button_dispose        (GObject            *object);
static void gtk_button_set_property   (GObject            *object,
                                       guint               prop_id,
                                       const GValue       *value,
                                       GParamSpec         *pspec);
static void gtk_button_get_property   (GObject            *object,
                                       guint               prop_id,
                                       GValue             *value,
                                       GParamSpec         *pspec);
static void gtk_button_screen_changed (GtkWidget          *widget,
				       GdkScreen          *previous_screen);
static void gtk_button_realize (GtkWidget * widget);
static void gtk_button_unrealize (GtkWidget * widget);
static void gtk_button_map (GtkWidget * widget);
static void gtk_button_unmap (GtkWidget * widget);
static void gtk_button_style_updated (GtkWidget * widget);
static void gtk_button_size_allocate (GtkWidget * widget,
				      GtkAllocation * allocation);
static gint gtk_button_draw (GtkWidget * widget, cairo_t *cr);
static gint gtk_button_grab_broken (GtkWidget * widget,
				    GdkEventGrabBroken * event);
static gint gtk_button_key_release (GtkWidget * widget, GdkEventKey * event);
static gint gtk_button_enter_notify (GtkWidget * widget,
				     GdkEventCrossing * event);
static gint gtk_button_leave_notify (GtkWidget * widget,
				     GdkEventCrossing * event);
static void gtk_real_button_pressed (GtkButton * button);
static void gtk_real_button_released (GtkButton * button);
static void gtk_real_button_clicked (GtkButton * button);
static void gtk_real_button_activate  (GtkButton          *button);
static void gtk_button_update_state   (GtkButton          *button);
static void gtk_button_enter_leave    (GtkButton          *button);
static void gtk_button_add            (GtkContainer       *container,
			               GtkWidget          *widget);
static GType gtk_button_child_type    (GtkContainer       *container);
static void gtk_button_finish_activate (GtkButton         *button,
					gboolean           do_it);

static void gtk_button_constructed (GObject *object);
static void gtk_button_construct_child (GtkButton             *button);
static void gtk_button_state_changed   (GtkWidget             *widget,
					GtkStateType           previous_state);
static void gtk_button_grab_notify     (GtkWidget             *widget,
					gboolean               was_grabbed);

static void gtk_button_actionable_iface_init     (GtkActionableInterface *iface);
static void gtk_button_activatable_interface_init(GtkActivatableIface  *iface);
static void gtk_button_update                    (GtkActivatable       *activatable,
				                  GtkAction            *action,
			                          const gchar          *property_name);
static void gtk_button_sync_action_properties    (GtkActivatable       *activatable,
                                                  GtkAction            *action);
static void gtk_button_set_related_action        (GtkButton            *button,
					          GtkAction            *action);
static void gtk_button_set_use_action_appearance (GtkButton            *button,
						  gboolean              use_appearance);

static void gtk_button_get_preferred_width             (GtkWidget           *widget,
                                                        gint                *minimum_size,
                                                        gint                *natural_size);
static void gtk_button_get_preferred_height            (GtkWidget           *widget,
                                                        gint                *minimum_size,
                                                        gint                *natural_size);
static void gtk_button_get_preferred_width_for_height  (GtkWidget           *widget,
                                                        gint                 for_size,
                                                        gint                *minimum_size,
                                                        gint                *natural_size);
static void gtk_button_get_preferred_height_for_width  (GtkWidget           *widget,
                                                        gint                 for_size,
                                                        gint                *minimum_size,
                                                        gint                *natural_size);
static void gtk_button_get_preferred_height_and_baseline_for_width (GtkWidget *widget,
								    gint       width,
								    gint      *minimum_size,
								    gint      *natural_size,
								    gint      *minimum_baseline,
								    gint      *natural_baseline);
  
static GParamSpec *props[LAST_PROP] = { NULL, };
static guint button_signals[LAST_SIGNAL] = { 0 };

G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
G_DEFINE_TYPE_WITH_CODE (GtkButton, gtk_button, GTK_TYPE_BIN,
                         G_ADD_PRIVATE (GtkButton)
                         G_IMPLEMENT_INTERFACE (GTK_TYPE_ACTIONABLE, gtk_button_actionable_iface_init)
			 G_IMPLEMENT_INTERFACE (GTK_TYPE_ACTIVATABLE,
						gtk_button_activatable_interface_init))
G_GNUC_END_IGNORE_DEPRECATIONS;

static void
gtk_button_class_init (GtkButtonClass *klass)
{
  GObjectClass *gobject_class;
  GtkWidgetClass *widget_class;
  GtkContainerClass *container_class;

  gobject_class = G_OBJECT_CLASS (klass);
  widget_class = (GtkWidgetClass*) klass;
  container_class = (GtkContainerClass*) klass;
  
  gobject_class->constructed  = gtk_button_constructed;
  gobject_class->dispose      = gtk_button_dispose;
  gobject_class->set_property = gtk_button_set_property;
  gobject_class->get_property = gtk_button_get_property;

  widget_class->get_preferred_width = gtk_button_get_preferred_width;
  widget_class->get_preferred_height = gtk_button_get_preferred_height;
  widget_class->get_preferred_width_for_height = gtk_button_get_preferred_width_for_height;
  widget_class->get_preferred_height_for_width = gtk_button_get_preferred_height_for_width;
  widget_class->get_preferred_height_and_baseline_for_width = gtk_button_get_preferred_height_and_baseline_for_width;
  widget_class->destroy = gtk_button_destroy;
  widget_class->screen_changed = gtk_button_screen_changed;
  widget_class->realize = gtk_button_realize;
  widget_class->unrealize = gtk_button_unrealize;
  widget_class->map = gtk_button_map;
  widget_class->unmap = gtk_button_unmap;
  widget_class->style_updated = gtk_button_style_updated;
  widget_class->size_allocate = gtk_button_size_allocate;
  widget_class->draw = gtk_button_draw;
  widget_class->grab_broken_event = gtk_button_grab_broken;
  widget_class->key_release_event = gtk_button_key_release;
  widget_class->enter_notify_event = gtk_button_enter_notify;
  widget_class->leave_notify_event = gtk_button_leave_notify;
  widget_class->state_changed = gtk_button_state_changed;
  widget_class->grab_notify = gtk_button_grab_notify;

  container_class->child_type = gtk_button_child_type;
  container_class->add = gtk_button_add;
  gtk_container_class_handle_border_width (container_class);

  klass->pressed = gtk_real_button_pressed;
  klass->released = gtk_real_button_released;
  klass->clicked = NULL;
  klass->enter = gtk_button_enter_leave;
  klass->leave = gtk_button_enter_leave;
  klass->activate = gtk_real_button_activate;

  props[PROP_LABEL] =
    g_param_spec_string ("label",
                         P_("Label"),
                         P_("Text of the label widget inside the button, if the button contains a label widget"),
                         NULL,
                         GTK_PARAM_READWRITE|G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY);
  
  props[PROP_USE_UNDERLINE] =
    g_param_spec_boolean ("use-underline",
                          P_("Use underline"),
                          P_("If set, an underline in the text indicates the next character should be used for the mnemonic accelerator key"),
                          FALSE,
                          GTK_PARAM_READWRITE|G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY);
  
  /**
   * GtkButton:use-stock:
   *
   * Deprecated: 3.10
   */
  props[PROP_USE_STOCK] =
    g_param_spec_boolean ("use-stock",
                          P_("Use stock"),
                          P_("If set, the label is used to pick a stock item instead of being displayed"),
                          FALSE,
                          GTK_PARAM_READWRITE|G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_DEPRECATED);
  
  props[PROP_FOCUS_ON_CLICK] =
    g_param_spec_boolean ("focus-on-click",
                          P_("Focus on click"),
                          P_("Whether the button grabs focus when it is clicked with the mouse"),
                          TRUE,
                          GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
  
  props[PROP_RELIEF] =
    g_param_spec_enum ("relief",
                       P_("Border relief"),
                       P_("The border relief style"),
                       GTK_TYPE_RELIEF_STYLE,
                       GTK_RELIEF_NORMAL,
                       GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
  
  /**
   * GtkButton:xalign:
   *
   * If the child of the button is a #GtkMisc or #GtkAlignment, this property 
   * can be used to control its horizontal alignment. 0.0 is left aligned, 
   * 1.0 is right aligned.
   *
   * Since: 2.4
   *
   * Deprecated: 3.14: Access the child widget directly if you need to control
   * its alignment.
   */
  props[PROP_XALIGN] =
    g_param_spec_float ("xalign",
                        P_("Horizontal alignment for child"),
                        P_("Horizontal position of child in available space. 0.0 is left aligned, 1.0 is right aligned"),
                        0.0, 1.0, 0.5,
                        GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_DEPRECATED);

  /**
   * GtkButton:yalign:
   *
   * If the child of the button is a #GtkMisc or #GtkAlignment, this property 
   * can be used to control its vertical alignment. 0.0 is top aligned, 
   * 1.0 is bottom aligned.
   *
   * Since: 2.4
   *
   * Deprecated: 3.14: Access the child widget directly if you need to control
   * its alignment.
   */
  props[PROP_YALIGN] =
    g_param_spec_float ("yalign",
                        P_("Vertical alignment for child"),
                        P_("Vertical position of child in available space. 0.0 is top aligned, 1.0 is bottom aligned"),
                        0.0, 1.0, 0.5,
                        GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_DEPRECATED);

  /**
   * GtkButton:image:
   *
   * The child widget to appear next to the button text.
   *
   * Since: 2.6
   */
  props[PROP_IMAGE] =
    g_param_spec_object ("image",
                         P_("Image widget"),
                         P_("Child widget to appear next to the button text"),
                         GTK_TYPE_WIDGET,
                         GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);

  /**
   * GtkButton:image-position:
   *
   * The position of the image relative to the text inside the button.
   *
   * Since: 2.10
   */
  props[PROP_IMAGE_POSITION] =
    g_param_spec_enum ("image-position",
                       P_("Image position"),
                       P_("The position of the image relative to the text"),
                       GTK_TYPE_POSITION_TYPE,
                       GTK_POS_LEFT,
                       GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);

  /**
   * GtkButton:always-show-image:
   *
   * If %TRUE, the button will ignore the #GtkSettings:gtk-button-images
   * setting and always show the image, if available.
   *
   * Use this property if the button would be useless or hard to use
   * without the image.
   *
   * Since: 3.6
   */
  props[PROP_ALWAYS_SHOW_IMAGE] =
     g_param_spec_boolean ("always-show-image",
                           P_("Always show image"),
                           P_("Whether the image will always be shown"),
                           FALSE,
                           GTK_PARAM_READWRITE|G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY);

  g_object_class_install_properties (gobject_class, LAST_PROP, props);

  g_object_class_override_property (gobject_class, PROP_ACTION_NAME, "action-name");
  g_object_class_override_property (gobject_class, PROP_ACTION_TARGET, "action-target");

  G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
  g_object_class_override_property (gobject_class, PROP_ACTIVATABLE_RELATED_ACTION, "related-action");
  g_object_class_override_property (gobject_class, PROP_ACTIVATABLE_USE_ACTION_APPEARANCE, "use-action-appearance");
  G_GNUC_END_IGNORE_DEPRECATIONS;

  /**
   * GtkButton::pressed:
   * @button: the object that received the signal
   *
   * Emitted when the button is pressed.
   *
   * Deprecated: 2.8: Use the #GtkWidget::button-press-event signal.
   */ 
  button_signals[PRESSED] =
    g_signal_new (I_("pressed"),
		  G_OBJECT_CLASS_TYPE (gobject_class),
		  G_SIGNAL_RUN_FIRST,
		  G_STRUCT_OFFSET (GtkButtonClass, pressed),
		  NULL, NULL,
		  _gtk_marshal_VOID__VOID,
		  G_TYPE_NONE, 0);

  /**
   * GtkButton::released:
   * @button: the object that received the signal
   *
   * Emitted when the button is released.
   *
   * Deprecated: 2.8: Use the #GtkWidget::button-release-event signal.
   */ 
  button_signals[RELEASED] =
    g_signal_new (I_("released"),
		  G_OBJECT_CLASS_TYPE (gobject_class),
		  G_SIGNAL_RUN_FIRST,
		  G_STRUCT_OFFSET (GtkButtonClass, released),
		  NULL, NULL,
		  _gtk_marshal_VOID__VOID,
		  G_TYPE_NONE, 0);

  /**
   * GtkButton::clicked:
   * @button: the object that received the signal
   *
   * Emitted when the button has been activated (pressed and released).
   */ 
  button_signals[CLICKED] =
    g_signal_new (I_("clicked"),
		  G_OBJECT_CLASS_TYPE (gobject_class),
		  G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
		  G_STRUCT_OFFSET (GtkButtonClass, clicked),
		  NULL, NULL,
		  _gtk_marshal_VOID__VOID,
		  G_TYPE_NONE, 0);

  /**
   * GtkButton::enter:
   * @button: the object that received the signal
   *
   * Emitted when the pointer enters the button.
   *
   * Deprecated: 2.8: Use the #GtkWidget::enter-notify-event signal.
   */ 
  button_signals[ENTER] =
    g_signal_new (I_("enter"),
		  G_OBJECT_CLASS_TYPE (gobject_class),
		  G_SIGNAL_RUN_FIRST,
		  G_STRUCT_OFFSET (GtkButtonClass, enter),
		  NULL, NULL,
		  _gtk_marshal_VOID__VOID,
		  G_TYPE_NONE, 0);

  /**
   * GtkButton::leave:
   * @button: the object that received the signal
   *
   * Emitted when the pointer leaves the button.
   *
   * Deprecated: 2.8: Use the #GtkWidget::leave-notify-event signal.
   */ 
  button_signals[LEAVE] =
    g_signal_new (I_("leave"),
		  G_OBJECT_CLASS_TYPE (gobject_class),
		  G_SIGNAL_RUN_FIRST,
		  G_STRUCT_OFFSET (GtkButtonClass, leave),
		  NULL, NULL,
		  _gtk_marshal_VOID__VOID,
		  G_TYPE_NONE, 0);

  /**
   * GtkButton::activate:
   * @widget: the object which received the signal.
   *
   * The ::activate signal on GtkButton is an action signal and
   * emitting it causes the button to animate press then release. 
   * Applications should never connect to this signal, but use the
   * #GtkButton::clicked signal.
   */
  button_signals[ACTIVATE] =
    g_signal_new (I_("activate"),
		  G_OBJECT_CLASS_TYPE (gobject_class),
		  G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
		  G_STRUCT_OFFSET (GtkButtonClass, activate),
		  NULL, NULL,
		  _gtk_marshal_VOID__VOID,
		  G_TYPE_NONE, 0);
  widget_class->activate_signal = button_signals[ACTIVATE];

  /**
   * GtkButton:default-border:
   *
   * The "default-border" style property defines the extra space to add
   * around a button that can become the default widget of its window.
   * For more information about default widgets, see gtk_widget_grab_default().
   *
   * Deprecated: 3.14: use CSS margins and padding instead.
   */

  gtk_widget_class_install_style_property (widget_class,
					   g_param_spec_boxed ("default-border",
							       P_("Default Spacing"),
							       P_("Extra space to add for GTK_CAN_DEFAULT buttons"),
							       GTK_TYPE_BORDER,
							       GTK_PARAM_READABLE|G_PARAM_DEPRECATED));

  /**
   * GtkButton:default-outside-border:
   *
   * The "default-outside-border" style property defines the extra outside
   * space to add around a button that can become the default widget of its
   * window. Extra outside space is always drawn outside the button border.
   * For more information about default widgets, see gtk_widget_grab_default().
   *
   * Deprecated: 3.14: use CSS margins and padding instead.
   */
  gtk_widget_class_install_style_property (widget_class,
					   g_param_spec_boxed ("default-outside-border",
							       P_("Default Outside Spacing"),
							       P_("Extra space to add for GTK_CAN_DEFAULT buttons that is always drawn outside the border"),
							       GTK_TYPE_BORDER,
							       GTK_PARAM_READABLE|G_PARAM_DEPRECATED));
  gtk_widget_class_install_style_property (widget_class,
					   g_param_spec_int ("child-displacement-x",
							     P_("Child X Displacement"),
							     P_("How far in the x direction to move the child when the button is depressed"),
							     G_MININT,
							     G_MAXINT,
							     0,
							     GTK_PARAM_READABLE|G_PARAM_DEPRECATED));
  gtk_widget_class_install_style_property (widget_class,
					   g_param_spec_int ("child-displacement-y",
							     P_("Child Y Displacement"),
							     P_("How far in the y direction to move the child when the button is depressed"),
							     G_MININT,
							     G_MAXINT,
							     0,
							     GTK_PARAM_READABLE|G_PARAM_DEPRECATED));

  /**
   * GtkButton:displace-focus:
   *
   * Whether the child_displacement_x/child_displacement_y properties 
   * should also affect the focus rectangle.
   *
   * Since: 2.6
   */
  gtk_widget_class_install_style_property (widget_class,
					   g_param_spec_boolean ("displace-focus",
								 P_("Displace focus"),
								 P_("Whether the child_displacement_x/_y properties should also affect the focus rectangle"),
								 FALSE,
								 GTK_PARAM_READABLE|G_PARAM_DEPRECATED));

  /**
   * GtkButton:inner-border:
   *
   * Sets the border between the button edges and child.
   *
   * Since: 2.10
   *
   * Deprecated: 3.4: Use the standard border and padding CSS properties;
   *   the value of this style property is ignored.
   */
  gtk_widget_class_install_style_property (widget_class,
					   g_param_spec_boxed ("inner-border",
                                                               P_("Inner Border"),
                                                               P_("Border between button edges and child."),
                                                               GTK_TYPE_BORDER,
                                                               GTK_PARAM_READABLE | G_PARAM_DEPRECATED));

  /**
   * GtkButton::image-spacing:
   *
   * Spacing in pixels between the image and label.
   *
   * Since: 2.10
   */
  gtk_widget_class_install_style_property (widget_class,
					   g_param_spec_int ("image-spacing",
							     P_("Image spacing"),
							     P_("Spacing in pixels between the image and label"),
							     0,
							     G_MAXINT,
							     2,
							     GTK_PARAM_READABLE));

  gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_BUTTON_ACCESSIBLE);
}

static void
multipress_pressed_cb (GtkGestureMultiPress *gesture,
                       guint                 n_press,
                       gdouble               x,
                       gdouble               y,
                       GtkWidget            *widget)
{
  GtkButton *button = GTK_BUTTON (widget);
  GtkButtonPrivate *priv = button->priv;

  if (priv->focus_on_click && !gtk_widget_has_focus (widget))
    gtk_widget_grab_focus (widget);

  priv->in_button = TRUE;
  g_signal_emit (button, button_signals[PRESSED], 0);
  gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
}

static void
multipress_released_cb (GtkGestureMultiPress *gesture,
                        guint                 n_press,
                        gdouble               x,
                        gdouble               y,
                        GtkWidget            *widget)
{
  GtkButton *button = GTK_BUTTON (widget);
  GtkButtonPrivate *priv = button->priv;
  GdkEventSequence *sequence;

  g_signal_emit (button, button_signals[RELEASED], 0);

  sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));

  if (sequence)
    {
      priv->in_button = FALSE;
      gtk_button_update_state (button);
    }
}

static void
multipress_gesture_update_cb (GtkGesture       *gesture,
                              GdkEventSequence *sequence,
                              GtkButton        *button)
{
  GtkButtonPrivate *priv = button->priv;
  GtkAllocation allocation;
  gboolean in_button;
  gdouble x, y;

  if (sequence != gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture)))
    return;

{'fraction_non_alphanumeric': 0.0743096268981376, 'fraction_numerical': 0.004806198338546954, 'mean_word_length': 2.374484445997903, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 91, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 72, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1495438', 'n_tokens_mistral': 15802, 'n_tokens_neox': 14395, 'n_words': 3428}