gtktogglebutton.c 20.6 KB
Newer Older
Cody Russell's avatar
Cody Russell committed
1
/* GTK - The GIMP Toolkit
Elliot Lee's avatar
Elliot Lee committed
2 3 4
 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
 *
 * This library is free software; you can redistribute it and/or
5
 * modify it under the terms of the GNU Lesser General Public
Elliot Lee's avatar
Elliot Lee committed
6 7 8 9 10 11
 * 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
12
 * Lesser General Public License for more details.
Elliot Lee's avatar
Elliot Lee committed
13
 *
14
 * You should have received a copy of the GNU Lesser General Public
15 16 17
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
Elliot Lee's avatar
Elliot Lee committed
18
 */
19 20

/*
21
 * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22 23 24 25 26
 * 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/. 
 */

27
#include "config.h"
28 29 30 31

#include "gtktogglebutton.h"

#include "gtkbuttonprivate.h"
Elliot Lee's avatar
Elliot Lee committed
32 33
#include "gtklabel.h"
#include "gtkmain.h"
34
#include "gtkmarshalers.h"
35 36
#include "gtktoggleaction.h"
#include "gtkactivatable.h"
37
#include "gtkprivate.h"
38
#include "gtkintl.h"
39
#include "a11y/gtktogglebuttonaccessible.h"
40

Elliot Lee's avatar
Elliot Lee committed
41

42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
/**
 * SECTION:gtktogglebutton
 * @Short_description: Create buttons which retain their state
 * @Title: GtkToggleButton
 * @See_also: #GtkButton, #GtkCheckButton, #GtkCheckMenuItem
 *
 * A #GtkToggleButton is a #GtkButton which will remain 'pressed-in' when
 * clicked. Clicking again will cause the toggle button to return to its
 * normal state.
 *
 * A toggle button is created by calling either gtk_toggle_button_new() or
 * gtk_toggle_button_new_with_label(). If using the former, it is advisable to
 * pack a widget, (such as a #GtkLabel and/or a #GtkPixmap), into the toggle
 * button's container. (See #GtkButton for more information).
 *
 * The state of a #GtkToggleButton can be set specifically using
 * gtk_toggle_button_set_active(), and retrieved using
 * gtk_toggle_button_get_active().
 *
 * To simply switch the state of a toggle button, use gtk_toggle_button_toggled().
 *
 * <example>
 * <title>Creating two #GtkToggleButton widgets.</title>
 * <programlisting>
 * void make_toggles (void) {
 *    GtkWidget *dialog, *toggle1, *toggle2;
 *
 *    dialog = gtk_dialog_new (<!-- -->);
 *    toggle1 = gtk_toggle_button_new_with_label ("Hi, i'm a toggle button.");
 *
 *    // Makes this toggle button invisible
 *    gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (toggle1), TRUE);
 *
 *    g_signal_connect (toggle1, "toggled",
 *                      G_CALLBACK (output_state), NULL);
 *    gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->action_area),
 *                        toggle1, FALSE, FALSE, 2);
 *
 *    toggle2 = gtk_toggle_button_new_with_label ("Hi, i'm another toggle button.");
 *    gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (toggle2), FALSE);
 *    g_signal_connect (toggle2, "toggled",
 *                      G_CALLBACK (output_state), NULL);
 *    gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->action_area),
 *                        toggle2, FALSE, FALSE, 2);
 *
 *    gtk_widget_show_all (dialog);
 * }
 * </programlisting>
 * </example>
 */


Elliot Lee's avatar
Elliot Lee committed
94 95 96 97
#define DEFAULT_LEFT_POS  4
#define DEFAULT_TOP_POS   4
#define DEFAULT_SPACING   7

98 99 100 101 102 103 104
struct _GtkToggleButtonPrivate
{
  guint active         : 1;
  guint draw_indicator : 1;
  guint inconsistent   : 1;
};

Elliot Lee's avatar
Elliot Lee committed
105 106 107 108 109
enum {
  TOGGLED,
  LAST_SIGNAL
};

