gtkeditable.c 36.4 KB
Newer Older
Cody Russell's avatar
Cody Russell committed
1
/* GTK - The GIMP Toolkit
2
3
4
 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
 *
 * This library is free software; you can redistribute it and/or
5
 * modify it under the terms of the GNU Lesser General Public
6
7
8
9
10
11
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * 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
Javier Jardón's avatar
Javier Jardón committed
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
21
22
23
24
 * file for a list of people on the GTK+ Team.  See the ChangeLog
 * files for a list of changes.  These files are distributed with
 * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
 */

25
/**
Matthias Clasen's avatar
Matthias Clasen committed
26
 * GtkEditable:
27
 *
Matthias Clasen's avatar
Matthias Clasen committed
28
 * `GtkEditable` is an interface for text editing widgets.
29
 *
Matthias Clasen's avatar
Matthias Clasen committed
30
31
32
33
34
35
36
37
38
 * Typical examples of editable widgets are [class@Gtk.Entry] and
 * [class@Gtk.SpinButton]. It contains functions for generically manipulating
 * an editable widget, a large number of action signals used for key bindings,
 * and several signals that an application can connect to modify the behavior
 * of a widget.
 *
 * As an example of the latter usage, by connecting the following handler to
 * [signal@Gtk.Editable::insert-text], an application can convert all entry
 * into a widget into uppercase.
39
 *
40
41
 * ## Forcing entry to uppercase.
 *
Matthias Clasen's avatar
Matthias Clasen committed
42
 * ```c
43
 * #include <ctype.h>
44
45
 *
 * void
46
 * insert_text_handler (GtkEditable *editable,
47
48
49
 *                      const char  *text,
 *                      int          length,
 *                      int         *position,
50
51
 *                      gpointer     data)
 * {
52
 *   char *result = g_utf8_strup (text, length);
53
54
55
56
57
58
59
60
61
62
63
 *
 *   g_signal_handlers_block_by_func (editable,
 *                                (gpointer) insert_text_handler, data);
 *   gtk_editable_insert_text (editable, result, length, position);
 *   g_signal_handlers_unblock_by_func (editable,
 *                                      (gpointer) insert_text_handler, data);
 *
 *   g_signal_stop_emission_by_name (editable, "insert_text");
 *
 *   g_free (result);
 * }
Matthias Clasen's avatar
Matthias Clasen committed
64
 * ```
65
66
 *
 * ## Implementing GtkEditable
Matthias Clasen's avatar
Matthias Clasen committed
67
68
 *
 * The most likely scenario for implementing `GtkEditable` on your own widget
Matthias Clasen's avatar
Matthias Clasen committed
69
 * is that you will embed a `GtkText` inside a complex widget, and want to
Matthias Clasen's avatar
Matthias Clasen committed
70
 * delegate the editable functionality to that text widget. `GtkEditable`
71
72
 * provides some utility functions to make this easy.
 *
Matthias Clasen's avatar
Matthias Clasen committed
73
 * In your class_init function, call [func@Gtk.Editable.install_properties],
74
 * passing the first available property ID:
Matthias Clasen's avatar
Matthias Clasen committed
75
76
 *
 * ```c
77
78
79
 * static void
 * my_class_init (MyClass *class)
 * {
Matthias Clasen's avatar
Matthias Clasen committed
80
81
82
83
 *   ...
 *   g_object_class_install_properties (object_class, NUM_PROPERTIES, props);
 *   gtk_editable_install_properties (object_clas, NUM_PROPERTIES);
 *   ...
84
 * }
Matthias Clasen's avatar
Matthias Clasen committed
85
 * ```
86
 *
Matthias Clasen's avatar
Matthias Clasen committed
87
 * In your interface_init function for the `GtkEditable` interface, provide
88
89
 * an implementation for the get_delegate vfunc that returns your text widget:
 *
Matthias Clasen's avatar
Matthias Clasen committed
90
 * ```c
91
92
93
94
95
96
97
98
99
100
101
 * GtkEditable *
 * get_editable_delegate (GtkEditable *editable)
 * {
 *   return GTK_EDITABLE (MY_WIDGET (editable)->text_widget);
 * }
 *
 * static void
 * my_editable_init (GtkEditableInterface *iface)
 * {
 *   iface->get_delegate = get_editable_delegate;
 * }
Matthias Clasen's avatar
Matthias Clasen committed
102
 * ```
103
104
 *
 * You don't need to provide any other vfuncs. The default implementations
Matthias Clasen's avatar
Matthias Clasen committed
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
Matthias Clasen's avatar
Matthias Clasen committed
109
 * [method@Gtk.Editable.init_delegate]:
110
 *
Matthias Clasen's avatar
Matthias Clasen committed
111
 * ```c
112
113
114
115
116
117
118
119
 * static void
 * my_widget_init (MyWidget *self)
 * {
 *   ...
 *   self->text_widget = gtk_text_new ();
 *   gtk_editable_init_delegate (GTK_EDITABLE (self));
 *   ...
 * }
Matthias Clasen's avatar
Matthias Clasen committed
120
121
122
 * ```
 *
 * In your dispose function, call [method@Gtk.Editable.finish_delegate] before
123
124
 * destroying your text widget:
 *
Matthias Clasen's avatar
Matthias Clasen committed
125
 * ```c
126
127
128
129
130
131
132
133
 * static void
 * my_widget_dispose (GObject *object)
 * {
 *   ...
 *   gtk_editable_finish_delegate (GTK_EDITABLE (self));
 *   g_clear_pointer (&self->text_widget, gtk_widget_unparent);
 *   ...
 * }
Matthias Clasen's avatar
Matthias Clasen committed
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
 *
Matthias Clasen's avatar
Matthias Clasen committed
139
 * ```c
140
141
142
143
144
145
 *   ...
 *   if (gtk_editable_delegate_set_property (object, prop_id, value, pspec))
 *     return;
 *
 *   switch (prop_id)
 *   ...
Matthias Clasen's avatar
Matthias Clasen committed
146
147
148
149
150
151
152
153
154
155
 * ```
 *
 * It is important to note that if you create a `GtkEditable` that uses
 * a delegate, the low level [signal@Gtk.Editable::insert-text] and
 * [signal@Gtk.Editable::delete-text] signals will be propagated from the
 * "wrapper" editable to the delegate, but they will not be propagated from
 * the delegate to the "wrapper" editable, as they would cause an infinite
 * recursion. If you wish to connect to the [signal@Gtk.Editable::insert-text]
 * and [signal@Gtk.Editable::delete-text] signals, you will need to connect
 * to them on the delegate obtained via [method@Gtk.Editable.get_delegate].
156
157
 */

