]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkentry.c
Updated Norwegian bokmål translation
[~andy/gtk] / gtk / gtkentry.c
index 38dbe9d1a7a9eda1f5146c91fe8efd14841b89fa..ebae2c0cbdd2356145812c5a375901ebffe9e031 100644 (file)
@@ -66,7 +66,7 @@
 #include "gtkiconfactory.h"
 #include "gtkicontheme.h"
 #include "gtkwidgetprivate.h"
-
+#include "gtkstylecontextprivate.h"
 
 /**
  * SECTION:gtkentry
@@ -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,9 @@ enum {
   PROP_TOOLTIP_MARKUP_PRIMARY,
   PROP_TOOLTIP_MARKUP_SECONDARY,
   PROP_IM_MODULE,
-  PROP_EDITING_CANCELED
+  PROP_EDITING_CANCELED,
+  PROP_PLACEHOLDER_TEXT,
+  PROP_COMPLETION
 };
 
 static guint signals[LAST_SIGNAL] = { 0 };
@@ -515,7 +519,6 @@ static void         gtk_entry_draw_cursor              (GtkEntry       *entry,
 static PangoLayout *gtk_entry_ensure_layout            (GtkEntry       *entry,
                                                         gboolean        include_preedit);
 static void         gtk_entry_reset_layout             (GtkEntry       *entry);
-static void         gtk_entry_queue_draw               (GtkEntry       *entry);
 static void         gtk_entry_recompute                (GtkEntry       *entry);
 static gint         gtk_entry_find_position            (GtkEntry       *entry,
                                                        gint            x);
@@ -560,6 +563,7 @@ static void         get_text_area_size                 (GtkEntry       *entry,
                                                        gint           *width,
                                                        gint           *height);
 static void         get_frame_size                     (GtkEntry       *entry,
+                                                        gboolean        relative_to_window,
                                                        gint           *x,
                                                        gint           *y,
                                                        gint           *width,
@@ -567,7 +571,7 @@ static void         get_frame_size                     (GtkEntry       *entry,
 static void         gtk_entry_move_adjustments         (GtkEntry             *entry);
 static void         gtk_entry_ensure_pixbuf            (GtkEntry             *entry,
                                                         GtkEntryIconPosition  icon_pos);
-
+static void         gtk_entry_update_cached_style_values(GtkEntry      *entry);
 
 /* Completion */
 static gint         gtk_entry_completion_timeout       (gpointer            data);
@@ -597,7 +601,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,
@@ -620,7 +623,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)
@@ -984,6 +986,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.
@@ -1314,6 +1331,21 @@ gtk_entry_class_init (GtkEntryClass *class)
                                                         NULL,
                                                         GTK_PARAM_READWRITE));
 
