]> code.delx.au - gnu-emacs/blobdiff - src/frame.c
Merge branch 'emacs-24'
[gnu-emacs] / src / frame.c
index 307119c44820246ed1ab7212620aa4b68f497aed..eaab63a0ea41d4a9391f92d806c7defcc0d22340 100644 (file)
@@ -51,6 +51,9 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "msdos.h"
 #include "dosfns.h"
 #endif
+#ifdef USE_X_TOOLKIT
+#include "widget.h"
+#endif
 
 #ifdef HAVE_NS
 Lisp_Object Qns_parse_geometry;
@@ -75,7 +78,6 @@ Lisp_Object Qauto_raise, Qauto_lower;
 Lisp_Object Qborder_color, Qborder_width;
 Lisp_Object Qcursor_color, Qcursor_type;
 Lisp_Object Qheight, Qwidth;
-Lisp_Object Qleft, Qright;
 Lisp_Object Qicon_left, Qicon_top, Qicon_type, Qicon_name;
 Lisp_Object Qtooltip;
 Lisp_Object Qinternal_border_width;
@@ -83,6 +85,7 @@ Lisp_Object Qright_divider_width, Qbottom_divider_width;
 Lisp_Object Qmouse_color;
 Lisp_Object Qminibuffer;
 Lisp_Object Qscroll_bar_width, Qvertical_scroll_bars;
+Lisp_Object Qscroll_bar_height, Qhorizontal_scroll_bars;
 Lisp_Object Qvisibility;
 Lisp_Object Qscroll_bar_foreground, Qscroll_bar_background;
 Lisp_Object Qscreen_gamma;
@@ -114,9 +117,14 @@ Lisp_Object Qface_set_after_frame_default;
 static Lisp_Object Qfocus_in_hook;
 static Lisp_Object Qfocus_out_hook;
 static Lisp_Object Qdelete_frame_functions;
-
+static Lisp_Object Qframe_windows_min_size;
 static Lisp_Object Qgeometry, Qworkarea, Qmm_size, Qframes, Qsource;
 
+Lisp_Object Qframe_position, Qframe_outer_size, Qframe_inner_size;
+Lisp_Object Qexternal_border_size, Qtitle_height;
+Lisp_Object Qmenu_bar_external, Qmenu_bar_size;
+Lisp_Object Qtool_bar_external, Qtool_bar_size;
+
 /* The currently selected frame.  */
 
 Lisp_Object selected_frame;
@@ -163,19 +171,16 @@ decode_any_frame (register Lisp_Object frame)
   return XFRAME (frame);
 }
 
+#ifdef HAVE_WINDOW_SYSTEM
+
 bool
 window_system_available (struct frame *f)
 {
-  if (f)
-    return FRAME_WINDOW_P (f) || FRAME_MSDOS_P (f);
-  else
-#ifdef HAVE_WINDOW_SYSTEM
-    return x_display_list != NULL;
-#else
-    return 0;
-#endif
+  return f ? FRAME_WINDOW_P (f) || FRAME_MSDOS_P (f) : x_display_list != NULL;
 }
 
+#endif /* HAVE_WINDOW_SYSTEM */
+
 struct frame *
 decode_window_system_frame (Lisp_Object frame)
 {
@@ -194,30 +199,34 @@ check_window_system (struct frame *f)
           : "Window system is not in use or not initialized");
 }
 
-static void
-set_menu_bar_lines_1 (Lisp_Object window, int n)
+/* Return the value of frame parameter PROP in frame FRAME.  */
+
+Lisp_Object
+get_frame_param (register struct frame *frame, Lisp_Object prop)
 {
-  struct window *w = XWINDOW (window);
-  struct frame *f = XFRAME (WINDOW_FRAME (w));
-
-  w->top_line += n;
-  w->pixel_top += n * FRAME_LINE_HEIGHT (f);
-  w->total_lines -= n;
-  w->pixel_height -= n * FRAME_LINE_HEIGHT (f);
-
-  /* Handle just the top child in a vertical split.  */
-  if (WINDOW_VERTICAL_COMBINATION_P (w))
-    set_menu_bar_lines_1 (w->contents, n);
-  else if (WINDOW_HORIZONTAL_COMBINATION_P (w))
-    /* Adjust all children in a horizontal split.  */
-    for (window = w->contents; !NILP (window); window = w->next)
-      {
-       w = XWINDOW (window);
-       set_menu_bar_lines_1 (window, n);
-      }
+  register Lisp_Object tem;
+
+  tem = Fassq (prop, frame->param_alist);
+  if (EQ (tem, Qnil))
+    return tem;
+  return Fcdr (tem);
 }
 
-void
+/* Return 1 if `frame-inhibit-implied-resize' is non-nil or fullscreen
+   state of frame F would be affected by a vertical (horizontal if
+   HORIZONTAL is true) resize.  PARAMETER is the symbol of the frame
+   parameter that is changed.  */
+bool
+frame_inhibit_resize (struct frame *f, bool horizontal, Lisp_Object parameter)
+{
+  return (EQ (frame_inhibit_implied_resize, Qt)
+         || (CONSP (frame_inhibit_implied_resize)
+             && !NILP (Fmemq (parameter, frame_inhibit_implied_resize)))
+         || !NILP (get_frame_param (f, Qfullscreen))
+         || FRAME_TERMCAP_P (f) || FRAME_MSDOS_P (f));
+}
+
+static void
 set_menu_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval)
 {
   int nlines;
@@ -238,11 +247,11 @@ set_menu_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval)
   if (nlines != olines)
     {
       windows_or_buffers_changed = 14;
-      FRAME_WINDOW_SIZES_CHANGED (f) = 1;
       FRAME_MENU_BAR_LINES (f) = nlines;
       FRAME_MENU_BAR_HEIGHT (f) = nlines * FRAME_LINE_HEIGHT (f);
-      set_menu_bar_lines_1 (f->root_window, nlines - olines);
-      adjust_frame_glyphs (f);
+      change_frame_size (f, FRAME_COLS (f),
+                        FRAME_LINES (f) + olines - nlines,
+                        0, 1, 0, 0);
     }
 }
 \f
@@ -325,6 +334,255 @@ predicates which report frame's specific UI-related capabilities.  */)
     return type;
 }
 
