gtktogglebutton.c 20.3 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 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
/**
 * 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
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 gint gtk_toggle_button_draw         (GtkWidget            *widget,
					    cairo_t              *cr);
118 119
static gboolean gtk_toggle_button_mnemonic_activate  (GtkWidget            *widget,
                                                      gboolean              group_cycling);
120 121 122 123 124 125 126 127 128 129 130
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);
131
static void gtk_toggle_button_update_state  (GtkButton            *button);
Elliot Lee's avatar
Elliot Lee committed
132 133


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

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
147 148 149 150

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

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

159 160
  gobject_class->set_property = gtk_toggle_button_set_property;
  gobject_class->get_property = gtk_toggle_button_get_property;
161

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

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

  class->toggled = NULL;
172

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

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

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

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

  g_type_class_add_private (class, sizeof (GtkToggleButtonPrivate));
214 215

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

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

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

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

267
  parent_activatable_iface->sync_action_properties (activatable, action);
268

269
  if (!GTK_IS_TOGGLE_ACTION (action))
270 271 272 273 274 275 276 277 278
    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);
}

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

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

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

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

  tb = GTK_TOGGLE_BUTTON (object);

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

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

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

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

Elliot Lee's avatar
Elliot Lee committed
399 400
  g_return_if_fail (GTK_IS_TOGGLE_BUTTON (toggle_button));

401 402
  priv = toggle_button->priv;

Elliot Lee's avatar
Elliot Lee committed
403 404
  draw_indicator = draw_indicator ? TRUE : FALSE;

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

409
      priv->draw_indicator = draw_indicator;
410 411
      GTK_BUTTON (toggle_button)->priv->depress_on_activate = !draw_indicator;

412
      if (gtk_widget_get_visible (GTK_WIDGET (toggle_button)))
Elliot Lee's avatar
Elliot Lee committed
413
	gtk_widget_queue_resize (GTK_WIDGET (toggle_button));
414

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

      /* 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
426 427 428
    }
}

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

444
  return toggle_button->priv->draw_indicator;
445
}
446

447 448 449 450 451 452 453 454 455
/**
 * 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
456
void
457 458
gtk_toggle_button_set_active (GtkToggleButton *toggle_button,
			      gboolean         is_active)
Elliot Lee's avatar
Elliot Lee committed
459
{
460 461
  GtkToggleButtonPrivate *priv;

Elliot Lee's avatar
Elliot Lee committed
462 463
  g_return_if_fail (GTK_IS_TOGGLE_BUTTON (toggle_button));

464 465
  priv = toggle_button->priv;

466
  is_active = is_active != FALSE;
467

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

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

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

493
  return toggle_button->priv->active;
494 495
}

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

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

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

533
  g_return_if_fail (GTK_IS_TOGGLE_BUTTON (toggle_button));
534 535 536

  priv = toggle_button->priv;

537 538
  setting = setting != FALSE;

539
  if (setting != priv->inconsistent)
540
    {
541 542
      priv->inconsistent = setting;

543
      gtk_toggle_button_update_state (GTK_BUTTON (toggle_button));
544
      gtk_widget_queue_draw (GTK_WIDGET (toggle_button));
545 546

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

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

563
  return toggle_button->priv->inconsistent;
564
}
Elliot Lee's avatar
Elliot Lee committed
565

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

576
  state = gtk_widget_get_state_flags (widget);
577 578

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

  _gtk_button_paint (button, cr,
                     gtk_widget_get_allocated_width (widget),
                     gtk_widget_get_allocated_height (widget),
586
                     state);
587 588 589 590

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

591
  return FALSE;
592 593
}

594 595 596 597 598 599 600 601 602
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.
   */
603
  if (gtk_widget_get_can_focus (widget))
604 605 606 607 608 609 610 611
    gtk_widget_grab_focus (widget);

  if (!group_cycling)
    gtk_widget_activate (widget);

  return TRUE;
}

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

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

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

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

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

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

  priv->active = !priv->active;
Elliot Lee's avatar
Elliot Lee committed
643 644 645

  gtk_toggle_button_toggled (toggle_button);

646
  gtk_toggle_button_update_state (button);
647 648

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

Matthias Clasen's avatar
Matthias Clasen committed
650 651
  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
652 653
}

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

662 663 664 665 666
  new_state = gtk_widget_get_state_flags (GTK_WIDGET (button)) &
    ~(GTK_STATE_FLAG_INCONSISTENT |
      GTK_STATE_FLAG_PRELIGHT |
      GTK_STATE_FLAG_ACTIVE);

667 668 669
  if (priv->inconsistent)
    new_state |= GTK_STATE_FLAG_INCONSISTENT;

670
  if (priv->inconsistent)
671
    depressed = FALSE;
672
  else if (button->priv->in_button && button->priv->button_down)
673
    depressed = TRUE;
674
  else
675 676
    depressed = priv->active;

677
  if (button->priv->in_button && (!button->priv->button_down || priv->draw_indicator))
678
    new_state |= GTK_STATE_FLAG_PRELIGHT;
679 680

  if (depressed)
681
    new_state |= GTK_STATE_FLAG_ACTIVE;
682

683 684
  _gtk_button_set_depressed (button, depressed);
  gtk_widget_set_state_flags (GTK_WIDGET (toggle_button), new_state, TRUE);
685
}