+  /**
+   * GtkEntry:completion:
+   *
+   * The auxiliary completion object to use with the entry.
+   *
+   * Since: 3.2
+   */     
+  g_object_class_install_property (gobject_class,
+                                   PROP_COMPLETION,
+                                   g_param_spec_object ("completion",
+                                                        P_("Completion"),
+                                                        P_("The auxiliary completion object"),
+                                                        GTK_TYPE_ENTRY_COMPLETION,
+                                                        GTK_PARAM_READWRITE));
+
   /**
    * GtkEntry:icon-prelight:
    *
@@ -1604,7 +1636,7 @@ gtk_entry_class_init (GtkEntryClass *class)
    * GtkEntry::icon-press:
    * @entry: The entry on which the signal is emitted
    * @icon_pos: The position of the clicked icon
-   * @event: the button press event
+   * @event: (type Gdk.EventButton): the button press event
    *
    * The ::icon-press signal is emitted when an activatable icon
    * is clicked.
@@ -1626,7 +1658,7 @@ gtk_entry_class_init (GtkEntryClass *class)
    * GtkEntry::icon-release:
    * @entry: The entry on which the signal is emitted
    * @icon_pos: The position of the clicked icon
-   * @event: the button release event
+   * @event: (type Gdk.EventButton): the button release event
    *
    * The ::icon-release signal is emitted on the button release from a
    * mouse click over an activatable icon.
@@ -1866,7 +1898,6 @@ gtk_entry_set_property (GObject         *object,
 {
   GtkEntry *entry = GTK_ENTRY (object);
   GtkEntryPrivate *priv = entry->priv;
-  GtkWidget *widget;
 
   switch (prop_id)
     {
@@ -1880,7 +1911,8 @@ gtk_entry_set_property (GObject         *object,
 
         if (new_value != priv->editable)
          {
-            widget = GTK_WIDGET (entry);
+            GtkWidget *widget = GTK_WIDGET (entry);
+
            if (!new_value)
              {
                _gtk_entry_reset_im_context (entry);
@@ -1896,7 +1928,7 @@ gtk_entry_set_property (GObject         *object,
            if (new_value && gtk_widget_has_focus (widget))
              gtk_im_context_focus_in (priv->im_context);
 
-           gtk_entry_queue_draw (entry);
+           gtk_widget_queue_draw (widget);
          }
       }
       break;
@@ -1968,6 +2000,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,
@@ -2075,6 +2111,10 @@ gtk_entry_set_property (GObject         *object,
       priv->editing_canceled = g_value_get_boolean (value);
       break;
 
+    case PROP_COMPLETION:
+      gtk_entry_set_completion (entry, GTK_ENTRY_COMPLETION (g_value_get_object (value)));
+      break;
+
     case PROP_SCROLL_OFFSET:
     case PROP_CURSOR_POSITION:
     default:
@@ -2186,6 +2226,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,
@@ -2291,6 +2335,10 @@ gtk_entry_get_property (GObject         *object,
                            priv->editing_canceled);
       break;
 
+    case PROP_COMPLETION:
+      g_value_set_object (value, G_OBJECT (gtk_entry_get_completion (entry)));
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -2361,7 +2409,6 @@ gtk_entry_init (GtkEntry *entry)
 
   priv->editable = TRUE;
   priv->visible = TRUE;
-  priv->invisible_char = find_invisible_char (GTK_WIDGET (entry));
   priv->dnd_position = -1;
   priv->width_chars = -1;
   priv->is_cell_renderer = FALSE;
@@ -2397,6 +2444,8 @@ gtk_entry_init (GtkEntry *entry)
 
   context = gtk_widget_get_style_context (GTK_WIDGET (entry));
   gtk_style_context_add_class (context, GTK_STYLE_CLASS_ENTRY);
+
+  gtk_entry_update_cached_style_values (entry);
 }
 
 static gint
@@ -2530,6 +2579,7 @@ gtk_entry_dispose (GObject *object)
 {
   GtkEntry *entry = GTK_ENTRY (object);
   GtkEntryPrivate *priv = entry->priv;
+  GdkKeymap *keymap;
 
   gtk_entry_set_icon_from_pixbuf (entry, GTK_ENTRY_ICON_PRIMARY, NULL);
   gtk_entry_set_icon_tooltip_markup (entry, GTK_ENTRY_ICON_PRIMARY, NULL);
@@ -2543,6 +2593,9 @@ gtk_entry_dispose (GObject *object)
       priv->buffer = NULL;
     }
 
+  keymap = gdk_keymap_get_for_display (gtk_widget_get_display (GTK_WIDGET (object)));
+  g_signal_handlers_disconnect_by_func (keymap, keymap_state_changed, entry);
+  g_signal_handlers_disconnect_by_func (keymap, keymap_direction_changed, entry);
   G_OBJECT_CLASS (gtk_entry_parent_class)->dispose (object);
 }
 
@@ -2582,6 +2635,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);
@@ -2668,7 +2722,6 @@ gtk_entry_get_display_text (GtkEntry *entry,
 
       return g_string_free (str, FALSE);
     }
-
 }
 
 static void
@@ -2847,7 +2900,7 @@ gtk_entry_realize (GtkWidget *widget)
 
   get_text_area_size (entry, &attributes.x, &attributes.y, &attributes.width, &attributes.height);
 
-  get_frame_size (entry, &frame_x, &frame_y, NULL, NULL);
+  get_frame_size (entry, TRUE, &frame_x, &frame_y, NULL, NULL);
   attributes.x += frame_x;
   attributes.y += frame_y;
 
@@ -3068,7 +3121,7 @@ place_windows (GtkEntry *entry)
   GtkAllocation secondary;
   EntryIconInfo *icon_info = NULL;
 
-  get_frame_size (entry, &frame_x, &frame_y, NULL, NULL);
+  get_frame_size (entry, TRUE, &frame_x, &frame_y, NULL, NULL);
   get_text_area_size (entry, &x, &y, &width, &height);
   get_icon_allocations (entry, &primary, &secondary);
 
@@ -3120,7 +3173,7 @@ gtk_entry_get_text_area_size (GtkEntry *entry,
   _gtk_entry_get_borders (entry, &xborder, &yborder);
 
   if (gtk_widget_get_realized (widget))
-    get_frame_size (entry, NULL, NULL, NULL, &frame_height);
+    get_frame_size (entry, TRUE, NULL, NULL, NULL, &frame_height);
   else
     frame_height = requisition.height;
 
@@ -3160,6 +3213,7 @@ get_text_area_size (GtkEntry *entry,
 
 static void
 get_frame_size (GtkEntry *entry,
+                gboolean  relative_to_window,
                 gint     *x,
                 gint     *y,
                 gint     *width,
@@ -3174,14 +3228,17 @@ get_frame_size (GtkEntry *entry,
   gtk_widget_get_allocation (widget, &allocation);
 
   if (x)
-    *x = allocation.x;
+    *x = relative_to_window ? allocation.x : 0;
 
   if (y)
     {
       if (priv->is_cell_renderer)
-       *y = allocation.y;
+       *y = 0;
       else
-       *y = allocation.y + (allocation.height - requisition.height) / 2;
+       *y = (allocation.height - requisition.height) / 2;
+
+      if (relative_to_window)
+        *y += allocation.y;
     }
 
   if (width)
@@ -3348,15 +3405,13 @@ gtk_entry_draw_frame (GtkWidget       *widget,
   GtkEntry *entry = GTK_ENTRY (widget);
   GtkEntryPrivate *priv = entry->priv;
   gint x = 0, y = 0, width, height;
-  GtkAllocation allocation;
   gint frame_x, frame_y;
 
   cairo_save (cr);
 
-  get_frame_size (GTK_ENTRY (widget), &frame_x, &frame_y, &width, &height);
-  gtk_widget_get_allocation (widget, &allocation);
+  get_frame_size (GTK_ENTRY (widget), FALSE, &frame_x, &frame_y, &width, &height);
 
-  cairo_translate (cr, frame_x - allocation.x, frame_y - allocation.y);
+  cairo_translate (cr, frame_x, frame_y);
 
   /* Fix a problem with some themes which assume that entry->text_area's
    * width equals widget->window's width
@@ -3504,44 +3559,41 @@ gtk_entry_draw (GtkWidget *widget,
   gtk_style_context_save (context);
   gtk_style_context_set_state (context, state);
 
-  if (gtk_cairo_should_draw_window (cr, gtk_widget_get_window (widget)))
-    {
-      /* Draw entry_bg, shadow, progress and focus */
-      gtk_entry_draw_frame (widget, context, cr);
+  /* Draw entry_bg, shadow, progress and focus */
+  gtk_entry_draw_frame (widget, context, cr);
 
