2 * Copyright (C) 2000 Red Hat, Inc.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
22 #undef GTK_DISABLE_DEPRECATED
25 #include "prop-editor.h"
31 GObject
*alive_object
;
36 disconnect_func (gpointer data
)
38 DisconnectData
*dd
= data
;
40 g_signal_handler_disconnect (dd
->instance
, dd
->id
);
44 signal_removed (gpointer data
,
47 DisconnectData
*dd
= data
;
49 g_object_steal_data (dd
->alive_object
, "alive-object-data");
54 is_child_property (GParamSpec
*pspec
)
56 return g_param_spec_get_qdata (pspec
, g_quark_from_string ("is-child-prop")) != NULL
;
60 mark_child_property (GParamSpec
*pspec
)
62 g_param_spec_set_qdata (pspec
, g_quark_from_string ("is-child-prop"),
63 GINT_TO_POINTER (TRUE
));
67 g_object_connect_property (GObject
*object
,
71 GObject
*alive_object
)
77 if (is_child_property (spec
))
78 with_detail
= g_strconcat ("child-notify::", spec
->name
, NULL
);
80 with_detail
= g_strconcat ("notify::", spec
->name
, NULL
);
82 dd
= g_new (DisconnectData
, 1);
84 closure
= g_cclosure_new (func
, data
, NULL
);
86 g_closure_add_invalidate_notifier (closure
, dd
, signal_removed
);
88 dd
->id
= g_signal_connect_closure (object
, with_detail
,
91 dd
->instance
= object
;
92 dd
->alive_object
= alive_object
;
94 g_object_set_data_full (G_OBJECT (alive_object
),
110 free_object_property (ObjectProperty
*p
)
116 connect_controller (GObject
*controller
,
124 p
= g_new (ObjectProperty
, 1);
128 p
->modified_id
= g_signal_connect_data (controller
, signal
, func
, p
,
129 (GClosureNotify
)free_object_property
,
131 g_object_set_data (controller
, "object-property", p
);
135 block_controller (GObject
*controller
)
137 ObjectProperty
*p
= g_object_get_data (controller
, "object-property");
140 g_signal_handler_block (controller
, p
->modified_id
);
144 unblock_controller (GObject
*controller
)
146 ObjectProperty
*p
= g_object_get_data (controller
, "object-property");
149 g_signal_handler_unblock (controller
, p
->modified_id
);
153 int_modified (GtkAdjustment
*adj
, gpointer data
)
155 ObjectProperty
*p
= data
;
157 if (is_child_property (p
->spec
))
159 GtkWidget
*widget
= GTK_WIDGET (p
->obj
);
160 GtkWidget
*parent
= gtk_widget_get_parent (widget
);
162 gtk_container_child_set (GTK_CONTAINER (parent
),
163 widget
, p
->spec
->name
, (int) adj
->value
, NULL
);
166 g_object_set (p
->obj
, p
->spec
->name
, (int) adj
->value
, NULL
);
170 get_property_value (GObject
*object
, GParamSpec
*pspec
, GValue
*value
)
172 if (is_child_property (pspec
))
174 GtkWidget
*widget
= GTK_WIDGET (object
);
175 GtkWidget
*parent
= gtk_widget_get_parent (widget
);
177 gtk_container_child_get_property (GTK_CONTAINER (parent
),
178 widget
, pspec
->name
, value
);
181 g_object_get_property (object
, pspec
->name
, value
);
185 int_changed (GObject
*object
, GParamSpec
*pspec
, gpointer data
)
187 GtkAdjustment
*adj
= GTK_ADJUSTMENT (data
);
190 g_value_init (&val
, G_TYPE_INT
);
192 get_property_value (object
, pspec
, &val
);
194 if (g_value_get_int (&val
) != (int)adj
->value
)
196 block_controller (G_OBJECT (adj
));
197 gtk_adjustment_set_value (adj
, g_value_get_int (&val
));
198 unblock_controller (G_OBJECT (adj
));
201 g_value_unset (&val
);
205 uint_modified (GtkAdjustment
*adj
, gpointer data
)
207 ObjectProperty
*p
= data
;
209 if (is_child_property (p
->spec
))
211 GtkWidget
*widget
= GTK_WIDGET (p
->obj
);
212 GtkWidget
*parent
= gtk_widget_get_parent (widget
);
214 gtk_container_child_set (GTK_CONTAINER (parent
),
215 widget
, p
->spec
->name
, (guint
) adj
->value
, NULL
);
218 g_object_set (p
->obj
, p
->spec
->name
, (guint
) adj
->value
, NULL
);
222 uint_changed (GObject
*object
, GParamSpec
*pspec
, gpointer data
)
224 GtkAdjustment
*adj
= GTK_ADJUSTMENT (data
);
227 g_value_init (&val
, G_TYPE_UINT
);
228 get_property_value (object
, pspec
, &val
);
230 if (g_value_get_uint (&val
) != (guint
)adj
->value
)
232 block_controller (G_OBJECT (adj
));
233 gtk_adjustment_set_value (adj
, g_value_get_uint (&val
));
234 unblock_controller (G_OBJECT (adj
));
237 g_value_unset (&val
);
241 float_modified (GtkAdjustment
*adj
, gpointer data
)
243 ObjectProperty
*p
= data
;
245 if (is_child_property (p
->spec
))
247 GtkWidget
*widget
= GTK_WIDGET (p
->obj
);
248 GtkWidget
*parent
= gtk_widget_get_parent (widget
);
250 gtk_container_child_set (GTK_CONTAINER (parent
),
251 widget
, p
->spec
->name
, (float) adj
->value
, NULL
);
254 g_object_set (p
->obj
, p
->spec
->name
, (float) adj
->value
, NULL
);
258 float_changed (GObject
*object
, GParamSpec
*pspec
, gpointer data
)
260 GtkAdjustment
*adj
= GTK_ADJUSTMENT (data
);
263 g_value_init (&val
, G_TYPE_FLOAT
);
264 get_property_value (object
, pspec
, &val
);
266 if (g_value_get_float (&val
) != (float) adj
->value
)
268 block_controller (G_OBJECT (adj
));
269 gtk_adjustment_set_value (adj
, g_value_get_float (&val
));
270 unblock_controller (G_OBJECT (adj
));
273 g_value_unset (&val
);
277 double_modified (GtkAdjustment
*adj
, gpointer data
)
279 ObjectProperty
*p
= data
;
281 if (is_child_property (p
->spec
))
283 GtkWidget
*widget
= GTK_WIDGET (p
->obj
);
284 GtkWidget
*parent
= gtk_widget_get_parent (widget
);
286 gtk_container_child_set (GTK_CONTAINER (parent
),
287 widget
, p
->spec
->name
, (double) adj
->value
, NULL
);
290 g_object_set (p
->obj
, p
->spec
->name
, (double) adj
->value
, NULL
);
294 double_changed (GObject
*object
, GParamSpec
*pspec
, gpointer data
)
296 GtkAdjustment
*adj
= GTK_ADJUSTMENT (data
);
299 g_value_init (&val
, G_TYPE_DOUBLE
);
300 get_property_value (object
, pspec
, &val
);
302 if (g_value_get_double (&val
) != adj
->value
)
304 block_controller (G_OBJECT (adj
));
305 gtk_adjustment_set_value (adj
, g_value_get_double (&val
));
306 unblock_controller (G_OBJECT (adj
));
309 g_value_unset (&val
);
313 string_modified (GtkEntry
*entry
, gpointer data
)
315 ObjectProperty
*p
= data
;
318 text
= gtk_entry_get_text (entry
);
320 if (is_child_property (p
->spec
))
322 GtkWidget
*widget
= GTK_WIDGET (p
->obj
);
323 GtkWidget
*parent
= gtk_widget_get_parent (widget
);
325 gtk_container_child_set (GTK_CONTAINER (parent
),
326 widget
, p
->spec
->name
, text
, NULL
);
329 g_object_set (p
->obj
, p
->spec
->name
, text
, NULL
);
333 string_changed (GObject
*object
, GParamSpec
*pspec
, gpointer data
)
335 GtkEntry
*entry
= GTK_ENTRY (data
);
340 g_value_init (&val
, G_TYPE_STRING
);
341 get_property_value (object
, pspec
, &val
);
343 str
= g_value_get_string (&val
);
346 text
= gtk_entry_get_text (entry
);
348 if (strcmp (str
, text
) != 0)
350 block_controller (G_OBJECT (entry
));
351 gtk_entry_set_text (entry
, str
);
352 unblock_controller (G_OBJECT (entry
));
355 g_value_unset (&val
);
359 bool_modified (GtkToggleButton
*tb
, gpointer data
)
361 ObjectProperty
*p
= data
;
363 if (is_child_property (p
->spec
))
365 GtkWidget
*widget
= GTK_WIDGET (p
->obj
);
366 GtkWidget
*parent
= gtk_widget_get_parent (widget
);
368 gtk_container_child_set (GTK_CONTAINER (parent
),
369 widget
, p
->spec
->name
, (int) tb
->active
, NULL
);
372 g_object_set (p
->obj
, p
->spec
->name
, (int) tb
->active
, NULL
);
376 bool_changed (GObject
*object
, GParamSpec
*pspec
, gpointer data
)
378 GtkToggleButton
*tb
= GTK_TOGGLE_BUTTON (data
);
381 g_value_init (&val
, G_TYPE_BOOLEAN
);
382 get_property_value (object
, pspec
, &val
);
384 if (g_value_get_boolean (&val
) != tb
->active
)
386 block_controller (G_OBJECT (tb
));
387 gtk_toggle_button_set_active (tb
, g_value_get_boolean (&val
));
388 unblock_controller (G_OBJECT (tb
));
391 gtk_label_set_text (GTK_LABEL (GTK_BIN (tb
)->child
), g_value_get_boolean (&val
) ?
394 g_value_unset (&val
);
399 enum_modified (GtkOptionMenu
*om
, gpointer data
)
401 ObjectProperty
*p
= data
;
405 eclass
= G_ENUM_CLASS (g_type_class_peek (p
->spec
->value_type
));
407 i
= gtk_option_menu_get_history (om
);
409 if (is_child_property (p
->spec
))
411 GtkWidget
*widget
= GTK_WIDGET (p
->obj
);
412 GtkWidget
*parent
= gtk_widget_get_parent (widget
);
414 gtk_container_child_set (GTK_CONTAINER (parent
),
415 widget
, p
->spec
->name
, eclass
->values
[i
].value
, NULL
);
418 g_object_set (p
->obj
, p
->spec
->name
, eclass
->values
[i
].value
, NULL
);
422 enum_changed (GObject
*object
, GParamSpec
*pspec
, gpointer data
)
424 GtkOptionMenu
*om
= GTK_OPTION_MENU (data
);
429 eclass
= G_ENUM_CLASS (g_type_class_peek (pspec
->value_type
));
431 g_value_init (&val
, pspec
->value_type
);
432 get_property_value (object
, pspec
, &val
);
435 while (i
< eclass
->n_values
)
437 if (eclass
->values
[i
].value
== g_value_get_enum (&val
))
442 if (gtk_option_menu_get_history (om
) != i
)
444 block_controller (G_OBJECT (om
));
445 gtk_option_menu_set_history (om
, i
);
446 unblock_controller (G_OBJECT (om
));
449 g_value_unset (&val
);
454 flags_modified (GtkCheckButton
*button
, gpointer data
)
456 ObjectProperty
*p
= data
;
462 fclass
= G_FLAGS_CLASS (g_type_class_peek (p
->spec
->value_type
));
464 active
= gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button
));
465 i
= GPOINTER_TO_INT (g_object_get_data (G_OBJECT (button
), "index"));
467 if (is_child_property (p
->spec
))
469 GtkWidget
*widget
= GTK_WIDGET (p
->obj
);
470 GtkWidget
*parent
= gtk_widget_get_parent (widget
);
472 gtk_container_child_get (GTK_CONTAINER (parent
),
473 widget
, p
->spec
->name
, &flags
, NULL
);
475 flags
|= fclass
->values
[i
].value
;
477 flags
&= ~fclass
->values
[i
].value
;
479 gtk_container_child_set (GTK_CONTAINER (parent
),
480 widget
, p
->spec
->name
, flags
, NULL
);
484 g_object_get (p
->obj
, p
->spec
->name
, &flags
, NULL
);
487 flags
|= fclass
->values
[i
].value
;
489 flags
&= ~fclass
->values
[i
].value
;
491 g_object_set (p
->obj
, p
->spec
->name
, flags
, NULL
);
496 flags_changed (GObject
*object
, GParamSpec
*pspec
, gpointer data
)
504 fclass
= G_FLAGS_CLASS (g_type_class_peek (pspec
->value_type
));
506 g_value_init (&val
, pspec
->value_type
);
507 get_property_value (object
, pspec
, &val
);
508 flags
= g_value_get_flags (&val
);
509 g_value_unset (&val
);
511 children
= gtk_container_get_children (GTK_CONTAINER (data
));
513 for (c
= children
, i
= 0; c
; c
= c
->next
, i
++)
515 block_controller (G_OBJECT (c
->data
));
516 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (c
->data
),
517 (fclass
->values
[i
].value
& flags
) != 0);
518 unblock_controller (G_OBJECT (c
->data
));
521 g_list_free (children
);
525 unichar_get_value (GtkEntry
*entry
)
527 const gchar
*text
= gtk_entry_get_text (entry
);
530 return g_utf8_get_char (text
);
536 unichar_modified (GtkEntry
*entry
, gpointer data
)
538 ObjectProperty
*p
= data
;
539 gunichar val
= unichar_get_value (entry
);
541 if (is_child_property (p
->spec
))
543 GtkWidget
*widget
= GTK_WIDGET (p
->obj
);
544 GtkWidget
*parent
= gtk_widget_get_parent (widget
);
546 gtk_container_child_set (GTK_CONTAINER (parent
),
547 widget
, p
->spec
->name
, val
, NULL
);
550 g_object_set (p
->obj
, p
->spec
->name
, val
, NULL
);
554 unichar_changed (GObject
*object
, GParamSpec
*pspec
, gpointer data
)
556 GtkEntry
*entry
= GTK_ENTRY (data
);
558 gunichar old_val
= unichar_get_value (entry
);
563 g_value_init (&val
, pspec
->value_type
);
564 get_property_value (object
, pspec
, &val
);
565 new_val
= (gunichar
)g_value_get_uint (&val
);
567 if (new_val
!= old_val
)
572 len
= g_unichar_to_utf8 (new_val
, buf
);
576 block_controller (G_OBJECT (entry
));
577 gtk_entry_set_text (entry
, buf
);
578 unblock_controller (G_OBJECT (entry
));
583 pointer_changed (GObject
*object
, GParamSpec
*pspec
, gpointer data
)
585 GtkLabel
*label
= GTK_LABEL (data
);
589 g_object_get (object
, pspec
->name
, &ptr
, NULL
);
591 str
= g_strdup_printf ("Pointer: %p", ptr
);
592 gtk_label_set_text (label
, str
);
597 object_label (GObject
*obj
)
602 name
= g_type_name (G_TYPE_FROM_INSTANCE (obj
));
605 return g_strdup_printf ("Object: %p (%s)", obj
, name
);
609 object_changed (GObject
*object
, GParamSpec
*pspec
, gpointer data
)
611 GtkWidget
*label
, *button
;
615 GList
*children
= gtk_container_get_children (GTK_CONTAINER (data
));
616 label
= GTK_WIDGET (children
->data
);
617 button
= GTK_WIDGET (children
->next
->data
);
618 g_object_get (object
, pspec
->name
, &obj
, NULL
);
619 g_list_free (children
);
621 str
= object_label (obj
);
623 gtk_label_set_text (GTK_LABEL (label
), str
);
624 gtk_widget_set_sensitive (button
, G_IS_OBJECT (obj
));
627 g_object_unref (obj
);
633 model_destroy (gpointer data
)
635 g_object_steal_data (data
, "model-object");
636 gtk_widget_destroy (data
);
640 window_destroy (gpointer data
)
642 g_object_steal_data (data
, "prop-editor-win");
646 object_properties (GtkWidget
*button
,
652 name
= (gchar
*) g_object_get_data (G_OBJECT (button
), "property-name");
653 g_object_get (object
, name
, &obj
, NULL
);
654 if (G_IS_OBJECT (obj
))
655 create_prop_editor (obj
, 0);
659 property_widget (GObject
*object
,
663 GtkWidget
*prop_edit
;
666 GType type
= G_PARAM_SPEC_TYPE (spec
);
668 if (type
== G_TYPE_PARAM_INT
)
670 adj
= GTK_ADJUSTMENT (gtk_adjustment_new (G_PARAM_SPEC_INT (spec
)->default_value
,
671 G_PARAM_SPEC_INT (spec
)->minimum
,
672 G_PARAM_SPEC_INT (spec
)->maximum
,
674 MAX ((G_PARAM_SPEC_INT (spec
)->maximum
-
675 G_PARAM_SPEC_INT (spec
)->minimum
) / 10, 1),
678 prop_edit
= gtk_spin_button_new (adj
, 1.0, 0);
680 g_object_connect_property (object
, spec
,
681 G_CALLBACK (int_changed
),
682 adj
, G_OBJECT (adj
));
685 connect_controller (G_OBJECT (adj
), "value_changed",
686 object
, spec
, (GtkSignalFunc
) int_modified
);
688 else if (type
== G_TYPE_PARAM_UINT
)
690 adj
= GTK_ADJUSTMENT (
691 gtk_adjustment_new (G_PARAM_SPEC_UINT (spec
)->default_value
,
692 G_PARAM_SPEC_UINT (spec
)->minimum
,
693 G_PARAM_SPEC_UINT (spec
)->maximum
,
695 MAX ((G_PARAM_SPEC_UINT (spec
)->maximum
-
696 G_PARAM_SPEC_UINT (spec
)->minimum
) / 10, 1),
699 prop_edit
= gtk_spin_button_new (adj
, 1.0, 0);
701 g_object_connect_property (object
, spec
,
702 G_CALLBACK (uint_changed
),
703 adj
, G_OBJECT (adj
));
706 connect_controller (G_OBJECT (adj
), "value_changed",
707 object
, spec
, (GtkSignalFunc
) uint_modified
);
709 else if (type
== G_TYPE_PARAM_FLOAT
)
712 adj
= GTK_ADJUSTMENT (gtk_adjustment_new (G_PARAM_SPEC_FLOAT (spec
)->default_value
,
713 G_PARAM_SPEC_FLOAT (spec
)->minimum
,
714 G_PARAM_SPEC_FLOAT (spec
)->maximum
,
716 MAX ((G_PARAM_SPEC_FLOAT (spec
)->maximum
-
717 G_PARAM_SPEC_FLOAT (spec
)->minimum
) / 10, 0.1),
720 prop_edit
= gtk_spin_button_new (adj
, 0.1, 2);
722 g_object_connect_property (object
, spec
,
723 G_CALLBACK (float_changed
),
724 adj
, G_OBJECT (adj
));
727 connect_controller (G_OBJECT (adj
), "value_changed",
728 object
, spec
, (GtkSignalFunc
) float_modified
);
730 else if (type
== G_TYPE_PARAM_DOUBLE
)
732 adj
= GTK_ADJUSTMENT (gtk_adjustment_new (G_PARAM_SPEC_DOUBLE (spec
)->default_value
,
733 G_PARAM_SPEC_DOUBLE (spec
)->minimum
,
734 G_PARAM_SPEC_DOUBLE (spec
)->maximum
,
736 MAX ((G_PARAM_SPEC_DOUBLE (spec
)->maximum
-
737 G_PARAM_SPEC_DOUBLE (spec
)->minimum
) / 10, 0.1),
740 prop_edit
= gtk_spin_button_new (adj
, 0.1, 2);
742 g_object_connect_property (object
, spec
,
743 G_CALLBACK (double_changed
),
744 adj
, G_OBJECT (adj
));
747 connect_controller (G_OBJECT (adj
), "value_changed",
748 object
, spec
, (GtkSignalFunc
) double_modified
);
750 else if (type
== G_TYPE_PARAM_STRING
)
752 prop_edit
= gtk_entry_new ();
754 g_object_connect_property (object
, spec
,
755 G_CALLBACK (string_changed
),
756 prop_edit
, G_OBJECT (prop_edit
));
759 connect_controller (G_OBJECT (prop_edit
), "changed",
760 object
, spec
, (GtkSignalFunc
) string_modified
);
762 else if (type
== G_TYPE_PARAM_BOOLEAN
)
764 prop_edit
= gtk_toggle_button_new_with_label ("");
766 g_object_connect_property (object
, spec
,
767 G_CALLBACK (bool_changed
),
768 prop_edit
, G_OBJECT (prop_edit
));
771 connect_controller (G_OBJECT (prop_edit
), "toggled",
772 object
, spec
, (GtkSignalFunc
) bool_modified
);
774 else if (type
== G_TYPE_PARAM_ENUM
)
781 prop_edit
= gtk_option_menu_new ();
783 menu
= gtk_menu_new ();
785 eclass
= G_ENUM_CLASS (g_type_class_ref (spec
->value_type
));
788 while (j
< eclass
->n_values
)
792 mi
= gtk_menu_item_new_with_label (eclass
->values
[j
].value_name
);
794 gtk_widget_show (mi
);
796 gtk_menu_shell_append (GTK_MENU_SHELL (menu
), mi
);
801 g_type_class_unref (eclass
);
803 gtk_option_menu_set_menu (GTK_OPTION_MENU (prop_edit
), menu
);
805 g_object_connect_property (object
, spec
,
806 G_CALLBACK (enum_changed
),
807 prop_edit
, G_OBJECT (prop_edit
));
810 connect_controller (G_OBJECT (prop_edit
), "changed",
811 object
, spec
, (GtkSignalFunc
) enum_modified
);
814 else if (type
== G_TYPE_PARAM_FLAGS
)
820 prop_edit
= gtk_vbox_new (FALSE
, 0);
822 fclass
= G_FLAGS_CLASS (g_type_class_ref (spec
->value_type
));
824 for (j
= 0; j
< fclass
->n_values
; j
++)
828 b
= gtk_check_button_new_with_label (fclass
->values
[j
].value_name
);
829 g_object_set_data (G_OBJECT (b
), "index", GINT_TO_POINTER (j
));
831 gtk_box_pack_start (GTK_BOX (prop_edit
), b
, FALSE
, FALSE
, 0);
833 connect_controller (G_OBJECT (b
), "toggled",
834 object
, spec
, (GtkSignalFunc
) flags_modified
);
837 g_type_class_unref (fclass
);
839 g_object_connect_property (object
, spec
,
840 G_CALLBACK (flags_changed
),
841 prop_edit
, G_OBJECT (prop_edit
));
844 else if (type
== G_TYPE_PARAM_UNICHAR
)
846 prop_edit
= gtk_entry_new ();
847 gtk_entry_set_max_length (GTK_ENTRY (prop_edit
), 1);
849 g_object_connect_property (object
, spec
,
850 G_CALLBACK (unichar_changed
),
851 prop_edit
, G_OBJECT (prop_edit
));
854 connect_controller (G_OBJECT (prop_edit
), "changed",
855 object
, spec
, (GtkSignalFunc
) unichar_modified
);
857 else if (type
== G_TYPE_PARAM_POINTER
)
859 prop_edit
= gtk_label_new ("");
861 g_object_connect_property (object
, spec
,
862 G_CALLBACK (pointer_changed
),
863 prop_edit
, G_OBJECT (prop_edit
));
865 else if (type
== G_TYPE_PARAM_OBJECT
)
867 GtkWidget
*label
, *button
;
869 prop_edit
= gtk_hbox_new (FALSE
, 5);
871 label
= gtk_label_new ("");
872 button
= gtk_button_new_with_label ("Properties");
873 g_object_set_data (G_OBJECT (button
), "property-name", spec
->name
);
874 g_signal_connect (button
, "clicked",
875 G_CALLBACK (object_properties
),
878 gtk_container_add (GTK_CONTAINER (prop_edit
), label
);
879 gtk_container_add (GTK_CONTAINER (prop_edit
), button
);
881 g_object_connect_property (object
, spec
,
882 G_CALLBACK (object_changed
),
883 prop_edit
, G_OBJECT (label
));
887 msg
= g_strdup_printf ("uneditable property type: %s",
888 g_type_name (G_PARAM_SPEC_TYPE (spec
)));
889 prop_edit
= gtk_label_new (msg
);
891 gtk_misc_set_alignment (GTK_MISC (prop_edit
), 0.0, 0.5);
898 properties_from_type (GObject
*object
,
902 GtkWidget
*prop_edit
;
911 if (G_TYPE_IS_INTERFACE (type
))
913 gpointer vtable
= g_type_default_interface_peek (type
);
914 specs
= g_object_interface_list_properties (vtable
, &n_specs
);
918 GObjectClass
*class = G_OBJECT_CLASS (g_type_class_peek (type
));
919 specs
= g_object_class_list_properties (class, &n_specs
);
927 table
= gtk_table_new (n_specs
, 2, FALSE
);
928 gtk_table_set_col_spacing (GTK_TABLE (table
), 0, 10);
929 gtk_table_set_row_spacings (GTK_TABLE (table
), 3);
934 GParamSpec
*spec
= specs
[i
];
939 can_modify
= ((spec
->flags
& G_PARAM_WRITABLE
) != 0 &&
940 (spec
->flags
& G_PARAM_CONSTRUCT_ONLY
) == 0);
942 if ((spec
->flags
& G_PARAM_READABLE
) == 0)
944 /* can't display unreadable properties */
949 if (spec
->owner_type
!= type
)
951 /* we're only interested in params of type */
956 label
= gtk_label_new (g_param_spec_get_nick (spec
));
957 gtk_misc_set_alignment (GTK_MISC (label
), 0.0, 0.5);
958 gtk_table_attach_defaults (GTK_TABLE (table
), label
, 0, 1, i
, i
+ 1);
960 prop_edit
= property_widget (object
, spec
, can_modify
);
961 gtk_table_attach_defaults (GTK_TABLE (table
), prop_edit
, 1, 2, i
, i
+ 1);
966 gtk_widget_set_sensitive (prop_edit
, FALSE
);
968 if (g_param_spec_get_blurb (spec
))
969 gtk_tooltips_set_tip (tips
, prop_edit
, g_param_spec_get_blurb (spec
), NULL
);
971 /* set initial value */
972 g_object_notify (object
, spec
->name
);
979 vbox
= gtk_vbox_new (FALSE
, 0);
980 gtk_box_pack_start (GTK_BOX (vbox
), table
, FALSE
, FALSE
, 0);
982 sw
= gtk_scrolled_window_new (NULL
, NULL
);
983 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw
),
984 GTK_POLICY_NEVER
, GTK_POLICY_AUTOMATIC
);
986 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (sw
), vbox
);
994 child_properties_from_object (GObject
*object
,
997 GtkWidget
*prop_edit
;
1007 if (!GTK_IS_WIDGET (object
))
1010 parent
= gtk_widget_get_parent (GTK_WIDGET (object
));
1015 specs
= gtk_container_class_list_child_properties (G_OBJECT_GET_CLASS (parent
), &n_specs
);
1017 table
= gtk_table_new (n_specs
, 2, FALSE
);
1018 gtk_table_set_col_spacing (GTK_TABLE (table
), 0, 10);
1019 gtk_table_set_row_spacings (GTK_TABLE (table
), 3);
1024 GParamSpec
*spec
= specs
[i
];
1025 gboolean can_modify
;
1029 can_modify
= ((spec
->flags
& G_PARAM_WRITABLE
) != 0 &&
1030 (spec
->flags
& G_PARAM_CONSTRUCT_ONLY
) == 0);
1032 if ((spec
->flags
& G_PARAM_READABLE
) == 0)
1034 /* can't display unreadable properties */
1039 label
= gtk_label_new (g_param_spec_get_nick (spec
));
1040 gtk_misc_set_alignment (GTK_MISC (label
), 0.0, 0.5);
1041 gtk_table_attach_defaults (GTK_TABLE (table
), label
, 0, 1, i
, i
+ 1);
1043 mark_child_property (spec
);
1044 prop_edit
= property_widget (object
, spec
, can_modify
);
1045 gtk_table_attach_defaults (GTK_TABLE (table
), prop_edit
, 1, 2, i
, i
+ 1);
1050 gtk_widget_set_sensitive (prop_edit
, FALSE
);
1052 if (g_param_spec_get_blurb (spec
))
1053 gtk_tooltips_set_tip (tips
, prop_edit
, g_param_spec_get_blurb (spec
), NULL
);
1055 /* set initial value */
1056 gtk_widget_child_notify (GTK_WIDGET (object
), spec
->name
);
1062 vbox
= gtk_vbox_new (FALSE
, 0);
1063 gtk_box_pack_start (GTK_BOX (vbox
), table
, FALSE
, FALSE
, 0);
1065 sw
= gtk_scrolled_window_new (NULL
, NULL
);
1066 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw
),
1067 GTK_POLICY_NEVER
, GTK_POLICY_AUTOMATIC
);
1069 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (sw
), vbox
);
1077 child_properties (GtkWidget
*button
,
1080 create_prop_editor (object
, 0);
1084 children_from_object (GObject
*object
,
1087 GList
*children
, *c
;
1088 GtkWidget
*table
, *label
, *prop_edit
, *button
, *vbox
, *sw
;
1092 if (!GTK_IS_CONTAINER (object
))
1095 children
= gtk_container_get_children (GTK_CONTAINER (object
));
1097 table
= gtk_table_new (g_list_length (children
), 2, FALSE
);
1098 gtk_table_set_col_spacing (GTK_TABLE (table
), 0, 10);
1099 gtk_table_set_row_spacings (GTK_TABLE (table
), 3);
1101 for (c
= children
, i
= 0; c
; c
= c
->next
, i
++)
1105 label
= gtk_label_new ("Child");
1106 gtk_misc_set_alignment (GTK_MISC (label
), 0.0, 0.5);
1107 gtk_table_attach_defaults (GTK_TABLE (table
), label
, 0, 1, i
, i
+ 1);
1109 prop_edit
= gtk_hbox_new (FALSE
, 5);
1111 str
= object_label (object
);
1112 label
= gtk_label_new (str
);
1114 button
= gtk_button_new_with_label ("Properties");
1115 g_signal_connect (button
, "clicked",
1116 G_CALLBACK (child_properties
),
1119 gtk_container_add (GTK_CONTAINER (prop_edit
), label
);
1120 gtk_container_add (GTK_CONTAINER (prop_edit
), button
);
1122 gtk_table_attach_defaults (GTK_TABLE (table
), prop_edit
, 1, 2, i
, i
+ 1);
1125 vbox
= gtk_vbox_new (FALSE
, 0);
1126 gtk_box_pack_start (GTK_BOX (vbox
), table
, FALSE
, FALSE
, 0);
1128 sw
= gtk_scrolled_window_new (NULL
, NULL
);
1129 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw
),
1130 GTK_POLICY_NEVER
, GTK_POLICY_AUTOMATIC
);
1132 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (sw
), vbox
);
1134 g_list_free (children
);
1140 cells_from_object (GObject
*object
,
1144 GtkWidget
*table
, *label
, *prop_edit
, *button
, *vbox
, *sw
;
1148 if (!GTK_IS_CELL_LAYOUT (object
))
1151 cells
= gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (object
));
1153 table
= gtk_table_new (g_list_length (cells
), 2, FALSE
);
1154 gtk_table_set_col_spacing (GTK_TABLE (table
), 0, 10);
1155 gtk_table_set_row_spacings (GTK_TABLE (table
), 3);
1157 for (c
= cells
, i
= 0; c
; c
= c
->next
, i
++)
1161 label
= gtk_label_new ("Cell");
1162 gtk_misc_set_alignment (GTK_MISC (label
), 0.0, 0.5);
1163 gtk_table_attach_defaults (GTK_TABLE (table
), label
, 0, 1, i
, i
+ 1);
1165 prop_edit
= gtk_hbox_new (FALSE
, 5);
1167 str
= object_label (object
);
1168 label
= gtk_label_new (str
);
1170 button
= gtk_button_new_with_label ("Properties");
1171 g_signal_connect (button
, "clicked",
1172 G_CALLBACK (child_properties
),
1175 gtk_container_add (GTK_CONTAINER (prop_edit
), label
);
1176 gtk_container_add (GTK_CONTAINER (prop_edit
), button
);
1178 gtk_table_attach_defaults (GTK_TABLE (table
), prop_edit
, 1, 2, i
, i
+ 1);
1181 vbox
= gtk_vbox_new (FALSE
, 0);
1182 gtk_box_pack_start (GTK_BOX (vbox
), table
, FALSE
, FALSE
, 0);
1184 sw
= gtk_scrolled_window_new (NULL
, NULL
);
1185 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw
),
1186 GTK_POLICY_NEVER
, GTK_POLICY_AUTOMATIC
);
1188 gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (sw
), vbox
);
1190 g_list_free (cells
);
1195 kill_tips (GtkWindow
*win
, GtkObject
*tips
)
1197 gtk_object_destroy (tips
);
1198 g_object_unref (tips
);
1201 /* Pass zero for type if you want all properties */
1203 create_prop_editor (GObject
*object
,
1207 GtkWidget
*notebook
;
1209 GtkWidget
*properties
;
1215 if ((win
= g_object_get_data (G_OBJECT (object
), "prop-editor-win")))
1217 gtk_window_present (GTK_WINDOW (win
));
1221 win
= gtk_window_new (GTK_WINDOW_TOPLEVEL
);
1222 if (GTK_IS_WIDGET (object
))
1223 gtk_window_set_screen (GTK_WINDOW (win
),
1224 gtk_widget_get_screen (GTK_WIDGET (object
)));
1226 tips
= gtk_tooltips_new ();
1227 g_object_ref (tips
);
1228 gtk_object_sink (GTK_OBJECT (tips
));
1230 /* Kill the tips when the widget goes away. */
1231 g_signal_connect (win
, "destroy", G_CALLBACK (kill_tips
), tips
);
1233 /* hold a weak ref to the object we're editing */
1234 g_object_set_data_full (G_OBJECT (object
), "prop-editor-win", win
, model_destroy
);
1235 g_object_set_data_full (G_OBJECT (win
), "model-object", object
, window_destroy
);
1239 notebook
= gtk_notebook_new ();
1240 gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook
), GTK_POS_LEFT
);
1242 gtk_container_add (GTK_CONTAINER (win
), notebook
);
1244 type
= G_TYPE_FROM_INSTANCE (object
);
1246 title
= g_strdup_printf ("Properties of %s widget", g_type_name (type
));
1247 gtk_window_set_title (GTK_WINDOW (win
), title
);
1252 properties
= properties_from_type (object
, type
, tips
);
1255 label
= gtk_label_new (g_type_name (type
));
1256 gtk_notebook_append_page (GTK_NOTEBOOK (notebook
),
1260 type
= g_type_parent (type
);
1263 ifaces
= g_type_interfaces (G_TYPE_FROM_INSTANCE (object
), &n_ifaces
);
1266 properties
= properties_from_type (object
, ifaces
[n_ifaces
], tips
);
1269 label
= gtk_label_new (g_type_name (ifaces
[n_ifaces
]));
1270 gtk_notebook_append_page (GTK_NOTEBOOK (notebook
),
1277 properties
= child_properties_from_object (object
, tips
);
1280 label
= gtk_label_new ("Child properties");
1281 gtk_notebook_append_page (GTK_NOTEBOOK (notebook
),
1285 properties
= children_from_object (object
, tips
);
1288 label
= gtk_label_new ("Children");
1289 gtk_notebook_append_page (GTK_NOTEBOOK (notebook
),
1293 properties
= cells_from_object (object
, tips
);
1296 label
= gtk_label_new ("Cell renderers");
1297 gtk_notebook_append_page (GTK_NOTEBOOK (notebook
),
1303 properties
= properties_from_type (object
, type
, tips
);
1304 gtk_container_add (GTK_CONTAINER (win
), properties
);
1305 title
= g_strdup_printf ("Properties of %s", g_type_name (type
));
1306 gtk_window_set_title (GTK_WINDOW (win
), title
);
1310 gtk_window_set_default_size (GTK_WINDOW (win
), -1, 400);
1312 gtk_widget_show_all (win
);