]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkentry.c
Change FSF Address
[~andy/gtk] / gtk / gtkentry.c
index b432f8ba966835a5004bfabb82aa38bf8955e39d..e42670be048c82ca6fa6ebd69ca8ef36985ef2ac 100644 (file)
@@ -16,9 +16,7 @@
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
  */
 
 /*
@@ -147,6 +145,8 @@ struct _GtkEntryPrivate
   GtkShadowType          shadow_type;
   GtkWidget             *popup_menu;
 
+  GdkDevice             *device;
+
   GdkDevice             *completion_device;
   GdkWindow             *text_area;
 
@@ -169,7 +169,6 @@ struct _GtkEntryPrivate
   gint          drag_start_x;
   gint          drag_start_y;
   gint          focus_width;
-  gint          icon_margin;
   gint          insert_pos;
   gint          selection_bound;
   gint          scroll_offset;
@@ -548,6 +547,8 @@ static void         gtk_entry_do_popup                 (GtkEntry       *entry,
                                                        GdkEventButton *event);
 static gboolean     gtk_entry_mnemonic_activate        (GtkWidget      *widget,
                                                        gboolean        group_cycling);
+static void         gtk_entry_grab_notify              (GtkWidget      *widget,
+                                                        gboolean        was_grabbed);
 static void         gtk_entry_check_cursor_blink       (GtkEntry       *entry);
 static void         gtk_entry_pend_cursor_blink        (GtkEntry       *entry);
 static void         gtk_entry_reset_blink_time         (GtkEntry       *entry);
@@ -692,6 +693,7 @@ gtk_entry_class_init (GtkEntryClass *class)
   widget_class->state_flags_changed = gtk_entry_state_flags_changed;
   widget_class->screen_changed = gtk_entry_screen_changed;
   widget_class->mnemonic_activate = gtk_entry_mnemonic_activate;
+  widget_class->grab_notify = gtk_entry_grab_notify;
 
   widget_class->drag_drop = gtk_entry_drag_drop;
   widget_class->drag_motion = gtk_entry_drag_motion;
@@ -783,13 +785,22 @@ gtk_entry_class_init (GtkEntryClass *class)
                                                          TRUE,
                                                         GTK_PARAM_READWRITE));
 
+  /**
+   * GtkEntry:inner-border:
+   *
+   * Sets the text area's border between the text and the frame.
+   *
+   * Deprecated: 3.4: Use the standard border and padding CSS properties;
+   *   the value of this style property is ignored.
+   */
   g_object_class_install_property (gobject_class,
                                    PROP_INNER_BORDER,
                                    g_param_spec_boxed ("inner-border",
                                                        P_("Inner Border"),
                                                        P_("Border between text and frame. Overrides the inner-border style property"),
                                                        GTK_TYPE_BORDER,
-                                                       GTK_PARAM_READWRITE));
+                                                       GTK_PARAM_READWRITE |
+                                                       G_PARAM_DEPRECATED));
 
   g_object_class_install_property (gobject_class,
                                    PROP_INVISIBLE_CHAR,
@@ -1367,20 +1378,24 @@ gtk_entry_class_init (GtkEntryClass *class)
    * The border around the progress bar in the entry.
    *
    * Since: 2.16
+   *
+   * Deprecated: 3.4: Use the standard margin CSS property;
+   *   the value of this style property is ignored.
    */
   gtk_widget_class_install_style_property (widget_class,
                                           g_param_spec_boxed ("progress-border",
                                                                P_("Progress Border"),
                                                                P_("Border around the progress bar"),
                                                                GTK_TYPE_BORDER,
-                                                               GTK_PARAM_READABLE));
+                                                               GTK_PARAM_READABLE |
+                                                               G_PARAM_DEPRECATED));
   
   /**
    * GtkEntry:invisible-char:
    *
    * The invisible character is used when masking entry contents (in
    * \"password mode\")"). When it is not explicitly set with the
-   * #GtkEntry::invisible-char property, GTK+ determines the character
+   * #GtkEntry:invisible-char property, GTK+ determines the character
    * to use from a list of possible candidates, depending on availability
    * in the current font.
    *
@@ -1859,13 +1874,17 @@ gtk_entry_class_init (GtkEntryClass *class)
    * Sets the text area's border between the text and the frame.
    *
    * Since: 2.10
+   *
+   * Deprecated: 3.4: Use the standard border and padding CSS properties;
+   *   the value of this style property is ignored.
    */
   gtk_widget_class_install_style_property (widget_class,
                                           g_param_spec_boxed ("inner-border",
                                                                P_("Inner Border"),
                                                                P_("Border between text and frame."),
                                                                GTK_TYPE_BORDER,
-                                                               GTK_PARAM_READABLE)); 
+                                                               GTK_PARAM_READABLE |
+                                                               G_PARAM_DEPRECATED));
 
   g_type_class_add_private (gobject_class, sizeof (GtkEntryPrivate));
 
@@ -1892,6 +1911,27 @@ gtk_entry_cell_editable_init (GtkCellEditableIface *iface)
   iface->start_editing = gtk_entry_start_editing;
 }
 