158
#include "config.h"
159
#include <string.h>
Owen Taylor's avatar
Owen Taylor committed
160

161
#include "gtkeditable.h"
162
#include "gtkentrybuffer.h"
163
#include "gtkmarshalers.h"
164
#include "gtkprivate.h"
165

166
G_DEFINE_INTERFACE (GtkEditable, gtk_editable, GTK_TYPE_WIDGET)
167

168
169
170
171
172
173
174
enum {
  CHANGED,
  DELETE_TEXT,
  INSERT_TEXT,
  N_SIGNALS
};

175
static GQuark quark_editable_data;
176
static guint signals[N_SIGNALS];
177

178
179
180
181
182
183
184
185
186
187
static GtkEditable *
get_delegate (GtkEditable *editable)
{
  GtkEditableInterface *iface = GTK_EDITABLE_GET_IFACE (editable);

  if (iface->get_delegate)
    return iface->get_delegate (editable);

  return NULL;
}
188

189
190
191
192
193
static void
gtk_editable_default_do_insert_text (GtkEditable *editable,
                                     const char  *text,
                                     int          length,
                                     int         *position)
194
{
195
  g_signal_emit (editable, signals[INSERT_TEXT], 0, text, length, position);
196
}
197

198
199
200
201
202
203
204
205
206
207
#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);
208

209
210
211
212
  if (delegate)
    gtk_editable_insert_text (delegate, text, length, position);
  else
    warn_no_delegate ("insert_text");
213
214
}

215
static void
216
217
218
gtk_editable_default_do_delete_text (GtkEditable *editable,
                                     int          start_pos,
                                     int          end_pos)
219
{
220
  g_signal_emit (editable, signals[DELETE_TEXT], 0, start_pos, end_pos);
221
}
222

223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
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.
   *
Matthias Clasen's avatar
Matthias Clasen committed
301
302
303
304
305
306
   * 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.
307
   */
