diff options
author | Matthias Clasen <mclasen@redhat.com> | 2019-02-13 20:16:33 -0500 |
---|---|---|
committer | Matthias Clasen <mclasen@redhat.com> | 2019-02-17 23:07:17 -0500 |
commit | 7325f8e2048152974a16107dfa749b171c9fa374 (patch) | |
tree | ecd32432e0eb479b1277a361f36610321dc2a3c2 /gtk/gtkeditable.c | |
parent | 76be7a50258de62048e21e3e54e8168f8125c60b (diff) | |
download | gtk+-7325f8e2048152974a16107dfa749b171c9fa374.tar.gz |
editable: Add more to interface
Add all the things to the GtkEditable interface that
make sense for most implementations.
Diffstat (limited to 'gtk/gtkeditable.c')
-rw-r--r-- | gtk/gtkeditable.c | 848 |
1 files changed, 671 insertions, 177 deletions
diff --git a/gtk/gtkeditable.c b/gtk/gtkeditable.c index 50d0df44ba..3ebc45d159 100644 --- a/gtk/gtkeditable.c +++ b/gtk/gtkeditable.c @@ -44,12 +44,12 @@ * * void * insert_text_handler (GtkEditable *editable, - * const gchar *text, - * gint length, - * gint *position, + * const char *text, + * int length, + * int *position, * gpointer data) * { - * gchar *result = g_utf8_strup (text, length); + * char *result = g_utf8_strup (text, length); * * g_signal_handlers_block_by_func (editable, * (gpointer) insert_text_handler, data); @@ -68,129 +68,267 @@ #include <string.h> #include "gtkeditable.h" +#include "gtkentrybuffer.h" #include "gtkmarshalers.h" #include "gtkintl.h" +#include "gtkprivate.h" +G_DEFINE_INTERFACE (GtkEditable, gtk_editable, GTK_TYPE_WIDGET) -static void gtk_editable_base_init (gpointer g_class); +static GQuark quark_editable_data; +static GtkEditable * +get_delegate (GtkEditable *editable) +{ + GtkEditableInterface *iface = GTK_EDITABLE_GET_IFACE (editable); + + if (iface->get_delegate) + return iface->get_delegate (editable); + + return NULL; +} -GType -gtk_editable_get_type (void) +static void +gtk_editable_default_do_insert_text (GtkEditable *editable, + const char *text, + int length, + int *position) { - static GType editable_type = 0; + g_signal_emit_by_name (editable, "insert-text", text, length, position); +} - if (!editable_type) - { - const GTypeInfo editable_info = - { - sizeof (GtkEditableInterface), /* class_size */ - gtk_editable_base_init, /* base_init */ - NULL, /* base_finalize */ - }; - - editable_type = g_type_register_static (G_TYPE_INTERFACE, I_("GtkEditable"), - &editable_info, 0); - } +#define warn_no_delegate(func) \ + g_critical ("GtkEditable %s: default implementation called without a delegate", func); + +static void +gtk_editable_default_insert_text (GtkEditable *editable, + const char *text, + int length, + int *position) +{ + GtkEditable *delegate = get_delegate (editable); - return editable_type; + if (delegate) + gtk_editable_insert_text (delegate, text, length, position); + else + warn_no_delegate ("insert_text"); } static void -gtk_editable_base_init (gpointer g_class) +gtk_editable_default_do_delete_text (GtkEditable *editable, + int start_pos, + int end_pos) { - static gboolean initialized = FALSE; + g_signal_emit_by_name (editable, "delete-text", start_pos, end_pos); +} - if (! initialized) - { - /** - * GtkEditable::insert-text: - * @editable: the object which received the signal - * @new_text: the new text to insert - * @new_text_length: the length of the new text, in bytes, - * or -1 if new_text is nul-terminated - * @position: (inout) (type int): the position, in characters, - * at which to insert the new text. this is an in-out - * parameter. After the signal emission is finished, it - * should point after the newly inserted text. - * - * This signal is emitted when text is inserted into - * the widget by the user. The default handler for - * this signal will normally be responsible for inserting - * the text, so by connecting to this signal and then - * stopping the signal with g_signal_stop_emission(), it - * is possible to modify the inserted text, or prevent - * it from being inserted entirely. - */ - g_signal_new (I_("insert-text"), - GTK_TYPE_EDITABLE, - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GtkEditableInterface, insert_text), - NULL, NULL, - _gtk_marshal_VOID__STRING_INT_POINTER, - G_TYPE_NONE, 3, - G_TYPE_STRING, - G_TYPE_INT, - G_TYPE_POINTER); - - /** - * GtkEditable::delete-text: - * @editable: the object which received the signal - * @start_pos: the starting position - * @end_pos: the end position - * - * This signal is emitted when text is deleted from - * the widget by the user. The default handler for - * this signal will normally be responsible for deleting - * the text, so by connecting to this signal and then - * stopping the signal with g_signal_stop_emission(), it - * is possible to modify the range of deleted text, or - * prevent it from being deleted entirely. The @start_pos - * and @end_pos parameters are interpreted as for - * gtk_editable_delete_text(). - */ - g_signal_new (I_("delete-text"), - GTK_TYPE_EDITABLE, - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GtkEditableInterface, delete_text), - NULL, NULL, - _gtk_marshal_VOID__INT_INT, - G_TYPE_NONE, 2, - G_TYPE_INT, - G_TYPE_INT); - /** - * GtkEditable::changed: - * @editable: the object which received the signal - * - * The ::changed signal is emitted at the end of a single - * user-visible operation on the contents of the #GtkEditable. - * - * E.g., a paste operation that replaces the contents of the - * selection will cause only one signal emission (even though it - * is implemented by first deleting the selection, then inserting - * the new content, and may cause multiple ::notify::text signals - * to be emitted). - */ - g_signal_new (I_("changed"), - GTK_TYPE_EDITABLE, - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GtkEditableInterface, changed), - NULL, NULL, - NULL, - G_TYPE_NONE, 0); - - initialized = TRUE; - } +static void +gtk_editable_default_delete_text (GtkEditable *editable, + int start_pos, + int end_pos) +{ + GtkEditable *delegate = get_delegate (editable); + + if (delegate) + gtk_editable_delete_text (delegate, start_pos, end_pos); + else + warn_no_delegate ("delete_text"); +} + +static const char * +gtk_editable_default_get_text (GtkEditable *editable) +{ + GtkEditable *delegate = get_delegate (editable); + + if (delegate) + return gtk_editable_get_text (delegate); + else + warn_no_delegate ("get_text"); + + return NULL; +} + +static void +gtk_editable_default_set_selection_bounds (GtkEditable *editable, + int start_pos, + int end_pos) +{ + GtkEditable *delegate = get_delegate (editable); + + if (delegate) + gtk_editable_select_region (delegate, start_pos, end_pos); + else + warn_no_delegate ("select_region"); +} + +static gboolean +gtk_editable_default_get_selection_bounds (GtkEditable *editable, + int *start_pos, + int *end_pos) +{ + GtkEditable *delegate = get_delegate (editable); + + if (delegate) + return gtk_editable_get_selection_bounds (delegate, start_pos, end_pos); + else + warn_no_delegate ("select_region"); + + return FALSE; +} + +static void +gtk_editable_default_init (GtkEditableInterface *iface) +{ + quark_editable_data = g_quark_from_static_string ("GtkEditable-data"); + + iface->insert_text = gtk_editable_default_insert_text; + iface->delete_text = gtk_editable_default_delete_text; + iface->get_text = gtk_editable_default_get_text; + iface->do_insert_text = gtk_editable_default_do_insert_text; + iface->do_delete_text = gtk_editable_default_do_delete_text; + iface->get_selection_bounds = gtk_editable_default_get_selection_bounds; + iface->set_selection_bounds = gtk_editable_default_set_selection_bounds; + + /** + * GtkEditable::insert-text: + * @editable: the object which received the signal + * @text: the new text to insert + * @length: the length of the new text, in bytes, + * or -1 if new_text is nul-terminated + * @position: (inout) (type int): the position, in characters, + * at which to insert the new text. this is an in-out + * parameter. After the signal emission is finished, it + * should point after the newly inserted text. + * + * This signal is emitted when text is inserted into + * the widget by the user. The default handler for + * this signal will normally be responsible for inserting + * the text, so by connecting to this signal and then + * stopping the signal with g_signal_stop_emission(), it + * is possible to modify the inserted text, or prevent + * it from being inserted entirely. + */ + g_signal_new (I_("insert-text"), + GTK_TYPE_EDITABLE, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GtkEditableInterface, insert_text), + NULL, NULL, + _gtk_marshal_VOID__STRING_INT_POINTER, + G_TYPE_NONE, 3, + G_TYPE_STRING, + G_TYPE_INT, + G_TYPE_POINTER); + + /** + * GtkEditable::delete-text: + * @editable: the object which received the signal + * @start_pos: the starting position + * @end_pos: the end position + * + * This signal is emitted when text is deleted from + * the widget by the user. The default handler for + * this signal will normally be responsible for deleting + * the text, so by connecting to this signal and then + * stopping the signal with g_signal_stop_emission(), it + * is possible to modify the range of deleted text, or + * prevent it from being deleted entirely. The @start_pos + * and @end_pos parameters are interpreted as for + * gtk_editable_delete_text(). + */ + g_signal_new (I_("delete-text"), + GTK_TYPE_EDITABLE, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GtkEditableInterface, delete_text), + NULL, NULL, + _gtk_marshal_VOID__INT_INT, + G_TYPE_NONE, 2, + G_TYPE_INT, + G_TYPE_INT); + + /** + * GtkEditable::changed: + * @editable: the object which received the signal + * + * The ::changed signal is emitted at the end of a single + * user-visible operation on the contents of the #GtkEditable. + * + * E.g., a paste operation that replaces the contents of the + * selection will cause only one signal emission (even though it + * is implemented by first deleting the selection, then inserting + * the new content, and may cause multiple ::notify::text signals + * to be emitted). + */ + g_signal_new (I_("changed"), + GTK_TYPE_EDITABLE, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GtkEditableInterface, changed), + NULL, NULL, + NULL, + G_TYPE_NONE, 0); + + g_object_interface_install_property (iface, + g_param_spec_string ("text", + P_("Text"), + P_("The contents of the entry"), + "", + GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY)); + + g_object_interface_install_property (iface, + g_param_spec_int ("cursor-position", + P_("Cursor Position"), + P_("The current position of the insertion cursor in chars"), + 0, GTK_ENTRY_BUFFER_MAX_SIZE, + 0, + GTK_PARAM_READABLE)); + + g_object_interface_install_property (iface, + g_param_spec_int ("selection-bound", + P_("Selection Bound"), + P_("The position of the opposite end of the selection from the cursor in chars"), + 0, GTK_ENTRY_BUFFER_MAX_SIZE, + 0, + GTK_PARAM_READABLE)); + + g_object_interface_install_property (iface, + g_param_spec_boolean ("editable", + P_("Editable"), + P_("Whether the entry contents can be edited"), + TRUE, + GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY)); + + g_object_interface_install_property (iface, + g_param_spec_int ("width-chars", + P_("Width in chars"), + P_("Number of characters to leave space for in the entry"), + -1, G_MAXINT, + -1, + GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY)); + + g_object_interface_install_property (iface, + g_param_spec_int ("max-width-chars", + P_("Maximum width in characters"), + P_("The desired maximum width of the entry, in characters"), + -1, G_MAXINT, + -1, + GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY)); + + g_object_interface_install_property (iface, + g_param_spec_float ("xalign", + P_("X align"), + P_("The horizontal alignment, from 0 (left) to 1 (right). Reversed for RTL layouts."), + 0.0, 1.0, + 0.0, + GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY)); } /** * gtk_editable_insert_text: (virtual do_insert_text) * @editable: a #GtkEditable - * @new_text: the text to append - * @new_text_length: the length of the text in bytes, or -1 + * @text: the text to append + * @length: the length of the text in bytes, or -1 * @position: (inout): location of the position text will be inserted at * - * Inserts @new_text_length bytes of @new_text into the contents of the + * Inserts @length bytes of @text into the contents of the * widget, at position @position. * * Note that the position is in characters, not in bytes. @@ -198,17 +336,17 @@ gtk_editable_base_init (gpointer g_class) */ void gtk_editable_insert_text (GtkEditable *editable, - const gchar *new_text, - gint new_text_length, - gint *position) + const char *text, + int length, + int *position) { g_return_if_fail (GTK_IS_EDITABLE (editable)); g_return_if_fail (position != NULL); - if (new_text_length < 0) - new_text_length = strlen (new_text); + if (length < 0) + length = strlen (text); - GTK_EDITABLE_GET_IFACE (editable)->do_insert_text (editable, new_text, new_text_length, position); + GTK_EDITABLE_GET_IFACE (editable)->do_insert_text (editable, text, length, position); } /** @@ -226,8 +364,8 @@ gtk_editable_insert_text (GtkEditable *editable, */ void gtk_editable_delete_text (GtkEditable *editable, - gint start_pos, - gint end_pos) + int start_pos, + int end_pos) { g_return_if_fail (GTK_IS_EDITABLE (editable)); @@ -247,18 +385,73 @@ gtk_editable_delete_text (GtkEditable *editable, * * Note that positions are specified in characters, not bytes. * - * Returns: a pointer to the contents of the widget as a + * Returns: (transfer full): a pointer to the contents of the widget as a * string. This string is allocated by the #GtkEditable * implementation and should be freed by the caller. */ -gchar * +char * gtk_editable_get_chars (GtkEditable *editable, - gint start_pos, - gint end_pos) + int start_pos, + int end_pos) { + const char *text; + int length; + int start_index,end_index; + g_return_val_if_fail (GTK_IS_EDITABLE (editable), NULL); - return GTK_EDITABLE_GET_IFACE (editable)->get_chars (editable, start_pos, end_pos); + text = GTK_EDITABLE_GET_IFACE (editable)->get_text (editable); + length = g_utf8_strlen (text, -1); + + if (end_pos < 0) + end_pos = length; + + start_pos = MIN (length, start_pos); + end_pos = MIN (length, end_pos); + + start_index = g_utf8_offset_to_pointer (text, start_pos) - text; + end_index = g_utf8_offset_to_pointer (text, end_pos) - text; + + return g_strndup (text + start_index, end_index - start_index); +} + +/** + * gtk_editable_get_text: + * @editable: a #GtkEditable + * + * Retrieves the contents of @editable. The returned string is + * owned by GTK and must not be modified or freed. + * + * Returns: (transfer none): a pointer to the contents of the editable. + */ +const char * +gtk_editable_get_text (GtkEditable *editable) +{ + g_return_val_if_fail (GTK_IS_EDITABLE (editable), NULL); + + return GTK_EDITABLE_GET_IFACE (editable)->get_text (editable); +} + +/** + * gtk_editable_set_text: + * @editable: a #GtkEditable + * + * Sets the text in the editable to the given value, + * replacing the current contents. + */ +void +gtk_editable_set_text (GtkEditable *editable, + const char *text) +{ + int pos; + + g_return_if_fail (GTK_IS_EDITABLE (editable)); + + g_object_freeze_notify (G_OBJECT (editable)); + gtk_editable_delete_text (editable, 0, -1); + pos = 0; + gtk_editable_insert_text (editable, text, -1, &pos); + g_object_thaw_notify (G_OBJECT (editable)); } /** @@ -275,12 +468,12 @@ gtk_editable_get_chars (GtkEditable *editable, * of the editable. Note that @position is in characters, not in bytes. */ void -gtk_editable_set_position (GtkEditable *editable, - gint position) +gtk_editable_set_position (GtkEditable *editable, + int position) { g_return_if_fail (GTK_IS_EDITABLE (editable)); - GTK_EDITABLE_GET_IFACE (editable)->set_position (editable, position); + GTK_EDITABLE_GET_IFACE (editable)->set_selection_bounds (editable, position, position); } /** @@ -294,12 +487,16 @@ gtk_editable_set_position (GtkEditable *editable, * * Returns: the cursor position */ -gint +int gtk_editable_get_position (GtkEditable *editable) { + int start, end; + g_return_val_if_fail (GTK_IS_EDITABLE (editable), 0); - return GTK_EDITABLE_GET_IFACE (editable)->get_position (editable); + GTK_EDITABLE_GET_IFACE (editable)->get_selection_bounds (editable, &start, &end); + + return end; } /** @@ -308,20 +505,22 @@ gtk_editable_get_position (GtkEditable *editable) * @start_pos: (out) (allow-none): location to store the starting position, or %NULL * @end_pos: (out) (allow-none): location to store the end position, or %NULL * - * Retrieves the selection bound of the editable. start_pos will be filled - * with the start of the selection and @end_pos with end. If no text was - * selected both will be identical and %FALSE will be returned. + * Retrieves the selection bound of the editable. + * + * @start_pos will be filled with the start of the selection and + * @end_pos with end. If no text was selected both will be identical + * and %FALSE will be returned. * * Note that positions are specified in characters, not bytes. * - * Returns: %TRUE if an area is selected, %FALSE otherwise + * Returns: %TRUE if there is a non-empty selection, %FALSE otherwise */ gboolean gtk_editable_get_selection_bounds (GtkEditable *editable, - gint *start_pos, - gint *end_pos) + int *start_pos, + int *end_pos) { - gint tmp_start, tmp_end; + int tmp_start, tmp_end; gboolean result; g_return_val_if_fail (GTK_IS_EDITABLE (editable), FALSE); @@ -346,7 +545,7 @@ gtk_editable_get_selection_bounds (GtkEditable *editable, void gtk_editable_delete_selection (GtkEditable *editable) { - gint start, end; + int start, end; g_return_if_fail (GTK_IS_EDITABLE (editable)); @@ -360,18 +559,19 @@ gtk_editable_delete_selection (GtkEditable *editable) * @start_pos: start of region * @end_pos: end of region * - * Selects a region of text. The characters that are selected are - * those characters at positions from @start_pos up to, but not - * including @end_pos. If @end_pos is negative, then the - * characters selected are those characters from @start_pos to - * the end of the text. + * Selects a region of text. + * + * The characters that are selected are those characters at positions + * from @start_pos up to, but not including @end_pos. If @end_pos is + * negative, then the characters selected are those characters from + * @start_pos to the end of the text. * * Note that positions are specified in characters, not bytes. */ void gtk_editable_select_region (GtkEditable *editable, - gint start_pos, - gint end_pos) + int start_pos, + int end_pos) { g_return_if_fail (GTK_IS_EDITABLE (editable)); @@ -379,87 +579,381 @@ gtk_editable_select_region (GtkEditable *editable, } /** - * gtk_editable_cut_clipboard: + * gtk_editable_set_editable: * @editable: a #GtkEditable + * @is_editable: %TRUE if the user is allowed to edit the text + * in the widget * - * Removes the contents of the currently selected content in the editable and - * puts it on the clipboard. + * Determines if the user can edit the text + * in the editable widget or not. */ void -gtk_editable_cut_clipboard (GtkEditable *editable) +gtk_editable_set_editable (GtkEditable *editable, + gboolean is_editable) { g_return_if_fail (GTK_IS_EDITABLE (editable)); - - g_signal_emit_by_name (editable, "cut-clipboard"); + + g_object_set (editable, "editable", is_editable, NULL); } /** - * gtk_editable_copy_clipboard: + * gtk_editable_get_editable: * @editable: a #GtkEditable * - * Copies the contents of the currently selected content in the editable and - * puts it on the clipboard. + * Retrieves whether @editable is editable. + * See gtk_editable_set_editable(). + * + * Returns: %TRUE if @editable is editable. + */ +gboolean +gtk_editable_get_editable (GtkEditable *editable) +{ + gboolean is_editable; + + g_return_val_if_fail (GTK_IS_EDITABLE (editable), FALSE); + + g_object_get (editable, "editable", &is_editable, NULL); + + return is_editable; +} + + +/** + * gtk_editable_get_alignment: + * @editable: a #GtkEditable + * + * Gets the value set by gtk_editable_set_alignment(). + * + * Returns: the alignment + **/ +float +gtk_editable_get_alignment (GtkEditable *editable) +{ + float xalign; + + g_return_val_if_fail (GTK_IS_EDITABLE (editable), 0); + + g_object_get (editable, "xalign", &xalign, NULL); + + return xalign; +} + +/** + * gtk_editable_set_alignment: + * @editable: a #GtkEditable + * @xalign: The horizontal alignment, from 0 (left) to 1 (right). + * Reversed for RTL layouts + * + * Sets the alignment for the contents of the editable. + * + * This controls the horizontal positioning of the contents when + * the displayed text is shorter than the width of the editable. */ void -gtk_editable_copy_clipboard (GtkEditable *editable) +gtk_editable_set_alignment (GtkEditable *editable, + float xalign) { g_return_if_fail (GTK_IS_EDITABLE (editable)); - - g_signal_emit_by_name (editable, "copy-clipboard"); + + g_object_set (editable, "xalign", xalign, NULL); } /** - * gtk_editable_paste_clipboard: + * gtk_editable_get_width_chars: * @editable: a #GtkEditable * - * Pastes the content of the clipboard to the current position of the - * cursor in the editable. - */ + * Gets the value set by gtk_editable_set_width_chars(). + * + * Returns: number of chars to request space for, or negative if unset + **/ +int +gtk_editable_get_width_chars (GtkEditable *editable) +{ + int width_chars; + + g_return_val_if_fail (GTK_IS_EDITABLE (editable), 0); + + g_object_get (editable, "width-chars", &width_chars, NULL); + + return width_chars; +} + +/** + * gtk_editable_set_width_chars: + * @editable: a #GtkEditable + * @n_chars: width in chars + * + * Changes the size request of the editable to be about the + * right size for @n_chars characters. + * + * Note that it changes the size request, the size can still + * be affected by how you pack the widget into containers. + * If @n_chars is -1, the size reverts to the default size. + **/ void -gtk_editable_paste_clipboard (GtkEditable *editable) +gtk_editable_set_width_chars (GtkEditable *editable, + int n_chars) { g_return_if_fail (GTK_IS_EDITABLE (editable)); - - g_signal_emit_by_name (editable, "paste-clipboard"); + + g_object_set (editable, "width-chars", n_chars, NULL); } /** - * gtk_editable_set_editable: + * gtk_editable_get_max_width_chars: * @editable: a #GtkEditable - * @is_editable: %TRUE if the user is allowed to edit the text - * in the widget * - * Determines if the user can edit the text in the editable - * widget or not. + * Retrieves the desired maximum width of @editable, in characters. + * See gtk_editable_set_max_width_chars(). + * + * Returns: the maximum width of the entry, in characters + */ +int +gtk_editable_get_max_width_chars (GtkEditable *editable) +{ + int max_width_chars; + + g_return_val_if_fail (GTK_IS_EDITABLE (editable), 0); + + g_object_get (editable, "max-width-chars", &max_width_chars, NULL); + + return max_width_chars; +} + +/** + * gtk_editable_set_max_width_chars: + * @editable: a #GtkEditable + * @n_chars: the new desired maximum width, in characters + * + * Sets the desired maximum width in characters of @editable. */ void -gtk_editable_set_editable (GtkEditable *editable, - gboolean is_editable) +gtk_editable_set_max_width_chars (GtkEditable *editable, + int n_chars) { g_return_if_fail (GTK_IS_EDITABLE (editable)); - g_object_set (editable, - "editable", is_editable != FALSE, - NULL); + g_object_set (editable, "max-width-chars", n_chars, NULL); } /** - * gtk_editable_get_editable: + * gtk_editable_install_properties: + * @object_class: a #GObjectClass + * @first_prop: property ID to use for the first property + * + * Installs the GtkEditable properties for @class. + * + * This is a helper function that should be called in class_init, + * after installing your own properties. + * + * To handle the properties in your set_property and get_property + * functions, you can either use gtk_editable_delegate_set_property() + * and gtk_editable_delegate_get_property() (if you are using a delegate), + * or remember the @first_prop offset and add it to the values in the + * #GtkEditableProperties enumeration to get the property IDs for these + * properties. + * + * Returns: the number of properties that were installed + */ +guint +gtk_editable_install_properties (GObjectClass *object_class, + guint first_prop) +{ + g_type_set_qdata (G_TYPE_FROM_CLASS (object_class), + quark_editable_data, + GUINT_TO_POINTER (first_prop)); + + g_object_class_override_property (object_class, first_prop + GTK_EDITABLE_PROP_TEXT, "text"); + g_object_class_override_property (object_class, first_prop + GTK_EDITABLE_PROP_CURSOR_POSITION, "cursor-position"); + g_object_class_override_property (object_class, first_prop + GTK_EDITABLE_PROP_SELECTION_BOUND, "selection-bound"); + g_object_class_override_property (object_class, first_prop + GTK_EDITABLE_PROP_EDITABLE, "editable"); + g_object_class_override_property (object_class, first_prop + GTK_EDITABLE_PROP_WIDTH_CHARS, "width-chars"); + g_object_class_override_property (object_class, first_prop + GTK_EDITABLE_PROP_MAX_WIDTH_CHARS, "max-width-chars"); + g_object_class_override_property (object_class, first_prop + GTK_EDITABLE_PROP_XALIGN, "xalign"); + + return GTK_EDITABLE_NUM_PROPERTIES; +} + +static void +delegate_changed (GtkEditable *delegate, + gpointer editable) +{ + g_signal_emit_by_name (editable, "changed"); +} + +static void +delegate_notify (GObject *object, + GParamSpec *pspec, + gpointer data) +{ + gpointer iface; + + iface = g_type_interface_peek (g_type_class_peek (G_OBJECT_TYPE (object)), gtk_editable_get_type ()); + if (g_object_interface_find_property (iface, pspec->name)) + g_object_notify (data, pspec->name); +} + +/** + * gtk_editable_init_delegate: * @editable: a #GtkEditable * - * Retrieves whether @editable is editable. See - * gtk_editable_set_editable(). + * Sets up a delegate for #GtkEditable, assuming that the + * get_delegate vfunc in the #GtkEditable interface has been + * set up for the @editable's type. * - * Returns: %TRUE if @editable is editable. + * This is a helper function that should be called in instance init, + * after creating the delegate object. + */ +void +gtk_editable_init_delegate (GtkEditable *editable) +{ + GtkEditable *delegate = get_delegate (editable); + g_signal_connect (delegate, "notify", G_CALLBACK (delegate_notify), editable); + g_signal_connect (delegate, "changed", G_CALLBACK (delegate_changed), editable); +} + +/** + * gtk_editable_finish_delegate: + * @editable: a #GtkEditable + * + * Undoes the setup done by gtk_editable_init_delegate(). + * + * This is a helper function that should be called from dispose, + * before removing the delegate object. + */ +void +gtk_editable_finish_delegate (GtkEditable *editable) +{ + GtkEditable *delegate = get_delegate (editable); + g_signal_handlers_disconnect_by_func (delegate, delegate_notify, editable); + g_signal_handlers_disconnect_by_func (delegate, delegate_changed, editable); +} + +/** + * gtk_editable_set_property: + * @object: a #GObject + * @prop_id: a property ID + * @value: value to set + * @pspec: the #GParamSpec for the property + * + * Sets a property on the #GtkEditable delegate for @object. + * + * This is a helper function that should be called in set_property, + * before handling your own properties. + * + * Returns: %TRUE if the property was found */ gboolean -gtk_editable_get_editable (GtkEditable *editable) +gtk_editable_delegate_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) { - gboolean value; + GtkEditable *delegate = get_delegate (GTK_EDITABLE (object)); + GType type = G_TYPE_FROM_INSTANCE (object); + guint first_prop; - g_return_val_if_fail (GTK_IS_EDITABLE (editable), FALSE); + first_prop = GPOINTER_TO_UINT (g_type_get_qdata (type, quark_editable_data)); - g_object_get (editable, "editable", &value, NULL); + if (prop_id < first_prop) + return FALSE; - return value; + switch (prop_id - first_prop) + { + case GTK_EDITABLE_PROP_TEXT: + gtk_editable_set_text (delegate, g_value_get_string (value)); + break; + + case GTK_EDITABLE_PROP_EDITABLE: + gtk_editable_set_editable (delegate, g_value_get_boolean (value)); + break; + + case GTK_EDITABLE_PROP_WIDTH_CHARS: + gtk_editable_set_width_chars (delegate, g_value_get_int (value)); + break; + + case GTK_EDITABLE_PROP_MAX_WIDTH_CHARS: + gtk_editable_set_max_width_chars (delegate, g_value_get_int (value)); + break; + + case GTK_EDITABLE_PROP_XALIGN: + gtk_editable_set_alignment (delegate, g_value_get_float (value)); + break; + + default: + return FALSE; + } + + return TRUE; +} + +/** + * gtk_editable_get_property: + * @object: a #GObject + * @prop_id: a property ID + * @value: value to set + * @pspec: the #GParamSpec for the property + * + * Gets a property of the #GtkEditable delegate for @object. + * + * This is helper function that should be called in get_property, + * before handling your own properties. + * + * Returns: %TRUE if the property was found + */ +gboolean +gtk_editable_delegate_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GtkEditable *delegate = get_delegate (GTK_EDITABLE (object)); + int cursor_position, selection_bound; + GType type = G_TYPE_FROM_INSTANCE (object); + guint first_prop; + + first_prop = GPOINTER_TO_UINT (g_type_get_qdata (type, quark_editable_data)); + + if (prop_id < first_prop) + return FALSE; + + switch (prop_id - first_prop) + { + case GTK_EDITABLE_PROP_TEXT: + g_value_set_string (value, gtk_editable_get_text (delegate)); + break; + + case GTK_EDITABLE_PROP_CURSOR_POSITION: + gtk_editable_get_selection_bounds (delegate, &cursor_position, &selection_bound); + g_value_set_int (value, cursor_position); + break; + + case GTK_EDITABLE_PROP_SELECTION_BOUND: + gtk_editable_get_selection_bounds (delegate, &cursor_position, &selection_bound); + g_value_set_int (value, selection_bound); + break; + + case GTK_EDITABLE_PROP_EDITABLE: + g_value_set_boolean (value, gtk_editable_get_editable (delegate)); + break; + + case GTK_EDITABLE_PROP_WIDTH_CHARS: + g_value_set_int (value, gtk_editable_get_width_chars (delegate)); + break; + + case GTK_EDITABLE_PROP_MAX_WIDTH_CHARS: + g_value_set_int (value, gtk_editable_get_max_width_chars (delegate)); + break; + + case GTK_EDITABLE_PROP_XALIGN: + g_value_set_float (value, gtk_editable_get_alignment (delegate)); + break; + + default: + return FALSE; + } + + return TRUE; } + + |