Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Gnome/gtk/   (Gnome Linux Desktop Version 4.23.2©)  Datei vom 30.5.2026 mit Größe 38 kB image not shown  

Quelle  gtkcheckbutton.c

  Sprache: C
 

/* GTK - The GIMP Toolkit
 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
 *
 * 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-2000.  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/.
 */


#include "config.h"

#include "gtkcheckbutton.h"

#include "gtkactionhelperprivate.h"
#include "gtkboxlayout.h"
#include "gtkbuiltiniconprivate.h"
#include "gtkgestureclick.h"
#include <glib/gi18n-lib.h>
#include "gtklabel.h"
#include "gtkprivate.h"
#include "gtkshortcuttrigger.h"
#include "gtkcssnodeprivate.h"
#include "gtkwidgetprivate.h"
#include <gdk/gdkkeysyms.h>

/**
 * GtkCheckButton:
 *
 * Places a label next to an indicator.
 *
 * <picture>
 *   <source srcset="check-button-dark.png" media="(prefers-color-scheme: dark)">
 *   <img alt="Example GtkCheckButtons" src="check-button.png">
 * </picture>
 *
 * A `GtkCheckButton` is created by calling either [ctor@Gtk.CheckButton.new]
 * or [ctor@Gtk.CheckButton.new_with_label].
 *
 * The state of a `GtkCheckButton` can be set specifically using
 * [method@Gtk.CheckButton.set_active], and retrieved using
 * [method@Gtk.CheckButton.get_active].
 *
 * # Inconsistent state
 *
 * In addition to "on" and "off", check buttons can be an
 * "in between" state that is neither on nor off. This can be used
 * e.g. when the user has selected a range of elements (such as some
 * text or spreadsheet cells) that are affected by a check button,
 * and the current values in that range are inconsistent.
 *
 * To set a `GtkCheckButton` to inconsistent state, use
 * [method@Gtk.CheckButton.set_inconsistent].
 *
 * # Grouping
 *
 * Check buttons can be grouped together, to form mutually exclusive
 * groups - only one of the buttons can be toggled at a time, and toggling
 * another one will switch the currently toggled one off.
 *
 * Grouped check buttons use a different indicator, and are commonly referred
 * to as *radio buttons*.
 *
 * <picture>
 *   <source srcset="radio-button-dark.png" media="(prefers-color-scheme: dark)">
 *   <img alt="Example GtkRadioButtons" src="radio-button.png">
 * </picture>
 *
 * To add a `GtkCheckButton` to a group, use [method@Gtk.CheckButton.set_group].
 *
 * When the code must keep track of the state of a group of radio buttons, it
 * is recommended to keep track of such state through a stateful
 * `GAction` with a target for each button. Using the `toggled` signals to keep
 * track of the group changes and state is discouraged.
 *
 * # Shortcuts and Gestures
 *
 * `GtkCheckButton` supports the following keyboard shortcuts:
 *
 * - <kbd></kbd> or <kbd>Enter</kbd> activates the button.
 *
 * # CSS nodes
 *
 * ```
 * checkbutton[.text-button][.grouped]
 *  check
 *  [label]
 * ```
 *
 * A `GtkCheckButton` has a main node with name checkbutton. If the
 * [property@Gtk.CheckButton:label] or [property@Gtk.CheckButton:child]
 * properties are set, it contains a child widget. The indicator node
 * is named check when no group is set, and radio if the checkbutton
 * is grouped together with other checkbuttons.
 *
 * # Accessibility
 *
 * `GtkCheckButton` uses the [enum@Gtk.AccessibleRole.checkbox] role.
 */


typedef struct {
  GtkWidget *indicator_widget;
  GtkWidget *child;

  guint inconsistent:  1;
  guint active:        1;
  guint use_underline: 1;
  guint child_type:    1;

  GtkCheckButton *group_next;
  GtkCheckButton *group_prev;

  GtkActionHelper *action_helper;
} GtkCheckButtonPrivate;

enum {
  PROP_0,
  PROP_ACTIVE,
  PROP_GROUP,
  PROP_LABEL,
  PROP_INCONSISTENT,
  PROP_USE_UNDERLINE,
  PROP_CHILD,
  /* GtkActionable */
  PROP_ACTION_NAME,
  PROP_ACTION_TARGET,
  LAST_PROP
};

enum {
  TOGGLED,
  ACTIVATE,
  LAST_SIGNAL
};

enum {
  LABEL_CHILD,
  WIDGET_CHILD
};

static void gtk_check_button_actionable_iface_init (GtkActionableInterface *iface);

static guint signals[LAST_SIGNAL] = { 0 };
static GParamSpec *props[LAST_PROP] = { NULL, };

G_DEFINE_TYPE_WITH_CODE (GtkCheckButton, gtk_check_button, GTK_TYPE_WIDGET,
                         G_ADD_PRIVATE (GtkCheckButton)
                         G_IMPLEMENT_INTERFACE (GTK_TYPE_ACTIONABLE, gtk_check_button_actionable_iface_init))