+static int
+frame_windows_min_size (Lisp_Object frame, Lisp_Object horizontal, Lisp_Object pixelwise)
+{
+  return XINT (call3 (Qframe_windows_min_size, frame, horizontal, pixelwise));
+}
+
+
+/* Make sure windows sizes of frame F are OK.  new_width and new_height
+   are in pixels.  A value of -1 means no change is requested for that
+   size (but the frame may still have to be resized to accommodate
+   windows with their minimum sizes).  This can either issue a request
+   to resize the frame externally (via x_set_window_size), to resize the
+   frame internally (via resize_frame_windows) or do nothing at all.
+
+   The argument INHIBIT can assume the following values:
+
+   0 means to unconditionally call x_set_window_size even if sizes
+     apparently do not change.  Fx_create_frame uses this to pass the
+     initial size to the window manager.
+
+   1 means to call x_set_window_size if the outer frame size really
+     changes.  Fset_frame_size, Fset_frame_height, ... use this.
+
+   2 means to call x_set_window_size provided frame_inhibit_resize
+     allows it.  The menu and tool bar code use this ("3" won't work
+     here in general because menu and tool bar are often not counted in
+     the frame's text height).
+
+   3 means call x_set_window_size if window minimum sizes must be
+     preserved or frame_inhibit_resize allows it.  x_set_left_fringe,
+     x_set_scroll_bar_width, x_new_font ... use (or should use) this.
+
+   4 means call x_set_window_size only if window minimum sizes must be
+     preserved.  x_set_right_divider_width, x_set_border_width and the
+     code responsible for wrapping the tool bar use this.
+
+   5 means to never call x_set_window_size.  change_frame_size uses
+     this.
+
+   Note that even when x_set_window_size is not called, individual
+   windows may have to be resized (via `window--sanitize-window-sizes')
+   in order to support minimum size constraints.
+
+   PRETEND is as for change_frame_size.  PARAMETER, if non-nil, is the
+   symbol of the parameter changed (like `menu-bar-lines', `font', ...).
+   This is passed on to frame_inhibit_resize to let the latter decide on
+   a case-by-case basis whether the frame may be resized externally.  */
+void
+adjust_frame_size (struct frame *f, int new_width, int new_height, int inhibit,
+                  bool pretend, Lisp_Object parameter)
+{
+  int unit_width = FRAME_COLUMN_WIDTH (f);
+  int unit_height = FRAME_LINE_HEIGHT (f);
+  int old_pixel_width = FRAME_PIXEL_WIDTH (f);
+  int old_pixel_height = FRAME_PIXEL_HEIGHT (f);
+  int new_pixel_width, new_pixel_height;
+  /* The following two values are calculated from the old frame pixel
+     sizes and any "new" settings for tool bar, menu bar and internal
+     borders.  We do it this way to detect whether we have to call
+     x_set_window_size as consequence of the new settings.  */
+  int windows_width = FRAME_WINDOWS_WIDTH (f);
+  int windows_height = FRAME_WINDOWS_HEIGHT (f);
+  int min_windows_width, min_windows_height;
+  /* These are a bit tedious, maybe we should use a macro.  */
+  struct window *r = XWINDOW (FRAME_ROOT_WINDOW (f));
+  int old_windows_width = WINDOW_PIXEL_WIDTH (r);
+  int old_windows_height
+    = (WINDOW_PIXEL_HEIGHT (r)
+       + (FRAME_HAS_MINIBUF_P (f)
+         ? WINDOW_PIXEL_HEIGHT (XWINDOW (FRAME_MINIBUF_WINDOW (f)))
+         : 0));
+  int new_windows_width, new_windows_height;
+  int old_text_width = FRAME_TEXT_WIDTH (f);
+  int old_text_height = FRAME_TEXT_HEIGHT (f);
+  /* If a size is < 0 use the old value.  */
+  int new_text_width = (new_width >= 0) ? new_width : old_text_width;
+  int new_text_height = (new_height >= 0) ? new_height : old_text_height;
+  int new_cols, new_lines;
+  bool inhibit_horizontal, inhibit_vertical;
+  Lisp_Object frame;
+
+  XSETFRAME (frame, f);
+  /* The following two values are calculated from the old window body
+     sizes and any "new" settings for scroll bars, dividers, fringes and
+     margins (though the latter should have been processed already).  */
+  min_windows_width = frame_windows_min_size (frame, Qt, Qt);
+  min_windows_height = frame_windows_min_size (frame, Qnil, Qt);
+
+  if (inhibit >= 2 && inhibit <= 4)
+    /* If INHIBIT is in [2..4] inhibit if the "old" window sizes stay
+       within the limits and either frame_inhibit_resize tells us to do
+       so or INHIBIT equals 4.  */
+    {
+      inhibit_horizontal = ((windows_width >= min_windows_width
+                            && (inhibit == 4
+                                || frame_inhibit_resize (f, true, parameter)))
+                           ? true : false);
+      inhibit_vertical = ((windows_height >= min_windows_height
+                          && (inhibit == 4
+                              || frame_inhibit_resize (f, false, parameter)))
+                         ? true : false);
+    }
+  else
+    /* Otherwise inhibit if INHIBIT equals 5.  */
+    inhibit_horizontal = inhibit_vertical = inhibit == 5;
+
+  new_pixel_width = ((inhibit_horizontal && (inhibit < 5))
+                    ? old_pixel_width
+                    : max (FRAME_TEXT_TO_PIXEL_WIDTH (f, new_text_width),
+                           min_windows_width
+                           + 2 * FRAME_INTERNAL_BORDER_WIDTH (f)));
+  new_windows_width = new_pixel_width - 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
+  new_text_width = FRAME_PIXEL_TO_TEXT_WIDTH (f, new_pixel_width);
+  new_cols = new_text_width / unit_width;
+
+  new_pixel_height = ((inhibit_vertical && (inhibit < 5))
+                     ? old_pixel_height
+                     : max (FRAME_TEXT_TO_PIXEL_HEIGHT (f, new_text_height),
+                            min_windows_height
+                            + FRAME_TOP_MARGIN_HEIGHT (f)
+                            + 2 * FRAME_INTERNAL_BORDER_WIDTH (f)));
+  new_windows_height = (new_pixel_height
+                       - FRAME_TOP_MARGIN_HEIGHT (f)
+                       - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
+  new_text_height = FRAME_PIXEL_TO_TEXT_HEIGHT (f, new_pixel_height);
+  new_lines = new_text_height / unit_height;
+
+#ifdef HAVE_WINDOW_SYSTEM
+  if (FRAME_WINDOW_P (f)
+      && f->can_x_set_window_size
+      && ((!inhibit_horizontal
+          && (new_pixel_width != old_pixel_width
+              || inhibit == 0 || inhibit == 2))
+         || (!inhibit_vertical
+             && (new_pixel_height != old_pixel_height
+                 || inhibit == 0 || inhibit == 2))))
+    /* We are either allowed to change the frame size or the minimum
+       sizes request such a change.  Do not care for fixing minimum
+       sizes here, we do that eventually when we're called from
+       change_frame_size.  */
+    {
+      /* Make sure we respect fullheight and fullwidth.  */
+      if (inhibit_horizontal)
+       new_text_width = old_text_width;
+      else if (inhibit_vertical)
+       new_text_height = old_text_height;
+
+      x_set_window_size (f, 0, new_text_width, new_text_height, 1);
+      f->resized_p = true;
+
+      return;
+    }
+#endif
+
+  if (new_text_width == old_text_width
+      && new_text_height == old_text_height
+      && new_windows_width == old_windows_width
+      && new_windows_height == old_windows_height
+      && new_pixel_width == old_pixel_width
+      && new_pixel_height == old_pixel_height)
+    /* No change.  Sanitize window sizes and return.  */
+    {
+      sanitize_window_sizes (frame, Qt);
+      sanitize_window_sizes (frame, Qnil);
+
+      return;
+    }
+
+  block_input ();
+
+#ifdef MSDOS
+  /* We only can set screen dimensions to certain values supported
+     by our video hardware.  Try to find the smallest size greater
+     or equal to the requested dimensions.  */
+  dos_set_window_size (&new_lines, &new_cols);
+#endif
+
+  if (new_windows_width != old_windows_width)
+    {
+      resize_frame_windows (f, new_windows_width, 1, 1);
+
+      /* MSDOS frames cannot PRETEND, as they change frame size by
+        manipulating video hardware.  */
+      if ((FRAME_TERMCAP_P (f) && !pretend) || FRAME_MSDOS_P (f))
+       FrameCols (FRAME_TTY (f)) = new_cols;
+
+#if defined (HAVE_WINDOW_SYSTEM) && ! defined (USE_GTK) && ! defined (HAVE_NS)
+      if (WINDOWP (f->tool_bar_window))
+       {
+         XWINDOW (f->tool_bar_window)->pixel_width = new_windows_width;
+         XWINDOW (f->tool_bar_window)->total_cols
+           = new_windows_width / unit_width;
+       }
+#endif
+    }
+
+  if (new_windows_height != old_windows_height
+      /* When the top margin has changed we have to recalculate the top
+        edges of all windows.  No such calculation is necessary for the
+        left edges.  */
+      || WINDOW_TOP_PIXEL_EDGE (r) != FRAME_TOP_MARGIN_HEIGHT (f))
+    {
+      resize_frame_windows (f, new_windows_height, 0, 1);
+
+      /* MSDOS frames cannot PRETEND, as they change frame size by
+        manipulating video hardware.  */
+      if ((FRAME_TERMCAP_P (f) && !pretend) || FRAME_MSDOS_P (f))
+       FrameRows (FRAME_TTY (f)) = new_lines + FRAME_TOP_MARGIN (f);
+    }
+
+  /* Assign new sizes.  */
+  FRAME_TEXT_WIDTH (f) = new_text_width;
+  FRAME_TEXT_HEIGHT (f) = new_text_height;
+  FRAME_PIXEL_WIDTH (f) = new_pixel_width;
+  FRAME_PIXEL_HEIGHT (f) = new_pixel_height;
+  SET_FRAME_COLS (f, new_cols);
+  SET_FRAME_LINES (f, new_lines);
+
+  {
+    struct window *w = XWINDOW (FRAME_SELECTED_WINDOW (f));
+    int text_area_x, text_area_y, text_area_width, text_area_height;
+
+    window_box (w, TEXT_AREA, &text_area_x, &text_area_y, &text_area_width,
+               &text_area_height);
+    if (w->cursor.x >= text_area_x + text_area_width)
+      w->cursor.hpos = w->cursor.x = 0;
+    if (w->cursor.y >= text_area_y + text_area_height)
+      w->cursor.vpos = w->cursor.y = 0;
+  }
+
+  /* Sanitize window sizes.  */
+  sanitize_window_sizes (frame, Qt);
+  sanitize_window_sizes (frame, Qnil);
+
+  adjust_frame_glyphs (f);
+  calculate_costs (f);
+  SET_FRAME_GARBAGED (f);
+
+  /* A frame was "resized" if one of its pixelsizes changed, even if its
+     X window wasn't resized at all.  */
+  f->resized_p = (new_pixel_width != old_pixel_width
+                 || new_pixel_height != old_pixel_height);
+
+  unblock_input ();
+
+  run_window_configuration_change_hook (f);
+}
+
+
 struct frame *
 make_frame (bool mini_p)
 {
@@ -337,9 +595,11 @@ make_frame (bool mini_p)
   f = allocate_frame ();
   XSETFRAME (frame, f);
 
+#ifdef USE_GTK
   /* Initialize Lisp data.  Note that allocate_frame initializes all
      Lisp data to nil, so do it only for slots which should not be nil.  */
   fset_tool_bar_position (f, Qtop);
+#endif
 
   /* Initialize non-Lisp data.  Note that allocate_frame zeroes out all
      non-Lisp data, so do it only for slots which should not be zero.
@@ -348,11 +608,17 @@ make_frame (bool mini_p)
   f->wants_modeline = true;
   f->redisplay = true;
   f->garbaged = true;
-  f->vertical_scroll_bar_type = vertical_scroll_bar_none;
+  f->can_x_set_window_size = false;
+  f->can_run_window_configuration_change_hook = false;
   f->column_width = 1;  /* !FRAME_WINDOW_P value.  */
   f->line_height = 1;  /* !FRAME_WINDOW_P value.  */
 #ifdef HAVE_WINDOW_SYSTEM
+  f->vertical_scroll_bar_type = vertical_scroll_bar_none;
+  f->horizontal_scroll_bars = false;
   f->want_fullscreen = FULLSCREEN_NONE;
+#if ! defined (USE_GTK) && ! defined (HAVE_NS)
+  f->last_tool_bar_item = -1;
+#endif
 #endif
 
   root_window = make_window ();
@@ -378,10 +644,10 @@ make_frame (bool mini_p)
 
   /* 10 is arbitrary,
      just so that there is "something there."
-     Correct size will be set up later with change_frame_size.  */
+     Correct size will be set up later with adjust_frame_size.  */
 
   SET_FRAME_COLS (f, 10);
-  FRAME_LINES (f) = 10;
+  SET_FRAME_LINES (f, 10);
   SET_FRAME_WIDTH (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f));
   SET_FRAME_HEIGHT (f, FRAME_LINES (f) * FRAME_LINE_HEIGHT (f));
 
@@ -419,11 +685,15 @@ make_frame (bool mini_p)
   }
 
   if (mini_p)
-    set_window_buffer (mini_window,
-                      (NILP (Vminibuffer_list)
-                       ? get_minibuffer (0)
-                       : Fcar (Vminibuffer_list)),
-                      0, 0);
+    {
+      set_window_buffer (mini_window,
+                        (NILP (Vminibuffer_list)
+                         ? get_minibuffer (0)
+                         : Fcar (Vminibuffer_list)),
+                        0, 0);
+      /* No horizontal scroll bars in minibuffers.  */
+      wset_horizontal_scroll_bar (mw, Qnil);
+    }
 
   fset_root_window (f, root_window);
   fset_selected_window (f, root_window);
@@ -567,7 +837,10 @@ make_initial_frame (void)
   FRAME_FOREGROUND_PIXEL (f) = FACE_TTY_DEFAULT_FG_COLOR;
   FRAME_BACKGROUND_PIXEL (f) = FACE_TTY_DEFAULT_BG_COLOR;
 
-  FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = vertical_scroll_bar_none;
+#ifdef HAVE_WINDOW_SYSTEM
+  f->vertical_scroll_bar_type = vertical_scroll_bar_none;
+  f->horizontal_scroll_bars = false;
+#endif
 
   /* The default value of menu-bar-mode is t.  */
   set_menu_bar_lines (f, make_number (1), Qnil);
@@ -617,9 +890,15 @@ make_terminal_frame (struct terminal *terminal)
   FRAME_BACKGROUND_PIXEL (f) = FACE_TTY_DEFAULT_BG_COLOR;
 #endif /* not MSDOS */
 
-  FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = vertical_scroll_bar_none;
+#ifdef HAVE_WINDOW_SYSTEM
+  f->vertical_scroll_bar_type = vertical_scroll_bar_none;
+  f->horizontal_scroll_bars = false;
+#endif
+
   FRAME_MENU_BAR_LINES (f) = NILP (Vmenu_bar_mode) ? 0 : 1;
+  FRAME_LINES (f) = FRAME_LINES (f) - FRAME_MENU_BAR_LINES (f);
   FRAME_MENU_BAR_HEIGHT (f) = FRAME_MENU_BAR_LINES (f) * FRAME_LINE_HEIGHT (f);
+  FRAME_TEXT_HEIGHT (f) = FRAME_TEXT_HEIGHT (f) - FRAME_MENU_BAR_HEIGHT (f);
 
   /* Set the top frame to the newly created frame.  */
   if (FRAMEP (FRAME_TTY (f)->top_frame)
@@ -701,7 +980,7 @@ affects all frames on the same terminal device.  */)
     if (CONSP (terminal))
       {
         terminal = XCDR (terminal);
-        t = get_terminal (terminal, 1);
+        t = decode_live_terminal (terminal);
       }
 #ifdef MSDOS
     if (t && t != the_only_display_info.terminal)
