1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2 /*
3 * st-button.c: Plain button actor
4 *
5 * Copyright 2007 OpenedHand
6 * Copyright 2008, 2009 Intel Corporation.
7 * Copyright 2009, 2010 Red Hat, Inc.
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms and conditions of the GNU Lesser General Public License,
11 * version 2.1, as published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope it will be useful, but WITHOUT ANY
14 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
16 * more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 /**
23 * SECTION:st-button
24 * @short_description: Button widget
25 *
26 * A button widget with support for either a text label or icon, toggle mode
27 * and transitions effects between states.
28 */
29
30 #ifdef HAVE_CONFIG_H
31 #include "config.h"
32 #endif
33
34 #include <stdlib.h>
35 #include <string.h>
36
37 #include <glib.h>
38
39 #include <clutter/clutter.h>
40
41 #include "st-button.h"
42
43 #include "st-enum-types.h"
44 #include "st-texture-cache.h"
45 #include "st-private.h"
46
47 #include "st-widget-accessible.h"
48
49 enum
50 {
51 PROP_0,
52
53 PROP_LABEL,
54 PROP_BUTTON_MASK,
55 PROP_TOGGLE_MODE,
56 PROP_CHECKED,
57 PROP_PRESSED
58 };
59
60 enum
61 {
62 CLICKED,
63
64 LAST_SIGNAL
65 };
66
67 struct _StButtonPrivate
68 {
69 gchar *text;
70
71 guint button_mask : 3;
72 guint is_toggle : 1;
73
74 guint pressed : 3;
75 guint grabbed : 3;
76 guint is_checked : 1;
77
78 gint spacing;
79 };
80
81 static guint button_signals[LAST_SIGNAL] = { 0, };
82
83 G_DEFINE_TYPE_WITH_PRIVATE (StButton, st_button, ST_TYPE_BIN);
84
85 static GType st_button_accessible_get_type (void) G_GNUC_CONST;
86
87 static void
st_button_update_label_style(StButton * button)88 st_button_update_label_style (StButton *button)
89 {
90 ClutterActor *label;
91
92 label = st_bin_get_child (ST_BIN (button));
93
94 /* check the child is really a label */
95 if (!CLUTTER_IS_TEXT (label))
96 return;
97
98 _st_set_text_from_style (CLUTTER_TEXT (label), st_widget_get_theme_node (ST_WIDGET (button)));
99 }
100
101 static void
st_button_style_changed(StWidget * widget)102 st_button_style_changed (StWidget *widget)
103 {
104 StButton *button = ST_BUTTON (widget);
105 StButtonPrivate *priv = button->priv;
106 StButtonClass *button_class = ST_BUTTON_GET_CLASS (button);
107 StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (button));
108 double spacing;
109
110 ST_WIDGET_CLASS (st_button_parent_class)->style_changed (widget);
111
112 spacing = 6;
113 st_theme_node_lookup_length (theme_node, "border-spacing", FALSE, &spacing);
114 priv->spacing = (int)(0.5 + spacing);
115
116 /* update the label styling */
117 st_button_update_label_style (button);
118
119 /* run a transition if applicable */
120 if (button_class->transition)
121 {
122 button_class->transition (button);
123 }
124 }
125
126 static void
st_button_press(StButton * button,StButtonMask mask)127 st_button_press (StButton *button,
128 StButtonMask mask)
129 {
130 if (button->priv->pressed == 0)
131 st_widget_add_style_pseudo_class (ST_WIDGET (button), "active");
132
133 button->priv->pressed |= mask;
134 }
135
136 static void
st_button_release(StButton * button,StButtonMask mask,int clicked_button)137 st_button_release (StButton *button,
138 StButtonMask mask,
139 int clicked_button)
140 {
141 button->priv->pressed &= ~mask;
142 if (button->priv->pressed != 0)
143 return;
144
145 st_widget_remove_style_pseudo_class (ST_WIDGET (button), "active");
146
147 if (clicked_button)
148 {
149 if (button->priv->is_toggle)
150 st_button_set_checked (button, !button->priv->is_checked);
151
152 g_signal_emit (button, button_signals[CLICKED], 0, clicked_button);
153 }
154 }
155
156 static gboolean
st_button_button_press(ClutterActor * actor,ClutterButtonEvent * event)157 st_button_button_press (ClutterActor *actor,
158 ClutterButtonEvent *event)
159 {
160 StButton *button = ST_BUTTON (actor);
161 StButtonMask mask = ST_BUTTON_MASK_FROM_BUTTON (event->button);
162
163 if (button->priv->button_mask & mask)
164 {
165 if (button->priv->grabbed == 0)
166 clutter_grab_pointer (actor);
167
168 button->priv->grabbed |= mask;
169 st_button_press (button, mask);
170
171 return TRUE;
172 }
173
174 return FALSE;
175 }
176
177 static gboolean
st_button_button_release(ClutterActor * actor,ClutterButtonEvent * event)178 st_button_button_release (ClutterActor *actor,
179 ClutterButtonEvent *event)
180 {
181 StButton *button = ST_BUTTON (actor);
182 StButtonMask mask = ST_BUTTON_MASK_FROM_BUTTON (event->button);
183
184 if (button->priv->button_mask & mask)
185 {
186 gboolean is_click;
187
188 is_click = button->priv->grabbed && st_widget_get_hover (ST_WIDGET (button));
189 st_button_release (button, mask, is_click ? event->button : 0);
190
191 button->priv->grabbed &= ~mask;
192 if (button->priv->grabbed == 0)
193 clutter_ungrab_pointer ();
194
195 return TRUE;
196 }
197
198 return FALSE;
199 }
200
201 static gboolean
st_button_key_press(ClutterActor * actor,ClutterKeyEvent * event)202 st_button_key_press (ClutterActor *actor,
203 ClutterKeyEvent *event)
204 {
205 StButton *button = ST_BUTTON (actor);
206
207 if (button->priv->button_mask & ST_BUTTON_ONE)
208 {
209 if (event->keyval == CLUTTER_KEY_space ||
210 event->keyval == CLUTTER_KEY_Return ||
211 event->keyval == CLUTTER_KEY_KP_Enter)
212 {
213 st_button_press (button, ST_BUTTON_ONE);
214 return TRUE;
215 }
216 }
217
218 return CLUTTER_ACTOR_CLASS (st_button_parent_class)->key_press_event (actor, event);
219 }
220
221 static gboolean
st_button_key_release(ClutterActor * actor,ClutterKeyEvent * event)222 st_button_key_release (ClutterActor *actor,
223 ClutterKeyEvent *event)
224 {
225 StButton *button = ST_BUTTON (actor);
226
227 if (button->priv->button_mask & ST_BUTTON_ONE)
228 {
229 if (event->keyval == CLUTTER_KEY_space ||
230 event->keyval == CLUTTER_KEY_Return ||
231 event->keyval == CLUTTER_KEY_KP_Enter)
232 {
233 gboolean is_click;
234
235 is_click = (button->priv->pressed & ST_BUTTON_ONE);
236 st_button_release (button, ST_BUTTON_ONE, is_click ? 1 : 0);
237 return TRUE;
238 }
239 }
240
241 return FALSE;
242 }
243
244 static void
st_button_key_focus_out(ClutterActor * actor)245 st_button_key_focus_out (ClutterActor *actor)
246 {
247 StButton *button = ST_BUTTON (actor);
248
249 /* If we lose focus between a key press and release, undo the press */
250 if ((button->priv->pressed & ST_BUTTON_ONE) &&
251 !(button->priv->grabbed & ST_BUTTON_ONE))
252 st_button_release (button, ST_BUTTON_ONE, 0);
253
254 CLUTTER_ACTOR_CLASS (st_button_parent_class)->key_focus_out (actor);
255 }
256
257 static gboolean
st_button_enter(ClutterActor * actor,ClutterCrossingEvent * event)258 st_button_enter (ClutterActor *actor,
259 ClutterCrossingEvent *event)
260 {
261 StButton *button = ST_BUTTON (actor);
262 gboolean ret;
263
264 ret = CLUTTER_ACTOR_CLASS (st_button_parent_class)->enter_event (actor, event);
265
266 if (button->priv->grabbed)
267 {
268 if (st_widget_get_hover (ST_WIDGET (button)))
269 st_button_press (button, button->priv->grabbed);
270 else
271 st_button_release (button, button->priv->grabbed, 0);
272 }
273
274 return ret;
275 }
276
277 static gboolean
st_button_leave(ClutterActor * actor,ClutterCrossingEvent * event)278 st_button_leave (ClutterActor *actor,
279 ClutterCrossingEvent *event)
280 {
281 StButton *button = ST_BUTTON (actor);
282 gboolean ret;
283
284 ret = CLUTTER_ACTOR_CLASS (st_button_parent_class)->leave_event (actor, event);
285
286 if (button->priv->grabbed)
287 {
288 if (st_widget_get_hover (ST_WIDGET (button)))
289 st_button_press (button, button->priv->grabbed);
290 else
291 st_button_release (button, button->priv->grabbed, 0);
292 }
293
294 return ret;
295 }
296
297 static void
st_button_set_property(GObject * gobject,guint prop_id,const GValue * value,GParamSpec * pspec)298 st_button_set_property (GObject *gobject,
299 guint prop_id,
300 const GValue *value,
301 GParamSpec *pspec)
302 {
303 StButton *button = ST_BUTTON (gobject);
304
305 switch (prop_id)
306 {
307 case PROP_LABEL:
308 st_button_set_label (button, g_value_get_string (value));
309 break;
310 case PROP_BUTTON_MASK:
311 st_button_set_button_mask (button, g_value_get_flags (value));
312 break;
313 case PROP_TOGGLE_MODE:
314 st_button_set_toggle_mode (button, g_value_get_boolean (value));
315 break;
316 case PROP_CHECKED:
317 st_button_set_checked (button, g_value_get_boolean (value));
318 break;
319
320
321 default:
322 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
323 break;
324 }
325 }
326
327 static void
st_button_get_property(GObject * gobject,guint prop_id,GValue * value,GParamSpec * pspec)328 st_button_get_property (GObject *gobject,
329 guint prop_id,
330 GValue *value,
331 GParamSpec *pspec)
332 {
333 StButtonPrivate *priv = ST_BUTTON (gobject)->priv;
334
335 switch (prop_id)
336 {
337 case PROP_LABEL:
338 g_value_set_string (value, priv->text);
339 break;
340 case PROP_BUTTON_MASK:
341 g_value_set_flags (value, priv->button_mask);
342 break;
343 case PROP_TOGGLE_MODE:
344 g_value_set_boolean (value, priv->is_toggle);
345 break;
346 case PROP_CHECKED:
347 g_value_set_boolean (value, priv->is_checked);
348 break;
349 case PROP_PRESSED:
350 g_value_set_boolean (value, priv->pressed != 0);
351 break;
352
353
354 default:
355 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
356 break;
357 }
358 }
359
360 static void
st_button_finalize(GObject * gobject)361 st_button_finalize (GObject *gobject)
362 {
363 StButtonPrivate *priv = ST_BUTTON (gobject)->priv;
364
365 g_free (priv->text);
366
367 G_OBJECT_CLASS (st_button_parent_class)->finalize (gobject);
368 }
369
370 static void
st_button_class_init(StButtonClass * klass)371 st_button_class_init (StButtonClass *klass)
372 {
373 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
374 ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
375 StWidgetClass *widget_class = ST_WIDGET_CLASS (klass);
376 GParamSpec *pspec;
377
378 gobject_class->set_property = st_button_set_property;
379 gobject_class->get_property = st_button_get_property;
380 gobject_class->finalize = st_button_finalize;
381
382 actor_class->button_press_event = st_button_button_press;
383 actor_class->button_release_event = st_button_button_release;
384 actor_class->key_press_event = st_button_key_press;
385 actor_class->key_release_event = st_button_key_release;
386 actor_class->key_focus_out = st_button_key_focus_out;
387 actor_class->enter_event = st_button_enter;
388 actor_class->leave_event = st_button_leave;
389
390 widget_class->style_changed = st_button_style_changed;
391 widget_class->get_accessible_type = st_button_accessible_get_type;
392
393 pspec = g_param_spec_string ("label",
394 "Label",
395 "Label of the button",
396 NULL, G_PARAM_READWRITE);
397 g_object_class_install_property (gobject_class, PROP_LABEL, pspec);
398
399 pspec = g_param_spec_flags ("button-mask",
400 "Button mask",
401 "Which buttons trigger the 'clicked' signal",
402 ST_TYPE_BUTTON_MASK, ST_BUTTON_ONE,
403 G_PARAM_READWRITE);
404 g_object_class_install_property (gobject_class, PROP_BUTTON_MASK, pspec);
405
406 pspec = g_param_spec_boolean ("toggle-mode",
407 "Toggle Mode",
408 "Enable or disable toggling",
409 FALSE, G_PARAM_READWRITE);
410 g_object_class_install_property (gobject_class, PROP_TOGGLE_MODE, pspec);
411
412 pspec = g_param_spec_boolean ("checked",
413 "Checked",
414 "Indicates if a toggle button is \"on\""
415 " or \"off\"",
416 FALSE, G_PARAM_READWRITE);
417 g_object_class_install_property (gobject_class, PROP_CHECKED, pspec);
418
419 pspec = g_param_spec_boolean ("pressed",
420 "Pressed",
421 "Indicates if the button is pressed in",
422 FALSE, G_PARAM_READABLE);
423 g_object_class_install_property (gobject_class, PROP_PRESSED, pspec);
424
425
426 /**
427 * StButton::clicked:
428 * @button: the object that received the signal
429 * @clicked_button: the mouse button that was used
430 *
431 * Emitted when the user activates the button, either with a mouse press and
432 * release or with the keyboard.
433 */
434 button_signals[CLICKED] =
435 g_signal_new ("clicked",
436 G_TYPE_FROM_CLASS (klass),
437 G_SIGNAL_RUN_LAST,
438 G_STRUCT_OFFSET (StButtonClass, clicked),
439 NULL, NULL, NULL,
440 G_TYPE_NONE, 1,
441 G_TYPE_INT);
442 }
443
444 static void
st_button_init(StButton * button)445 st_button_init (StButton *button)
446 {
447 button->priv = st_button_get_instance_private (button);
448 button->priv->spacing = 6;
449 button->priv->button_mask = ST_BUTTON_ONE;
450
451 clutter_actor_set_reactive (CLUTTER_ACTOR (button), TRUE);
452 st_widget_set_track_hover (ST_WIDGET (button), TRUE);
453 }
454
455 /**
456 * st_button_new:
457 *
458 * Create a new button
459 *
460 * Returns: a new #StButton
461 */
462 StWidget *
st_button_new(void)463 st_button_new (void)
464 {
465 return g_object_new (ST_TYPE_BUTTON, NULL);
466 }
467
468 /**
469 * st_button_new_with_label:
470 * @text: text to set the label to
471 *
472 * Create a new #StButton with the specified label
473 *
474 * Returns: a new #StButton
475 */
476 StWidget *
st_button_new_with_label(const gchar * text)477 st_button_new_with_label (const gchar *text)
478 {
479 return g_object_new (ST_TYPE_BUTTON, "label", text, NULL);
480 }
481
482 /**
483 * st_button_get_label:
484 * @button: a #StButton
485 *
486 * Get the text displayed on the button
487 *
488 * Returns: the text for the button. This must not be freed by the application
489 */
490 const gchar *
st_button_get_label(StButton * button)491 st_button_get_label (StButton *button)
492 {
493 g_return_val_if_fail (ST_IS_BUTTON (button), NULL);
494
495 return button->priv->text;
496 }
497
498 /**
499 * st_button_set_label:
500 * @button: a #Stbutton
501 * @text: text to set the label to
502 *
503 * Sets the text displayed on the button
504 */
505 void
st_button_set_label(StButton * button,const gchar * text)506 st_button_set_label (StButton *button,
507 const gchar *text)
508 {
509 StButtonPrivate *priv;
510 ClutterActor *label;
511
512 g_return_if_fail (ST_IS_BUTTON (button));
513
514 priv = button->priv;
515
516 g_free (priv->text);
517
518 if (text)
519 priv->text = g_strdup (text);
520 else
521 priv->text = g_strdup ("");
522
523 label = st_bin_get_child (ST_BIN (button));
524
525 if (label && CLUTTER_IS_TEXT (label))
526 {
527 clutter_text_set_text (CLUTTER_TEXT (label), priv->text);
528 }
529 else
530 {
531 label = g_object_new (CLUTTER_TYPE_TEXT,
532 "text", priv->text,
533 "line-alignment", PANGO_ALIGN_CENTER,
534 "ellipsize", PANGO_ELLIPSIZE_END,
535 "use-markup", TRUE,
536 NULL);
537 st_bin_set_child (ST_BIN (button), label);
538 }
539
540 /* Fake a style change so that we reset the style properties on the label */
541 st_widget_style_changed (ST_WIDGET (button));
542
543 g_object_notify (G_OBJECT (button), "label");
544 }
545
546 /**
547 * st_button_get_button_mask:
548 * @button: a #StButton
549 *
550 * Gets the mask of mouse buttons that @button emits the
551 * #StButton::clicked signal for.
552 *
553 * Returns: the mask of mouse buttons that @button emits the
554 * #StButton::clicked signal for.
555 */
556 StButtonMask
st_button_get_button_mask(StButton * button)557 st_button_get_button_mask (StButton *button)
558 {
559 g_return_val_if_fail (ST_IS_BUTTON (button), 0);
560
561 return button->priv->button_mask;
562 }
563
564 /**
565 * st_button_set_button_mask:
566 * @button: a #Stbutton
567 * @mask: the mask of mouse buttons that @button responds to
568 *
569 * Sets which mouse buttons @button emits #StButton::clicked for.
570 */
571 void
st_button_set_button_mask(StButton * button,StButtonMask mask)572 st_button_set_button_mask (StButton *button,
573 StButtonMask mask)
574 {
575 g_return_if_fail (ST_IS_BUTTON (button));
576
577 button->priv->button_mask = mask;
578
579 g_object_notify (G_OBJECT (button), "button-mask");
580 }
581
582 /**
583 * st_button_get_toggle_mode:
584 * @button: a #StButton
585 *
586 * Get the toggle mode status of the button.
587 *
588 * Returns: %TRUE if toggle mode is set, otherwise %FALSE
589 */
590 gboolean
st_button_get_toggle_mode(StButton * button)591 st_button_get_toggle_mode (StButton *button)
592 {
593 g_return_val_if_fail (ST_IS_BUTTON (button), FALSE);
594
595 return button->priv->is_toggle;
596 }
597
598 /**
599 * st_button_set_toggle_mode:
600 * @button: a #Stbutton
601 * @toggle: %TRUE or %FALSE
602 *
603 * Enables or disables toggle mode for the button. In toggle mode, the active
604 * state will be "toggled" when the user clicks the button.
605 */
606 void
st_button_set_toggle_mode(StButton * button,gboolean toggle)607 st_button_set_toggle_mode (StButton *button,
608 gboolean toggle)
609 {
610 g_return_if_fail (ST_IS_BUTTON (button));
611
612 button->priv->is_toggle = toggle;
613
614 g_object_notify (G_OBJECT (button), "toggle-mode");
615 }
616
617 /**
618 * st_button_get_checked:
619 * @button: a #StButton
620 *
621 * Get the state of the button that is in toggle mode.
622 *
623 * Returns: %TRUE if the button is checked, or %FALSE if not
624 */
625 gboolean
st_button_get_checked(StButton * button)626 st_button_get_checked (StButton *button)
627 {
628 g_return_val_if_fail (ST_IS_BUTTON (button), FALSE);
629
630 return button->priv->is_checked;
631 }
632
633 /**
634 * st_button_set_checked:
635 * @button: a #Stbutton
636 * @checked: %TRUE or %FALSE
637 *
638 * Sets the pressed state of the button. This is only really useful if the
639 * button has #toggle-mode mode set to %TRUE.
640 */
641 void
st_button_set_checked(StButton * button,gboolean checked)642 st_button_set_checked (StButton *button,
643 gboolean checked)
644 {
645 g_return_if_fail (ST_IS_BUTTON (button));
646
647 if (button->priv->is_checked != checked)
648 {
649 button->priv->is_checked = checked;
650
651 st_widget_change_style_pseudo_class (ST_WIDGET (button), "checked", checked);
652 }
653
654 g_object_notify (G_OBJECT (button), "checked");
655 }
656
657 /**
658 * st_button_fake_release:
659 * @button: an #StButton
660 *
661 * If this widget is holding a pointer grab, this function will
662 * will ungrab it, and reset the pressed state. The effect is
663 * similar to if the user had released the mouse button, but without
664 * emitting the clicked signal.
665 *
666 * This function is useful if for example you want to do something
667 * after the user is holding the mouse button for a given period of
668 * time, breaking the grab.
669 */
670 void
st_button_fake_release(StButton * button)671 st_button_fake_release (StButton *button)
672 {
673 if (button->priv->pressed)
674 st_button_release (button, button->priv->pressed, 0);
675
676 if (button->priv->grabbed)
677 {
678 button->priv->grabbed = 0;
679 clutter_ungrab_pointer ();
680 }
681 }
682
683 /******************************************************************************/
684 /*************************** ACCESSIBILITY SUPPORT ****************************/
685 /******************************************************************************/
686
687 #define ST_TYPE_BUTTON_ACCESSIBLE st_button_accessible_get_type ()
688
689 #define ST_BUTTON_ACCESSIBLE(obj) \
690 (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
691 ST_TYPE_BUTTON_ACCESSIBLE, StButtonAccessible))
692
693 #define ST_IS_BUTTON_ACCESSIBLE(obj) \
694 (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
695 ST_TYPE_BUTTON_ACCESSIBLE))
696
697 #define ST_BUTTON_ACCESSIBLE_CLASS(klass) \
698 (G_TYPE_CHECK_CLASS_CAST ((klass), \
699 ST_TYPE_BUTTON_ACCESSIBLE, StButtonAccessibleClass))
700
701 #define ST_IS_BUTTON_ACCESSIBLE_CLASS(klass) \
702 (G_TYPE_CHECK_CLASS_TYPE ((klass), \
703 ST_TYPE_BUTTON_ACCESSIBLE))
704
705 #define ST_BUTTON_ACCESSIBLE_GET_CLASS(obj) \
706 (G_TYPE_INSTANCE_GET_CLASS ((obj), \
707 ST_TYPE_BUTTON_ACCESSIBLE, StButtonAccessibleClass))
708
709 typedef struct _StButtonAccessible StButtonAccessible;
710 typedef struct _StButtonAccessibleClass StButtonAccessibleClass;
711
712 struct _StButtonAccessible
713 {
714 StWidgetAccessible parent;
715 };
716
717 struct _StButtonAccessibleClass
718 {
719 StWidgetAccessibleClass parent_class;
720 };
721
722 /* AtkObject */
723 static void st_button_accessible_initialize (AtkObject *obj,
724 gpointer data);
725
G_DEFINE_TYPE(StButtonAccessible,st_button_accessible,ST_TYPE_WIDGET_ACCESSIBLE)726 G_DEFINE_TYPE (StButtonAccessible, st_button_accessible, ST_TYPE_WIDGET_ACCESSIBLE)
727
728 static const gchar *
729 st_button_accessible_get_name (AtkObject *obj)
730 {
731 StButton *button = NULL;
732 const gchar *name = NULL;
733
734 button = ST_BUTTON (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (obj)));
735
736 if (button == NULL)
737 return NULL;
738
739 name = ATK_OBJECT_CLASS (st_button_accessible_parent_class)->get_name (obj);
740 if (name != NULL)
741 return name;
742
743 return button->priv->text;
744 }
745
746 static void
st_button_accessible_class_init(StButtonAccessibleClass * klass)747 st_button_accessible_class_init (StButtonAccessibleClass *klass)
748 {
749 AtkObjectClass *atk_class = ATK_OBJECT_CLASS (klass);
750
751 atk_class->initialize = st_button_accessible_initialize;
752 atk_class->get_name = st_button_accessible_get_name;
753 }
754
755 static void
st_button_accessible_init(StButtonAccessible * self)756 st_button_accessible_init (StButtonAccessible *self)
757 {
758 /* initialization done on AtkObject->initialize */
759 }
760
761 static void
st_button_accessible_notify_label_cb(StButton * button,GParamSpec * psec,AtkObject * accessible)762 st_button_accessible_notify_label_cb (StButton *button,
763 GParamSpec *psec,
764 AtkObject *accessible)
765 {
766 g_object_notify (G_OBJECT (accessible), "accessible-name");
767 }
768
769 static void
st_button_accessible_initialize(AtkObject * obj,gpointer data)770 st_button_accessible_initialize (AtkObject *obj,
771 gpointer data)
772 {
773 ATK_OBJECT_CLASS (st_button_accessible_parent_class)->initialize (obj, data);
774
775 obj->role = ATK_ROLE_PUSH_BUTTON;
776
777 g_signal_connect (data, "notify::label",
778 G_CALLBACK (st_button_accessible_notify_label_cb), obj);
779 }
780