static void
gtk_check_button_dispose (GObject *object)
{
  GtkCheckButtonPrivate *priv = gtk_check_button_get_instance_private (GTK_CHECK_BUTTON (object));

  g_clear_object (&priv->action_helper);

  g_clear_pointer (&priv->indicator_widget, gtk_widget_unparent);
  g_clear_pointer (&priv->child, gtk_widget_unparent);

  gtk_check_button_set_group (GTK_CHECK_BUTTON (object), NULL);

  G_OBJECT_CLASS (gtk_check_button_parent_class)->dispose (object);
}

static void
force_set_accessible_role (GtkCheckButton *button, GtkAccessibleRole role)
{
  gboolean was_realized;
  GtkWidget *widget = GTK_WIDGET (button);
  GtkATContext *context = gtk_accessible_get_at_context (GTK_ACCESSIBLE (widget));
  if (context)
    was_realized = gtk_at_context_is_realized (context);
  else
    was_realized = FALSE;
  if (was_realized)
    gtk_at_context_unrealize (context);
  gtk_widget_set_accessible_role (widget, role);
  if (was_realized)
    gtk_at_context_realize (context);
  if (context)
    g_object_unref (context);
}

static void
update_button_role (GtkCheckButton *self,
                    GtkButtonRole   role)
{
  GtkCheckButtonPrivate *priv = gtk_check_button_get_instance_private (self);

  if (priv->indicator_widget == NULL)
    return;

  if (role == GTK_BUTTON_ROLE_RADIO)
    {
      gtk_css_node_set_name (gtk_widget_get_css_node (priv->indicator_widget),
                             g_quark_from_static_string ("radio"));

      gtk_widget_add_css_class (GTK_WIDGET (self), "grouped");

      force_set_accessible_role (self, GTK_ACCESSIBLE_ROLE_RADIO);
    }
  else
    {
      gtk_css_node_set_name (gtk_widget_get_css_node (priv->indicator_widget),
                             g_quark_from_static_string ("check"));

      gtk_widget_remove_css_class (GTK_WIDGET (self), "grouped");

      force_set_accessible_role (self, GTK_ACCESSIBLE_ROLE_CHECKBOX);
    }
}

static void
button_role_changed (GtkCheckButton *self)
{
  GtkCheckButtonPrivate *priv = gtk_check_button_get_instance_private (self);

  update_button_role (self, gtk_action_helper_get_role (priv->action_helper));
}

static void
ensure_action_helper (GtkCheckButton *self)
{
  GtkCheckButtonPrivate *priv = gtk_check_button_get_instance_private (self);

  if (priv->action_helper)
    return;

  priv->action_helper = gtk_action_helper_new (GTK_ACTIONABLE (self));
  g_signal_connect_swapped (priv->action_helper, "notify::role",
                            G_CALLBACK (button_role_changed), self);
}

static void
gtk_check_button_set_action_name (GtkActionable *actionable,
                                  const char    *action_name)
{
  GtkCheckButton *self = GTK_CHECK_BUTTON (actionable);
  GtkCheckButtonPrivate *priv = gtk_check_button_get_instance_private (self);

  ensure_action_helper (self);

  gtk_action_helper_set_action_name (priv->action_helper, action_name);
}

static void
gtk_check_button_set_action_target_value (GtkActionable *actionable,
                                          GVariant      *action_target)
{
  GtkCheckButton *self = GTK_CHECK_BUTTON (actionable);
  GtkCheckButtonPrivate *priv = gtk_check_button_get_instance_private (self);

  ensure_action_helper (self);

  gtk_action_helper_set_action_target_value (priv->action_helper, action_target);
}