@@ -716,22 +995,24 @@ affects all frames on the same terminal device.  */)
     {
       char *name = 0, *type = 0;
       Lisp_Object tty, tty_type;
+      USE_SAFE_ALLOCA;
 
       tty = get_future_frame_param
         (Qtty, parms, (FRAME_TERMCAP_P (XFRAME (selected_frame))
                        ? FRAME_TTY (XFRAME (selected_frame))->name
                        : NULL));
       if (!NILP (tty))
-       name = xlispstrdupa (tty);
+       SAFE_ALLOCA_STRING (name, tty);
 
       tty_type = get_future_frame_param
         (Qtty_type, parms, (FRAME_TERMCAP_P (XFRAME (selected_frame))
                             ? FRAME_TTY (XFRAME (selected_frame))->type
                             : NULL));
       if (!NILP (tty_type))
-       type = xlispstrdupa (tty_type);
+       SAFE_ALLOCA_STRING (type, tty_type);
 
       t = init_tty (name, type, 0); /* Errors are not fatal.  */
+      SAFE_FREE ();
     }
 
   f = make_terminal_frame (t);
@@ -739,7 +1020,7 @@ affects all frames on the same terminal device.  */)
   {
     int width, height;
     get_tty_size (fileno (FRAME_TTY (f)->input), &width, &height);
-    change_frame_size (f, width, height, 0, 0, 0, 0);
+    adjust_frame_size (f, width, height - FRAME_MENU_BAR_LINES (f), 5, 0, Qnil);
   }
 
   adjust_frame_glyphs (f);
@@ -870,8 +1151,8 @@ do_switch_frame (Lisp_Object frame, int track, int for_deletion, Lisp_Object nor
             frame's data.  */
          if (FRAME_COLS (f) != FrameCols (tty))
            FrameCols (tty) = FRAME_COLS (f);
-         if (FRAME_LINES (f) != FrameRows (tty))
-           FrameRows (tty) = FRAME_LINES (f);
+         if (FRAME_TOTAL_LINES (f) != FrameRows (tty))
+           FrameRows (tty) = FRAME_TOTAL_LINES (f);
        }
       tty->top_frame = frame;
     }
@@ -1365,7 +1646,9 @@ delete_frame (Lisp_Object frame, Lisp_Object force)
   fset_buried_buffer_list (f, Qnil);
 
   free_font_driver_list (f);
+#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI)
   xfree (f->namebuf);
+#endif
   xfree (f->decode_mode_spec_buffer);
   xfree (FRAME_INSERT_COST (f));
   xfree (FRAME_DELETEN_COST (f));
@@ -1608,6 +1891,42 @@ and nil for X and Y.  */)
   RETURN_UNGCPRO (retval);
 }
 
+#ifdef HAVE_WINDOW_SYSTEM
+
+/* On frame F, convert character coordinates X and Y to pixel
+   coordinates *PIX_X and *PIX_Y.  */
+
+static void
+frame_char_to_pixel_position (struct frame *f, int x, int y,
+                             int *pix_x, int *pix_y)
+{
+  *pix_x = FRAME_COL_TO_PIXEL_X (f, x) + FRAME_COLUMN_WIDTH (f) / 2;
+  *pix_y = FRAME_LINE_TO_PIXEL_Y (f, y) + FRAME_LINE_HEIGHT (f) / 2;
+
+  if (*pix_x < 0)
+    *pix_x = 0;
+  if (*pix_x > FRAME_PIXEL_WIDTH (f))
+    *pix_x = FRAME_PIXEL_WIDTH (f);
+
+  if (*pix_y < 0)
+    *pix_y = 0;
+  if (*pix_y > FRAME_PIXEL_HEIGHT (f))
+    *pix_y = FRAME_PIXEL_HEIGHT (f);
+}
+
+/* On frame F, reposition mouse pointer to character coordinates X and Y.  */
+
+static void
+frame_set_mouse_position (struct frame *f, int x, int y)
+{
+  int pix_x, pix_y;
+
+  frame_char_to_pixel_position (f, x, y, &pix_x, &pix_y);
+  frame_set_mouse_pixel_position (f, pix_x, pix_y);
+}
+
+#endif /* HAVE_WINDOW_SYSTEM */
+
 DEFUN ("set-mouse-position", Fset_mouse_position, Sset_mouse_position, 3, 3, 0,
        doc: /* Move the mouse pointer to the center of character cell (X,Y) in FRAME.
 Coordinates are relative to the frame, not a window,
@@ -1633,7 +1952,7 @@ before calling this function on it, like this.
 #ifdef HAVE_WINDOW_SYSTEM
   if (FRAME_WINDOW_P (XFRAME (frame)))
     /* Warping the mouse will cause enternotify and focus events.  */
-    x_set_mouse_position (XFRAME (frame), XINT (x), XINT (y));
+    frame_set_mouse_position (XFRAME (frame), XINT (x), XINT (y));
 #else
 #if defined (MSDOS)
   if (FRAME_MSDOS_P (XFRAME (frame)))
@@ -1674,7 +1993,7 @@ before calling this function on it, like this.
 #ifdef HAVE_WINDOW_SYSTEM
   if (FRAME_WINDOW_P (XFRAME (frame)))
     /* Warping the mouse will cause enternotify and focus events.  */
-    x_set_mouse_pixel_position (XFRAME (frame), XINT (x), XINT (y));
+    frame_set_mouse_pixel_position (XFRAME (frame), XINT (x), XINT (y));
 #else
 #if defined (MSDOS)
   if (FRAME_MSDOS_P (XFRAME (frame)))
@@ -1941,25 +2260,27 @@ If there is no window system support, this function does nothing.  */)
   return Qnil;
 }
 
-\f
-/* Return the value of frame parameter PROP in frame FRAME.  */
-
-#ifdef HAVE_WINDOW_SYSTEM
-#if !HAVE_NS && !HAVE_NTGUI
-static
-#endif
-Lisp_Object
-get_frame_param (register struct frame *frame, Lisp_Object prop)
+DEFUN ("frame-can-run-window-configuration-change-hook",
+       Fcan_run_window_configuration_change_hook,
+       Scan_run_window_configuration_change_hook, 2, 2, 0,
+       doc: /* Whether `window-configuration-change-hook' is run for frame FRAME.
+FRAME nil means use the selected frame.  Second argument ALLOW non-nil
+means functions on `window-configuration-change-hook' are called
+whenever the window configuration of FRAME changes.  ALLOW nil means
+these functions are not called.
+
+This function is currently called by `face-set-after-frame-default' only
+and should be otherwise used with utter care to avoid that running
+functions on `window-configuration-change-hook' is impeded forever.  */)
+  (Lisp_Object frame, Lisp_Object allow)
 {
-  register Lisp_Object tem;
+  struct frame *f = decode_live_frame (frame);
 
-  tem = Fassq (prop, frame->param_alist);
-  if (EQ (tem, Qnil))
-    return tem;
-  return Fcdr (tem);
+  f->can_run_window_configuration_change_hook = NILP (allow) ? false : true;
+  return Qnil;
 }
-#endif
 
+\f
 /* Discard BUFFER from the buffer-list and buried-buffer-list of each frame.  */
 
 void
@@ -2043,20 +2364,6 @@ set_term_frame_name (struct frame *f, Lisp_Object name)
   update_mode_lines = 16;
 }
 
-#ifdef HAVE_NTGUI
-void
-set_frame_param (struct frame *f, Lisp_Object prop, Lisp_Object val)
-{
-  register Lisp_Object old_alist_elt;
-
-  old_alist_elt = Fassq (prop, f->param_alist);
-  if (EQ (old_alist_elt, Qnil))
-    fset_param_alist (f, Fcons (Fcons (prop, val), f->param_alist));
-  else
-    Fsetcdr (old_alist_elt, val);
-}
-#endif
-
 void
 store_frame_param (struct frame *f, Lisp_Object prop, Lisp_Object val)
 {
@@ -2148,6 +2455,18 @@ store_frame_param (struct frame *f, Lisp_Object prop, Lisp_Object val)
     }
 }
 
+/* Return color matches UNSPEC on frame F or nil if UNSPEC
+   is not an unspecified foreground or background color.  */
+
+static Lisp_Object
+frame_unspecified_color (struct frame *f, Lisp_Object unspec)
+{
+  return (!strncmp (SSDATA (unspec), unspecified_bg, SBYTES (unspec))
+         ? tty_color_name (f, FRAME_BACKGROUND_PIXEL (f))
+         : (!strncmp (SSDATA (unspec), unspecified_fg, SBYTES (unspec))
+            ? tty_color_name (f, FRAME_FOREGROUND_PIXEL (f)) : Qnil));
+}
+
 DEFUN ("frame-parameters", Fframe_parameters, Sframe_parameters, 0, 1, 0,
        doc: /* Return the parameters-alist of frame FRAME.
 It is a list of elements of the form (PARM . VALUE), where PARM is a symbol.
@@ -2168,8 +2487,6 @@ If FRAME is omitted or nil, return information on the currently selected frame.
 
   if (!FRAME_WINDOW_P (f))
     {
-      int fg = FRAME_FOREGROUND_PIXEL (f);
-      int bg = FRAME_BACKGROUND_PIXEL (f);
       Lisp_Object elt;
 
       /* If the frame's parameter alist says the colors are
@@ -2178,31 +2495,23 @@ If FRAME is omitted or nil, return information on the currently selected frame.
       elt = Fassq (Qforeground_color, alist);
       if (CONSP (elt) && STRINGP (XCDR (elt)))
        {
-         if (strncmp (SSDATA (XCDR (elt)),
-                      unspecified_bg,
-                      SCHARS (XCDR (elt))) == 0)
-           store_in_alist (&alist, Qforeground_color, tty_color_name (f, bg));
-         else if (strncmp (SSDATA (XCDR (elt)),
-                           unspecified_fg,
-                           SCHARS (XCDR (elt))) == 0)
-           store_in_alist (&alist, Qforeground_color, tty_color_name (f, fg));
+         elt = frame_unspecified_color (f, XCDR (elt));
+         if (!NILP (elt))
+           store_in_alist (&alist, Qforeground_color, elt);
        }
       else
-       store_in_alist (&alist, Qforeground_color, tty_color_name (f, fg));
+       store_in_alist (&alist, Qforeground_color,
+                       tty_color_name (f, FRAME_FOREGROUND_PIXEL (f)));
       elt = Fassq (Qbackground_color, alist);
       if (CONSP (elt) && STRINGP (XCDR (elt)))
        {
-         if (strncmp (SSDATA (XCDR (elt)),
-                      unspecified_fg,
-                      SCHARS (XCDR (elt))) == 0)
-           store_in_alist (&alist, Qbackground_color, tty_color_name (f, fg));
-         else if (strncmp (SSDATA (XCDR (elt)),
-                           unspecified_bg,
-                           SCHARS (XCDR (elt))) == 0)
-           store_in_alist (&alist, Qbackground_color, tty_color_name (f, bg));
+         elt = frame_unspecified_color (f, XCDR (elt));
+         if (!NILP (elt))
+           store_in_alist (&alist, Qbackground_color, elt);
        }
       else
-       store_in_alist (&alist, Qbackground_color, tty_color_name (f, bg));
+       store_in_alist (&alist, Qbackground_color,
+                       tty_color_name (f, FRAME_BACKGROUND_PIXEL (f)));
       store_in_alist (&alist, intern ("font"),
                      build_string (FRAME_MSDOS_P (f)
                                    ? "ms-dos"
@@ -2282,29 +2591,7 @@ If FRAME is nil, describe the currently selected frame.  */)
                 important when param_alist's notion of colors is
                 "unspecified".  We need to do the same here.  */
              if (STRINGP (value) && !FRAME_WINDOW_P (f))