-      /* Draw text and cursor */
-      cairo_save (cr);
+  /* Draw text and cursor */
+  cairo_save (cr);
 
-      gtk_cairo_transform_to_window (cr, widget, priv->text_area);
+  gtk_cairo_transform_to_window (cr, widget, priv->text_area);
 
-      if (priv->dnd_position != -1)
-       gtk_entry_draw_cursor (GTK_ENTRY (widget), cr, CURSOR_DND);
-      
-      gtk_entry_draw_text (GTK_ENTRY (widget), cr);
+  if (priv->dnd_position != -1)
+    gtk_entry_draw_cursor (GTK_ENTRY (widget), cr, CURSOR_DND);
+  
+  gtk_entry_draw_text (GTK_ENTRY (widget), cr);
 
-      /* When no text is being displayed at all, don't show the cursor */
-      if (gtk_entry_get_display_mode (entry) != DISPLAY_BLANK &&
-         gtk_widget_has_focus (widget) &&
-         priv->selection_bound == priv->current_pos && priv->cursor_visible)
-        gtk_entry_draw_cursor (GTK_ENTRY (widget), cr, CURSOR_STANDARD);
+  /* When no text is being displayed at all, don't show the cursor */
+  if (gtk_entry_get_display_mode (entry) != DISPLAY_BLANK &&
+      gtk_widget_has_focus (widget) &&
+      priv->selection_bound == priv->current_pos && priv->cursor_visible)
+    gtk_entry_draw_cursor (GTK_ENTRY (widget), cr, CURSOR_STANDARD);
 
