gtktogglebutton.c 19.4 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
Javier Jardón's avatar
Javier Jardón committed
15
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
Elliot Lee's avatar
Elliot Lee committed
16
 */
17 18

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

25
#include "config.h"
26 27 28 29

#include "gtktogglebutton.h"

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

Elliot Lee's avatar
Elliot Lee committed
39

40 41 42 43 44 45 46 47 48 49 50 51
/**
 * 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
52
 * pack a widget, (such as a #GtkLabel and/or a #GtkImage), into the toggle
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
 * 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
92 93 94 95
#define DEFAULT_LEFT_POS  4
#define DEFAULT_TOP_POS   4
#define DEFAULT_SPACING   7

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

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

108
enum {
109 110 111 112
  PROP_0,
  PROP_ACTIVE,
  PROP_INCONSISTENT,
  PROP_DRAW_INDICATOR
113 114
};

Elliot Lee's avatar
Elliot Lee committed
115

116 117
static gboolean gtk_toggle_button_mnemonic_activate  (GtkWidget            *widget,
                                                      gboolean              group_cycling);
118 119 120 121 122 123 124 125 126 127 128
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);
129
static void gtk_toggle_button_update_state  (GtkButton            *button);
Elliot Lee's avatar
Elliot Lee committed
130 131


132
static void gtk_toggle_button_activatable_interface_init (GtkActivatableIface  *iface);
133 134 135 136 137
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);
138 139 140 141 142 143 144

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
145 146 147 148

static void
gtk_toggle_button_class_init (GtkToggleButtonClass *class)
{
Manish Singh's avatar
Manish Singh committed
149
  GObjectClass *gobject_class;
Elliot Lee's avatar
Elliot Lee committed
150 151 152
  GtkWidgetClass *widget_class;
  GtkButtonClass *button_class;

153
  gobject_class = G_OBJECT_CLASS (class);
Elliot Lee's avatar
Elliot Lee committed
154 155 156
  widget_class = (GtkWidgetClass*) class;
  button_class = (GtkButtonClass*) class;

157 158
  gobject_class->set_property = gtk_toggle_button_set_property;
  gobject_class->get_property = gtk_toggle_button_get_property;
159

160
  widget_class->mnemonic_activate = gtk_toggle_button_mnemonic_activate;
Elliot Lee's avatar
Elliot Lee committed
161 162 163 164

  button_class->pressed = gtk_toggle_button_pressed;
  button_class->released = gtk_toggle_button_released;
  button_class->clicked = gtk_toggle_button_clicked;
165 166
  button_class->enter = gtk_toggle_button_update_state;
  button_class->leave = gtk_toggle_button_update_state;
Elliot Lee's avatar
Elliot Lee committed
167 168

  class->toggled = NULL;
169

170 171 172
  g_object_class_install_property (gobject_class,
                                   PROP_ACTIVE,
                                   g_param_spec_boolean ("active",
173
							 P_("Active"),
174
							 P_("If the toggle button should be pressed in"),
175
							 FALSE,
176
							 GTK_PARAM_READWRITE));
177 178 179 180

  g_object_class_install_property (gobject_class,
                                   PROP_INCONSISTENT,
                                   g_param_spec_boolean ("inconsistent",
181 182
							 P_("Inconsistent"),
							 P_("If the toggle button is in an \"in between\" state"),
183
							 FALSE,
184
							 GTK_PARAM_READWRITE));
185 186 187

  g_object_class_install_property (gobject_class,
                                   PROP_DRAW_INDICATOR,
188
                                   g_param_spec_boolean ("draw-indicator",
189 190
							 P_("Draw Indicator"),
							 P_("If the toggle part of the button is displayed"),
191
							 FALSE,
192
							 GTK_PARAM_READWRITE));
193

194 195 196 197 198 199 200
  /**
   * 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.
   */
201
  toggle_button_signals[TOGGLED] =
202
    g_signal_new (I_("toggled"),
Manish Singh's avatar
Manish Singh committed
203 204 205 206 207 208
		  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);