static void
gtk_check_button_set_property (GObject      *object,
                               guint         prop_id,
                               const GValue *value,
                               GParamSpec   *pspec)
{
  switch (prop_id)
    {
    case PROP_ACTIVE:
      gtk_check_button_set_active (GTK_CHECK_BUTTON (object), g_value_get_boolean (value));
      break;
    case PROP_GROUP:
      gtk_check_button_set_group (GTK_CHECK_BUTTON (object), g_value_get_object (value));
      break;
    case PROP_LABEL:
      gtk_check_button_set_label (GTK_CHECK_BUTTON (object), g_value_get_string (value));
      break;
    case PROP_INCONSISTENT:
      gtk_check_button_set_inconsistent (GTK_CHECK_BUTTON (object), g_value_get_boolean (value));
      break;
    case PROP_USE_UNDERLINE:
      gtk_check_button_set_use_underline (GTK_CHECK_BUTTON (object), g_value_get_boolean (value));
      break;
    case PROP_CHILD:
      gtk_check_button_set_child (GTK_CHECK_BUTTON (object), g_value_get_object (value));
      break;
    case PROP_ACTION_NAME:
      gtk_check_button_set_action_name (GTK_ACTIONABLE (object), g_value_get_string (value));
      break;
    case PROP_ACTION_TARGET:
      gtk_check_button_set_action_target_value (GTK_ACTIONABLE (object), g_value_get_variant (value));
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

static void
gtk_check_button_get_property (GObject    *object,
                               guint       prop_id,
                               GValue     *value,
                               GParamSpec *pspec)
{
  GtkCheckButtonPrivate *priv = gtk_check_button_get_instance_private (GTK_CHECK_BUTTON (object));

  switch (prop_id)
    {
    case PROP_ACTIVE:
      g_value_set_boolean (value, gtk_check_button_get_active (GTK_CHECK_BUTTON (object)));
      break;
    case PROP_LABEL:
      g_value_set_string (value, gtk_check_button_get_label (GTK_CHECK_BUTTON (object)));
      break;
    case PROP_INCONSISTENT:
      g_value_set_boolean (value, gtk_check_button_get_inconsistent (GTK_CHECK_BUTTON (object)));
      break;
    case PROP_USE_UNDERLINE:
      g_value_set_boolean (value, gtk_check_button_get_use_underline (GTK_CHECK_BUTTON (object)));
      break;
    case PROP_CHILD:
      g_value_set_object (value, gtk_check_button_get_child (GTK_CHECK_BUTTON (object)));
      break;
    case PROP_ACTION_NAME:
      g_value_set_string (value, gtk_action_helper_get_action_name (priv->action_helper));
      break;
    case PROP_ACTION_TARGET:
      g_value_set_variant (value, gtk_action_helper_get_action_target_value (priv->action_helper));
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

static const char *
gtk_check_button_get_action_name (GtkActionable *actionable)
{
  GtkCheckButton *self = GTK_CHECK_BUTTON (actionable);
  GtkCheckButtonPrivate *priv = gtk_check_button_get_instance_private (self);

  return gtk_action_helper_get_action_name (priv->action_helper);
}

static GVariant *
gtk_check_button_get_action_target_value (GtkActionable *actionable)
{
  GtkCheckButton *self = GTK_CHECK_BUTTON (actionable);
  GtkCheckButtonPrivate *priv = gtk_check_button_get_instance_private (self);

  return gtk_action_helper_get_action_target_value (priv->action_helper);
}

static void
gtk_check_button_actionable_iface_init (GtkActionableInterface *iface)
{
  iface->get_action_name = gtk_check_button_get_action_name;
  iface->set_action_name = gtk_check_button_set_action_name;
  iface->get_action_target_value = gtk_check_button_get_action_target_value;
  iface->set_action_target_value = gtk_check_button_set_action_target_value;
}

static void
click_pressed_cb (GtkGestureClick *gesture,
                  guint            n_press,
                  double           x,
                  double           y,
                  GtkWidget       *widget)
{
  if (gtk_widget_get_focus_on_click (widget) && !gtk_widget_has_focus (widget))
    gtk_widget_grab_focus (widget);
}

static void
click_released_cb (GtkGestureClick *gesture,
                   guint            n_press,
                   double           x,
                   double           y,
                   GtkWidget       *widget)
{
  GtkCheckButton *self = GTK_CHECK_BUTTON (widget);
  GtkCheckButtonPrivate *priv = gtk_check_button_get_instance_private (self);

  if (priv->active && (priv->group_prev || priv->group_next))
    return;

  gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
  if  (gtk_widget_is_sensitive (widget) &&
       gtk_widget_contains (widget, x, y))
    {
      if (priv->action_helper)
        gtk_action_helper_activate (priv->action_helper);
      else
        gtk_check_button_set_active (self, !priv->active);
    }
}

static void
update_accessible_state (GtkCheckButton *check_button)
{
  GtkCheckButtonPrivate *priv = gtk_check_button_get_instance_private (check_button);

  GtkAccessibleTristate checked_state;

  if (priv->inconsistent)
    checked_state = GTK_ACCESSIBLE_TRISTATE_MIXED;
  else if (priv->active)
    checked_state = GTK_ACCESSIBLE_TRISTATE_TRUE;
  else
    checked_state = GTK_ACCESSIBLE_TRISTATE_FALSE;

  gtk_accessible_update_state (GTK_ACCESSIBLE (check_button),
                               GTK_ACCESSIBLE_STATE_CHECKED, checked_state,
                               -1);
}

static void
update_accessible_mnemonic (GtkCheckButton *check_button)
{
  GtkCheckButtonPrivate *priv = gtk_check_button_get_instance_private (check_button);

  if (priv->child_type == LABEL_CHILD && priv->child != NULL && priv->use_underline)
    {
      guint keyval = gtk_label_get_mnemonic_keyval (GTK_LABEL (priv->child));
      if (keyval != GDK_KEY_VoidSymbol)
        {
          const char *name = gdk_keyval_name (gdk_keyval_to_upper (keyval));
          char *shortcut = g_strdup_printf ("Alt+%s", name);
          gtk_accessible_update_property (GTK_ACCESSIBLE (check_button),
                                          GTK_ACCESSIBLE_PROPERTY_KEY_SHORTCUTS, shortcut,
                                          -1);
          g_free (shortcut);
          return;
        }
    }

  /* No mnemonic - clear the property */
  gtk_accessible_reset_property (GTK_ACCESSIBLE (check_button),
                                 GTK_ACCESSIBLE_PROPERTY_KEY_SHORTCUTS);
}

static GtkCheckButton *
get_group_next (GtkCheckButton *self)
{
  return ((GtkCheckButtonPrivate *)gtk_check_button_get_instance_private (self))->group_next;
}

static GtkCheckButton *
get_group_prev (GtkCheckButton *self)
{
  return ((GtkCheckButtonPrivate *)gtk_check_button_get_instance_private (self))->group_prev;
}

static GtkCheckButton *
get_group_first (GtkCheckButton *self)
{
  GtkCheckButton *group_first = NULL;
  GtkCheckButton *iter;

  /* Find first in group */
  iter = self;
  while (iter)
    {
      group_first = iter;

      iter = get_group_prev (iter);
      if (!iter)
        break;
    }

  g_assert (group_first);

  return group_first;
}

static GtkCheckButton *
get_group_active_button (GtkCheckButton *self)
{
  GtkCheckButton *iter;

  for (iter = get_group_first (self); iter; iter = get_group_next (iter))
    {
      if (gtk_check_button_get_active (iter))
        return iter;
    }

  return NULL;
}

static void
gtk_check_button_state_flags_changed (GtkWidget     *widget,
                                      GtkStateFlags  previous_flags)
{
  GtkCheckButton *self = GTK_CHECK_BUTTON (widget);
  GtkCheckButtonPrivate *priv = gtk_check_button_get_instance_private (self);
  GtkStateFlags state = gtk_widget_get_state_flags (GTK_WIDGET (self));

  gtk_widget_set_state_flags (priv->indicator_widget, state, TRUE);

  GTK_WIDGET_CLASS (gtk_check_button_parent_class)->state_flags_changed (widget, previous_flags);
}

static gboolean
gtk_check_button_focus (GtkWidget         *widget,
                        GtkDirectionType   direction)
{
  GtkCheckButton *self = GTK_CHECK_BUTTON (widget);

  if (gtk_widget_is_focus (widget))
    {
      GtkCheckButton *iter;
      GPtrArray *child_array;
      GtkWidget *new_focus = NULL;
      guint index;
      gboolean found;
      guint i;

      if (direction == GTK_DIR_TAB_FORWARD ||
          direction == GTK_DIR_TAB_BACKWARD)
        return FALSE;

      child_array = g_ptr_array_new ();
      for (iter = get_group_first (self); iter; iter = get_group_next (iter))
        g_ptr_array_add (child_array, iter);

      gtk_widget_focus_sort (widget, direction, child_array);
      found = g_ptr_array_find (child_array, widget, &index);

      if (found)
        {
          /* Start at the *next* widget in the list */
          if (index < child_array->len - 1)
            index ++;
        }
      else
        {
          /* Search from the start of the list */
          index = 0;
        }

      for (i = index; i < child_array->len; i ++)
        {
          GtkWidget *child = g_ptr_array_index (child_array, i);

          if (gtk_widget_get_mapped (child) && gtk_widget_is_sensitive (child))
            {
              new_focus = child;
              break;
            }
        }

      g_ptr_array_free (child_array, TRUE);

      if (new_focus && new_focus != widget)
        {
          gtk_widget_grab_focus (new_focus);
          gtk_widget_activate (new_focus);
          return TRUE;
        }
      return FALSE;
    }
  else
    {
      GtkCheckButton *active_button;

      active_button = get_group_active_button (self);
      if (active_button && active_button != self)
        return FALSE;

      gtk_widget_grab_focus (widget);
      return TRUE;
    }
}

static void
gtk_check_button_real_set_child (GtkCheckButton *self,
                                 GtkWidget      *child,
                                 guint           child_type)
{
  GtkCheckButtonPrivate *priv = gtk_check_button_get_instance_private (self);

  g_return_if_fail (GTK_IS_CHECK_BUTTON (self));

  g_clear_pointer (&priv->child, gtk_widget_unparent);

  priv->child = child;

  if (priv->child)
    {
      gtk_widget_set_parent (priv->child, GTK_WIDGET (self));
      gtk_widget_insert_after (priv->child, GTK_WIDGET (self), priv->indicator_widget);
    }

  if (child_type == priv->child_type)
    return;

  priv->child_type = child_type;
  if (child_type != LABEL_CHILD)
    g_object_notify_by_pspec (G_OBJECT (self), props[PROP_LABEL]);
  else
    g_object_notify_by_pspec (G_OBJECT (self), props[PROP_CHILD]);

}

static void
gtk_check_button_real_activate (GtkCheckButton *self)
{
  GtkCheckButtonPrivate *priv = gtk_check_button_get_instance_private (self);

  if (priv->active && (priv->group_prev || priv->group_next))
    return;

  if (priv->action_helper)
    gtk_action_helper_activate (priv->action_helper);
  else
    gtk_check_button_set_active (self, !gtk_check_button_get_active (self));
}

static void
gtk_check_button_class_init (GtkCheckButtonClass *class)
{
  GObjectClass *object_class = G_OBJECT_CLASS (class);
  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
  GtkShortcutTrigger *trigger;
  GtkShortcut *activate_shortcut;

  object_class->dispose = gtk_check_button_dispose;
  object_class->set_property = gtk_check_button_set_property;
  object_class->get_property = gtk_check_button_get_property;

  widget_class->state_flags_changed = gtk_check_button_state_flags_changed;
  widget_class->focus = gtk_check_button_focus;

  class->activate = gtk_check_button_real_activate;

  /**
   * GtkCheckButton:active:
   *
   * If the check button is active.
   *
   * Setting `active` to %TRUE will add the `:checked:` state to both
   * the check button and the indicator CSS node.
   */

  props[PROP_ACTIVE] =
      g_param_spec_boolean ("active", NULL, NULL,
                            FALSE,
                            G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_EXPLICIT_NOTIFY);

  /**
   * GtkCheckButton:group:
   *
   * The check button whose group this widget belongs to.
   */

  props[PROP_GROUP] =
      g_param_spec_object ("group", NULL, NULL,
                           GTK_TYPE_CHECK_BUTTON,
                           G_PARAM_WRITABLE | G_PARAM_STATIC_NAME);

  /**
   * GtkCheckButton:label:
   *
   * Text of the label inside the check button, if it contains a label widget.
   */

  props[PROP_LABEL] =
    g_param_spec_string ("label", NULL, NULL,
                         NULL,
                         G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_EXPLICIT_NOTIFY);

  /**
   * GtkCheckButton:inconsistent:
   *
   * If the check button is in an in between state.
   *
   * The inconsistent state only affects visual appearance,
   * not the semantics of the button.
   */

  props[PROP_INCONSISTENT] =
      g_param_spec_boolean ("inconsistent", NULL, NULL,
                            FALSE,
                            G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_EXPLICIT_NOTIFY);

  /**
   * GtkCheckButton:use-underline:
   *
   * If set, an underline in the text indicates that the following
   * character is to be used as mnemonic.
   */

  props[PROP_USE_UNDERLINE] =
      g_param_spec_boolean ("use-underline", NULL, NULL,
                            FALSE,
                            G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_EXPLICIT_NOTIFY);

  /**
   * GtkCheckButton:child:
   *
   * The child widget.
   *
   * Since: 4.8
   */

  props[PROP_CHILD] =
      g_param_spec_object ("child", NULL, NULL,
                           GTK_TYPE_WIDGET,
                           G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_EXPLICIT_NOTIFY);

  props[PROP_ACTION_NAME] = g_param_spec_override ("action-name",
      g_object_interface_find_property (g_type_default_interface_ref (GTK_TYPE_ACTIONABLE), "action-name"));
  props[PROP_ACTION_TARGET] = g_param_spec_override ("action-target",
      g_object_interface_find_property (g_type_default_interface_ref (GTK_TYPE_ACTIONABLE), "action-target"));

  g_object_class_install_properties (object_class, LAST_PROP, props);

  /**
   * GtkCheckButton::toggled:
   *
   * Emitted when the buttons's [property@Gtk.CheckButton:active]
   * property changes.
   */

  signals[TOGGLED] =
    g_signal_new (I_("toggled"),
                  G_OBJECT_CLASS_TYPE (object_class),
                  G_SIGNAL_RUN_FIRST,
                  G_STRUCT_OFFSET (GtkCheckButtonClass, toggled),
                  NULL, NULL,
                  NULL,
                  G_TYPE_NONE, 0);

  /**
   * GtkCheckButton::activate:
   * @widget: the object which received the signal.
   *
   * Emitted to when the check button is activated.
   *
   * The `::activate` signal on `GtkCheckButton` 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
   * [signal@Gtk.CheckButton::toggled] signal.
   *
   * The default bindings for this signal are all forms of the
   * <kbd></kbd> and <kbd>Enter</kbd> keys.
   *
   * Since: 4.2
   */

  signals[ACTIVATE] =
      g_signal_new (I_ ("activate"),
                    G_OBJECT_CLASS_TYPE (object_class),
                    G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
                    G_STRUCT_OFFSET (GtkCheckButtonClass, activate),
                    NULL, NULL,
                    NULL,
                    G_TYPE_NONE, 0);

  gtk_widget_class_set_activate_signal (widget_class, signals[ACTIVATE]);

  trigger = gtk_alternative_trigger_new (gtk_shortcut_trigger_create_with_aliases (GDK_KEY_Return, 0),
                                         gtk_shortcut_trigger_create_with_aliases (GDK_KEY_space, 0));
  activate_shortcut = gtk_shortcut_new (trigger, gtk_signal_action_new ("activate"));
  gtk_widget_class_add_shortcut (widget_class, activate_shortcut);
  g_object_unref (activate_shortcut);

  gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BOX_LAYOUT);
  gtk_widget_class_set_css_name (widget_class, I_("checkbutton"));
  gtk_widget_class_set_accessible_role (widget_class, GTK_ACCESSIBLE_ROLE_CHECKBOX);
}

static void
gtk_check_button_init (GtkCheckButton *self)
{
  GtkCheckButtonPrivate *priv = gtk_check_button_get_instance_private (self);
  GtkGesture *gesture;

  gtk_widget_set_receives_default (GTK_WIDGET (self), FALSE);
  priv->indicator_widget = gtk_builtin_icon_new ("check");
  gtk_widget_set_halign (priv->indicator_widget, GTK_ALIGN_CENTER);
  gtk_widget_set_valign (priv->indicator_widget, GTK_ALIGN_CENTER);
  gtk_widget_set_parent (priv->indicator_widget, GTK_WIDGET (self));

  update_accessible_state (self);

  gesture = gtk_gesture_click_new ();
  gtk_gesture_single_set_touch_only (GTK_GESTURE_SINGLE (gesture), FALSE);
  gtk_gesture_single_set_exclusive (GTK_GESTURE_SINGLE (gesture), TRUE);
  gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (gesture), GDK_BUTTON_PRIMARY);
  g_signal_connect (gesture, "pressed", G_CALLBACK (click_pressed_cb), self);
  g_signal_connect (gesture, "released", G_CALLBACK (click_released_cb), self);
  gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (gesture), GTK_PHASE_CAPTURE);
  gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (gesture));

  gtk_widget_set_focusable (GTK_WIDGET (self), TRUE);
}