110
enum {
111 112 113 114
  PROP_0,
  PROP_ACTIVE,
  PROP_INCONSISTENT,
  PROP_DRAW_INDICATOR
115 116
};

Elliot Lee's avatar
Elliot Lee committed
117

118 119
static gint gtk_toggle_button_draw         (GtkWidget            *widget,
					    cairo_t              *cr);
120 121
static gboolean gtk_toggle_button_mnemonic_activate  (GtkWidget            *widget,
                                                      gboolean              group_cycling);
122 123 124 125 126 127 128 129 130 131 132
static void gtk_toggle_button_pressed       (GtkButton            *button);
static void gtk_toggle_button_released      (GtkButton            *button);
static void gtk_toggle_button_clicked       (GtkButton            *button);
static void gtk_toggle_button_set_property  (GObject              *object,
					     guint                 prop_id,
					     const GValue         *value,
					     GParamSpec           *pspec);
static void gtk_toggle_button_get_property  (GObject              *object,
					     guint                 prop_id,
					     GValue               *value,
					     GParamSpec           *pspec);
133
static void gtk_toggle_button_update_state  (GtkButton            *button);
Elliot Lee's avatar
Elliot Lee committed
134 135


136
static void gtk_toggle_button_activatable_interface_init (GtkActivatableIface  *iface);
137 138 139 140 141
static void gtk_toggle_button_update         	     (GtkActivatable       *activatable,
					 	      GtkAction            *action,
						      const gchar          *property_name);
static void gtk_toggle_button_sync_action_properties (GtkActivatable       *activatable,
						      GtkAction            *action);
142 143 144 145 146 147 148

static GtkActivatableIface *parent_activatable_iface;
static guint                toggle_button_signals[LAST_SIGNAL] = { 0 };

G_DEFINE_TYPE_WITH_CODE (GtkToggleButton, gtk_toggle_button, GTK_TYPE_BUTTON,
			 G_IMPLEMENT_INTERFACE (GTK_TYPE_ACTIVATABLE,
						gtk_toggle_button_activatable_interface_init))
Elliot Lee's avatar
Elliot Lee committed
149 150 151 152

static void
gtk_toggle_button_class_init (GtkToggleButtonClass *class)
{
Manish Singh's avatar
Manish Singh committed
153
  GObjectClass *gobject_class;
Elliot Lee's avatar
Elliot Lee committed
154 155 156
  GtkWidgetClass *widget_class;
  GtkButtonClass *button_class;

157
  gobject_class = G_OBJECT_CLASS (class);
Elliot Lee's avatar
Elliot Lee committed
158 159 160
  widget_class = (GtkWidgetClass*) class;
  button_class = (GtkButtonClass*) class;

161 162
  gobject_class->set_property = gtk_toggle_button_set_property;
  gobject_class->get_property = gtk_toggle_button_get_property;
163

164
  widget_class->draw = gtk_toggle_button_draw;
165
  widget_class->mnemonic_activate = gtk_toggle_button_mnemonic_activate;
Elliot Lee's avatar
Elliot Lee committed
166 167 168 169

  button_class->pressed = gtk_toggle_button_pressed;
  button_class->released = gtk_toggle_button_released;
  button_class->clicked = gtk_toggle_button_clicked;
170 171
  button_class->enter = gtk_toggle_button_update_state;
  button_class->leave = gtk_toggle_button_update_state;
Elliot Lee's avatar
Elliot Lee committed
172 173

  class->toggled = NULL;
174

175 176 177
  g_object_class_install_property (gobject_class,
                                   PROP_ACTIVE,
                                   g_param_spec_boolean ("active",
178
							 P_("Active"),
179
							 P_("If the toggle button should be pressed in"),
180
							 FALSE,
181
							 GTK_PARAM_READWRITE));
182 183 184 185

  g_object_class_install_property (gobject_class,
                                   PROP_INCONSISTENT,
                                   g_param_spec_boolean ("inconsistent",
186 187
							 P_("Inconsistent"),
							 P_("If the toggle button is in an \"in between\" state"),
188
							 FALSE,
189
							 GTK_PARAM_READWRITE));
190 191 192

  g_object_class_install_property (gobject_class,
                                   PROP_DRAW_INDICATOR,
193
                                   g_param_spec_boolean ("draw-indicator",
194 195
							 P_("Draw Indicator"),
							 P_("If the toggle part of the button is displayed"),
196
							 FALSE,
197
							 GTK_PARAM_READWRITE));
198

199 200 201 202 203 204 205
  /**
   * GtkToggleButton::toggled:
   * @togglebutton: the object which received the signal.
   *
   * Should be connected if you wish to perform an action whenever the
   * #GtkToggleButton's state is changed.
   */
206
  toggle_button_signals[TOGGLED] =
207
    g_signal_new (I_("toggled"),
Manish Singh's avatar
Manish Singh committed
208 209 210 211 212 213
		  G_OBJECT_CLASS_TYPE (gobject_class),
		  G_SIGNAL_RUN_FIRST,
		  G_STRUCT_OFFSET (GtkToggleButtonClass, toggled),
		  NULL, NULL,
		  _gtk_marshal_VOID__VOID,
		  G_TYPE_NONE, 0);
214 215

  g_type_class_add_private (class, sizeof (GtkToggleButtonPrivate));
216 217

  gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_TOGGLE_BUTTON_ACCESSIBLE);