209 210

  g_type_class_add_private (class, sizeof (GtkToggleButtonPrivate));
211 212

  gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_TOGGLE_BUTTON_ACCESSIBLE);
Elliot Lee's avatar
Elliot Lee committed
213 214 215 216 217
}

static void
gtk_toggle_button_init (GtkToggleButton *toggle_button)
{
218 219 220 221 222 223 224 225 226
  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;
227
  GTK_BUTTON (toggle_button)->priv->depress_on_activate = TRUE;
Elliot Lee's avatar
Elliot Lee committed
228 229
}

230 231
static void
gtk_toggle_button_activatable_interface_init (GtkActivatableIface *iface)
232 233
{
  parent_activatable_iface = g_type_interface_peek_parent (iface);
234 235
  iface->update = gtk_toggle_button_update;
  iface->sync_action_properties = gtk_toggle_button_sync_action_properties;
236 237 238
}

static void
239 240 241
gtk_toggle_button_update (GtkActivatable *activatable,
			  GtkAction      *action,
			  const gchar    *property_name)
242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258
{
  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
259 260
gtk_toggle_button_sync_action_properties (GtkActivatable *activatable,
				          GtkAction      *action)
261 262 263
{
  GtkToggleButton *button;

264
  parent_activatable_iface->sync_action_properties (activatable, action);
265

266
  if (!GTK_IS_TOGGLE_ACTION (action))
267 268 269 270 271 272 273 274 275
    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);
}

276 277 278 279 280 281 282
/**
 * 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
283
GtkWidget*
284
gtk_toggle_button_new (void)
Elliot Lee's avatar
Elliot Lee committed
285
{
Manish Singh's avatar
Manish Singh committed
286
  return g_object_new (GTK_TYPE_TOGGLE_BUTTON, NULL);
Elliot Lee's avatar
Elliot Lee committed
287 288
}

289 290 291 292 293 294 295 296
/**
 * 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
297 298 299
GtkWidget*
gtk_toggle_button_new_with_label (const gchar *label)
{
300
  return g_object_new (GTK_TYPE_TOGGLE_BUTTON, "label", label, NULL);
Elliot Lee's avatar
Elliot Lee committed
301 302
}

303 304 305 306 307 308 309 310
/**
 * 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
311 312 313
 *
 * Returns: a new #GtkToggleButton
 */
314 315 316
GtkWidget*
gtk_toggle_button_new_with_mnemonic (const gchar *label)
{
317 318 319 320
  return g_object_new (GTK_TYPE_TOGGLE_BUTTON, 
		       "label", label, 
		       "use-underline", TRUE, 
		       NULL);
321 322
}

323
static void
324 325 326 327
gtk_toggle_button_set_property (GObject      *object,
				guint         prop_id,
				const GValue *value,
				GParamSpec   *pspec)
328 329 330 331 332
{
  GtkToggleButton *tb;

  tb = GTK_TOGGLE_BUTTON (object);

333
  switch (prop_id)
334
    {
335 336 337 338 339
    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));
340
      break;
341 342
    case PROP_DRAW_INDICATOR:
      gtk_toggle_button_set_mode (tb, g_value_get_boolean (value));
343 344
      break;
    default:
345
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
346 347 348 349 350
      break;
    }
}

static void
351 352 353 354
gtk_toggle_button_get_property (GObject      *object,
				guint         prop_id,
				GValue       *value,
				GParamSpec   *pspec)
355
{
356 357
  GtkToggleButton *tb = GTK_TOGGLE_BUTTON (object);
  GtkToggleButtonPrivate *priv = tb->priv;
358

359
  switch (prop_id)
360
    {
361
    case PROP_ACTIVE:
362
      g_value_set_boolean (value, priv->active);
363 364
      break;
    case PROP_INCONSISTENT:
365
      g_value_set_boolean (value, priv->inconsistent);
366
      break;
367
    case PROP_DRAW_INDICATOR:
368
      g_value_set_boolean (value, priv->draw_indicator);
369 370
      break;
    default:
371
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
372 373 374 375
      break;
    }
}