308
309
310
311
312
313
314
315
316
317
318
319
320
321
  signals[INSERT_TEXT] =
    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);
  g_signal_set_va_marshaller (signals[INSERT_TEXT],
                              G_TYPE_FROM_INTERFACE (iface),
                              _gtk_marshal_VOID__STRING_INT_POINTERv);
322
323
324
325
326
327

  /**
   * GtkEditable::delete-text:
   * @editable: the object which received the signal
   * @start_pos: the starting position
   * @end_pos: the end position
Matthias Clasen's avatar
Matthias Clasen committed
328
329
330
331
332
333
334
335
336
337
   *
   * 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
   * [method@Gtk.Editable.delete_text].
338
   */
339
340
341
342
343
344
345
346
347
348
349
350
351
  signals[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);
  g_signal_set_va_marshaller (signals[DELETE_TEXT],
                              G_TYPE_FROM_INTERFACE (iface),
                              _gtk_marshal_VOID__INT_INTv);
352
353
354
355
356

  /**
   * GtkEditable::changed:
   * @editable: the object which received the signal
   *
Matthias Clasen's avatar
Matthias Clasen committed
357
358
   * Emitted at the end of a single user-visible operation on the
   * contents.
359
360
361
362
363
364
   *
   * 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).
Matthias Clasen's avatar
Matthias Clasen committed
365
   */
366
367
368
369
370
371
372
373
  signals[CHANGED] =
    g_signal_new (I_("changed"),
                  GTK_TYPE_EDITABLE,
                  G_SIGNAL_RUN_LAST,
                  G_STRUCT_OFFSET (GtkEditableInterface, changed),
                  NULL, NULL,
                  NULL,
                  G_TYPE_NONE, 0);
374

Matthias Clasen's avatar
Matthias Clasen committed
375
376
377
378
379
  /**
   * GtkEditable:text: (attributes org.gtk.Property.get=gtk_editable_get_text org.gtk.Property.set=gtk_editable_set_text)
   *
   * The contents of the entry.
   */
380
  g_object_interface_install_property (iface,
381
      g_param_spec_string ("text", NULL, NULL,
382
383
384
                           "",
                           GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));

Matthias Clasen's avatar
Matthias Clasen committed
385
386
387
388
389
  /**
   * GtkEditable:cursor-position: (attributes org.gtk.Property.get=gtk_editable_get_position org.gtk.Property.set=gtk_editable_set_position)
   *
   * The current position of the insertion cursor in chars.
   */
390
  g_object_interface_install_property (iface,
391
      g_param_spec_int ("cursor-position", NULL, NULL,
392
393
394
395
                        0, GTK_ENTRY_BUFFER_MAX_SIZE,
                        0,
                        GTK_PARAM_READABLE));

Matthias Clasen's avatar
Matthias Clasen committed
396
397
398
399
400
  /**
   * GtkEditable:enable-undo: (attributes org.gtk.Property.get=gtk_editable_get_enable_undo org.gtk.Property.setg=gtk_editable_set_enable_undo)
   *
   * If undo/redo should be enabled for the editable.
   */
401
  g_object_interface_install_property (iface,
402
      g_param_spec_boolean ("enable-undo", NULL, NULL,
403
404
405
                            TRUE,
                            GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));

Matthias Clasen's avatar
Matthias Clasen committed
406
407
408
409
410
  /**
   * GtkEditable:selection-bound:
   *
   * The position of the opposite end of the selection from the cursor in chars.
   */
411
  g_object_interface_install_property (iface,
412
      g_param_spec_int ("selection-bound", NULL, NULL,
413
414
415
416
                        0, GTK_ENTRY_BUFFER_MAX_SIZE,
                        0,
                        GTK_PARAM_READABLE));

Matthias Clasen's avatar
Matthias Clasen committed
417
418
419
420
421
  /**
   * GtkEditable:editable: (attributes org.gtk.Property.get=gtk_editable_get_editable org.gtk.Property.set=gtk_editable_set_editable)
   *
   * Whether the entry contents can be edited.
   */
422
  g_object_interface_install_property (iface,
423
      g_param_spec_boolean ("editable", NULL, NULL,
424
425
426
                            TRUE,
                            GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));