-               {
-                 const char *color_name;
-                 ptrdiff_t csz;
-
-                 if (EQ (parameter, Qbackground_color))
-                   {
-                     color_name = SSDATA (value);
-                     csz = SCHARS (value);
-                     if (strncmp (color_name, unspecified_bg, csz) == 0)
-                       value = tty_color_name (f, FRAME_BACKGROUND_PIXEL (f));
-                     else if (strncmp (color_name, unspecified_fg, csz) == 0)
-                       value = tty_color_name (f, FRAME_FOREGROUND_PIXEL (f));
-                   }
-                 else if (EQ (parameter, Qforeground_color))
-                   {
-                     color_name = SSDATA (value);
-                     csz = SCHARS (value);
-                     if (strncmp (color_name, unspecified_fg, csz) == 0)
-                       value = tty_color_name (f, FRAME_FOREGROUND_PIXEL (f));
-                     else if (strncmp (color_name, unspecified_bg, csz) == 0)
-                       value = tty_color_name (f, FRAME_BACKGROUND_PIXEL (f));
-                   }
-               }
+               value = frame_unspecified_color (f, value);
            }
          else
            value = Fcdr (Fassq (parameter, Fframe_parameters (frame)));
@@ -2455,7 +2742,7 @@ to `frame-height'). */)
     return make_number (FRAME_PIXEL_HEIGHT (f));
   else
 #endif
-    return make_number (FRAME_LINES (f));
+    return make_number (FRAME_TOTAL_LINES (f));
 }
 
 DEFUN ("frame-pixel-width", Fframe_pixel_width,
@@ -2472,7 +2759,7 @@ If FRAME is omitted or nil, the selected frame is used.  */)
     return make_number (FRAME_PIXEL_WIDTH (f));
   else
 #endif
-    return make_number (FRAME_COLS (f));
+    return make_number (FRAME_TOTAL_COLS (f));
 }
 
 DEFUN ("tool-bar-pixel-width", Ftool_bar_pixel_width,
@@ -2507,12 +2794,19 @@ DEFUN ("frame-text-lines", Fframe_text_lines, Sframe_text_lines, 0, 1, 0,
 }
 
 DEFUN ("frame-total-cols", Fframe_total_cols, Sframe_total_cols, 0, 1, 0,
-       doc: /* Return total columns of FRAME.  */)
+       doc: /* Return number of total columns of FRAME.  */)
   (Lisp_Object frame)
 {
   return make_number (FRAME_TOTAL_COLS (decode_any_frame (frame)));
 }
 
+DEFUN ("frame-total-lines", Fframe_total_lines, Sframe_total_lines, 0, 1, 0,
+       doc: /* Return number of total lines of FRAME.  */)
+  (Lisp_Object frame)
+{
+  return make_number (FRAME_TOTAL_LINES (decode_any_frame (frame)));
+}
+
 DEFUN ("frame-text-width", Fframe_text_width, Sframe_text_width, 0, 1, 0,
        doc: /* Return text area width of FRAME in pixels.  */)
   (Lisp_Object frame)
@@ -2534,6 +2828,13 @@ DEFUN ("frame-scroll-bar-width", Fscroll_bar_width, Sscroll_bar_width, 0, 1, 0,
   return make_number (FRAME_SCROLL_BAR_AREA_WIDTH (decode_any_frame (frame)));
 }
 
+DEFUN ("frame-scroll-bar-height", Fscroll_bar_height, Sscroll_bar_height, 0, 1, 0,
+       doc: /* Return scroll bar height of FRAME in pixels.  */)
+  (Lisp_Object frame)
+{
+  return make_number (FRAME_SCROLL_BAR_AREA_HEIGHT (decode_any_frame (frame)));
+}
+
 DEFUN ("frame-fringe-width", Ffringe_width, Sfringe_width, 0, 1, 0,
        doc: /* Return fringe width of FRAME in pixels.  */)
   (Lisp_Object frame)
@@ -2561,110 +2862,84 @@ DEFUN ("frame-bottom-divider-width", Fbottom_divider_width, Sbottom_divider_widt
 {
   return make_number (FRAME_BOTTOM_DIVIDER_WIDTH (decode_any_frame (frame)));
 }
-\f
+
 DEFUN ("set-frame-height", Fset_frame_height, Sset_frame_height, 2, 4, 0,
-       doc: /* Specify that the frame FRAME has HEIGHT text lines.
+       doc: /* Set height of frame FRAME to HEIGHT lines.
 Optional third arg PRETEND non-nil means that redisplay should use
 HEIGHT lines but that the idea of the actual height of the frame should
-not be changed.  Optional fourth argument PIXELWISE non-nil means that
-FRAME should be HEIGHT pixels high.  */)
+not be changed.
+
+Optional fourth argument PIXELWISE non-nil means that FRAME should be
+HEIGHT pixels high.  Note: When `frame-resize-pixelwise' is nil, some
+window managers may refuse to honor a HEIGHT that is not an integer
+multiple of the default frame font height.  */)
   (Lisp_Object frame, Lisp_Object height, Lisp_Object pretend, Lisp_Object pixelwise)
 {
-  register struct frame *f = decode_live_frame (frame);
+  struct frame *f = decode_live_frame (frame);
+  int pixel_height;
 
   CHECK_TYPE_RANGED_INTEGER (int, height);
 
-  /* I think this should be done with a hook.  */
-#ifdef HAVE_WINDOW_SYSTEM
-  if (FRAME_WINDOW_P (f))
-    {
-      if (NILP (pixelwise))
-       {
-         if (XINT (height) != FRAME_LINES (f))
-           x_set_window_size (f, 1, FRAME_COLS (f), XINT (height), 0);
+  pixel_height = (!NILP (pixelwise)
+                 ? XINT (height)
+                 : XINT (height) * FRAME_LINE_HEIGHT (f));
+  if (pixel_height != FRAME_TEXT_HEIGHT (f))
+    adjust_frame_size (f, -1, pixel_height, 1, !NILP (pretend), Qheight);
 
-         do_pending_window_change (0);
-       }
-      else if (XINT (height) != FRAME_TEXT_HEIGHT (f))
-       {
-         x_set_window_size (f, 1, FRAME_TEXT_WIDTH (f), XINT (height), 1);
-         do_pending_window_change (0);
-       }
-    }
-  else
-#endif
-    change_frame_size (f, 0, XINT (height), !NILP (pretend), 0, 0,
-                      NILP (pixelwise) ? 0 : 1);
   return Qnil;
 }
 
 DEFUN ("set-frame-width", Fset_frame_width, Sset_frame_width, 2, 4, 0,
-       doc: /* Specify that the frame FRAME has WIDTH columns.
+       doc: /* Set width of frame FRAME to WIDTH columns.
 Optional third arg PRETEND non-nil means that redisplay should use WIDTH
 columns but that the idea of the actual width of the frame should not
-be changed.  Optional fourth argument PIXELWISE non-nil means that FRAME
-should be WIDTH pixels wide.  */)
+be changed.
+
+Optional fourth argument PIXELWISE non-nil means that FRAME should be
+WIDTH pixels wide.  Note: When `frame-resize-pixelwise' is nil, some
+window managers may refuse to honor a WIDTH that is not an integer
+multiple of the default frame font width.  */)
   (Lisp_Object frame, Lisp_Object width, Lisp_Object pretend, Lisp_Object pixelwise)
 {
-  register struct frame *f = decode_live_frame (frame);
+  struct frame *f = decode_live_frame (frame);
+  int pixel_width;
 
   CHECK_TYPE_RANGED_INTEGER (int, width);
 
-  /* I think this should be done with a hook.  */
-#ifdef HAVE_WINDOW_SYSTEM
-  if (FRAME_WINDOW_P (f))
-    {
-      if (NILP (pixelwise))
-       {
-         if (XINT (width) != FRAME_COLS (f))
-           x_set_window_size (f, 1, XINT (width), FRAME_LINES (f), 0);
+  pixel_width = (!NILP (pixelwise)
+                ? XINT (width)
+                : XINT (width) * FRAME_COLUMN_WIDTH (f));
+  if (pixel_width != FRAME_TEXT_WIDTH (f))
+    adjust_frame_size (f, pixel_width, -1, 1, !NILP (pretend), Qwidth);
 
-         do_pending_window_change (0);
-       }
-      else if (XINT (width) != FRAME_TEXT_WIDTH (f))
-       {
-         x_set_window_size (f, 1, XINT (width), FRAME_TEXT_HEIGHT (f), 1);
-         do_pending_window_change (0);
-       }
-    }
-  else
-#endif
-    change_frame_size (f, XINT (width), 0, !NILP (pretend), 0, 0,
-                      NILP (pixelwise) ? 0 : 1);
   return Qnil;
 }
 
 DEFUN ("set-frame-size", Fset_frame_size, Sset_frame_size, 3, 4, 0,
-       doc: /* Sets size of FRAME to WIDTH by HEIGHT, measured in characters.
-Optional argument PIXELWISE non-nil means to measure in pixels.  */)
+       doc: /* Set size of FRAME to WIDTH by HEIGHT, measured in characters.
+Optional argument PIXELWISE non-nil means to measure in pixels.  Note:
+When `frame-resize-pixelwise' is nil, some window managers may refuse to
+honor a WIDTH that is not an integer multiple of the default frame font
+width or a HEIGHT that is not an integer multiple of the default frame
+font height.  */)
   (Lisp_Object frame, Lisp_Object width, Lisp_Object height, Lisp_Object pixelwise)
 {
-  register struct frame *f = decode_live_frame (frame);
+  struct frame *f = decode_live_frame (frame);
+  int pixel_width, pixel_height;
 
   CHECK_TYPE_RANGED_INTEGER (int, width);
   CHECK_TYPE_RANGED_INTEGER (int, height);
 
-  /* I think this should be done with a hook.  */
-#ifdef HAVE_WINDOW_SYSTEM
-  if (FRAME_WINDOW_P (f))
-    {
-      if (!NILP (pixelwise)
-         ? (XINT (width) != FRAME_TEXT_WIDTH (f)
-            || XINT (height) != FRAME_TEXT_HEIGHT (f)
-            || f->new_height || f->new_width)
-         : (XINT (width) != FRAME_COLS (f)
-            || XINT (height) != FRAME_LINES (f)
-            || f->new_height || f->new_width))
-       {
-         x_set_window_size (f, 1, XINT (width), XINT (height),
-                            NILP (pixelwise) ? 0 : 1);
-         do_pending_window_change (0);
-       }
-    }
-  else
-#endif
-    change_frame_size (f, XINT (width), XINT (height), 0, 0, 0,
-                      NILP (pixelwise) ? 0 : 1);
+  pixel_width = (!NILP (pixelwise)
+                ? XINT (width)
+                : XINT (width) * FRAME_COLUMN_WIDTH (f));
+  pixel_height = (!NILP (pixelwise)
+                 ? XINT (height)
+                 : XINT (height) * FRAME_LINE_HEIGHT (f));
+
+  if (pixel_width != FRAME_TEXT_WIDTH (f)
+      || pixel_height != FRAME_TEXT_HEIGHT (f))
+    adjust_frame_size (f, pixel_width, pixel_height, 1, 0, Qsize);
 
   return Qnil;
 }