376 377 378 379 380 381 382 383 384 385
/**
 * 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
 *
386
 * This function only affects instances of classes like #GtkCheckButton
387 388 389
 * and #GtkRadioButton that derive from #GtkToggleButton,
 * not instances of #GtkToggleButton itself.
 */
Elliot Lee's avatar
Elliot Lee committed
390 391
void
gtk_toggle_button_set_mode (GtkToggleButton *toggle_button,
392
			    gboolean         draw_indicator)
Elliot Lee's avatar
Elliot Lee committed
393
{
394 395
  GtkToggleButtonPrivate *priv;

Elliot Lee's avatar
Elliot Lee committed
396 397
  g_return_if_fail (GTK_IS_TOGGLE_BUTTON (toggle_button));

398 399
  priv = toggle_button->priv;

Elliot Lee's avatar
Elliot Lee committed
400 401
  draw_indicator = draw_indicator ? TRUE : FALSE;

402
  if (priv->draw_indicator != draw_indicator)
Elliot Lee's avatar
Elliot Lee committed
403
    {
404 405
      GtkStyleContext *context;

406
      priv->draw_indicator = draw_indicator;
407 408
      GTK_BUTTON (toggle_button)->priv->depress_on_activate = !draw_indicator;

409
      if (gtk_widget_get_visible (GTK_WIDGET (toggle_button)))
Elliot Lee's avatar
Elliot Lee committed
410
	gtk_widget_queue_resize (GTK_WIDGET (toggle_button));
411

412
      g_object_notify (G_OBJECT (toggle_button), "draw-indicator");
413 414 415 416 417 418 419 420 421 422

      /* 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
423 424 425
    }
}

426 427 428 429 430 431 432 433 434 435 436 437 438 439 440
/**
 * 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);

441
  return toggle_button->priv->draw_indicator;
442
}
443

444 445 446 447 448 449 450
/**
 * 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.
451 452
 * This action causes the #GtkToggleButton::toggled signal and the
 * #GtkButton::clicked signal to be emitted.
453
 */
Elliot Lee's avatar
Elliot Lee committed
454
void
455 456
gtk_toggle_button_set_active (GtkToggleButton *toggle_button,
			      gboolean         is_active)
Elliot Lee's avatar
Elliot Lee committed
457
{
458 459
  GtkToggleButtonPrivate *priv;

Elliot Lee's avatar
Elliot Lee committed
460 461
  g_return_if_fail (GTK_IS_TOGGLE_BUTTON (toggle_button));

462 463
  priv = toggle_button->priv;

464
  is_active = is_active != FALSE;
465

466
  if (priv->active != is_active)
Elliot Lee's avatar
Elliot Lee committed
467 468 469
    gtk_button_clicked (GTK_BUTTON (toggle_button));
}

470 471 472 473
void
_gtk_toggle_button_set_active (GtkToggleButton *toggle_button,
                               gboolean         is_active)
{
474
  toggle_button->priv->active = is_active;
475 476
}

477 478 479 480 481 482 483 484 485
/**
 * 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.
 */
486 487 488 489 490
gboolean
gtk_toggle_button_get_active (GtkToggleButton *toggle_button)
{
  g_return_val_if_fail (GTK_IS_TOGGLE_BUTTON (toggle_button), FALSE);

491
  return toggle_button->priv->active;
492 493
}

494 495 496 497 498 499 500 501
/**
 * 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
502 503 504
void
gtk_toggle_button_toggled (GtkToggleButton *toggle_button)
{
505 506
  g_return_if_fail (GTK_IS_TOGGLE_BUTTON (toggle_button));

Manish Singh's avatar
Manish Singh committed
507
  g_signal_emit (toggle_button, toggle_button_signals[TOGGLED], 0);
Elliot Lee's avatar
Elliot Lee committed
508 509
}

510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528
/**
 * 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)
{
529 530
  GtkToggleButtonPrivate *priv;

531
  g_return_if_fail (GTK_IS_TOGGLE_BUTTON (toggle_button));
532 533 534

  priv = toggle_button->priv;

535 536
  setting = setting != FALSE;

537
  if (setting != priv->inconsistent)
538
    {
539 540
      priv->inconsistent = setting;

541
      gtk_toggle_button_update_state (GTK_BUTTON (toggle_button));
542
      gtk_widget_queue_draw (GTK_WIDGET (toggle_button));
543 544

      g_object_notify (G_OBJECT (toggle_button), "inconsistent");      
545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560
    }
}

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

561
  return toggle_button->priv->inconsistent;
562
}
Elliot Lee's avatar
Elliot Lee committed
563

564 565 566 567 568 569 570 571 572
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.
   */
573
  if (gtk_widget_get_can_focus (widget))
574 575 576 577 578 579 580 581
    gtk_widget_grab_focus (widget);

  if (!group_cycling)
    gtk_widget_activate (widget);

  return TRUE;
}

Elliot Lee's avatar
Elliot Lee committed
582 583 584
static void
gtk_toggle_button_pressed (GtkButton *button)
{
585
  button->priv->button_down = TRUE;
Elliot Lee's avatar
Elliot Lee committed
586

587
  gtk_toggle_button_update_state (button);
588
  gtk_widget_queue_draw (GTK_WIDGET (button));
Elliot Lee's avatar
Elliot Lee committed
589 590 591 592 593
}

static void
gtk_toggle_button_released (GtkButton *button)
{
594
  if (button->priv->button_down)
Elliot Lee's avatar
Elliot Lee committed
595
    {
596
      button->priv->button_down = FALSE;
Elliot Lee's avatar
Elliot Lee committed
597

598
      if (button->priv->in_button)
599
	gtk_button_clicked (button);
Elliot Lee's avatar
Elliot Lee committed
600

601
      gtk_toggle_button_update_state (button);
602
      gtk_widget_queue_draw (GTK_WIDGET (button));
Elliot Lee's avatar
Elliot Lee committed
603 604 605 606 607 608
    }
}

static void
gtk_toggle_button_clicked (GtkButton *button)
{
609
  GtkToggleButton *toggle_button = GTK_TOGGLE_BUTTON (button);
610 611 612
  GtkToggleButtonPrivate *priv = toggle_button->priv;

  priv->active = !priv->active;
Elliot Lee's avatar
Elliot Lee committed
613 614 615

  gtk_toggle_button_toggled (toggle_button);

616
  gtk_toggle_button_update_state (button);
617 618

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

Matthias Clasen's avatar
Matthias Clasen committed
620 621
  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
622 623
}

624 625 626 627
static void
gtk_toggle_button_update_state (GtkButton *button)
{
  GtkToggleButton *toggle_button = GTK_TOGGLE_BUTTON (button);
628
  GtkToggleButtonPrivate *priv = toggle_button->priv;
629
  gboolean depressed;
630
  GtkStateFlags new_state = 0;
631

632 633 634 635 636
  new_state = gtk_widget_get_state_flags (GTK_WIDGET (button)) &
    ~(GTK_STATE_FLAG_INCONSISTENT |
      GTK_STATE_FLAG_PRELIGHT |
      GTK_STATE_FLAG_ACTIVE);

637 638 639
  if (priv->inconsistent)
    new_state |= GTK_STATE_FLAG_INCONSISTENT;

640
  if (priv->inconsistent)
641
    depressed = FALSE;
642
  else if (button->priv->in_button && button->priv->button_down)
643
    depressed = TRUE;
644
  else
645 646
    depressed = priv->active;

647
  if (button->priv->in_button)
648
    new_state |= GTK_STATE_FLAG_PRELIGHT;
649 650

  if (depressed)
651
    new_state |= GTK_STATE_FLAG_ACTIVE;
652

653 654
  _gtk_button_set_depressed (button, depressed);
  gtk_widget_set_state_flags (GTK_WIDGET (toggle_button), new_state, TRUE);
655
}