Matthias Clasen's avatar
Matthias Clasen committed
427
428
429
430
431
  /**
   * GtkEditable:width-chars: (attributes org.gtk.Property.get=gtk_editable_get_width_chars org.gtk.Property.set=gtk_editable_set_width_chars)
   *
   * Number of characters to leave space for in the entry.
   */
432
  g_object_interface_install_property (iface,
433
      g_param_spec_int ("width-chars", NULL, NULL,
434
435
436
437
                        -1, G_MAXINT,
                        -1,
                        GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));

Matthias Clasen's avatar
Matthias Clasen committed
438
439
440
441
442
  /**
   * 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)
   *
   * The desired maximum width of the entry, in characters.
   */
443
  g_object_interface_install_property (iface,
444
      g_param_spec_int ("max-width-chars", NULL, NULL,
445
446
447
448
                        -1, G_MAXINT,
                        -1,
                        GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));

Matthias Clasen's avatar
Matthias Clasen committed
449
450
451
452
453
454
455
  /**
   * GtkEditable:xalign: (attributes org.gtk.Property.get=gtk_editable_get_alignment org.gtk.Property.set=gtk_editable_set_alignment)
   *
   * The horizontal alignment, from 0 (left) to 1 (right).
   *
   * Reversed for RTL layouts.
   */
456
  g_object_interface_install_property (iface,
457
      g_param_spec_float ("xalign", NULL, NULL,
458
459
460
                          0.0, 1.0,
                          0.0,
                          GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
461
462
}

463
/**
Jasper St. Pierre's avatar
Jasper St. Pierre committed
464
 * gtk_editable_insert_text: (virtual do_insert_text)
Matthias Clasen's avatar
Matthias Clasen committed
465
 * @editable: a `GtkEditable`
466
467
 * @text: the text to append
 * @length: the length of the text in bytes, or -1
468
 * @position: (inout): location of the position text will be inserted at
Matthias Clasen's avatar
Matthias Clasen committed
469
 *
470
 * Inserts @length bytes of @text into the contents of the
471
 * widget, at position @position.
472
 *
Matthias Clasen's avatar
Matthias Clasen committed
473
474
475
 * Note that the position is in characters, not in bytes.
 * The function updates @position to point after the newly
 * inserted text.
Matthias Clasen's avatar
Matthias Clasen committed
476
 */
477
478
void
gtk_editable_insert_text (GtkEditable *editable,
479
480
481
                          const char  *text,
                          int          length,
                          int         *position)
482
483
{
  g_return_if_fail (GTK_IS_EDITABLE (editable));
Owen Taylor's avatar
Owen Taylor committed
484
  g_return_if_fail (position != NULL);
Owen Taylor's avatar
Owen Taylor committed
485

486
487
  if (length < 0)
    length = strlen (text);
488
  
489
  GTK_EDITABLE_GET_IFACE (editable)->do_insert_text (editable, text, length, position);
490
491
}

492
/**
Jasper St. Pierre's avatar
Jasper St. Pierre committed
493
 * gtk_editable_delete_text: (virtual do_delete_text)
Matthias Clasen's avatar
Matthias Clasen committed
494
 * @editable: a `GtkEditable`
495
496
497
 * @start_pos: start position
 * @end_pos: end position
 *
Matthias Clasen's avatar
Matthias Clasen committed
498
499
500
501
502
503
 * Deletes a sequence of characters.
 *
 * The characters that are deleted are those characters at positions
 * from @start_pos up to, but not including @end_pos. If @end_pos is
 * negative, then the characters deleted are those from @start_pos to
 * the end of the text.
Matthias Clasen's avatar
Matthias Clasen committed
504
505
506
 *
 * Note that the positions are specified in characters, not bytes.
 */
507
508
void
gtk_editable_delete_text (GtkEditable *editable,
509
510
                          int          start_pos,
                          int          end_pos)
511
512
513
{
  g_return_if_fail (GTK_IS_EDITABLE (editable));

514
  GTK_EDITABLE_GET_IFACE (editable)->do_delete_text (editable, start_pos, end_pos);
515
516
}

517
518
/**
 * gtk_editable_get_chars:
Matthias Clasen's avatar
Matthias Clasen committed
519
 * @editable: a `GtkEditable`
Matthias Clasen's avatar
Matthias Clasen committed
520
521
 * @start_pos: start of text
 * @end_pos: end of text
522
 *
Matthias Clasen's avatar
Matthias Clasen committed
523
524
525
526
527
528
529
 * Retrieves a sequence of characters.
 *
 * The characters that are retrieved are those characters at positions
 * from @start_pos up to, but not including @end_pos. If @end_pos is negative,
 * then the characters retrieved are those characters from @start_pos to
 * the end of the text.
 *
530
531
 * Note that positions are specified in characters, not bytes.
 *
532
 * Returns: (transfer full): a pointer to the contents of the widget as a
Matthias Clasen's avatar
Matthias Clasen committed
533
534
 *   string. This string is allocated by the `GtkEditable` implementation
 *   and should be freed by the caller.
Matthias Clasen's avatar
Matthias Clasen committed
535
 */
Matthias Clasen's avatar
Matthias Clasen committed
536
char *
Owen Taylor's avatar
Owen Taylor committed
537
gtk_editable_get_chars (GtkEditable *editable,
538
539
                        int          start_pos,
                        int          end_pos)
540
{
541
542
543
544
  const char *text;
  int length;
  int start_index,end_index;

545
  g_return_val_if_fail (GTK_IS_EDITABLE (editable), NULL);
546

547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
  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);
}