@@ -2729,9 +3004,11 @@ static const struct frame_parm_table frame_parms[] =
   {"mouse-color",              &Qmouse_color},
   {"name",                     &Qname},
   {"scroll-bar-width",         &Qscroll_bar_width},
+  {"scroll-bar-height",                &Qscroll_bar_height},
   {"title",                    &Qtitle},
   {"unsplittable",             &Qunsplittable},
   {"vertical-scroll-bars",     &Qvertical_scroll_bars},
+  {"horizontal-scroll-bars",   &Qhorizontal_scroll_bars},
   {"visibility",               &Qvisibility},
   {"tool-bar-lines",           &Qtool_bar_lines},
   {"scroll-bar-foreground",    &Qscroll_bar_foreground},
@@ -2748,52 +3025,6 @@ static const struct frame_parm_table frame_parms[] =
   {"tool-bar-position",                &Qtool_bar_position},
 };
 
-#ifdef HAVE_NTGUI
-
-/* Calculate fullscreen size.  Return in *TOP_POS and *LEFT_POS the
-   wanted positions of the WM window (not Emacs window).
-   Return in *WIDTH and *HEIGHT the wanted width and height of Emacs
-   window (FRAME_X_WINDOW).
- */
-
-void
-x_fullscreen_adjust (struct frame *f, int *width, int *height, int *top_pos, int *left_pos)
-{
-  int newwidth = FRAME_COLS (f);
-  int newheight = FRAME_LINES (f);
-  Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
-
-  *top_pos = f->top_pos;
-  *left_pos = f->left_pos;
-
-  if (f->want_fullscreen & FULLSCREEN_HEIGHT)
-    {
-      int ph;
-
-      ph = x_display_pixel_height (dpyinfo);
-      newheight = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, ph);
-      ph = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, newheight) - f->y_pixels_diff;
-      newheight = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, ph);
-      *top_pos = 0;
-    }
-
-  if (f->want_fullscreen & FULLSCREEN_WIDTH)
-    {
-      int pw;
-
-      pw = x_display_pixel_width (dpyinfo);
-      newwidth = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, pw);
-      pw = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, newwidth) - f->x_pixels_diff;
-      newwidth = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, pw);
-      *left_pos = 0;
-    }
-
-  *width = newwidth;
-  *height = newheight;
-}
-
-#endif /* HAVE_NTGUI */
-
 #ifdef HAVE_WINDOW_SYSTEM
 
 /* Change the parameters of frame F as specified by ALIST.
@@ -2810,7 +3041,7 @@ x_set_frame_parameters (struct frame *f, Lisp_Object alist)
   /* If both of these parameters are present, it's more efficient to
      set them both at once.  So we wait until we've looked at the
      entire list before we set them.  */
-  int width = 0, height = 0;
+  int width IF_LINT (= 0), height IF_LINT (= 0);
   bool width_change = 0, height_change = 0;
 
   /* Same here.  */
@@ -2827,14 +3058,14 @@ x_set_frame_parameters (struct frame *f, Lisp_Object alist)
 #ifdef HAVE_X_WINDOWS
   bool icon_left_no_change = 0, icon_top_no_change = 0;
 #endif
-  struct gcpro gcpro1, gcpro2;
 
   i = 0;
   for (tail = alist; CONSP (tail); tail = XCDR (tail))
     i++;
 
-  parms = alloca (i * sizeof *parms);
-  values = alloca (i * sizeof *values);
+  USE_SAFE_ALLOCA;
+  SAFE_ALLOCA_LISP (parms, 2 * i);
+  values = parms + i;
 
   /* Extract parm names and values into those vectors.  */
 
@@ -2851,10 +3082,6 @@ x_set_frame_parameters (struct frame *f, Lisp_Object alist)
   /* TAIL and ALIST are not used again below here.  */
   alist = tail = Qnil;
 
-  GCPRO2 (*parms, *values);
-  gcpro1.nvars = i;
-  gcpro2.nvars = i;
-
   /* There is no need to gcpro LEFT, TOP, ICON_LEFT, or ICON_TOP,
      because their values appear in VALUES and strings are not valid.  */
   top = left = Qunbound;
@@ -2883,8 +3110,7 @@ x_set_frame_parameters (struct frame *f, Lisp_Object alist)
 
              param_index = Fget (prop, Qx_frame_parameter);
              if (NATNUMP (param_index)
-                 && (XFASTINT (param_index)
-                     < sizeof (frame_parms)/sizeof (frame_parms[0]))
+                 && XFASTINT (param_index) < ARRAYELTS (frame_parms)
                   && FRAME_RIF (f)->frame_parm_handlers[XINT (param_index)])
                 (*(FRAME_RIF (f)->frame_parm_handlers[XINT (param_index)])) (f, val, old_value);
            }
@@ -2932,8 +3158,7 @@ x_set_frame_parameters (struct frame *f, Lisp_Object alist)
 
          param_index = Fget (prop, Qx_frame_parameter);
          if (NATNUMP (param_index)
-             && (XFASTINT (param_index)
-                 < sizeof (frame_parms)/sizeof (frame_parms[0]))
+             && XFASTINT (param_index) < ARRAYELTS (frame_parms)
              && FRAME_RIF (f)->frame_parm_handlers[XINT (param_index)])
            (*(FRAME_RIF (f)->frame_parm_handlers[XINT (param_index)])) (f, val, old_value);
        }
@@ -2988,15 +3213,11 @@ x_set_frame_parameters (struct frame *f, Lisp_Object alist)
   {
     Lisp_Object frame;
 
-    /* Make this 1, eventually.  */
-    check_frame_size (f, &width, &height, 1);
-
     XSETFRAME (frame, f);
 
-    if ((width_change || height_change)
-        && (width != FRAME_TEXT_WIDTH (f)
-            || height != FRAME_TEXT_HEIGHT (f)
-            || f->new_height || f->new_width))
+    if ((width_change && width != FRAME_TEXT_WIDTH (f))
+       || (height_change && height != FRAME_TEXT_HEIGHT (f))
+       || f->new_height || f->new_width)
       {
        /* If necessary provide default values for HEIGHT and WIDTH.  Do
           that here since otherwise a size change implied by an
@@ -3089,7 +3310,7 @@ x_set_frame_parameters (struct frame *f, Lisp_Object alist)
 #endif /* HAVE_X_WINDOWS */
   }
 
-  UNGCPRO;
+  SAFE_FREE ();
 }
 
 
@@ -3141,6 +3362,14 @@ x_report_frame_params (struct frame *f, Lisp_Object *alistptr)
                      for non-toolkit scroll bar.
                      ruler-mode.el depends on this.  */
                   : Qnil));
+  store_in_alist (alistptr, Qscroll_bar_height,
+                 (! FRAME_HAS_HORIZONTAL_SCROLL_BARS (f)
+                  ? make_number (0)
+                  : FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) > 0
+                  ? make_number (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f))
+                  /* nil means "use default height"
+                     for non-toolkit scroll bar.  */
+                  : Qnil));
   /* FRAME_X_WINDOW is not guaranteed to return an integer.  E.g., on
      MS-Windows it returns a value whose type is HANDLE, which is
      actually a pointer.  Explicit casting avoids compiler
@@ -3170,7 +3399,7 @@ x_report_frame_params (struct frame *f, Lisp_Object *alistptr)
     tem = make_natnum ((uintptr_t) FRAME_X_OUTPUT (f)->parent_desc);
   store_in_alist (alistptr, Qexplicit_name, (f->explicit_name ? Qt : Qnil));
   store_in_alist (alistptr, Qparent_id, tem);
-  store_in_alist (alistptr, Qtool_bar_position, f->tool_bar_position);
+  store_in_alist (alistptr, Qtool_bar_position, FRAME_TOOL_BAR_POSITION (f));
 }
 
 
@@ -3244,8 +3473,7 @@ x_set_screen_gamma (struct frame *f, Lisp_Object new_value, Lisp_Object old_valu
     {
       Lisp_Object parm_index = Fget (Qbackground_color, Qx_frame_parameter);
       if (NATNUMP (parm_index)
-         && (XFASTINT (parm_index)
-             < sizeof (frame_parms)/sizeof (frame_parms[0]))
+         && XFASTINT (parm_index) < ARRAYELTS (frame_parms)
          && FRAME_RIF (f)->frame_parm_handlers[XFASTINT (parm_index)])
          (*FRAME_RIF (f)->frame_parm_handlers[XFASTINT (parm_index)])
            (f, bgcolor, Qnil);
@@ -3418,58 +3646,66 @@ x_set_font_backend (struct frame *f, Lisp_Object new_value, Lisp_Object old_valu
     }
 }
 
-
 void
-x_set_fringe_width (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
+x_set_left_fringe (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
 {
-  compute_fringe_widths (f, 1);
-#ifdef HAVE_X_WINDOWS
-  /* Must adjust this so window managers report correct number of columns.  */
-  if (FRAME_X_WINDOW (f) != 0)
-    x_wm_set_size_hint (f, 0, 0);
-#endif
+  int unit = FRAME_COLUMN_WIDTH (f);
+  int old_width = FRAME_LEFT_FRINGE_WIDTH (f);
+  int new_width;
+
+  new_width = (RANGED_INTEGERP (-INT_MAX, new_value, INT_MAX)
+              ? eabs (XINT (new_value)) : 8);
+
+  if (new_width != old_width)
+    {
+      FRAME_LEFT_FRINGE_WIDTH (f) = new_width;
+      FRAME_FRINGE_COLS (f) /* Round up.  */
+       = (new_width + FRAME_RIGHT_FRINGE_WIDTH (f) + unit - 1) / unit;
+
+      if (FRAME_X_WINDOW (f) != 0)
+       adjust_frame_size (f, -1, -1, 3, 0, Qleft_fringe);
+
+      SET_FRAME_GARBAGED (f);
+    }
 }
 
+
 void