Elliot Lee's avatar
Elliot Lee committed
218 219 220 221 222
}

static void
gtk_toggle_button_init (GtkToggleButton *toggle_button)
{
223 224 225 226 227 228 229 230 231
  GtkToggleButtonPrivate *priv;

  toggle_button->priv = G_TYPE_INSTANCE_GET_PRIVATE (toggle_button,
                                                     GTK_TYPE_TOGGLE_BUTTON,
                                                     GtkToggleButtonPrivate);
  priv = toggle_button->priv;

  priv->active = FALSE;
  priv->draw_indicator = FALSE;
232
  GTK_BUTTON (toggle_button)->priv->depress_on_activate = TRUE;
Elliot Lee's avatar
Elliot Lee committed
233 234
}

235 236
static void
gtk_toggle_button_activatable_interface_init (GtkActivatableIface *iface)
237 238
{
  parent_activatable_iface = g_type_interface_peek_parent (iface);
239 240
  iface->update = gtk_toggle_button_update;
  iface->sync_action_properties = gtk_toggle_button_sync_action_properties;
241 242 243
}

static void
244 245 246
gtk_toggle_button_update (GtkActivatable *activatable,
			  GtkAction      *action,
			  const gchar    *property_name)
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263
{
  GtkToggleButton *button;

  parent_activatable_iface->update (activatable, action, property_name);

  button = GTK_TOGGLE_BUTTON (activatable);

  if (strcmp (property_name, "active") == 0)
    {
      gtk_action_block_activate (action);
      gtk_toggle_button_set_active (button, gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)));
      gtk_action_unblock_activate (action);
    }

}

static void
264 265
gtk_toggle_button_sync_action_properties (GtkActivatable *activatable,
				          GtkAction      *action)
266 267 268
{
  GtkToggleButton *button;

269
  parent_activatable_iface->sync_action_properties (activatable, action);
270

271
  if (!GTK_IS_TOGGLE_ACTION (action))
272 273 274 275 276 277 278 279 280
    return;

  button = GTK_TOGGLE_BUTTON (activatable);

  gtk_action_block_activate (action);
  gtk_toggle_button_set_active (button, gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)));
  gtk_action_unblock_activate (action);
}

281 282 283 284 285 286 287
/**
 * gtk_toggle_button_new:
 *
 * Creates a new toggle button. A widget should be packed into the button, as in gtk_button_new().
 *
 * Returns: a new toggle button.
 */
Elliot Lee's avatar
Elliot Lee committed
288
GtkWidget*
289
gtk_toggle_button_new (void)
Elliot Lee's avatar
Elliot Lee committed
290
{
Manish Singh's avatar
Manish Singh committed
291
  return g_object_new (GTK_TYPE_TOGGLE_BUTTON, NULL);
Elliot Lee's avatar
Elliot Lee committed
292 293
}