/**
Matthias Clasen's avatar
Matthias Clasen committed
563
564
565
566
 * gtk_editable_get_text: (attributes org.gtk.Method.get_property=text)
 * @editable: a `GtkEditable`
 *
 * Retrieves the contents of @editable.
567
 *
Matthias Clasen's avatar
Matthias Clasen committed
568
 * The returned string is owned by GTK and must not be modified or freed.
569
 *
Matthias Clasen's avatar
Matthias Clasen committed
570
 * Returns: (transfer none): a pointer to the contents of the editable
571
572
573
574
575
576
577
578
579
580
 */
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);
}

/**
Matthias Clasen's avatar
Matthias Clasen committed
581
582
 * gtk_editable_set_text: (attributes org.gtk.Method.set_property=text)
 * @editable: a `GtkEditable`
583
 * @text: the text to set
584
 *
Matthias Clasen's avatar
Matthias Clasen committed
585
586
587
 * Sets the text in the editable to the given value.
 *
 * This is replacing the current contents.
588
589
590
591
592
593
594
595
596
597
598
599
600
601
 */
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));
602
603
}

604
/**
Matthias Clasen's avatar
Matthias Clasen committed
605
606
607
 * gtk_editable_set_position: (attributes org.gtk.Method.set_property=cursor-position)
 * @editable: a `GtkEditable`
 * @position: the position of the cursor
608
609
 *
 * Sets the cursor position in the editable to the given value.
Matthias Clasen's avatar
Matthias Clasen committed
610
 *
Matthias Clasen's avatar
Matthias Clasen committed
611
612
613
614
 * The cursor is displayed before the character with the given (base 0)
 * index in the contents of the editable. The value must be less than
 * or equal to the number of characters in the editable. A value of -1
 * indicates that the position should be set after the last character
Matthias Clasen's avatar
Matthias Clasen committed
615
616
 * of the editable. Note that @position is in characters, not in bytes.
 */
Owen Taylor's avatar
Owen Taylor committed
617
void
618
619
gtk_editable_set_position (GtkEditable *editable,
                           int          position)
Owen Taylor's avatar
Owen Taylor committed
620
621
622
{
  g_return_if_fail (GTK_IS_EDITABLE (editable));

623
  GTK_EDITABLE_GET_IFACE (editable)->set_selection_bounds (editable, position, position);
Owen Taylor's avatar
Owen Taylor committed
624
625
}

626
/**
Matthias Clasen's avatar
Matthias Clasen committed
627
628
629
630
631
 * gtk_editable_get_position: (attributes org.gtk.Method.get_property=cursor-position)
 * @editable: a `GtkEditable`
 *
 * Retrieves the current position of the cursor relative
 * to the start of the content of the editable.
632
 *
Matthias Clasen's avatar
Matthias Clasen committed
633
 * Note that this position is in characters, not in bytes.
634
 *
635
 * Returns: the cursor position
Matthias Clasen's avatar
Matthias Clasen committed
636
 */