/**
 * gtk_check_button_new:
 *
 * Creates a new `GtkCheckButton`.
 *
 * Returns: a new `GtkCheckButton`
 */

GtkWidget *
gtk_check_button_new (void)
{
  return g_object_new (GTK_TYPE_CHECK_BUTTON, NULL);
}

/**
 * gtk_check_button_new_with_label:
 * @label: (nullable): the text for the check button.
 *
 * Creates a new `GtkCheckButton` with the given text.
 *
 * Returns: a new `GtkCheckButton`
 */

GtkWidget*
gtk_check_button_new_with_label (const char *label)
{
  return g_object_new (GTK_TYPE_CHECK_BUTTON, "label", label, NULL);
}

/**
 * gtk_check_button_new_with_mnemonic:
 * @label: (nullable): The text of the button, with an underscore
 *   in front of the mnemonic character
 *
 * Creates a new `GtkCheckButton` with the given text and a mnemonic.
 *
 * Returns: a new `GtkCheckButton`
 */

GtkWidget*
gtk_check_button_new_with_mnemonic (const char *label)
{
  return g_object_new (GTK_TYPE_CHECK_BUTTON,
                       "label", label,
                       "use-underline"TRUE,
                       NULL);
}

/**
 * gtk_check_button_set_inconsistent:
 * @check_button: a `GtkCheckButton`
 * @inconsistent: %TRUE if state is inconsistent
 *
 * Sets the `GtkCheckButton` to inconsistent state.
 *
 * You should turn off the inconsistent state again if the user checks
 * the check button. This has to be done manually.
 */