+/* for deprecated properties */
+static void
+gtk_entry_do_set_inner_border (GtkEntry *entry,
+                               const GtkBorder *border)
+{
+  if (border)
+    g_object_set_qdata_full (G_OBJECT (entry), quark_inner_border,
+                             gtk_border_copy (border),
+                             (GDestroyNotify) gtk_border_free);
+  else
+    g_object_set_qdata (G_OBJECT (entry), quark_inner_border, NULL);
+
+  g_object_notify (G_OBJECT (entry), "inner-border");
+}
+
+static const GtkBorder *
+gtk_entry_do_get_inner_border (GtkEntry *entry)
+{
+  return g_object_get_qdata (G_OBJECT (entry), quark_inner_border);
+}
+
 static void
 gtk_entry_set_property (GObject         *object,
                         guint            prop_id,
@@ -1948,7 +1988,7 @@ gtk_entry_set_property (GObject         *object,
       break;
 
     case PROP_INNER_BORDER:
-      gtk_entry_set_inner_border (entry, g_value_get_boxed (value));
+      gtk_entry_do_set_inner_border (entry, g_value_get_boxed (value));
       break;
 
     case PROP_INVISIBLE_CHAR:
@@ -2165,7 +2205,7 @@ gtk_entry_get_property (GObject         *object,
       break;
 
     case PROP_INNER_BORDER:
-      g_value_set_boxed (value, gtk_entry_get_inner_border (entry));
+      g_value_set_boxed (value, gtk_entry_do_get_inner_border (entry));
       break;
 
     case PROP_INVISIBLE_CHAR:
@@ -2450,20 +2490,70 @@ gtk_entry_init (GtkEntry *entry)
   gtk_entry_update_cached_style_values (entry);
 }
 
+static void
+gtk_entry_prepare_context_for_icon (GtkEntry             *entry,
+                                    GtkStyleContext      *context,
+                                    GtkEntryIconPosition  icon_pos)
+{
+  GtkEntryPrivate *priv = entry->priv;
+  EntryIconInfo *icon_info = priv->icons[icon_pos];
+  GtkWidget *widget;
+  GtkStateFlags state;
+
+  widget = GTK_WIDGET (entry);
+  state = gtk_widget_get_state_flags (widget);
+
+  state &= ~(GTK_STATE_FLAG_PRELIGHT);
+
+  if ((state & GTK_STATE_FLAG_INSENSITIVE) || icon_info->insensitive)
+    state |= GTK_STATE_FLAG_INSENSITIVE;
+  else if (icon_info->prelight)
+    state |= GTK_STATE_FLAG_PRELIGHT;
+
+  gtk_style_context_save (context);
+
+  gtk_style_context_set_state (context, state);
+  gtk_style_context_add_class (context, GTK_STYLE_CLASS_IMAGE);
+
+  if (gtk_widget_get_direction (GTK_WIDGET (entry)) == GTK_TEXT_DIR_RTL) 
+    {
+      if (icon_pos == GTK_ENTRY_ICON_PRIMARY)
+        gtk_style_context_add_class (context, GTK_STYLE_CLASS_RIGHT);
+      else
+        gtk_style_context_add_class (context, GTK_STYLE_CLASS_LEFT);
+    }
+  else
+    {
+      if (icon_pos == GTK_ENTRY_ICON_PRIMARY)
+        gtk_style_context_add_class (context, GTK_STYLE_CLASS_LEFT);
+      else
+        gtk_style_context_add_class (context, GTK_STYLE_CLASS_RIGHT);
+    }
+}
+
 static gint
 get_icon_width (GtkEntry             *entry,
                 GtkEntryIconPosition  icon_pos)
 {
   GtkEntryPrivate *priv = entry->priv;
   EntryIconInfo *icon_info = priv->icons[icon_pos];
+  GtkStyleContext *context;
+  GtkBorder padding;
   gint width;
 
   if (!icon_info)
     return 0;
 
-  _gtk_icon_helper_get_size (icon_info->icon_helper,
-                             gtk_widget_get_style_context (GTK_WIDGET (entry)),
+  context = gtk_widget_get_style_context (GTK_WIDGET (entry));
+  gtk_entry_prepare_context_for_icon (entry, context, icon_pos);
+  gtk_style_context_get_padding (context, 0, &padding);
+
+  _gtk_icon_helper_get_size (icon_info->icon_helper, context,
                              &width, NULL);
+  gtk_style_context_restore (context);
+
+  if (width > 0)
+    width += padding.left + padding.right;
 
   return width;
 }
@@ -2485,14 +2575,10 @@ get_icon_allocations (GtkEntry      *entry,
   primary->y = y;
   primary->height = height;
   primary->width = get_icon_width (entry, GTK_ENTRY_ICON_PRIMARY);
-  if (primary->width > 0)
-    primary->width += 2 * priv->icon_margin;
 
   secondary->y = y;
   secondary->height = height;
   secondary->width = get_icon_width (entry, GTK_ENTRY_ICON_SECONDARY);
-  if (secondary->width > 0)
-    secondary->width += 2 * priv->icon_margin;
 
   if (gtk_widget_get_direction (GTK_WIDGET (entry)) == GTK_TEXT_DIR_RTL)
     {
@@ -2513,6 +2599,8 @@ begin_change (GtkEntry *entry)
   GtkEntryPrivate *priv = entry->priv;
 
   priv->change_count++;
+
+  g_object_freeze_notify (G_OBJECT (entry));
 }
 
 static void
@@ -2523,6 +2611,8 @@ end_change (GtkEntry *entry)
 
   g_return_if_fail (priv->change_count > 0);
 
+  g_object_thaw_notify (G_OBJECT (entry));
+
   priv->change_count--;
 
   if (priv->change_count == 0)
@@ -2991,34 +3081,37 @@ gtk_entry_unrealize (GtkWidget *widget)
 
 void
 _gtk_entry_get_borders (GtkEntry *entry,
-                       gint     *xborder,
-                       gint     *yborder)
+                        GtkBorder *border_out)
 {
   GtkEntryPrivate *priv = entry->priv;
   GtkWidget *widget = GTK_WIDGET (entry);
+  GtkBorder tmp = { 0, 0, 0, 0 };
+  GtkStyleContext *context;
+
+  context = gtk_widget_get_style_context (widget);
+  gtk_style_context_get_padding (context, 0, &tmp);
 
   if (priv->has_frame)
     {
-      GtkStyleContext *context;
-      GtkBorder padding;
+      GtkBorder border;
 
-      context = gtk_widget_get_style_context (widget);
-      gtk_style_context_get_padding (context, 0, &padding);
-
-      *xborder = padding.left;
-      *yborder = padding.top;
-    }
-  else
-    {
-      *xborder = 0;
-      *yborder = 0;
+      gtk_style_context_get_border (context, 0, &border);
+      tmp.top += border.top;
+      tmp.right += border.right;
+      tmp.bottom += border.bottom;
+      tmp.left += border.left;
     }
 
   if (!priv->interior_focus)
     {
-      *xborder += priv->focus_width;
-      *yborder += priv->focus_width;
+      tmp.top += priv->focus_width;
+      tmp.right += priv->focus_width;
+      tmp.bottom += priv->focus_width;
+      tmp.left += priv->focus_width;
     }
+
+  if (border_out != NULL)
+    *border_out = tmp;
 }
 
 static void
@@ -3029,8 +3122,7 @@ gtk_entry_get_preferred_width (GtkWidget *widget,
   GtkEntry *entry = GTK_ENTRY (widget);
   GtkEntryPrivate *priv = entry->priv;
   PangoFontMetrics *metrics;
-  gint xborder, yborder;
-  GtkBorder inner_border;
+  GtkBorder borders;
   PangoContext *context;
   GtkStyleContext *style_context;
   GtkStateFlags state;
@@ -3047,25 +3139,24 @@ gtk_entry_get_preferred_width (GtkWidget *widget,
                                        gtk_style_context_get_font (style_context, state),
                                        pango_context_get_language (context));
 
-  _gtk_entry_get_borders (entry, &xborder, &yborder);
-  _gtk_entry_effective_inner_border (entry, &inner_border);
+  _gtk_entry_get_borders (entry, &borders);
 
   if (priv->width_chars < 0)
-    width = MIN_ENTRY_WIDTH + xborder * 2 + inner_border.left + inner_border.right;
+    width = MIN_ENTRY_WIDTH + borders.left + borders.right;
   else
     {
       gint char_width = pango_font_metrics_get_approximate_char_width (metrics);
       gint digit_width = pango_font_metrics_get_approximate_digit_width (metrics);
       gint char_pixels = (MAX (char_width, digit_width) + PANGO_SCALE - 1) / PANGO_SCALE;
 
-      width = char_pixels * priv->width_chars + xborder * 2 + inner_border.left + inner_border.right;
+      width = char_pixels * priv->width_chars + borders.left + borders.right;
     }
 
   for (i = 0; i < MAX_ICONS; i++)
     {
       icon_width = get_icon_width (entry, i);
       if (icon_width > 0)
-        icon_widths += icon_width + 2 * priv->icon_margin;
+        icon_widths += icon_width;
     }
 
   if (icon_widths > width)
@@ -3085,8 +3176,7 @@ gtk_entry_get_preferred_height (GtkWidget *widget,
   GtkEntry *entry = GTK_ENTRY (widget);
   GtkEntryPrivate *priv = entry->priv;
   PangoFontMetrics *metrics;
-  gint xborder, yborder;
-  GtkBorder inner_border;
+  GtkBorder borders;
   GtkStyleContext *style_context;
   GtkStateFlags state;
   PangoContext *context;
@@ -3104,10 +3194,9 @@ gtk_entry_get_preferred_height (GtkWidget *widget,
   priv->ascent = pango_font_metrics_get_ascent (metrics);
   priv->descent = pango_font_metrics_get_descent (metrics);
 
-  _gtk_entry_get_borders (entry, &xborder, &yborder);
-  _gtk_entry_effective_inner_border (entry, &inner_border);
+  _gtk_entry_get_borders (entry, &borders);
 
-  height = PANGO_PIXELS (priv->ascent + priv->descent) + yborder * 2 + inner_border.top + inner_border.bottom;
+  height = PANGO_PIXELS (priv->ascent + priv->descent) + borders.top + borders.bottom;
 
   pango_font_metrics_unref (metrics);
 
@@ -3172,13 +3261,13 @@ gtk_entry_get_text_area_size (GtkEntry *entry,
   GtkRequisition requisition;
   gint req_height;
   gint frame_height;
-  gint xborder, yborder;
+  GtkBorder borders;
 
   gtk_widget_get_preferred_size (widget, &requisition, NULL);
   req_height = requisition.height - gtk_widget_get_margin_top (widget) - gtk_widget_get_margin_bottom (widget);
 
   gtk_widget_get_allocation (widget, &allocation);
-  _gtk_entry_get_borders (entry, &xborder, &yborder);
+  _gtk_entry_get_borders (entry, &borders);
 
   if (gtk_widget_get_realized (widget))
     get_frame_size (entry, TRUE, NULL, NULL, NULL, &frame_height);
@@ -3189,16 +3278,16 @@ gtk_entry_get_text_area_size (GtkEntry *entry,
     frame_height -= 2 * priv->focus_width;
 
   if (x)
-    *x = xborder;
+    *x = borders.left;
 
   if (y)
-    *y = frame_height / 2 - (req_height - yborder * 2) / 2;
+    *y = floor ((frame_height - req_height) / 2) + borders.top;
 
   if (width)
-    *width = allocation.width - xborder * 2;
+    *width = allocation.width - borders.left - borders.right;
 
   if (height)
-    *height = req_height - yborder * 2;
+    *height = req_height - borders.top - borders.bottom;
 }
 
 static void
@@ -3265,32 +3354,6 @@ get_frame_size (GtkEntry *entry,
     }
 }
 
-void
-_gtk_entry_effective_inner_border (GtkEntry  *entry,
-                                   GtkBorder *border)
-{
-  GtkBorder *tmp_border;
-
-  tmp_border = g_object_get_qdata (G_OBJECT (entry), quark_inner_border);
-
-  if (tmp_border)
-    {
-      *border = *tmp_border;
-      return;
-    }
-
-  gtk_widget_style_get (GTK_WIDGET (entry), "inner-border", &tmp_border, NULL);
-
-  if (tmp_border)
-    {
-      *border = *tmp_border;
-      gtk_border_free (tmp_border);
-      return;
-    }
-
-  *border = default_inner_border;
-}
-
 static void
 gtk_entry_size_allocate (GtkWidget     *widget,
                         GtkAllocation *allocation)
@@ -3336,30 +3399,6 @@ should_prelight (GtkEntry             *entry,
   return prelight;
 }
 
-static void
-gtk_entry_prepare_context_for_icon (GtkEntry             *entry,
-                                    GtkStyleContext      *context,
-                                    GtkEntryIconPosition  icon_pos)
-{
-  GtkEntryPrivate *priv = entry->priv;
-  EntryIconInfo *icon_info = priv->icons[icon_pos];
-  GtkWidget *widget;
-  GtkStateFlags state;
-
-  widget = GTK_WIDGET (entry);
-  state = GTK_STATE_FLAG_NORMAL;
-
-  if (!gtk_widget_is_sensitive (widget) || icon_info->insensitive)
-    state |= GTK_STATE_FLAG_INSENSITIVE;
-  else if (icon_info->prelight)
-    state |= GTK_STATE_FLAG_PRELIGHT;
-
-  gtk_style_context_save (context);
-
-  gtk_style_context_set_state (context, state);
-  gtk_style_context_add_class (context, GTK_STYLE_CLASS_IMAGE);
-}
-
 static void
 draw_icon (GtkWidget            *widget,
            cairo_t              *cr,
@@ -3370,15 +3409,11 @@ draw_icon (GtkWidget            *widget,
   EntryIconInfo *icon_info = priv->icons[icon_pos];
   gint x, y, width, height, pix_width, pix_height;
   GtkStyleContext *context;
-
-  context = gtk_widget_get_style_context (widget);
+  GtkBorder padding;
 
   if (!icon_info)
     return;
 
-  cairo_save (cr);
-  gtk_cairo_transform_to_window (cr, widget, icon_info->window);
-
   width = gdk_window_get_width (icon_info->window);
   height = gdk_window_get_height (icon_info->window);
 
@@ -3387,10 +3422,16 @@ draw_icon (GtkWidget            *widget,
   if (width == 1 || height == 1)
     return;
 
+  cairo_save (cr);
+  gtk_cairo_transform_to_window (cr, widget, icon_info->window);
+
+  context = gtk_widget_get_style_context (widget);
   gtk_entry_prepare_context_for_icon (entry, context, icon_pos);
-  _gtk_icon_helper_get_size (icon_info->icon_helper, context, &pix_width, &pix_height);
+  _gtk_icon_helper_get_size (icon_info->icon_helper, context,
+                             &pix_width, &pix_height);
+  gtk_style_context_get_padding (context, 0, &padding);
 
-  x = MAX (0, (width  - pix_width) / 2);
+  x = MAX (0, padding.left);
   y = MAX (0, (height - pix_height) / 2);
 
   _gtk_icon_helper_draw (icon_info->icon_helper,
@@ -3423,13 +3464,13 @@ gtk_entry_draw_frame (GtkWidget       *widget,
    * http://bugzilla.gnome.org/show_bug.cgi?id=466000 */
   if (GTK_IS_SPIN_BUTTON (widget))
     {
-      gint xborder, yborder;
+      GtkBorder borders;
 
       gtk_entry_get_text_area_size (GTK_ENTRY (widget), &x, NULL, &width, NULL);
-      _gtk_entry_get_borders (GTK_ENTRY (widget), &xborder, &yborder);
+      _gtk_entry_get_borders (GTK_ENTRY (widget), &borders);
 
-      x -= xborder;
-      width += xborder * 2;
+      x -= borders.left;
+      width += borders.left + borders.right;
     }
 
   if (gtk_widget_has_focus (widget) && !priv->interior_focus)
@@ -3463,6 +3504,18 @@ gtk_entry_draw_frame (GtkWidget       *widget,
   cairo_restore (cr);
 }
 
+static void
+gtk_entry_prepare_context_for_progress (GtkEntry *entry,
+                                        GtkStyleContext *context)
+{
+  GtkEntryPrivate *private = entry->priv;
+
+  gtk_style_context_save (context);
+  gtk_style_context_add_class (context, GTK_STYLE_CLASS_PROGRESSBAR);
+  if (private->progress_pulse_mode)
+    gtk_style_context_add_class (context, GTK_STYLE_CLASS_PULSE);
+}
+
 static void
 get_progress_area (GtkWidget *widget,
                    gint       *x,
@@ -3472,29 +3525,51 @@ get_progress_area (GtkWidget *widget,
 {
   GtkEntry *entry = GTK_ENTRY (widget);
   GtkEntryPrivate *private = entry->priv;
-  GtkBorder *progress_border;
+  GtkStyleContext *context;
+  GtkBorder margin, border, entry_borders;
+  gint frame_width, text_area_width, text_area_height;
+
+  context = gtk_widget_get_style_context (widget);
+  _gtk_entry_get_borders (entry, &entry_borders);
+  get_text_area_size (entry,
+                      NULL, NULL,
+                      &text_area_width, &text_area_height);
+  get_frame_size (entry, FALSE,
+                  NULL, NULL,
+                  &frame_width, NULL);
 
-  get_text_area_size (entry, x, y, width, height);
+  *x = 0;
+  *y = 0;
+  *width = text_area_width + entry_borders.left + entry_borders.right;
+  *height = text_area_height + entry_borders.top + entry_borders.bottom;
 
-  if (!private->interior_focus)
+  /* if the text area got resized by a subclass, subtract the left/right
+   * border width, so that the progress bar won't extend over the resized
+   * text area.
+   */
+  if (frame_width > *width)
     {
-      *x -= private->focus_width;
-      *y -= private->focus_width;
-      *width += 2 * private->focus_width;
-      *height += 2 * private->focus_width;
+      gtk_style_context_get_border (context, 0, &border);
+      if (gtk_widget_get_direction (GTK_WIDGET (entry)) == GTK_TEXT_DIR_RTL)
+        {
+          *x = (frame_width - *width) + border.left;
+          *width -= border.left;
+        }
+      else
+        {
+          *width -= border.right;
+        }
     }
 
-  gtk_widget_style_get (widget, "progress-border", &progress_border, NULL);
+  gtk_entry_prepare_context_for_progress (entry, context);
+  gtk_style_context_get_margin (context, 0, &margin);
 
-  if (progress_border)
-    {
-      *x += progress_border->left;
-      *y += progress_border->top;
-      *width -= progress_border->left + progress_border->right;
-      *height -= progress_border->top + progress_border->bottom;
+  gtk_style_context_restore (context);
 
-      gtk_border_free (progress_border);
-    }
+  *x += margin.left;
+  *y += margin.top;
+  *width -= margin.left + margin.right;
+  *height -= margin.top + margin.bottom;
 
   if (private->progress_pulse_mode)
     {
@@ -3533,19 +3608,14 @@ gtk_entry_draw_progress (GtkWidget       *widget,
                          cairo_t         *cr)
 {
   GtkEntry *entry = GTK_ENTRY (widget);
-  GtkEntryPrivate *private = entry->priv;
   gint x, y, width, height;
 
   get_progress_area (widget, &x, &y, &width, &height);
 
   if ((width <= 0) || (height <= 0))
     return;
-
-  gtk_style_context_save (context);
-  gtk_style_context_add_class (context, GTK_STYLE_CLASS_PROGRESSBAR);
-  if (private->progress_pulse_mode)
-    gtk_style_context_add_class (context, GTK_STYLE_CLASS_PULSE);
-
+  gtk_entry_prepare_context_for_progress (entry, context);
   gtk_render_activity (context, cr,
                        x, y, width, height);
 
@@ -3558,15 +3628,10 @@ gtk_entry_draw (GtkWidget *widget,
 {
   GtkEntry *entry = GTK_ENTRY (widget);
   GtkStyleContext *context;
-  GtkStateFlags state;
   GtkEntryPrivate *priv = entry->priv;
   int i;
 
   context = gtk_widget_get_style_context (widget);
-  state = gtk_widget_get_state_flags (widget);
-
-  gtk_style_context_save (context);
-  gtk_style_context_set_state (context, state);
 
   /* Draw entry_bg, shadow, progress and focus */
   gtk_entry_draw_frame (widget, context, cr);
@@ -3598,8 +3663,6 @@ gtk_entry_draw (GtkWidget *widget,
         draw_icon (widget, cr, i);
     }
 
-  gtk_style_context_restore (context);
-
   return FALSE;
 }
 
@@ -3770,7 +3833,8 @@ gtk_entry_button_press (GtkWidget      *widget,
   gtk_entry_reset_blink_time (entry);
 
   priv->button = event->button;
-  
+  priv->device = gdk_event_get_device ((GdkEvent *) event);
+
   if (!gtk_widget_has_focus (widget))
     {
       priv->in_click = TRUE;
@@ -3784,10 +3848,11 @@ gtk_entry_button_press (GtkWidget      *widget,
     {
       gtk_entry_do_popup (entry, event);
       priv->button = 0; /* Don't wait for release, since the menu will gtk_grab_add */
+      priv->device = NULL;
 
       return TRUE;
     }
-  else if (event->button == 1)
+  else if (event->button == GDK_BUTTON_PRIMARY)
     {
       gboolean have_selection = gtk_editable_get_selection_bounds (editable, &sel_start, &sel_end);
 
@@ -3897,7 +3962,7 @@ gtk_entry_button_press (GtkWidget      *widget,
 
       return TRUE;
     }
-  else if (event->button == 2 && event->type == GDK_BUTTON_PRESS)
+  else if (event->button == GDK_BUTTON_MIDDLE && event->type == GDK_BUTTON_PRESS)
     {
       if (priv->editable)
         {
@@ -3961,9 +4026,10 @@ gtk_entry_button_release (GtkWidget      *widget,
 
       priv->in_drag = 0;
     }
-  
+
   priv->button = 0;
-  
+  priv->device = NULL;
+
   gtk_entry_update_primary_selection (entry);
              
   return TRUE;
@@ -4032,7 +4098,7 @@ gtk_entry_motion_notify (GtkWidget      *widget,
       priv->mouse_cursor_obscured = FALSE;
     }
 
-  if (event->window != priv->text_area || priv->button != 1)
+  if (event->window != priv->text_area || priv->button != GDK_BUTTON_PRIMARY)
     return FALSE;
 
   if (priv->select_lines)
@@ -4072,7 +4138,8 @@ gtk_entry_motion_notify (GtkWidget      *widget,
 
           priv->in_drag = FALSE;
           priv->button = 0;
-         
+          priv->device = NULL;
+
           gtk_target_list_unref (target_list);
         }
     }
@@ -4514,17 +4581,6 @@ icon_theme_changed (GtkEntry *entry)
   gtk_widget_queue_draw (GTK_WIDGET (entry));
 }
 
-static void
-icon_margin_changed (GtkEntry *entry)
-{
-  GtkEntryPrivate *priv = entry->priv;
-  GtkBorder border;
-
-  _gtk_entry_effective_inner_border (GTK_ENTRY (entry), &border);
-
-  priv->icon_margin = border.left;
-}
-
 static void
 gtk_entry_update_cached_style_values (GtkEntry *entry)
 {
@@ -4563,7 +4619,6 @@ gtk_entry_style_updated (GtkWidget *widget)
   gtk_entry_recompute (entry);
 
   icon_theme_changed (entry);
-  icon_margin_changed (entry);
 }
 
 /* GtkCellEditable method implementations
@@ -4658,11 +4713,9 @@ gtk_entry_real_insert_text (GtkEditable *editable,
    * buffer_notify_text(), buffer_notify_length()
    */
   begin_change (GTK_ENTRY (editable));
-  g_object_freeze_notify (G_OBJECT (editable));
 
   n_inserted = gtk_entry_buffer_insert_text (get_buffer (GTK_ENTRY (editable)), *position, new_text, n_chars);
 
-  g_object_thaw_notify (G_OBJECT (editable));
   end_change (GTK_ENTRY (editable));
 
   if (n_inserted != n_chars)
@@ -4683,9 +4736,9 @@ gtk_entry_real_delete_text (GtkEditable *editable,
    */
 
   begin_change (GTK_ENTRY (editable));
-  g_object_freeze_notify (G_OBJECT (editable));
+
   gtk_entry_buffer_delete_text (get_buffer (GTK_ENTRY (editable)), start_pos, end_pos - start_pos);
-  g_object_thaw_notify (G_OBJECT (editable));
+
   end_change (GTK_ENTRY (editable));
 }
 
@@ -5650,16 +5703,13 @@ get_layout_position (GtkEntry *entry,
   PangoLayout *layout;
   PangoRectangle logical_rect;
   gint area_width, area_height;
-  GtkBorder inner_border;
   gint y_pos;
   PangoLayoutLine *line;
   
   layout = gtk_entry_ensure_layout (entry, TRUE);
 
   gtk_entry_get_text_area_size (entry, NULL, NULL, &area_width, &area_height);
-  _gtk_entry_effective_inner_border (entry, &inner_border);
-
-  area_height = PANGO_SCALE * (area_height - inner_border.top - inner_border.bottom);
+  area_height = PANGO_SCALE * area_height;
 
   line = pango_layout_get_lines_readonly (layout)->data;
   pango_layout_line_get_extents (line, NULL, &logical_rect);
@@ -5676,10 +5726,10 @@ get_layout_position (GtkEntry *entry,
   else if (y_pos + logical_rect.height > area_height)
     y_pos = area_height - logical_rect.height;
   
-  y_pos = inner_border.top + y_pos / PANGO_SCALE;
+  y_pos = y_pos / PANGO_SCALE;
 
   if (x)
-    *x = inner_border.left - priv->scroll_offset;
+    *x = - priv->scroll_offset;
 
   if (y)
     *y = y_pos;
@@ -5712,7 +5762,6 @@ draw_text_with_color (GtkEntry *entry,
       gint n_ranges, i;
       PangoRectangle logical_rect;
       GdkRGBA selection_color, text_color;
-      GtkBorder inner_border;
       GtkStyleContext *context;
       GtkStateFlags state;
 
@@ -5720,19 +5769,15 @@ draw_text_with_color (GtkEntry *entry,
       pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
       gtk_entry_get_pixel_ranges (entry, &ranges, &n_ranges);
 
-      state = GTK_STATE_FLAG_SELECTED;
-
-      if (gtk_widget_has_focus (widget))
-        state |= GTK_STATE_FLAG_FOCUSED;
+      state = gtk_widget_get_state_flags (widget);
+      state |= GTK_STATE_FLAG_SELECTED;
 
       gtk_style_context_get_background_color (context, state, &selection_color);
       gtk_style_context_get_color (context, state, &text_color);
 
-      _gtk_entry_effective_inner_border (entry, &inner_border);
-
       for (i = 0; i < n_ranges; ++i)
         cairo_rectangle (cr,
-                         inner_border.left - priv->scroll_offset + ranges[2 * i],
+                         - priv->scroll_offset + ranges[2 * i],
                         y,
                         ranges[2 * i + 1],
                         logical_rect.height);
@@ -5774,8 +5819,7 @@ gtk_entry_draw_text (GtkEntry *entry,
   gtk_style_context_get_color (context, state, &text_color);
 
   /* Get foreground color for progressbars */
-  gtk_style_context_save (context);
-  gtk_style_context_add_class (context, GTK_STYLE_CLASS_PROGRESSBAR);
+  gtk_entry_prepare_context_for_progress (entry, context);
   gtk_style_context_get_color (context, state, &bar_text_color);
   gtk_style_context_restore (context);
 
@@ -5838,27 +5882,6 @@ gtk_entry_draw_text (GtkEntry *entry,
   cairo_restore (cr);
 }
 
-static void
-draw_insertion_cursor (GtkEntry      *entry,
-                       cairo_t       *cr,
-                      GdkRectangle  *cursor_location,
-                      gboolean       is_primary,
-                      PangoDirection direction,
-                      gboolean       draw_arrow)
-{
-  GtkWidget *widget = GTK_WIDGET (entry);
-  GtkTextDirection text_dir;
-
-  if (direction == PANGO_DIRECTION_LTR)
-    text_dir = GTK_TEXT_DIR_LTR;
-  else
-    text_dir = GTK_TEXT_DIR_RTL;
-
-  gtk_draw_insertion_cursor (widget, cr,
-                            cursor_location,
-                            is_primary, text_dir, draw_arrow);
-}
-
 static void
 gtk_entry_draw_cursor (GtkEntry  *entry,
                        cairo_t   *cr,
@@ -5866,29 +5889,22 @@ gtk_entry_draw_cursor (GtkEntry  *entry,
 {
   GtkEntryPrivate *priv = entry->priv;
   GtkWidget *widget = GTK_WIDGET (entry);
-  GdkKeymap *keymap = gdk_keymap_get_for_display (gtk_widget_get_display (GTK_WIDGET (entry)));
-  PangoDirection keymap_direction = gdk_keymap_get_direction (keymap);
-  GdkRectangle cursor_location;
-  gboolean split_cursor;
+  GtkStyleContext *context;
   PangoRectangle cursor_rect;
-  GtkBorder inner_border;
-  gint xoffset;
-  gint text_area_height;
   gint cursor_index;
   gboolean block;
   gboolean block_at_line_end;
   PangoLayout *layout;
   const char *text;
+  gint x, y;
 
-  _gtk_entry_effective_inner_border (entry, &inner_border);
-
-  xoffset = inner_border.left - priv->scroll_offset;
-
-  text_area_height = gdk_window_get_height (priv->text_area);
+  context = gtk_widget_get_style_context (widget);
 
   layout = gtk_entry_ensure_layout (entry, TRUE);
   text = pango_layout_get_text (layout);
   cursor_index = g_utf8_offset_to_pointer (text, priv->current_pos + priv->preedit_cursor) - text;
+  get_layout_position (entry, &x, &y);
+
   if (!priv->overwrite_mode)
     block = FALSE;
   else
@@ -5897,73 +5913,22 @@ gtk_entry_draw_cursor (GtkEntry  *entry,
 
   if (!block)
     {
-      gint strong_x, weak_x;
-      PangoDirection dir1 = PANGO_DIRECTION_NEUTRAL;
-      PangoDirection dir2 = PANGO_DIRECTION_NEUTRAL;
-      gint x1 = 0;
-      gint x2 = 0;
-
-      gtk_entry_get_cursor_locations (entry, type, &strong_x, &weak_x);
-
-      g_object_get (gtk_widget_get_settings (widget),
-                    "gtk-split-cursor", &split_cursor,
-                    NULL);
-
-      dir1 = priv->resolved_dir;
-  
-      if (split_cursor)
-        {
-          x1 = strong_x;
-
-          if (weak_x != strong_x)
-            {
-              dir2 = (priv->resolved_dir == PANGO_DIRECTION_LTR) ? PANGO_DIRECTION_RTL : PANGO_DIRECTION_LTR;
-              x2 = weak_x;
-            }
-        }
-      else
-        {
-          if (keymap_direction == priv->resolved_dir)
-            x1 = strong_x;
-          else
-            x1 = weak_x;
-        }
-
-      cursor_location.x = xoffset + x1;
-      cursor_location.y = inner_border.top;
-      cursor_location.width = 0;
-      cursor_location.height = text_area_height - inner_border.top - inner_border.bottom;
-
-      draw_insertion_cursor (entry, cr,
-                             &cursor_location, TRUE, dir1,
-                             dir2 != PANGO_DIRECTION_NEUTRAL);
-  
-      if (dir2 != PANGO_DIRECTION_NEUTRAL)
-        {
-          cursor_location.x = xoffset + x2;
-          draw_insertion_cursor (entry, cr,
-                                 &cursor_location, FALSE, dir2,
-                                 TRUE);
-        }
+      gtk_render_insertion_cursor (context, cr,
+                                   x, y,
+                                   layout, cursor_index, priv->resolved_dir);
     }
   else /* overwrite_mode */
     {
-      GtkStyleContext *context;
       GdkRGBA cursor_color;
       GdkRectangle rect;
-      gint x, y;
 
       cairo_save (cr);
 
-      get_layout_position (entry, &x, &y);
-
       rect.x = PANGO_PIXELS (cursor_rect.x) + x;
       rect.y = PANGO_PIXELS (cursor_rect.y) + y;
       rect.width = PANGO_PIXELS (cursor_rect.width);
       rect.height = PANGO_PIXELS (cursor_rect.height);
 
-      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);
@@ -6156,7 +6121,6 @@ gtk_entry_adjust_scroll (GtkEntry *entry)
   GtkEntryPrivate *priv = entry->priv;
   gint min_offset, max_offset;
   gint text_area_width, text_width;
-  GtkBorder inner_border;
   gint strong_x, weak_x;
   gint strong_xoffset, weak_xoffset;
   gfloat xalign;
@@ -6167,10 +6131,8 @@ gtk_entry_adjust_scroll (GtkEntry *entry)
   if (!gtk_widget_get_realized (GTK_WIDGET (entry)))
     return;
 
-  _gtk_entry_effective_inner_border (entry, &inner_border);
-
   text_area_width = gdk_window_get_width (priv->text_area);
-  text_area_width -= inner_border.left + inner_border.right;
+
   if (text_area_width < 0)
     text_area_width = 0;
 
@@ -6255,7 +6217,8 @@ gtk_entry_move_adjustments (GtkEntry *entry)
   PangoFontMetrics *metrics;
   GtkStyleContext *style_context;
   GtkStateFlags state;
-  gint x, layout_x, border_x, border_y;
+  GtkBorder borders;
+  gint x, layout_x;
   gint char_width;
 
   adjustment = g_object_get_qdata (G_OBJECT (entry), quark_cursor_hadjustment);
@@ -6267,8 +6230,8 @@ gtk_entry_move_adjustments (GtkEntry *entry)
   /* Cursor position, layout offset, border width, and widget allocation */
   gtk_entry_get_cursor_locations (entry, CURSOR_STANDARD, &x, NULL);
   get_layout_position (entry, &layout_x, NULL);
-  _gtk_entry_get_borders (entry, &border_x, &border_y);
-  x += allocation.x + layout_x + border_x;
+  _gtk_entry_get_borders (entry, &borders);
+  x += allocation.x + layout_x + borders.left;
 
   /* Approximate width of a char, so user can see what is ahead/behind */
   context = gtk_widget_get_pango_context (widget);
@@ -6521,7 +6484,7 @@ paste_received (GtkClipboard *clipboard,
   GtkEditable *editable = GTK_EDITABLE (entry);
   GtkEntryPrivate *priv = entry->priv;
 
-  if (priv->button == 2)
+  if (priv->button == GDK_BUTTON_MIDDLE)
     {
       gint pos, start, end;
       pos = priv->insert_pos;
@@ -6556,14 +6519,12 @@ paste_received (GtkClipboard *clipboard,
        }
 
       begin_change (entry);
-      g_object_freeze_notify (G_OBJECT (entry));
       if (gtk_editable_get_selection_bounds (editable, &start, &end))
         gtk_editable_delete_text (editable, start, end);
 
       pos = priv->current_pos;
       gtk_editable_insert_text (editable, text, length, &pos);
       gtk_editable_set_position (editable, pos);
-      g_object_thaw_notify (G_OBJECT (entry));
       end_change (entry);
 
       if (completion &&
@@ -6920,11 +6881,9 @@ gtk_entry_set_text (GtkEntry    *entry,
     g_signal_handler_block (entry, completion->priv->changed_id);
 
   begin_change (entry);
-  g_object_freeze_notify (G_OBJECT (entry));
   gtk_editable_delete_text (GTK_EDITABLE (entry), 0, -1);
   tmp_pos = 0;
   gtk_editable_insert_text (GTK_EDITABLE (entry), text, strlen (text), &tmp_pos);
-  g_object_thaw_notify (G_OBJECT (entry));
   end_change (entry);
 
   if (completion && completion->priv->changed_id > 0)
@@ -7371,6 +7330,9 @@ gtk_entry_get_has_frame (GtkEntry *entry)
  * pixel-exact positioning of the entry is important.
  *
  * Since: 2.10
+ *
+ * Deprecated: 3.4: Use the standard border and padding CSS properties;
+ *   the value set with this function is ignored by #GtkEntry.
  **/
 void
 gtk_entry_set_inner_border (GtkEntry        *entry,
@@ -7378,16 +7340,7 @@ gtk_entry_set_inner_border (GtkEntry        *entry,
 {
   g_return_if_fail (GTK_IS_ENTRY (entry));
 
-  gtk_widget_queue_resize (GTK_WIDGET (entry));
-
-  if (border)
-    g_object_set_qdata_full (G_OBJECT (entry), quark_inner_border,
-                             gtk_border_copy (border),
-                             (GDestroyNotify) gtk_border_free);
-  else
-    g_object_set_qdata (G_OBJECT (entry), quark_inner_border, NULL);
-
-  g_object_notify (G_OBJECT (entry), "inner-border");
+  gtk_entry_do_set_inner_border (entry, border);
 }
 
 /**
@@ -7400,13 +7353,16 @@ gtk_entry_set_inner_border (GtkEntry        *entry,
  * Return value: (transfer none): the entry's #GtkBorder, or %NULL if none was set.
  *
  * Since: 2.10
+ *
+ * Deprecated: 3.4: Use the standard border and padding CSS properties;
+ *   the value returned by this function is ignored by #GtkEntry.
  **/
 const GtkBorder *
 gtk_entry_get_inner_border (GtkEntry *entry)
 {
   g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL);
 
-  return g_object_get_qdata (G_OBJECT (entry), quark_inner_border);
+  return gtk_entry_do_get_inner_border (entry);
 }
 
 /**
@@ -8016,8 +7972,7 @@ gtk_entry_get_icon_gicon (GtkEntry             *entry,
   if (!icon_info)
     return NULL;
 
-  return _gtk_icon_helper_get_storage_type (icon_info->icon_helper) == GTK_IMAGE_GICON ? 
-    _gtk_icon_helper_peek_gicon (icon_info->icon_helper) : NULL;
+  return _gtk_icon_helper_peek_gicon (icon_info->icon_helper);
 }
 
 /**
@@ -8050,9 +8005,7 @@ gtk_entry_get_icon_stock (GtkEntry             *entry,
   if (!icon_info)
     return NULL;
 
-  return _gtk_icon_helper_get_storage_type (icon_info->icon_helper) == GTK_IMAGE_STOCK ? 
-    _gtk_icon_helper_get_stock_id (icon_info->icon_helper) : NULL;
-
+  return _gtk_icon_helper_get_stock_id (icon_info->icon_helper);
 }
 
 /**
@@ -8085,9 +8038,7 @@ gtk_entry_get_icon_name (GtkEntry             *entry,
   if (!icon_info)
     return NULL;
 
-  return _gtk_icon_helper_get_storage_type (icon_info->icon_helper) == GTK_IMAGE_ICON_NAME ? 
-    _gtk_icon_helper_get_icon_name (icon_info->icon_helper) : NULL;
-
+  return _gtk_icon_helper_get_icon_name (icon_info->icon_helper);
 }
 
 /**
@@ -8628,6 +8579,26 @@ gtk_entry_mnemonic_activate (GtkWidget *widget,
   return TRUE;
 }
 
+static void
+gtk_entry_grab_notify (GtkWidget *widget,
+                       gboolean   was_grabbed)
+{
+  GtkEntryPrivate *priv;
+
+  priv = GTK_ENTRY (widget)->priv;
+
+  if (priv->device &&
+      gtk_widget_device_is_shadowed (widget, priv->device))
+    {
+      /* Unset button so we don't expect
+       * a button release anymore
+       */
+      priv->button = 0;
+      priv->device = NULL;
+      priv->in_drag = FALSE;
+    }
+}
+
 static void
 append_action_signal (GtkEntry     *entry,
                      GtkWidget    *menu,
@@ -8670,7 +8641,7 @@ popup_position_func (GtkMenu   *menu,
   GdkScreen *screen;
   GtkRequisition menu_req;
   GdkRectangle monitor;
-  GtkBorder inner_border;
+  GtkBorder borders;
   gint monitor_num, strong_x, height;
  
   g_return_if_fail (gtk_widget_get_realized (widget));
@@ -8683,14 +8654,14 @@ popup_position_func (GtkMenu   *menu,
     monitor_num = 0;
   gtk_menu_set_monitor (menu, monitor_num);
 
-  gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
+  gdk_screen_get_monitor_workarea (screen, monitor_num, &monitor);
   gtk_widget_get_preferred_size (priv->popup_menu,
                                  &menu_req, NULL);
   height = gdk_window_get_height (priv->text_area);
   gtk_entry_get_cursor_locations (entry, CURSOR_STANDARD, &strong_x, NULL);
-  _gtk_entry_effective_inner_border (entry, &inner_border);
+  _gtk_entry_get_borders (entry, &borders);
 
-  *x += inner_border.left + strong_x - priv->scroll_offset;
+  *x += borders.left + strong_x - priv->scroll_offset;
   if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
     *x -= menu_req.width;
 
@@ -9075,10 +9046,8 @@ gtk_entry_drag_data_received (GtkWidget        *widget,
        {
          /* Replacing selection */
           begin_change (entry);
-          g_object_freeze_notify (G_OBJECT (entry));
          gtk_editable_delete_text (editable, sel1, sel2);
          gtk_editable_insert_text (editable, str, length, &sel1);
-          g_object_thaw_notify (G_OBJECT (entry));
           end_change (entry);
        }
       
@@ -9604,18 +9573,13 @@ keypress_completion_out:
           event->keyval == GDK_KEY_KP_Tab ||
           event->keyval == GDK_KEY_ISO_Left_Tab) 
     {
-      GtkDirectionType dir = event->keyval == GDK_KEY_ISO_Left_Tab ? 
-       GTK_DIR_TAB_BACKWARD : GTK_DIR_TAB_FORWARD;
-      
       _gtk_entry_reset_im_context (GTK_ENTRY (widget));
       _gtk_entry_completion_popdown (completion);
 
       g_free (completion->priv->completion_prefix);
       completion->priv->completion_prefix = NULL;
 
-      gtk_widget_child_focus (gtk_widget_get_toplevel (widget), dir);
-
-      return TRUE;
+      return FALSE;
     }
   else if (event->keyval == GDK_KEY_ISO_Enter ||
            event->keyval == GDK_KEY_KP_Enter ||