637
int
638
gtk_editable_get_position (GtkEditable *editable)
Owen Taylor's avatar
Owen Taylor committed
639
{
640
641
  int start, end;

Owen Taylor's avatar
Owen Taylor committed
642
  g_return_val_if_fail (GTK_IS_EDITABLE (editable), 0);
Owen Taylor's avatar
Owen Taylor committed
643

644
645
646
  GTK_EDITABLE_GET_IFACE (editable)->get_selection_bounds (editable, &start, &end);

  return end;
647
648
}

649
650
/**
 * gtk_editable_get_selection_bounds:
Matthias Clasen's avatar
Matthias Clasen committed
651
 * @editable: a `GtkEditable`
Matthias Clasen's avatar
Matthias Clasen committed
652
653
 * @start_pos: (out) (optional): location to store the starting position
 * @end_pos: (out) (optional): location to store the end position
654
 *
655
 * Retrieves the selection bound of the editable.
Matthias Clasen's avatar
Matthias Clasen committed
656
 *
657
658
659
 * @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.
660
 *
Matthias Clasen's avatar
Matthias Clasen committed
661
 * Note that positions are specified in characters, not bytes.
662
 *
663
 * Returns: %TRUE if there is a non-empty selection, %FALSE otherwise
Matthias Clasen's avatar
Matthias Clasen committed
664
 */
Owen Taylor's avatar
Owen Taylor committed
665
666
gboolean
gtk_editable_get_selection_bounds (GtkEditable *editable,
667
668
                                   int         *start_pos,
                                   int         *end_pos)
669
{
670
  int tmp_start, tmp_end;
Owen Taylor's avatar
Owen Taylor committed
671
  gboolean result;
Matthias Clasen's avatar
Matthias Clasen committed
672

Owen Taylor's avatar
Owen Taylor committed
673
  g_return_val_if_fail (GTK_IS_EDITABLE (editable), FALSE);
674

675
  result = GTK_EDITABLE_GET_IFACE (editable)->get_selection_bounds (editable, &tmp_start, &tmp_end);
676

Owen Taylor's avatar
Owen Taylor committed
677
678
679
680
  if (start_pos)
    *start_pos = MIN (tmp_start, tmp_end);
  if (end_pos)
    *end_pos = MAX (tmp_start, tmp_end);
681

Owen Taylor's avatar
Owen Taylor committed
682
  return result;
683
684
}

685
686
/**
 * gtk_editable_delete_selection:
Matthias Clasen's avatar
Matthias Clasen committed
687
 * @editable: a `GtkEditable`
688
689
 *
 * Deletes the currently selected text of the editable.
Matthias Clasen's avatar
Matthias Clasen committed
690
 *
691
 * This call doesn’t do anything if there is no selected text.
Matthias Clasen's avatar
Matthias Clasen committed
692
 */
693
694
695
void
gtk_editable_delete_selection (GtkEditable *editable)
{
696
  int start, end;
697

698
699
  g_return_if_fail (GTK_IS_EDITABLE (editable));

Owen Taylor's avatar
Owen Taylor committed
700
701
  if (gtk_editable_get_selection_bounds (editable, &start, &end))
    gtk_editable_delete_text (editable, start, end);
702
703
}

704
/**
Jasper St. Pierre's avatar
Jasper St. Pierre committed
705
 * gtk_editable_select_region: (virtual set_selection_bounds)
Matthias Clasen's avatar
Matthias Clasen committed
706
 * @editable: a `GtkEditable`
Matthias Clasen's avatar
Matthias Clasen committed
707
708
 * @start_pos: start of region
 * @end_pos: end of region
709
 *
710
 * Selects a region of text.
Matthias Clasen's avatar
Matthias Clasen committed
711
 *
712
713
714
715
 * 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.
Matthias Clasen's avatar
Matthias Clasen committed
716
 *
Matthias Clasen's avatar
Matthias Clasen committed
717
718
 * Note that positions are specified in characters, not bytes.
 */
719
720
void
gtk_editable_select_region (GtkEditable *editable,
721
722
                            int          start_pos,
                            int          end_pos)
723
{
724
  g_return_if_fail (GTK_IS_EDITABLE (editable));
Matthias Clasen's avatar
Matthias Clasen committed
725

726
  GTK_EDITABLE_GET_IFACE (editable)->set_selection_bounds (editable, start_pos, end_pos);
727
728
}