294 295 296 297 298 299 300 301
/**
 * gtk_toggle_button_new_with_label:
 * @label: a string containing the message to be placed in the toggle button.
 *
 * Creates a new toggle button with a text label.
 *
 * Returns: a new toggle button.
 */
Elliot Lee's avatar
Elliot Lee committed
302 303 304
GtkWidget*
gtk_toggle_button_new_with_label (const gchar *label)
{
305
  return g_object_new (GTK_TYPE_TOGGLE_BUTTON, "label", label, NULL);
Elliot Lee's avatar
Elliot Lee committed
306 307
}

308 309 310 311 312 313 314 315
/**
 * gtk_toggle_button_new_with_mnemonic:
 * @label: the text of the button, with an underscore in front of the
 *         mnemonic character
 *
 * Creates a new #GtkToggleButton containing a label. The label
 * will be created using gtk_label_new_with_mnemonic(), so underscores
 * in @label indicate the mnemonic for the button.
Matthias Clasen's avatar
Matthias Clasen committed
316 317 318
 *
 * Returns: a new #GtkToggleButton
 */
319 320 321
GtkWidget*
gtk_toggle_button_new_with_mnemonic (const gchar *label)
{
322 323 324 325
  return g_object_new (GTK_TYPE_TOGGLE_BUTTON, 
		       "label", label, 
		       "use-underline", TRUE, 
		       NULL);
326 327
}

328
static void
329 330 331 332
gtk_toggle_button_set_property (GObject      *object,
				guint         prop_id,
				const GValue *value,
				GParamSpec   *pspec)
333 334 335 336 337
{
  GtkToggleButton *tb;

  tb = GTK_TOGGLE_BUTTON (object);

338
  switch (prop_id)
339
    {
340 341 342 343 344
    case PROP_ACTIVE:
      gtk_toggle_button_set_active (tb, g_value_get_boolean (value));
      break;
    case PROP_INCONSISTENT:
      gtk_toggle_button_set_inconsistent (tb, g_value_get_boolean (value));
345
      break;
346 347
    case PROP_DRAW_INDICATOR:
      gtk_toggle_button_set_mode (tb, g_value_get_boolean (value));
348 349
      break;
    default:
350
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
351 352 353 354 355
      break;
    }
}

static void
356 357 358 359
gtk_toggle_button_get_property (GObject      *object,
				guint         prop_id,
				GValue       *value,
				GParamSpec   *pspec)
360
{
361 362
  GtkToggleButton *tb = GTK_TOGGLE_BUTTON (object);
  GtkToggleButtonPrivate *priv = tb->priv;
363

364
  switch (prop_id)
365
    {
366
    case PROP_ACTIVE:
367
      g_value_set_boolean (value, priv->active);
368 369
      break;
    case PROP_INCONSISTENT:
370
      g_value_set_boolean (value, priv->inconsistent);
371
      break;
372
    case PROP_DRAW_INDICATOR:
373
      g_value_set_boolean (value, priv->draw_indicator);
374 375
      break;
    default:
376
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
377 378 379 380
      break;
    }
}

381 382 383 384 385 386 387 388 389 390
/**
 * gtk_toggle_button_set_mode:
 * @toggle_button: a #GtkToggleButton
 * @draw_indicator: if %TRUE, draw the button as a separate indicator
 * and label; if %FALSE, draw the button like a normal button
 *
 * Sets whether the button is displayed as a separate indicator and label.
 * You can call this function on a checkbutton or a radiobutton with
 * @draw_indicator = %FALSE to make the button look like a normal button
 *
391
 * This function only affects instances of classes like #GtkCheckButton
392 393 394
 * and #GtkRadioButton that derive from #GtkToggleButton,
 * not instances of #GtkToggleButton itself.
 */
Elliot Lee's avatar
Elliot Lee committed
395 396
void
gtk_toggle_button_set_mode (GtkToggleButton *toggle_button,
397
			    gboolean         draw_indicator)