void
gtk_check_button_set_inconsistent (GtkCheckButton *check_button,
                                   gboolean        inconsistent)
{
  GtkCheckButtonPrivate *priv = gtk_check_button_get_instance_private (check_button);

  g_return_if_fail (GTK_IS_CHECK_BUTTON (check_button));

  inconsistent = !!inconsistent;
  if (priv->inconsistent != inconsistent)
    {
      priv->inconsistent = inconsistent;

      if (inconsistent)
        {
          gtk_widget_set_state_flags (GTK_WIDGET (check_button), GTK_STATE_FLAG_INCONSISTENT, FALSE);
          gtk_widget_set_state_flags (priv->indicator_widget, GTK_STATE_FLAG_INCONSISTENT, FALSE);
        }
      else
        {
          gtk_widget_unset_state_flags (GTK_WIDGET (check_button), GTK_STATE_FLAG_INCONSISTENT);
          gtk_widget_unset_state_flags (priv->indicator_widget, GTK_STATE_FLAG_INCONSISTENT);
        }

      update_accessible_state (check_button);

      g_object_notify_by_pspec (G_OBJECT (check_button), props[PROP_INCONSISTENT]);
    }
}

/**
 * gtk_check_button_get_inconsistent:
 * @check_button: a `GtkCheckButton`
 *
 * Returns whether the check button is in an inconsistent state.
 *
 * Returns: %TRUE if @check_button is currently in an inconsistent state
 */

