1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2/* GTK - The GIMP Toolkit
3 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * Copyright (C) 2004-2006 Christian Hammond
5 * Copyright (C) 2008 Cody Russell
6 * Copyright (C) 2008 Red Hat, Inc.
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22/*
23 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
24 * file for a list of people on the GTK+ Team. See the ChangeLog
25 * files for a list of changes. These files are distributed with
26 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
27 */
28
29#include "config.h"
30
31#include "gtkentryprivate.h"
32
33#include "gtkaccessibleprivate.h"
34#include "gtkadjustment.h"
35#include "gtkbox.h"
36#include "gtkbutton.h"
37#include "gtkcelleditable.h"
38#include "gtkcelllayout.h"
39#include "gtkdebug.h"
40#include "gtkeditable.h"
41#include "gtkemojichooser.h"
42#include "gtkemojicompletion.h"
43#include "gtkentrybuffer.h"
44#include "gtkgesturedrag.h"
45#include "gtkimageprivate.h"
46#include "gtkimcontextsimple.h"
47#include "gtkintl.h"
48#include "gtklabel.h"
49#include "gtkmain.h"
50#include "gtkmarshalers.h"
51#include "gtkpango.h"
52#include "gtkpopover.h"
53#include "gtkprivate.h"
54#include "gtkprogressbar.h"
55#include "gtksettings.h"
56#include "gtksnapshot.h"
57#include "gtktextprivate.h"
58#include "gtktexthandleprivate.h"
59#include "gtktextutil.h"
60#include "gtktooltip.h"
61#include "gtktreeselection.h"
62#include "gtktreeview.h"
63#include "gtktypebuiltins.h"
64#include "gtkwidgetprivate.h"
65#include "gtkwindow.h"
66#include "gtknative.h"
67#include "gtkgestureclick.h"
68#include "gtkdragsourceprivate.h"
69#include "gtkdragicon.h"
70#include "gtkwidgetpaintable.h"
71
72#include <cairo-gobject.h>
73#include <string.h>
74
75/**
76 * GtkEntry:
77 *
78 * `GtkEntry` is a single line text entry widget.
79 *
80 * ![An example GtkEntry](entry.png)
81 *
82 * A fairly large set of key bindings are supported by default. If the
83 * entered text is longer than the allocation of the widget, the widget
84 * will scroll so that the cursor position is visible.
85 *
86 * When using an entry for passwords and other sensitive information, it
87 * can be put into “password mode” using [method@Gtk.Entry.set_visibility].
88 * In this mode, entered text is displayed using a “invisible” character.
89 * By default, GTK picks the best invisible character that is available
90 * in the current font, but it can be changed with
91 * [method@Gtk.Entry.set_invisible_char].
92 *
93 * `GtkEntry` has the ability to display progress or activity
94 * information behind the text. To make an entry display such information,
95 * use [method@Gtk.Entry.set_progress_fraction] or
96 * [method@Gtk.Entry.set_progress_pulse_step].
97 *
98 * Additionally, `GtkEntry` can show icons at either side of the entry.
99 * These icons can be activatable by clicking, can be set up as drag source
100 * and can have tooltips. To add an icon, use
101 * [method@Gtk.Entry.set_icon_from_gicon] or one of the various other functions
102 * that set an icon from an icon name or a paintable. To trigger an action when
103 * the user clicks an icon, connect to the [signal@Gtk.Entry::icon-press] signal.
104 * To allow DND operations from an icon, use
105 * [method@Gtk.Entry.set_icon_drag_source]. To set a tooltip on an icon, use
106 * [method@Gtk.Entry.set_icon_tooltip_text] or the corresponding function
107 * for markup.
108 *
109 * Note that functionality or information that is only available by clicking
110 * on an icon in an entry may not be accessible at all to users which are not
111 * able to use a mouse or other pointing device. It is therefore recommended
112 * that any such functionality should also be available by other means, e.g.
113 * via the context menu of the entry.
114 *
115 * # CSS nodes
116 *
117 * ```
118 * entry[.flat][.warning][.error]
119 * ├── text[.readonly]
120 * ├── image.left
121 * ├── image.right
122 * ╰── [progress[.pulse]]
123 * ```
124 *
125 * `GtkEntry` has a main node with the name entry. Depending on the properties
126 * of the entry, the style classes .read-only and .flat may appear. The style
127 * classes .warning and .error may also be used with entries.
128 *
129 * When the entry shows icons, it adds subnodes with the name image and the
130 * style class .left or .right, depending on where the icon appears.
131 *
132 * When the entry shows progress, it adds a subnode with the name progress.
133 * The node has the style class .pulse when the shown progress is pulsing.
134 *
135 * For all the subnodes added to the text node in various situations,
136 * see [class@Gtk.Text].
137 *
138 * # GtkEntry as GtkBuildable
139 *
140 * The `GtkEntry` implementation of the `GtkBuildable` interface supports a
141 * custom <attributes> element, which supports any number of <attribute>
142 * elements. The <attribute> element has attributes named “name“, “value“,
143 * “start“ and “end“ and allows you to specify `PangoAttribute` values for
144 * this label.
145 *
146 * An example of a UI definition fragment specifying Pango attributes:
147 * ```xml
148 * <object class="GtkEntry">
149 * <attributes>
150 * <attribute name="weight" value="PANGO_WEIGHT_BOLD"/>
151 * <attribute name="background" value="red" start="5" end="10"/>
152 * </attributes>
153 * </object>
154 * ```
155 *
156 * The start and end attributes specify the range of characters to which the
157 * Pango attribute applies. If start and end are not specified, the attribute
158 * is applied to the whole text. Note that specifying ranges does not make much
159 * sense with translatable attributes. Use markup embedded in the translatable
160 * content instead.
161 *
162 * # Accessibility
163 *
164 * `GtkEntry` uses the %GTK_ACCESSIBLE_ROLE_TEXT_BOX role.
165 */
166
167#define MAX_ICONS 2
168
169#define IS_VALID_ICON_POSITION(pos) \
170 ((pos) == GTK_ENTRY_ICON_PRIMARY || \
171 (pos) == GTK_ENTRY_ICON_SECONDARY)
172
173static GQuark quark_entry_completion = 0;
174
175typedef struct _EntryIconInfo EntryIconInfo;
176
177typedef struct _GtkEntryPrivate GtkEntryPrivate;
178struct _GtkEntryPrivate
179{
180 EntryIconInfo *icons[MAX_ICONS];
181
182 GtkWidget *text;
183 GtkWidget *progress_widget;
184
185 guint show_emoji_icon : 1;
186 guint editing_canceled : 1; /* Only used by GtkCellRendererText */
187};
188
189struct _EntryIconInfo
190{
191 GtkWidget *widget;
192 char *tooltip;
193 guint nonactivatable : 1;
194 guint in_drag : 1;
195
196 GdkDragAction actions;
197 GdkContentProvider *content;
198};
199
200enum {
201 ACTIVATE,
202 ICON_PRESS,
203 ICON_RELEASE,
204 LAST_SIGNAL
205};
206
207enum {
208 PROP_0,
209 PROP_BUFFER,
210 PROP_MAX_LENGTH,
211 PROP_VISIBILITY,
212 PROP_HAS_FRAME,
213 PROP_INVISIBLE_CHAR,
214 PROP_ACTIVATES_DEFAULT,
215 PROP_SCROLL_OFFSET,
216 PROP_TRUNCATE_MULTILINE,
217 PROP_OVERWRITE_MODE,
218 PROP_TEXT_LENGTH,
219 PROP_INVISIBLE_CHAR_SET,
220 PROP_PROGRESS_FRACTION,
221 PROP_PROGRESS_PULSE_STEP,
222 PROP_PAINTABLE_PRIMARY,
223 PROP_PAINTABLE_SECONDARY,
224 PROP_ICON_NAME_PRIMARY,
225 PROP_ICON_NAME_SECONDARY,
226 PROP_GICON_PRIMARY,
227 PROP_GICON_SECONDARY,
228 PROP_STORAGE_TYPE_PRIMARY,
229 PROP_STORAGE_TYPE_SECONDARY,
230 PROP_ACTIVATABLE_PRIMARY,
231 PROP_ACTIVATABLE_SECONDARY,
232 PROP_SENSITIVE_PRIMARY,
233 PROP_SENSITIVE_SECONDARY,
234 PROP_TOOLTIP_TEXT_PRIMARY,
235 PROP_TOOLTIP_TEXT_SECONDARY,
236 PROP_TOOLTIP_MARKUP_PRIMARY,
237 PROP_TOOLTIP_MARKUP_SECONDARY,
238 PROP_IM_MODULE,
239 PROP_PLACEHOLDER_TEXT,
240 PROP_COMPLETION,
241 PROP_INPUT_PURPOSE,
242 PROP_INPUT_HINTS,
243 PROP_ATTRIBUTES,
244 PROP_TABS,
245 PROP_EXTRA_MENU,
246 PROP_SHOW_EMOJI_ICON,
247 PROP_ENABLE_EMOJI_COMPLETION,
248 PROP_EDITING_CANCELED,
249 NUM_PROPERTIES = PROP_EDITING_CANCELED,
250};
251
252static GParamSpec *entry_props[NUM_PROPERTIES] = { NULL, };
253
254static guint signals[LAST_SIGNAL] = { 0 };
255
256typedef enum {
257 CURSOR_STANDARD,
258 CURSOR_DND
259} CursorType;
260
261typedef enum
262{
263 DISPLAY_NORMAL, /* The entry text is being shown */
264 DISPLAY_INVISIBLE, /* In invisible mode, text replaced by (eg) bullets */
265 DISPLAY_BLANK /* In invisible mode, nothing shown at all */
266} DisplayMode;
267
268/* GObject methods
269 */
270static void gtk_entry_editable_init (GtkEditableInterface *iface);
271static void gtk_entry_cell_editable_init (GtkCellEditableIface *iface);
272static void gtk_entry_set_property (GObject *object,
273 guint prop_id,
274 const GValue *value,
275 GParamSpec *pspec);
276static void gtk_entry_get_property (GObject *object,
277 guint prop_id,
278 GValue *value,
279 GParamSpec *pspec);
280static void gtk_entry_finalize (GObject *object);
281static void gtk_entry_dispose (GObject *object);
282
283/* GtkWidget methods
284 */
285static void gtk_entry_size_allocate (GtkWidget *widget,
286 int width,
287 int height,
288 int baseline);
289static void gtk_entry_snapshot (GtkWidget *widget,
290 GtkSnapshot *snapshot);
291static gboolean gtk_entry_query_tooltip (GtkWidget *widget,
292 int x,
293 int y,
294 gboolean keyboard_tip,
295 GtkTooltip *tooltip);
296static void gtk_entry_direction_changed (GtkWidget *widget,
297 GtkTextDirection previous_dir);
298
299
300/* GtkCellEditable method implementations
301 */
302static void gtk_entry_start_editing (GtkCellEditable *cell_editable,
303 GdkEvent *event);
304
305/* Default signal handlers
306 */
307static GtkEntryBuffer *get_buffer (GtkEntry *entry);
308static void set_show_emoji_icon (GtkEntry *entry,
309 gboolean value);
310
311static void gtk_entry_measure (GtkWidget *widget,
312 GtkOrientation orientation,
313 int for_size,
314 int *minimum,
315 int *natural,
316 int *minimum_baseline,
317 int *natural_baseline);
318
319static GtkBuildableIface *buildable_parent_iface = NULL;
320
321static void gtk_entry_buildable_interface_init (GtkBuildableIface *iface);
322static void gtk_entry_accessible_interface_init (GtkAccessibleInterface *iface);
323
324G_DEFINE_TYPE_WITH_CODE (GtkEntry, gtk_entry, GTK_TYPE_WIDGET,
325 G_ADD_PRIVATE (GtkEntry)
326 G_IMPLEMENT_INTERFACE (GTK_TYPE_ACCESSIBLE,
327 gtk_entry_accessible_interface_init)
328 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
329 gtk_entry_buildable_interface_init)
330 G_IMPLEMENT_INTERFACE (GTK_TYPE_EDITABLE,
331 gtk_entry_editable_init)
332 G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_EDITABLE,
333 gtk_entry_cell_editable_init))
334
335/* Implement the GtkAccessible interface, in order to obtain focus
336 * state from the GtkText widget that we are wrapping. The GtkText
337 * widget is ignored for accessibility purposes (it has role NONE),
338 * and any a11y text functionality is implemented for GtkEntry and
339 * similar wrappers (GtkPasswordEntry, GtkSpinButton, etc).
340 */
341static gboolean
342gtk_entry_accessible_get_platform_state (GtkAccessible *self,
343 GtkAccessiblePlatformState state)
344{
345 GtkEntry *entry = GTK_ENTRY (self);
346 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
347
348 switch (state)
349 {
350 case GTK_ACCESSIBLE_PLATFORM_STATE_FOCUSABLE:
351 return gtk_widget_get_focusable (GTK_WIDGET (priv->text));
352 case GTK_ACCESSIBLE_PLATFORM_STATE_FOCUSED:
353 return gtk_widget_has_focus (GTK_WIDGET (priv->text));
354 case GTK_ACCESSIBLE_PLATFORM_STATE_ACTIVE:
355 return FALSE;
356 default:
357 g_assert_not_reached ();
358 }
359}
360
361static void
362gtk_entry_accessible_interface_init (GtkAccessibleInterface *iface)
363{
364 GtkAccessibleInterface *parent_iface = g_type_interface_peek_parent (g_iface: iface);
365 iface->get_at_context = parent_iface->get_at_context;
366 iface->get_platform_state = gtk_entry_accessible_get_platform_state;
367}
368
369static const GtkBuildableParser pango_parser =
370{
371 gtk_pango_attribute_start_element,
372};
373
374static gboolean
375gtk_entry_buildable_custom_tag_start (GtkBuildable *buildable,
376 GtkBuilder *builder,
377 GObject *child,
378 const char *tagname,
379 GtkBuildableParser *parser,
380 gpointer *data)
381{
382 if (buildable_parent_iface->custom_tag_start (buildable, builder, child,
383 tagname, parser, data))
384 return TRUE;
385
386 if (strcmp (s1: tagname, s2: "attributes") == 0)
387 {
388 GtkPangoAttributeParserData *parser_data;
389
390 parser_data = g_slice_new0 (GtkPangoAttributeParserData);
391 parser_data->builder = g_object_ref (builder);
392 parser_data->object = (GObject *) g_object_ref (buildable);
393 *parser = pango_parser;
394 *data = parser_data;
395 return TRUE;
396 }
397 return FALSE;
398}
399
400static void
401gtk_entry_buildable_custom_finished (GtkBuildable *buildable,
402 GtkBuilder *builder,
403 GObject *child,
404 const char *tagname,
405 gpointer user_data)
406{
407 GtkPangoAttributeParserData *data = user_data;
408
409 buildable_parent_iface->custom_finished (buildable, builder, child,
410 tagname, user_data);
411
412 if (strcmp (s1: tagname, s2: "attributes") == 0)
413 {
414 if (data->attrs)
415 {
416 gtk_entry_set_attributes (GTK_ENTRY (buildable), attrs: data->attrs);
417 pango_attr_list_unref (list: data->attrs);
418 }
419
420 g_object_unref (object: data->object);
421 g_object_unref (object: data->builder);
422 g_slice_free (GtkPangoAttributeParserData, data);
423 }
424}
425
426static void
427gtk_entry_buildable_interface_init (GtkBuildableIface *iface)
428{
429 buildable_parent_iface = g_type_interface_peek_parent (g_iface: iface);
430
431 iface->custom_tag_start = gtk_entry_buildable_custom_tag_start;
432 iface->custom_finished = gtk_entry_buildable_custom_finished;
433}
434
435static gboolean
436gtk_entry_grab_focus (GtkWidget *widget)
437{
438 GtkEntry *entry = GTK_ENTRY (widget);
439 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
440
441 return gtk_widget_grab_focus (widget: priv->text);
442}
443
444static gboolean
445gtk_entry_mnemonic_activate (GtkWidget *widget,
446 gboolean group_cycling)
447{
448 GtkEntry *entry = GTK_ENTRY (widget);
449 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
450
451 gtk_widget_grab_focus (widget: priv->text);
452
453 return TRUE;
454}
455
456static void
457gtk_entry_class_init (GtkEntryClass *class)
458{
459 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
460 GtkWidgetClass *widget_class;
461
462 widget_class = (GtkWidgetClass*) class;
463
464 gobject_class->dispose = gtk_entry_dispose;
465 gobject_class->finalize = gtk_entry_finalize;
466 gobject_class->set_property = gtk_entry_set_property;
467 gobject_class->get_property = gtk_entry_get_property;
468
469 widget_class->measure = gtk_entry_measure;
470 widget_class->size_allocate = gtk_entry_size_allocate;
471 widget_class->snapshot = gtk_entry_snapshot;
472 widget_class->query_tooltip = gtk_entry_query_tooltip;
473 widget_class->direction_changed = gtk_entry_direction_changed;
474 widget_class->grab_focus = gtk_entry_grab_focus;
475 widget_class->focus = gtk_widget_focus_child;
476 widget_class->mnemonic_activate = gtk_entry_mnemonic_activate;
477
478 quark_entry_completion = g_quark_from_static_string (string: "gtk-entry-completion-key");
479
480 /**
481 * GtkEntry:buffer: (attributes org.gtk.Property.get=gtk_entry_get_buffer org.gtk.Property.set=gtk_entry_set_buffer)
482 *
483 * The buffer object which actually stores the text.
484 */
485 entry_props[PROP_BUFFER] =
486 g_param_spec_object (name: "buffer",
487 P_("Text Buffer"),
488 P_("Text buffer object which actually stores entry text"),
489 GTK_TYPE_ENTRY_BUFFER,
490 GTK_PARAM_READWRITE|G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY);
491
492 /**
493 * GtkEntry:max-length: (attributes org.gtk.Property.get=gtk_entry_get_max_length org.gtk.Property.set=gtk_entry_set_max_length)
494 *
495 * Maximum number of characters for this entry.
496 */
497 entry_props[PROP_MAX_LENGTH] =
498 g_param_spec_int (name: "max-length",
499 P_("Maximum length"),
500 P_("Maximum number of characters for this entry. Zero if no maximum"),
501 minimum: 0, GTK_ENTRY_BUFFER_MAX_SIZE,
502 default_value: 0,
503 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
504
505 /**
506 * GtkEntry:visibility: (attributes org.gtk.Property.get=gtk_entry_get_visibility org.gtk.Property.set=gtk_entry_set_visibility)
507 *
508 * Whether the entry should show the “invisible char” instead of the
509 * actual text (“password mode”).
510 */
511 entry_props[PROP_VISIBILITY] =
512 g_param_spec_boolean (name: "visibility",
513 P_("Visibility"),
514 P_("FALSE displays the “invisible char” instead of the actual text (password mode)"),
515 TRUE,
516 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
517
518 /**
519 * GtkEntry:has-frame: (attributes org.gtk.Property.get=gtk_entry_get_has_frame org.gtk.Property.set=gtk_entry_set_has_frame)
520 *
521 * Whehter the entry should draw a frame.
522 */
523 entry_props[PROP_HAS_FRAME] =
524 g_param_spec_boolean (name: "has-frame",
525 P_("Has Frame"),
526 P_("FALSE removes outside bevel from entry"),
527 TRUE,
528 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
529
530 /**
531 * GtkEntry:invisible-char: (attributes org.gtk.Property.get=gtk_entry_get_invisible_char org.gtk.Property.set=gtk_entry_set_invisible_char)
532 *
533 * The character to use when masking entry contents (“password mode”).
534 */
535 entry_props[PROP_INVISIBLE_CHAR] =
536 g_param_spec_unichar (name: "invisible-char",
537 P_("Invisible character"),
538 P_("The character to use when masking entry contents (in “password mode”)"),
539 default_value: '*',
540 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
541
542 /**
543 * GtkEntry:activates-default: (attributes org.gtk.Property.get=gtk_entry_get_activates_default org.gtk.Property.set=gtk_entry_set_activates_default)
544 *
545 * Whether to activate the default widget when Enter is pressed.
546 */
547 entry_props[PROP_ACTIVATES_DEFAULT] =
548 g_param_spec_boolean (name: "activates-default",
549 P_("Activates default"),
550 P_("Whether to activate the default widget (such as the default button in a dialog) when Enter is pressed"),
551 FALSE,
552 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
553
554 /**
555 * GtkEntry:scroll-offset:
556 *
557 * Number of pixels of the entry scrolled off the screen to the left.
558 */
559 entry_props[PROP_SCROLL_OFFSET] =
560 g_param_spec_int (name: "scroll-offset",
561 P_("Scroll offset"),
562 P_("Number of pixels of the entry scrolled off the screen to the left"),
563 minimum: 0, G_MAXINT,
564 default_value: 0,
565 GTK_PARAM_READABLE|G_PARAM_EXPLICIT_NOTIFY);
566
567 /**
568 * GtkEntry:truncate-multiline:
569 *
570 * When %TRUE, pasted multi-line text is truncated to the first line.
571 */
572 entry_props[PROP_TRUNCATE_MULTILINE] =
573 g_param_spec_boolean (name: "truncate-multiline",
574 P_("Truncate multiline"),
575 P_("Whether to truncate multiline pastes to one line."),
576 FALSE,
577 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
578
579 /**
580 * GtkEntry:overwrite-mode: (attributes org.gtk.Property.get=gtk_entry_get_overwrite_mode org.gtk.Property.set=gtk_entry_set_overwrite_mode)
581 *
582 * If text is overwritten when typing in the `GtkEntry`.
583 */
584 entry_props[PROP_OVERWRITE_MODE] =
585 g_param_spec_boolean (name: "overwrite-mode",
586 P_("Overwrite mode"),
587 P_("Whether new text overwrites existing text"),
588 FALSE,
589 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
590
591 /**
592 * GtkEntry:text-length: (attributes org.gtk.Property.get=gtk_entry_get_text_length)
593 *
594 * The length of the text in the `GtkEntry`.
595 */
596 entry_props[PROP_TEXT_LENGTH] =
597 g_param_spec_uint (name: "text-length",
598 P_("Text length"),
599 P_("Length of the text currently in the entry"),
600 minimum: 0, G_MAXUINT16,
601 default_value: 0,
602 GTK_PARAM_READABLE);
603
604 /**
605 * GtkEntry:invisible-char-set:
606 *
607 * Whether the invisible char has been set for the `GtkEntry`.
608 */
609 entry_props[PROP_INVISIBLE_CHAR_SET] =
610 g_param_spec_boolean (name: "invisible-char-set",
611 P_("Invisible character set"),
612 P_("Whether the invisible character has been set"),
613 FALSE,
614 GTK_PARAM_READWRITE);
615
616 /**
617 * GtkEntry:progress-fraction: (attributes org.gtk.Property.get=gtk_entry_get_progress_fraction org.gtk.Property.set=gtk_entry_set_progress_fraction)
618 *
619 * The current fraction of the task that's been completed.
620 */
621 entry_props[PROP_PROGRESS_FRACTION] =
622 g_param_spec_double (name: "progress-fraction",
623 P_("Progress Fraction"),
624 P_("The current fraction of the task that’s been completed"),
625 minimum: 0.0, maximum: 1.0,
626 default_value: 0.0,
627 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
628
629 /**
630 * GtkEntry:progress-pulse-step: (attributes org.gtk.Property.get=gtk_entry_get_progress_pulse_step org.gtk.Property.set=gtk_entry_set_progress_pulse_step)
631 *
632 * The fraction of total entry width to move the progress
633 * bouncing block for each pulse.
634 *
635 * See [method@Gtk.Entry.progress_pulse].
636 */
637 entry_props[PROP_PROGRESS_PULSE_STEP] =
638 g_param_spec_double (name: "progress-pulse-step",
639 P_("Progress Pulse Step"),
640 P_("The fraction of total entry width to move the progress bouncing block for each call to gtk_entry_progress_pulse()"),
641 minimum: 0.0, maximum: 1.0,
642 default_value: 0.0,
643 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
644
645 /**
646 * GtkEntry:placeholder-text: (attributes org.gtk.Property.get=gtk_entry_get_placeholder_text org.gtk.Property.set=gtk_entry_set_placeholder_text)
647 *
648 * The text that will be displayed in the `GtkEntry` when it is empty
649 * and unfocused.
650 */
651 entry_props[PROP_PLACEHOLDER_TEXT] =
652 g_param_spec_string (name: "placeholder-text",
653 P_("Placeholder text"),
654 P_("Show text in the entry when it’s empty and unfocused"),
655 NULL,
656 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
657
658 /**
659 * GtkEntry:primary-icon-paintable:
660 *
661 * A `GdkPaintable` to use as the primary icon for the entry.
662 */
663 entry_props[PROP_PAINTABLE_PRIMARY] =
664 g_param_spec_object (name: "primary-icon-paintable",
665 P_("Primary paintable"),
666 P_("Primary paintable for the entry"),
667 GDK_TYPE_PAINTABLE,
668 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
669
670 /**
671 * GtkEntry:secondary-icon-paintable:
672 *
673 * A `GdkPaintable` to use as the secondary icon for the entry.
674 */
675 entry_props[PROP_PAINTABLE_SECONDARY] =
676 g_param_spec_object (name: "secondary-icon-paintable",
677 P_("Secondary paintable"),
678 P_("Secondary paintable for the entry"),
679 GDK_TYPE_PAINTABLE,
680 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
681
682 /**
683 * GtkEntry:primary-icon-name:
684 *
685 * The icon name to use for the primary icon for the entry.
686 */
687 entry_props[PROP_ICON_NAME_PRIMARY] =
688 g_param_spec_string (name: "primary-icon-name",
689 P_("Primary icon name"),
690 P_("Icon name for primary icon"),
691 NULL,
692 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
693
694 /**
695 * GtkEntry:secondary-icon-name:
696 *
697 * The icon name to use for the secondary icon for the entry.
698 */
699 entry_props[PROP_ICON_NAME_SECONDARY] =
700 g_param_spec_string (name: "secondary-icon-name",
701 P_("Secondary icon name"),
702 P_("Icon name for secondary icon"),
703 NULL,
704 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
705
706 /**
707 * GtkEntry:primary-icon-gicon:
708 *
709 * The `GIcon` to use for the primary icon for the entry.
710 */
711 entry_props[PROP_GICON_PRIMARY] =
712 g_param_spec_object (name: "primary-icon-gicon",
713 P_("Primary GIcon"),
714 P_("GIcon for primary icon"),
715 G_TYPE_ICON,
716 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
717
718 /**
719 * GtkEntry:secondary-icon-gicon:
720 *
721 * The `GIcon` to use for the secondary icon for the entry.
722 */
723 entry_props[PROP_GICON_SECONDARY] =
724 g_param_spec_object (name: "secondary-icon-gicon",
725 P_("Secondary GIcon"),
726 P_("GIcon for secondary icon"),
727 G_TYPE_ICON,
728 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
729
730 /**
731 * GtkEntry:primary-icon-storage-type:
732 *
733 * The representation which is used for the primary icon of the entry.
734 */
735 entry_props[PROP_STORAGE_TYPE_PRIMARY] =
736 g_param_spec_enum (name: "primary-icon-storage-type",
737 P_("Primary storage type"),
738 P_("The representation being used for primary icon"),
739 enum_type: GTK_TYPE_IMAGE_TYPE,
740 default_value: GTK_IMAGE_EMPTY,
741 GTK_PARAM_READABLE);
742
743 /**
744 * GtkEntry:secondary-icon-storage-type:
745 *
746 * The representation which is used for the secondary icon of the entry.
747 */
748 entry_props[PROP_STORAGE_TYPE_SECONDARY] =
749 g_param_spec_enum (name: "secondary-icon-storage-type",
750 P_("Secondary storage type"),
751 P_("The representation being used for secondary icon"),
752 enum_type: GTK_TYPE_IMAGE_TYPE,
753 default_value: GTK_IMAGE_EMPTY,
754 GTK_PARAM_READABLE);
755
756 /**
757 * GtkEntry:primary-icon-activatable:
758 *
759 * Whether the primary icon is activatable.
760 *
761 * GTK emits the [signal@Gtk.Entry::icon-press] and
762 * [signal@Gtk.Entry::icon-release] signals only on sensitive,
763 * activatable icons.
764 *
765 * Sensitive, but non-activatable icons can be used for purely
766 * informational purposes.
767 */
768 entry_props[PROP_ACTIVATABLE_PRIMARY] =
769 g_param_spec_boolean (name: "primary-icon-activatable",
770 P_("Primary icon activatable"),
771 P_("Whether the primary icon is activatable"),
772 TRUE,
773 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
774
775 /**
776 * GtkEntry:secondary-icon-activatable:
777 *
778 * Whether the secondary icon is activatable.
779 *
780 * GTK emits the [signal@Gtk.Entry::icon-press] and
781 * [signal@Gtk.Entry::icon-release] signals only on sensitive,
782 * activatable icons.
783 *
784 * Sensitive, but non-activatable icons can be used for purely
785 * informational purposes.
786 */
787 entry_props[PROP_ACTIVATABLE_SECONDARY] =
788 g_param_spec_boolean (name: "secondary-icon-activatable",
789 P_("Secondary icon activatable"),
790 P_("Whether the secondary icon is activatable"),
791 TRUE,
792 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
793
794 /**
795 * GtkEntry:primary-icon-sensitive:
796 *
797 * Whether the primary icon is sensitive.
798 *
799 * An insensitive icon appears grayed out. GTK does not emit the
800 * [signal@Gtk.Entry::icon-press] and [signal@Gtk.Entry::icon-release]
801 * signals and does not allow DND from insensitive icons.
802 *
803 * An icon should be set insensitive if the action that would trigger
804 * when clicked is currently not available.
805 */
806 entry_props[PROP_SENSITIVE_PRIMARY] =
807 g_param_spec_boolean (name: "primary-icon-sensitive",
808 P_("Primary icon sensitive"),
809 P_("Whether the primary icon is sensitive"),
810 TRUE,
811 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
812
813 /**
814 * GtkEntry:secondary-icon-sensitive:
815 *
816 * Whether the secondary icon is sensitive.
817 *
818 * An insensitive icon appears grayed out. GTK does not emit the
819 * [signal@Gtk.Entry::icon-press[ and [signal@Gtk.Entry::icon-release]
820 * signals and does not allow DND from insensitive icons.
821 *
822 * An icon should be set insensitive if the action that would trigger
823 * when clicked is currently not available.
824 */
825 entry_props[PROP_SENSITIVE_SECONDARY] =
826 g_param_spec_boolean (name: "secondary-icon-sensitive",
827 P_("Secondary icon sensitive"),
828 P_("Whether the secondary icon is sensitive"),
829 TRUE,
830 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
831
832 /**
833 * GtkEntry:primary-icon-tooltip-text:
834 *
835 * The contents of the tooltip on the primary icon.
836 *
837 * Also see [method@Gtk.Entry.set_icon_tooltip_text].
838 */
839 entry_props[PROP_TOOLTIP_TEXT_PRIMARY] =
840 g_param_spec_string (name: "primary-icon-tooltip-text",
841 P_("Primary icon tooltip text"),
842 P_("The contents of the tooltip on the primary icon"),
843 NULL,
844 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
845
846 /**
847 * GtkEntry:secondary-icon-tooltip-text:
848 *
849 * The contents of the tooltip on the secondary icon.
850 *
851 * Also see [method@Gtk.Entry.set_icon_tooltip_text].
852 */
853 entry_props[PROP_TOOLTIP_TEXT_SECONDARY] =
854 g_param_spec_string (name: "secondary-icon-tooltip-text",
855 P_("Secondary icon tooltip text"),
856 P_("The contents of the tooltip on the secondary icon"),
857 NULL,
858 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
859
860 /**
861 * GtkEntry:primary-icon-tooltip-markup:
862 *
863 * The contents of the tooltip on the primary icon, with markup.
864 *
865 * Also see [method@Gtk.Entry.set_icon_tooltip_markup].
866 */
867 entry_props[PROP_TOOLTIP_MARKUP_PRIMARY] =
868 g_param_spec_string (name: "primary-icon-tooltip-markup",
869 P_("Primary icon tooltip markup"),
870 P_("The contents of the tooltip on the primary icon"),
871 NULL,
872 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
873
874 /**
875 * GtkEntry:secondary-icon-tooltip-markup:
876 *
877 * The contents of the tooltip on the secondary icon, with markup.
878 *
879 * Also see [method@Gtk.Entry.set_icon_tooltip_markup].
880 */
881 entry_props[PROP_TOOLTIP_MARKUP_SECONDARY] =
882 g_param_spec_string (name: "secondary-icon-tooltip-markup",
883 P_("Secondary icon tooltip markup"),
884 P_("The contents of the tooltip on the secondary icon"),
885 NULL,
886 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
887
888 /**
889 * GtkEntry:im-module:
890 *
891 * Which IM (input method) module should be used for this entry.
892 *
893 * See [class@Gtk.IMContext].
894 *
895 * Setting this to a non-%NULL value overrides the system-wide IM
896 * module setting. See the GtkSettings [property@Gtk.Settings:gtk-im-module]
897 * property.
898 */
899 entry_props[PROP_IM_MODULE] =
900 g_param_spec_string (name: "im-module",
901 P_("IM module"),
902 P_("Which IM module should be used"),
903 NULL,
904 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
905
906 /**
907 * GtkEntry:completion: (attributes org.gtk.Property.get=gtk_entry_get_completion org.gtk.Property.set=gtk_entry_set_completion)
908 *
909 * The auxiliary completion object to use with the entry.
910 */
911 entry_props[PROP_COMPLETION] =
912 g_param_spec_object (name: "completion",
913 P_("Completion"),
914 P_("The auxiliary completion object"),
915 GTK_TYPE_ENTRY_COMPLETION,
916 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
917
918 /**
919 * GtkEntry:input-purpose: (attributes org.gtk.Property.get=gtk_entry_get_input_purpose org.gtk.Property.set=gtk_entry_set_input_purpose)
920 *
921 * The purpose of this text field.
922 *
923 * This property can be used by on-screen keyboards and other input
924 * methods to adjust their behaviour.
925 *
926 * Note that setting the purpose to %GTK_INPUT_PURPOSE_PASSWORD or
927 * %GTK_INPUT_PURPOSE_PIN is independent from setting
928 * [property@Gtk.Entry:visibility].
929 */
930 entry_props[PROP_INPUT_PURPOSE] =
931 g_param_spec_enum (name: "input-purpose",
932 P_("Purpose"),
933 P_("Purpose of the text field"),
934 enum_type: GTK_TYPE_INPUT_PURPOSE,
935 default_value: GTK_INPUT_PURPOSE_FREE_FORM,
936 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
937
938 /**
939 * GtkEntry:input-hints: (attributes org.gtk.Property.get=gtk_entry_get_input_hints org.gtk.Property.set=gtk_entry_set_input_hints)
940 *
941 * Additional hints that allow input methods to fine-tune their behavior.
942 *
943 * Also see [property@Gtk.Entry:input-purpose]
944 */
945 entry_props[PROP_INPUT_HINTS] =
946 g_param_spec_flags (name: "input-hints",
947 P_("hints"),
948 P_("Hints for the text field behaviour"),
949 flags_type: GTK_TYPE_INPUT_HINTS,
950 default_value: GTK_INPUT_HINT_NONE,
951 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
952
953 /**
954 * GtkEntry:attributes: (attributes org.gtk.Property.get=gtk_entry_get_attributes org.gtk.Property.set=gtk_entry_set_attributes)
955 *
956 * A list of Pango attributes to apply to the text of the entry.
957 *
958 * This is mainly useful to change the size or weight of the text.
959 *
960 * The `PangoAttribute`'s @start_index and @end_index must refer to the
961 * [class@Gtk.EntryBuffer] text, i.e. without the preedit string.
962 */
963 entry_props[PROP_ATTRIBUTES] =
964 g_param_spec_boxed (name: "attributes",
965 P_("Attributes"),
966 P_("A list of style attributes to apply to the text of the entry"),
967 PANGO_TYPE_ATTR_LIST,
968 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
969
970 /**
971 * GtkEntry::tabs: (attributes org.gtk.Property.get=gtk_entry_get_tabs org.gtk.Property.set=gtk_entry_set_tabs)
972 *
973 * A list of tabstops to apply to the text of the entry.
974 */
975 entry_props[PROP_TABS] =
976 g_param_spec_boxed (name: "tabs",
977 P_("Tabs"),
978 P_("A list of tabstop locations to apply to the text of the entry"),
979 PANGO_TYPE_TAB_ARRAY,
980 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
981
982 /**
983 * GtkEntry::show-emoji-icon:
984 *
985 * Whether the entry will sohw an Emoji icon in the secondary icon position
986 * to open the Emoji chooser.
987 */
988 entry_props[PROP_SHOW_EMOJI_ICON] =
989 g_param_spec_boolean (name: "show-emoji-icon",
990 P_("Emoji icon"),
991 P_("Whether to show an icon for Emoji"),
992 FALSE,
993 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
994
995 /**
996 * GtkEntry:extra-menu: (attributes org.gtk.Property.get=gtk_entry_get_extra_menu org.gtk.Property.set=gtk_entry_set_extra_menu)
997 *
998 * A menu model whose contents will be appended to the context menu.
999 */
1000 entry_props[PROP_EXTRA_MENU] =
1001 g_param_spec_object (name: "extra-menu",
1002 P_("Extra menu"),
1003 P_("Model menu to append to the context menu"),
1004 G_TYPE_MENU_MODEL,
1005 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
1006
1007 /**
1008 * GtkEntry:enable-emoji-completion:
1009 *
1010 * Whether to suggest Emoji replacements for :-delimited names
1011 * like `:heart:`.
1012 */
1013 entry_props[PROP_ENABLE_EMOJI_COMPLETION] =
1014 g_param_spec_boolean (name: "enable-emoji-completion",
1015 P_("Enable Emoji completion"),
1016 P_("Whether to suggest Emoji replacements"),
1017 FALSE,
1018 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
1019
1020 g_object_class_install_properties (oclass: gobject_class, n_pspecs: NUM_PROPERTIES, pspecs: entry_props);
1021 g_object_class_override_property (oclass: gobject_class, property_id: PROP_EDITING_CANCELED, name: "editing-canceled");
1022 gtk_editable_install_properties (object_class: gobject_class, first_prop: PROP_EDITING_CANCELED + 1);
1023
1024 /**
1025 * GtkEntry::activate:
1026 * @self: The widget on which the signal is emitted
1027 *
1028 * Emitted when the entry is activated.
1029 *
1030 * The keybindings for this signal are all forms of the Enter key.
1031 */
1032 signals[ACTIVATE] =
1033 g_signal_new (I_("activate"),
1034 G_OBJECT_CLASS_TYPE (gobject_class),
1035 signal_flags: G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1036 G_STRUCT_OFFSET (GtkEntryClass, activate),
1037 NULL, NULL,
1038 NULL,
1039 G_TYPE_NONE, n_params: 0);
1040
1041 /**
1042 * GtkEntry::icon-press:
1043 * @entry: The entry on which the signal is emitted
1044 * @icon_pos: The position of the clicked icon
1045 *
1046 * Emitted when an activatable icon is clicked.
1047 */
1048 signals[ICON_PRESS] =
1049 g_signal_new (I_("icon-press"),
1050 G_TYPE_FROM_CLASS (gobject_class),
1051 signal_flags: G_SIGNAL_RUN_LAST,
1052 class_offset: 0,
1053 NULL, NULL,
1054 NULL,
1055 G_TYPE_NONE, n_params: 1,
1056 GTK_TYPE_ENTRY_ICON_POSITION);
1057
1058 /**
1059 * GtkEntry::icon-release:
1060 * @entry: The entry on which the signal is emitted
1061 * @icon_pos: The position of the clicked icon
1062 *
1063 * Emitted on the button release from a mouse click
1064 * over an activatable icon.
1065 */
1066 signals[ICON_RELEASE] =
1067 g_signal_new (I_("icon-release"),
1068 G_TYPE_FROM_CLASS (gobject_class),
1069 signal_flags: G_SIGNAL_RUN_LAST,
1070 class_offset: 0,
1071 NULL, NULL,
1072 NULL,
1073 G_TYPE_NONE, n_params: 1,
1074 GTK_TYPE_ENTRY_ICON_POSITION);
1075
1076 gtk_widget_class_set_css_name (widget_class, I_("entry"));
1077 gtk_widget_class_set_accessible_role (widget_class, accessible_role: GTK_ACCESSIBLE_ROLE_TEXT_BOX);
1078}
1079
1080static GtkEditable *
1081gtk_entry_get_delegate (GtkEditable *editable)
1082{
1083 GtkEntry *entry = GTK_ENTRY (editable);
1084 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
1085
1086 return GTK_EDITABLE (priv->text);
1087}
1088
1089static void
1090gtk_entry_editable_init (GtkEditableInterface *iface)
1091{
1092 iface->get_delegate = gtk_entry_get_delegate;
1093}
1094
1095static void
1096gtk_entry_cell_editable_init (GtkCellEditableIface *iface)
1097{
1098 iface->start_editing = gtk_entry_start_editing;
1099}
1100
1101static void
1102gtk_entry_set_property (GObject *object,
1103 guint prop_id,
1104 const GValue *value,
1105 GParamSpec *pspec)
1106{
1107 GtkEntry *entry = GTK_ENTRY (object);
1108 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
1109
1110 if (gtk_editable_delegate_set_property (object, prop_id, value, pspec))
1111 {
1112 if (prop_id == PROP_EDITING_CANCELED + 1 + GTK_EDITABLE_PROP_EDITABLE)
1113 {
1114 gtk_accessible_update_property (self: GTK_ACCESSIBLE (ptr: entry),
1115 first_property: GTK_ACCESSIBLE_PROPERTY_READ_ONLY, !g_value_get_boolean (value),
1116 -1);
1117 }
1118
1119 return;
1120 }
1121
1122 switch (prop_id)
1123 {
1124 case PROP_BUFFER:
1125 case PROP_MAX_LENGTH:
1126 case PROP_VISIBILITY:
1127 case PROP_INVISIBLE_CHAR:
1128 case PROP_INVISIBLE_CHAR_SET:
1129 case PROP_ACTIVATES_DEFAULT:
1130 case PROP_TRUNCATE_MULTILINE:
1131 case PROP_OVERWRITE_MODE:
1132 case PROP_IM_MODULE:
1133 case PROP_INPUT_PURPOSE:
1134 case PROP_INPUT_HINTS:
1135 case PROP_ATTRIBUTES:
1136 case PROP_TABS:
1137 case PROP_ENABLE_EMOJI_COMPLETION:
1138 g_object_set_property (G_OBJECT (priv->text), property_name: pspec->name, value);
1139 break;
1140
1141 case PROP_PLACEHOLDER_TEXT:
1142 gtk_entry_set_placeholder_text (entry, text: g_value_get_string (value));
1143 break;
1144
1145 case PROP_HAS_FRAME:
1146 gtk_entry_set_has_frame (entry, setting: g_value_get_boolean (value));
1147 break;
1148
1149 case PROP_PROGRESS_FRACTION:
1150 gtk_entry_set_progress_fraction (entry, fraction: g_value_get_double (value));
1151 break;
1152
1153 case PROP_PROGRESS_PULSE_STEP:
1154 gtk_entry_set_progress_pulse_step (entry, fraction: g_value_get_double (value));
1155 break;
1156
1157 case PROP_PAINTABLE_PRIMARY:
1158 gtk_entry_set_icon_from_paintable (entry,
1159 icon_pos: GTK_ENTRY_ICON_PRIMARY,
1160 paintable: g_value_get_object (value));
1161 break;
1162
1163 case PROP_PAINTABLE_SECONDARY:
1164 gtk_entry_set_icon_from_paintable (entry,
1165 icon_pos: GTK_ENTRY_ICON_SECONDARY,
1166 paintable: g_value_get_object (value));
1167 break;
1168
1169 case PROP_ICON_NAME_PRIMARY:
1170 gtk_entry_set_icon_from_icon_name (entry,
1171 icon_pos: GTK_ENTRY_ICON_PRIMARY,
1172 icon_name: g_value_get_string (value));
1173 break;
1174
1175 case PROP_ICON_NAME_SECONDARY:
1176 gtk_entry_set_icon_from_icon_name (entry,
1177 icon_pos: GTK_ENTRY_ICON_SECONDARY,
1178 icon_name: g_value_get_string (value));
1179 break;
1180
1181 case PROP_GICON_PRIMARY:
1182 gtk_entry_set_icon_from_gicon (entry,
1183 icon_pos: GTK_ENTRY_ICON_PRIMARY,
1184 icon: g_value_get_object (value));
1185 break;
1186
1187 case PROP_GICON_SECONDARY:
1188 gtk_entry_set_icon_from_gicon (entry,
1189 icon_pos: GTK_ENTRY_ICON_SECONDARY,
1190 icon: g_value_get_object (value));
1191 break;
1192
1193 case PROP_ACTIVATABLE_PRIMARY:
1194 gtk_entry_set_icon_activatable (entry,
1195 icon_pos: GTK_ENTRY_ICON_PRIMARY,
1196 activatable: g_value_get_boolean (value));
1197 break;
1198
1199 case PROP_ACTIVATABLE_SECONDARY:
1200 gtk_entry_set_icon_activatable (entry,
1201 icon_pos: GTK_ENTRY_ICON_SECONDARY,
1202 activatable: g_value_get_boolean (value));
1203 break;
1204
1205 case PROP_SENSITIVE_PRIMARY:
1206 gtk_entry_set_icon_sensitive (entry,
1207 icon_pos: GTK_ENTRY_ICON_PRIMARY,
1208 sensitive: g_value_get_boolean (value));
1209 break;
1210
1211 case PROP_SENSITIVE_SECONDARY:
1212 gtk_entry_set_icon_sensitive (entry,
1213 icon_pos: GTK_ENTRY_ICON_SECONDARY,
1214 sensitive: g_value_get_boolean (value));
1215 break;
1216
1217 case PROP_TOOLTIP_TEXT_PRIMARY:
1218 gtk_entry_set_icon_tooltip_text (entry,
1219 icon_pos: GTK_ENTRY_ICON_PRIMARY,
1220 tooltip: g_value_get_string (value));
1221 break;
1222
1223 case PROP_TOOLTIP_TEXT_SECONDARY:
1224 gtk_entry_set_icon_tooltip_text (entry,
1225 icon_pos: GTK_ENTRY_ICON_SECONDARY,
1226 tooltip: g_value_get_string (value));
1227 break;
1228
1229 case PROP_TOOLTIP_MARKUP_PRIMARY:
1230 gtk_entry_set_icon_tooltip_markup (entry,
1231 icon_pos: GTK_ENTRY_ICON_PRIMARY,
1232 tooltip: g_value_get_string (value));
1233 break;
1234
1235 case PROP_TOOLTIP_MARKUP_SECONDARY:
1236 gtk_entry_set_icon_tooltip_markup (entry,
1237 icon_pos: GTK_ENTRY_ICON_SECONDARY,
1238 tooltip: g_value_get_string (value));
1239 break;
1240
1241 case PROP_EDITING_CANCELED:
1242 if (priv->editing_canceled != g_value_get_boolean (value))
1243 {
1244 priv->editing_canceled = g_value_get_boolean (value);
1245 g_object_notify (object, property_name: "editing-canceled");
1246 }
1247 break;
1248
1249 case PROP_COMPLETION:
1250 gtk_entry_set_completion (entry, GTK_ENTRY_COMPLETION (g_value_get_object (value)));
1251 break;
1252
1253 case PROP_SHOW_EMOJI_ICON:
1254 set_show_emoji_icon (entry, value: g_value_get_boolean (value));
1255 break;
1256
1257 case PROP_EXTRA_MENU:
1258 gtk_entry_set_extra_menu (entry, model: g_value_get_object (value));
1259 break;
1260
1261 default:
1262 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1263 break;
1264 }
1265}
1266
1267static void
1268gtk_entry_get_property (GObject *object,
1269 guint prop_id,
1270 GValue *value,
1271 GParamSpec *pspec)
1272{
1273 GtkEntry *entry = GTK_ENTRY (object);
1274 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
1275
1276 if (gtk_editable_delegate_get_property (object, prop_id, value, pspec))
1277 return;
1278
1279 switch (prop_id)
1280 {
1281 case PROP_BUFFER:
1282 case PROP_IM_MODULE:
1283 case PROP_MAX_LENGTH:
1284 case PROP_VISIBILITY:
1285 case PROP_INVISIBLE_CHAR:
1286 case PROP_INVISIBLE_CHAR_SET:
1287 case PROP_ACTIVATES_DEFAULT:
1288 case PROP_SCROLL_OFFSET:
1289 case PROP_TRUNCATE_MULTILINE:
1290 case PROP_OVERWRITE_MODE:
1291 case PROP_PLACEHOLDER_TEXT:
1292 case PROP_INPUT_PURPOSE:
1293 case PROP_INPUT_HINTS:
1294 case PROP_ATTRIBUTES:
1295 case PROP_TABS:
1296 case PROP_ENABLE_EMOJI_COMPLETION:
1297 g_object_get_property (G_OBJECT (priv->text), property_name: pspec->name, value);
1298 break;
1299
1300 case PROP_HAS_FRAME:
1301 g_value_set_boolean (value, v_boolean: gtk_entry_get_has_frame (entry));
1302 break;
1303
1304 case PROP_TEXT_LENGTH:
1305 g_value_set_uint (value, v_uint: gtk_entry_get_text_length (entry));
1306 break;
1307
1308 case PROP_PROGRESS_FRACTION:
1309 g_value_set_double (value, v_double: gtk_entry_get_progress_fraction (entry));
1310 break;
1311
1312 case PROP_PROGRESS_PULSE_STEP:
1313 g_value_set_double (value, v_double: gtk_entry_get_progress_pulse_step (entry));
1314 break;
1315
1316 case PROP_PAINTABLE_PRIMARY:
1317 g_value_set_object (value,
1318 v_object: gtk_entry_get_icon_paintable (entry,
1319 icon_pos: GTK_ENTRY_ICON_PRIMARY));
1320 break;
1321
1322 case PROP_PAINTABLE_SECONDARY:
1323 g_value_set_object (value,
1324 v_object: gtk_entry_get_icon_paintable (entry,
1325 icon_pos: GTK_ENTRY_ICON_SECONDARY));
1326 break;
1327
1328 case PROP_ICON_NAME_PRIMARY:
1329 g_value_set_string (value,
1330 v_string: gtk_entry_get_icon_name (entry,
1331 icon_pos: GTK_ENTRY_ICON_PRIMARY));
1332 break;
1333
1334 case PROP_ICON_NAME_SECONDARY:
1335 g_value_set_string (value,
1336 v_string: gtk_entry_get_icon_name (entry,
1337 icon_pos: GTK_ENTRY_ICON_SECONDARY));
1338 break;
1339
1340 case PROP_GICON_PRIMARY:
1341 g_value_set_object (value,
1342 v_object: gtk_entry_get_icon_gicon (entry,
1343 icon_pos: GTK_ENTRY_ICON_PRIMARY));
1344 break;
1345
1346 case PROP_GICON_SECONDARY:
1347 g_value_set_object (value,
1348 v_object: gtk_entry_get_icon_gicon (entry,
1349 icon_pos: GTK_ENTRY_ICON_SECONDARY));
1350 break;
1351
1352 case PROP_STORAGE_TYPE_PRIMARY:
1353 g_value_set_enum (value,
1354 v_enum: gtk_entry_get_icon_storage_type (entry,
1355 icon_pos: GTK_ENTRY_ICON_PRIMARY));
1356 break;
1357
1358 case PROP_STORAGE_TYPE_SECONDARY:
1359 g_value_set_enum (value,
1360 v_enum: gtk_entry_get_icon_storage_type (entry,
1361 icon_pos: GTK_ENTRY_ICON_SECONDARY));
1362 break;
1363
1364 case PROP_ACTIVATABLE_PRIMARY:
1365 g_value_set_boolean (value,
1366 v_boolean: gtk_entry_get_icon_activatable (entry, icon_pos: GTK_ENTRY_ICON_PRIMARY));
1367 break;
1368
1369 case PROP_ACTIVATABLE_SECONDARY:
1370 g_value_set_boolean (value,
1371 v_boolean: gtk_entry_get_icon_activatable (entry, icon_pos: GTK_ENTRY_ICON_SECONDARY));
1372 break;
1373
1374 case PROP_SENSITIVE_PRIMARY:
1375 g_value_set_boolean (value,
1376 v_boolean: gtk_entry_get_icon_sensitive (entry, icon_pos: GTK_ENTRY_ICON_PRIMARY));
1377 break;
1378
1379 case PROP_SENSITIVE_SECONDARY:
1380 g_value_set_boolean (value,
1381 v_boolean: gtk_entry_get_icon_sensitive (entry, icon_pos: GTK_ENTRY_ICON_SECONDARY));
1382 break;
1383
1384 case PROP_TOOLTIP_TEXT_PRIMARY:
1385 g_value_take_string (value,
1386 v_string: gtk_entry_get_icon_tooltip_text (entry, icon_pos: GTK_ENTRY_ICON_PRIMARY));
1387 break;
1388
1389 case PROP_TOOLTIP_TEXT_SECONDARY:
1390 g_value_take_string (value,
1391 v_string: gtk_entry_get_icon_tooltip_text (entry, icon_pos: GTK_ENTRY_ICON_SECONDARY));
1392 break;
1393
1394 case PROP_TOOLTIP_MARKUP_PRIMARY:
1395 g_value_take_string (value,
1396 v_string: gtk_entry_get_icon_tooltip_markup (entry, icon_pos: GTK_ENTRY_ICON_PRIMARY));
1397 break;
1398
1399 case PROP_TOOLTIP_MARKUP_SECONDARY:
1400 g_value_take_string (value,
1401 v_string: gtk_entry_get_icon_tooltip_markup (entry, icon_pos: GTK_ENTRY_ICON_SECONDARY));
1402 break;
1403
1404 case PROP_EDITING_CANCELED:
1405 g_value_set_boolean (value,
1406 v_boolean: priv->editing_canceled);
1407 break;
1408
1409 case PROP_COMPLETION:
1410 g_value_set_object (value, G_OBJECT (gtk_entry_get_completion (entry)));
1411 break;
1412
1413 case PROP_SHOW_EMOJI_ICON:
1414 g_value_set_boolean (value, v_boolean: priv->show_emoji_icon);
1415 break;
1416
1417 case PROP_EXTRA_MENU:
1418 g_value_set_object (value, v_object: gtk_entry_get_extra_menu (entry));
1419 break;
1420
1421 default:
1422 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1423 break;
1424 }
1425}
1426
1427static void
1428activate_cb (GtkText *text, GtkEntry *entry)
1429{
1430 g_signal_emit (instance: entry, signal_id: signals[ACTIVATE], detail: 0);
1431}
1432
1433static void
1434notify_cb (GObject *object,
1435 GParamSpec *pspec,
1436 gpointer data)
1437{
1438 gpointer iface;
1439 gpointer class;
1440
1441 /* The editable interface properties are already forwarded by the editable delegate setup */
1442 iface = g_type_interface_peek (instance_class: g_type_class_peek (G_OBJECT_TYPE (object)), iface_type: gtk_editable_get_type ());
1443 class = g_type_class_peek (GTK_TYPE_ENTRY);
1444 if (!g_object_interface_find_property (g_iface: iface, property_name: pspec->name) &&
1445 g_object_class_find_property (oclass: class, property_name: pspec->name))
1446 g_object_notify (object: data, property_name: pspec->name);
1447}
1448
1449static void
1450connect_text_signals (GtkEntry *entry)
1451{
1452 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
1453
1454 g_signal_connect (priv->text, "activate", G_CALLBACK (activate_cb), entry);
1455 g_signal_connect (priv->text, "notify", G_CALLBACK (notify_cb), entry);
1456}
1457
1458static void
1459disconnect_text_signals (GtkEntry *entry)
1460{
1461 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
1462
1463 g_signal_handlers_disconnect_by_func (priv->text, activate_cb, entry);
1464 g_signal_handlers_disconnect_by_func (priv->text, notify_cb, entry);
1465}
1466
1467static void
1468catchall_click_press (GtkGestureClick *gesture,
1469 int n_press,
1470 double x,
1471 double y,
1472 gpointer user_data)
1473{
1474 gtk_gesture_set_state (GTK_GESTURE (gesture), state: GTK_EVENT_SEQUENCE_CLAIMED);
1475}
1476
1477static void
1478gtk_entry_init (GtkEntry *entry)
1479{
1480 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
1481 GtkGesture *catchall;
1482
1483 priv->text = gtk_text_new ();
1484 gtk_widget_set_parent (widget: priv->text, GTK_WIDGET (entry));
1485 gtk_editable_init_delegate (GTK_EDITABLE (entry));
1486 connect_text_signals (entry);
1487
1488 catchall = gtk_gesture_click_new ();
1489 g_signal_connect (catchall, "pressed",
1490 G_CALLBACK (catchall_click_press), entry);
1491 gtk_widget_add_controller (GTK_WIDGET (entry),
1492 GTK_EVENT_CONTROLLER (catchall));
1493
1494 priv->editing_canceled = FALSE;
1495}
1496
1497static void
1498gtk_entry_dispose (GObject *object)
1499{
1500 GtkEntry *entry = GTK_ENTRY (object);
1501 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
1502
1503 gtk_entry_set_icon_from_paintable (entry, icon_pos: GTK_ENTRY_ICON_PRIMARY, NULL);
1504 gtk_entry_set_icon_tooltip_markup (entry, icon_pos: GTK_ENTRY_ICON_PRIMARY, NULL);
1505 gtk_entry_set_icon_from_paintable (entry, icon_pos: GTK_ENTRY_ICON_SECONDARY, NULL);
1506 gtk_entry_set_icon_tooltip_markup (entry, icon_pos: GTK_ENTRY_ICON_SECONDARY, NULL);
1507
1508 gtk_entry_set_completion (entry, NULL);
1509
1510 if (priv->text)
1511 {
1512 disconnect_text_signals (entry);
1513 gtk_editable_finish_delegate (GTK_EDITABLE (entry));
1514 }
1515 g_clear_pointer (&priv->text, gtk_widget_unparent);
1516
1517 G_OBJECT_CLASS (gtk_entry_parent_class)->dispose (object);
1518}
1519
1520static void
1521gtk_entry_finalize (GObject *object)
1522{
1523 GtkEntry *entry = GTK_ENTRY (object);
1524 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
1525 EntryIconInfo *icon_info = NULL;
1526 int i;
1527
1528 for (i = 0; i < MAX_ICONS; i++)
1529 {
1530 icon_info = priv->icons[i];
1531 if (icon_info == NULL)
1532 continue;
1533
1534 g_clear_object (&icon_info->content);
1535
1536 gtk_widget_unparent (widget: icon_info->widget);
1537
1538 g_slice_free (EntryIconInfo, icon_info);
1539 }
1540
1541 g_clear_pointer (&priv->progress_widget, gtk_widget_unparent);
1542
1543 G_OBJECT_CLASS (gtk_entry_parent_class)->finalize (object);
1544}
1545
1546static void
1547update_icon_style (GtkWidget *widget,
1548 GtkEntryIconPosition icon_pos)
1549{
1550 GtkEntry *entry = GTK_ENTRY (widget);
1551 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
1552 EntryIconInfo *icon_info = priv->icons[icon_pos];
1553 const char *sides[2] = { "left", "right" };
1554
1555 if (icon_info == NULL)
1556 return;
1557
1558 if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
1559 icon_pos = 1 - icon_pos;
1560
1561 gtk_widget_add_css_class (widget: icon_info->widget, css_class: sides[icon_pos]);
1562 gtk_widget_remove_css_class (widget: icon_info->widget, css_class: sides[1 - icon_pos]);
1563}
1564
1565static void
1566update_node_ordering (GtkEntry *entry)
1567{
1568 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
1569 EntryIconInfo *icon_info;
1570 GtkEntryIconPosition first_icon_pos, second_icon_pos;
1571
1572 if (priv->progress_widget)
1573 gtk_widget_insert_before (widget: priv->progress_widget, GTK_WIDGET (entry), NULL);
1574
1575 if (gtk_widget_get_direction (GTK_WIDGET (entry)) == GTK_TEXT_DIR_RTL)
1576 {
1577 first_icon_pos = GTK_ENTRY_ICON_SECONDARY;
1578 second_icon_pos = GTK_ENTRY_ICON_PRIMARY;
1579 }
1580 else
1581 {
1582 first_icon_pos = GTK_ENTRY_ICON_PRIMARY;
1583 second_icon_pos = GTK_ENTRY_ICON_SECONDARY;
1584 }
1585
1586 icon_info = priv->icons[first_icon_pos];
1587 if (icon_info)
1588 gtk_widget_insert_after (widget: icon_info->widget, GTK_WIDGET (entry), NULL);
1589
1590 icon_info = priv->icons[second_icon_pos];
1591 if (icon_info)
1592 gtk_widget_insert_before (widget: icon_info->widget, GTK_WIDGET (entry), NULL);
1593}
1594
1595static GtkEntryIconPosition
1596get_icon_position_from_controller (GtkEntry *entry,
1597 GtkEventController *controller)
1598{
1599 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
1600 GtkWidget *widget = gtk_event_controller_get_widget (controller);
1601
1602 if (priv->icons[GTK_ENTRY_ICON_PRIMARY] &&
1603 priv->icons[GTK_ENTRY_ICON_PRIMARY]->widget == widget)
1604 return GTK_ENTRY_ICON_PRIMARY;
1605 else if (priv->icons[GTK_ENTRY_ICON_SECONDARY] &&
1606 priv->icons[GTK_ENTRY_ICON_SECONDARY]->widget == widget)
1607 return GTK_ENTRY_ICON_SECONDARY;
1608
1609 g_assert_not_reached ();
1610 return -1;
1611}
1612
1613static void
1614icon_pressed_cb (GtkGestureClick *gesture,
1615 int n_press,
1616 double x,
1617 double y,
1618 GtkEntry *entry)
1619{
1620 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
1621 GtkEntryIconPosition pos;
1622 EntryIconInfo *icon_info;
1623
1624 pos = get_icon_position_from_controller (entry, GTK_EVENT_CONTROLLER (gesture));
1625 icon_info = priv->icons[pos];
1626
1627 if (!icon_info->nonactivatable)
1628 g_signal_emit (instance: entry, signal_id: signals[ICON_PRESS], detail: 0, pos);
1629
1630 gtk_gesture_set_state (GTK_GESTURE (gesture), state: GTK_EVENT_SEQUENCE_CLAIMED);
1631}
1632
1633static void
1634icon_released_cb (GtkGestureClick *gesture,
1635 int n_press,
1636 double x,
1637 double y,
1638 GtkEntry *entry)
1639{
1640 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
1641 GtkEntryIconPosition pos;
1642 EntryIconInfo *icon_info;
1643
1644 pos = get_icon_position_from_controller (entry, GTK_EVENT_CONTROLLER (gesture));
1645 icon_info = priv->icons[pos];
1646
1647 if (!icon_info->nonactivatable)
1648 g_signal_emit (instance: entry, signal_id: signals[ICON_RELEASE], detail: 0, pos);
1649}
1650
1651static void
1652icon_drag_update_cb (GtkGestureDrag *gesture,
1653 double offset_x,
1654 double offset_y,
1655 GtkEntry *entry)
1656{
1657 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
1658 GtkEntryIconPosition pos;
1659 EntryIconInfo *icon_info;
1660
1661 pos = get_icon_position_from_controller (entry, GTK_EVENT_CONTROLLER (gesture));
1662 icon_info = priv->icons[pos];
1663
1664 if (icon_info->content != NULL &&
1665 gtk_drag_check_threshold_double (widget: icon_info->widget, start_x: 0, start_y: 0, current_x: offset_x, current_y: offset_y))
1666 {
1667 GdkPaintable *paintable;
1668 GdkSurface *surface;
1669 GdkDevice *device;
1670 GdkDrag *drag;
1671 double start_x, start_y;
1672
1673 icon_info->in_drag = TRUE;
1674
1675 surface = gtk_native_get_surface (self: gtk_widget_get_native (GTK_WIDGET (entry)));
1676 device = gtk_gesture_get_device (GTK_GESTURE (gesture));
1677
1678 gtk_gesture_drag_get_start_point (gesture, x: &start_x, y: &start_y);
1679
1680 drag = gdk_drag_begin (surface, device, content: icon_info->content, actions: icon_info->actions, dx: start_x, dy: start_y);
1681 paintable = gtk_widget_paintable_new (widget: icon_info->widget);
1682 gtk_drag_icon_set_from_paintable (drag, paintable, hot_x: -2, hot_y: -2);
1683 g_object_unref (object: paintable);
1684
1685 g_object_unref (object: drag);
1686 }
1687}
1688
1689static EntryIconInfo*
1690construct_icon_info (GtkWidget *widget,
1691 GtkEntryIconPosition icon_pos)
1692{
1693 GtkEntry *entry = GTK_ENTRY (widget);
1694 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
1695 EntryIconInfo *icon_info;
1696 GtkGesture *drag, *press;
1697
1698 g_return_val_if_fail (priv->icons[icon_pos] == NULL, NULL);
1699
1700 icon_info = g_slice_new0 (EntryIconInfo);
1701 priv->icons[icon_pos] = icon_info;
1702
1703 icon_info->widget = gtk_image_new ();
1704 gtk_widget_set_cursor_from_name (widget: icon_info->widget, name: "default");
1705 if (icon_pos == GTK_ENTRY_ICON_PRIMARY)
1706 gtk_widget_insert_before (widget: icon_info->widget, parent: widget, next_sibling: priv->text);
1707 else
1708 gtk_widget_insert_after (widget: icon_info->widget, parent: widget, previous_sibling: priv->text);
1709
1710 update_icon_style (widget, icon_pos);
1711 update_node_ordering (entry);
1712
1713 press = gtk_gesture_click_new ();
1714 g_signal_connect (press, "pressed", G_CALLBACK (icon_pressed_cb), entry);
1715 g_signal_connect (press, "released", G_CALLBACK (icon_released_cb), entry);
1716 gtk_widget_add_controller (widget: icon_info->widget, GTK_EVENT_CONTROLLER (press));
1717
1718 drag = gtk_gesture_drag_new ();
1719 g_signal_connect (drag, "drag-update",
1720 G_CALLBACK (icon_drag_update_cb), entry);
1721 gtk_widget_add_controller (widget: icon_info->widget, GTK_EVENT_CONTROLLER (drag));
1722
1723 gtk_gesture_group (group_gesture: press, gesture: drag);
1724
1725 return icon_info;
1726}
1727
1728static void
1729gtk_entry_measure (GtkWidget *widget,
1730 GtkOrientation orientation,
1731 int for_size,
1732 int *minimum,
1733 int *natural,
1734 int *minimum_baseline,
1735 int *natural_baseline)
1736{
1737 GtkEntry *entry = GTK_ENTRY (widget);
1738 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
1739 int i;
1740
1741 gtk_widget_measure (widget: priv->text,
1742 orientation,
1743 for_size,
1744 minimum, natural,
1745 minimum_baseline, natural_baseline);
1746
1747 for (i = 0; i < MAX_ICONS; i++)
1748 {
1749 EntryIconInfo *icon_info = priv->icons[i];
1750 int icon_min, icon_nat;
1751
1752 if (!icon_info)
1753 continue;
1754
1755 gtk_widget_measure (widget: icon_info->widget,
1756 orientation: GTK_ORIENTATION_HORIZONTAL,
1757 for_size: -1, minimum: &icon_min, natural: &icon_nat, NULL, NULL);
1758
1759 if (orientation == GTK_ORIENTATION_HORIZONTAL)
1760 {
1761 *minimum += icon_min;
1762 *natural += icon_nat;
1763 }
1764 else
1765 {
1766 *minimum = MAX (*minimum, icon_min);
1767 *natural = MAX (*natural, icon_nat);
1768 }
1769 }
1770
1771 if (priv->progress_widget && gtk_widget_get_visible (widget: priv->progress_widget))
1772 {
1773 int prog_min, prog_nat;
1774
1775 gtk_widget_measure (widget: priv->progress_widget,
1776 orientation,
1777 for_size,
1778 minimum: &prog_min, natural: &prog_nat,
1779 NULL, NULL);
1780
1781 *minimum = MAX (*minimum, prog_min);
1782 *natural = MAX (*natural, prog_nat);
1783 }
1784}
1785
1786static void
1787gtk_entry_size_allocate (GtkWidget *widget,
1788 int width,
1789 int height,
1790 int baseline)
1791{
1792 const gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
1793 GtkEntry *entry = GTK_ENTRY (widget);
1794 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
1795 int i;
1796 GtkAllocation text_alloc;
1797
1798 text_alloc.x = 0;
1799 text_alloc.y = 0;
1800 text_alloc.width = width;
1801 text_alloc.height = height;
1802
1803 for (i = 0; i < MAX_ICONS; i++)
1804 {
1805 EntryIconInfo *icon_info = priv->icons[i];
1806 GtkAllocation icon_alloc;
1807 int icon_width;
1808
1809 if (!icon_info)
1810 continue;
1811
1812 gtk_widget_measure (widget: icon_info->widget,
1813 orientation: GTK_ORIENTATION_HORIZONTAL,
1814 for_size: -1,
1815 NULL, natural: &icon_width,
1816 NULL, NULL);
1817
1818 if ((is_rtl && i == GTK_ENTRY_ICON_PRIMARY) ||
1819 (!is_rtl && i == GTK_ENTRY_ICON_SECONDARY))
1820 icon_alloc.x = width - icon_width;
1821 else
1822 icon_alloc.x = 0;
1823 icon_alloc.y = 0;
1824 icon_alloc.width = icon_width;
1825 icon_alloc.height = height;
1826
1827 gtk_widget_size_allocate (widget: icon_info->widget, allocation: &icon_alloc, baseline);
1828
1829 text_alloc.width -= icon_width;
1830
1831 if ((!is_rtl && i == GTK_ENTRY_ICON_PRIMARY) ||
1832 (is_rtl && i == GTK_ENTRY_ICON_SECONDARY))
1833 text_alloc.x += icon_width;
1834 }
1835
1836 gtk_widget_size_allocate (widget: priv->text, allocation: &text_alloc, baseline);
1837
1838 if (priv->progress_widget && gtk_widget_get_visible (widget: priv->progress_widget))
1839 {
1840 GtkAllocation progress_alloc;
1841 int min, nat;
1842
1843 gtk_widget_measure (widget: priv->progress_widget,
1844 orientation: GTK_ORIENTATION_VERTICAL,
1845 for_size: -1,
1846 minimum: &min, natural: &nat,
1847 NULL, NULL);
1848 progress_alloc.x = 0;
1849 progress_alloc.y = height - nat;
1850 progress_alloc.width = width;
1851 progress_alloc.height = nat;
1852
1853 gtk_widget_size_allocate (widget: priv->progress_widget, allocation: &progress_alloc, baseline: -1);
1854 }
1855
1856 /* Do this here instead of gtk_entry_size_allocate() so it works
1857 * inside spinbuttons, which don't chain up.
1858 */
1859 if (gtk_widget_get_realized (widget))
1860 {
1861 GtkEntryCompletion *completion;
1862
1863 completion = gtk_entry_get_completion (entry);
1864 if (completion)
1865 _gtk_entry_completion_resize_popup (completion);
1866 }
1867}
1868
1869static void
1870gtk_entry_snapshot (GtkWidget *widget,
1871 GtkSnapshot *snapshot)
1872{
1873 GtkEntry *entry = GTK_ENTRY (widget);
1874 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
1875 int i;
1876
1877 /* Draw progress */
1878 if (priv->progress_widget && gtk_widget_get_visible (widget: priv->progress_widget))
1879 gtk_widget_snapshot_child (widget, child: priv->progress_widget, snapshot);
1880
1881 gtk_widget_snapshot_child (widget, child: priv->text, snapshot);
1882
1883 /* Draw icons */
1884 for (i = 0; i < MAX_ICONS; i++)
1885 {
1886 EntryIconInfo *icon_info = priv->icons[i];
1887
1888 if (icon_info != NULL)
1889 gtk_widget_snapshot_child (widget, child: icon_info->widget, snapshot);
1890 }
1891}
1892
1893/**
1894 * gtk_entry_grab_focus_without_selecting:
1895 * @entry: a `GtkEntry`
1896 *
1897 * Causes @entry to have keyboard focus.
1898 *
1899 * It behaves like [method@Gtk.Widget.grab_focus], except that it doesn't
1900 * select the contents of the entry. You only want to call this on some
1901 * special entries which the user usually doesn't want to replace all text
1902 * in, such as search-as-you-type entries.
1903 *
1904 * Returns: %TRUE if focus is now inside @self
1905 */
1906gboolean
1907gtk_entry_grab_focus_without_selecting (GtkEntry *entry)
1908{
1909 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
1910
1911 g_return_val_if_fail (GTK_IS_ENTRY (entry), FALSE);
1912
1913 return gtk_text_grab_focus_without_selecting (GTK_TEXT (priv->text));
1914}
1915
1916static void
1917gtk_entry_direction_changed (GtkWidget *widget,
1918 GtkTextDirection previous_dir)
1919{
1920 GtkEntry *entry = GTK_ENTRY (widget);
1921
1922 update_icon_style (widget, icon_pos: GTK_ENTRY_ICON_PRIMARY);
1923 update_icon_style (widget, icon_pos: GTK_ENTRY_ICON_SECONDARY);
1924
1925 update_node_ordering (entry);
1926
1927 GTK_WIDGET_CLASS (gtk_entry_parent_class)->direction_changed (widget, previous_dir);
1928}
1929
1930/* GtkCellEditable method implementations
1931 */
1932static void
1933gtk_cell_editable_entry_activated (GtkEntry *entry, gpointer data)
1934{
1935 gtk_cell_editable_editing_done (GTK_CELL_EDITABLE (entry));
1936 gtk_cell_editable_remove_widget (GTK_CELL_EDITABLE (entry));
1937}
1938
1939static gboolean
1940gtk_cell_editable_entry_key_pressed (GtkEventControllerKey *key,
1941 guint keyval,
1942 guint keycode,
1943 GdkModifierType modifiers,
1944 GtkEntry *entry)
1945{
1946 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
1947
1948 if (keyval == GDK_KEY_Escape)
1949 {
1950 priv->editing_canceled = TRUE;
1951 gtk_cell_editable_editing_done (GTK_CELL_EDITABLE (entry));
1952 gtk_cell_editable_remove_widget (GTK_CELL_EDITABLE (entry));
1953
1954 return GDK_EVENT_STOP;
1955 }
1956
1957 /* override focus */
1958 if (keyval == GDK_KEY_Up || keyval == GDK_KEY_Down)
1959 {
1960 gtk_cell_editable_editing_done (GTK_CELL_EDITABLE (entry));
1961 gtk_cell_editable_remove_widget (GTK_CELL_EDITABLE (entry));
1962
1963 return GDK_EVENT_STOP;
1964 }
1965
1966 return GDK_EVENT_PROPAGATE;
1967}
1968
1969static void
1970gtk_entry_start_editing (GtkCellEditable *cell_editable,
1971 GdkEvent *event)
1972{
1973 g_signal_connect (cell_editable, "activate",
1974 G_CALLBACK (gtk_cell_editable_entry_activated), NULL);
1975 g_signal_connect (gtk_entry_get_key_controller (GTK_ENTRY (cell_editable)),
1976 "key-pressed",
1977 G_CALLBACK (gtk_cell_editable_entry_key_pressed),
1978 cell_editable);
1979}
1980
1981/* Internal functions
1982 */
1983
1984/**
1985 * gtk_entry_reset_im_context:
1986 * @entry: a `GtkEntry`
1987 *
1988 * Reset the input method context of the entry if needed.
1989 *
1990 * This can be necessary in the case where modifying the buffer
1991 * would confuse on-going input method behavior.
1992 */
1993void
1994gtk_entry_reset_im_context (GtkEntry *entry)
1995{
1996 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
1997
1998 g_return_if_fail (GTK_IS_ENTRY (entry));
1999
2000 gtk_text_reset_im_context (GTK_TEXT (priv->text));
2001}
2002
2003static void
2004gtk_entry_clear_icon (GtkEntry *entry,
2005 GtkEntryIconPosition icon_pos)
2006{
2007 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
2008 EntryIconInfo *icon_info = priv->icons[icon_pos];
2009 GtkImageType storage_type;
2010
2011 if (icon_info == NULL)
2012 return;
2013
2014 storage_type = gtk_image_get_storage_type (GTK_IMAGE (icon_info->widget));
2015
2016 if (storage_type == GTK_IMAGE_EMPTY)
2017 return;
2018
2019 g_object_freeze_notify (G_OBJECT (entry));
2020
2021 switch (storage_type)
2022 {
2023 case GTK_IMAGE_PAINTABLE:
2024 g_object_notify_by_pspec (G_OBJECT (entry),
2025 pspec: entry_props[icon_pos == GTK_ENTRY_ICON_PRIMARY
2026 ? PROP_PAINTABLE_PRIMARY
2027 : PROP_PAINTABLE_SECONDARY]);
2028 break;
2029
2030 case GTK_IMAGE_ICON_NAME:
2031 g_object_notify_by_pspec (G_OBJECT (entry),
2032 pspec: entry_props[icon_pos == GTK_ENTRY_ICON_PRIMARY
2033 ? PROP_ICON_NAME_PRIMARY
2034 : PROP_ICON_NAME_SECONDARY]);
2035 break;
2036
2037 case GTK_IMAGE_GICON:
2038 g_object_notify_by_pspec (G_OBJECT (entry),
2039 pspec: entry_props[icon_pos == GTK_ENTRY_ICON_PRIMARY
2040 ? PROP_GICON_PRIMARY
2041 : PROP_GICON_SECONDARY]);
2042 break;
2043
2044 case GTK_IMAGE_EMPTY:
2045 default:
2046 g_assert_not_reached ();
2047 break;
2048 }
2049
2050 gtk_image_clear (GTK_IMAGE (icon_info->widget));
2051
2052 g_object_notify_by_pspec (G_OBJECT (entry),
2053 pspec: entry_props[icon_pos == GTK_ENTRY_ICON_PRIMARY
2054 ? PROP_STORAGE_TYPE_PRIMARY
2055 : PROP_STORAGE_TYPE_SECONDARY]);
2056
2057 g_object_thaw_notify (G_OBJECT (entry));
2058}
2059
2060/* Public API
2061 */
2062
2063/**
2064 * gtk_entry_new:
2065 *
2066 * Creates a new entry.
2067 *
2068 * Returns: a new `GtkEntry`.
2069 */
2070GtkWidget*
2071gtk_entry_new (void)
2072{
2073 return g_object_new (GTK_TYPE_ENTRY, NULL);
2074}
2075
2076/**
2077 * gtk_entry_new_with_buffer:
2078 * @buffer: The buffer to use for the new `GtkEntry`.
2079 *
2080 * Creates a new entry with the specified text buffer.
2081 *
2082 * Returns: a new `GtkEntry`
2083 */
2084GtkWidget*
2085gtk_entry_new_with_buffer (GtkEntryBuffer *buffer)
2086{
2087 g_return_val_if_fail (GTK_IS_ENTRY_BUFFER (buffer), NULL);
2088
2089 return g_object_new (GTK_TYPE_ENTRY, first_property_name: "buffer", buffer, NULL);
2090}
2091
2092static GtkEntryBuffer*
2093get_buffer (GtkEntry *entry)
2094{
2095 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
2096
2097 return gtk_text_get_buffer (GTK_TEXT (priv->text));
2098}
2099
2100/**
2101 * gtk_entry_get_buffer: (attributes org.gtk.Method.get_property=buffer)
2102 * @entry: a `GtkEntry`
2103 *
2104 * Get the `GtkEntryBuffer` object which holds the text for
2105 * this widget.
2106 *
2107 * Returns: (transfer none): A `GtkEntryBuffer` object.
2108 */
2109GtkEntryBuffer*
2110gtk_entry_get_buffer (GtkEntry *entry)
2111{
2112 g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL);
2113
2114 return get_buffer (entry);
2115}
2116
2117/**
2118 * gtk_entry_set_buffer: (attributes org.gtk.Method.set_property=buffer)
2119 * @entry: a `GtkEntry`
2120 * @buffer: a `GtkEntryBuffer`
2121 *
2122 * Set the `GtkEntryBuffer` object which holds the text for
2123 * this widget.
2124 */
2125void
2126gtk_entry_set_buffer (GtkEntry *entry,
2127 GtkEntryBuffer *buffer)
2128{
2129 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
2130
2131 g_return_if_fail (GTK_IS_ENTRY (entry));
2132
2133 gtk_text_set_buffer (GTK_TEXT (priv->text), buffer);
2134}
2135
2136/**
2137 * gtk_entry_set_visibility: (attributes org.gtk.Method.set_property=visibility)
2138 * @entry: a `GtkEntry`
2139 * @visible: %TRUE if the contents of the entry are displayed as plaintext
2140 *
2141 * Sets whether the contents of the entry are visible or not.
2142 *
2143 * When visibility is set to %FALSE, characters are displayed
2144 * as the invisible char, and will also appear that way when
2145 * the text in the entry widget is copied elsewhere.
2146 *
2147 * By default, GTK picks the best invisible character available
2148 * in the current font, but it can be changed with
2149 * [method@Gtk.Entry.set_invisible_char].
2150 *
2151 * Note that you probably want to set [property@Gtk.Entry:input-purpose]
2152 * to %GTK_INPUT_PURPOSE_PASSWORD or %GTK_INPUT_PURPOSE_PIN to
2153 * inform input methods about the purpose of this entry,
2154 * in addition to setting visibility to %FALSE.
2155 */
2156void
2157gtk_entry_set_visibility (GtkEntry *entry,
2158 gboolean visible)
2159{
2160 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
2161
2162 g_return_if_fail (GTK_IS_ENTRY (entry));
2163
2164 gtk_text_set_visibility (GTK_TEXT (priv->text), visible);
2165}
2166
2167/**
2168 * gtk_entry_get_visibility: (attributes org.gtk.Method.get_property=visibility)
2169 * @entry: a `GtkEntry`
2170 *
2171 * Retrieves whether the text in @entry is visible.
2172 *
2173 * See [method@Gtk.Entry.set_visibility].
2174 *
2175 * Returns: %TRUE if the text is currently visible
2176 */
2177gboolean
2178gtk_entry_get_visibility (GtkEntry *entry)
2179{
2180 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
2181
2182 g_return_val_if_fail (GTK_IS_ENTRY (entry), FALSE);
2183
2184 return gtk_text_get_visibility (GTK_TEXT (priv->text));
2185}
2186
2187/**
2188 * gtk_entry_set_invisible_char: (attributes org.gtk.Method.sets_property=invisible-char)
2189 * @entry: a `GtkEntry`
2190 * @ch: a Unicode character
2191 *
2192 * Sets the character to use in place of the actual text
2193 * in “password mode”.
2194 *
2195 * See [method@Gtk.Entry.set_visibility] for how to enable
2196 * “password mode”.
2197 *
2198 * By default, GTK picks the best invisible char available in
2199 * the current font. If you set the invisible char to 0, then
2200 * the user will get no feedback at all; there will be no text
2201 * on the screen as they type.
2202 */
2203void
2204gtk_entry_set_invisible_char (GtkEntry *entry,
2205 gunichar ch)
2206{
2207 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
2208
2209 g_return_if_fail (GTK_IS_ENTRY (entry));
2210
2211 gtk_text_set_invisible_char (GTK_TEXT (priv->text), ch);
2212}
2213
2214/**
2215 * gtk_entry_get_invisible_char: (attributes org.gtk.Method.get_property=invisible-char)
2216 * @entry: a `GtkEntry`
2217 *
2218 * Retrieves the character displayed in place of the actual text
2219 * in “password mode”.
2220 *
2221 * Returns: the current invisible char, or 0, if the entry does not
2222 * show invisible text at all.
2223 */
2224gunichar
2225gtk_entry_get_invisible_char (GtkEntry *entry)
2226{
2227 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
2228
2229 g_return_val_if_fail (GTK_IS_ENTRY (entry), 0);
2230
2231 return gtk_text_get_invisible_char (GTK_TEXT (priv->text));
2232}
2233
2234/**
2235 * gtk_entry_unset_invisible_char:
2236 * @entry: a `GtkEntry`
2237 *
2238 * Unsets the invisible char, so that the default invisible char
2239 * is used again. See [method@Gtk.Entry.set_invisible_char].
2240 */
2241void
2242gtk_entry_unset_invisible_char (GtkEntry *entry)
2243{
2244 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
2245
2246 g_return_if_fail (GTK_IS_ENTRY (entry));
2247
2248 gtk_text_unset_invisible_char (GTK_TEXT (priv->text));
2249}
2250
2251/**
2252 * gtk_entry_set_overwrite_mode: (attributes org.gtk.Method.set_property=overwrite-mode)
2253 * @entry: a `GtkEntry`
2254 * @overwrite: new value
2255 *
2256 * Sets whether the text is overwritten when typing in the `GtkEntry`.
2257 */
2258void
2259gtk_entry_set_overwrite_mode (GtkEntry *entry,
2260 gboolean overwrite)
2261{
2262 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
2263
2264 g_return_if_fail (GTK_IS_ENTRY (entry));
2265
2266 gtk_text_set_overwrite_mode (GTK_TEXT (priv->text), overwrite);
2267}
2268
2269/**
2270 * gtk_entry_get_overwrite_mode: (attributes org.gtk.Method.get_property=overwrite-mode)
2271 * @entry: a `GtkEntry`
2272 *
2273 * Gets whether the `GtkEntry` is in overwrite mode.
2274 *
2275 * Returns: whether the text is overwritten when typing.
2276 */
2277gboolean
2278gtk_entry_get_overwrite_mode (GtkEntry *entry)
2279{
2280 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
2281
2282 g_return_val_if_fail (GTK_IS_ENTRY (entry), FALSE);
2283
2284 return gtk_text_get_overwrite_mode (GTK_TEXT (priv->text));
2285
2286}
2287
2288/**
2289 * gtk_entry_set_max_length: (attributes org.gtk.Method.set_property=max-length)
2290 * @entry: a `GtkEntry`
2291 * @max: the maximum length of the entry, or 0 for no maximum.
2292 * (other than the maximum length of entries.) The value passed in will
2293 * be clamped to the range 0-65536.
2294 *
2295 * Sets the maximum allowed length of the contents of the widget.
2296 *
2297 * If the current contents are longer than the given length, then
2298 * they will be truncated to fit. The length is is in characters.
2299 *
2300 * This is equivalent to getting @entry's `GtkEntryBuffer` and
2301 * calling [method@Gtk.EntryBuffer.set_max_length] on it.
2302 */
2303void
2304gtk_entry_set_max_length (GtkEntry *entry,
2305 int max)
2306{
2307 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
2308
2309 g_return_if_fail (GTK_IS_ENTRY (entry));
2310
2311 gtk_text_set_max_length (GTK_TEXT (priv->text), length: max);
2312}
2313
2314/**
2315 * gtk_entry_get_max_length: (attributes org.gtk.Method.get_property=max-length)
2316 * @entry: a `GtkEntry`
2317 *
2318 * Retrieves the maximum allowed length of the text in @entry.
2319 *
2320 * See [method@Gtk.Entry.set_max_length].
2321 *
2322 * Returns: the maximum allowed number of characters
2323 * in `GtkEntry`, or 0 if there is no maximum.
2324 */
2325int
2326gtk_entry_get_max_length (GtkEntry *entry)
2327{
2328 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
2329
2330 g_return_val_if_fail (GTK_IS_ENTRY (entry), 0);
2331
2332 return gtk_text_get_max_length (GTK_TEXT (priv->text));
2333}
2334
2335/**
2336 * gtk_entry_get_text_length: (attributes org.gtk.Method.get_property=text-length)
2337 * @entry: a `GtkEntry`
2338 *
2339 * Retrieves the current length of the text in @entry.
2340 *
2341 * This is equivalent to getting @entry's `GtkEntryBuffer`
2342 * and calling [method@Gtk.EntryBuffer.get_length] on it.
2343 *
2344 * Returns: the current number of characters
2345 * in `GtkEntry`, or 0 if there are none.
2346 */
2347guint16
2348gtk_entry_get_text_length (GtkEntry *entry)
2349{
2350 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
2351
2352 g_return_val_if_fail (GTK_IS_ENTRY (entry), 0);
2353
2354 return gtk_text_get_text_length (GTK_TEXT (priv->text));
2355}
2356
2357/**
2358 * gtk_entry_set_activates_default: (attributes org.gtk.Method.set_property=activates-default)
2359 * @entry: a `GtkEntry`
2360 * @setting: %TRUE to activate window’s default widget on Enter keypress
2361 *
2362 * Sets whether pressing Enter in the @entry will activate the default
2363 * widget for the window containing the entry.
2364 *
2365 * This usually means that the dialog containing the entry will be closed,
2366 * since the default widget is usually one of the dialog buttons.
2367 */
2368void
2369gtk_entry_set_activates_default (GtkEntry *entry,
2370 gboolean setting)
2371{
2372 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
2373
2374 g_return_if_fail (GTK_IS_ENTRY (entry));
2375
2376 gtk_text_set_activates_default (GTK_TEXT (priv->text), activates: setting);
2377}
2378
2379/**
2380 * gtk_entry_get_activates_default: (attributes org.gtk.Method.get_property=activates-default)
2381 * @entry: a `GtkEntry`
2382 *
2383 * Retrieves the value set by gtk_entry_set_activates_default().
2384 *
2385 * Returns: %TRUE if the entry will activate the default widget
2386 */
2387gboolean
2388gtk_entry_get_activates_default (GtkEntry *entry)
2389{
2390 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
2391
2392 g_return_val_if_fail (GTK_IS_ENTRY (entry), FALSE);
2393
2394 return gtk_text_get_activates_default (GTK_TEXT (priv->text));
2395}
2396
2397/**
2398 * gtk_entry_set_has_frame: (attributes org.gtk.Method.set_property=has-frame)
2399 * @entry: a `GtkEntry`
2400 * @setting: new value
2401 *
2402 * Sets whether the entry has a beveled frame around it.
2403 */
2404void
2405gtk_entry_set_has_frame (GtkEntry *entry,
2406 gboolean setting)
2407{
2408 g_return_if_fail (GTK_IS_ENTRY (entry));
2409
2410 setting = (setting != FALSE);
2411
2412 if (setting == gtk_entry_get_has_frame (entry))
2413 return;
2414
2415 if (setting)
2416 gtk_widget_remove_css_class (GTK_WIDGET (entry), css_class: "flat");
2417 else
2418 gtk_widget_add_css_class (GTK_WIDGET (entry), css_class: "flat");
2419
2420 g_object_notify_by_pspec (G_OBJECT (entry), pspec: entry_props[PROP_HAS_FRAME]);
2421}
2422
2423/**
2424 * gtk_entry_get_has_frame: (attributes org.gtk.Method.get_property=has-frame)
2425 * @entry: a `GtkEntry`
2426 *
2427 * Gets the value set by gtk_entry_set_has_frame().
2428 *
2429 * Returns: whether the entry has a beveled frame
2430 */
2431gboolean
2432gtk_entry_get_has_frame (GtkEntry *entry)
2433{
2434 g_return_val_if_fail (GTK_IS_ENTRY (entry), FALSE);
2435
2436 return !gtk_widget_has_css_class (GTK_WIDGET (entry), css_class: "flat");
2437}
2438
2439/**
2440 * gtk_entry_set_alignment:
2441 * @entry: a `GtkEntry`
2442 * @xalign: The horizontal alignment, from 0 (left) to 1 (right).
2443 * Reversed for RTL layouts
2444 *
2445 * Sets the alignment for the contents of the entry.
2446 *
2447 * This controls the horizontal positioning of the contents when
2448 * the displayed text is shorter than the width of the entry.
2449 *
2450 * See also: [property@Gtk.Editable:xalign]
2451 */
2452void
2453gtk_entry_set_alignment (GtkEntry *entry,
2454 float xalign)
2455{
2456 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
2457
2458 g_return_if_fail (GTK_IS_ENTRY (entry));
2459
2460 gtk_editable_set_alignment (GTK_EDITABLE (priv->text), xalign);
2461}
2462
2463/**
2464 * gtk_entry_get_alignment:
2465 * @entry: a `GtkEntry`
2466 *
2467 * Gets the value set by gtk_entry_set_alignment().
2468 *
2469 * See also: [property@Gtk.Editable:xalign]
2470 *
2471 * Returns: the alignment
2472 */
2473float
2474gtk_entry_get_alignment (GtkEntry *entry)
2475{
2476 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
2477
2478 g_return_val_if_fail (GTK_IS_ENTRY (entry), 0.0);
2479
2480 return gtk_editable_get_alignment (GTK_EDITABLE (priv->text));
2481}
2482
2483/**
2484 * gtk_entry_set_icon_from_paintable:
2485 * @entry: a `GtkEntry`
2486 * @icon_pos: Icon position
2487 * @paintable: (nullable): A `GdkPaintable`
2488 *
2489 * Sets the icon shown in the specified position using a `GdkPaintable`.
2490 *
2491 * If @paintable is %NULL, no icon will be shown in the specified position.
2492 */
2493void
2494gtk_entry_set_icon_from_paintable (GtkEntry *entry,
2495 GtkEntryIconPosition icon_pos,
2496 GdkPaintable *paintable)
2497{
2498 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
2499
2500 g_return_if_fail (GTK_IS_ENTRY (entry));
2501 g_return_if_fail (IS_VALID_ICON_POSITION (icon_pos));
2502
2503 g_object_freeze_notify (G_OBJECT (entry));
2504
2505 if (paintable)
2506 {
2507 EntryIconInfo *icon_info;
2508
2509 if ((icon_info = priv->icons[icon_pos]) == NULL)
2510 icon_info = construct_icon_info (GTK_WIDGET (entry), icon_pos);
2511
2512 g_object_ref (paintable);
2513
2514 gtk_image_set_from_paintable (GTK_IMAGE (icon_info->widget), paintable);
2515
2516 if (icon_pos == GTK_ENTRY_ICON_PRIMARY)
2517 {
2518 g_object_notify_by_pspec (G_OBJECT (entry), pspec: entry_props[PROP_PAINTABLE_PRIMARY]);
2519 g_object_notify_by_pspec (G_OBJECT (entry), pspec: entry_props[PROP_STORAGE_TYPE_PRIMARY]);
2520 }
2521 else
2522 {
2523 g_object_notify_by_pspec (G_OBJECT (entry), pspec: entry_props[PROP_PAINTABLE_SECONDARY]);
2524 g_object_notify_by_pspec (G_OBJECT (entry), pspec: entry_props[PROP_STORAGE_TYPE_SECONDARY]);
2525 }
2526
2527 g_object_unref (object: paintable);
2528 }
2529 else
2530 gtk_entry_clear_icon (entry, icon_pos);
2531
2532 if (gtk_widget_get_visible (GTK_WIDGET (entry)))
2533 gtk_widget_queue_resize (GTK_WIDGET (entry));
2534
2535 g_object_thaw_notify (G_OBJECT (entry));
2536}
2537
2538/**
2539 * gtk_entry_set_icon_from_icon_name:
2540 * @entry: A `GtkEntry`
2541 * @icon_pos: The position at which to set the icon
2542 * @icon_name: (nullable): An icon name
2543 *
2544 * Sets the icon shown in the entry at the specified position
2545 * from the current icon theme.
2546 *
2547 * If the icon name isn’t known, a “broken image” icon will be
2548 * displayed instead.
2549 *
2550 * If @icon_name is %NULL, no icon will be shown in the
2551 * specified position.
2552 */
2553void
2554gtk_entry_set_icon_from_icon_name (GtkEntry *entry,
2555 GtkEntryIconPosition icon_pos,
2556 const char *icon_name)
2557{
2558 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
2559 EntryIconInfo *icon_info;
2560
2561 g_return_if_fail (GTK_IS_ENTRY (entry));
2562 g_return_if_fail (IS_VALID_ICON_POSITION (icon_pos));
2563
2564 if ((icon_info = priv->icons[icon_pos]) == NULL)
2565 icon_info = construct_icon_info (GTK_WIDGET (entry), icon_pos);
2566
2567 g_object_freeze_notify (G_OBJECT (entry));
2568
2569
2570 if (icon_name != NULL)
2571 {
2572 gtk_image_set_from_icon_name (GTK_IMAGE (icon_info->widget), icon_name);
2573
2574 if (icon_pos == GTK_ENTRY_ICON_PRIMARY)
2575 {
2576 g_object_notify_by_pspec (G_OBJECT (entry), pspec: entry_props[PROP_ICON_NAME_PRIMARY]);
2577 g_object_notify_by_pspec (G_OBJECT (entry), pspec: entry_props[PROP_STORAGE_TYPE_PRIMARY]);
2578 }
2579 else
2580 {
2581 g_object_notify_by_pspec (G_OBJECT (entry), pspec: entry_props[PROP_ICON_NAME_SECONDARY]);
2582 g_object_notify_by_pspec (G_OBJECT (entry), pspec: entry_props[PROP_STORAGE_TYPE_SECONDARY]);
2583 }
2584 }
2585 else
2586 gtk_entry_clear_icon (entry, icon_pos);
2587
2588 if (gtk_widget_get_visible (GTK_WIDGET (entry)))
2589 gtk_widget_queue_resize (GTK_WIDGET (entry));
2590
2591 g_object_thaw_notify (G_OBJECT (entry));
2592}
2593
2594/**
2595 * gtk_entry_set_icon_from_gicon:
2596 * @entry: A `GtkEntry`
2597 * @icon_pos: The position at which to set the icon
2598 * @icon: (nullable): The icon to set
2599 *
2600 * Sets the icon shown in the entry at the specified position
2601 * from the current icon theme.
2602 *
2603 * If the icon isn’t known, a “broken image” icon will be
2604 * displayed instead.
2605 *
2606 * If @icon is %NULL, no icon will be shown in the
2607 * specified position.
2608 */
2609void
2610gtk_entry_set_icon_from_gicon (GtkEntry *entry,
2611 GtkEntryIconPosition icon_pos,
2612 GIcon *icon)
2613{
2614 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
2615 EntryIconInfo *icon_info;
2616
2617 g_return_if_fail (GTK_IS_ENTRY (entry));
2618 g_return_if_fail (IS_VALID_ICON_POSITION (icon_pos));
2619
2620 if ((icon_info = priv->icons[icon_pos]) == NULL)
2621 icon_info = construct_icon_info (GTK_WIDGET (entry), icon_pos);
2622
2623 g_object_freeze_notify (G_OBJECT (entry));
2624
2625 if (icon)
2626 {
2627 gtk_image_set_from_gicon (GTK_IMAGE (icon_info->widget), icon);
2628
2629 if (icon_pos == GTK_ENTRY_ICON_PRIMARY)
2630 {
2631 g_object_notify_by_pspec (G_OBJECT (entry), pspec: entry_props[PROP_GICON_PRIMARY]);
2632 g_object_notify_by_pspec (G_OBJECT (entry), pspec: entry_props[PROP_STORAGE_TYPE_PRIMARY]);
2633 }
2634 else
2635 {
2636 g_object_notify_by_pspec (G_OBJECT (entry), pspec: entry_props[PROP_GICON_SECONDARY]);
2637 g_object_notify_by_pspec (G_OBJECT (entry), pspec: entry_props[PROP_STORAGE_TYPE_SECONDARY]);
2638 }
2639 }
2640 else
2641 gtk_entry_clear_icon (entry, icon_pos);
2642
2643 if (gtk_widget_get_visible (GTK_WIDGET (entry)))
2644 gtk_widget_queue_resize (GTK_WIDGET (entry));
2645
2646 g_object_thaw_notify (G_OBJECT (entry));
2647}
2648
2649/**
2650 * gtk_entry_set_icon_activatable:
2651 * @entry: A `GtkEntry`
2652 * @icon_pos: Icon position
2653 * @activatable: %TRUE if the icon should be activatable
2654 *
2655 * Sets whether the icon is activatable.
2656 */
2657void
2658gtk_entry_set_icon_activatable (GtkEntry *entry,
2659 GtkEntryIconPosition icon_pos,
2660 gboolean activatable)
2661{
2662 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
2663 EntryIconInfo *icon_info;
2664
2665 g_return_if_fail (GTK_IS_ENTRY (entry));
2666 g_return_if_fail (IS_VALID_ICON_POSITION (icon_pos));
2667
2668 if ((icon_info = priv->icons[icon_pos]) == NULL)
2669 icon_info = construct_icon_info (GTK_WIDGET (entry), icon_pos);
2670
2671 activatable = activatable != FALSE;
2672
2673 if (icon_info->nonactivatable != !activatable)
2674 {
2675 icon_info->nonactivatable = !activatable;
2676
2677 g_object_notify_by_pspec (G_OBJECT (entry),
2678 pspec: entry_props[icon_pos == GTK_ENTRY_ICON_PRIMARY
2679 ? PROP_ACTIVATABLE_PRIMARY
2680 : PROP_ACTIVATABLE_SECONDARY]);
2681 }
2682}
2683
2684/**
2685 * gtk_entry_get_icon_activatable:
2686 * @entry: a `GtkEntry`
2687 * @icon_pos: Icon position
2688 *
2689 * Returns whether the icon is activatable.
2690 *
2691 * Returns: %TRUE if the icon is activatable.
2692 */
2693gboolean
2694gtk_entry_get_icon_activatable (GtkEntry *entry,
2695 GtkEntryIconPosition icon_pos)
2696{
2697 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
2698 EntryIconInfo *icon_info;
2699
2700 g_return_val_if_fail (GTK_IS_ENTRY (entry), FALSE);
2701 g_return_val_if_fail (IS_VALID_ICON_POSITION (icon_pos), FALSE);
2702
2703 icon_info = priv->icons[icon_pos];
2704
2705 return (!icon_info || !icon_info->nonactivatable);
2706}
2707
2708/**
2709 * gtk_entry_get_icon_paintable:
2710 * @entry: A `GtkEntry`
2711 * @icon_pos: Icon position
2712 *
2713 * Retrieves the `GdkPaintable` used for the icon.
2714 *
2715 * If no `GdkPaintable` was used for the icon, %NULL is returned.
2716 *
2717 * Returns: (transfer none) (nullable): A `GdkPaintable`
2718 * if no icon is set for this position or the icon set is not
2719 * a `GdkPaintable`.
2720 */
2721GdkPaintable *
2722gtk_entry_get_icon_paintable (GtkEntry *entry,
2723 GtkEntryIconPosition icon_pos)
2724{
2725 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
2726 EntryIconInfo *icon_info;
2727
2728 g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL);
2729 g_return_val_if_fail (IS_VALID_ICON_POSITION (icon_pos), NULL);
2730
2731 icon_info = priv->icons[icon_pos];
2732
2733 if (!icon_info)
2734 return NULL;
2735
2736 return gtk_image_get_paintable (GTK_IMAGE (icon_info->widget));
2737}
2738
2739/**
2740 * gtk_entry_get_icon_gicon:
2741 * @entry: A `GtkEntry`
2742 * @icon_pos: Icon position
2743 *
2744 * Retrieves the `GIcon` used for the icon.
2745 *
2746 * %NULL will be returned if there is no icon or if the icon was
2747 * set by some other method (e.g., by `GdkPaintable` or icon name).
2748 *
2749 * Returns: (transfer none) (nullable): A `GIcon`
2750 */
2751GIcon *
2752gtk_entry_get_icon_gicon (GtkEntry *entry,
2753 GtkEntryIconPosition icon_pos)
2754{
2755 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
2756 EntryIconInfo *icon_info;
2757
2758 g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL);
2759 g_return_val_if_fail (IS_VALID_ICON_POSITION (icon_pos), NULL);
2760
2761 icon_info = priv->icons[icon_pos];
2762
2763 if (!icon_info)
2764 return NULL;
2765
2766 return gtk_image_get_gicon (GTK_IMAGE (icon_info->widget));
2767}
2768
2769/**
2770 * gtk_entry_get_icon_name:
2771 * @entry: A `GtkEntry`
2772 * @icon_pos: Icon position
2773 *
2774 * Retrieves the icon name used for the icon.
2775 *
2776 * %NULL is returned if there is no icon or if the icon was set
2777 * by some other method (e.g., by `GdkPaintable` or gicon).
2778 *
2779 * Returns: (nullable): An icon name
2780 */
2781const char *
2782gtk_entry_get_icon_name (GtkEntry *entry,
2783 GtkEntryIconPosition icon_pos)
2784{
2785 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
2786 EntryIconInfo *icon_info;
2787
2788 g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL);
2789 g_return_val_if_fail (IS_VALID_ICON_POSITION (icon_pos), NULL);
2790
2791 icon_info = priv->icons[icon_pos];
2792
2793 if (!icon_info)
2794 return NULL;
2795
2796 return gtk_image_get_icon_name (GTK_IMAGE (icon_info->widget));
2797}
2798
2799/**
2800 * gtk_entry_set_icon_sensitive:
2801 * @entry: A `GtkEntry`
2802 * @icon_pos: Icon position
2803 * @sensitive: Specifies whether the icon should appear
2804 * sensitive or insensitive
2805 *
2806 * Sets the sensitivity for the specified icon.
2807 */
2808void
2809gtk_entry_set_icon_sensitive (GtkEntry *entry,
2810 GtkEntryIconPosition icon_pos,
2811 gboolean sensitive)
2812{
2813 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
2814 EntryIconInfo *icon_info;
2815
2816 g_return_if_fail (GTK_IS_ENTRY (entry));
2817 g_return_if_fail (IS_VALID_ICON_POSITION (icon_pos));
2818
2819 if ((icon_info = priv->icons[icon_pos]) == NULL)
2820 icon_info = construct_icon_info (GTK_WIDGET (entry), icon_pos);
2821
2822 if (gtk_widget_get_sensitive (widget: icon_info->widget) != sensitive)
2823 {
2824 gtk_widget_set_sensitive (widget: icon_info->widget, sensitive);
2825
2826 g_object_notify_by_pspec (G_OBJECT (entry),
2827 pspec: entry_props[icon_pos == GTK_ENTRY_ICON_PRIMARY
2828 ? PROP_SENSITIVE_PRIMARY
2829 : PROP_SENSITIVE_SECONDARY]);
2830 }
2831}
2832
2833/**
2834 * gtk_entry_get_icon_sensitive:
2835 * @entry: a `GtkEntry`
2836 * @icon_pos: Icon position
2837 *
2838 * Returns whether the icon appears sensitive or insensitive.
2839 *
2840 * Returns: %TRUE if the icon is sensitive.
2841 */
2842gboolean
2843gtk_entry_get_icon_sensitive (GtkEntry *entry,
2844 GtkEntryIconPosition icon_pos)
2845{
2846 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
2847 EntryIconInfo *icon_info;
2848
2849 g_return_val_if_fail (GTK_IS_ENTRY (entry), TRUE);
2850 g_return_val_if_fail (IS_VALID_ICON_POSITION (icon_pos), TRUE);
2851
2852 icon_info = priv->icons[icon_pos];
2853
2854 if (!icon_info)
2855 return TRUE; /* Default of the property */
2856
2857 return gtk_widget_get_sensitive (widget: icon_info->widget);
2858}
2859
2860/**
2861 * gtk_entry_get_icon_storage_type:
2862 * @entry: a `GtkEntry`
2863 * @icon_pos: Icon position
2864 *
2865 * Gets the type of representation being used by the icon
2866 * to store image data.
2867 *
2868 * If the icon has no image data, the return value will
2869 * be %GTK_IMAGE_EMPTY.
2870 *
2871 * Returns: image representation being used
2872 */
2873GtkImageType
2874gtk_entry_get_icon_storage_type (GtkEntry *entry,
2875 GtkEntryIconPosition icon_pos)
2876{
2877 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
2878 EntryIconInfo *icon_info;
2879
2880 g_return_val_if_fail (GTK_IS_ENTRY (entry), GTK_IMAGE_EMPTY);
2881 g_return_val_if_fail (IS_VALID_ICON_POSITION (icon_pos), GTK_IMAGE_EMPTY);
2882
2883 icon_info = priv->icons[icon_pos];
2884
2885 if (!icon_info)
2886 return GTK_IMAGE_EMPTY;
2887
2888 return gtk_image_get_storage_type (GTK_IMAGE (icon_info->widget));
2889}
2890
2891/**
2892 * gtk_entry_get_icon_at_pos:
2893 * @entry: a `GtkEntry`
2894 * @x: the x coordinate of the position to find, relative to @entry
2895 * @y: the y coordinate of the position to find, relative to @entry
2896 *
2897 * Finds the icon at the given position and return its index.
2898 *
2899 * The position’s coordinates are relative to the @entry’s
2900 * top left corner. If @x, @y doesn’t lie inside an icon,
2901 * -1 is returned. This function is intended for use in a
2902 * [signal@Gtk.Widget::query-tooltip] signal handler.
2903 *
2904 * Returns: the index of the icon at the given position, or -1
2905 */
2906int
2907gtk_entry_get_icon_at_pos (GtkEntry *entry,
2908 int x,
2909 int y)
2910{
2911 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
2912 guint i;
2913
2914 g_return_val_if_fail (GTK_IS_ENTRY (entry), -1);
2915
2916 for (i = 0; i < MAX_ICONS; i++)
2917 {
2918 EntryIconInfo *icon_info = priv->icons[i];
2919 double icon_x, icon_y;
2920
2921 if (icon_info == NULL)
2922 continue;
2923
2924 gtk_widget_translate_coordinates (GTK_WIDGET (entry), dest_widget: icon_info->widget,
2925 src_x: x, src_y: y, dest_x: &icon_x, dest_y: &icon_y);
2926
2927 if (gtk_widget_contains (widget: icon_info->widget, x: icon_x, y: icon_y))
2928 return i;
2929 }
2930
2931 return -1;
2932}
2933
2934/**
2935 * gtk_entry_set_icon_drag_source:
2936 * @entry: a `GtkEntry`
2937 * @icon_pos: icon position
2938 * @provider: a `GdkContentProvider`
2939 * @actions: a bitmask of the allowed drag actions
2940 *
2941 * Sets up the icon at the given position as drag source.
2942 *
2943 * This makes it so that GTK will start a drag
2944 * operation when the user clicks and drags the icon.
2945 */
2946void
2947gtk_entry_set_icon_drag_source (GtkEntry *entry,
2948 GtkEntryIconPosition icon_pos,
2949 GdkContentProvider *provider,
2950 GdkDragAction actions)
2951{
2952 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
2953 EntryIconInfo *icon_info;
2954
2955 g_return_if_fail (GTK_IS_ENTRY (entry));
2956 g_return_if_fail (IS_VALID_ICON_POSITION (icon_pos));
2957
2958 if ((icon_info = priv->icons[icon_pos]) == NULL)
2959 icon_info = construct_icon_info (GTK_WIDGET (entry), icon_pos);
2960
2961 g_set_object (&icon_info->content, provider);
2962 icon_info->actions = actions;
2963}
2964
2965/**
2966 * gtk_entry_get_current_icon_drag_source:
2967 * @entry: a `GtkEntry`
2968 *
2969 * Returns the index of the icon which is the source of the
2970 * current DND operation, or -1.
2971 *
2972 * Returns: index of the icon which is the source of the
2973 * current DND operation, or -1.
2974 */
2975int
2976gtk_entry_get_current_icon_drag_source (GtkEntry *entry)
2977{
2978 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
2979 EntryIconInfo *icon_info = NULL;
2980 int i;
2981
2982 g_return_val_if_fail (GTK_IS_ENTRY (entry), -1);
2983
2984 for (i = 0; i < MAX_ICONS; i++)
2985 {
2986 if ((icon_info = priv->icons[i]))
2987 {
2988 if (icon_info->in_drag)
2989 return i;
2990 }
2991 }
2992
2993 return -1;
2994}
2995
2996/**
2997 * gtk_entry_get_icon_area:
2998 * @entry: A `GtkEntry`
2999 * @icon_pos: Icon position
3000 * @icon_area: (out): Return location for the icon’s area
3001 *
3002 * Gets the area where entry’s icon at @icon_pos is drawn.
3003 *
3004 * This function is useful when drawing something to the
3005 * entry in a draw callback.
3006 *
3007 * If the entry is not realized or has no icon at the given
3008 * position, @icon_area is filled with zeros. Otherwise,
3009 * @icon_area will be filled with the icon's allocation,
3010 * relative to @entry's allocation.
3011 */
3012void
3013gtk_entry_get_icon_area (GtkEntry *entry,
3014 GtkEntryIconPosition icon_pos,
3015 GdkRectangle *icon_area)
3016{
3017 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
3018 EntryIconInfo *icon_info;
3019 graphene_rect_t r;
3020
3021 g_return_if_fail (GTK_IS_ENTRY (entry));
3022 g_return_if_fail (icon_area != NULL);
3023
3024 icon_info = priv->icons[icon_pos];
3025
3026 if (icon_info &&
3027 gtk_widget_compute_bounds (widget: icon_info->widget, GTK_WIDGET (entry), out_bounds: &r))
3028 {
3029 *icon_area = (GdkRectangle){
3030 floorf (x: r.origin.x),
3031 floorf (x: r.origin.y),
3032 ceilf (x: r.size.width),
3033 ceilf (x: r.size.height),
3034 };
3035 }
3036 else
3037 {
3038 icon_area->x = 0;
3039 icon_area->y = 0;
3040 icon_area->width = 0;
3041 icon_area->height = 0;
3042 }
3043}
3044
3045static void
3046ensure_has_tooltip (GtkEntry *entry)
3047{
3048 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
3049 const char *text = gtk_widget_get_tooltip_text (GTK_WIDGET (entry));
3050 gboolean has_tooltip = text != NULL;
3051
3052 if (!has_tooltip)
3053 {
3054 int i;
3055
3056 for (i = 0; i < MAX_ICONS; i++)
3057 {
3058 EntryIconInfo *icon_info = priv->icons[i];
3059
3060 if (icon_info != NULL && icon_info->tooltip != NULL)
3061 {
3062 has_tooltip = TRUE;
3063 break;
3064 }
3065 }
3066 }
3067
3068 gtk_widget_set_has_tooltip (GTK_WIDGET (entry), has_tooltip);
3069}
3070
3071/**
3072 * gtk_entry_get_icon_tooltip_text:
3073 * @entry: a `GtkEntry`
3074 * @icon_pos: the icon position
3075 *
3076 * Gets the contents of the tooltip on the icon at the specified
3077 * position in @entry.
3078 *
3079 * Returns: (nullable) (transfer full): the tooltip text
3080 */
3081char *
3082gtk_entry_get_icon_tooltip_text (GtkEntry *entry,
3083 GtkEntryIconPosition icon_pos)
3084{
3085 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
3086 EntryIconInfo *icon_info;
3087 char *text = NULL;
3088
3089 g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL);
3090 g_return_val_if_fail (IS_VALID_ICON_POSITION (icon_pos), NULL);
3091
3092 icon_info = priv->icons[icon_pos];
3093
3094 if (!icon_info)
3095 return NULL;
3096
3097 if (icon_info->tooltip &&
3098 !pango_parse_markup (markup_text: icon_info->tooltip, length: -1, accel_marker: 0, NULL, text: &text, NULL, NULL))
3099 g_assert (NULL == text); /* text should still be NULL in case of markup errors */
3100
3101 return text;
3102}
3103
3104/**
3105 * gtk_entry_set_icon_tooltip_text:
3106 * @entry: a `GtkEntry`
3107 * @icon_pos: the icon position
3108 * @tooltip: (nullable): the contents of the tooltip for the icon
3109 *
3110 * Sets @tooltip as the contents of the tooltip for the icon
3111 * at the specified position.
3112 *
3113 * Use %NULL for @tooltip to remove an existing tooltip.
3114 *
3115 * See also [method@Gtk.Widget.set_tooltip_text] and
3116 * [method@Gtk.Entry.set_icon_tooltip_markup].
3117 *
3118 * If you unset the widget tooltip via
3119 * [method@Gtk.Widget.set_tooltip_text] or
3120 * [method@Gtk.Widget.set_tooltip_markup], this sets
3121 * [property@Gtk.Widget:has-tooltip] to %FALSE, which suppresses
3122 * icon tooltips too. You can resolve this by then calling
3123 * [method@Gtk.Widget.set_has_tooltip] to set
3124 * [property@Gtk.Widget:has-tooltip] back to %TRUE, or
3125 * setting at least one non-empty tooltip on any icon
3126 * achieves the same result.
3127 */
3128void
3129gtk_entry_set_icon_tooltip_text (GtkEntry *entry,
3130 GtkEntryIconPosition icon_pos,
3131 const char *tooltip)
3132{
3133 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
3134 EntryIconInfo *icon_info;
3135
3136 g_return_if_fail (GTK_IS_ENTRY (entry));
3137 g_return_if_fail (IS_VALID_ICON_POSITION (icon_pos));
3138
3139 if ((icon_info = priv->icons[icon_pos]) == NULL)
3140 icon_info = construct_icon_info (GTK_WIDGET (entry), icon_pos);
3141
3142 g_free (mem: icon_info->tooltip);
3143
3144 /* Treat an empty string as a NULL string,
3145 * because an empty string would be useless for a tooltip:
3146 */
3147 if (tooltip && tooltip[0] == '\0')
3148 tooltip = NULL;
3149
3150 icon_info->tooltip = tooltip ? g_markup_escape_text (text: tooltip, length: -1) : NULL;
3151
3152 ensure_has_tooltip (entry);
3153
3154 g_object_notify_by_pspec (G_OBJECT (entry),
3155 pspec: entry_props[icon_pos == GTK_ENTRY_ICON_PRIMARY
3156 ? PROP_TOOLTIP_TEXT_PRIMARY
3157 : PROP_TOOLTIP_TEXT_SECONDARY]);
3158}
3159
3160/**
3161 * gtk_entry_get_icon_tooltip_markup:
3162 * @entry: a `GtkEntry`
3163 * @icon_pos: the icon position
3164 *
3165 * Gets the contents of the tooltip on the icon at the specified
3166 * position in @entry.
3167 *
3168 * Returns: (nullable) (transfer full): the tooltip text
3169 */
3170char *
3171gtk_entry_get_icon_tooltip_markup (GtkEntry *entry,
3172 GtkEntryIconPosition icon_pos)
3173{
3174 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
3175 EntryIconInfo *icon_info;
3176
3177 g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL);
3178 g_return_val_if_fail (IS_VALID_ICON_POSITION (icon_pos), NULL);
3179
3180 icon_info = priv->icons[icon_pos];
3181
3182 if (!icon_info)
3183 return NULL;
3184
3185 return g_strdup (str: icon_info->tooltip);
3186}
3187
3188/**
3189 * gtk_entry_set_icon_tooltip_markup:
3190 * @entry: a `GtkEntry`
3191 * @icon_pos: the icon position
3192 * @tooltip: (nullable): the contents of the tooltip for the icon
3193 *
3194 * Sets @tooltip as the contents of the tooltip for the icon at
3195 * the specified position.
3196 *
3197 * @tooltip is assumed to be marked up with Pango Markup.
3198 *
3199 * Use %NULL for @tooltip to remove an existing tooltip.
3200 *
3201 * See also [method@Gtk.Widget.set_tooltip_markup] and
3202 * [method@Gtk.Entry.set_icon_tooltip_text].
3203 */
3204void
3205gtk_entry_set_icon_tooltip_markup (GtkEntry *entry,
3206 GtkEntryIconPosition icon_pos,
3207 const char *tooltip)
3208{
3209 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
3210 EntryIconInfo *icon_info;
3211
3212 g_return_if_fail (GTK_IS_ENTRY (entry));
3213 g_return_if_fail (IS_VALID_ICON_POSITION (icon_pos));
3214
3215 if ((icon_info = priv->icons[icon_pos]) == NULL)
3216 icon_info = construct_icon_info (GTK_WIDGET (entry), icon_pos);
3217
3218 g_free (mem: icon_info->tooltip);
3219
3220 /* Treat an empty string as a NULL string,
3221 * because an empty string would be useless for a tooltip:
3222 */
3223 if (tooltip && tooltip[0] == '\0')
3224 tooltip = NULL;
3225
3226 icon_info->tooltip = g_strdup (str: tooltip);
3227
3228 ensure_has_tooltip (entry);
3229
3230 g_object_notify_by_pspec (G_OBJECT (entry),
3231 pspec: entry_props[icon_pos == GTK_ENTRY_ICON_PRIMARY
3232 ? PROP_TOOLTIP_MARKUP_PRIMARY
3233 : PROP_TOOLTIP_MARKUP_SECONDARY]);
3234}
3235
3236static gboolean
3237gtk_entry_query_tooltip (GtkWidget *widget,
3238 int x,
3239 int y,
3240 gboolean keyboard_tip,
3241 GtkTooltip *tooltip)
3242{
3243 GtkEntry *entry = GTK_ENTRY (widget);
3244 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
3245 EntryIconInfo *icon_info;
3246 int icon_pos;
3247
3248 if (!keyboard_tip)
3249 {
3250 icon_pos = gtk_entry_get_icon_at_pos (entry, x, y);
3251 if (icon_pos != -1)
3252 {
3253 if ((icon_info = priv->icons[icon_pos]) != NULL)
3254 {
3255 if (icon_info->tooltip)
3256 {
3257 gtk_tooltip_set_markup (tooltip, markup: icon_info->tooltip);
3258 return TRUE;
3259 }
3260
3261 return FALSE;
3262 }
3263 }
3264 }
3265
3266 return GTK_WIDGET_CLASS (gtk_entry_parent_class)->query_tooltip (widget,
3267 x, y,
3268 keyboard_tip,
3269 tooltip);
3270}
3271
3272/**
3273 * gtk_entry_set_completion: (attributes org.gtk.Method.set_property=completion)
3274 * @entry: A `GtkEntry`
3275 * @completion: (nullable): The `GtkEntryCompletion`
3276 *
3277 * Sets @completion to be the auxiliary completion object
3278 * to use with @entry.
3279 *
3280 * All further configuration of the completion mechanism is
3281 * done on @completion using the `GtkEntryCompletion` API.
3282 * Completion is disabled if @completion is set to %NULL.
3283 */
3284void
3285gtk_entry_set_completion (GtkEntry *entry,
3286 GtkEntryCompletion *completion)
3287{
3288 GtkEntryCompletion *old;
3289
3290 g_return_if_fail (GTK_IS_ENTRY (entry));
3291 g_return_if_fail (!completion || GTK_IS_ENTRY_COMPLETION (completion));
3292
3293 old = gtk_entry_get_completion (entry);
3294
3295 if (old == completion)
3296 return;
3297
3298 if (old)
3299 {
3300 _gtk_entry_completion_disconnect (completion: old);
3301 g_object_unref (object: old);
3302 }
3303
3304 if (!completion)
3305 {
3306 g_object_set_qdata (G_OBJECT (entry), quark: quark_entry_completion, NULL);
3307 return;
3308 }
3309
3310 /* hook into the entry */
3311 g_object_ref (completion);
3312
3313 _gtk_entry_completion_connect (completion, entry);
3314
3315 g_object_set_qdata (G_OBJECT (entry), quark: quark_entry_completion, data: completion);
3316
3317 g_object_notify_by_pspec (G_OBJECT (entry), pspec: entry_props[PROP_COMPLETION]);
3318}
3319
3320/**
3321 * gtk_entry_get_completion: (attributes org.gtk.Method.get_property=completion)
3322 * @entry: A `GtkEntry`
3323 *
3324 * Returns the auxiliary completion object currently
3325 * in use by @entry.
3326 *
3327 * Returns: (nullable) (transfer none): The auxiliary
3328 * completion object currently in use by @entry
3329 */
3330GtkEntryCompletion *
3331gtk_entry_get_completion (GtkEntry *entry)
3332{
3333 GtkEntryCompletion *completion;
3334
3335 g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL);
3336
3337 completion = GTK_ENTRY_COMPLETION (g_object_get_qdata (G_OBJECT (entry), quark_entry_completion));
3338
3339 return completion;
3340}
3341
3342static void
3343gtk_entry_ensure_progress_widget (GtkEntry *entry)
3344{
3345 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
3346
3347 if (priv->progress_widget)
3348 return;
3349
3350 priv->progress_widget = g_object_new (GTK_TYPE_PROGRESS_BAR,
3351 first_property_name: "css-name", "progress",
3352 NULL);
3353 gtk_widget_set_can_target (widget: priv->progress_widget, FALSE);
3354
3355 gtk_widget_set_parent (widget: priv->progress_widget, GTK_WIDGET (entry));
3356
3357 update_node_ordering (entry);
3358}
3359
3360/**
3361 * gtk_entry_set_progress_fraction: (attributes org.gtk.Method.set_property=progress-fraction)
3362 * @entry: a `GtkEntry`
3363 * @fraction: fraction of the task that’s been completed
3364 *
3365 * Causes the entry’s progress indicator to “fill in” the given
3366 * fraction of the bar.
3367 *
3368 * The fraction should be between 0.0 and 1.0, inclusive.
3369 */
3370void
3371gtk_entry_set_progress_fraction (GtkEntry *entry,
3372 double fraction)
3373{
3374 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
3375 double old_fraction;
3376
3377 g_return_if_fail (GTK_IS_ENTRY (entry));
3378
3379 gtk_entry_ensure_progress_widget (entry);
3380 old_fraction = gtk_progress_bar_get_fraction (GTK_PROGRESS_BAR (priv->progress_widget));
3381 fraction = CLAMP (fraction, 0.0, 1.0);
3382
3383 if (fraction != old_fraction)
3384 {
3385 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (priv->progress_widget), fraction);
3386 gtk_widget_set_visible (widget: priv->progress_widget, visible: fraction > 0);
3387
3388 g_object_notify_by_pspec (G_OBJECT (entry), pspec: entry_props[PROP_PROGRESS_FRACTION]);
3389 }
3390}
3391
3392/**
3393 * gtk_entry_get_progress_fraction: (attributes org.gtk.Method.get_property=progress-fraction)
3394 * @entry: a `GtkEntry`
3395 *
3396 * Returns the current fraction of the task that’s been completed.
3397 *
3398 * See [method@Gtk.Entry.set_progress_fraction].
3399 *
3400 * Returns: a fraction from 0.0 to 1.0
3401 */
3402double
3403gtk_entry_get_progress_fraction (GtkEntry *entry)
3404{
3405 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
3406
3407 g_return_val_if_fail (GTK_IS_ENTRY (entry), 0.0);
3408
3409 if (priv->progress_widget)
3410 return gtk_progress_bar_get_fraction (GTK_PROGRESS_BAR (priv->progress_widget));
3411
3412 return 0.0;
3413}
3414
3415/**
3416 * gtk_entry_set_progress_pulse_step: (attributes org.gtk.Method.set_property=progress-pulse-step)
3417 * @entry: a `GtkEntry`
3418 * @fraction: fraction between 0.0 and 1.0
3419 *
3420 * Sets the fraction of total entry width to move the progress
3421 * bouncing block for each pulse.
3422 *
3423 * Use [method@Gtk.Entry.progress_pulse] to pulse
3424 * the progress.
3425 */
3426void
3427gtk_entry_set_progress_pulse_step (GtkEntry *entry,
3428 double fraction)
3429{
3430 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
3431
3432 g_return_if_fail (GTK_IS_ENTRY (entry));
3433
3434 fraction = CLAMP (fraction, 0.0, 1.0);
3435 gtk_entry_ensure_progress_widget (entry);
3436
3437
3438 if (fraction != gtk_progress_bar_get_pulse_step (GTK_PROGRESS_BAR (priv->progress_widget)))
3439 {
3440 gtk_progress_bar_set_pulse_step (GTK_PROGRESS_BAR (priv->progress_widget), fraction);
3441 g_object_notify_by_pspec (G_OBJECT (entry), pspec: entry_props[PROP_PROGRESS_PULSE_STEP]);
3442 }
3443}
3444
3445/**
3446 * gtk_entry_get_progress_pulse_step: (attributes org.gtk.Method.get_property=progress-pulse-step)
3447 * @entry: a `GtkEntry`
3448 *
3449 * Retrieves the pulse step set with
3450 * gtk_entry_set_progress_pulse_step().
3451 *
3452 * Returns: a fraction from 0.0 to 1.0
3453 */
3454double
3455gtk_entry_get_progress_pulse_step (GtkEntry *entry)
3456{
3457 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
3458
3459 g_return_val_if_fail (GTK_IS_ENTRY (entry), 0.0);
3460
3461 if (priv->progress_widget)
3462 return gtk_progress_bar_get_pulse_step (GTK_PROGRESS_BAR (priv->progress_widget));
3463
3464 return 0.0;
3465}
3466
3467/**
3468 * gtk_entry_progress_pulse:
3469 * @entry: a `GtkEntry`
3470 *
3471 * Indicates that some progress is made, but you don’t
3472 * know how much.
3473 *
3474 * Causes the entry’s progress indicator to enter “activity
3475 * mode”, where a block bounces back and forth. Each call to
3476 * gtk_entry_progress_pulse() causes the block to move by a
3477 * little bit (the amount of movement per pulse is determined
3478 * by [method@Gtk.Entry.set_progress_pulse_step]).
3479 */
3480void
3481gtk_entry_progress_pulse (GtkEntry *entry)
3482{
3483 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
3484
3485 g_return_if_fail (GTK_IS_ENTRY (entry));
3486
3487 if (priv->progress_widget)
3488 gtk_progress_bar_pulse (GTK_PROGRESS_BAR (priv->progress_widget));
3489}
3490
3491/**
3492 * gtk_entry_set_placeholder_text: (attributes org.gtk.Method.set_property=placeholder-text)
3493 * @entry: a `GtkEntry`
3494 * @text: (nullable): a string to be displayed when @entry is empty and unfocused
3495 *
3496 * Sets text to be displayed in @entry when it is empty.
3497 *
3498 * This can be used to give a visual hint of the expected
3499 * contents of the `GtkEntry`.
3500 */
3501void
3502gtk_entry_set_placeholder_text (GtkEntry *entry,
3503 const char *text)
3504{
3505 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
3506
3507 g_return_if_fail (GTK_IS_ENTRY (entry));
3508
3509 gtk_text_set_placeholder_text (GTK_TEXT (priv->text), text);
3510
3511 gtk_accessible_update_property (self: GTK_ACCESSIBLE (ptr: entry),
3512 first_property: GTK_ACCESSIBLE_PROPERTY_PLACEHOLDER, text,
3513 -1);
3514}
3515
3516/**
3517 * gtk_entry_get_placeholder_text: (attributes org.gtk.Method.get_property=placeholder-text)
3518 * @entry: a `GtkEntry`
3519 *
3520 * Retrieves the text that will be displayed when @entry
3521 * is empty and unfocused
3522 *
3523 * Returns: (nullable) (transfer none):a pointer to the
3524 * placeholder text as a string. This string points to
3525 * internally allocated storage in the widget and must
3526 * not be freed, modified or stored. If no placeholder
3527 * text has been set, %NULL will be returned.
3528 */
3529const char *
3530gtk_entry_get_placeholder_text (GtkEntry *entry)
3531{
3532 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
3533
3534 g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL);
3535
3536 return gtk_text_get_placeholder_text (GTK_TEXT (priv->text));
3537}
3538
3539/**
3540 * gtk_entry_set_input_purpose: (attributes org.gtk.Method.set_property=input-purpose)
3541 * @entry: a `GtkEntry`
3542 * @purpose: the purpose
3543 *
3544 * Sets the input purpose which can be used by input methods
3545 * to adjust their behavior.
3546 */
3547void
3548gtk_entry_set_input_purpose (GtkEntry *entry,
3549 GtkInputPurpose purpose)
3550
3551{
3552 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
3553
3554 g_return_if_fail (GTK_IS_ENTRY (entry));
3555
3556 gtk_text_set_input_purpose (GTK_TEXT (priv->text), purpose);
3557}
3558
3559/**
3560 * gtk_entry_get_input_purpose: (attributes org.gtk.Method.get_property=input-purpose)
3561 * @entry: a `GtkEntry`
3562 *
3563 * Gets the input purpose of the `GtkEntry`.
3564 *
3565 * Returns: the input purpose
3566 */
3567GtkInputPurpose
3568gtk_entry_get_input_purpose (GtkEntry *entry)
3569{
3570 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
3571
3572 g_return_val_if_fail (GTK_IS_ENTRY (entry), GTK_INPUT_PURPOSE_FREE_FORM);
3573
3574 return gtk_text_get_input_purpose (GTK_TEXT (priv->text));
3575}
3576
3577/**
3578 * gtk_entry_set_input_hints: (attributes org.gtk.Method.set_property=input-hints)
3579 * @entry: a `GtkEntry`
3580 * @hints: the hints
3581 *
3582 * Set additional hints which allow input methods to
3583 * fine-tune their behavior.
3584 */
3585void
3586gtk_entry_set_input_hints (GtkEntry *entry,
3587 GtkInputHints hints)
3588
3589{
3590 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
3591
3592 g_return_if_fail (GTK_IS_ENTRY (entry));
3593
3594 gtk_text_set_input_hints (GTK_TEXT (priv->text), hints);
3595}
3596
3597/**
3598 * gtk_entry_get_input_hints: (attributes org.gtk.Method.get_property=input-hints)
3599 * @entry: a `GtkEntry`
3600 *
3601 * Gets the input hints of this `GtkEntry`.
3602 *
3603 * Returns: the input hints
3604 */
3605GtkInputHints
3606gtk_entry_get_input_hints (GtkEntry *entry)
3607{
3608 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
3609
3610 g_return_val_if_fail (GTK_IS_ENTRY (entry), GTK_INPUT_HINT_NONE);
3611
3612 return gtk_text_get_input_hints (GTK_TEXT (priv->text));
3613}
3614
3615/**
3616 * gtk_entry_set_attributes: (attributes org.gtk.Method.set_property=attributes)
3617 * @entry: a `GtkEntry`
3618 * @attrs: a `PangoAttrList`
3619 *
3620 * Sets a `PangoAttrList`.
3621 *
3622 * The attributes in the list are applied to the entry text.
3623 *
3624 * Since the attributes will be applies to text that changes
3625 * as the user types, it makes most sense to use attributes
3626 * with unlimited extent.
3627 */
3628void
3629gtk_entry_set_attributes (GtkEntry *entry,
3630 PangoAttrList *attrs)
3631{
3632 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
3633
3634 g_return_if_fail (GTK_IS_ENTRY (entry));
3635
3636 gtk_text_set_attributes (GTK_TEXT (priv->text), attrs);
3637}
3638
3639/**
3640 * gtk_entry_get_attributes: (attributes org.gtk.Method.get_property=attributes)
3641 * @entry: a `GtkEntry`
3642 *
3643 * Gets the attribute list of the `GtkEntry`.
3644 *
3645 * See [method@Gtk.Entry.set_attributes].
3646 *
3647 * Returns: (transfer none) (nullable): the attribute list
3648 */
3649PangoAttrList *
3650gtk_entry_get_attributes (GtkEntry *entry)
3651{
3652 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
3653
3654 g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL);
3655
3656 return gtk_text_get_attributes (GTK_TEXT (priv->text));
3657}
3658
3659/**
3660 * gtk_entry_set_tabs: (attributes org.gtk.Method.set_property=tabs)
3661 * @entry: a `GtkEntry`
3662 * @tabs: (nullable): a `PangoTabArray`
3663 *
3664 * Sets a `PangoTabArray`.
3665 *
3666 * The tabstops in the array are applied to the entry text.
3667 */
3668
3669void
3670gtk_entry_set_tabs (GtkEntry *entry,
3671 PangoTabArray *tabs)
3672{
3673 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
3674
3675 g_return_if_fail (GTK_IS_ENTRY (entry));
3676
3677 gtk_text_set_tabs (GTK_TEXT (priv->text), tabs);
3678}
3679
3680/**
3681 * gtk_entry_get_tabs: (attributes org.gtk.Method.get_property=tabs)
3682 * @entry: a `GtkEntry`
3683 *
3684 * Gets the tabstops of the `GtkEntry.
3685 *
3686 * See [method@Gtk.Entry.set_tabs].
3687 *
3688 * Returns: (nullable) (transfer none): the tabstops
3689 */
3690
3691PangoTabArray *
3692gtk_entry_get_tabs (GtkEntry *entry)
3693{
3694 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
3695
3696 g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL);
3697
3698 return gtk_text_get_tabs (GTK_TEXT (priv->text));
3699}
3700
3701static void
3702pick_emoji (GtkEntry *entry,
3703 int icon,
3704 GdkEvent *event,
3705 gpointer data)
3706{
3707 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
3708
3709 if (gtk_widget_get_ancestor (GTK_WIDGET (entry), GTK_TYPE_EMOJI_CHOOSER) != NULL)
3710 return;
3711
3712 if (icon == GTK_ENTRY_ICON_SECONDARY)
3713 g_signal_emit_by_name (instance: priv->text, detailed_signal: "insert-emoji");
3714}
3715
3716static void
3717set_show_emoji_icon (GtkEntry *entry,
3718 gboolean value)
3719{
3720 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
3721
3722 if (priv->show_emoji_icon == value)
3723 return;
3724
3725 priv->show_emoji_icon = value;
3726
3727 if (priv->show_emoji_icon)
3728 {
3729 gtk_entry_set_icon_from_icon_name (entry,
3730 icon_pos: GTK_ENTRY_ICON_SECONDARY,
3731 icon_name: "face-smile-symbolic");
3732
3733 gtk_entry_set_icon_sensitive (entry,
3734 icon_pos: GTK_ENTRY_ICON_SECONDARY,
3735 TRUE);
3736
3737 gtk_entry_set_icon_activatable (entry,
3738 icon_pos: GTK_ENTRY_ICON_SECONDARY,
3739 TRUE);
3740
3741 gtk_entry_set_icon_tooltip_text (entry,
3742 icon_pos: GTK_ENTRY_ICON_SECONDARY,
3743 _("Insert Emoji"));
3744
3745 g_signal_connect (entry, "icon-press", G_CALLBACK (pick_emoji), NULL);
3746 }
3747 else
3748 {
3749 g_signal_handlers_disconnect_by_func (entry, pick_emoji, NULL);
3750
3751 gtk_entry_set_icon_from_icon_name (entry,
3752 icon_pos: GTK_ENTRY_ICON_SECONDARY,
3753 NULL);
3754
3755 gtk_entry_set_icon_tooltip_text (entry,
3756 icon_pos: GTK_ENTRY_ICON_SECONDARY,
3757 NULL);
3758 }
3759
3760 g_object_notify_by_pspec (G_OBJECT (entry), pspec: entry_props[PROP_SHOW_EMOJI_ICON]);
3761 gtk_widget_queue_resize (GTK_WIDGET (entry));
3762}
3763
3764GtkEventController *
3765gtk_entry_get_key_controller (GtkEntry *entry)
3766{
3767 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
3768
3769 return gtk_text_get_key_controller (GTK_TEXT (priv->text));
3770}
3771
3772GtkText *
3773gtk_entry_get_text_widget (GtkEntry *entry)
3774{
3775 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
3776
3777 return GTK_TEXT (priv->text);
3778}
3779
3780/**
3781 * gtk_entry_set_extra_menu: (attributes org.gtk.Method.set_property=extra-menu)
3782 * @entry: a `GtkEntry`
3783 * @model: (nullable): a `GMenuModel`
3784 *
3785 * Sets a menu model to add when constructing
3786 * the context menu for @entry.
3787 */
3788void
3789gtk_entry_set_extra_menu (GtkEntry *entry,
3790 GMenuModel *model)
3791{
3792 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
3793
3794 g_return_if_fail (GTK_IS_ENTRY (entry));
3795
3796 gtk_text_set_extra_menu (GTK_TEXT (priv->text), model);
3797
3798 g_object_notify_by_pspec (G_OBJECT (entry), pspec: entry_props[PROP_EXTRA_MENU]);
3799}
3800
3801/**
3802 * gtk_entry_get_extra_menu: (attributes org.gtk.Method.get_property=extra-menu)
3803 * @entry: a `GtkEntry`
3804 *
3805 * Gets the menu model set with gtk_entry_set_extra_menu().
3806 *
3807 * Returns: (transfer none) (nullable): the menu model
3808 */
3809GMenuModel *
3810gtk_entry_get_extra_menu (GtkEntry *entry)
3811{
3812 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
3813
3814 g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL);
3815
3816 return gtk_text_get_extra_menu (GTK_TEXT (priv->text));
3817}
3818
3819/*< private >
3820 * gtk_entry_activate_icon:
3821 * @entry: a `GtkEntry`
3822 * @pos: the icon position
3823 *
3824 * Activates an icon.
3825 *
3826 * This causes the [signal@Gtk.Entry::icon-press] and
3827 * [signal@Gtk.Entry::icon-release] signals to be emitted
3828 * on the @entry icon at the given @pos, if the icon is
3829 * set and activatable.
3830 *
3831 * Returns: %TRUE if the signal was emitted
3832 */
3833gboolean
3834gtk_entry_activate_icon (GtkEntry *entry,
3835 GtkEntryIconPosition pos)
3836{
3837 GtkEntryPrivate *priv = gtk_entry_get_instance_private (self: entry);
3838 EntryIconInfo *icon_info;
3839
3840 g_return_val_if_fail (GTK_IS_ENTRY (entry), FALSE);
3841
3842 icon_info = priv->icons[pos];
3843
3844 if (icon_info != NULL &&
3845 gtk_image_get_storage_type (GTK_IMAGE (icon_info->widget)) != GTK_IMAGE_EMPTY &&
3846 !icon_info->nonactivatable)
3847 {
3848 g_signal_emit (instance: entry, signal_id: signals[ICON_PRESS], detail: 0, pos);
3849 g_signal_emit (instance: entry, signal_id: signals[ICON_RELEASE], detail: 0, pos);
3850 return TRUE;
3851 }
3852
3853 return FALSE;
3854}
3855

source code of gtk/gtk/gtkentry.c