comparison pidgin/gtkexpander.c @ 15374:5fe8042783c1

Rename gtk/ and libgaim/ to pidgin/ and libpurple/
author Sean Egan <seanegan@gmail.com>
date Sat, 20 Jan 2007 02:32:10 +0000
parents
children 44b4e8bd759b
comparison
equal deleted inserted replaced
15373:f79e0f4df793 15374:5fe8042783c1
1 /* GTK - The GIMP Toolkit
2 *
3 * Copyright (C) 2003 Sun Microsystems, Inc.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
19 *
20 * Authors:
21 * Mark McLoughlin <mark@skynet.ie>
22 */
23
24 /*
25 #include <config.h>
26 */
27
28 #include <gtk/gtkversion.h>
29 #if !GTK_CHECK_VERSION(2,4,0)
30 #include "gtkexpander.h"
31
32 #include <gtk/gtklabel.h>
33 #include <gtk/gtkcontainer.h>
34 #include <gtk/gtkmarshal.h>
35 #include <gtk/gtkmain.h>
36 #include <gtk/gtkprivate.h>
37 #include <gdk/gdkkeysyms.h>
38
39 #define P_(x) (x)
40
41 #define DEFAULT_EXPANDER_SIZE 10
42 #define DEFAULT_EXPANDER_SPACING 2
43
44 enum
45 {
46 PROP_0,
47 PROP_EXPANDED,
48 PROP_LABEL,
49 PROP_USE_UNDERLINE,
50 PROP_USE_MARKUP,
51 PROP_SPACING,
52 PROP_LABEL_WIDGET
53 };
54
55 struct _GtkExpanderPrivate
56 {
57 GtkWidget *label_widget;
58 GdkWindow *event_window;
59 gint spacing;
60
61 GtkExpanderStyle expander_style;
62 guint animation_timeout;
63
64 guint expanded : 1;
65 guint use_underline : 1;
66 guint use_markup : 1;
67 guint button_down : 1;
68 guint prelight : 1;
69 };
70
71 static void gtk_expander_class_init (GtkExpanderClass *klass);
72 static void gtk_expander_init (GtkExpander *expander);
73
74 static void gtk_expander_set_property (GObject *object,
75 guint prop_id,
76 const GValue *value,
77 GParamSpec *pspec);
78 static void gtk_expander_get_property (GObject *object,
79 guint prop_id,
80 GValue *value,
81 GParamSpec *pspec);
82
83 static void gtk_expander_finalize (GObject *object);
84
85 static void gtk_expander_destroy (GtkObject *object);
86
87 static void gtk_expander_realize (GtkWidget *widget);
88 static void gtk_expander_unrealize (GtkWidget *widget);
89 static void gtk_expander_size_request (GtkWidget *widget,
90 GtkRequisition *requisition);
91 static void gtk_expander_size_allocate (GtkWidget *widget,
92 GtkAllocation *allocation);
93 static void gtk_expander_map (GtkWidget *widget);
94 static void gtk_expander_unmap (GtkWidget *widget);
95 static gboolean gtk_expander_expose (GtkWidget *widget,
96 GdkEventExpose *event);
97 static gboolean gtk_expander_button_press (GtkWidget *widget,
98 GdkEventButton *event);
99 static gboolean gtk_expander_button_release (GtkWidget *widget,
100 GdkEventButton *event);
101 static gboolean gtk_expander_enter_notify (GtkWidget *widget,
102 GdkEventCrossing *event);
103 static gboolean gtk_expander_leave_notify (GtkWidget *widget,
104 GdkEventCrossing *event);
105 static gboolean gtk_expander_focus (GtkWidget *widget,
106 GtkDirectionType direction);
107 static void gtk_expander_grab_notify (GtkWidget *widget,
108 gboolean was_grabbed);
109 static void gtk_expander_state_changed (GtkWidget *widget,
110 GtkStateType previous_state);
111
112 static void gtk_expander_add (GtkContainer *container,
113 GtkWidget *widget);
114 static void gtk_expander_remove (GtkContainer *container,
115 GtkWidget *widget);
116 static void gtk_expander_forall (GtkContainer *container,
117 gboolean include_internals,
118 GtkCallback callback,
119 gpointer callback_data);
120
121 static void gtk_expander_activate (GtkExpander *expander);
122
123 static void get_expander_bounds (GtkExpander *expander,
124 GdkRectangle *rect);
125
126 static GtkBinClass *parent_class = NULL;
127
128 GType
129 gtk_expander_get_type (void)
130 {
131 static GType expander_type = 0;
132
133 if (!expander_type)
134 {
135 static const GTypeInfo expander_info =
136 {
137 sizeof (GtkExpanderClass),
138 NULL, /* base_init */
139 NULL, /* base_finalize */
140 (GClassInitFunc) gtk_expander_class_init,
141 NULL, /* class_finalize */
142 NULL, /* class_data */
143 sizeof (GtkExpander),
144 0, /* n_preallocs */
145 (GInstanceInitFunc) gtk_expander_init,
146 };
147
148 expander_type = g_type_register_static (GTK_TYPE_BIN,
149 "GtkExpander",
150 &expander_info, 0);
151 }
152
153 return expander_type;
154 }
155
156 static void
157 gtk_expander_class_init (GtkExpanderClass *klass)
158 {
159 GObjectClass *gobject_class;
160 GtkObjectClass *object_class;
161 GtkWidgetClass *widget_class;
162 GtkContainerClass *container_class;
163
164 parent_class = g_type_class_peek_parent (klass);
165
166 gobject_class = (GObjectClass *) klass;
167 object_class = (GtkObjectClass *) klass;
168 widget_class = (GtkWidgetClass *) klass;
169 container_class = (GtkContainerClass *) klass;
170
171 gobject_class->set_property = gtk_expander_set_property;
172 gobject_class->get_property = gtk_expander_get_property;
173 gobject_class->finalize = gtk_expander_finalize;
174
175 object_class->destroy = gtk_expander_destroy;
176
177 widget_class->realize = gtk_expander_realize;
178 widget_class->unrealize = gtk_expander_unrealize;
179 widget_class->size_request = gtk_expander_size_request;
180 widget_class->size_allocate = gtk_expander_size_allocate;
181 widget_class->map = gtk_expander_map;
182 widget_class->unmap = gtk_expander_unmap;
183 widget_class->expose_event = gtk_expander_expose;
184 widget_class->button_press_event = gtk_expander_button_press;
185 widget_class->button_release_event = gtk_expander_button_release;
186 widget_class->enter_notify_event = gtk_expander_enter_notify;
187 widget_class->leave_notify_event = gtk_expander_leave_notify;
188 widget_class->focus = gtk_expander_focus;
189 widget_class->grab_notify = gtk_expander_grab_notify;
190 widget_class->state_changed = gtk_expander_state_changed;
191
192 container_class->add = gtk_expander_add;
193 container_class->remove = gtk_expander_remove;
194 container_class->forall = gtk_expander_forall;
195
196 klass->activate = gtk_expander_activate;
197
198 g_object_class_install_property (gobject_class,
199 PROP_EXPANDED,
200 g_param_spec_boolean ("expanded",
201 P_("Expanded"),
202 P_("Whether the expander has been opened to reveal the child widget"),
203 FALSE,
204 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
205
206 g_object_class_install_property (gobject_class,
207 PROP_LABEL,
208 g_param_spec_string ("label",
209 P_("Label"),
210 P_("Text of the expander's label"),
211 NULL,
212 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
213
214 g_object_class_install_property (gobject_class,
215 PROP_USE_UNDERLINE,
216 g_param_spec_boolean ("use_underline",
217 P_("Use underline"),
218 P_("If set, an underline in the text indicates the next character should be used for the mnemonic accelerator key"),
219 FALSE,
220 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
221
222 g_object_class_install_property (gobject_class,
223 PROP_USE_MARKUP,
224 g_param_spec_boolean ("use_markup",
225 P_("Use markup"),
226 P_("The text of the label includes XML markup. See pango_parse_markup()"),
227 FALSE,
228 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
229
230 g_object_class_install_property (gobject_class,
231 PROP_SPACING,
232 g_param_spec_int ("spacing",
233 P_("Spacing"),
234 P_("Space to put between the label and the child"),
235 0,
236 G_MAXINT,
237 0,
238 G_PARAM_READWRITE));
239
240 g_object_class_install_property (gobject_class,
241 PROP_LABEL_WIDGET,
242 g_param_spec_object ("label_widget",
243 P_("Label widget"),
244 P_("A widget to display in place of the usual expander label"),
245 GTK_TYPE_WIDGET,
246 G_PARAM_READWRITE));
247
248 gtk_widget_class_install_style_property (widget_class,
249 g_param_spec_int ("expander-size",
250 P_("Expander Size"),
251 P_("Size of the expander arrow"),
252 0,
253 G_MAXINT,
254 DEFAULT_EXPANDER_SIZE,
255 G_PARAM_READABLE));
256
257 gtk_widget_class_install_style_property (widget_class,
258 g_param_spec_int ("expander-spacing",
259 P_("Indicator Spacing"),
260 P_("Spacing around expander arrow"),
261 0,
262 G_MAXINT,
263 DEFAULT_EXPANDER_SPACING,
264 G_PARAM_READABLE));
265
266 widget_class->activate_signal =
267 g_signal_new ("activate",
268 G_TYPE_FROM_CLASS (gobject_class),
269 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
270 G_STRUCT_OFFSET (GtkExpanderClass, activate),
271 NULL, NULL,
272 gtk_marshal_VOID__VOID,
273 G_TYPE_NONE, 0);
274 }
275
276 static void
277 gtk_expander_finalize (GObject *obj)
278 {
279 GtkExpander *self = (GtkExpander *)obj;
280
281 g_free(self->priv);
282
283 G_OBJECT_CLASS(parent_class)->finalize (obj);
284 }
285
286 static void
287 gtk_expander_init (GtkExpander *expander)
288 {
289 GtkExpanderPrivate *priv;
290
291 expander->priv = priv = g_new0(GtkExpanderPrivate, 1);
292
293 GTK_WIDGET_SET_FLAGS (expander, GTK_CAN_FOCUS);
294 GTK_WIDGET_SET_FLAGS (expander, GTK_NO_WINDOW);
295
296 priv->label_widget = NULL;
297 priv->event_window = NULL;
298 priv->spacing = 0;
299
300 priv->expander_style = GTK_EXPANDER_COLLAPSED;
301 priv->animation_timeout = 0;
302
303 priv->expanded = FALSE;
304 priv->use_underline = FALSE;
305 priv->use_markup = FALSE;
306 priv->button_down = FALSE;
307 priv->prelight = FALSE;
308 }
309
310 static void
311 gtk_expander_set_property (GObject *object,
312 guint prop_id,
313 const GValue *value,
314 GParamSpec *pspec)
315 {
316 GtkExpander *expander = GTK_EXPANDER (object);
317
318 switch (prop_id)
319 {
320 case PROP_EXPANDED:
321 gtk_expander_set_expanded (expander, g_value_get_boolean (value));
322 break;
323 case PROP_LABEL:
324 gtk_expander_set_label (expander, g_value_get_string (value));
325 break;
326 case PROP_USE_UNDERLINE:
327 gtk_expander_set_use_underline (expander, g_value_get_boolean (value));
328 break;
329 case PROP_USE_MARKUP:
330 gtk_expander_set_use_markup (expander, g_value_get_boolean (value));
331 break;
332 case PROP_SPACING:
333 gtk_expander_set_spacing (expander, g_value_get_int (value));
334 break;
335 case PROP_LABEL_WIDGET:
336 gtk_expander_set_label_widget (expander, g_value_get_object (value));
337 break;
338 default:
339 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
340 break;
341 }
342 }
343
344 static void
345 gtk_expander_get_property (GObject *object,
346 guint prop_id,
347 GValue *value,
348 GParamSpec *pspec)
349 {
350 GtkExpander *expander = GTK_EXPANDER (object);
351 GtkExpanderPrivate *priv = expander->priv;
352
353 switch (prop_id)
354 {
355 case PROP_EXPANDED:
356 g_value_set_boolean (value, priv->expanded);
357 break;
358 case PROP_LABEL:
359 g_value_set_string (value, gtk_expander_get_label (expander));
360 break;
361 case PROP_USE_UNDERLINE:
362 g_value_set_boolean (value, priv->use_underline);
363 break;
364 case PROP_USE_MARKUP:
365 g_value_set_boolean (value, priv->use_markup);
366 break;
367 case PROP_SPACING:
368 g_value_set_int (value, priv->spacing);
369 break;
370 case PROP_LABEL_WIDGET:
371 g_value_set_object (value,
372 priv->label_widget ?
373 G_OBJECT (priv->label_widget) : NULL);
374 break;
375 default:
376 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
377 break;
378 }
379 }
380
381 static void
382 gtk_expander_destroy (GtkObject *object)
383 {
384 GtkExpanderPrivate *priv = GTK_EXPANDER (object)->priv;
385
386 if (priv->animation_timeout)
387 {
388 g_source_remove (priv->animation_timeout);
389 priv->animation_timeout = 0;
390 }
391
392 GTK_OBJECT_CLASS (parent_class)->destroy (object);
393 }
394
395 static void
396 gtk_expander_realize (GtkWidget *widget)
397 {
398 GtkExpanderPrivate *priv;
399 GdkWindowAttr attributes;
400 gint attributes_mask;
401 gint border_width;
402 GdkRectangle expander_rect;
403
404 priv = GTK_EXPANDER (widget)->priv;
405 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
406
407 border_width = GTK_CONTAINER (widget)->border_width;
408
409 get_expander_bounds (GTK_EXPANDER (widget), &expander_rect);
410
411 attributes.window_type = GDK_WINDOW_CHILD;
412 attributes.x = widget->allocation.x + border_width;
413 attributes.y = expander_rect.y;
414 attributes.width = MAX (widget->allocation.width - 2 * border_width, 1);
415 attributes.height = expander_rect.width;
416 attributes.wclass = GDK_INPUT_ONLY;
417 attributes.event_mask = gtk_widget_get_events (widget) |
418 GDK_BUTTON_PRESS_MASK |
419 GDK_BUTTON_RELEASE_MASK |
420 GDK_ENTER_NOTIFY_MASK |
421 GDK_LEAVE_NOTIFY_MASK;
422
423 attributes_mask = GDK_WA_X | GDK_WA_Y;
424
425 widget->window = gtk_widget_get_parent_window (widget);
426 g_object_ref (widget->window);
427
428 priv->event_window = gdk_window_new (gtk_widget_get_parent_window (widget),
429 &attributes, attributes_mask);
430 gdk_window_set_user_data (priv->event_window, widget);
431
432 widget->style = gtk_style_attach (widget->style, widget->window);
433 gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
434 }
435
436 static void
437 gtk_expander_unrealize (GtkWidget *widget)
438 {
439 GtkExpanderPrivate *priv = GTK_EXPANDER (widget)->priv;
440
441 if (priv->event_window)
442 {
443 gdk_window_set_user_data (priv->event_window, NULL);
444 gdk_window_destroy (priv->event_window);
445 priv->event_window = NULL;
446 }
447
448 GTK_WIDGET_CLASS (parent_class)->unrealize (widget);
449 }
450
451 static void
452 gtk_expander_size_request (GtkWidget *widget,
453 GtkRequisition *requisition)
454 {
455 GtkExpander *expander;
456 GtkBin *bin;
457 GtkExpanderPrivate *priv;
458 gint border_width;
459 gint expander_size;
460 gint expander_spacing;
461 gboolean interior_focus;
462 gint focus_width;
463 gint focus_pad;
464
465 bin = GTK_BIN (widget);
466 expander = GTK_EXPANDER (widget);
467 priv = expander->priv;
468
469 border_width = GTK_CONTAINER (widget)->border_width;
470
471 gtk_widget_style_get (widget,
472 "interior-focus", &interior_focus,
473 "focus-line-width", &focus_width,
474 "focus-padding", &focus_pad,
475 "expander-size", &expander_size,
476 "expander-spacing", &expander_spacing,
477 NULL);
478
479 requisition->width = expander_size + 2 * expander_spacing +
480 2 * focus_width + 2 * focus_pad;
481 requisition->height = interior_focus ? (2 * focus_width + 2 * focus_pad) : 0;
482
483 if (priv->label_widget && GTK_WIDGET_VISIBLE (priv->label_widget))
484 {
485 GtkRequisition label_requisition;
486
487 gtk_widget_size_request (priv->label_widget, &label_requisition);
488
489 requisition->width += label_requisition.width;
490 requisition->height += label_requisition.height;
491 }
492
493 requisition->height = MAX (expander_size + 2 * expander_spacing, requisition->height);
494
495 if (!interior_focus)
496 requisition->height += 2 * focus_width + 2 * focus_pad;
497
498 if (bin->child && GTK_WIDGET_CHILD_VISIBLE (bin->child))
499 {
500 GtkRequisition child_requisition;
501
502 gtk_widget_size_request (bin->child, &child_requisition);
503
504 requisition->width = MAX (requisition->width, child_requisition.width);
505 requisition->height += child_requisition.height + priv->spacing;
506 }
507
508 requisition->width += 2 * border_width;
509 requisition->height += 2 * border_width;
510 }
511
512 static void
513 get_expander_bounds (GtkExpander *expander,
514 GdkRectangle *rect)
515 {
516 GtkWidget *widget;
517 GtkBin *bin;
518 GtkExpanderPrivate *priv;
519 gint border_width;
520 gint expander_size;
521 gint expander_spacing;
522 gboolean interior_focus;
523 gint focus_width;
524 gint focus_pad;
525 gboolean ltr;
526
527 widget = GTK_WIDGET (expander);
528 bin = GTK_BIN (expander);
529 priv = expander->priv;
530
531 border_width = GTK_CONTAINER (expander)->border_width;
532
533 gtk_widget_style_get (widget,
534 "interior-focus", &interior_focus,
535 "focus-line-width", &focus_width,
536 "focus-padding", &focus_pad,
537 "expander-size", &expander_size,
538 "expander-spacing", &expander_spacing,
539 NULL);
540
541 ltr = gtk_widget_get_direction (widget) != GTK_TEXT_DIR_RTL;
542
543 rect->x = widget->allocation.x + border_width;
544 rect->y = widget->allocation.y + border_width;
545
546 if (ltr)
547 rect->x += expander_spacing;
548 else
549 rect->x += widget->allocation.width - 2 * border_width -
550 expander_spacing - expander_size;
551
552 if (priv->label_widget && GTK_WIDGET_VISIBLE (priv->label_widget))
553 {
554 GtkAllocation label_allocation;
555
556 label_allocation = priv->label_widget->allocation;
557
558 if (expander_size < label_allocation.height)
559 rect->y += focus_width + focus_pad + (label_allocation.height - expander_size) / 2;
560 else
561 rect->y += expander_spacing;
562 }
563 else
564 {
565 rect->y += expander_spacing;
566 }
567
568 if (!interior_focus)
569 {
570 if (ltr)
571 rect->x += focus_width + focus_pad;
572 else
573 rect->x -= focus_width + focus_pad;
574 rect->y += focus_width + focus_pad;
575 }
576
577 rect->width = rect->height = expander_size;
578 }
579
580 static void
581 gtk_expander_size_allocate (GtkWidget *widget,
582 GtkAllocation *allocation)
583 {
584 GtkExpander *expander;
585 GtkBin *bin;
586 GtkExpanderPrivate *priv;
587 GtkRequisition child_requisition;
588 gboolean child_visible = FALSE;
589 gint border_width;
590 gint expander_size;
591 gint expander_spacing;
592 gboolean interior_focus;
593 gint focus_width;
594 gint focus_pad;
595 gint label_height;
596
597 expander = GTK_EXPANDER (widget);
598 bin = GTK_BIN (widget);
599 priv = expander->priv;
600
601 border_width = GTK_CONTAINER (widget)->border_width;
602
603 gtk_widget_style_get (widget,
604 "interior-focus", &interior_focus,
605 "focus-line-width", &focus_width,
606 "focus-padding", &focus_pad,
607 "expander-size", &expander_size,
608 "expander-spacing", &expander_spacing,
609 NULL);
610
611 child_requisition.width = 0;
612 child_requisition.height = 0;
613 if (bin->child && GTK_WIDGET_CHILD_VISIBLE (bin->child))
614 {
615 child_visible = TRUE;
616 gtk_widget_get_child_requisition (bin->child, &child_requisition);
617 }
618
619 widget->allocation = *allocation;
620
621 if (priv->label_widget && GTK_WIDGET_VISIBLE (priv->label_widget))
622 {
623 GtkAllocation label_allocation;
624 GtkRequisition label_requisition;
625 gboolean ltr;
626
627 gtk_widget_get_child_requisition (priv->label_widget, &label_requisition);
628
629 ltr = gtk_widget_get_direction (widget) != GTK_TEXT_DIR_RTL;
630
631 if (ltr)
632 label_allocation.x = (widget->allocation.x +
633 border_width + focus_width + focus_pad +
634 expander_size + 2 * expander_spacing);
635 else
636 label_allocation.x = (widget->allocation.x + widget->allocation.width -
637 (label_requisition.width +
638 border_width + focus_width + focus_pad +
639 expander_size + 2 * expander_spacing));
640
641 label_allocation.y = widget->allocation.y + border_width + focus_width + focus_pad;
642
643 label_allocation.width = MIN (label_requisition.width,
644 allocation->width - 2 * border_width -
645 expander_size - 2 * expander_spacing -
646 2 * focus_width - 2 * focus_pad);
647 label_allocation.width = MAX (label_allocation.width, 1);
648
649 label_allocation.height = MIN (label_requisition.height,
650 allocation->height - 2 * border_width -
651 2 * focus_width - 2 * focus_pad -
652 (child_visible ? priv->spacing : 0));
653 label_allocation.height = MAX (label_allocation.height, 1);
654
655 gtk_widget_size_allocate (priv->label_widget, &label_allocation);
656
657 label_height = label_allocation.height;
658 }
659 else
660 {
661 label_height = 0;
662 }
663
664 if (GTK_WIDGET_REALIZED (widget))
665 {
666 GdkRectangle rect;
667
668 get_expander_bounds (expander, &rect);
669
670 gdk_window_move_resize (priv->event_window,
671 allocation->x + border_width, rect.y,
672 MAX (allocation->width - 2 * border_width, 1), rect.width);
673 }
674
675 if (child_visible)
676 {
677 GtkAllocation child_allocation;
678 gint top_height;
679
680 top_height = MAX (2 * expander_spacing + expander_size,
681 label_height +
682 (interior_focus ? 2 * focus_width + 2 * focus_pad : 0));
683
684 child_allocation.x = widget->allocation.x + border_width;
685 child_allocation.y = widget->allocation.y + border_width + top_height + priv->spacing;
686
687 if (!interior_focus)
688 child_allocation.y += 2 * focus_width + 2 * focus_pad;
689
690 child_allocation.width = MAX (allocation->width - 2 * border_width, 1);
691
692 child_allocation.height = allocation->height - top_height -
693 2 * border_width - priv->spacing -
694 (!interior_focus ? 2 * focus_width + 2 * focus_pad : 0);
695 child_allocation.height = MAX (child_allocation.height, 1);
696
697 gtk_widget_size_allocate (bin->child, &child_allocation);
698 }
699 }
700
701 static void
702 gtk_expander_map (GtkWidget *widget)
703 {
704 GtkExpanderPrivate *priv = GTK_EXPANDER (widget)->priv;
705
706 if (priv->label_widget)
707 gtk_widget_map (priv->label_widget);
708
709 GTK_WIDGET_CLASS (parent_class)->map (widget);
710
711 if (priv->event_window)
712 gdk_window_show (priv->event_window);
713 }
714
715 static void
716 gtk_expander_unmap (GtkWidget *widget)
717 {
718 GtkExpanderPrivate *priv = GTK_EXPANDER (widget)->priv;
719
720 if (priv->event_window)
721 gdk_window_hide (priv->event_window);
722
723 GTK_WIDGET_CLASS (parent_class)->unmap (widget);
724
725 if (priv->label_widget)
726 gtk_widget_unmap (priv->label_widget);
727 }
728
729 static void
730 gtk_expander_paint_prelight (GtkExpander *expander)
731 {
732 GtkWidget *widget;
733 GtkContainer *container;
734 GtkExpanderPrivate *priv;
735 GdkRectangle area;
736 gboolean interior_focus;
737 int focus_width;
738 int focus_pad;
739 int expander_size;
740 int expander_spacing;
741
742 priv = expander->priv;
743 widget = GTK_WIDGET (expander);
744 container = GTK_CONTAINER (expander);
745
746 gtk_widget_style_get (widget,
747 "interior-focus", &interior_focus,
748 "focus-line-width", &focus_width,
749 "focus-padding", &focus_pad,
750 "expander-size", &expander_size,
751 "expander-spacing", &expander_spacing,
752 NULL);
753
754 area.x = widget->allocation.x + container->border_width;
755 area.y = widget->allocation.y + container->border_width;
756 area.width = widget->allocation.width - (2 * container->border_width);
757
758 if (priv->label_widget && GTK_WIDGET_VISIBLE (priv->label_widget))
759 area.height = priv->label_widget->allocation.height;
760 else
761 area.height = 0;
762
763 area.height += interior_focus ? (focus_width + focus_pad) * 2 : 0;
764 area.height = MAX (area.height, expander_size + 2 * expander_spacing);
765 area.height += !interior_focus ? (focus_width + focus_pad) * 2 : 0;
766
767 gtk_paint_flat_box (widget->style, widget->window,
768 GTK_STATE_PRELIGHT,
769 GTK_SHADOW_ETCHED_OUT,
770 &area, widget, "expander",
771 area.x, area.y,
772 area.width, area.height);
773 }
774
775 static void
776 gtk_expander_paint (GtkExpander *expander)
777 {
778 GtkWidget *widget;
779 GdkRectangle clip;
780 GtkStateType state;
781
782 widget = GTK_WIDGET (expander);
783
784 get_expander_bounds (expander, &clip);
785
786 state = widget->state;
787 if (expander->priv->prelight)
788 {
789 state = GTK_STATE_PRELIGHT;
790
791 gtk_expander_paint_prelight (expander);
792 }
793
794 gtk_paint_expander (widget->style,
795 widget->window,
796 state,
797 &clip,
798 widget,
799 "expander",
800 clip.x + clip.width / 2,
801 clip.y + clip.height / 2,
802 expander->priv->expander_style);
803 }
804
805 static void
806 gtk_expander_paint_focus (GtkExpander *expander,
807 GdkRectangle *area)
808 {
809 GtkWidget *widget;
810 GtkExpanderPrivate *priv;
811 gint x, y, width, height;
812 gboolean interior_focus;
813 gint border_width;
814 gint focus_width;
815 gint focus_pad;
816 gint expander_size;
817 gint expander_spacing;
818 gboolean ltr;
819
820 widget = GTK_WIDGET (expander);
821 priv = expander->priv;
822
823 border_width = GTK_CONTAINER (widget)->border_width;
824
825 gtk_widget_style_get (widget,
826 "interior-focus", &interior_focus,
827 "focus-line-width", &focus_width,
828 "focus-padding", &focus_pad,
829 "expander-size", &expander_size,
830 "expander-spacing", &expander_spacing,
831 NULL);
832
833 ltr = gtk_widget_get_direction (widget) != GTK_TEXT_DIR_RTL;
834
835 x = widget->allocation.x + border_width;
836 y = widget->allocation.y + border_width;
837
838 if (ltr && interior_focus)
839 x += expander_spacing * 2 + expander_size;
840
841 width = height = 0;
842
843 if (priv->label_widget && GTK_WIDGET_VISIBLE (priv->label_widget))
844 {
845 GtkAllocation label_allocation = priv->label_widget->allocation;
846
847 width = label_allocation.width;
848 height = label_allocation.height;
849 }
850
851 if (!interior_focus)
852 {
853 width += expander_size + 2 * expander_spacing;
854 height = MAX (height, expander_size + 2 * expander_spacing);
855 }
856
857 width += 2 * focus_pad + 2 * focus_width;
858 height += 2 * focus_pad + 2 * focus_width;
859
860 gtk_paint_focus (widget->style, widget->window, GTK_WIDGET_STATE (widget),
861 area, widget, "expander",
862 x, y, width, height);
863 }
864
865 static gboolean
866 gtk_expander_expose (GtkWidget *widget,
867 GdkEventExpose *event)
868 {
869 if (GTK_WIDGET_DRAWABLE (widget))
870 {
871 GtkExpander *expander = GTK_EXPANDER (widget);
872
873 gtk_expander_paint (expander);
874
875 if (GTK_WIDGET_HAS_FOCUS (expander))
876 gtk_expander_paint_focus (expander, &event->area);
877
878 GTK_WIDGET_CLASS (parent_class)->expose_event (widget, event);
879 }
880
881 return FALSE;
882 }
883
884 static gboolean
885 gtk_expander_button_press (GtkWidget *widget,
886 GdkEventButton *event)
887 {
888 GtkExpander *expander = GTK_EXPANDER (widget);
889
890 if (event->button == 1 && event->window == expander->priv->event_window)
891 {
892 expander->priv->button_down = TRUE;
893 return TRUE;
894 }
895
896 return FALSE;
897 }
898
899 static gboolean
900 gtk_expander_button_release (GtkWidget *widget,
901 GdkEventButton *event)
902 {
903 GtkExpander *expander = GTK_EXPANDER (widget);
904
905 if (event->button == 1 && expander->priv->button_down)
906 {
907 gtk_widget_activate (widget);
908 expander->priv->button_down = FALSE;
909 return TRUE;
910 }
911
912 return FALSE;
913 }
914
915 static void
916 gtk_expander_grab_notify (GtkWidget *widget,
917 gboolean was_grabbed)
918 {
919 if (!was_grabbed)
920 GTK_EXPANDER (widget)->priv->button_down = FALSE;
921 }
922
923 static void
924 gtk_expander_state_changed (GtkWidget *widget,
925 GtkStateType previous_state)
926 {
927 if (!GTK_WIDGET_IS_SENSITIVE (widget))
928 GTK_EXPANDER (widget)->priv->button_down = FALSE;
929 }
930
931 static void
932 gtk_expander_redraw_expander (GtkExpander *expander)
933 {
934 GtkWidget *widget;
935
936 widget = GTK_WIDGET (expander);
937
938 if (GTK_WIDGET_REALIZED (widget))
939 gdk_window_invalidate_rect (widget->window, &widget->allocation, FALSE);
940 }
941
942 static gboolean
943 gtk_expander_enter_notify (GtkWidget *widget,
944 GdkEventCrossing *event)
945 {
946 GtkExpander *expander = GTK_EXPANDER (widget);
947 GtkWidget *event_widget;
948
949 event_widget = gtk_get_event_widget ((GdkEvent *) event);
950
951 if (event_widget == widget &&
952 event->detail != GDK_NOTIFY_INFERIOR)
953 {
954 expander->priv->prelight = TRUE;
955
956 if (expander->priv->label_widget)
957 gtk_widget_set_state (expander->priv->label_widget, GTK_STATE_PRELIGHT);
958
959 gtk_expander_redraw_expander (expander);
960 }
961
962 return FALSE;
963 }
964
965 static gboolean
966 gtk_expander_leave_notify (GtkWidget *widget,
967 GdkEventCrossing *event)
968 {
969 GtkExpander *expander = GTK_EXPANDER (widget);
970 GtkWidget *event_widget;
971
972 event_widget = gtk_get_event_widget ((GdkEvent *) event);
973
974 if (event_widget == widget &&
975 event->detail != GDK_NOTIFY_INFERIOR)
976 {
977 expander->priv->prelight = FALSE;
978
979 if (expander->priv->label_widget)
980 gtk_widget_set_state (expander->priv->label_widget, GTK_STATE_NORMAL);
981
982 gtk_expander_redraw_expander (expander);
983 }
984
985 return FALSE;
986 }
987
988 typedef enum
989 {
990 FOCUS_NONE,
991 FOCUS_WIDGET,
992 FOCUS_LABEL,
993 FOCUS_CHILD
994 } FocusSite;
995
996 static gboolean
997 focus_current_site (GtkExpander *expander,
998 GtkDirectionType direction)
999 {
1000 GtkWidget *current_focus;
1001
1002 current_focus = GTK_CONTAINER (expander)->focus_child;
1003
1004 if (!current_focus)
1005 return FALSE;
1006
1007 return gtk_widget_child_focus (current_focus, direction);
1008 }
1009
1010 static gboolean
1011 focus_in_site (GtkExpander *expander,
1012 FocusSite site,
1013 GtkDirectionType direction)
1014 {
1015 switch (site)
1016 {
1017 case FOCUS_WIDGET:
1018 gtk_widget_grab_focus (GTK_WIDGET (expander));
1019 return TRUE;
1020 case FOCUS_LABEL:
1021 if (expander->priv->label_widget)
1022 return gtk_widget_child_focus (expander->priv->label_widget, direction);
1023 else
1024 return FALSE;
1025 case FOCUS_CHILD:
1026 {
1027 GtkWidget *child = gtk_bin_get_child (GTK_BIN (expander));
1028
1029 if (child && GTK_WIDGET_CHILD_VISIBLE (child))
1030 return gtk_widget_child_focus (child, direction);
1031 else
1032 return FALSE;
1033 }
1034 case FOCUS_NONE:
1035 break;
1036 }
1037
1038 g_assert_not_reached ();
1039 return FALSE;
1040 }
1041
1042 static FocusSite
1043 get_next_site (GtkExpander *expander,
1044 FocusSite site,
1045 GtkDirectionType direction)
1046 {
1047 gboolean ltr;
1048
1049 ltr = gtk_widget_get_direction (GTK_WIDGET (expander)) != GTK_TEXT_DIR_RTL;
1050
1051 switch (site)
1052 {
1053 case FOCUS_NONE:
1054 switch (direction)
1055 {
1056 case GTK_DIR_TAB_BACKWARD:
1057 case GTK_DIR_LEFT:
1058 case GTK_DIR_UP:
1059 return FOCUS_CHILD;
1060 case GTK_DIR_TAB_FORWARD:
1061 case GTK_DIR_DOWN:
1062 case GTK_DIR_RIGHT:
1063 return FOCUS_WIDGET;
1064 }
1065 case FOCUS_WIDGET:
1066 switch (direction)
1067 {
1068 case GTK_DIR_TAB_BACKWARD:
1069 case GTK_DIR_UP:
1070 return FOCUS_NONE;
1071 case GTK_DIR_LEFT:
1072 return ltr ? FOCUS_NONE : FOCUS_LABEL;
1073 case GTK_DIR_TAB_FORWARD:
1074 case GTK_DIR_DOWN:
1075 return FOCUS_LABEL;
1076 case GTK_DIR_RIGHT:
1077 return ltr ? FOCUS_LABEL : FOCUS_NONE;
1078 break;
1079 }
1080 case FOCUS_LABEL:
1081 switch (direction)
1082 {
1083 case GTK_DIR_TAB_BACKWARD:
1084 case GTK_DIR_UP:
1085 return FOCUS_WIDGET;
1086 case GTK_DIR_LEFT:
1087 return ltr ? FOCUS_WIDGET : FOCUS_CHILD;
1088 case GTK_DIR_TAB_FORWARD:
1089 case GTK_DIR_DOWN:
1090 return FOCUS_CHILD;
1091 case GTK_DIR_RIGHT:
1092 return ltr ? FOCUS_CHILD : FOCUS_WIDGET;
1093 break;
1094 }
1095 case FOCUS_CHILD:
1096 switch (direction)
1097 {
1098 case GTK_DIR_TAB_BACKWARD:
1099 case GTK_DIR_LEFT:
1100 case GTK_DIR_UP:
1101 return FOCUS_LABEL;
1102 case GTK_DIR_TAB_FORWARD:
1103 case GTK_DIR_DOWN:
1104 case GTK_DIR_RIGHT:
1105 return FOCUS_NONE;
1106 }
1107 }
1108
1109 g_assert_not_reached ();
1110 return FOCUS_NONE;
1111 }
1112
1113 static gboolean
1114 gtk_expander_focus (GtkWidget *widget,
1115 GtkDirectionType direction)
1116 {
1117 GtkExpander *expander = GTK_EXPANDER (widget);
1118
1119 if (!focus_current_site (expander, direction))
1120 {
1121 GtkWidget *old_focus_child;
1122 gboolean widget_is_focus;
1123 FocusSite site = FOCUS_NONE;
1124
1125 widget_is_focus = gtk_widget_is_focus (widget);
1126 old_focus_child = GTK_CONTAINER (widget)->focus_child;
1127
1128 if (old_focus_child && old_focus_child == expander->priv->label_widget)
1129 site = FOCUS_LABEL;
1130 else if (old_focus_child)
1131 site = FOCUS_CHILD;
1132 else if (widget_is_focus)
1133 site = FOCUS_WIDGET;
1134
1135 while ((site = get_next_site (expander, site, direction)) != FOCUS_NONE)
1136 {
1137 if (focus_in_site (expander, site, direction))
1138 return TRUE;
1139 }
1140
1141 return FALSE;
1142 }
1143
1144 return TRUE;
1145 }
1146
1147 static void
1148 gtk_expander_add (GtkContainer *container,
1149 GtkWidget *widget)
1150 {
1151 GTK_CONTAINER_CLASS (parent_class)->add (container, widget);
1152
1153 gtk_widget_set_child_visible (widget, GTK_EXPANDER (container)->priv->expanded);
1154 gtk_widget_queue_resize (GTK_WIDGET (container));
1155 }
1156
1157 static void
1158 gtk_expander_remove (GtkContainer *container,
1159 GtkWidget *widget)
1160 {
1161 GtkExpander *expander = GTK_EXPANDER (container);
1162
1163 if (GTK_EXPANDER (expander)->priv->label_widget == widget)
1164 gtk_expander_set_label_widget (expander, NULL);
1165 else
1166 GTK_CONTAINER_CLASS (parent_class)->remove (container, widget);
1167 }
1168
1169 static void
1170 gtk_expander_forall (GtkContainer *container,
1171 gboolean include_internals,
1172 GtkCallback callback,
1173 gpointer callback_data)
1174 {
1175 GtkBin *bin = GTK_BIN (container);
1176 GtkExpanderPrivate *priv = GTK_EXPANDER (container)->priv;
1177
1178 if (bin->child)
1179 (* callback) (bin->child, callback_data);
1180
1181 if (priv->label_widget)
1182 (* callback) (priv->label_widget, callback_data);
1183 }
1184
1185 static void
1186 gtk_expander_activate (GtkExpander *expander)
1187 {
1188 gtk_expander_set_expanded (expander, !expander->priv->expanded);
1189 }
1190
1191
1192 /**
1193 * gtk_expander_new:
1194 * @label: the text of the label
1195 *
1196 * Creates a new expander using @label as the text of the label.
1197 *
1198 * Return value: a new #GtkExpander widget.
1199 *
1200 * Since: 2.4
1201 **/
1202 GtkWidget *
1203 gtk_expander_new (const gchar *label)
1204 {
1205 return g_object_new (GTK_TYPE_EXPANDER, "label", label, NULL);
1206 }
1207
1208 /**
1209 * gtk_expander_new_with_mnemonic:
1210 * @label: the text of the label with an underscore in front of the
1211 * mnemonic character
1212 *
1213 * Creates a new expander using @label as the text of the label.
1214 * If characters in @label are preceded by an underscore, they are underlined.
1215 * If you need a literal underscore character in a label, use '__' (two
1216 * underscores). The first underlined character represents a keyboard
1217 * accelerator called a mnemonic.
1218 * Pressing Alt and that key activates the button.
1219 *
1220 * Return value: a new #GtkExpander widget.
1221 *
1222 * Since: 2.4
1223 **/
1224 GtkWidget *
1225 gtk_expander_new_with_mnemonic (const gchar *label)
1226 {
1227 return g_object_new (GTK_TYPE_EXPANDER,
1228 "label", label,
1229 "use_underline", TRUE,
1230 NULL);
1231 }
1232
1233 static gboolean
1234 gtk_expander_animation_timeout (GtkExpander *expander)
1235 {
1236 GtkExpanderPrivate *priv = expander->priv;
1237 GdkRectangle area;
1238 gboolean finish = FALSE;
1239
1240 GDK_THREADS_ENTER();
1241
1242 if (GTK_WIDGET_REALIZED (expander))
1243 {
1244 get_expander_bounds (expander, &area);
1245 gdk_window_invalidate_rect (GTK_WIDGET (expander)->window, &area, TRUE);
1246 }
1247
1248 if (priv->expanded)
1249 {
1250 if (priv->expander_style == GTK_EXPANDER_COLLAPSED)
1251 {
1252 priv->expander_style = GTK_EXPANDER_SEMI_EXPANDED;
1253 }
1254 else
1255 {
1256 priv->expander_style = GTK_EXPANDER_EXPANDED;
1257 finish = TRUE;
1258 }
1259 }
1260 else
1261 {
1262 if (priv->expander_style == GTK_EXPANDER_EXPANDED)
1263 {
1264 priv->expander_style = GTK_EXPANDER_SEMI_COLLAPSED;
1265 }
1266 else
1267 {
1268 priv->expander_style = GTK_EXPANDER_COLLAPSED;
1269 finish = TRUE;
1270 }
1271 }
1272
1273 if (finish)
1274 {
1275 priv->animation_timeout = 0;
1276 if (GTK_BIN (expander)->child)
1277 gtk_widget_set_child_visible (GTK_BIN (expander)->child, priv->expanded);
1278 gtk_widget_queue_resize (GTK_WIDGET (expander));
1279 }
1280
1281 GDK_THREADS_LEAVE();
1282
1283 return !finish;
1284 }
1285
1286 static void
1287 gtk_expander_start_animation (GtkExpander *expander)
1288 {
1289 GtkExpanderPrivate *priv = expander->priv;
1290
1291 if (priv->animation_timeout)
1292 g_source_remove (priv->animation_timeout);
1293
1294 priv->animation_timeout =
1295 g_timeout_add (50,
1296 (GSourceFunc) gtk_expander_animation_timeout,
1297 expander);
1298 }
1299
1300 /**
1301 * gtk_expander_set_expanded:
1302 * @expander: a #GtkExpander
1303 * @expanded: whether the child widget is revealed
1304 *
1305 * Sets the state of the expander. Set to %TRUE, if you want
1306 * the child widget to be revealed, and %FALSE if you want the
1307 * child widget to be hidden.
1308 *
1309 * Since: 2.4
1310 **/
1311 void
1312 gtk_expander_set_expanded (GtkExpander *expander,
1313 gboolean expanded)
1314 {
1315 GtkExpanderPrivate *priv;
1316
1317 g_return_if_fail (GTK_IS_EXPANDER (expander));
1318
1319 priv = expander->priv;
1320
1321 expanded = expanded != FALSE;
1322
1323 if (priv->expanded != expanded)
1324 {
1325 priv->expanded = expanded;
1326
1327 if (GTK_WIDGET_REALIZED (expander))
1328 {
1329 gtk_expander_start_animation (expander);
1330 }
1331 else
1332 {
1333 priv->expander_style = expanded ? GTK_EXPANDER_EXPANDED :
1334 GTK_EXPANDER_COLLAPSED;
1335
1336 if (GTK_BIN (expander)->child)
1337 {
1338 gtk_widget_set_child_visible (GTK_BIN (expander)->child, priv->expanded);
1339 gtk_widget_queue_resize (GTK_WIDGET (expander));
1340 }
1341 }
1342
1343 g_object_notify (G_OBJECT (expander), "expanded");
1344 }
1345 }
1346
1347 /**
1348 * gtk_expander_get_expanded:
1349 * @expander:a #GtkExpander
1350 *
1351 * Queries a #GtkExpander and returns its current state. Returns %TRUE
1352 * if the child widget is revealed.
1353 *
1354 * See gtk_expander_set_expanded().
1355 *
1356 * Return value: the current state of the expander.
1357 *
1358 * Since: 2.4
1359 **/
1360 gboolean
1361 gtk_expander_get_expanded (GtkExpander *expander)
1362 {
1363 g_return_val_if_fail (GTK_IS_EXPANDER (expander), FALSE);
1364
1365 return expander->priv->expanded;
1366 }
1367
1368 /**
1369 * gtk_expander_set_spacing:
1370 * @expander: a #GtkExpander
1371 * @spacing: distance between the expander and child in pixels.
1372 *
1373 * Sets the spacing field of @expander, which is the number of pixels to
1374 * place between expander and the child.
1375 *
1376 * Since: 2.4
1377 **/
1378 void
1379 gtk_expander_set_spacing (GtkExpander *expander,
1380 gint spacing)
1381 {
1382 g_return_if_fail (GTK_IS_EXPANDER (expander));
1383 g_return_if_fail (spacing >= 0);
1384
1385 if (expander->priv->spacing != spacing)
1386 {
1387 expander->priv->spacing = spacing;
1388
1389 gtk_widget_queue_resize (GTK_WIDGET (expander));
1390
1391 g_object_notify (G_OBJECT (expander), "spacing");
1392 }
1393 }
1394
1395 /**
1396 * gtk_expander_get_spacing:
1397 * @expander: a #GtkExpander
1398 *
1399 * Gets the value set by gtk_expander_set_spacing().
1400 *
1401 * Return value: spacing between the expander and child.
1402 *
1403 * Since: 2.4
1404 **/
1405 gint
1406 gtk_expander_get_spacing (GtkExpander *expander)
1407 {
1408 g_return_val_if_fail (GTK_IS_EXPANDER (expander), 0);
1409
1410 return expander->priv->spacing;
1411 }
1412
1413 /**
1414 * gtk_expander_set_label:
1415 * @expander: a #GtkExpander
1416 * @label: a string
1417 *
1418 * Sets the text of the label of the expander to @label.
1419 *
1420 * This will also clear any previously set labels.
1421 *
1422 * Since: 2.4
1423 **/
1424 void
1425 gtk_expander_set_label (GtkExpander *expander,
1426 const gchar *label)
1427 {
1428 g_return_if_fail (GTK_IS_EXPANDER (expander));
1429
1430 if (!label)
1431 {
1432 gtk_expander_set_label_widget (expander, NULL);
1433 }
1434 else
1435 {
1436 GtkWidget *child;
1437
1438 child = gtk_label_new (label);
1439 gtk_label_set_use_underline (GTK_LABEL (child), expander->priv->use_underline);
1440 gtk_label_set_use_markup (GTK_LABEL (child), expander->priv->use_markup);
1441 gtk_widget_show (child);
1442
1443 gtk_expander_set_label_widget (expander, child);
1444 }
1445
1446 g_object_notify (G_OBJECT (expander), "label");
1447 }
1448
1449 /**
1450 * gtk_expander_get_label:
1451 * @expander: a #GtkExpander
1452 *
1453 * Fetches the text from the label of the expander, as set by
1454 * gtk_expander_set_label(). If the label text has not
1455 * been set the return value will be %NULL. This will be the
1456 * case if you create an empty button with gtk_button_new() to
1457 * use as a container.
1458 *
1459 * Return value: The text of the label widget. This string is owned
1460 * by the widget and must not be modified or freed.
1461 *
1462 * Since: 2.4
1463 **/
1464 G_CONST_RETURN char *
1465 gtk_expander_get_label (GtkExpander *expander)
1466 {
1467 GtkExpanderPrivate *priv;
1468
1469 g_return_val_if_fail (GTK_IS_EXPANDER (expander), NULL);
1470
1471 priv = expander->priv;
1472
1473 if (priv->label_widget && GTK_IS_LABEL (priv->label_widget))
1474 return gtk_label_get_text (GTK_LABEL (priv->label_widget));
1475 else
1476 return NULL;
1477 }
1478
1479 /**
1480 * gtk_expander_set_use_underline:
1481 * @expander: a #GtkExpander
1482 * @use_underline: %TRUE if underlines in the text indicate mnemonics
1483 *
1484 * If true, an underline in the text of the expander label indicates
1485 * the next character should be used for the mnemonic accelerator key.
1486 *
1487 * Since: 2.4
1488 **/
1489 void
1490 gtk_expander_set_use_underline (GtkExpander *expander,
1491 gboolean use_underline)
1492 {
1493 GtkExpanderPrivate *priv;
1494
1495 g_return_if_fail (GTK_IS_EXPANDER (expander));
1496
1497 priv = expander->priv;
1498
1499 use_underline = use_underline != FALSE;
1500
1501 if (priv->use_underline != use_underline)
1502 {
1503 priv->use_underline = use_underline;
1504
1505 if (priv->label_widget && GTK_IS_LABEL (priv->label_widget))
1506 gtk_label_set_use_underline (GTK_LABEL (priv->label_widget), use_underline);
1507
1508 g_object_notify (G_OBJECT (expander), "use-underline");
1509 }
1510 }
1511
1512 /**
1513 * gtk_expander_get_use_underline:
1514 * @expander: a #GtkExpander
1515 *
1516 * Returns whether an embedded underline in the expander label indicates a
1517 * mnemonic. See gtk_expander_set_use_underline().
1518 *
1519 * Return value: %TRUE if an embedded underline in the expander label
1520 * indicates the mnemonic accelerator keys.
1521 *
1522 * Since: 2.4
1523 **/
1524 gboolean
1525 gtk_expander_get_use_underline (GtkExpander *expander)
1526 {
1527 g_return_val_if_fail (GTK_IS_EXPANDER (expander), FALSE);
1528
1529 return expander->priv->use_underline;
1530 }
1531
1532 /**
1533 * gtk_expander_set_use_markup:
1534 * @expander: a #GtkExpander
1535 * @use_markup: %TRUE if the label's text should be parsed for markup
1536 *
1537 * Sets whether the text of the label contains markup in <link
1538 * linkend="PangoMarkupFormat">Pango's text markup
1539 * language</link>. See gtk_label_set_markup().
1540 *
1541 * Since: 2.4
1542 **/
1543 void
1544 gtk_expander_set_use_markup (GtkExpander *expander,
1545 gboolean use_markup)
1546 {
1547 GtkExpanderPrivate *priv;
1548
1549 g_return_if_fail (GTK_IS_EXPANDER (expander));
1550
1551 priv = expander->priv;
1552
1553 use_markup = use_markup != FALSE;
1554
1555 if (priv->use_markup != use_markup)
1556 {
1557 priv->use_markup = use_markup;
1558
1559 if (priv->label_widget && GTK_IS_LABEL (priv->label_widget))
1560 gtk_label_set_use_markup (GTK_LABEL (priv->label_widget), use_markup);
1561
1562 g_object_notify (G_OBJECT (expander), "use-markup");
1563 }
1564 }
1565
1566 /**
1567 * gtk_expander_get_use_markup:
1568 * @expander: a #GtkExpander
1569 *
1570 * Returns whether the label's text is interpreted as marked up with
1571 * the <link linkend="PangoMarkupFormat">Pango text markup
1572 * language</link>. See gtk_expander_set_use_markup ().
1573 *
1574 * Return value: %TRUE if the label's text will be parsed for markup
1575 *
1576 * Since: 2.4
1577 **/
1578 gboolean
1579 gtk_expander_get_use_markup (GtkExpander *expander)
1580 {
1581 g_return_val_if_fail (GTK_IS_EXPANDER (expander), FALSE);
1582
1583 return expander->priv->use_markup;
1584 }
1585
1586 /**
1587 * gtk_expander_set_label_widget:
1588 * @expander: a #GtkExpander
1589 * @label_widget: the new label widget
1590 *
1591 * Set the label widget for the expander. This is the widget
1592 * that will appear embedded alongside the expander arrow.
1593 *
1594 * Since: 2.4
1595 **/
1596 void
1597 gtk_expander_set_label_widget (GtkExpander *expander,
1598 GtkWidget *label_widget)
1599 {
1600 GtkExpanderPrivate *priv;
1601
1602 g_return_if_fail (GTK_IS_EXPANDER (expander));
1603 g_return_if_fail (label_widget == NULL || GTK_IS_WIDGET (label_widget));
1604 g_return_if_fail (label_widget == NULL || label_widget->parent == NULL);
1605
1606 priv = expander->priv;
1607
1608 if (priv->label_widget == label_widget)
1609 return;
1610
1611 if (priv->label_widget)
1612 {
1613 gtk_widget_set_state (priv->label_widget, GTK_STATE_NORMAL);
1614 gtk_widget_unparent (priv->label_widget);
1615 }
1616
1617 priv->label_widget = label_widget;
1618
1619 if (label_widget)
1620 {
1621 priv->label_widget = label_widget;
1622
1623 gtk_widget_set_parent (label_widget, GTK_WIDGET (expander));
1624
1625 if (priv->prelight)
1626 gtk_widget_set_state (label_widget, GTK_STATE_PRELIGHT);
1627 }
1628
1629 if (GTK_WIDGET_VISIBLE (expander))
1630 gtk_widget_queue_resize (GTK_WIDGET (expander));
1631
1632 g_object_freeze_notify (G_OBJECT (expander));
1633 g_object_notify (G_OBJECT (expander), "label-widget");
1634 g_object_notify (G_OBJECT (expander), "label");
1635 g_object_thaw_notify (G_OBJECT (expander));
1636 }
1637
1638 /**
1639 * gtk_expander_get_label_widget:
1640 * @expander: a #GtkExpander
1641 *
1642 * Retrieves the label widget for the frame. See
1643 * gtk_expander_set_label_widget().
1644 *
1645 * Return value: the label widget, or %NULL if there is none.
1646 *
1647 * Since: 2.4
1648 **/
1649 GtkWidget *
1650 gtk_expander_get_label_widget (GtkExpander *expander)
1651 {
1652 g_return_val_if_fail (GTK_IS_EXPANDER (expander), NULL);
1653
1654 return expander->priv->label_widget;
1655 }
1656
1657 #define __GTK_EXPANDER_C__
1658
1659 #endif /* Gtk 2.4 */