gboolean
gtk_check_button_get_inconsistent (GtkCheckButton *check_button)
{
  GtkCheckButtonPrivate *priv = gtk_check_button_get_instance_private (check_button);

  g_return_val_if_fail (GTK_IS_CHECK_BUTTON (check_button), FALSE);

  return priv->inconsistent;
}

/**
 * gtk_check_button_get_active:
 * @self: a `GtkCheckButton`
 *
 * Returns whether the check button is active.
 *
 * Returns: whether the check button is active
 */

gboolean
gtk_check_button_get_active (GtkCheckButton *self)
{
  GtkCheckButtonPrivate *priv = gtk_check_button_get_instance_private (self);

  g_return_val_if_fail (GTK_IS_CHECK_BUTTON (self), FALSE);

  return priv->active;
}

/**
 * gtk_check_button_set_active:
 * @self: a `GtkCheckButton`
 * @setting: the new value to set
 *
 * Changes the check buttons active state.
 */

void
gtk_check_button_set_active (GtkCheckButton *self,
                             gboolean       setting)
{
  GtkCheckButtonPrivate *priv = gtk_check_button_get_instance_private (self);

  g_return_if_fail (GTK_IS_CHECK_BUTTON (self));

  setting = !!setting;

  if (setting == priv->active)
    return;

  if (setting)
    {
      gtk_widget_set_state_flags (GTK_WIDGET (self), GTK_STATE_FLAG_CHECKED, FALSE);
      gtk_widget_set_state_flags (priv->indicator_widget, GTK_STATE_FLAG_CHECKED, FALSE);
    }
  else
    {
      gtk_widget_unset_state_flags (GTK_WIDGET (self), GTK_STATE_FLAG_CHECKED);
      gtk_widget_unset_state_flags (priv->indicator_widget, GTK_STATE_FLAG_CHECKED);
    }

  if (setting && (priv->group_prev || priv->group_next))
    {
      GtkCheckButton *group_first = NULL;
      GtkCheckButton *iter;

      group_first = get_group_first (self);
      g_assert (group_first);

      /* Set all buttons in group to !active */
      for (iter = group_first; iter; iter = get_group_next (iter))
        gtk_check_button_set_active (iter, FALSE);

      /* ... and the next code block will set this one to active */
    }

  priv->active = setting;
  update_accessible_state (self);
  g_object_notify_by_pspec (G_OBJECT (self), props[PROP_ACTIVE]);
  g_signal_emit (self, signals[TOGGLED], 0);
}