-      cairo_restore (cr);
+  cairo_restore (cr);
 
-      /* Draw icons */
-      for (i = 0; i < MAX_ICONS; i++)
-        {
-          EntryIconInfo *icon_info = priv->icons[i];
+  /* Draw icons */
+  for (i = 0; i < MAX_ICONS; i++)
+    {
+      EntryIconInfo *icon_info = priv->icons[i];
 
-          if (icon_info != NULL)
-            {
-              cairo_save (cr);
+      if (icon_info != NULL)
+        {
+          cairo_save (cr);
 
-              gtk_cairo_transform_to_window (cr, widget, icon_info->window);
+          gtk_cairo_transform_to_window (cr, widget, icon_info->window);
 
-              draw_icon (widget, cr, i);
+          draw_icon (widget, cr, i);
 
-              cairo_restore (cr);
-            }
+          cairo_restore (cr);
         }
     }
 
@@ -4192,8 +4244,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;
 }
@@ -4218,25 +4278,33 @@ 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);
 
   completion = gtk_entry_get_completion (entry);
   if (completion)
     _gtk_entry_completion_popdown (completion);
-  
+
   return FALSE;
 }
 
 static void
-gtk_entry_grab_focus (GtkWidget        *widget)
+gtk_entry_grab_focus (GtkWidget *widget)
 {
   GtkEntry *entry = GTK_ENTRY (widget);
   GtkEntryPrivate *priv = entry->priv;
   gboolean select_on_focus;
-  
+
   GTK_WIDGET_CLASS (gtk_entry_parent_class)->grab_focus (widget);
 
   if (priv->editable && !priv->in_click)
@@ -4245,20 +4313,20 @@ gtk_entry_grab_focus (GtkWidget        *widget)
                     "gtk-entry-select-on-focus",
                     &select_on_focus,
                     NULL);
-  
+
       if (select_on_focus)
         gtk_editable_select_region (GTK_EDITABLE (widget), 0, -1);
     }
 }
 
-static void 
+static void
 gtk_entry_direction_changed (GtkWidget        *widget,
-                            GtkTextDirection  previous_dir)
+                             GtkTextDirection  previous_dir)
 {
   GtkEntry *entry = GTK_ENTRY (widget);
 
   gtk_entry_recompute (entry);
-      
+
   GTK_WIDGET_CLASS (gtk_entry_parent_class)->direction_changed (widget, previous_dir);
 }
 
@@ -4269,12 +4337,12 @@ gtk_entry_state_flags_changed (GtkWidget     *widget,
   GtkEntry *entry = GTK_ENTRY (widget);
   GtkEntryPrivate *priv = entry->priv;
   GdkCursor *cursor;
-  
+
   if (gtk_widget_get_realized (widget))
     {
       if (gtk_widget_is_sensitive (widget))
         cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget), GDK_XTERM);
-      else 
+      else
         cursor = NULL;
 
       gdk_window_set_cursor (priv->text_area, cursor);