Elliot Lee's avatar
Elliot Lee committed
398
{
399 400
  GtkToggleButtonPrivate *priv;

Elliot Lee's avatar
Elliot Lee committed
401 402
  g_return_if_fail (GTK_IS_TOGGLE_BUTTON (toggle_button));

403 404
  priv = toggle_button->priv;

Elliot Lee's avatar
Elliot Lee committed
405 406
  draw_indicator = draw_indicator ? TRUE : FALSE;

407
  if (priv->draw_indicator != draw_indicator)
Elliot Lee's avatar
Elliot Lee committed
408
    {
409 410
      GtkStyleContext *context;

411
      priv->draw_indicator = draw_indicator;
412 413
      GTK_BUTTON (toggle_button)->priv->depress_on_activate = !draw_indicator;

414
      if (gtk_widget_get_visible (GTK_WIDGET (toggle_button)))
Elliot Lee's avatar
Elliot Lee committed
415
	gtk_widget_queue_resize (GTK_WIDGET (toggle_button));
416

417
      g_object_notify (G_OBJECT (toggle_button), "draw-indicator");
418 419 420 421 422 423 424 425 426 427

      /* Make toggle buttons conditionally have the "button"
       * class depending on draw_indicator.
       */
      context = gtk_widget_get_style_context (GTK_WIDGET (toggle_button));

      if (draw_indicator)
        gtk_style_context_remove_class (context, GTK_STYLE_CLASS_BUTTON);
      else
        gtk_style_context_add_class (context, GTK_STYLE_CLASS_BUTTON);
Elliot Lee's avatar
Elliot Lee committed
428 429 430
    }
}

431 432 433 434 435 436 437 438 439 440 441 442 443 444 445
/**
 * gtk_toggle_button_get_mode:
 * @toggle_button: a #GtkToggleButton
 *
 * Retrieves whether the button is displayed as a separate indicator
 * and label. See gtk_toggle_button_set_mode().
 *
 * Return value: %TRUE if the togglebutton is drawn as a separate indicator
 *   and label.
 **/
gboolean
gtk_toggle_button_get_mode (GtkToggleButton *toggle_button)
{
  g_return_val_if_fail (GTK_IS_TOGGLE_BUTTON (toggle_button), FALSE);

446
  return toggle_button->priv->draw_indicator;
447
}
448

449 450 451 452 453 454 455 456 457
/**
 * gtk_toggle_button_set_active:
 * @toggle_button: a #GtkToggleButton.
 * @is_active: %TRUE or %FALSE.
 *
 * Sets the status of the toggle button. Set to %TRUE if you want the
 * GtkToggleButton to be 'pressed in', and %FALSE to raise it.
 * This action causes the toggled signal to be emitted.
 */
Elliot Lee's avatar
Elliot Lee committed
458
void
459 460
gtk_toggle_button_set_active (GtkToggleButton *toggle_button,
			      gboolean         is_active)
Elliot Lee's avatar
Elliot Lee committed
461
{
462 463
  GtkToggleButtonPrivate *priv;

Elliot Lee's avatar
Elliot Lee committed
464 465
  g_return_if_fail (GTK_IS_TOGGLE_BUTTON (toggle_button));

466 467
  priv = toggle_button->priv;

468
  is_active = is_active != FALSE;
469

470
  if (priv->active != is_active)
Elliot Lee's avatar
Elliot Lee committed
471 472 473
    gtk_button_clicked (GTK_BUTTON (toggle_button));
}

474 475 476 477
void
_gtk_toggle_button_set_active (GtkToggleButton *toggle_button,
                               gboolean         is_active)
{
478
  toggle_button->priv->active = is_active;
479 480
}

481 482 483 484 485 486 487 488 489
/**
 * gtk_toggle_button_get_active:
 * @toggle_button: a #GtkToggleButton.
 *
 * Queries a #GtkToggleButton and returns its current state. Returns %TRUE if
 * the toggle button is pressed in and %FALSE if it is raised.
 *
 * Returns: a #gboolean value.
 */
490 491 492 493 494
gboolean
gtk_toggle_button_get_active (GtkToggleButton *toggle_button)
{
  g_return_val_if_fail (GTK_IS_TOGGLE_BUTTON (toggle_button), FALSE);

495
  return toggle_button->priv->active;
496 497
}