/**
 * gtk_check_button_get_label:
 * @self: a `GtkCheckButton`
 *
 * Returns the label of the check button or `NULL` if [property@CheckButton:child] is set.
 *
 * Returns: (nullable) (transfer none): The label @self shows next
 *   to the indicator. If no label is shown, %NULL will be returned.
 */

const char *
gtk_check_button_get_label (GtkCheckButton *self)
{
  GtkCheckButtonPrivate *priv = gtk_check_button_get_instance_private (self);

  g_return_val_if_fail (GTK_IS_CHECK_BUTTON (self), "");

  if (priv->child_type == LABEL_CHILD && priv->child != NULL)
    return gtk_label_get_label (GTK_LABEL (priv->child));

  return NULL;
}

/**
 * gtk_check_button_set_label:
 * @self: a `GtkCheckButton`
 * @label: (nullable): The text shown next to the indicator, or %NULL
 *   to show no text
 *
 * Sets the text of @self.
 *
 * If [property@Gtk.CheckButton:use-underline] is %TRUE, an underscore
 * in @label is interpreted as mnemonic indicator, see
 * [method@Gtk.CheckButton.set_use_underline] for details on this behavior.
 */

void
gtk_check_button_set_label (GtkCheckButton *self,
                            const char     *label)
{
  GtkCheckButtonPrivate *priv = gtk_check_button_get_instance_private (self);
  GtkWidget *child;

  g_return_if_fail (GTK_IS_CHECK_BUTTON (self));

  g_object_freeze_notify (G_OBJECT (self));

  if (label == NULL || label[0] == '\0')
    {
      gtk_check_button_real_set_child (self, NULL, LABEL_CHILD);
      gtk_widget_remove_css_class (GTK_WIDGET (self), "text-button");
    }
  else
    {
      if (priv->child_type != LABEL_CHILD || priv->child == NULL)
        {
          child = gtk_label_new (NULL);
          gtk_widget_set_hexpand (child, TRUE);
          gtk_label_set_xalign (GTK_LABEL (child), 0.0f);
          if (priv->use_underline)
            gtk_label_set_use_underline (GTK_LABEL (child), priv->use_underline);
          gtk_check_button_real_set_child (self, GTK_WIDGET (child), LABEL_CHILD);
        }

      gtk_widget_add_css_class (GTK_WIDGET (self), "text-button");
      gtk_label_set_label (GTK_LABEL (priv->child), label);
    }

  /* Use the processed text from the label widget for accessibility,
   * which strips mnemonics when use_underline is enabled */

  if (priv->child_type == LABEL_CHILD && priv->child != NULL)
    {
      const char *text = gtk_label_get_text (GTK_LABEL (priv->child));
      gtk_accessible_update_property (GTK_ACCESSIBLE (self),
                                      GTK_ACCESSIBLE_PROPERTY_LABEL, text,
                                      -1);
    }
  else
    {
      gtk_accessible_update_property (GTK_ACCESSIBLE (self),
                                      GTK_ACCESSIBLE_PROPERTY_LABEL, label,
                                      -1);
    }

  update_accessible_mnemonic (self);

  g_object_notify_by_pspec (G_OBJECT (self), props[PROP_LABEL]);

  g_object_thaw_notify (G_OBJECT (self));
}

/**
 * gtk_check_button_set_group:
 * @self: a `GtkCheckButton`
 * @group: (nullable) (transfer none): another `GtkCheckButton` to
 *   form a group with
 *
 * Adds @self to the group of @group.
 *
 * In a group of multiple check buttons, only one button can be active
 * at a time. The behavior of a checkbutton in a group is also commonly
 * known as a *radio button*.
 *
 * Setting the group of a check button also changes the css name of the
 * indicator widget's CSS node to 'radio'.
 *
 * Setting up groups in a cycle leads to undefined behavior.
 *
 * Note that the same effect can be achieved via the [iface@Gtk.Actionable]
 * API, by using the same action with parameter type and state type 's'
 * for all buttons in the group, and giving each button its own target
 * value.
 */

