1/* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser 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.
8 *
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 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18/*
19 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
20 * file for a list of people on the GTK+ Team. See the ChangeLog
21 * files for a list of changes. These files are distributed with
22 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
23 */
24
25/**
26 * GtkEditable:
27 *
28 * `GtkEditable` is an interface for text editing widgets.
29 *
30 * Typical examples of editable widgets are [class@Gtk.Entry] and
31 * [class@Gtk.SpinButton]. It contains functions for generically manipulating
32 * an editable widget, a large number of action signals used for key bindings,
33 * and several signals that an application can connect to modify the behavior
34 * of a widget.
35 *
36 * As an example of the latter usage, by connecting the following handler to
37 * [signal@Gtk.Editable::insert-text], an application can convert all entry
38 * into a widget into uppercase.
39 *
40 * ## Forcing entry to uppercase.
41 *
42 * ```c
43 * #include <ctype.h>
44 *
45 * void
46 * insert_text_handler (GtkEditable *editable,
47 * const char *text,
48 * int length,
49 * int *position,
50 * gpointer data)
51 * {
52 * char *result = g_utf8_strup (text, length);
53 *
54 * g_signal_handlers_block_by_func (editable,
55 * (gpointer) insert_text_handler, data);
56 * gtk_editable_insert_text (editable, result, length, position);
57 * g_signal_handlers_unblock_by_func (editable,
58 * (gpointer) insert_text_handler, data);
59 *
60 * g_signal_stop_emission_by_name (editable, "insert_text");
61 *
62 * g_free (result);
63 * }
64 * ```
65 *
66 * ## Implementing GtkEditable
67 *
68 * The most likely scenario for implementing `GtkEditable` on your own widget
69 * is that you will embed a `GtkText` inside a complex widget, and want to
70 * delegate the editable functionality to that text widget. `GtkEditable`
71 * provides some utility functions to make this easy.
72 *
73 * In your class_init function, call [func@Gtk.Editable.install_properties],
74 * passing the first available property ID:
75 *
76 * ```c
77 * static void
78 * my_class_init (MyClass *class)
79 * {
80 * ...
81 * g_object_class_install_properties (object_class, NUM_PROPERTIES, props);
82 * gtk_editable_install_properties (object_clas, NUM_PROPERTIES);
83 * ...
84 * }
85 * ```
86 *
87 * In your interface_init function for the `GtkEditable` interface, provide
88 * an implementation for the get_delegate vfunc that returns your text widget:
89 *
90 * ```c
91 * GtkEditable *
92 * get_editable_delegate (GtkEditable *editable)
93 * {
94 * return GTK_EDITABLE (MY_WIDGET (editable)->text_widget);
95 * }
96 *
97 * static void
98 * my_editable_init (GtkEditableInterface *iface)
99 * {
100 * iface->get_delegate = get_editable_delegate;
101 * }
102 * ```
103 *
104 * You don't need to provide any other vfuncs. The default implementations
105 * work by forwarding to the delegate that the GtkEditableInterface.get_delegate()
106 * vfunc returns.
107 *
108 * In your instance_init function, create your text widget, and then call
109 * [method@Gtk.Editable.init_delegate]:
110 *
111 * ```c
112 * static void
113 * my_widget_init (MyWidget *self)
114 * {
115 * ...
116 * self->text_widget = gtk_text_new ();
117 * gtk_editable_init_delegate (GTK_EDITABLE (self));
118 * ...
119 * }
120 * ```
121 *
122 * In your dispose function, call [method@Gtk.Editable.finish_delegate] before
123 * destroying your text widget:
124 *
125 * ```c
126 * static void
127 * my_widget_dispose (GObject *object)
128 * {
129 * ...
130 * gtk_editable_finish_delegate (GTK_EDITABLE (self));
131 * g_clear_pointer (&self->text_widget, gtk_widget_unparent);
132 * ...
133 * }
134 * ```
135 *
136 * Finally, use [func@Gtk.Editable.delegate_set_property] in your `set_property`
137 * function (and similar for `get_property`), to set the editable properties:
138 *
139 * ```c
140 * ...
141 * if (gtk_editable_delegate_set_property (object, prop_id, value, pspec))
142 * return;
143 *
144 * switch (prop_id)
145 * ...
146 * ```
147 *
148 * It is important to note that if you create a `GtkEditable` that uses
149 * a delegate, the low level [signal@Gtk.Editable::insert-text] and
150 * [signal@Gtk.Editable::delete-text] signals will be propagated from the
151 * "wrapper" editable to the delegate, but they will not be propagated from
152 * the delegate to the "wrapper" editable, as they would cause an infinite
153 * recursion. If you wish to connect to the [signal@Gtk.Editable::insert-text]
154 * and [signal@Gtk.Editable::delete-text] signals, you will need to connect
155 * to them on the delegate obtained via [method@Gtk.Editable.get_delegate].
156 */
157
158#include "config.h"
159#include <string.h>
160
161#include "gtkeditable.h"
162#include "gtkentrybuffer.h"
163#include "gtkmarshalers.h"
164#include "gtkintl.h"
165#include "gtkprivate.h"
166
167G_DEFINE_INTERFACE (GtkEditable, gtk_editable, GTK_TYPE_WIDGET)
168
169enum {
170 CHANGED,
171 DELETE_TEXT,
172 INSERT_TEXT,
173 N_SIGNALS
174};
175
176static GQuark quark_editable_data;
177static guint signals[N_SIGNALS];
178
179static GtkEditable *
180get_delegate (GtkEditable *editable)
181{
182 GtkEditableInterface *iface = GTK_EDITABLE_GET_IFACE (editable);
183
184 if (iface->get_delegate)
185 return iface->get_delegate (editable);
186
187 return NULL;
188}
189
190static void
191gtk_editable_default_do_insert_text (GtkEditable *editable,
192 const char *text,
193 int length,
194 int *position)
195{
196 g_signal_emit (instance: editable, signal_id: signals[INSERT_TEXT], detail: 0, text, length, position);
197}
198
199#define warn_no_delegate(func) \
200 g_critical ("GtkEditable %s: default implementation called without a delegate", func);
201
202static void
203gtk_editable_default_insert_text (GtkEditable *editable,
204 const char *text,
205 int length,
206 int *position)
207{
208 GtkEditable *delegate = get_delegate (editable);
209
210 if (delegate)
211 gtk_editable_insert_text (editable: delegate, text, length, position);
212 else
213 warn_no_delegate ("insert_text");
214}
215
216static void
217gtk_editable_default_do_delete_text (GtkEditable *editable,
218 int start_pos,
219 int end_pos)
220{
221 g_signal_emit (instance: editable, signal_id: signals[DELETE_TEXT], detail: 0, start_pos, end_pos);
222}
223
224static void
225gtk_editable_default_delete_text (GtkEditable *editable,
226 int start_pos,
227 int end_pos)
228{
229 GtkEditable *delegate = get_delegate (editable);
230
231 if (delegate)
232 gtk_editable_delete_text (editable: delegate, start_pos, end_pos);
233 else
234 warn_no_delegate ("delete_text");
235}
236
237static const char *
238gtk_editable_default_get_text (GtkEditable *editable)
239{
240 GtkEditable *delegate = get_delegate (editable);
241
242 if (delegate)
243 return gtk_editable_get_text (editable: delegate);
244 else
245 warn_no_delegate ("get_text");
246
247 return NULL;
248}
249
250static void
251gtk_editable_default_set_selection_bounds (GtkEditable *editable,
252 int start_pos,
253 int end_pos)
254{
255 GtkEditable *delegate = get_delegate (editable);
256
257 if (delegate)
258 gtk_editable_select_region (editable: delegate, start_pos, end_pos);
259 else
260 warn_no_delegate ("select_region");
261}
262
263static gboolean
264gtk_editable_default_get_selection_bounds (GtkEditable *editable,
265 int *start_pos,
266 int *end_pos)
267{
268 GtkEditable *delegate = get_delegate (editable);
269
270 if (delegate)
271 return gtk_editable_get_selection_bounds (editable: delegate, start_pos, end_pos);
272 else
273 warn_no_delegate ("select_region");
274
275 return FALSE;
276}
277
278static void
279gtk_editable_default_init (GtkEditableInterface *iface)
280{
281 quark_editable_data = g_quark_from_static_string (string: "GtkEditable-data");
282
283 iface->insert_text = gtk_editable_default_insert_text;
284 iface->delete_text = gtk_editable_default_delete_text;
285 iface->get_text = gtk_editable_default_get_text;
286 iface->do_insert_text = gtk_editable_default_do_insert_text;
287 iface->do_delete_text = gtk_editable_default_do_delete_text;
288 iface->get_selection_bounds = gtk_editable_default_get_selection_bounds;
289 iface->set_selection_bounds = gtk_editable_default_set_selection_bounds;
290
291 /**
292 * GtkEditable::insert-text:
293 * @editable: the object which received the signal
294 * @text: the new text to insert
295 * @length: the length of the new text, in bytes,
296 * or -1 if new_text is nul-terminated
297 * @position: (inout) (type int): the position, in characters,
298 * at which to insert the new text. this is an in-out
299 * parameter. After the signal emission is finished, it
300 * should point after the newly inserted text.
301 *
302 * Emitted when text is inserted into the widget by the user.
303 *
304 * The default handler for this signal will normally be responsible
305 * for inserting the text, so by connecting to this signal and then
306 * stopping the signal with g_signal_stop_emission(), it is possible
307 * to modify the inserted text, or prevent it from being inserted entirely.
308 */
309 signals[INSERT_TEXT] =
310 g_signal_new (I_("insert-text"),
311 GTK_TYPE_EDITABLE,
312 signal_flags: G_SIGNAL_RUN_LAST,
313 G_STRUCT_OFFSET (GtkEditableInterface, insert_text),
314 NULL, NULL,
315 c_marshaller: _gtk_marshal_VOID__STRING_INT_POINTER,
316 G_TYPE_NONE, n_params: 3,
317 G_TYPE_STRING,
318 G_TYPE_INT,
319 G_TYPE_POINTER);
320 g_signal_set_va_marshaller (signal_id: signals[INSERT_TEXT],
321 G_TYPE_FROM_INTERFACE (iface),
322 va_marshaller: _gtk_marshal_VOID__STRING_INT_POINTERv);
323
324 /**
325 * GtkEditable::delete-text:
326 * @editable: the object which received the signal
327 * @start_pos: the starting position
328 * @end_pos: the end position
329 *
330 * Emitted when text is deleted from the widget by the user.
331 *
332 * The default handler for this signal will normally be responsible for
333 * deleting the text, so by connecting to this signal and then stopping
334 * the signal with g_signal_stop_emission(), it is possible to modify the
335 * range of deleted text, or prevent it from being deleted entirely.
336 *
337 * The @start_pos and @end_pos parameters are interpreted as for
338 * [method@Gtk.Editable.delete_text].
339 */
340 signals[DELETE_TEXT] =
341 g_signal_new (I_("delete-text"),
342 GTK_TYPE_EDITABLE,
343 signal_flags: G_SIGNAL_RUN_LAST,
344 G_STRUCT_OFFSET (GtkEditableInterface, delete_text),
345 NULL, NULL,
346 c_marshaller: _gtk_marshal_VOID__INT_INT,
347 G_TYPE_NONE, n_params: 2,
348 G_TYPE_INT,
349 G_TYPE_INT);
350 g_signal_set_va_marshaller (signal_id: signals[DELETE_TEXT],
351 G_TYPE_FROM_INTERFACE (iface),
352 va_marshaller: _gtk_marshal_VOID__INT_INTv);
353
354 /**
355 * GtkEditable::changed:
356 * @editable: the object which received the signal
357 *
358 * Emitted at the end of a single user-visible operation on the
359 * contents.
360 *
361 * E.g., a paste operation that replaces the contents of the
362 * selection will cause only one signal emission (even though it
363 * is implemented by first deleting the selection, then inserting
364 * the new content, and may cause multiple ::notify::text signals
365 * to be emitted).
366 */
367 signals[CHANGED] =
368 g_signal_new (I_("changed"),
369 GTK_TYPE_EDITABLE,
370 signal_flags: G_SIGNAL_RUN_LAST,
371 G_STRUCT_OFFSET (GtkEditableInterface, changed),
372 NULL, NULL,
373 NULL,
374 G_TYPE_NONE, n_params: 0);
375
376 /**
377 * GtkEditable:text: (attributes org.gtk.Property.get=gtk_editable_get_text org.gtk.Property.set=gtk_editable_set_text)
378 *
379 * The contents of the entry.
380 */
381 g_object_interface_install_property (g_iface: iface,
382 pspec: g_param_spec_string (name: "text",
383 P_("Text"),
384 P_("The contents of the entry"),
385 default_value: "",
386 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
387
388 /**
389 * GtkEditable:cursor-position: (attributes org.gtk.Property.get=gtk_editable_get_position org.gtk.Property.set=gtk_editable_set_position)
390 *
391 * The current position of the insertion cursor in chars.
392 */
393 g_object_interface_install_property (g_iface: iface,
394 pspec: g_param_spec_int (name: "cursor-position",
395 P_("Cursor Position"),
396 P_("The current position of the insertion cursor in chars"),
397 minimum: 0, GTK_ENTRY_BUFFER_MAX_SIZE,
398 default_value: 0,
399 GTK_PARAM_READABLE));
400
401 /**
402 * GtkEditable:enable-undo: (attributes org.gtk.Property.get=gtk_editable_get_enable_undo org.gtk.Property.setg=gtk_editable_set_enable_undo)
403 *
404 * If undo/redo should be enabled for the editable.
405 */
406 g_object_interface_install_property (g_iface: iface,
407 pspec: g_param_spec_boolean (name: "enable-undo",
408 P_("Enable Undo"),
409 P_("If undo/redo should be enabled for the editable"),
410 TRUE,
411 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
412
413 /**
414 * GtkEditable:selection-bound:
415 *
416 * The position of the opposite end of the selection from the cursor in chars.
417 */
418 g_object_interface_install_property (g_iface: iface,
419 pspec: g_param_spec_int (name: "selection-bound",
420 P_("Selection Bound"),
421 P_("The position of the opposite end of the selection from the cursor in chars"),
422 minimum: 0, GTK_ENTRY_BUFFER_MAX_SIZE,
423 default_value: 0,
424 GTK_PARAM_READABLE));
425
426 /**
427 * GtkEditable:editable: (attributes org.gtk.Property.get=gtk_editable_get_editable org.gtk.Property.set=gtk_editable_set_editable)
428 *
429 * Whether the entry contents can be edited.
430 */
431 g_object_interface_install_property (g_iface: iface,
432 pspec: g_param_spec_boolean (name: "editable",
433 P_("Editable"),
434 P_("Whether the entry contents can be edited"),
435 TRUE,
436 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
437
438 /**
439 * GtkEditable:width-chars: (attributes org.gtk.Property.get=gtk_editable_get_width_chars org.gtk.Property.set=gtk_editable_set_width_chars)
440 *
441 * Number of characters to leave space for in the entry.
442 */
443 g_object_interface_install_property (g_iface: iface,
444 pspec: g_param_spec_int (name: "width-chars",
445 P_("Width in chars"),
446 P_("Number of characters to leave space for in the entry"),
447 minimum: -1, G_MAXINT,
448 default_value: -1,
449 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
450
451 /**
452 * GtkEditable:max-width-chars: (attributes org.gtk.Property.get=gtk_editable_get_max_width_chars org.gtk.Property.set=gtk_editable_set_max_width_chars)
453 *
454 * The desired maximum width of the entry, in characters.
455 */
456 g_object_interface_install_property (g_iface: iface,
457 pspec: g_param_spec_int (name: "max-width-chars",
458 P_("Maximum width in characters"),
459 P_("The desired maximum width of the entry, in characters"),
460 minimum: -1, G_MAXINT,
461 default_value: -1,
462 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
463
464 /**
465 * GtkEditable:xalign: (attributes org.gtk.Property.get=gtk_editable_get_alignment org.gtk.Property.set=gtk_editable_set_alignment)
466 *
467 * The horizontal alignment, from 0 (left) to 1 (right).
468 *
469 * Reversed for RTL layouts.
470 */
471 g_object_interface_install_property (g_iface: iface,
472 pspec: g_param_spec_float (name: "xalign",
473 P_("X align"),
474 P_("The horizontal alignment, from 0 (left) to 1 (right). Reversed for RTL layouts."),
475 minimum: 0.0, maximum: 1.0,
476 default_value: 0.0,
477 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
478}
479
480/**
481 * gtk_editable_insert_text: (virtual do_insert_text)
482 * @editable: a `GtkEditable`
483 * @text: the text to append
484 * @length: the length of the text in bytes, or -1
485 * @position: (inout): location of the position text will be inserted at
486 *
487 * Inserts @length bytes of @text into the contents of the
488 * widget, at position @position.
489 *
490 * Note that the position is in characters, not in bytes.
491 * The function updates @position to point after the newly
492 * inserted text.
493 */
494void
495gtk_editable_insert_text (GtkEditable *editable,
496 const char *text,
497 int length,
498 int *position)
499{
500 g_return_if_fail (GTK_IS_EDITABLE (editable));
501 g_return_if_fail (position != NULL);
502
503 if (length < 0)
504 length = strlen (s: text);
505
506 GTK_EDITABLE_GET_IFACE (editable)->do_insert_text (editable, text, length, position);
507}
508
509/**
510 * gtk_editable_delete_text: (virtual do_delete_text)
511 * @editable: a `GtkEditable`
512 * @start_pos: start position
513 * @end_pos: end position
514 *
515 * Deletes a sequence of characters.
516 *
517 * The characters that are deleted are those characters at positions
518 * from @start_pos up to, but not including @end_pos. If @end_pos is
519 * negative, then the characters deleted are those from @start_pos to
520 * the end of the text.
521 *
522 * Note that the positions are specified in characters, not bytes.
523 */
524void
525gtk_editable_delete_text (GtkEditable *editable,
526 int start_pos,
527 int end_pos)
528{
529 g_return_if_fail (GTK_IS_EDITABLE (editable));
530
531 GTK_EDITABLE_GET_IFACE (editable)->do_delete_text (editable, start_pos, end_pos);
532}
533
534/**
535 * gtk_editable_get_chars:
536 * @editable: a `GtkEditable`
537 * @start_pos: start of text
538 * @end_pos: end of text
539 *
540 * Retrieves a sequence of characters.
541 *
542 * The characters that are retrieved are those characters at positions
543 * from @start_pos up to, but not including @end_pos. If @end_pos is negative,
544 * then the characters retrieved are those characters from @start_pos to
545 * the end of the text.
546 *
547 * Note that positions are specified in characters, not bytes.
548 *
549 * Returns: (transfer full): a pointer to the contents of the widget as a
550 * string. This string is allocated by the `GtkEditable` implementation
551 * and should be freed by the caller.
552 */
553char *
554gtk_editable_get_chars (GtkEditable *editable,
555 int start_pos,
556 int end_pos)
557{
558 const char *text;
559 int length;
560 int start_index,end_index;
561
562 g_return_val_if_fail (GTK_IS_EDITABLE (editable), NULL);
563
564 text = GTK_EDITABLE_GET_IFACE (editable)->get_text (editable);
565 length = g_utf8_strlen (p: text, max: -1);
566
567 if (end_pos < 0)
568 end_pos = length;
569
570 start_pos = MIN (length, start_pos);
571 end_pos = MIN (length, end_pos);
572
573 start_index = g_utf8_offset_to_pointer (str: text, offset: start_pos) - text;
574 end_index = g_utf8_offset_to_pointer (str: text, offset: end_pos) - text;
575
576 return g_strndup (str: text + start_index, n: end_index - start_index);
577}
578
579/**
580 * gtk_editable_get_text: (attributes org.gtk.Method.get_property=text)
581 * @editable: a `GtkEditable`
582 *
583 * Retrieves the contents of @editable.
584 *
585 * The returned string is owned by GTK and must not be modified or freed.
586 *
587 * Returns: (transfer none): a pointer to the contents of the editable
588 */
589const char *
590gtk_editable_get_text (GtkEditable *editable)
591{
592 g_return_val_if_fail (GTK_IS_EDITABLE (editable), NULL);
593
594 return GTK_EDITABLE_GET_IFACE (editable)->get_text (editable);
595}
596
597/**
598 * gtk_editable_set_text: (attributes org.gtk.Method.set_property=text)
599 * @editable: a `GtkEditable`
600 * @text: the text to set
601 *
602 * Sets the text in the editable to the given value.
603 *
604 * This is replacing the current contents.
605 */
606void
607gtk_editable_set_text (GtkEditable *editable,
608 const char *text)
609{
610 int pos;
611
612 g_return_if_fail (GTK_IS_EDITABLE (editable));
613
614 g_object_freeze_notify (G_OBJECT (editable));
615 gtk_editable_delete_text (editable, start_pos: 0, end_pos: -1);
616 pos = 0;
617 gtk_editable_insert_text (editable, text, length: -1, position: &pos);
618 g_object_thaw_notify (G_OBJECT (editable));
619}
620
621/**
622 * gtk_editable_set_position: (attributes org.gtk.Method.set_property=cursor-position)
623 * @editable: a `GtkEditable`
624 * @position: the position of the cursor
625 *
626 * Sets the cursor position in the editable to the given value.
627 *
628 * The cursor is displayed before the character with the given (base 0)
629 * index in the contents of the editable. The value must be less than
630 * or equal to the number of characters in the editable. A value of -1
631 * indicates that the position should be set after the last character
632 * of the editable. Note that @position is in characters, not in bytes.
633 */
634void
635gtk_editable_set_position (GtkEditable *editable,
636 int position)
637{
638 g_return_if_fail (GTK_IS_EDITABLE (editable));
639
640 GTK_EDITABLE_GET_IFACE (editable)->set_selection_bounds (editable, position, position);
641}
642
643/**
644 * gtk_editable_get_position: (attributes org.gtk.Method.get_property=cursor-position)
645 * @editable: a `GtkEditable`
646 *
647 * Retrieves the current position of the cursor relative
648 * to the start of the content of the editable.
649 *
650 * Note that this position is in characters, not in bytes.
651 *
652 * Returns: the cursor position
653 */
654int
655gtk_editable_get_position (GtkEditable *editable)
656{
657 int start, end;
658
659 g_return_val_if_fail (GTK_IS_EDITABLE (editable), 0);
660
661 GTK_EDITABLE_GET_IFACE (editable)->get_selection_bounds (editable, &start, &end);
662
663 return end;
664}
665
666/**
667 * gtk_editable_get_selection_bounds:
668 * @editable: a `GtkEditable`
669 * @start_pos: (out) (optional): location to store the starting position
670 * @end_pos: (out) (optional): location to store the end position
671 *
672 * Retrieves the selection bound of the editable.
673 *
674 * @start_pos will be filled with the start of the selection and
675 * @end_pos with end. If no text was selected both will be identical
676 * and %FALSE will be returned.
677 *
678 * Note that positions are specified in characters, not bytes.
679 *
680 * Returns: %TRUE if there is a non-empty selection, %FALSE otherwise
681 */
682gboolean
683gtk_editable_get_selection_bounds (GtkEditable *editable,
684 int *start_pos,
685 int *end_pos)
686{
687 int tmp_start, tmp_end;
688 gboolean result;
689
690 g_return_val_if_fail (GTK_IS_EDITABLE (editable), FALSE);
691
692 result = GTK_EDITABLE_GET_IFACE (editable)->get_selection_bounds (editable, &tmp_start, &tmp_end);
693
694 if (start_pos)
695 *start_pos = MIN (tmp_start, tmp_end);
696 if (end_pos)
697 *end_pos = MAX (tmp_start, tmp_end);
698
699 return result;
700}
701
702/**
703 * gtk_editable_delete_selection:
704 * @editable: a `GtkEditable`
705 *
706 * Deletes the currently selected text of the editable.
707 *
708 * This call doesn’t do anything if there is no selected text.
709 */
710void
711gtk_editable_delete_selection (GtkEditable *editable)
712{
713 int start, end;
714
715 g_return_if_fail (GTK_IS_EDITABLE (editable));
716
717 if (gtk_editable_get_selection_bounds (editable, start_pos: &start, end_pos: &end))
718 gtk_editable_delete_text (editable, start_pos: start, end_pos: end);
719}
720
721/**
722 * gtk_editable_select_region: (virtual set_selection_bounds)
723 * @editable: a `GtkEditable`
724 * @start_pos: start of region
725 * @end_pos: end of region
726 *
727 * Selects a region of text.
728 *
729 * The characters that are selected are those characters at positions
730 * from @start_pos up to, but not including @end_pos. If @end_pos is
731 * negative, then the characters selected are those characters from
732 * @start_pos to the end of the text.
733 *
734 * Note that positions are specified in characters, not bytes.
735 */
736void
737gtk_editable_select_region (GtkEditable *editable,
738 int start_pos,
739 int end_pos)
740{
741 g_return_if_fail (GTK_IS_EDITABLE (editable));
742
743 GTK_EDITABLE_GET_IFACE (editable)->set_selection_bounds (editable, start_pos, end_pos);
744}
745
746/**
747 * gtk_editable_set_editable: (attributes org.gtk.Method.set_property=editable)
748 * @editable: a `GtkEditable`
749 * @is_editable: %TRUE if the user is allowed to edit the text
750 * in the widget
751 *
752 * Determines if the user can edit the text in the editable widget.
753 */
754void
755gtk_editable_set_editable (GtkEditable *editable,
756 gboolean is_editable)
757{
758 g_return_if_fail (GTK_IS_EDITABLE (editable));
759
760 g_object_set (object: editable, first_property_name: "editable", is_editable, NULL);
761}
762
763/**
764 * gtk_editable_get_editable: (attributes org.gtk.Method.get_property=editable)
765 * @editable: a `GtkEditable`
766 *
767 * Retrieves whether @editable is editable.
768 *
769 * Returns: %TRUE if @editable is editable.
770 */
771gboolean
772gtk_editable_get_editable (GtkEditable *editable)
773{
774 gboolean is_editable;
775
776 g_return_val_if_fail (GTK_IS_EDITABLE (editable), FALSE);
777
778 g_object_get (object: editable, first_property_name: "editable", &is_editable, NULL);
779
780 return is_editable;
781}
782
783
784/**
785 * gtk_editable_get_alignment: (attributes org.gtk.Method.get_property=xalign)
786 * @editable: a `GtkEditable`
787 *
788 * Gets the alignment of the editable.
789 *
790 * Returns: the alignment
791 */
792float
793gtk_editable_get_alignment (GtkEditable *editable)
794{
795 float xalign;
796
797 g_return_val_if_fail (GTK_IS_EDITABLE (editable), 0);
798
799 g_object_get (object: editable, first_property_name: "xalign", &xalign, NULL);
800
801 return xalign;
802}
803
804/**
805 * gtk_editable_set_alignment: (attributes org.gtk.Method.set_property=xalign)
806 * @editable: a `GtkEditable`
807 * @xalign: The horizontal alignment, from 0 (left) to 1 (right).
808 * Reversed for RTL layouts
809 *
810 * Sets the alignment for the contents of the editable.
811 *
812 * This controls the horizontal positioning of the contents when
813 * the displayed text is shorter than the width of the editable.
814 */
815void
816gtk_editable_set_alignment (GtkEditable *editable,
817 float xalign)
818{
819 g_return_if_fail (GTK_IS_EDITABLE (editable));
820
821 g_object_set (object: editable, first_property_name: "xalign", xalign, NULL);
822}
823
824/**
825 * gtk_editable_get_width_chars: (attributes org.gtk.Method.get_property=width-chars)
826 * @editable: a `GtkEditable`
827 *
828 * Gets the number of characters of space reserved
829 * for the contents of the editable.
830 *
831 * Returns: number of chars to request space for, or negative if unset
832 */
833int
834gtk_editable_get_width_chars (GtkEditable *editable)
835{
836 int width_chars;
837
838 g_return_val_if_fail (GTK_IS_EDITABLE (editable), 0);
839
840 g_object_get (object: editable, first_property_name: "width-chars", &width_chars, NULL);
841
842 return width_chars;
843}
844
845/**
846 * gtk_editable_set_width_chars: (attributes org.gtk.Method.set_property=width-chars)
847 * @editable: a `GtkEditable`
848 * @n_chars: width in chars
849 *
850 * Changes the size request of the editable to be about the
851 * right size for @n_chars characters.
852 *
853 * Note that it changes the size request, the size can still
854 * be affected by how you pack the widget into containers.
855 * If @n_chars is -1, the size reverts to the default size.
856 */
857void
858gtk_editable_set_width_chars (GtkEditable *editable,
859 int n_chars)
860{
861 g_return_if_fail (GTK_IS_EDITABLE (editable));
862
863 g_object_set (object: editable, first_property_name: "width-chars", n_chars, NULL);
864}
865
866/**
867 * gtk_editable_get_max_width_chars: (attributes org.gtk.Method.get_property=max-width-chars)
868 * @editable: a `GtkEditable`
869 *
870 * Retrieves the desired maximum width of @editable, in characters.
871 *
872 * Returns: the maximum width of the entry, in characters
873 */
874int
875gtk_editable_get_max_width_chars (GtkEditable *editable)
876{
877 int max_width_chars;
878
879 g_return_val_if_fail (GTK_IS_EDITABLE (editable), 0);
880
881 g_object_get (object: editable, first_property_name: "max-width-chars", &max_width_chars, NULL);
882
883 return max_width_chars;
884}
885
886/**
887 * gtk_editable_set_max_width_chars: (attributes org.gtk.Method.set_property=max-width-chars)
888 * @editable: a `GtkEditable`
889 * @n_chars: the new desired maximum width, in characters
890 *
891 * Sets the desired maximum width in characters of @editable.
892 */
893void
894gtk_editable_set_max_width_chars (GtkEditable *editable,
895 int n_chars)
896{
897 g_return_if_fail (GTK_IS_EDITABLE (editable));
898
899 g_object_set (object: editable, first_property_name: "max-width-chars", n_chars, NULL);
900}
901
902/**
903 * gtk_editable_get_enable_undo: (attributes org.gtk.Method.get_property=enable-undo)
904 * @editable: a `GtkEditable`
905 *
906 * Gets if undo/redo actions are enabled for @editable
907 *
908 * Returns: %TRUE if undo is enabled
909 */
910gboolean
911gtk_editable_get_enable_undo (GtkEditable *editable)
912{
913 gboolean enable_undo;
914
915 g_return_val_if_fail (GTK_IS_EDITABLE (editable), 0);
916
917 g_object_get (object: editable, first_property_name: "enable-undo", &enable_undo, NULL);
918
919 return enable_undo;
920}
921
922/**
923 * gtk_editable_set_enable_undo: (attributes org.gtk.Method.set_property=enable-undo)
924 * @editable: a `GtkEditable`
925 * @enable_undo: if undo/redo should be enabled
926 *
927 * If enabled, changes to @editable will be saved for undo/redo
928 * actions.
929 *
930 * This results in an additional copy of text changes and are not
931 * stored in secure memory. As such, undo is forcefully disabled
932 * when [property@Gtk.Text:visibility] is set to %FALSE.
933 */
934void
935gtk_editable_set_enable_undo (GtkEditable *editable,
936 gboolean enable_undo)
937{
938 g_return_if_fail (GTK_IS_EDITABLE (editable));
939
940 g_object_set (object: editable, first_property_name: "enable-undo", enable_undo, NULL);
941}
942
943/**
944 * gtk_editable_install_properties:
945 * @object_class: a `GObjectClass`
946 * @first_prop: property ID to use for the first property
947 *
948 * Overrides the `GtkEditable` properties for @class.
949 *
950 * This is a helper function that should be called in class_init,
951 * after installing your own properties.
952 *
953 * Note that your class must have "text", "cursor-position",
954 * "selection-bound", "editable", "width-chars", "max-width-chars",
955 * "xalign" and "enable-undo" properties for this function to work.
956 *
957 * To handle the properties in your set_property and get_property
958 * functions, you can either use [func@Gtk.Editable.delegate_set_property]
959 * and [func@Gtk.Editable.delegate_get_property] (if you are using
960 * a delegate), or remember the @first_prop offset and add it to the
961 * values in the [enum@Gtk.EditableProperties] enumeration to get the
962 * property IDs for these properties.
963 *
964 * Returns: the number of properties that were installed
965 */
966guint
967gtk_editable_install_properties (GObjectClass *object_class,
968 guint first_prop)
969{
970 g_type_set_qdata (G_TYPE_FROM_CLASS (object_class),
971 quark: quark_editable_data,
972 GUINT_TO_POINTER (first_prop));
973
974 g_object_class_override_property (oclass: object_class, property_id: first_prop + GTK_EDITABLE_PROP_TEXT, name: "text");
975 g_object_class_override_property (oclass: object_class, property_id: first_prop + GTK_EDITABLE_PROP_CURSOR_POSITION, name: "cursor-position");
976 g_object_class_override_property (oclass: object_class, property_id: first_prop + GTK_EDITABLE_PROP_SELECTION_BOUND, name: "selection-bound");
977 g_object_class_override_property (oclass: object_class, property_id: first_prop + GTK_EDITABLE_PROP_EDITABLE, name: "editable");
978 g_object_class_override_property (oclass: object_class, property_id: first_prop + GTK_EDITABLE_PROP_WIDTH_CHARS, name: "width-chars");
979 g_object_class_override_property (oclass: object_class, property_id: first_prop + GTK_EDITABLE_PROP_MAX_WIDTH_CHARS, name: "max-width-chars");
980 g_object_class_override_property (oclass: object_class, property_id: first_prop + GTK_EDITABLE_PROP_XALIGN, name: "xalign");
981 g_object_class_override_property (oclass: object_class, property_id: first_prop + GTK_EDITABLE_PROP_ENABLE_UNDO, name: "enable-undo");
982
983 return GTK_EDITABLE_NUM_PROPERTIES;
984}
985
986static void
987delegate_changed (GtkEditable *delegate,
988 gpointer editable)
989{
990 g_signal_emit (instance: editable, signal_id: signals[CHANGED], detail: 0);
991}
992
993static void
994delegate_notify (GObject *object,
995 GParamSpec *pspec,
996 gpointer data)
997{
998 gpointer iface;
999
1000 iface = g_type_interface_peek (instance_class: g_type_class_peek (G_OBJECT_TYPE (object)), iface_type: gtk_editable_get_type ());
1001 if (g_object_interface_find_property (g_iface: iface, property_name: pspec->name))
1002 g_object_notify (object: data, property_name: pspec->name);
1003}
1004
1005/**
1006 * gtk_editable_get_delegate:
1007 * @editable: a `GtkEditable`
1008 *
1009 * Gets the `GtkEditable` that @editable is delegating its
1010 * implementation to.
1011 *
1012 * Typically, the delegate is a [class@Gtk.Text] widget.
1013 *
1014 * Returns: (nullable) (transfer none): the delegate `GtkEditable`
1015 */
1016GtkEditable *
1017gtk_editable_get_delegate (GtkEditable *editable)
1018{
1019 return get_delegate (editable);
1020}
1021
1022/**
1023 * gtk_editable_init_delegate:
1024 * @editable: a `GtkEditable`
1025 *
1026 * Sets up a delegate for `GtkEditable`.
1027 *
1028 * This is assuming that the get_delegate vfunc in the `GtkEditable`
1029 * interface has been set up for the @editable's type.
1030 *
1031 * This is a helper function that should be called in instance init,
1032 * after creating the delegate object.
1033 */
1034void
1035gtk_editable_init_delegate (GtkEditable *editable)
1036{
1037 GtkEditable *delegate = get_delegate (editable);
1038 g_signal_connect (delegate, "notify", G_CALLBACK (delegate_notify), editable);
1039 g_signal_connect (delegate, "changed", G_CALLBACK (delegate_changed), editable);
1040}
1041
1042/**
1043 * gtk_editable_finish_delegate:
1044 * @editable: a `GtkEditable`
1045 *
1046 * Undoes the setup done by [method@Gtk.Editable.init_delegate].
1047 *
1048 * This is a helper function that should be called from dispose,
1049 * before removing the delegate object.
1050 */
1051void
1052gtk_editable_finish_delegate (GtkEditable *editable)
1053{
1054 GtkEditable *delegate = get_delegate (editable);
1055 g_signal_handlers_disconnect_by_func (delegate, delegate_notify, editable);
1056 g_signal_handlers_disconnect_by_func (delegate, delegate_changed, editable);
1057}
1058
1059/**
1060 * gtk_editable_delegate_set_property:
1061 * @object: a `GObject`
1062 * @prop_id: a property ID
1063 * @value: value to set
1064 * @pspec: the `GParamSpec` for the property
1065 *
1066 * Sets a property on the `GtkEditable` delegate for @object.
1067 *
1068 * This is a helper function that should be called in the `set_property`
1069 * function of your `GtkEditable` implementation, before handling your
1070 * own properties.
1071 *
1072 * Returns: %TRUE if the property was found
1073 */
1074gboolean
1075gtk_editable_delegate_set_property (GObject *object,
1076 guint prop_id,
1077 const GValue *value,
1078 GParamSpec *pspec)
1079{
1080 GtkEditable *delegate = get_delegate (GTK_EDITABLE (object));
1081 GType type = G_TYPE_FROM_INSTANCE (object);
1082 guint first_prop;
1083
1084 do {
1085 first_prop = GPOINTER_TO_UINT (g_type_get_qdata (type, quark_editable_data));
1086 type = g_type_parent (type);
1087 } while (first_prop == 0 && type != 0);
1088
1089 if (prop_id < first_prop)
1090 return FALSE;
1091
1092 switch (prop_id - first_prop)
1093 {
1094 case GTK_EDITABLE_PROP_TEXT:
1095 gtk_editable_set_text (editable: delegate, text: g_value_get_string (value));
1096 break;
1097
1098 case GTK_EDITABLE_PROP_EDITABLE:
1099 gtk_editable_set_editable (editable: delegate, is_editable: g_value_get_boolean (value));
1100 break;
1101
1102 case GTK_EDITABLE_PROP_WIDTH_CHARS:
1103 gtk_editable_set_width_chars (editable: delegate, n_chars: g_value_get_int (value));
1104 break;
1105
1106 case GTK_EDITABLE_PROP_MAX_WIDTH_CHARS:
1107 gtk_editable_set_max_width_chars (editable: delegate, n_chars: g_value_get_int (value));
1108 break;
1109
1110 case GTK_EDITABLE_PROP_XALIGN:
1111 gtk_editable_set_alignment (editable: delegate, xalign: g_value_get_float (value));
1112 break;
1113
1114 case GTK_EDITABLE_PROP_ENABLE_UNDO:
1115 gtk_editable_set_enable_undo (editable: delegate, enable_undo: g_value_get_boolean (value));
1116 break;
1117
1118 default:
1119 return FALSE;
1120 }
1121
1122 return TRUE;
1123}
1124
1125/**
1126 * gtk_editable_delegate_get_property:
1127 * @object: a `GObject`
1128 * @prop_id: a property ID
1129 * @value: value to set
1130 * @pspec: the `GParamSpec` for the property
1131 *
1132 * Gets a property of the `GtkEditable` delegate for @object.
1133 *
1134 * This is helper function that should be called in the `get_property`
1135 * function of your `GtkEditable` implementation, before handling your
1136 * own properties.
1137 *
1138 * Returns: %TRUE if the property was found
1139 */
1140gboolean
1141gtk_editable_delegate_get_property (GObject *object,
1142 guint prop_id,
1143 GValue *value,
1144 GParamSpec *pspec)
1145{
1146 GtkEditable *delegate = get_delegate (GTK_EDITABLE (object));
1147 int cursor_position, selection_bound;
1148 GType type = G_TYPE_FROM_INSTANCE (object);
1149 guint first_prop;
1150
1151 do {
1152 first_prop = GPOINTER_TO_UINT (g_type_get_qdata (type, quark_editable_data));
1153 type = g_type_parent (type);
1154 } while (first_prop == 0 && type != 0);
1155
1156 if (prop_id < first_prop)
1157 return FALSE;
1158
1159 switch (prop_id - first_prop)
1160 {
1161 case GTK_EDITABLE_PROP_TEXT:
1162 g_value_set_string (value, v_string: gtk_editable_get_text (editable: delegate));
1163 break;
1164
1165 case GTK_EDITABLE_PROP_CURSOR_POSITION:
1166 gtk_editable_get_selection_bounds (editable: delegate, start_pos: &cursor_position, end_pos: &selection_bound);
1167 g_value_set_int (value, v_int: cursor_position);
1168 break;
1169
1170 case GTK_EDITABLE_PROP_SELECTION_BOUND:
1171 gtk_editable_get_selection_bounds (editable: delegate, start_pos: &cursor_position, end_pos: &selection_bound);
1172 g_value_set_int (value, v_int: selection_bound);
1173 break;
1174
1175 case GTK_EDITABLE_PROP_EDITABLE:
1176 g_value_set_boolean (value, v_boolean: gtk_editable_get_editable (editable: delegate));
1177 break;
1178
1179 case GTK_EDITABLE_PROP_WIDTH_CHARS:
1180 g_value_set_int (value, v_int: gtk_editable_get_width_chars (editable: delegate));
1181 break;
1182
1183 case GTK_EDITABLE_PROP_MAX_WIDTH_CHARS:
1184 g_value_set_int (value, v_int: gtk_editable_get_max_width_chars (editable: delegate));
1185 break;
1186
1187 case GTK_EDITABLE_PROP_XALIGN:
1188 g_value_set_float (value, v_float: gtk_editable_get_alignment (editable: delegate));
1189 break;
1190
1191 case GTK_EDITABLE_PROP_ENABLE_UNDO:
1192 g_value_set_boolean (value, v_boolean: gtk_editable_get_enable_undo (editable: delegate));
1193 break;
1194
1195 default:
1196 return FALSE;
1197 }
1198
1199 return TRUE;
1200}
1201

source code of gtk/gtk/gtkeditable.c