498 499 500 501 502 503 504 505
/**
 * gtk_toggle_button_toggled:
 * @toggle_button: a #GtkToggleButton.
 *
 * Emits the #GtkToggleButton::toggled signal on the
 * #GtkToggleButton. There is no good reason for an
 * application ever to call this function.
 */
Elliot Lee's avatar
Elliot Lee committed
506 507 508
void
gtk_toggle_button_toggled (GtkToggleButton *toggle_button)
{
509 510
  g_return_if_fail (GTK_IS_TOGGLE_BUTTON (toggle_button));

Manish Singh's avatar
Manish Singh committed
511
  g_signal_emit (toggle_button, toggle_button_signals[TOGGLED], 0);
Elliot Lee's avatar
Elliot Lee committed
512 513
}

514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532
/**
 * gtk_toggle_button_set_inconsistent:
 * @toggle_button: a #GtkToggleButton
 * @setting: %TRUE if state is inconsistent
 *
 * If the user has selected a range of elements (such as some text or
 * spreadsheet cells) that are affected by a toggle button, and the
 * current values in that range are inconsistent, you may want to
 * display the toggle in an "in between" state. This function turns on
 * "in between" display.  Normally you would turn off the inconsistent
 * state again if the user toggles the toggle button. This has to be
 * done manually, gtk_toggle_button_set_inconsistent() only affects
 * visual appearance, it doesn't affect the semantics of the button.
 * 
 **/
void
gtk_toggle_button_set_inconsistent (GtkToggleButton *toggle_button,
                                    gboolean         setting)
{
533 534
  GtkToggleButtonPrivate *priv;

535
  g_return_if_fail (GTK_IS_TOGGLE_BUTTON (toggle_button));
536 537 538

  priv = toggle_button->priv;

539 540
  setting = setting != FALSE;

541
  if (setting != priv->inconsistent)
542
    {
543 544
      priv->inconsistent = setting;

545
      gtk_toggle_button_update_state (GTK_BUTTON (toggle_button));
546
      gtk_widget_queue_draw (GTK_WIDGET (toggle_button));
547 548

      g_object_notify (G_OBJECT (toggle_button), "inconsistent");      
549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564
    }
}

/**
 * gtk_toggle_button_get_inconsistent:
 * @toggle_button: a #GtkToggleButton
 * 
 * Gets the value set by gtk_toggle_button_set_inconsistent().
 * 
 * Return value: %TRUE if the button is displayed as inconsistent, %FALSE otherwise
 **/
gboolean
gtk_toggle_button_get_inconsistent (GtkToggleButton *toggle_button)
{
  g_return_val_if_fail (GTK_IS_TOGGLE_BUTTON (toggle_button), FALSE);

565
  return toggle_button->priv->inconsistent;
566
}
Elliot Lee's avatar
Elliot Lee committed
567

568
static gint
569 570
gtk_toggle_button_draw (GtkWidget *widget,
			cairo_t   *cr)
Elliot Lee's avatar
Elliot Lee committed
571
{
572 573
  GtkToggleButton *toggle_button = GTK_TOGGLE_BUTTON (widget);
  GtkToggleButtonPrivate *priv = toggle_button->priv;
574 575
  GtkWidget *child = gtk_bin_get_child (GTK_BIN (widget));
  GtkButton *button = GTK_BUTTON (widget);
576
  GtkStateType state;
Elliot Lee's avatar
Elliot Lee committed
577

578
  state = gtk_widget_get_state_flags (widget);
579 580

  if (priv->inconsistent)
581 582 583
    state |= GTK_STATE_FLAG_INCONSISTENT;
  else if (button->priv->depressed)
    state |= GTK_STATE_FLAG_ACTIVE;
584 585 586 587

  _gtk_button_paint (button, cr,
                     gtk_widget_get_allocated_width (widget),
                     gtk_widget_get_allocated_height (widget),
588
                     state);
589 590 591 592

  if (child)
    gtk_container_propagate_draw (GTK_CONTAINER (widget), child, cr);

593
  return FALSE;
594 595
}