void
gtk_check_button_set_group (GtkCheckButton *self,
                            GtkCheckButton *group)
{
  GtkCheckButtonPrivate *priv = gtk_check_button_get_instance_private (self);
  GtkCheckButtonPrivate *group_priv;

  g_return_if_fail (GTK_IS_CHECK_BUTTON (self));
  g_return_if_fail (self != group);

  if (!group)
    {
      if (priv->group_prev)
        {
          GtkCheckButtonPrivate *p = gtk_check_button_get_instance_private (priv->group_prev);
          p->group_next = priv->group_next;
        }
      if (priv->group_next)
        {
          GtkCheckButtonPrivate *p = gtk_check_button_get_instance_private (priv->group_next);
          p->group_prev = priv->group_prev;
        }

      priv->group_next = NULL;
      priv->group_prev = NULL;

      update_button_role (self, GTK_BUTTON_ROLE_CHECK);

      force_set_accessible_role (self, GTK_ACCESSIBLE_ROLE_CHECKBOX);

      return;
    }

  if (priv->group_next == group)
    return;

  group_priv = gtk_check_button_get_instance_private (group);

  priv->group_prev = NULL;
  if (group_priv->group_prev)
    {
      GtkCheckButtonPrivate *prev = gtk_check_button_get_instance_private (group_priv->group_prev);

      prev->group_next = self;
      priv->group_prev = group_priv->group_prev;
    }

  group_priv->group_prev = self;
  priv->group_next = group;

  update_button_role (self, GTK_BUTTON_ROLE_RADIO);
  update_button_role (group, GTK_BUTTON_ROLE_RADIO);

  force_set_accessible_role (self, GTK_ACCESSIBLE_ROLE_RADIO);
  force_set_accessible_role (group, GTK_ACCESSIBLE_ROLE_RADIO);

  g_object_notify_by_pspec (G_OBJECT (self), props[PROP_GROUP]);
}

/**
 * gtk_check_button_get_use_underline:
 * @self: a `GtkCheckButton`
 *
 * Returns whether underlines in the label indicate mnemonics.
 *
 * Returns: The value of the [property@Gtk.CheckButton:use-underline] property.
 *   See [method@Gtk.CheckButton.set_use_underline] for details on how to set
 *   a new value.
 */

gboolean
gtk_check_button_get_use_underline (GtkCheckButton *self)
{
  GtkCheckButtonPrivate *priv = gtk_check_button_get_instance_private (self);

  g_return_val_if_fail (GTK_IS_CHECK_BUTTON (self), FALSE);

  return priv->use_underline;
}

/**
 * gtk_check_button_set_use_underline:
 * @self: a `GtkCheckButton`
 * @setting: the new value to set
 *
 * Sets whether underlines in the label indicate mnemonics.
 *
 * If @setting is %TRUE, an underscore character in @self's label
 * indicates a mnemonic accelerator key. This behavior is similar
 * to [property@Gtk.Label:use-underline].
 */

void
gtk_check_button_set_use_underline (GtkCheckButton *self,
                                    gboolean       setting)
{
  GtkCheckButtonPrivate *priv = gtk_check_button_get_instance_private (self);

  g_return_if_fail (GTK_IS_CHECK_BUTTON (self));

  setting = !!setting;

  if (setting == priv->use_underline)
    return;

  priv->use_underline = setting;
  if (priv->child_type == LABEL_CHILD && priv->child != NULL)
    {
      gtk_label_set_use_underline (GTK_LABEL (priv->child), priv->use_underline);

      const char *text = gtk_label_get_text (GTK_LABEL (priv->child));
      gtk_accessible_update_property (GTK_ACCESSIBLE (self),
                                      GTK_ACCESSIBLE_PROPERTY_LABEL, text,
                                      -1);
    }

  update_accessible_mnemonic (self);

  g_object_notify_by_pspec (G_OBJECT (self), props[PROP_USE_UNDERLINE]);
}

/**
 * gtk_check_button_set_child:
 * @button: a `GtkCheckButton`
 * @child: (nullable): the child widget
 *
 * Sets the child widget of @button.
 *
 * Note that by using this API, you take full responsibility for setting
 * up the proper accessibility label and description information for @button.
 * Most likely, you'll either set the accessibility label or description
 * for @button explicitly, or you'll set a labelled-by or described-by
 * relations from @child to @button.
 *
 * Since: 4.8
 */

void
gtk_check_button_set_child (GtkCheckButton *button,
                            GtkWidget      *child)
{
  GtkCheckButtonPrivate *priv = gtk_check_button_get_instance_private (button);

  g_return_if_fail (GTK_IS_CHECK_BUTTON (button));
  g_return_if_fail (child == NULL || priv->child == child || gtk_widget_get_parent (child) == NULL);

  if (priv->child == child)
    return;

  g_object_freeze_notify (G_OBJECT (button));

  gtk_widget_remove_css_class (GTK_WIDGET (button), "text-button");

  gtk_check_button_real_set_child (button, child, WIDGET_CHILD);

  update_accessible_mnemonic (button);

  g_object_notify_by_pspec (G_OBJECT (button), props[PROP_CHILD]);

  g_object_thaw_notify (G_OBJECT (button));
}

/**
 * gtk_check_button_get_child:
 * @button: a `GtkCheckButton`
 *
 * Gets the child widget of @button or `NULL` if [property@CheckButton:label] is set.
 *
 * Returns: (nullable) (transfer none): the child widget of @button
 *
 * Since: 4.8
 */

GtkWidget *
gtk_check_button_get_child (GtkCheckButton *button)
{
  GtkCheckButtonPrivate *priv = gtk_check_button_get_instance_private (button);

  g_return_val_if_fail (GTK_IS_CHECK_BUTTON (button), NULL);

  if (priv->child_type == WIDGET_CHILD)
    return priv->child;

  return NULL;
}

Messung V0.5 in Prozent
C=98 H=96 G=96

¤ Dauer der Verarbeitung: 0.22 Sekunden  (vorverarbeitet am  2026-07-03) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.