X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtktogglebutton.c;h=999710c1671d93592c7f7a0f86e114a90356dc5d;hb=HEAD;hp=849dc8a64a3e0fcd50be680a9c45685c70986666;hpb=afee2c67c5091539cbe6270b14e7e74b2a7b60a7;p=~andy%2Fgtk diff --git a/gtk/gtktogglebutton.c b/gtk/gtktogglebutton.c index 849dc8a64..999710c16 100644 --- a/gtk/gtktogglebutton.c +++ b/gtk/gtktogglebutton.c @@ -12,9 +12,7 @@ * 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, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * License along with this library. If not, see . */ /* @@ -24,631 +22,634 @@ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. */ +#include "config.h" + +#include "gtktogglebutton.h" + +#include "gtkbuttonprivate.h" #include "gtklabel.h" #include "gtkmain.h" -#include "gtksignal.h" -#include "gtktogglebutton.h" +#include "gtkmarshalers.h" +#include "gtktoggleaction.h" +#include "gtkactivatable.h" +#include "gtkprivate.h" +#include "gtkintl.h" +#include "a11y/gtktogglebuttonaccessible.h" + + +/** + * 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 #GtkImage), 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(). + * + * + * Creating two #GtkToggleButton widgets. + * + * 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); + * } + * + * + */ #define DEFAULT_LEFT_POS 4 #define DEFAULT_TOP_POS 4 #define DEFAULT_SPACING 7 +struct _GtkToggleButtonPrivate +{ + guint active : 1; + guint draw_indicator : 1; + guint inconsistent : 1; +}; + enum { TOGGLED, LAST_SIGNAL }; enum { - ARG_0, - ARG_ACTIVE, - ARG_DRAW_INDICATOR + PROP_0, + PROP_ACTIVE, + PROP_INCONSISTENT, + PROP_DRAW_INDICATOR }; -static void gtk_toggle_button_class_init (GtkToggleButtonClass *klass); -static void gtk_toggle_button_init (GtkToggleButton *toggle_button); -static void gtk_toggle_button_paint (GtkWidget *widget, - GdkRectangle *area); -static void gtk_toggle_button_size_allocate (GtkWidget *widget, - GtkAllocation *allocation); -static void gtk_toggle_button_draw (GtkWidget *widget, - GdkRectangle *area); -static gint gtk_toggle_button_expose (GtkWidget *widget, - GdkEventExpose *event); -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_enter (GtkButton *button); -static void gtk_toggle_button_leave (GtkButton *button); -static void gtk_toggle_button_set_arg (GtkObject *object, - GtkArg *arg, - guint arg_id); -static void gtk_toggle_button_get_arg (GtkObject *object, - GtkArg *arg, - guint arg_id); -static void gtk_toggle_button_leave (GtkButton *button); -static void gtk_toggle_button_realize (GtkWidget *widget); -static void gtk_toggle_button_unrealize (GtkWidget *widget); -static void gtk_toggle_button_map (GtkWidget *widget); -static void gtk_toggle_button_unmap (GtkWidget *widget); - -static guint toggle_button_signals[LAST_SIGNAL] = { 0 }; -static GtkContainerClass *parent_class = NULL; - -GtkType -gtk_toggle_button_get_type (void) -{ - static GtkType toggle_button_type = 0; - - if (!toggle_button_type) - { - static const GtkTypeInfo toggle_button_info = - { - "GtkToggleButton", - sizeof (GtkToggleButton), - sizeof (GtkToggleButtonClass), - (GtkClassInitFunc) gtk_toggle_button_class_init, - (GtkObjectInitFunc) gtk_toggle_button_init, - /* reserved_1 */ NULL, - /* reserved_2 */ NULL, - (GtkClassInitFunc) NULL, - }; - - toggle_button_type = gtk_type_unique (GTK_TYPE_BUTTON, &toggle_button_info); - } - - return toggle_button_type; -} +static gboolean gtk_toggle_button_mnemonic_activate (GtkWidget *widget, + gboolean group_cycling); +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); +static void gtk_toggle_button_update_state (GtkButton *button); + + +static void gtk_toggle_button_activatable_interface_init (GtkActivatableIface *iface); +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); + +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)) static void gtk_toggle_button_class_init (GtkToggleButtonClass *class) { - GtkObjectClass *object_class; + GObjectClass *gobject_class; GtkWidgetClass *widget_class; - GtkContainerClass *container_class; GtkButtonClass *button_class; - object_class = (GtkObjectClass*) class; + gobject_class = G_OBJECT_CLASS (class); widget_class = (GtkWidgetClass*) class; - container_class = (GtkContainerClass*) class; button_class = (GtkButtonClass*) class; - parent_class = gtk_type_class (GTK_TYPE_BUTTON); - - gtk_object_add_arg_type ("GtkToggleButton::active", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_ACTIVE); - gtk_object_add_arg_type ("GtkToggleButton::draw_indicator", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_DRAW_INDICATOR); + gobject_class->set_property = gtk_toggle_button_set_property; + gobject_class->get_property = gtk_toggle_button_get_property; - toggle_button_signals[TOGGLED] = - gtk_signal_new ("toggled", - GTK_RUN_FIRST, - GTK_CLASS_TYPE (object_class), - GTK_SIGNAL_OFFSET (GtkToggleButtonClass, toggled), - gtk_marshal_NONE__NONE, - GTK_TYPE_NONE, 0); - - gtk_object_class_add_signals (object_class, toggle_button_signals, LAST_SIGNAL); - - object_class->set_arg = gtk_toggle_button_set_arg; - object_class->get_arg = gtk_toggle_button_get_arg; - - widget_class->size_allocate = gtk_toggle_button_size_allocate; - widget_class->draw = gtk_toggle_button_draw; - widget_class->expose_event = gtk_toggle_button_expose; - widget_class->realize = gtk_toggle_button_realize; - widget_class->unrealize = gtk_toggle_button_unrealize; - widget_class->map = gtk_toggle_button_map; - widget_class->unmap = gtk_toggle_button_unmap; + widget_class->mnemonic_activate = gtk_toggle_button_mnemonic_activate; button_class->pressed = gtk_toggle_button_pressed; button_class->released = gtk_toggle_button_released; button_class->clicked = gtk_toggle_button_clicked; - button_class->enter = gtk_toggle_button_enter; - button_class->leave = gtk_toggle_button_leave; + button_class->enter = gtk_toggle_button_update_state; + button_class->leave = gtk_toggle_button_update_state; class->toggled = NULL; + + g_object_class_install_property (gobject_class, + PROP_ACTIVE, + g_param_spec_boolean ("active", + P_("Active"), + P_("If the toggle button should be pressed in"), + FALSE, + GTK_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, + PROP_INCONSISTENT, + g_param_spec_boolean ("inconsistent", + P_("Inconsistent"), + P_("If the toggle button is in an \"in between\" state"), + FALSE, + GTK_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, + PROP_DRAW_INDICATOR, + g_param_spec_boolean ("draw-indicator", + P_("Draw Indicator"), + P_("If the toggle part of the button is displayed"), + FALSE, + GTK_PARAM_READWRITE)); + + /** + * 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. + */ + toggle_button_signals[TOGGLED] = + g_signal_new (I_("toggled"), + 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); + + g_type_class_add_private (class, sizeof (GtkToggleButtonPrivate)); + + gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_TOGGLE_BUTTON_ACCESSIBLE); } static void gtk_toggle_button_init (GtkToggleButton *toggle_button) { - toggle_button->active = FALSE; - toggle_button->draw_indicator = FALSE; - GTK_WIDGET_UNSET_FLAGS (toggle_button, GTK_NO_WINDOW); + 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; + GTK_BUTTON (toggle_button)->priv->depress_on_activate = TRUE; +} + +static void +gtk_toggle_button_activatable_interface_init (GtkActivatableIface *iface) +{ + parent_activatable_iface = g_type_interface_peek_parent (iface); + iface->update = gtk_toggle_button_update; + iface->sync_action_properties = gtk_toggle_button_sync_action_properties; +} + +static void +gtk_toggle_button_update (GtkActivatable *activatable, + GtkAction *action, + const gchar *property_name) +{ + 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 +gtk_toggle_button_sync_action_properties (GtkActivatable *activatable, + GtkAction *action) +{ + GtkToggleButton *button; + + parent_activatable_iface->sync_action_properties (activatable, action); + if (!GTK_IS_TOGGLE_ACTION (action)) + 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); +} + +/** + * 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. + */ GtkWidget* gtk_toggle_button_new (void) { - return GTK_WIDGET (gtk_type_new (gtk_toggle_button_get_type ())); + return g_object_new (GTK_TYPE_TOGGLE_BUTTON, NULL); } +/** + * 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. + */ GtkWidget* gtk_toggle_button_new_with_label (const gchar *label) { - GtkWidget *toggle_button; - GtkWidget *label_widget; - - toggle_button = gtk_toggle_button_new (); - label_widget = gtk_label_new (label); - gtk_misc_set_alignment (GTK_MISC (label_widget), 0.5, 0.5); - - gtk_container_add (GTK_CONTAINER (toggle_button), label_widget); - gtk_widget_show (label_widget); + return g_object_new (GTK_TYPE_TOGGLE_BUTTON, "label", label, NULL); +} - return toggle_button; +/** + * 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. + * + * Returns: a new #GtkToggleButton + */ +GtkWidget* +gtk_toggle_button_new_with_mnemonic (const gchar *label) +{ + return g_object_new (GTK_TYPE_TOGGLE_BUTTON, + "label", label, + "use-underline", TRUE, + NULL); } static void -gtk_toggle_button_set_arg (GtkObject *object, - GtkArg *arg, - guint arg_id) +gtk_toggle_button_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) { GtkToggleButton *tb; tb = GTK_TOGGLE_BUTTON (object); - switch (arg_id) + switch (prop_id) { - case ARG_ACTIVE: - gtk_toggle_button_set_active (tb, GTK_VALUE_BOOL (*arg)); + 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)); break; - case ARG_DRAW_INDICATOR: - gtk_toggle_button_set_mode (tb, GTK_VALUE_BOOL (*arg)); + case PROP_DRAW_INDICATOR: + gtk_toggle_button_set_mode (tb, g_value_get_boolean (value)); break; default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void -gtk_toggle_button_get_arg (GtkObject *object, - GtkArg *arg, - guint arg_id) +gtk_toggle_button_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) { - GtkToggleButton *tb; - - tb = GTK_TOGGLE_BUTTON (object); + GtkToggleButton *tb = GTK_TOGGLE_BUTTON (object); + GtkToggleButtonPrivate *priv = tb->priv; - switch (arg_id) + switch (prop_id) { - case ARG_ACTIVE: - GTK_VALUE_BOOL (*arg) = tb->active; + case PROP_ACTIVE: + g_value_set_boolean (value, priv->active); break; - case ARG_DRAW_INDICATOR: - GTK_VALUE_BOOL (*arg) = tb->draw_indicator; + case PROP_INCONSISTENT: + g_value_set_boolean (value, priv->inconsistent); + break; + case PROP_DRAW_INDICATOR: + g_value_set_boolean (value, priv->draw_indicator); break; default: - arg->type = GTK_TYPE_INVALID; + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } +/** + * 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 + * + * This function only affects instances of classes like #GtkCheckButton + * and #GtkRadioButton that derive from #GtkToggleButton, + * not instances of #GtkToggleButton itself. + */ void gtk_toggle_button_set_mode (GtkToggleButton *toggle_button, gboolean draw_indicator) { - GtkWidget *widget; + GtkToggleButtonPrivate *priv; - g_return_if_fail (toggle_button != NULL); g_return_if_fail (GTK_IS_TOGGLE_BUTTON (toggle_button)); - widget = GTK_WIDGET (toggle_button); + priv = toggle_button->priv; draw_indicator = draw_indicator ? TRUE : FALSE; - if (toggle_button->draw_indicator != draw_indicator) + if (priv->draw_indicator != draw_indicator) { - if (GTK_WIDGET_REALIZED (toggle_button)) - { - gboolean visible = GTK_WIDGET_VISIBLE (toggle_button); - - if (visible) - gtk_widget_hide (widget); - - gtk_widget_unrealize (widget); - toggle_button->draw_indicator = draw_indicator; - - if (toggle_button->draw_indicator) - GTK_WIDGET_SET_FLAGS (toggle_button, GTK_NO_WINDOW); - else - GTK_WIDGET_UNSET_FLAGS (toggle_button, GTK_NO_WINDOW); - - gtk_widget_realize (widget); - - if (visible) - gtk_widget_show (widget); - } - else - { - toggle_button->draw_indicator = draw_indicator; + GtkStyleContext *context; - if (toggle_button->draw_indicator) - GTK_WIDGET_SET_FLAGS (toggle_button, GTK_NO_WINDOW); - else - GTK_WIDGET_UNSET_FLAGS (toggle_button, GTK_NO_WINDOW); - } + priv->draw_indicator = draw_indicator; + GTK_BUTTON (toggle_button)->priv->depress_on_activate = !draw_indicator; - if (GTK_WIDGET_VISIBLE (toggle_button)) + if (gtk_widget_get_visible (GTK_WIDGET (toggle_button))) gtk_widget_queue_resize (GTK_WIDGET (toggle_button)); + + g_object_notify (G_OBJECT (toggle_button), "draw-indicator"); + + /* 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); } } +/** + * 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); + + return toggle_button->priv->draw_indicator; +} +/** + * 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 #GtkToggleButton::toggled signal and the + * #GtkButton::clicked signal to be emitted. + */ void gtk_toggle_button_set_active (GtkToggleButton *toggle_button, gboolean is_active) { - g_return_if_fail (toggle_button != NULL); + GtkToggleButtonPrivate *priv; + g_return_if_fail (GTK_IS_TOGGLE_BUTTON (toggle_button)); - is_active = is_active != 0; + priv = toggle_button->priv; + + is_active = is_active != FALSE; - if (toggle_button->active != is_active) + if (priv->active != is_active) gtk_button_clicked (GTK_BUTTON (toggle_button)); } +void +_gtk_toggle_button_set_active (GtkToggleButton *toggle_button, + gboolean is_active) +{ + toggle_button->priv->active = is_active; +} +/** + * 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. + */ gboolean gtk_toggle_button_get_active (GtkToggleButton *toggle_button) { - g_return_val_if_fail (toggle_button != NULL, FALSE); g_return_val_if_fail (GTK_IS_TOGGLE_BUTTON (toggle_button), FALSE); - return (toggle_button->active) ? TRUE : FALSE; + return toggle_button->priv->active; } - +/** + * 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. + */ void gtk_toggle_button_toggled (GtkToggleButton *toggle_button) { - g_return_if_fail (toggle_button != NULL); g_return_if_fail (GTK_IS_TOGGLE_BUTTON (toggle_button)); - gtk_signal_emit (GTK_OBJECT (toggle_button), toggle_button_signals[TOGGLED]); + g_signal_emit (toggle_button, toggle_button_signals[TOGGLED], 0); } - -static void -gtk_toggle_button_paint (GtkWidget *widget, - GdkRectangle *area) +/** + * 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) { - GtkButton *button; - GtkToggleButton *toggle_button; - GtkShadowType shadow_type; - gint width, height; - gint x, y; + GtkToggleButtonPrivate *priv; + + g_return_if_fail (GTK_IS_TOGGLE_BUTTON (toggle_button)); - button = GTK_BUTTON (widget); - toggle_button = GTK_TOGGLE_BUTTON (widget); + priv = toggle_button->priv; - if (GTK_WIDGET_DRAWABLE (widget)) + setting = setting != FALSE; + + if (setting != priv->inconsistent) { - x = 0; - y = 0; - width = widget->allocation.width - GTK_CONTAINER (widget)->border_width * 2; - height = widget->allocation.height - GTK_CONTAINER (widget)->border_width * 2; - - gdk_window_set_back_pixmap (widget->window, NULL, TRUE); - gdk_window_clear_area (widget->window, area->x, area->y, area->width, area->height); - - if (GTK_WIDGET_HAS_DEFAULT (widget) && - GTK_BUTTON (widget)->relief == GTK_RELIEF_NORMAL) - { - gtk_paint_box (widget->style, widget->window, - GTK_STATE_NORMAL, GTK_SHADOW_IN, - area, widget, "togglebuttondefault", - x, y, width, height); - } - - if (GTK_WIDGET_CAN_DEFAULT (widget)) - { - x += widget->style->xthickness; - y += widget->style->ythickness; - width -= 2 * x + DEFAULT_SPACING; - height -= 2 * y + DEFAULT_SPACING; - x += DEFAULT_LEFT_POS; - y += DEFAULT_TOP_POS; - } - - if (GTK_WIDGET_HAS_FOCUS (widget)) - { - x += 1; - y += 1; - width -= 2; - height -= 2; - } - - if ((GTK_WIDGET_STATE (widget) == GTK_STATE_ACTIVE) || - toggle_button->active) - shadow_type = GTK_SHADOW_IN; - else - shadow_type = GTK_SHADOW_OUT; - - if (button->relief != GTK_RELIEF_NONE || - (GTK_WIDGET_STATE(widget) != GTK_STATE_NORMAL && - GTK_WIDGET_STATE(widget) != GTK_STATE_INSENSITIVE)) - gtk_paint_box (widget->style, widget->window, - GTK_WIDGET_STATE (widget), - shadow_type, area, widget, "togglebutton", - x, y, width, height); - - if (GTK_WIDGET_HAS_FOCUS (widget)) - { - x -= 1; - y -= 1; - width += 2; - height += 2; - - gtk_paint_focus (widget->style, widget->window, - area, widget, "togglebutton", - x, y, width - 1, height - 1); - } + priv->inconsistent = setting; + + gtk_toggle_button_update_state (GTK_BUTTON (toggle_button)); + gtk_widget_queue_draw (GTK_WIDGET (toggle_button)); + + g_object_notify (G_OBJECT (toggle_button), "inconsistent"); } } -static void -gtk_toggle_button_size_allocate (GtkWidget *widget, - GtkAllocation *allocation) +/** + * 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) { - if (!GTK_WIDGET_NO_WINDOW (widget) && - GTK_WIDGET_CLASS (parent_class)->size_allocate) - GTK_WIDGET_CLASS (parent_class)->size_allocate (widget, allocation); -} + g_return_val_if_fail (GTK_IS_TOGGLE_BUTTON (toggle_button), FALSE); -static gint -gtk_toggle_button_expose (GtkWidget *widget, - GdkEventExpose *event) -{ - if (!GTK_WIDGET_NO_WINDOW (widget) && - GTK_WIDGET_CLASS (parent_class)->expose_event) - return GTK_WIDGET_CLASS (parent_class)->expose_event (widget, event); - else - return FALSE; + return toggle_button->priv->inconsistent; } -static void -gtk_toggle_button_draw (GtkWidget *widget, - GdkRectangle *area) +static gboolean +gtk_toggle_button_mnemonic_activate (GtkWidget *widget, + gboolean group_cycling) { - GdkRectangle child_area; - GdkRectangle tmp_area; - GtkBin *bin; - - g_return_if_fail (widget != NULL); - g_return_if_fail (GTK_IS_TOGGLE_BUTTON (widget)); - g_return_if_fail (area != NULL); - - bin = GTK_BIN (widget); - - if (GTK_WIDGET_DRAWABLE (widget) && !GTK_WIDGET_NO_WINDOW (widget)) - { - tmp_area = *area; - tmp_area.x -= GTK_CONTAINER (widget)->border_width; - tmp_area.y -= GTK_CONTAINER (widget)->border_width; - - gtk_toggle_button_paint (widget, &tmp_area); - - if (bin->child && gtk_widget_intersect (bin->child, &tmp_area, &child_area)) - gtk_widget_draw (bin->child, &child_area); - } + /* + * We override the standard implementation in + * gtk_widget_real_mnemonic_activate() in order to focus the widget even + * if there is no mnemonic conflict. + */ + if (gtk_widget_get_can_focus (widget)) + gtk_widget_grab_focus (widget); + + if (!group_cycling) + gtk_widget_activate (widget); + + return TRUE; } static void gtk_toggle_button_pressed (GtkButton *button) { - GtkToggleButton *toggle_button; - GtkStateType new_state; - - g_return_if_fail (button != NULL); - g_return_if_fail (GTK_IS_TOGGLE_BUTTON (button)); - - toggle_button = GTK_TOGGLE_BUTTON (button); - - button->button_down = TRUE; - - if (toggle_button->active) - new_state = (button->in_button ? GTK_STATE_NORMAL : GTK_STATE_ACTIVE); - else - new_state = (button->in_button ? GTK_STATE_ACTIVE : GTK_STATE_NORMAL); + button->priv->button_down = TRUE; - if (GTK_WIDGET_STATE (button) != new_state) - gtk_widget_set_state (GTK_WIDGET (button), new_state); + gtk_toggle_button_update_state (button); + gtk_widget_queue_draw (GTK_WIDGET (button)); } static void gtk_toggle_button_released (GtkButton *button) { - GtkToggleButton *toggle_button; - GtkStateType new_state; - - g_return_if_fail (button != NULL); - g_return_if_fail (GTK_IS_TOGGLE_BUTTON (button)); - - if (button->button_down) + if (button->priv->button_down) { - toggle_button = GTK_TOGGLE_BUTTON (button); + button->priv->button_down = FALSE; - button->button_down = FALSE; + if (button->priv->in_button) + gtk_button_clicked (button); - if (button->in_button) - { - gtk_button_clicked (button); - } - else - { - if (toggle_button->active) - new_state = (button->in_button ? GTK_STATE_PRELIGHT : GTK_STATE_ACTIVE); - else - new_state = (button->in_button ? GTK_STATE_PRELIGHT : GTK_STATE_NORMAL); - - if (GTK_WIDGET_STATE (button) != new_state) - gtk_widget_set_state (GTK_WIDGET (button), new_state); - } + gtk_toggle_button_update_state (button); + gtk_widget_queue_draw (GTK_WIDGET (button)); } } static void gtk_toggle_button_clicked (GtkButton *button) { - GtkToggleButton *toggle_button; - GtkStateType new_state; + GtkToggleButton *toggle_button = GTK_TOGGLE_BUTTON (button); + GtkToggleButtonPrivate *priv = toggle_button->priv; - g_return_if_fail (button != NULL); - g_return_if_fail (GTK_IS_TOGGLE_BUTTON (button)); - - toggle_button = GTK_TOGGLE_BUTTON (button); - toggle_button->active = !toggle_button->active; + priv->active = !priv->active; gtk_toggle_button_toggled (toggle_button); - if (toggle_button->active) - new_state = (button->in_button ? GTK_STATE_PRELIGHT : GTK_STATE_ACTIVE); - else - new_state = (button->in_button ? GTK_STATE_PRELIGHT : GTK_STATE_NORMAL); - - if (GTK_WIDGET_STATE (button) != new_state) - gtk_widget_set_state (GTK_WIDGET (button), new_state); - else - gtk_widget_queue_draw (GTK_WIDGET (button)); -} - -static void -gtk_toggle_button_enter (GtkButton *button) -{ - GtkToggleButton *toggle_button; - GtkStateType new_state; - - g_return_if_fail (button != NULL); - g_return_if_fail (GTK_IS_TOGGLE_BUTTON (button)); - - toggle_button = GTK_TOGGLE_BUTTON (button); - - if (toggle_button->active) - new_state = (button->button_down ? GTK_STATE_NORMAL : GTK_STATE_PRELIGHT); - else - new_state = (button->button_down ? GTK_STATE_ACTIVE : GTK_STATE_PRELIGHT); - - if (GTK_WIDGET_STATE (button) != new_state) - gtk_widget_set_state (GTK_WIDGET (button), new_state); -} - -static void -gtk_toggle_button_leave (GtkButton *button) -{ - GtkToggleButton *toggle_button; - GtkStateType new_state; - - g_return_if_fail (button != NULL); - g_return_if_fail (GTK_IS_TOGGLE_BUTTON (button)); - - toggle_button = GTK_TOGGLE_BUTTON (button); + gtk_toggle_button_update_state (button); - new_state = (toggle_button->active ? GTK_STATE_ACTIVE : GTK_STATE_NORMAL); + g_object_notify (G_OBJECT (toggle_button), "active"); - if (GTK_WIDGET_STATE (button) != new_state) - gtk_widget_set_state (GTK_WIDGET (button), new_state); + if (GTK_BUTTON_CLASS (gtk_toggle_button_parent_class)->clicked) + GTK_BUTTON_CLASS (gtk_toggle_button_parent_class)->clicked (button); } static void -gtk_toggle_button_realize (GtkWidget *widget) +gtk_toggle_button_update_state (GtkButton *button) { - GtkToggleButton *toggle_button; - GdkWindowAttr attributes; - gint attributes_mask; - gint border_width; - - g_return_if_fail (widget != NULL); - g_return_if_fail (GTK_IS_TOGGLE_BUTTON (widget)); - - toggle_button = GTK_TOGGLE_BUTTON (widget); - GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); - - border_width = GTK_CONTAINER (widget)->border_width; - - attributes.window_type = GDK_WINDOW_CHILD; - attributes.x = widget->allocation.x + border_width; - attributes.y = widget->allocation.y + border_width; - attributes.width = widget->allocation.width - border_width * 2; - attributes.height = widget->allocation.height - border_width * 2; - attributes.event_mask = gtk_widget_get_events (widget); - attributes.event_mask |= (GDK_EXPOSURE_MASK | - GDK_BUTTON_PRESS_MASK | - GDK_BUTTON_RELEASE_MASK | - GDK_ENTER_NOTIFY_MASK | - GDK_LEAVE_NOTIFY_MASK); - - if (GTK_WIDGET_NO_WINDOW (widget)) - { - attributes.wclass = GDK_INPUT_ONLY; - attributes_mask = GDK_WA_X | GDK_WA_Y; - - widget->window = gtk_widget_get_parent_window (widget); - gdk_window_ref (widget->window); - - toggle_button->event_window = gdk_window_new (gtk_widget_get_parent_window (widget), - &attributes, attributes_mask); - gdk_window_set_user_data (toggle_button->event_window, toggle_button); - } + GtkToggleButton *toggle_button = GTK_TOGGLE_BUTTON (button); + GtkToggleButtonPrivate *priv = toggle_button->priv; + gboolean depressed; + GtkStateFlags new_state = 0; + + new_state = gtk_widget_get_state_flags (GTK_WIDGET (button)) & + ~(GTK_STATE_FLAG_INCONSISTENT | + GTK_STATE_FLAG_PRELIGHT | + GTK_STATE_FLAG_ACTIVE); + + if (priv->inconsistent) + new_state |= GTK_STATE_FLAG_INCONSISTENT; + + if (priv->inconsistent) + depressed = FALSE; + else if (button->priv->in_button && button->priv->button_down) + depressed = TRUE; else - { - attributes.wclass = GDK_INPUT_OUTPUT; - attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; - attributes.visual = gtk_widget_get_visual (widget); - attributes.colormap = gtk_widget_get_colormap (widget); - widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), - &attributes, attributes_mask); - gdk_window_set_user_data (widget->window, toggle_button); - } - - widget->style = gtk_style_attach (widget->style, widget->window); - - if (!GTK_WIDGET_NO_WINDOW (widget)) - gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL); -} - -static void -gtk_toggle_button_unrealize (GtkWidget *widget) -{ - GtkToggleButton *toggle_button; - - g_return_if_fail (widget != NULL); - g_return_if_fail (GTK_IS_TOGGLE_BUTTON (widget)); - - toggle_button = GTK_TOGGLE_BUTTON (widget); - - if (GTK_WIDGET_NO_WINDOW (widget)) - { - gdk_window_set_user_data (toggle_button->event_window, NULL); - gdk_window_destroy (toggle_button->event_window); - toggle_button->event_window = NULL; - } + depressed = priv->active; - if (GTK_WIDGET_CLASS (parent_class)->unrealize) - (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget); -} - -static void -gtk_toggle_button_map (GtkWidget *widget) -{ - g_return_if_fail (widget != NULL); - g_return_if_fail (GTK_IS_TOGGLE_BUTTON (widget)); - - if (GTK_WIDGET_NO_WINDOW (widget)) - gdk_window_show (GTK_TOGGLE_BUTTON (widget)->event_window); - - GTK_WIDGET_CLASS (parent_class)->map (widget); -} - -static void -gtk_toggle_button_unmap (GtkWidget *widget) -{ - g_return_if_fail (widget != NULL); - g_return_if_fail (GTK_IS_TOGGLE_BUTTON (widget)); + if (button->priv->in_button) + new_state |= GTK_STATE_FLAG_PRELIGHT; - if (GTK_WIDGET_NO_WINDOW (widget)) - gdk_window_hide (GTK_TOGGLE_BUTTON (widget)->event_window); + if (depressed) + new_state |= GTK_STATE_FLAG_ACTIVE; - GTK_WIDGET_CLASS (parent_class)->unmap (widget); + _gtk_button_set_depressed (button, depressed); + gtk_widget_set_state_flags (GTK_WIDGET (toggle_button), new_state, TRUE); }