729
/**
Matthias Clasen's avatar
Matthias Clasen committed
730
731
 * gtk_editable_set_editable: (attributes org.gtk.Method.set_property=editable)
 * @editable: a `GtkEditable`
732
733
 * @is_editable: %TRUE if the user is allowed to edit the text
 *   in the widget
734
 *
Matthias Clasen's avatar
Matthias Clasen committed
735
 * Determines if the user can edit the text in the editable widget.
Matthias Clasen's avatar
Matthias Clasen committed
736
 */
737
void
738
739
gtk_editable_set_editable (GtkEditable *editable,
                           gboolean     is_editable)
740
{
741
  g_return_if_fail (GTK_IS_EDITABLE (editable));
742
743

  g_object_set (editable, "editable", is_editable, NULL);
744
745
}

746
/**
Matthias Clasen's avatar
Matthias Clasen committed
747
748
 * gtk_editable_get_editable: (attributes org.gtk.Method.get_property=editable)
 * @editable: a `GtkEditable`
749
 *
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
 * Retrieves whether @editable is 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;
}


/**
Matthias Clasen's avatar
Matthias Clasen committed
768
769
 * gtk_editable_get_alignment: (attributes org.gtk.Method.get_property=xalign)
 * @editable: a `GtkEditable`
770
 *
Matthias Clasen's avatar
Matthias Clasen committed
771
 * Gets the alignment of the editable.
772
773
 *
 * Returns: the alignment
Matthias Clasen's avatar
Matthias Clasen committed
774
 */
775
776
777
778
779
780
781
782
783
784
785
786
787
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;
}

/**
Matthias Clasen's avatar
Matthias Clasen committed
788
789
 * gtk_editable_set_alignment: (attributes org.gtk.Method.set_property=xalign)
 * @editable: a `GtkEditable`
790
 * @xalign: The horizontal alignment, from 0 (left) to 1 (right).
Matthias Clasen's avatar
Matthias Clasen committed
791
 *   Reversed for RTL layouts
792
793
794
795
796
 *
 * 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.
Matthias Clasen's avatar
Matthias Clasen committed
797
 */
798
void
799
800
gtk_editable_set_alignment (GtkEditable *editable,
                            float        xalign)
801
{
802
  g_return_if_fail (GTK_IS_EDITABLE (editable));
803
804

  g_object_set (editable, "xalign", xalign, NULL);
805
806
}

807
/**
Matthias Clasen's avatar
Matthias Clasen committed
808
809
 * gtk_editable_get_width_chars: (attributes org.gtk.Method.get_property=width-chars)
 * @editable: a `GtkEditable`
810
 *
Matthias Clasen's avatar
Matthias Clasen committed
811
812
 * Gets the number of characters of space reserved
 * for the contents of the editable.
813
814
 *
 * Returns: number of chars to request space for, or negative if unset
Matthias Clasen's avatar
Matthias Clasen committed
815
 */
816
817
818
819
820
821
822
823
824
825
826
827
828
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;
}

/**
Matthias Clasen's avatar
Matthias Clasen committed
829
830
 * gtk_editable_set_width_chars: (attributes org.gtk.Method.set_property=width-chars)
 * @editable: a `GtkEditable`
831
832
833
834
 * @n_chars: width in chars
 *
 * Changes the size request of the editable to be about the
 * right size for @n_chars characters.
Matthias Clasen's avatar
Matthias Clasen committed
835
 *
836
837
838
 * 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.
Matthias Clasen's avatar
Matthias Clasen committed
839
 */
840
void
841
842
gtk_editable_set_width_chars (GtkEditable *editable,
                              int          n_chars)
843
{
844
  g_return_if_fail (GTK_IS_EDITABLE (editable));
845
846

  g_object_set (editable, "width-chars", n_chars, NULL);
847
848
}

849
/**
Matthias Clasen's avatar
Matthias Clasen committed
850
851
 * gtk_editable_get_max_width_chars: (attributes org.gtk.Method.get_property=max-width-chars)
 * @editable: a `GtkEditable`
852
 *
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
 * Retrieves the desired maximum width of @editable, in characters.
 *
 * 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;
}

/**
Matthias Clasen's avatar
Matthias Clasen committed
870
871
 * gtk_editable_set_max_width_chars: (attributes org.gtk.Method.set_property=max-width-chars)
 * @editable: a `GtkEditable`
872
873
874
 * @n_chars: the new desired maximum width, in characters
 *
 * Sets the desired maximum width in characters of @editable.
Matthias Clasen's avatar
Matthias Clasen committed
875
 */
