summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/reference/gtk/gtk3-sections.txt2
-rw-r--r--gtk/gtk.symbols2
-rw-r--r--gtk/gtkcssprovider.c1
-rw-r--r--gtk/gtkentry.c156
-rw-r--r--gtk/gtkentry.h4
5 files changed, 155 insertions, 10 deletions
diff --git a/docs/reference/gtk/gtk3-sections.txt b/docs/reference/gtk/gtk3-sections.txt
index 5336a3f69a..024645afd3 100644
--- a/docs/reference/gtk/gtk3-sections.txt
+++ b/docs/reference/gtk/gtk3-sections.txt
@@ -1028,6 +1028,8 @@ gtk_entry_set_width_chars
gtk_entry_get_invisible_char
gtk_entry_set_alignment
gtk_entry_get_alignment
+gtk_entry_set_placeholder_text
+gtk_entry_get_placeholder_text
gtk_entry_set_overwrite_mode
gtk_entry_get_overwrite_mode
gtk_entry_get_layout
diff --git a/gtk/gtk.symbols b/gtk/gtk.symbols
index 31ecfc429a..39485e0687 100644
--- a/gtk/gtk.symbols
+++ b/gtk/gtk.symbols
@@ -828,6 +828,7 @@ gtk_entry_get_completion
gtk_entry_get_current_icon_drag_source
gtk_entry_get_cursor_hadjustment
gtk_entry_get_has_frame
+gtk_entry_get_placeholder_text
gtk_entry_get_icon_activatable
gtk_entry_get_icon_area
gtk_entry_get_icon_at_pos
@@ -866,6 +867,7 @@ gtk_entry_set_buffer
gtk_entry_set_completion
gtk_entry_set_cursor_hadjustment
gtk_entry_set_has_frame
+gtk_entry_set_placeholder_text
gtk_entry_set_icon_activatable
gtk_entry_set_icon_drag_source
gtk_entry_set_icon_from_gicon
diff --git a/gtk/gtkcssprovider.c b/gtk/gtkcssprovider.c
index 51cec89e97..9557a33bf0 100644
--- a/gtk/gtkcssprovider.c
+++ b/gtk/gtkcssprovider.c
@@ -3772,6 +3772,7 @@ gtk_css_provider_get_default (void)
"@define-color selected_fg_color #fff; \n"
"@define-color tooltip_bg_color #eee1b3; \n"
"@define-color tooltip_fg_color #000; \n"
+ "@define-color placeholder_text_color #808080; \n"
"\n"
"@define-color info_fg_color rgb (181, 171, 156);\n"
"@define-color info_bg_color rgb (252, 252, 189);\n"
diff --git a/gtk/gtkentry.c b/gtk/gtkentry.c
index 84f7204470..6dda7ecbf5 100644
--- a/gtk/gtkentry.c
+++ b/gtk/gtkentry.c
@@ -155,6 +155,8 @@ struct _GtkEntryPrivate
gdouble progress_pulse_fraction;
gdouble progress_pulse_current;
+ gchar *placeholder_text;
+
gfloat xalign;
gint ascent; /* font ascent in pango units */
@@ -306,7 +308,8 @@ enum {
PROP_TOOLTIP_MARKUP_PRIMARY,
PROP_TOOLTIP_MARKUP_SECONDARY,
PROP_IM_MODULE,
- PROP_EDITING_CANCELED
+ PROP_EDITING_CANCELED,
+ PROP_PLACEHOLDER_TEXT
};
static guint signals[LAST_SIGNAL] = { 0 };
@@ -596,7 +599,6 @@ static void begin_change (GtkEntry *entry);
static void end_change (GtkEntry *entry);
static void emit_changed (GtkEntry *entry);
-
static void buffer_inserted_text (GtkEntryBuffer *buffer,
guint position,
const gchar *chars,
@@ -619,7 +621,6 @@ static void buffer_connect_signals (GtkEntry *entry);
static void buffer_disconnect_signals (GtkEntry *entry);
static GtkEntryBuffer *get_buffer (GtkEntry *entry);
-
G_DEFINE_TYPE_WITH_CODE (GtkEntry, gtk_entry, GTK_TYPE_WIDGET,
G_IMPLEMENT_INTERFACE (GTK_TYPE_EDITABLE,
gtk_entry_editable_init)
@@ -983,6 +984,21 @@ gtk_entry_class_init (GtkEntryClass *class)
GTK_PARAM_READWRITE));
/**
+ * GtkEntry:placeholder-text:
+ *
+ * The text that will be displayed in the #GtkEntry when it is empty and unfocused.
+ *
+ * Since: 3.2
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_PLACEHOLDER_TEXT,
+ g_param_spec_string ("placeholder-text",
+ P_("Placeholder text"),
+ P_("Show text in the entry when it's empty and unfocused"),
+ NULL,
+ GTK_PARAM_READWRITE));
+
+ /**
* GtkEntry:primary-icon-pixbuf:
*
* A pixbuf to use as the primary icon for the entry.
@@ -1967,6 +1983,10 @@ gtk_entry_set_property (GObject *object,
gtk_entry_set_progress_pulse_step (entry, g_value_get_double (value));
break;
+ case PROP_PLACEHOLDER_TEXT:
+ gtk_entry_set_placeholder_text (entry, g_value_get_string (value));
+ break;
+
case PROP_PIXBUF_PRIMARY:
gtk_entry_set_icon_from_pixbuf (entry,
GTK_ENTRY_ICON_PRIMARY,
@@ -2185,6 +2205,10 @@ gtk_entry_get_property (GObject *object,
g_value_set_double (value, priv->progress_pulse_fraction);
break;
+ case PROP_PLACEHOLDER_TEXT:
+ g_value_set_string (value, gtk_entry_get_placeholder_text (entry));
+ break;
+
case PROP_PIXBUF_PRIMARY:
g_value_set_object (value,
gtk_entry_get_icon_pixbuf (entry,
@@ -2581,6 +2605,7 @@ gtk_entry_finalize (GObject *object)
if (priv->recompute_idle)
g_source_remove (priv->recompute_idle);
+ g_free (priv->placeholder_text);
g_free (priv->im_module);
G_OBJECT_CLASS (gtk_entry_parent_class)->finalize (object);
@@ -2667,7 +2692,6 @@ gtk_entry_get_display_text (GtkEntry *entry,
return g_string_free (str, FALSE);
}
-
}
static void
@@ -4191,8 +4215,16 @@ gtk_entry_focus_in (GtkWidget *widget,
g_signal_connect (keymap, "direction-changed",
G_CALLBACK (keymap_direction_changed), entry);
- gtk_entry_reset_blink_time (entry);
- gtk_entry_check_cursor_blink (entry);
+ if (gtk_entry_buffer_get_bytes (get_buffer (entry)) == 0 &&
+ priv->placeholder_text != NULL)
+ {
+ gtk_entry_recompute (entry);
+ }
+ else
+ {
+ gtk_entry_reset_blink_time (entry);
+ gtk_entry_check_cursor_blink (entry);
+ }
return FALSE;
}
@@ -4217,8 +4249,16 @@ gtk_entry_focus_out (GtkWidget *widget,
remove_capslock_feedback (entry);
}
- gtk_entry_check_cursor_blink (entry);
-
+ if (gtk_entry_buffer_get_bytes (get_buffer (entry)) == 0 &&
+ priv->placeholder_text != NULL)
+ {
+ gtk_entry_recompute (entry);
+ }
+ else
+ {
+ gtk_entry_check_cursor_blink (entry);
+ }
+
g_signal_handlers_disconnect_by_func (keymap, keymap_state_changed, entry);
g_signal_handlers_disconnect_by_func (keymap, keymap_direction_changed, entry);
@@ -5394,6 +5434,35 @@ gtk_entry_recompute (GtkEntry *entry)
}
}
+static void
+gtk_entry_get_placeholder_text_color (GtkEntry *entry,
+ PangoColor *color)
+{
+ GtkWidget *widget = GTK_WIDGET (entry);
+ GtkStyleContext *context;
+ GdkRGBA fg = { 0.5, 0.5, 0.5 };
+
+ context = gtk_widget_get_style_context (widget);
+ gtk_style_context_lookup_color (context, "placeholder_text_color", &fg);
+
+ color->red = CLAMP (fg.red * 65535. + 0.5, 0, 65535);
+ color->green = CLAMP (fg.green * 65535. + 0.5, 0, 65535);
+ color->blue = CLAMP (fg.blue * 65535. + 0.5, 0, 65535);
+}
+
+static inline gboolean
+show_placeholder_text (GtkEntry *entry)
+{
+ GtkEntryPrivate *priv = entry->priv;
+
+ if (!gtk_widget_has_focus (GTK_WIDGET (entry)) &&
+ gtk_entry_buffer_get_bytes (get_buffer (entry)) == 0 &&
+ priv->placeholder_text != NULL)
+ return TRUE;
+
+ return FALSE;
+}
+
static PangoLayout *
gtk_entry_create_layout (GtkEntry *entry,
gboolean include_preedit)
@@ -5402,6 +5471,7 @@ gtk_entry_create_layout (GtkEntry *entry,
GtkWidget *widget = GTK_WIDGET (entry);
PangoLayout *layout = gtk_widget_create_pango_layout (widget, NULL);
PangoAttrList *tmp_attrs = pango_attr_list_new ();
+ gboolean placeholder_layout = show_placeholder_text (entry);
gchar *preedit_string = NULL;
gint preedit_length = 0;
@@ -5412,15 +5482,26 @@ gtk_entry_create_layout (GtkEntry *entry,
pango_layout_set_single_paragraph_mode (layout, TRUE);
- display = gtk_entry_get_display_text (entry, 0, -1);
+ display = placeholder_layout ? g_strdup (priv->placeholder_text) : gtk_entry_get_display_text (entry, 0, -1);
n_bytes = strlen (display);
- if (include_preedit)
+ if (!placeholder_layout && include_preedit)
{
gtk_im_context_get_preedit_string (priv->im_context,
&preedit_string, &preedit_attrs, NULL);
preedit_length = priv->preedit_length;
}
+ else if (placeholder_layout)
+ {
+ PangoColor color;
+ PangoAttribute *attr;
+
+ gtk_entry_get_placeholder_text_color (entry, &color);
+ attr = pango_attr_foreground_new (color.red, color.green, color.blue);
+ attr->start_index = 0;
+ attr->end_index = G_MAXINT;
+ pango_attr_list_insert (tmp_attrs, attr);
+ }
if (preedit_length)
{
@@ -10132,6 +10213,61 @@ gtk_entry_progress_pulse (GtkEntry *entry)
gtk_widget_queue_draw (GTK_WIDGET (entry));
}
+/**
+ * gtk_entry_set_placeholder_text:
+ * @entry: a #GtkEntry
+ * @text: a string to be displayed when @entry is empty an unfocused, or %NULL
+ *
+ * Sets text to be displayed in @entry when
+ * it is empty and unfocused. This can be used to give a visual hint
+ * of the expected contents of the #GtkEntry.
+ *
+ * Since: 3.2
+ **/
+void
+gtk_entry_set_placeholder_text (GtkEntry *entry,
+ const gchar *text)
+{
+ GtkEntryPrivate *priv;
+
+ g_return_if_fail (GTK_IS_ENTRY (entry));
+
+ priv = entry->priv;
+
+ if (g_strcmp0 (priv->placeholder_text, text) == 0)
+ return;
+
+ g_free (priv->placeholder_text);
+ priv->placeholder_text = g_strdup (text);
+
+ gtk_entry_recompute (entry);
+
+ g_object_notify (G_OBJECT (entry), "placeholder-text");
+}
+
+/**
+ * gtk_entry_get_placeholder_text:
+ * @entry: a #GtkEntry
+ *
+ * Retrieves the text that will be displayed when @entry is empty and unfocused
+ *
+ * Returns: a pointer to the placeholder text as a string. This string points to internally allocated
+ * storage in the widget and must not be freed, modified or stored.
+ *
+ * Since: 3.2
+ **/
+G_CONST_RETURN gchar *
+gtk_entry_get_placeholder_text (GtkEntry *entry)
+{
+ GtkEntryPrivate *priv;
+
+ g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL);
+
+ priv = entry->priv;
+
+ return priv->placeholder_text;
+}
+
/* Caps Lock warning for password entries */
static void
diff --git a/gtk/gtkentry.h b/gtk/gtkentry.h
index 3bd37d35f7..2bca501592 100644
--- a/gtk/gtkentry.h
+++ b/gtk/gtkentry.h
@@ -213,6 +213,10 @@ gdouble gtk_entry_get_progress_pulse_step (GtkEntry *entry);
void gtk_entry_progress_pulse (GtkEntry *entry);
+G_CONST_RETURN gchar* gtk_entry_get_placeholder_text (GtkEntry *entry);
+
+void gtk_entry_set_placeholder_text (GtkEntry *entry,
+ const gchar *text);
/* Setting and managing icons
*/
void gtk_entry_set_icon_from_pixbuf (GtkEntry *entry,