@@ -4292,8 +4360,8 @@ gtk_entry_state_flags_changed (GtkWidget     *widget,
       /* Clear any selection */
       gtk_editable_select_region (GTK_EDITABLE (entry), priv->current_pos, priv->current_pos);
     }
-  
-  gtk_widget_queue_draw (widget);
+
+  gtk_entry_update_cached_style_values (entry);
 }
 
 static void
@@ -4461,24 +4529,40 @@ icon_margin_changed (GtkEntry *entry)
   priv->icon_margin = border.left;
 }
 
-static void 
-gtk_entry_style_updated (GtkWidget *widget)
+static void
+gtk_entry_update_cached_style_values (GtkEntry *entry)
 {
-  GtkEntry *entry = GTK_ENTRY (widget);
   GtkEntryPrivate *priv = entry->priv;
   gint focus_width;
   gboolean interior_focus;
 
-  gtk_widget_style_get (widget,
+  gtk_widget_style_get (GTK_WIDGET (entry),
                        "focus-line-width", &focus_width,
                        "interior-focus", &interior_focus,
                        NULL);
-
   priv->focus_width = focus_width;
   priv->interior_focus = interior_focus;
 
   if (!priv->invisible_char_set)
-    priv->invisible_char = find_invisible_char (GTK_WIDGET (entry));
+    {
+      gunichar ch = find_invisible_char (GTK_WIDGET (entry));
+
+      if (priv->invisible_char != ch)
+        {
+          priv->invisible_char = ch;
+          g_object_notify (G_OBJECT (entry), "invisible-char");
+        }
+    }
+}
+
+static void 
+gtk_entry_style_updated (GtkWidget *widget)
+{
+  GtkEntry *entry = GTK_ENTRY (widget);
+
+  GTK_WIDGET_CLASS (gtk_entry_parent_class)->style_updated (widget);
+
+  gtk_entry_update_cached_style_values (entry);
 
   gtk_entry_recompute (entry);
 
@@ -5105,7 +5189,7 @@ gtk_entry_paste_clipboard (GtkEntry *entry)
   GtkEntryPrivate *priv = entry->priv;
 
   if (priv->editable)
-    gtk_entry_paste (entry, GDK_NONE);
+    gtk_entry_paste (entry, GDK_SELECTION_CLIPBOARD);
   else
     gtk_widget_error_bell (GTK_WIDGET (entry));
 }
@@ -5370,8 +5454,8 @@ recompute_idle_func (gpointer data)
   if (gtk_widget_has_screen (GTK_WIDGET (entry)))
     {
       gtk_entry_adjust_scroll (entry);
-      gtk_entry_queue_draw (entry);
-      
+      gtk_widget_queue_draw (GTK_WIDGET (entry));
+
       update_im_cursor_location (entry);
     }
 
@@ -5393,6 +5477,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)
@@ -5401,6 +5514,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;
@@ -5411,15 +5525,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)
     {
@@ -5623,7 +5748,6 @@ gtk_entry_draw_text (GtkEntry *entry,
   GtkStateFlags state = 0;
   GdkRGBA text_color, bar_text_color;
   GtkStyleContext *context;
-  gint pos_x, pos_y;
   gint width, height;
   gint progress_x, progress_y, progress_width, progress_height;
   gint clip_width, clip_height;
@@ -5647,6 +5771,8 @@ gtk_entry_draw_text (GtkEntry *entry,
                      &progress_x, &progress_y,
                      &progress_width, &progress_height);
 
+  cairo_save (cr);
+
   clip_width = gdk_window_get_width (priv->text_area);
   clip_height = gdk_window_get_height (priv->text_area);
   cairo_rectangle (cr, 0, 0, clip_width, clip_height);
@@ -5661,21 +5787,22 @@ gtk_entry_draw_text (GtkEntry *entry,
     }
   else
     {
+      int frame_x, frame_y, area_x, area_y;
+
       width = gdk_window_get_width (priv->text_area);
       height = gdk_window_get_height (priv->text_area);
 
       cairo_save (cr);
 
-      cairo_rectangle (cr, 0, 0, width, height);
-      cairo_clip (cr);
-      cairo_save (cr);
-
       cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
       cairo_rectangle (cr, 0, 0, width, height);
 
-      gdk_window_get_position (priv->text_area, &pos_x, &pos_y);
-      progress_x -= pos_x;
-      progress_y -= pos_y;
+      /* progres area is frame-relative, we need it text-area window
+       * relative */
+      get_frame_size (entry, TRUE, &frame_x, &frame_y, NULL, NULL);
+      gdk_window_get_position (priv->text_area, &area_x, &area_y);
+      progress_x += frame_x - area_x;
+      progress_y += frame_y - area_y;
 
       cairo_rectangle (cr, progress_x, progress_y,
                        progress_width, progress_height);
@@ -5685,6 +5812,8 @@ gtk_entry_draw_text (GtkEntry *entry,
       draw_text_with_color (entry, cr, &text_color);
       cairo_restore (cr);
 
+      cairo_save (cr);
+
       cairo_rectangle (cr, progress_x, progress_y,
                        progress_width, progress_height);
       cairo_clip (cr);
@@ -5693,6 +5822,8 @@ gtk_entry_draw_text (GtkEntry *entry,
 
       cairo_restore (cr);
     }
+
+  cairo_restore (cr);
 }
 
 static void
@@ -5805,7 +5936,8 @@ gtk_entry_draw_cursor (GtkEntry  *entry,
     }
   else /* overwrite_mode */
     {
-      GdkColor cursor_color;
+      GtkStyleContext *context;
+      GdkRGBA cursor_color;
       GdkRectangle rect;
       gint x, y;
 
@@ -5818,18 +5950,18 @@ gtk_entry_draw_cursor (GtkEntry  *entry,
       rect.width = PANGO_PIXELS (cursor_rect.width);
       rect.height = PANGO_PIXELS (cursor_rect.height);
 
-      _gtk_widget_get_cursor_color (widget, &cursor_color);
-      gdk_cairo_set_source_color (cr, &cursor_color);
+      context = gtk_widget_get_style_context (widget);
+
+      _gtk_style_context_get_cursor_color (context, &cursor_color, NULL);
+      gdk_cairo_set_source_rgba (cr, &cursor_color);
       gdk_cairo_rectangle (cr, &rect);
       cairo_fill (cr);
 
       if (!block_at_line_end)
         {
-          GtkStyleContext *context;
           GtkStateFlags state;
           GdkRGBA color;
 
-          context = gtk_widget_get_style_context (widget);
           state = gtk_widget_get_state_flags (widget);
           gtk_style_context_get_background_color (context, state, &color);
 
@@ -5844,14 +5976,6 @@ gtk_entry_draw_cursor (GtkEntry  *entry,
     }
 }
 
-static void
-gtk_entry_queue_draw (GtkEntry *entry)
-{
-  if (gtk_widget_is_drawable (GTK_WIDGET (entry)))
-    gdk_window_invalidate_rect (gtk_widget_get_window (GTK_WIDGET (entry)),
-                                NULL, FALSE);
-}
-
 void
 _gtk_entry_reset_im_context (GtkEntry *entry)
 {
@@ -5886,7 +6010,7 @@ gtk_entry_reset_im_context (GtkEntry *entry)
 /**
  * gtk_entry_im_context_filter_keypress:
  * @entry: a #GtkEntry
- * @event: the key event
+ * @event: (type Gdk.EventKey): the key event
  *
  * Allow the #GtkEntry input method to internally handle key press
  * and release events. If this function returns %TRUE, then no further
@@ -6576,16 +6700,37 @@ gtk_entry_clear (GtkEntry             *entry,
   g_object_thaw_notify (G_OBJECT (entry));
 }
 
+static GdkPixbuf *
+create_normal_pixbuf (GtkStyleContext *context,
+                      const gchar     *stock_id,
+                      GtkIconSize      icon_size)
+{
+  GtkIconSet *icon_set;
+  GdkPixbuf *pixbuf;
+
+  gtk_style_context_save (context);
+
+  /* Unset any state */
+  gtk_style_context_set_state (context, 0);
+
+  icon_set = gtk_style_context_lookup_icon_set (context, stock_id);
+  pixbuf = gtk_icon_set_render_icon_pixbuf (icon_set, context, icon_size);
+
+  gtk_style_context_restore (context);
+
+  return pixbuf;
+}
+
 static void
 gtk_entry_ensure_pixbuf (GtkEntry             *entry,
                          GtkEntryIconPosition  icon_pos)
 {
   GtkEntryPrivate *priv = entry->priv;
   EntryIconInfo *icon_info = priv->icons[icon_pos];
+  GtkStyleContext *context;
   GtkIconInfo *info;
   GtkIconTheme *icon_theme;
   GtkSettings *settings;
-  GtkStateFlags state;
   GtkWidget *widget;
   GdkScreen *screen;
   gint width, height;
@@ -6594,6 +6739,7 @@ gtk_entry_ensure_pixbuf (GtkEntry             *entry,
     return;
 
   widget = GTK_WIDGET (entry);
+  context = gtk_widget_get_style_context (widget);
 
   switch (icon_info->storage_type)
     {
@@ -6601,16 +6747,13 @@ gtk_entry_ensure_pixbuf (GtkEntry             *entry,
     case GTK_IMAGE_PIXBUF:
       break;
     case GTK_IMAGE_STOCK:
-      state = gtk_widget_get_state_flags (widget);
-      gtk_widget_set_state_flags (widget, 0, TRUE);
-      icon_info->pixbuf = gtk_widget_render_icon_pixbuf (widget,
-                                                         icon_info->stock_id,
-                                                         GTK_ICON_SIZE_MENU);
+      icon_info->pixbuf = create_normal_pixbuf (context, icon_info->stock_id,
+                                                GTK_ICON_SIZE_MENU);
+
       if (!icon_info->pixbuf)
-        icon_info->pixbuf = gtk_widget_render_icon_pixbuf (widget,
-                                                           GTK_STOCK_MISSING_IMAGE,
-                                                           GTK_ICON_SIZE_MENU);
-      gtk_widget_set_state_flags (widget, state, TRUE);
+        icon_info->pixbuf = create_normal_pixbuf (context,
+                                                  GTK_STOCK_MISSING_IMAGE,
+                                                  GTK_ICON_SIZE_MENU);
       break;
 
     case GTK_IMAGE_ICON_NAME:
@@ -6630,14 +6773,9 @@ gtk_entry_ensure_pixbuf (GtkEntry             *entry,
                                                         0, NULL);
 
           if (icon_info->pixbuf == NULL)
-            {
-              state = gtk_widget_get_state_flags (widget);
-              gtk_widget_set_state_flags (widget, 0, TRUE);
-              icon_info->pixbuf = gtk_widget_render_icon_pixbuf (widget,
-                                                                 GTK_STOCK_MISSING_IMAGE,
-                                                                 GTK_ICON_SIZE_MENU);
-              gtk_widget_set_state_flags (widget, state, TRUE);
-            }
+            icon_info->pixbuf = create_normal_pixbuf (context,
+                                                      GTK_STOCK_MISSING_IMAGE,
+                                                      GTK_ICON_SIZE_MENU);
         }
       break;
 
@@ -6663,14 +6801,9 @@ gtk_entry_ensure_pixbuf (GtkEntry             *entry,
             }
 
           if (icon_info->pixbuf == NULL)
-            {
-              state = gtk_widget_get_state_flags (widget);
-              gtk_widget_set_state_flags (widget, 0, TRUE);
-              icon_info->pixbuf = gtk_widget_render_icon_pixbuf (widget,
-                                                                 GTK_STOCK_MISSING_IMAGE,
-                                                                 GTK_ICON_SIZE_MENU);
-              gtk_widget_set_state_flags (widget, state, TRUE);
-            }
+            icon_info->pixbuf = create_normal_pixbuf (context,
+                                                      GTK_STOCK_MISSING_IMAGE,
+                                                      GTK_ICON_SIZE_MENU);
         }
       break;
 
@@ -8159,7 +8292,8 @@ gtk_entry_get_icon_storage_type (GtkEntry             *entry,
  * @x: the x coordinate of the position to find
  * @y: the y coordinate of the position to find
  *
- * Finds the icon at the given position and return its index.
+ * Finds the icon at the given position and return its index. The
+ * position's coordinates are relative to the @entry's top left corner.
  * If @x, @y doesn't lie inside an icon, -1 is returned.
  * This function is intended for use in a #GtkWidget::query-tooltip
  * signal handler.
@@ -8179,7 +8313,7 @@ gtk_entry_get_icon_at_pos (GtkEntry *entry,
 
   g_return_val_if_fail (GTK_IS_ENTRY (entry), -1);
 
-  get_frame_size (entry, &frame_x, &frame_y, NULL, NULL);
+  get_frame_size (entry, FALSE, &frame_x, &frame_y, NULL, NULL);
   x -= frame_x;
   y -= frame_y;
 
@@ -8732,6 +8866,7 @@ popup_targets_received (GtkClipboard     *clipboard,
       gtk_menu_shell_append (GTK_MENU_SHELL (info_entry_priv->popup_menu), menuitem);
       
       menuitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_SELECT_ALL, NULL);
+      gtk_widget_set_sensitive (menuitem, gtk_entry_buffer_get_length (info_entry_priv->buffer) > 0);
       g_signal_connect_swapped (menuitem, "activate",
                                G_CALLBACK (gtk_entry_select_all), entry);
       gtk_widget_show (menuitem);
@@ -9585,6 +9720,8 @@ keypress_completion_out:
     {
       GtkTreeIter iter;
       GtkTreeModel *model = NULL;
+      GtkTreeModel *child_model;
+      GtkTreeIter child_iter;
       GtkTreeSelection *sel;
       gboolean retval = TRUE;
 
@@ -9598,9 +9735,11 @@ keypress_completion_out:
           sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (completion->priv->tree_view));
           if (gtk_tree_selection_get_selected (sel, &model, &iter))
             {
+              gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), &child_iter, &iter);
+              child_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model));
               g_signal_handler_block (widget, completion->priv->changed_id);
               g_signal_emit_by_name (completion, "match-selected",
-                                     model, &iter, &entry_set);
+                                     child_model, &child_iter, &entry_set);
               g_signal_handler_unblock (widget, completion->priv->changed_id);
 
               if (!entry_set)
@@ -9848,6 +9987,12 @@ gtk_entry_set_completion (GtkEntry           *entry,
           old->priv->completion_timeout = 0;
         }
 
+      if (old->priv->check_completion_idle)
+        {
+          g_source_destroy (old->priv->check_completion_idle);
+          old->priv->check_completion_idle = NULL;
+        }
+
       if (gtk_widget_get_mapped (old->priv->popup_window))
         _gtk_entry_completion_popdown (old);
 
@@ -9869,6 +10014,8 @@ gtk_entry_set_completion (GtkEntry           *entry,
   connect_completion_signals (entry, completion);    
   completion->priv->entry = GTK_WIDGET (entry);
   g_object_set_data (G_OBJECT (entry), I_(GTK_ENTRY_COMPLETION_KEY), completion);
+
+  g_object_notify (G_OBJECT (entry), "completion");
 }
 
 /**
@@ -10125,6 +10272,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
@@ -10190,7 +10392,7 @@ keymap_state_changed (GdkKeymap *keymap,
  * This is a helper function for GtkComboBox. A GtkEntry in a GtkComboBox
  * is supposed to behave like a GtkCellEditable when placed in a combo box.
  *
- * I.e take up it's allocation and get GtkEntry->is_cell_renderer = TRUE.
+ * I.e take up its allocation and get GtkEntry->is_cell_renderer = TRUE.
  *
  */
 void