876
void
877
878
gtk_editable_set_max_width_chars (GtkEditable *editable,
                                  int          n_chars)
879
880
881
{
  g_return_if_fail (GTK_IS_EDITABLE (editable));

882
  g_object_set (editable, "max-width-chars", n_chars, NULL);
883
}
884

885
/**
Matthias Clasen's avatar
Matthias Clasen committed
886
887
 * gtk_editable_get_enable_undo: (attributes org.gtk.Method.get_property=enable-undo)
 * @editable: a `GtkEditable`
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
 *
 * Gets if undo/redo actions are enabled for @editable
 *
 * Returns: %TRUE if undo is enabled
 */
gboolean
gtk_editable_get_enable_undo (GtkEditable *editable)
{
  gboolean enable_undo;

  g_return_val_if_fail (GTK_IS_EDITABLE (editable), 0);

  g_object_get (editable, "enable-undo", &enable_undo, NULL);

  return enable_undo;
}

/**
Matthias Clasen's avatar
Matthias Clasen committed
906
907
 * gtk_editable_set_enable_undo: (attributes org.gtk.Method.set_property=enable-undo)
 * @editable: a `GtkEditable`
908
909
 * @enable_undo: if undo/redo should be enabled
 *
Matthias Clasen's avatar
Matthias Clasen committed
910
911
 * If enabled, changes to @editable will be saved for undo/redo
 * actions.
912
 *
Matthias Clasen's avatar
Matthias Clasen committed
913
914
915
 * This results in an additional copy of text changes and are not
 * stored in secure memory. As such, undo is forcefully disabled
 * when [property@Gtk.Text:visibility] is set to %FALSE.
916
917
918
919
920
921
922
923
924
925
 */
void
gtk_editable_set_enable_undo (GtkEditable *editable,
                              gboolean     enable_undo)
{
  g_return_if_fail (GTK_IS_EDITABLE (editable));

  g_object_set (editable, "enable-undo", enable_undo, NULL);
}

926
/**
927
 * gtk_editable_install_properties:
Matthias Clasen's avatar
Matthias Clasen committed
928
 * @object_class: a `GObjectClass`
929
930
 * @first_prop: property ID to use for the first property
 *
Matthias Clasen's avatar
Matthias Clasen committed
931
 * Overrides the `GtkEditable` properties for @class.
932
933
934
935
 *
 * This is a helper function that should be called in class_init,
 * after installing your own properties.
 *
Matthias Clasen's avatar
Matthias Clasen committed
936
937
938
939
 * Note that your class must have "text", "cursor-position",
 * "selection-bound", "editable", "width-chars", "max-width-chars",
 * "xalign" and "enable-undo" properties for this function to work.
 *
940
 * To handle the properties in your set_property and get_property
Matthias Clasen's avatar
Matthias Clasen committed
941
942
943
944
945
946
 * functions, you can either use [func@Gtk.Editable.delegate_set_property]
 * and [func@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 [enum@Gtk.EditableProperties] enumeration to get the
 * property IDs for these properties.
 *
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
 * 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");
964
  g_object_class_override_property (object_class, first_prop + GTK_EDITABLE_PROP_ENABLE_UNDO, "enable-undo");
965
966
967
968
969
970
971
972

  return GTK_EDITABLE_NUM_PROPERTIES;
}

static void
delegate_changed (GtkEditable *delegate,
                  gpointer     editable)
{
973
  g_signal_emit (editable, signals[CHANGED], 0);
974
975
976
977
978
979
980
981
982
983
984
985
986
987
}

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);
}

988
989
/**
 * gtk_editable_get_delegate:
Matthias Clasen's avatar
Matthias Clasen committed
990
991
992
993
 * @editable: a `GtkEditable`
 *
 * Gets the `GtkEditable` that @editable is delegating its
 * implementation to.
994
 *
Matthias Clasen's avatar
Matthias Clasen committed
995
 * Typically, the delegate is a [class@Gtk.Text] widget.
996
 *
Matthias Clasen's avatar
Matthias Clasen committed
997
 * Returns: (nullable) (transfer none): the delegate `GtkEditable`
998
999
1000
 */
GtkEditable *
gtk_editable_get_delegate (GtkEditable *editable)