-x_set_border_width (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
+x_set_right_fringe (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
 {
-  CHECK_TYPE_RANGED_INTEGER (int, arg);
+  int unit = FRAME_COLUMN_WIDTH (f);
+  int old_width = FRAME_RIGHT_FRINGE_WIDTH (f);
+  int new_width;
 
-  if (XINT (arg) == f->border_width)
-    return;
+  new_width = (RANGED_INTEGERP (-INT_MAX, new_value, INT_MAX)
+              ? eabs (XINT (new_value)) : 8);
 
-  if (FRAME_X_WINDOW (f) != 0)
-    error ("Cannot change the border width of a frame");
+  if (new_width != old_width)
+    {
+      FRAME_RIGHT_FRINGE_WIDTH (f) = new_width;
+      FRAME_FRINGE_COLS (f) /* Round up.  */
+       = (new_width + FRAME_LEFT_FRINGE_WIDTH (f) + unit - 1) / unit;
 
-  f->border_width = XINT (arg);
+      if (FRAME_X_WINDOW (f) != 0)
+       adjust_frame_size (f, -1, -1, 3, 0, Qright_fringe);
+
+      SET_FRAME_GARBAGED (f);
+    }
 }
 
+
 void
-x_set_internal_border_width (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
+x_set_border_width (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
 {
-  int old = FRAME_INTERNAL_BORDER_WIDTH (f);
-
   CHECK_TYPE_RANGED_INTEGER (int, arg);
-  FRAME_INTERNAL_BORDER_WIDTH (f) = XINT (arg);
-  if (FRAME_INTERNAL_BORDER_WIDTH (f) < 0)
-    FRAME_INTERNAL_BORDER_WIDTH (f) = 0;
-
-#ifdef USE_X_TOOLKIT
-  if (FRAME_X_OUTPUT (f)->edit_widget)
-    widget_store_internal_border (FRAME_X_OUTPUT (f)->edit_widget);
-#endif
 
-  if (FRAME_INTERNAL_BORDER_WIDTH (f) == old)
+  if (XINT (arg) == f->border_width)
     return;
 
   if (FRAME_X_WINDOW (f) != 0)
-    {
-      x_set_window_size (f, 0, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f), 1);
-      SET_FRAME_GARBAGED (f);
-      do_pending_window_change (0);
-    }
-  else
-    SET_FRAME_GARBAGED (f);
+    error ("Cannot change the border width of a frame");
+
+  f->border_width = XINT (arg);
 }
 
 void
@@ -3481,18 +3717,13 @@ x_set_right_divider_width (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
   FRAME_RIGHT_DIVIDER_WIDTH (f) = XINT (arg);
   if (FRAME_RIGHT_DIVIDER_WIDTH (f) < 0)
     FRAME_RIGHT_DIVIDER_WIDTH (f) = 0;
-
-  if (FRAME_RIGHT_DIVIDER_WIDTH (f) == old)
-    return;
-
-  if (FRAME_X_WINDOW (f) != 0)
+  if (FRAME_RIGHT_DIVIDER_WIDTH (f) != old)
     {
-      x_set_window_size (f, 0, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f), 1);
+      adjust_frame_size (f, -1, -1, 4, 0, Qright_divider_width);
+      adjust_frame_glyphs (f);
       SET_FRAME_GARBAGED (f);
-      do_pending_window_change (0);
     }
-  else
-    SET_FRAME_GARBAGED (f);
+
 }
 
 void
@@ -3504,18 +3735,12 @@ x_set_bottom_divider_width (struct frame *f, Lisp_Object arg, Lisp_Object oldval
   FRAME_BOTTOM_DIVIDER_WIDTH (f) = XINT (arg);
   if (FRAME_BOTTOM_DIVIDER_WIDTH (f) < 0)
     FRAME_BOTTOM_DIVIDER_WIDTH (f) = 0;
-
-  if (FRAME_BOTTOM_DIVIDER_WIDTH (f) == old)
-    return;
-
-  if (FRAME_X_WINDOW (f) != 0)
+  if (FRAME_BOTTOM_DIVIDER_WIDTH (f) != old)
     {
-      x_set_window_size (f, 0, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f), 1);
+      adjust_frame_size (f, -1, -1, 4, 0, Qbottom_divider_width);
+      adjust_frame_glyphs (f);
       SET_FRAME_GARBAGED (f);
-      do_pending_window_change (0);
     }
-  else
-    SET_FRAME_GARBAGED (f);
 }
 
 void
@@ -3556,7 +3781,7 @@ x_set_vertical_scroll_bars (struct frame *f, Lisp_Object arg, Lisp_Object oldval
   if ((EQ (arg, Qleft) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
       || (EQ (arg, Qright) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f))
       || (NILP (arg) && FRAME_HAS_VERTICAL_SCROLL_BARS (f))
-      || (!NILP (arg) && ! FRAME_HAS_VERTICAL_SCROLL_BARS (f)))
+      || (!NILP (arg) && !FRAME_HAS_VERTICAL_SCROLL_BARS (f)))
     {
       FRAME_VERTICAL_SCROLL_BAR_TYPE (f)
        = (NILP (arg)
@@ -3576,12 +3801,33 @@ x_set_vertical_scroll_bars (struct frame *f, Lisp_Object arg, Lisp_Object oldval
         However, if the window hasn't been created yet, we shouldn't
         call x_set_window_size.  */
       if (FRAME_X_WINDOW (f))
-       x_set_window_size (f, 0, FRAME_TEXT_WIDTH (f),
-                          FRAME_TEXT_HEIGHT (f), 1);
-      do_pending_window_change (0);
+       adjust_frame_size (f, -1, -1, 3, 0, Qvertical_scroll_bars);
+
+      SET_FRAME_GARBAGED (f);
     }
 }
 
+void
+x_set_horizontal_scroll_bars (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
+{
+#if USE_HORIZONTAL_SCROLL_BARS
+  if ((NILP (arg) && FRAME_HAS_HORIZONTAL_SCROLL_BARS (f))
+      || (!NILP (arg) && !FRAME_HAS_HORIZONTAL_SCROLL_BARS (f)))
+    {
+      f->horizontal_scroll_bars = NILP (arg) ? false : true;
+
+      /* We set this parameter before creating the X window for the
+        frame, so we can get the geometry right from the start.
+        However, if the window hasn't been created yet, we shouldn't
+        call x_set_window_size.  */
+      if (FRAME_X_WINDOW (f))
+       adjust_frame_size (f, -1, -1, 3, 0, Qhorizontal_scroll_bars);
+
+      SET_FRAME_GARBAGED (f);
+    }
+#endif
+}
+
 void
 x_set_scroll_bar_width (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
 {
@@ -3592,9 +3838,9 @@ x_set_scroll_bar_width (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
       x_set_scroll_bar_default_width (f);
 
       if (FRAME_X_WINDOW (f))
-        x_set_window_size (f, 0, FRAME_TEXT_WIDTH (f),
-                          FRAME_TEXT_HEIGHT (f), 1);
-      do_pending_window_change (0);
+       adjust_frame_size (f, -1, -1, 3, 0, Qscroll_bar_width);
+
+      SET_FRAME_GARBAGED (f);
     }
   else if (RANGED_INTEGERP (1, arg, INT_MAX)
           && XFASTINT (arg) != FRAME_CONFIG_SCROLL_BAR_WIDTH (f))
@@ -3602,18 +3848,46 @@ x_set_scroll_bar_width (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
       FRAME_CONFIG_SCROLL_BAR_WIDTH (f) = XFASTINT (arg);
       FRAME_CONFIG_SCROLL_BAR_COLS (f) = (XFASTINT (arg) + unit - 1) / unit;
       if (FRAME_X_WINDOW (f))
-       x_set_window_size (f, 0, FRAME_TEXT_WIDTH (f),
-                          FRAME_TEXT_HEIGHT (f), 1);
-      do_pending_window_change (0);
+       adjust_frame_size (f, -1, -1, 3, 0, Qscroll_bar_width);
+
+      SET_FRAME_GARBAGED (f);
     }
 
-  /* Eventually remove the following call.  It should have been done by
-     x_set_window_size already.  */
-  change_frame_size (f, 0, 0, 0, 0, 0, 1);
   XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.hpos = 0;
   XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.x = 0;
 }
 
+void
+x_set_scroll_bar_height (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
+{
+#if USE_HORIZONTAL_SCROLL_BARS
+  int unit = FRAME_LINE_HEIGHT (f);
+
+  if (NILP (arg))
+    {
+      x_set_scroll_bar_default_height (f);
+
+      if (FRAME_X_WINDOW (f))
+       adjust_frame_size (f, -1, -1, 3, 0, Qscroll_bar_height);
+
+      SET_FRAME_GARBAGED (f);
+    }
+  else if (RANGED_INTEGERP (1, arg, INT_MAX)
+          && XFASTINT (arg) != FRAME_CONFIG_SCROLL_BAR_HEIGHT (f))
+    {
+      FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) = XFASTINT (arg);
+      FRAME_CONFIG_SCROLL_BAR_LINES (f) = (XFASTINT (arg) + unit - 1) / unit;
+      if (FRAME_X_WINDOW (f))
+       adjust_frame_size (f, -1, -1, 3, 0, Qscroll_bar_height);
+
+      SET_FRAME_GARBAGED (f);
+    }
+
+  XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.vpos = 0;
+  XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.y = 0;
+#endif
+}
+
 void
 x_set_alpha (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
 {
@@ -3769,10 +4043,6 @@ validate_x_resource_name (void)
 static Lisp_Object
 xrdb_get_resource (XrmDatabase rdb, Lisp_Object attribute, Lisp_Object class, Lisp_Object component, Lisp_Object subclass)
 {
-  register char *value;
-  char *name_key;
-  char *class_key;
-
   CHECK_STRING (attribute);
   CHECK_STRING (class);
 
@@ -3787,22 +4057,25 @@ xrdb_get_resource (XrmDatabase rdb, Lisp_Object attribute, Lisp_Object class, Li
 
   /* Allocate space for the components, the dots which separate them,
      and the final '\0'.  Make them big enough for the worst case.  */
-  name_key = alloca (SBYTES (Vx_resource_name)
-                    + (STRINGP (component)
-                       ? SBYTES (component) : 0)
-                    + SBYTES (attribute)
-                    + 3);
-
-  class_key = alloca (SBYTES (Vx_resource_class)
-                     + SBYTES (class)
-                     + (STRINGP (subclass)
-                        ? SBYTES (subclass) : 0)
-                     + 3);
+  ptrdiff_t name_keysize = (SBYTES (Vx_resource_name)
+                           + (STRINGP (component)
+                              ? SBYTES (component) : 0)
+                           + SBYTES (attribute)
+                           + 3);
+
+  ptrdiff_t class_keysize = (SBYTES (Vx_resource_class)
+                            + SBYTES (class)
+                            + (STRINGP (subclass)
+                               ? SBYTES (subclass) : 0)
+                            + 3);
+  USE_SAFE_ALLOCA;
+  char *name_key = SAFE_ALLOCA (name_keysize + class_keysize);
+  char *class_key = name_key + name_keysize;
 
   /* Start with emacs.FRAMENAME for the name (the specific one)
      and with `Emacs' for the class key (the general one).  */
-  strcpy (name_key, SSDATA (Vx_resource_name));
-  strcpy (class_key, SSDATA (Vx_resource_class));
+  lispstpcpy (name_key, Vx_resource_name);
+  lispstpcpy (class_key, Vx_resource_class);
 
   strcat (class_key, ".");
   strcat (class_key, SSDATA (class));
@@ -3819,7 +4092,8 @@ xrdb_get_resource (XrmDatabase rdb, Lisp_Object attribute, Lisp_Object class, Li
   strcat (name_key, ".");
   strcat (name_key, SSDATA (attribute));
 
-  value = x_get_string_resource (rdb, name_key, class_key);
+  char *value = x_get_string_resource (rdb, name_key, class_key);
+  SAFE_FREE();
 
   if (value && *value)
     return build_string (value);
@@ -3871,8 +4145,10 @@ x_get_resource_string (const char *attribute, const char *class)
 
   /* Allocate space for the components, the dots which separate them,
      and the final '\0'.  */
-  char *name_key = SAFE_ALLOCA (invocation_namelen + strlen (attribute) + 2);
-  char *class_key = alloca ((sizeof (EMACS_CLASS) - 1) + strlen (class) + 2);
+  ptrdiff_t name_keysize = invocation_namelen + strlen (attribute) + 2;
+  ptrdiff_t class_keysize = sizeof (EMACS_CLASS) - 1 + strlen (class) + 2;
+  char *name_key = SAFE_ALLOCA (name_keysize + class_keysize);
+  char *class_key = name_key + name_keysize;
 
   esprintf (name_key, "%s.%s", SSDATA (Vinvocation_name), attribute);
   sprintf (class_key, "%s.%s", EMACS_CLASS, class);
@@ -3899,7 +4175,7 @@ Lisp_Object
 x_get_arg (Display_Info *dpyinfo, Lisp_Object alist, Lisp_Object param,
           const char *attribute, const char *class, enum resource_types type)
 {
-  register Lisp_Object tem;
+  Lisp_Object tem;
 
   tem = Fassq (param, alist);
 
@@ -3925,10 +4201,9 @@ x_get_arg (Display_Info *dpyinfo, Lisp_Object alist, Lisp_Object param,
     {
       if (attribute && dpyinfo)
        {
-         tem = display_x_get_resource (dpyinfo,
-                                       build_string (attribute),
-                                       build_string (class),
-                                       Qnil, Qnil);
+         AUTO_STRING (at, attribute);
+         AUTO_STRING (cl, class);
+         tem = display_x_get_resource (dpyinfo, at, cl, Qnil, Qnil);
 
          if (NILP (tem))
            return Qunbound;
@@ -4038,7 +4313,8 @@ x_default_parameter (struct frame *f, Lisp_Object alist, Lisp_Object prop,
   tem = x_frame_get_arg (f, alist, prop, xprop, xclass, type);
   if (EQ (tem, Qunbound))
     tem = deflt;
-  x_set_frame_parameters (f, list1 (Fcons (prop, tem)));
+  AUTO_FRAME_ARG (arg, prop, tem);
+  x_set_frame_parameters (f, arg);
   return tem;
 }
 
@@ -4215,7 +4491,7 @@ On Nextstep, this just calls `ns-parse-geometry'.  */)
 long
 x_figure_window_size (struct frame *f, Lisp_Object parms, bool toolbar_p)
 {
-  register Lisp_Object tem0, tem1, tem2;
+  Lisp_Object height, width, user_size, top, left, user_position;
   long window_prompting = 0;
   Display_Info *dpyinfo = FRAME_DISPLAY_INFO (f);
 
@@ -4225,58 +4501,54 @@ x_figure_window_size (struct frame *f, Lisp_Object parms, bool toolbar_p)
   SET_FRAME_WIDTH (f, DEFAULT_COLS * FRAME_COLUMN_WIDTH (f));
   SET_FRAME_COLS (f, DEFAULT_COLS);
   SET_FRAME_HEIGHT (f, DEFAULT_ROWS * FRAME_LINE_HEIGHT (f));
-  FRAME_LINES (f) = DEFAULT_ROWS;
+  SET_FRAME_LINES (f, DEFAULT_ROWS);
 
   /* Window managers expect that if program-specified
      positions are not (0,0), they're intentional, not defaults.  */
   f->top_pos = 0;
   f->left_pos = 0;
 
-  /* Ensure that old new_width and new_height will not override the
-     values set here.  */
-  /* ++KFS: This was specific to W32, but seems ok for all platforms */
-  f->new_width = f->new_height = f->new_pixelwise = 0;
+  /* Ensure that earlier new_width and new_height settings won't
+     override what we specify below.  */
+  f->new_width = f->new_height = 0;
 
-  tem0 = x_get_arg (dpyinfo, parms, Qheight, 0, 0, RES_TYPE_NUMBER);
-  tem1 = x_get_arg (dpyinfo, parms, Qwidth, 0, 0, RES_TYPE_NUMBER);
-  tem2 = x_get_arg (dpyinfo, parms, Quser_size, 0, 0, RES_TYPE_NUMBER);
-  if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
+  height = x_get_arg (dpyinfo, parms, Qheight, 0, 0, RES_TYPE_NUMBER);
+  width = x_get_arg (dpyinfo, parms, Qwidth, 0, 0, RES_TYPE_NUMBER);
+  if (!EQ (width, Qunbound) || !EQ (height, Qunbound))
     {
-      if (!EQ (tem0, Qunbound))
+      if (!EQ (width, Qunbound))
        {
-         CHECK_NUMBER (tem0);
-         if (! (0 <= XINT (tem0) && XINT (tem0) <= INT_MAX))
-           xsignal1 (Qargs_out_of_range, tem0);
-         FRAME_LINES (f) = XINT (tem0);
+         CHECK_NUMBER (width);
+         if (! (0 <= XINT (width) && XINT (width) <= INT_MAX))
+           xsignal1 (Qargs_out_of_range, width);
+
+         SET_FRAME_WIDTH (f, XINT (width) * FRAME_COLUMN_WIDTH (f));
        }
-      if (!EQ (tem1, Qunbound))
+
+      if (!EQ (height, Qunbound))
        {
-         CHECK_NUMBER (tem1);
-         if (! (0 <= XINT (tem1) && XINT (tem1) <= INT_MAX))
-           xsignal1 (Qargs_out_of_range, tem1);
-         SET_FRAME_COLS (f, XINT (tem1));
+         CHECK_NUMBER (height);
+         if (! (0 <= XINT (height) && XINT (height) <= INT_MAX))
+           xsignal1 (Qargs_out_of_range, height);
+
+         SET_FRAME_HEIGHT (f, XINT (height) * FRAME_LINE_HEIGHT (f));
        }
-      if (!NILP (tem2) && !EQ (tem2, Qunbound))
+
+      user_size = x_get_arg (dpyinfo, parms, Quser_size, 0, 0, RES_TYPE_NUMBER);
+      if (!NILP (user_size) && !EQ (user_size, Qunbound))
        window_prompting |= USSize;
       else
        window_prompting |= PSize;
     }
 
-
-  /* This used to be done _before_ calling x_figure_window_size, but
-     since the height is reset here, this was really a no-op.  I
-     assume that moving it here does what Gerd intended (although he
-     no longer can remember what that was...  ++KFS, 2003-03-25.  */
-
-  /* Add the tool-bar height to the initial frame height so that the
-     user gets a text display area of the size he specified with -g or
-     via .Xdefaults.  Later changes of the tool-bar height don't
-     change the frame size.  This is done so that users can create
-     tall Emacs frames without having to guess how tall the tool-bar
-     will get.  */
-  if (toolbar_p && FRAME_TOOL_BAR_HEIGHT (f))
+  /* Add a tool bar height to the initial frame height so that the user
+     gets a text display area of the size he specified with -g or via
+     .Xdefaults.  Later changes of the tool bar height don't change the
+     frame size.  This is done so that users can create tall Emacs
+     frames without having to guess how tall the tool bar will get.  */
+  if (toolbar_p && FRAME_TOOL_BAR_LINES (f))
     {
-      int margin, relief, bar_height;
+      int margin, relief;
 
       relief = (tool_bar_button_relief >= 0
                ? tool_bar_button_relief
@@ -4290,78 +4562,73 @@ x_figure_window_size (struct frame *f, Lisp_Object parms, bool toolbar_p)
       else
        margin = 0;
 
-      /* PXW: We should be able to not round here.  */
-      bar_height = DEFAULT_TOOL_BAR_IMAGE_HEIGHT + 2 * margin + 2 * relief;
-      FRAME_LINES (f) += (bar_height + FRAME_LINE_HEIGHT (f) - 1) / FRAME_LINE_HEIGHT (f);
+      FRAME_TOOL_BAR_HEIGHT (f)
+       = DEFAULT_TOOL_BAR_IMAGE_HEIGHT + 2 * margin + 2 * relief;
+      Vframe_initial_frame_tool_bar_height = make_number (FRAME_TOOL_BAR_HEIGHT (f));
     }
 
-  compute_fringe_widths (f, 0);
-
-  SET_FRAME_WIDTH (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f));
-  SET_FRAME_HEIGHT(f, FRAME_LINES (f) * FRAME_LINE_HEIGHT (f));
-
-  tem0 = x_get_arg (dpyinfo, parms, Qtop, 0, 0, RES_TYPE_NUMBER);
-  tem1 = x_get_arg (dpyinfo, parms, Qleft, 0, 0, RES_TYPE_NUMBER);
-  tem2 = x_get_arg (dpyinfo, parms, Quser_position, 0, 0, RES_TYPE_NUMBER);
-  if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
+  top = x_get_arg (dpyinfo, parms, Qtop, 0, 0, RES_TYPE_NUMBER);
+  left = x_get_arg (dpyinfo, parms, Qleft, 0, 0, RES_TYPE_NUMBER);
+  user_position = x_get_arg (dpyinfo, parms, Quser_position, 0, 0, RES_TYPE_NUMBER);
+  if (! EQ (top, Qunbound) || ! EQ (left, Qunbound))
     {
-      if (EQ (tem0, Qminus))
+      if (EQ (top, Qminus))
        {
          f->top_pos = 0;
          window_prompting |= YNegative;
        }
-      else if (CONSP (tem0) && EQ (XCAR (tem0), Qminus)
-              && CONSP (XCDR (tem0))
-              && RANGED_INTEGERP (-INT_MAX, XCAR (XCDR (tem0)), INT_MAX))
+      else if (CONSP (top) && EQ (XCAR (top), Qminus)
+              && CONSP (XCDR (top))
+              && RANGED_INTEGERP (-INT_MAX, XCAR (XCDR (top)), INT_MAX))
        {
-         f->top_pos = - XINT (XCAR (XCDR (tem0)));
+         f->top_pos = - XINT (XCAR (XCDR (top)));
          window_prompting |= YNegative;
        }
-      else if (CONSP (tem0) && EQ (XCAR (tem0), Qplus)
-              && CONSP (XCDR (tem0))
-              && TYPE_RANGED_INTEGERP (int, XCAR (XCDR (tem0))))
+      else if (CONSP (top) && EQ (XCAR (top), Qplus)
+              && CONSP (XCDR (top))
+              && TYPE_RANGED_INTEGERP (int, XCAR (XCDR (top))))
        {
-         f->top_pos = XINT (XCAR (XCDR (tem0)));
+         f->top_pos = XINT (XCAR (XCDR (top)));
        }
-      else if (EQ (tem0, Qunbound))
+      else if (EQ (top, Qunbound))
        f->top_pos = 0;
       else
        {
-         CHECK_TYPE_RANGED_INTEGER (int, tem0);
-         f->top_pos = XINT (tem0);
+         CHECK_TYPE_RANGED_INTEGER (int, top);
+         f->top_pos = XINT (top);
          if (f->top_pos < 0)
            window_prompting |= YNegative;
        }
 
-      if (EQ (tem1, Qminus))
+      if (EQ (left, Qminus))
        {
          f->left_pos = 0;
          window_prompting |= XNegative;
        }
-      else if (CONSP (tem1) && EQ (XCAR (tem1), Qminus)
-              && CONSP (XCDR (tem1))
-              && RANGED_INTEGERP (-INT_MAX, XCAR (XCDR (tem1)), INT_MAX))
+      else if (CONSP (left) && EQ (XCAR (left), Qminus)
+              && CONSP (XCDR (left))
+              && RANGED_INTEGERP (-INT_MAX, XCAR (XCDR (left)), INT_MAX))
        {
-         f->left_pos = - XINT (XCAR (XCDR (tem1)));
+         f->left_pos = - XINT (XCAR (XCDR (left)));
          window_prompting |= XNegative;
        }
-      else if (CONSP (tem1) && EQ (XCAR (tem1), Qplus)
-              && CONSP (XCDR (tem1))
-              && TYPE_RANGED_INTEGERP (int, XCAR (XCDR (tem1))))
+      else if (CONSP (left) && EQ (XCAR (left), Qplus)
+              && CONSP (XCDR (left))
+              && TYPE_RANGED_INTEGERP (int, XCAR (XCDR (left))))
        {
-         f->left_pos = XINT (XCAR (XCDR (tem1)));
+         f->left_pos = XINT (XCAR (XCDR (left)));
        }
-      else if (EQ (tem1, Qunbound))
+      else if (EQ (left, Qunbound))
        f->left_pos = 0;
       else
        {
-         CHECK_TYPE_RANGED_INTEGER (int, tem1);
-         f->left_pos = XINT (tem1);
+         CHECK_TYPE_RANGED_INTEGER (int, left);
+         f->left_pos = XINT (left);
          if (f->left_pos < 0)
            window_prompting |= XNegative;
        }
 
-      if (!NILP (tem2) && ! EQ (tem2, Qunbound))
+      if (!NILP (user_position) && ! EQ (user_position, Qunbound))
        window_prompting |= USPosition;
       else
        window_prompting |= PPosition;
@@ -4392,16 +4659,11 @@ x_figure_window_size (struct frame *f, Lisp_Object parms, bool toolbar_p)
 #endif /* HAVE_WINDOW_SYSTEM */
 
 void
-frame_make_pointer_invisible (void)
+frame_make_pointer_invisible (struct frame *f)
 {
   if (! NILP (Vmake_pointer_invisible))
     {
-      struct frame *f;
-      if (!FRAMEP (selected_frame) || !FRAME_LIVE_P (XFRAME (selected_frame)))
-        return;
-
-      f = SELECTED_FRAME ();
-      if (f && !f->pointer_invisible
+      if (f && FRAME_LIVE_P (f) && !f->pointer_invisible
           && FRAME_TERMINAL (f)->toggle_invisible_pointer_hook)
         {
           f->mouse_moved = 0;
@@ -4412,17 +4674,11 @@ frame_make_pointer_invisible (void)
 }
 
 void
-frame_make_pointer_visible (void)
+frame_make_pointer_visible (struct frame *f)
 {
   /* We don't check Vmake_pointer_invisible here in case the
      pointer was invisible when Vmake_pointer_invisible was set to nil.  */
-  struct frame *f;
-
-  if (!FRAMEP (selected_frame) || !FRAME_LIVE_P (XFRAME (selected_frame)))
-    return;
-
-  f = SELECTED_FRAME ();
-  if (f && f->pointer_invisible && f->mouse_moved
+  if (f && FRAME_LIVE_P (f) && f->pointer_invisible && f->mouse_moved
       && FRAME_TERMINAL (f)->toggle_invisible_pointer_hook)
     {
       FRAME_TERMINAL (f)->toggle_invisible_pointer_hook (f, 0);
@@ -4519,6 +4775,7 @@ syms_of_frame (void)
 {
   DEFSYM (Qframep, "framep");
   DEFSYM (Qframe_live_p, "frame-live-p");
+  DEFSYM (Qframe_windows_min_size, "frame-windows-min-size");
   DEFSYM (Qexplicit_name, "explicit-name");
   DEFSYM (Qheight, "height");
   DEFSYM (Qicon, "icon");
@@ -4531,8 +4788,6 @@ syms_of_frame (void)
   DEFSYM (Qicon_left, "icon-left");
   DEFSYM (Qicon_top, "icon-top");
   DEFSYM (Qtooltip, "tooltip");
-  DEFSYM (Qleft, "left");
-  DEFSYM (Qright, "right");
   DEFSYM (Quser_position, "user-position");
   DEFSYM (Quser_size, "user-size");
   DEFSYM (Qwindow_id, "window-id");
@@ -4566,12 +4821,21 @@ syms_of_frame (void)
 
   DEFSYM (Qterminal, "terminal");
 
-  DEFSYM (Qgeometry, "geometry");
   DEFSYM (Qworkarea, "workarea");
   DEFSYM (Qmm_size, "mm-size");
   DEFSYM (Qframes, "frames");
   DEFSYM (Qsource, "source");
 
+  DEFSYM (Qframe_position, "frame-position");
+  DEFSYM (Qframe_outer_size, "frame-outer-size");
+  DEFSYM (Qexternal_border_size, "external-border-size");
+  DEFSYM (Qtitle_height, "title-height");
+  DEFSYM (Qmenu_bar_external, "menu-bar-external");
+  DEFSYM (Qmenu_bar_size, "menu-bar-size");
+  DEFSYM (Qtool_bar_external, "tool-bar-external");
+  DEFSYM (Qtool_bar_size, "tool-bar-size");
+  DEFSYM (Qframe_inner_size, "frame-inner-size");
+
 #ifdef HAVE_NS
   DEFSYM (Qns_parse_geometry, "ns-parse-geometry");
 #endif
@@ -4579,7 +4843,7 @@ syms_of_frame (void)
   {
     int i;
 
-    for (i = 0; i < sizeof (frame_parms) / sizeof (frame_parms[0]); i++)
+    for (i = 0; i < ARRAYELTS (frame_parms); i++)
       {
        Lisp_Object v = intern_c_string (frame_parms[i].name);
        if (frame_parms[i].variable)
@@ -4639,7 +4903,7 @@ Setting this variable does not affect existing frames, only new ones.  */);
   Vdefault_frame_alist = Qnil;
 
   DEFVAR_LISP ("default-frame-scroll-bars", Vdefault_frame_scroll_bars,
-              doc: /* Default position of scroll bars on this window-system.  */);
+              doc: /* Default position of vertical scroll bars on this window-system.  */);
 #ifdef HAVE_WINDOW_SYSTEM
 #if defined (HAVE_NTGUI) || defined (NS_IMPL_COCOA) || (defined (USE_GTK) && defined (USE_TOOLKIT_SCROLL_BARS))
   /* MS-Windows, Mac OS X, and GTK have scroll bars on the right by
@@ -4728,6 +4992,10 @@ or call the function `tool-bar-mode'.  */);
   Vtool_bar_mode = Qnil;
 #endif
 
+  DEFVAR_LISP ("frame-initial-frame-tool-bar-height", Vframe_initial_frame_tool_bar_height,
+               doc: /* Height of tool bar of initial frame.  */);
+  Vframe_initial_frame_tool_bar_height = make_number (0);
+
   DEFVAR_KBOARD ("default-minibuffer-frame", Vdefault_minibuffer_frame,
                 doc: /* Minibufferless frames use this frame's minibuffer.
 Emacs cannot create minibufferless frames unless this is set to an
@@ -4756,11 +5024,56 @@ current values of `frame-char-height' and `frame-char-width'.  If this
 is non-nil, no rounding occurs, hence frame sizes can increase/decrease
 by one pixel.
 
-With some window managers you have to set this to non-nil in order to
-fully maximize frames.  To resize your initial frame pixelwise,
-set this option to a non-nil value in your init file.  */);
+With some window managers you may have to set this to non-nil in order
+to set the size of a frame in pixels, to maximize frames or to make them
+fullscreen.  To resize your initial frame pixelwise, set this option to
+a non-nil value in your init file.  */);
   frame_resize_pixelwise = 0;
 
+  DEFVAR_LISP ("frame-inhibit-implied-resize", frame_inhibit_implied_resize,
+              doc: /* Whether frames should be resized implicitly.
+If this option is nil, setting font, menu bar, tool bar, internal
+borders, fringes or scroll bars of a specific frame may resize the frame
+in order to preserve the number of columns or lines it displays.  If
+this option is `t', no such resizing is done.  Note that the size of
+fullscreen and maximized frames, the height of fullheight frames and the
+width of fullwidth frames never change implicitly.
+
+The value of this option can be also be a list of frame parameters.  In
+this case, resizing is inhibited when changing a parameter that appears
+in that list.  The parameters currently handled by this option include
+`font', `font-backend', `internal-border-width', `menu-bar-lines' and
+`tool-bar-lines'.
+
+Changing any of the parameters `scroll-bar-width', `scroll-bar-height',
+`vertical-scroll-bars', `horizontal-scroll-bars', `left-fringe' and
+`right-fringe' is handled as if the frame contained just one live
+window.  This means, for example, that removing vertical scroll bars on
+a frame containing several side by side windows will shrink the frame
+width by the width of one scroll bar provided this option is nil and
+keep it unchanged if this option is either `t' or a list containing
+`vertical-scroll-bars'.
+
+The default value is '(tool-bar-lines) on Lucid, Motif and Windows
+(which means that adding/removing a tool bar does not change the frame
+height), nil on all other window systems including GTK+ (which means
+that changing any of the parameters listed above may change the size of
+the frame), and `t' otherwise (which means the frame size never changes
+implicitly when there's no window system support).
+
+Note that when a frame is not large enough to accommodate a change of
+any of the parameters listed above, Emacs may try to enlarge the frame
+even if this option is non-nil.  */);
+#if defined (HAVE_WINDOW_SYSTEM)
+#if defined (USE_LUCID) || defined (USE_MOTIF) || defined (HAVE_NTGUI)
+  frame_inhibit_implied_resize = list1 (Qtool_bar_lines);
+#else
+  frame_inhibit_implied_resize = Qnil;
+#endif
+#else
+  frame_inhibit_implied_resize = Qt;
+#endif
+
   staticpro (&Vframe_list);
 
   defsubr (&Sframep);
@@ -4791,6 +5104,7 @@ set this option to a non-nil value in your init file.  */);
   defsubr (&Sraise_frame);
   defsubr (&Slower_frame);
   defsubr (&Sx_focus_frame);
+  defsubr (&Scan_run_window_configuration_change_hook);
   defsubr (&Sredirect_frame_focus);
   defsubr (&Sframe_focus);
   defsubr (&Sframe_parameters);
@@ -4803,9 +5117,11 @@ set this option to a non-nil value in your init file.  */);
   defsubr (&Sframe_text_cols);
   defsubr (&Sframe_text_lines);
   defsubr (&Sframe_total_cols);
+  defsubr (&Sframe_total_lines);
   defsubr (&Sframe_text_width);
   defsubr (&Sframe_text_height);
   defsubr (&Sscroll_bar_width);
+  defsubr (&Sscroll_bar_height);
   defsubr (&Sfringe_width);
   defsubr (&Sborder_width);
   defsubr (&Sright_divider_width);