596 597 598 599 600 601 602 603 604
static gboolean
gtk_toggle_button_mnemonic_activate (GtkWidget *widget,
                                     gboolean   group_cycling)
{
  /*
   * We override the standard implementation in 
   * gtk_widget_real_mnemonic_activate() in order to focus the widget even
   * if there is no mnemonic conflict.
   */
605
  if (gtk_widget_get_can_focus (widget))
606 607 608 609 610 611 612 613
    gtk_widget_grab_focus (widget);

  if (!group_cycling)
    gtk_widget_activate (widget);

  return TRUE;
}

Elliot Lee's avatar
Elliot Lee committed
614 615 616
static void
gtk_toggle_button_pressed (GtkButton *button)
{
617
  button->priv->button_down = TRUE;
Elliot Lee's avatar
Elliot Lee committed
618

619
  gtk_toggle_button_update_state (button);
620
  gtk_widget_queue_draw (GTK_WIDGET (button));
Elliot Lee's avatar
Elliot Lee committed
621 622 623 624 625
}

static void
gtk_toggle_button_released (GtkButton *button)
{
626
  if (button->priv->button_down)
Elliot Lee's avatar
Elliot Lee committed
627
    {
628
      button->priv->button_down = FALSE;
Elliot Lee's avatar
Elliot Lee committed
629

630
      if (button->priv->in_button)
631
	gtk_button_clicked (button);
Elliot Lee's avatar
Elliot Lee committed
632

633
      gtk_toggle_button_update_state (button);
634
      gtk_widget_queue_draw (GTK_WIDGET (button));
Elliot Lee's avatar
Elliot Lee committed
635 636 637 638 639 640
    }
}

static void
gtk_toggle_button_clicked (GtkButton *button)
{
641
  GtkToggleButton *toggle_button = GTK_TOGGLE_BUTTON (button);
642 643 644
  GtkToggleButtonPrivate *priv = toggle_button->priv;

  priv->active = !priv->active;
Elliot Lee's avatar
Elliot Lee committed
645 646 647

  gtk_toggle_button_toggled (toggle_button);

648
  gtk_toggle_button_update_state (button);
649 650

  g_object_notify (G_OBJECT (toggle_button), "active");
651

Matthias Clasen's avatar
Matthias Clasen committed
652 653
  if (GTK_BUTTON_CLASS (gtk_toggle_button_parent_class)->clicked)
    GTK_BUTTON_CLASS (gtk_toggle_button_parent_class)->clicked (button);
Elliot Lee's avatar
Elliot Lee committed
654 655
}

656 657 658 659
static void
gtk_toggle_button_update_state (GtkButton *button)
{
  GtkToggleButton *toggle_button = GTK_TOGGLE_BUTTON (button);
660
  GtkToggleButtonPrivate *priv = toggle_button->priv;
661
  gboolean depressed, touchscreen;
662
  GtkStateFlags new_state = 0;
663

664 665 666 667
  g_object_get (gtk_widget_get_settings (GTK_WIDGET (button)),
                "gtk-touchscreen-mode", &touchscreen,
                NULL);

668 669 670 671 672
  new_state = gtk_widget_get_state_flags (GTK_WIDGET (button)) &
    ~(GTK_STATE_FLAG_INCONSISTENT |
      GTK_STATE_FLAG_PRELIGHT |
      GTK_STATE_FLAG_ACTIVE);

673 674 675
  if (priv->inconsistent)
    new_state |= GTK_STATE_FLAG_INCONSISTENT;

676
  if (priv->inconsistent)
677
    depressed = FALSE;
678
  else if (button->priv->in_button && button->priv->button_down)
679
    depressed = TRUE;
680
  else
681 682
    depressed = priv->active;

683
  if (!touchscreen && button->priv->in_button && (!button->priv->button_down || priv->draw_indicator))
684
    new_state |= GTK_STATE_FLAG_PRELIGHT;
685 686

  if (depressed)
687
    new_state |= GTK_STATE_FLAG_ACTIVE;
688

689 690
  _gtk_button_set_depressed (button, depressed);
  gtk_widget_set_state_flags (GTK_WIDGET (toggle_button), new_state, TRUE);
691
}