diff src/frame.c @ 5043:d0c14ea98592

various frame-geometry fixes -------------------- ChangeLog entries follow: -------------------- src/ChangeLog addition: 2010-02-15 Ben Wing <ben@xemacs.org> * EmacsFrame.c: * EmacsFrame.c (EmacsFrameResize): * console-msw-impl.h: * console-msw-impl.h (struct mswindows_frame): * console-msw-impl.h (FRAME_MSWINDOWS_TARGET_RECT): * device-tty.c: * device-tty.c (tty_asynch_device_change): * event-msw.c: * event-msw.c (mswindows_wnd_proc): * faces.c (Fface_list): * faces.h: * frame-gtk.c: * frame-gtk.c (gtk_set_initial_frame_size): * frame-gtk.c (gtk_set_frame_size): * frame-msw.c: * frame-msw.c (mswindows_init_frame_1): * frame-msw.c (mswindows_set_frame_size): * frame-msw.c (mswindows_size_frame_internal): * frame-msw.c (msprinter_init_frame_3): * frame.c: * frame.c (enum): * frame.c (Fmake_frame): * frame.c (adjust_frame_size): * frame.c (store_minibuf_frame_prop): * frame.c (Fframe_property): * frame.c (Fframe_properties): * frame.c (Fframe_displayable_pixel_height): * frame.c (Fframe_displayable_pixel_width): * frame.c (internal_set_frame_size): * frame.c (Fset_frame_height): * frame.c (Fset_frame_pixel_height): * frame.c (Fset_frame_displayable_pixel_height): * frame.c (Fset_frame_width): * frame.c (Fset_frame_pixel_width): * frame.c (Fset_frame_displayable_pixel_width): * frame.c (Fset_frame_size): * frame.c (Fset_frame_pixel_size): * frame.c (Fset_frame_displayable_pixel_size): * frame.c (frame_conversion_internal_1): * frame.c (get_frame_displayable_pixel_size): * frame.c (change_frame_size_1): * frame.c (change_frame_size): * frame.c (generate_title_string): * frame.h: * gtk-xemacs.c: * gtk-xemacs.c (gtk_xemacs_size_request): * gtk-xemacs.c (gtk_xemacs_size_allocate): * gtk-xemacs.c (gtk_xemacs_paint): * gutter.c: * gutter.c (update_gutter_geometry): * redisplay.c (end_hold_frame_size_changes): * redisplay.c (redisplay_frame): * toolbar.c: * toolbar.c (update_frame_toolbars_geometry): * window.c: * window.c (frame_pixsize_valid_p): * window.c (check_frame_size): Various fixes to frame geometry to make it a bit easier to understand and fix some bugs. 1. IMPORTANT: Some renamings. Will need to be applied carefully to the carbon repository, in the following order: -- pixel_to_char_size -> pixel_to_frame_unit_size -- char_to_pixel_size -> frame_unit_to_pixel_size -- pixel_to_real_char_size -> pixel_to_char_size -- char_to_real_pixel_size -> char_to_pixel_size -- Reverse second and third arguments of change_frame_size() and change_frame_size_1() to try to make functions consistent in putting width before height. -- Eliminate old round_size_to_char, because it didn't really do anything differently from round_size_to_real_char() -- round_size_to_real_char -> round_size_to_char; any places that called the old round_size_to_char should just call the new one. 2. IMPORTANT FOR CARBON: The set_frame_size() method is now passed sizes in "frame units", like all other frame-sizing functions, rather than some hacked-up combination of char-cell units and total pixel size. This only affects window systems that use "pixelated geometry", and I'm not sure if Carbon is one of them. MS Windows is pixelated, X and GTK are not. For pixelated-geometry systems, the size in set_frame_size() is in displayable pixels rather than total pixels and needs to be converted appropriately; take a look at the changes made to mswindows_set_frame_size() method if necessary. 3. Add a big long comment in frame.c describing how frame geometry works. 4. Remove MS Windows-specific character height and width fields, duplicative and unused. 5. frame-displayable-pixel-* and set-frame-displayable-pixel-* didn't use to work on MS Windows, but they do now. 6. In general, clean up the handling of "pixelated geometry" so that fewer functions have to worry about this. This is really an abomination that should be removed entirely but that will have to happen later. Fix some buggy code in frame_conversion_internal() that happened to "work" because it was countered by oppositely buggy code in change_frame_size(). 7. Clean up some frame-size code in toolbar.c and use functions already provided in frame.c instead of rolling its own. 8. Fix check_frame_size() in window.c, which formerly didn't take pixelated geometry into account.
author Ben Wing <ben@xemacs.org>
date Mon, 15 Feb 2010 22:14:11 -0600
parents 16112448d484
children e84a30b0e4a2
line wrap: on
line diff
--- a/src/frame.c	Mon Feb 15 21:52:39 2010 -0600
+++ b/src/frame.c	Mon Feb 15 22:14:11 2010 -0600
@@ -1,6 +1,6 @@
 /* Generic frame functions.
    Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
-   Copyright (C) 1995, 1996, 2002, 2003, 2005 Ben Wing.
+   Copyright (C) 1995, 1996, 2002, 2003, 2005, 2010 Ben Wing.
    Copyright (C) 1995 Sun Microsystems, Inc.
 
 This file is part of XEmacs.
@@ -24,6 +24,290 @@
 
 /* This file has been Mule-ized. */
 
+/* About window and frame geometry [ben]:
+
+   Here is an ASCII diagram:
+
++-----------------------------------------------------------------------------|
+|                          window-manager decoration                          |
+| +-------------------------------------------------------------------------+ |
+| |                                menubar                                  | |
+| ########################################################################### |
+| #                                toolbar                                  # |
+| #-------------------------------------------------------------------------# |
+| #  |                             gutter                                |  # |
+| #  |-------------------------------------------------------------------|  # |
+| #  | |                   internal border width                       | |  # |
+| #  | |-*************************************************************-| |  # |
+|w#  | | *                          |s|v*                          |s* | |  #w|
+|i#  | | *                          |c|e*                          |c* | |  #i|
+|n#  | | *                          |r|r*                          |r* | |  #n|
+|d#  | | *                          |o|t*                          |o* | |  #d|
+|o#  | | *         text area        |l|.*        text area         |l* | |  #o|
+|w#  | |i*                          |l| *                          |l*i| |  #w|
+|-#  | |n*                          |b|d*                          |b*n| |  #-|
+|m#  | |t*                          |a|i*                          |a*t| |  #m|
+|a#  | |.*                          |r|v*                          |r*.| |  #a|
+|n# t| | *--------------------------+-|i*--------------------------+-* | |t #n|
+|a# o|g|b*         scrollbar        | |d*        scrollbar         | *b|g|o #a|
+|g# o|u|o*--------------------------+-|e*--------------------------+-*o|u|o #g|
+|e# l|t|r*         modeline           |r*        modeline            *r|t|l #e|
+|r# b|t|d*************************************************************d|t|b #r|
+| # a|e|e*   =...texttexttex....=   |s|v*                          |s*e|e|a # |
+|d# r|r|r*o m=...texttexttextt..=o m|c|e*                          |c*r|r|r #d|
+|e#  | | *u a=.texttexttextte...=u a|r|r*                          |r* | |  #e|
+|c#  | |w*t r=.....texttexttex..=t r|o|t*                          |o*w| |  #c|
+|o#  | |i*s g=         etc.     =s g|l|.*        text area         |l*i| |  #o|
+|r#  | |d*i i=                  =i i|l| *                          |l*d| |  #r|
+|a#  | |t*d n=                  =d n|b|d*                          |b*t| |  #a|
+|t#  | |h*e  =  inner text area =e  |a|i*                          |a*h| |  #t|
+|i#  | | *   =                  =   |r|v*                          |r* | |  #i|
+|o#  | | *---====================---+-|i*--------------------------+-* | |  #o|
+|n#  | | *         scrollbar        | |d*        scrollbar         | * | |  #n|
+| #  | | *--------------------------+-|e*--------------------------+-* | |  # |
+| #  | | *         modeline           |r*        modeline            * | |  # |
+| #  | | ************************************************************* | |  # |
+| #  | | *                         minibuffer                        * | |  # |
+| #  | | ************************************************************* | |  # |
+| #  | |                    internal border width                      | |  # |
+| #  |-------------------------------------------------------------------|  # |
+| #  |                              gutter                               |  # |
+| #-------------------------------------------------------------------------# |
+| #                                 toolbar                                 # |
+| ########################################################################### |
+|                           window manager decoration                         |
++-----------------------------------------------------------------------------+
+
+   # = boundary of client area; * = window boundaries, boundary of paned area
+   = = boundary of inner text area; . = inside margin area
+
+   Note in particular what happens at the corners, where a "corner box"
+   occurs.  Top and bottom toolbars take precedence over left and right
+   toolbars, extending out horizontally into the corner boxes.  Gutters
+   work the same way.  The corner box where the scrollbars meet, however,
+   is assigned to neither scrollbar, and is known as the "dead box"; it is
+   an area that must be cleared specially.
+
+   THE FRAME
+   ---------
+
+   The "top-level window area" is the entire area of a top-level window (or
+   "frame").  The "client area" (a term from MS Windows) is the area of a
+   top-level window that XEmacs draws into and manages with redisplay.
+   This includes the toolbar, scrollbars, gutters, dividers, text area,
+   modeline and minibuffer.  It does not include the menubar, title or
+   outer borders.  The "non-client area" is the area of a top-level window
+   outside of the client area and includes the menubar, title and outer
+   borders.  Internally, all frame coordinates are relative to the client
+   area.
+
+
+   THE NON-CLIENT AREA
+   -------------------
+
+   Under X, the non-client area is split into two parts:
+
+   (1) The outer layer is the window-manager decorations: The title and
+   borders.  These are controlled by the window manager, a separate process
+   that controls the desktop, the location of icons, etc.  When a process
+   tries to create a window, the window manager intercepts this action and
+   "reparents" the window, placing another window around it which contains
+   the window decorations, including the title bar, outer borders used for
+   resizing, etc.  The window manager also implements any actions involving
+   the decorations, such as the ability to resize a window by dragging its
+   borders, move a window by dragging its title bar, etc.  If there is no
+   window manager or you kill it, windows will have no decorations (and
+   will lose them if they previously had any) and you will not be able to
+   move or resize them.
+
+   (2) Inside of the window-manager decorations is the "shell", which is
+   managed by the toolkit and widget libraries your program is linked with.
+   The code in *-x.c uses the Xt toolkit and various possible widget
+   libraries built on top of Xt, such as Motif, Athena, the "Lucid"
+   widgets, etc.  Another possibility is GTK (*-gtk.c), which implements
+   both the toolkit and widgets.  Under Xt, the "shell" window is an
+   EmacsShell widget, containing an EmacsManager widget of the same size,
+   which in turn contains a menubar widget and an EmacsFrame widget, inside
+   of which is the client area. (The division into EmacsShell and
+   EmacsManager is due to the complex and screwy geometry-management system
+   in Xt [and X more generally].  The EmacsShell handles negotation with
+   the window manager; the place of the EmacsManager widget is normally
+   assumed by a widget that manages the geometry of its child widgets, but
+   the EmacsManager widget just lets the XEmacs redisplay mechanism do the
+   positioning.)
+
+   Under Windows, the non-client area is managed by the window system.
+   There is no division such as under X.  Part of the window-system API
+   (USER.DLL) of Win32 includes functions to control the menubars, title,
+   etc. and implements the move and resize behavior.  There *is* an
+   equivalent of the window manager, called the "shell", but it manages
+   only the desktop, not the windows themselves.  The normal shell under
+   Windows is EXPLORER.EXE; if you kill this, you will lose the bar
+   containing the "Start" menu and tray and such, but the windows
+   themselves will not be affected or lose their decorations.
+
+
+   THE CLIENT AREA
+   ---------------
+
+   Inside of the client area is the toolbars, the gutters (where the buffer
+   tabs are displayed), the minibuffer, the internal border width, and one
+   or more non-overlapping "windows" (this is old Emacs terminology, from
+   before the time when frames existed at all; the standard terminology for
+   this would be "pane").  Each window can contain a modeline, horizontal
+   and/or vertical scrollbars, and (for non-rightmost windows) a vertical
+   divider, surrounding a text area.
+
+   The dimensions of the toolbars and gutters are determined by the formula
+   (THICKNESS + 2 * BORDER-THICKNESS), where "thickness" is a cover term
+   for height or width, as appropriate.  The height and width come from
+   `default-toolbar-height' and `default-toolbar-width' and the specific
+   versions of these (`top-toolbar-height', `left-toolbar-width', etc.).
+   The border thickness comes from `default-toolbar-border-height' and
+   `default-toolbar-border-width', and the specific versions of these.  The
+   gutter works exactly equivalently.
+
+   Note that for any particular toolbar or gutter, it will only be
+   displayed if [a] its visibility specifier (`default-toolbar-visible-p'
+   etc.) is non-nil; [b] its thickness (`default-toolbar-height' etc.)  is
+   greater than 0; [c] its contents (`default-toolbar' etc.) are non-nil.
+
+   The position-specific toolbars interact with the default specifications
+   as follows: If the value for a position-specific specifier is not
+   defined in a particular domain (usually a window), and the position of
+   that specifier is set as the default position (using
+   `default-toolbar-position'), then the value from the corresponding
+   default specifier in that domain will be used.  The gutters work the
+   same.
+
+
+   THE PANED AREA
+   --------------
+
+   The area occupied by the "windows" is called the paned area.  Note that
+   this includes the minibuffer, which is just another window but is
+   special-cased in XEmacs.  Each window can include a horizontal and/or
+   vertical scrollbar, a modeline and a vertical divider to its right, as
+   well as the text area.  Only non-rightmost windows can include a
+   vertical divider. (The minibuffer normally does not include either
+   modeline or scrollbars.)
+
+   Note that, because the toolbars and gutters are controlled by
+   specifiers, and specifiers can have window-specific and buffer-specific
+   values, the size of the paned area can change depending on which window
+   is selected: In other words, if the selected window or buffer changes,
+   the entire paned area for the frame may change.
+
+
+   TEXT AREAS, FRINGES, MARGINS
+   ----------------------------
+
+   The space occupied by a window can be divided into the text area and the
+   fringes.  The fringes include the modeline, scrollbars and vertical
+   divider on the right side (if any); inside of this is the text area,
+   where the text actually occurs.  Note that a window may or may not
+   contain any of the elements that are part of the fringe -- this is
+   controlled by specifiers, e.g. `has-modeline-p',
+   `horizontal-scrollbar-visible-p', `vertical-scrollbar-visible-p',
+   `vertical-divider-always-visible-p', etc.
+
+   In addition, it is possible to set margins in the text area using the
+   specifiers `left-margin-width' and `right-margin-width'.  When this is
+   done, only the "inner text area" (the area inside of the margins) will
+   be used for normal display of text; the margins will be used for glyphs
+   with a layout policy of `outside-margin' (as set on an extent containing
+   the glyph by `set-extent-begin-glyph-layout' or
+   `set-extent-end-glyph-layout').  However, the calculation of the text
+   area size (e.g. in the function `window-text-area-width') includes the
+   margins.  Which margin is used depends on whether a glyph has been set
+   as the begin-glyph or end-glyph of an extent (`set-extent-begin-glyph'
+   etc.), using the left and right margins, respectively.
+
+   Technically, the margins outside of the inner text area are known as the
+   "outside margins".  The "inside margins" are in the inner text area and
+   constitute the whitespace between the outside margins and the first or
+   last non-whitespace character in a line; their width can vary from line
+   to line.  Glyphs will be placed in the inside margin if their layout
+   policy is `inside-margin' or `whitespace', with `whitespace' glyphs on
+   the inside and `inside-margin' glyphs on the outside.  Inside-margin
+   glyphs can spill over into the outside margin if `use-left-overflow' or
+   `use-right-overflow', respectively, is non-nil.
+
+   See the Lisp Reference manual, under Annotations, for more details.
+
+
+   THE DISPLAYABLE AREA
+   --------------------
+
+   The "displayable area" is not so much an actual area as a convenient
+   fiction.  It is the area used to convert between pixel and character
+   dimensions for frames.  The character dimensions for a frame (e.g. as
+   returned by `frame-width' and `frame-height' and set by
+   `set-frame-width' and `set-frame-height') are determined from the
+   displayable area by dividing by the pixel size of the default font as
+   instantiated in the frame. (For proportional fonts, the "average" width
+   is used.  Under Windows, this is a built-in property of the fonts.
+   Under X, this is based on the width of the lowercase 'n', or if this is
+   zero then the width of the default character. [We prefer 'n' to the
+   specified default character because many X fonts have a default
+   character with a zero or otherwise non-representative width.])
+
+   The displayable area is essentially the "theoretical" paned area of the
+   frame excluding the rightmost and bottom-most scrollbars.  In this
+   context, "theoretical" means that all calculations on based on
+   frame-level values for toolbar, gutter and scrollbar thicknesses.
+   Because these thicknesses are controlled by specifiers, and specifiers
+   can have window-specific and buffer-specific values, these calculations
+   may or may not reflect the actual size of the paned area or of the
+   scrollbars when any particular window is selected.  Note also that the
+   "displayable area" may not even be contiguous!  In particular, if the
+   frame-level value of the horizontal scrollbar height is non-zero, then
+   the displayable area includes the paned area above and below the bottom
+   horizontal scrollbar but not the scrollbar itself.
+
+   As a further twist, the character-dimension calculations are adjusted so
+   that the truncation and continuation glyphs (see `truncation-glyph' and
+   `continuation-glyph') count as a single character even if they are wider
+   than the default font width. (Technically, the character width is
+   computed from the displayable-area width by subtracting the maximum of
+   the truncation-glyph width, continuation-glyph width and default-font
+   width before dividing by the default-font width, and then adding 1 to
+   the result.) (The ultimate motivation for this kludge as well as the
+   subtraction of the scrollbars, but not the minibuffer or bottom-most
+   modeline, is to maintain compatibility with TTY's.)
+
+   Despite all these concerns and kludges, however, the "displayable area"
+   concept works well in practice and mostly ensures that by default the
+   frame will actually fit 79 characters + continuation/truncation glyph.
+
+
+   WHICH FUNCTIONS USE WHICH?
+   --------------------------
+
+   [1] Top-level window area:
+
+   set-frame-position
+   `left' and `top' frame properties
+
+   [2] Client area:
+
+   frame-pixel-*, set-frame-pixel-*
+
+   [3] Paned area:
+
+   window-pixel-edges
+   event-x-pixel, event-y-pixel, event-properties, make-event
+
+   [4] Displayable area:
+
+   frame-width, frame-height and other all functions specifying frame size
+     in characters
+   frame-displayable-pixel-*
+
+   --ben
+
+*/
+
 #include <config.h>
 #include "lisp.h"
 
@@ -120,18 +404,35 @@
 
 static void store_minibuf_frame_prop (struct frame *f, Lisp_Object val);
 
-typedef enum  {
+typedef enum
+{
   DISPLAYABLE_PIXEL_TO_CHAR,
+  CHAR_TO_DISPLAYABLE_PIXEL,
   TOTAL_PIXEL_TO_CHAR,
   CHAR_TO_TOTAL_PIXEL,
-  CHAR_TO_DISPLAYABLE_PIXEL
-} pixel_to_char_mode_t;
+  TOTAL_PIXEL_TO_DISPLAYABLE_PIXEL,
+  DISPLAYABLE_PIXEL_TO_TOTAL_PIXEL,
+}
+pixel_to_char_mode_t;
+
+enum frame_size_type
+{
+  SIZE_TOTAL_PIXEL,
+  SIZE_DISPLAYABLE_PIXEL,
+  SIZE_CHAR_CELL,
+  SIZE_FRAME_UNIT,
+};
 
 static void frame_conversion_internal (struct frame *f,
-				       pixel_to_char_mode_t pixel_to_char,
-				       int *pixel_width, int *pixel_height,
-				       int *char_width, int *char_height,
-				       int real_face);
+				       enum frame_size_type source,
+				       int source_width, int source_height,
+				       enum frame_size_type dest,
+				       int *dest_width, int *dest_height);
+static void get_frame_char_size (struct frame *f, int *out_width,
+				 int *out_height);
+static void get_frame_displayable_pixel_size (struct frame *f, int *out_width,
+					      int *out_height);
+
 static struct display_line title_string_display_line;
 /* Used by generate_title_string. Global because they get used so much that
    the dynamic allocation time adds up. */
@@ -658,7 +959,7 @@
 	  reset_glyph_cachels (XWINDOW (f->minibuffer_window));
 	}
 
-      change_frame_size (f, f->height, f->width, 0);
+      change_frame_size (f, f->width, f->height, 0);
     }
 
   MAYBE_FRAMEMETH (f, init_frame_2, (f, props));
@@ -703,7 +1004,7 @@
 	 earlier. */
       init_frame_gutters (f);
 
-      change_frame_size (f, f->height, f->width, 0);
+      change_frame_size (f, f->width, f->height, 0);
     }
 
   if (first_frame_on_device)
@@ -826,9 +1127,9 @@
   if (!keep_char_size)
     {
       int height, width;
-      pixel_to_char_size (f, FRAME_PIXWIDTH(f), FRAME_PIXHEIGHT(f),
+      pixel_to_frame_unit_size (f, FRAME_PIXWIDTH(f), FRAME_PIXHEIGHT(f),
 			  &width, &height);
-      change_frame_size (f, height, width, 0);
+      change_frame_size (f, width, height, 0);
       CLEAR_FRAME_SIZE_SLIPPED (f);
     }
 }
@@ -2311,9 +2612,6 @@
 /*                           frame properties                              */
 /***************************************************************************/
 
-static void internal_set_frame_size (struct frame *f, int cols, int rows,
-				     int pretend);
-
 static void
 store_minibuf_frame_prop (struct frame *f, Lisp_Object val)
 {
@@ -2608,17 +2906,9 @@
 
   if (EQ (Qheight, property) || EQ (Qwidth, property))
     {
-      if (window_system_pixelated_geometry (frame))
-	{
-	  int width, height;
-	  pixel_to_real_char_size (f, FRAME_PIXWIDTH (f), FRAME_PIXHEIGHT (f),
-				   &width, &height);
-	  return make_int (EQ (Qheight, property) ? height: width);
-	}
-      else
-	return make_int (EQ (Qheight, property) ?
-			 FRAME_HEIGHT (f) :
-			 FRAME_WIDTH  (f));
+      int width, height;
+      get_frame_char_size (f, &width, &height);
+      return make_int (EQ (Qheight, property) ? height : width);
     }
 
   /* NOTE: FSF returns Qnil instead of Qt for FRAME_HAS_MINIBUF_P.
@@ -2710,17 +3000,7 @@
 		  result);
   {
     int width, height;
-
-    if (window_system_pixelated_geometry (frame))
-      {
-	pixel_to_real_char_size (f, FRAME_PIXWIDTH (f), FRAME_PIXHEIGHT (f),
-				 &width, &height);
-      }
-    else
-      {
-	height = FRAME_HEIGHT (f);
-	width = FRAME_WIDTH (f);
-      }
+    get_frame_char_size (f, &width, &height);
     result = cons3 (Qwidth , make_int (width),  result);
     result = cons3 (Qheight, make_int (height), result);
   }
@@ -2746,20 +3026,10 @@
        (frame))
 {
   struct frame *f = decode_frame (frame);
-  int height, pheight;
-  frame = wrap_frame (f);
-
-  if (!window_system_pixelated_geometry (frame))
-    {
-      height = FRAME_HEIGHT (f);
-
-      frame_conversion_internal (f, CHAR_TO_DISPLAYABLE_PIXEL,
-				 0, &pheight, 0, &height, 0);
-    }
-  else
-    pheight = FRAME_PIXHEIGHT (f);
-
-  return make_int (pheight);
+  int width, height;
+
+  get_frame_displayable_pixel_size (f, &width, &height);
+  return make_int (height);
 }
 
 DEFUN ("frame-pixel-width", Fframe_pixel_width, 0, 1, 0, /*
@@ -2776,20 +3046,10 @@
        (frame))
 {
   struct frame *f = decode_frame (frame);
-  int width, pwidth;
-  frame = wrap_frame (f);
-
-  if (!window_system_pixelated_geometry (frame))
-    {
-      width = FRAME_WIDTH (f);
-
-      frame_conversion_internal (f, CHAR_TO_DISPLAYABLE_PIXEL,
-				 &pwidth, 0, &width, 0, 0);
-    }
-  else
-    pwidth = FRAME_PIXWIDTH (f);
-
-  return make_int (pwidth);
+  int width, height;
+
+  get_frame_displayable_pixel_size (f, &width, &height);
+  return make_int (width);
 }
 
 DEFUN ("frame-name", Fframe_name, 0, 1, 0, /*
@@ -2815,7 +3075,7 @@
   return make_int (decode_frame (frame)->modiff);
 }
 
-static void
+void
 internal_set_frame_size (struct frame *f, int cols, int rows, int pretend)
 {
   /* This can call Lisp.  See mswindows_set_frame_size(). */
@@ -2823,7 +3083,7 @@
   CLEAR_FRAME_SIZE_SLIPPED (f);
 
   if (pretend || !HAS_FRAMEMETH_P (f, set_frame_size))
-    change_frame_size (f, rows, cols, 0);
+    change_frame_size (f, cols, rows, 0);
   else
     FRAMEMETH (f, set_frame_size, (f, cols, rows));
 }
@@ -2837,23 +3097,16 @@
 {
   /* This can call Lisp. */
   struct frame *f = decode_frame (frame);
-  int height, width;
-  frame = wrap_frame (f);
+  int cwidth, cheight;
+  int guwidth, guheight;
+
   CHECK_INT (lines);
-
-  if (window_system_pixelated_geometry (frame))
-    {
-      char_to_real_pixel_size (f, 0, XINT (lines), 0, &height);
-      width = FRAME_PIXWIDTH (f);
-    }
-  else
-    {
-      height = XINT (lines);
-      width = FRAME_WIDTH (f);
-    }
-
-  internal_set_frame_size (f, width, height, !NILP (pretend));
-  return frame;
+  get_frame_char_size (f, &cwidth, &cheight);
+  cheight = XINT (lines);
+  frame_conversion_internal (f, SIZE_CHAR_CELL, cwidth, cheight,
+			     SIZE_FRAME_UNIT, &guwidth, &guheight);
+  internal_set_frame_size (f, guwidth, guheight, !NILP (pretend));
+  return wrap_frame (f);
 }
 
 DEFUN ("set-frame-pixel-height", Fset_frame_pixel_height, 2, 3, 0, /*
@@ -2865,25 +3118,16 @@
 {
   /* This can call Lisp. */
   struct frame *f = decode_frame (frame);
-  int pheight, width;
-  frame = wrap_frame (f);
+  int pwidth, pheight;
+  int guwidth, guheight;
+
   CHECK_INT (height);
-
-  if (!window_system_pixelated_geometry (frame))
-    {
-      int h = XINT (height);
-      width = FRAME_WIDTH (f);
-
-      frame_conversion_internal (f, TOTAL_PIXEL_TO_CHAR, 0, &h, 0, &pheight, 0);
-    }
-  else
-    {
-      width = FRAME_PIXWIDTH (f);
-      pheight = XINT (height);
-    }
-
-  internal_set_frame_size (f, width, pheight, !NILP (pretend));
-  return frame;
+  pheight = XINT (height);
+  pwidth = FRAME_PIXWIDTH (f);
+  frame_conversion_internal (f, SIZE_TOTAL_PIXEL, pwidth, pheight,
+			     SIZE_FRAME_UNIT, &guwidth, &guheight);
+  internal_set_frame_size (f, guwidth, guheight, !NILP (pretend));
+  return wrap_frame (f);
 }
 
 DEFUN ("set-frame-displayable-pixel-height", Fset_frame_displayable_pixel_height, 2, 3, 0, /*
@@ -2895,24 +3139,16 @@
 {
   /* This can call Lisp. */
   struct frame *f = decode_frame (frame);
-  int pheight, width;
-  frame = wrap_frame (f);
+  int pwidth, pheight;
+  int guwidth, guheight;
+
   CHECK_INT (height);
-
-  if (!window_system_pixelated_geometry (frame))
-    {
-      int h = XINT (height);
-      width = FRAME_WIDTH (f);
-      frame_conversion_internal (f, DISPLAYABLE_PIXEL_TO_CHAR, 0, &h, 0, &pheight, 0);
-    }
-  else
-    {
-      width = FRAME_PIXWIDTH (f);
-      pheight = XINT (height);
-    }
-
-  internal_set_frame_size (f, width, pheight, !NILP (pretend));
-  return frame;
+  get_frame_displayable_pixel_size (f, &pwidth, &pheight);
+  pheight = XINT (height);
+  frame_conversion_internal (f, SIZE_DISPLAYABLE_PIXEL, pwidth, pheight,
+			     SIZE_FRAME_UNIT, &guwidth, &guheight);
+  internal_set_frame_size (f, guwidth, guheight, !NILP (pretend));
+  return wrap_frame (f);
 }
 
 
@@ -2925,23 +3161,16 @@
 {
   /* This can call Lisp. */
   struct frame *f = decode_frame (frame);
-  int width, height;
-  frame = wrap_frame (f);
+  int cwidth, cheight;
+  int guwidth, guheight;
+
   CHECK_INT (cols);
-
-  if (window_system_pixelated_geometry (frame))
-    {
-      char_to_real_pixel_size (f, XINT (cols), 0, &width, 0);
-      height = FRAME_PIXHEIGHT (f);
-    }
-  else
-    {
-      width = XINT (cols);
-      height = FRAME_HEIGHT (f);
-    }
-
-  internal_set_frame_size (f, width, height, !NILP (pretend));
-  return frame;
+  get_frame_char_size (f, &cwidth, &cheight);
+  cwidth = XINT (cols);
+  frame_conversion_internal (f, SIZE_CHAR_CELL, cwidth, cheight,
+			     SIZE_FRAME_UNIT, &guwidth, &guheight);
+  internal_set_frame_size (f, guwidth, guheight, !NILP (pretend));
+  return wrap_frame (f);
 }
 
 DEFUN ("set-frame-pixel-width", Fset_frame_pixel_width, 2, 3, 0, /*
@@ -2953,24 +3182,16 @@
 {
   /* This can call Lisp. */
   struct frame *f = decode_frame (frame);
-  int height, pwidth;
-  frame = wrap_frame (f);
+  int pwidth, pheight;
+  int guwidth, guheight;
+
   CHECK_INT (width);
-
-  if (!window_system_pixelated_geometry (frame))
-    {
-      int w = XINT (width);
-      height = FRAME_HEIGHT (f);
-      frame_conversion_internal (f, TOTAL_PIXEL_TO_CHAR, &w, 0, &pwidth, 0, 0);
-    }
-  else
-    {
-      height = FRAME_PIXHEIGHT (f);
-      pwidth = XINT (width);
-    }
-
-  internal_set_frame_size (f, pwidth, height, !NILP (pretend));
-  return frame;
+  pwidth = XINT (width);
+  pheight = FRAME_PIXHEIGHT (f);
+  frame_conversion_internal (f, SIZE_TOTAL_PIXEL, pwidth, pheight,
+			     SIZE_FRAME_UNIT, &guwidth, &guheight);
+  internal_set_frame_size (f, guwidth, guheight, !NILP (pretend));
+  return wrap_frame (f);
 }
 
 DEFUN ("set-frame-displayable-pixel-width", Fset_frame_displayable_pixel_width, 2, 3, 0, /*
@@ -2982,24 +3203,16 @@
 {
   /* This can call Lisp. */
   struct frame *f = decode_frame (frame);
-  int height, pwidth;
-  frame = wrap_frame (f);
+  int pwidth, pheight;
+  int guwidth, guheight;
+
   CHECK_INT (width);
-
-  if (!window_system_pixelated_geometry (frame))
-    {
-      int w = XINT (width);
-      height = FRAME_HEIGHT (f);
-      frame_conversion_internal (f, DISPLAYABLE_PIXEL_TO_CHAR, &w, 0, &pwidth, 0, 0);
-    }
-  else
-    {
-      height = FRAME_PIXHEIGHT (f);
-      pwidth = XINT (width);
-    }
-
-  internal_set_frame_size (f, pwidth, height, !NILP (pretend));
-  return frame;
+  get_frame_displayable_pixel_size (f, &pwidth, &pheight);
+  pwidth = XINT (width);
+  frame_conversion_internal (f, SIZE_DISPLAYABLE_PIXEL, pwidth, pheight,
+			     SIZE_FRAME_UNIT, &guwidth, &guheight);
+  internal_set_frame_size (f, guwidth, guheight, !NILP (pretend));
+  return wrap_frame (f);
 }
 
 DEFUN ("set-frame-size", Fset_frame_size, 3, 4, 0, /*
@@ -3011,21 +3224,14 @@
 {
   /* This can call Lisp. */
   struct frame *f = decode_frame (frame);
-  int height, width;
-  frame = wrap_frame (f);
+  int guwidth, guheight;
+
   CHECK_INT (cols);
   CHECK_INT (rows);
-
-  if (window_system_pixelated_geometry (frame))
-    char_to_real_pixel_size (f, XINT (cols), XINT (rows), &width, &height);
-  else
-    {
-      height = XINT (rows);
-      width = XINT (cols);
-    }
-
-  internal_set_frame_size (f, width, height, !NILP (pretend));
-  return frame;
+  frame_conversion_internal (f, SIZE_CHAR_CELL, XINT (cols), XINT (rows),
+			     SIZE_FRAME_UNIT, &guwidth, &guheight);
+  internal_set_frame_size (f, guwidth, guheight, !NILP (pretend));
+  return wrap_frame (f);
 }
 
 DEFUN ("set-frame-pixel-size", Fset_frame_pixel_size, 3, 4, 0, /*
@@ -3037,25 +3243,14 @@
 {
   /* This can call Lisp. */
   struct frame *f = decode_frame (frame);
-  int pheight, pwidth;
-  frame = wrap_frame (f);
+  int guwidth, guheight;
+
   CHECK_INT (width);
   CHECK_INT (height);
-
-  if (!window_system_pixelated_geometry (frame))
-    {
-      int w = XINT (width);
-      int h = XINT (height);
-      frame_conversion_internal (f, TOTAL_PIXEL_TO_CHAR, &w, &h, &pwidth, &pheight, 0);
-    }
-  else
-    {
-      pheight = XINT (height);
-      pwidth = XINT (width);
-    }
-
-  internal_set_frame_size (f, pwidth, pheight, !NILP (pretend));
-  return frame;
+  frame_conversion_internal (f, SIZE_TOTAL_PIXEL, XINT (width), XINT (height),
+			     SIZE_FRAME_UNIT, &guwidth, &guheight);
+  internal_set_frame_size (f, guwidth, guheight, !NILP (pretend));
+  return wrap_frame (f);
 }
 
 DEFUN ("set-frame-displayable-pixel-size", Fset_frame_displayable_pixel_size, 3, 4, 0, /*
@@ -3067,25 +3262,15 @@
 {
   /* This can call Lisp. */
   struct frame *f = decode_frame (frame);
-  int pheight, pwidth;
-  frame = wrap_frame (f);
+  int guwidth, guheight;
+
   CHECK_INT (width);
   CHECK_INT (height);
-
-  if (!window_system_pixelated_geometry (frame))
-    {
-      int w = XINT (width);
-      int h = XINT (height);
-      frame_conversion_internal (f, DISPLAYABLE_PIXEL_TO_CHAR, &w, &h, &pwidth, &pheight, 0);
-    }
-  else
-    {
-      pheight = XINT (height);
-      pwidth = XINT (width);
-    }
-
-  internal_set_frame_size (f, pwidth, pheight, !NILP (pretend));
-  return frame;
+  frame_conversion_internal (f, SIZE_DISPLAYABLE_PIXEL,
+			     XINT (width), XINT (height),
+			     SIZE_FRAME_UNIT, &guwidth, &guheight);
+  internal_set_frame_size (f, guwidth, guheight, !NILP (pretend));
+  return wrap_frame (f);
 }
 
 DEFUN ("set-frame-position", Fset_frame_position, 3, 3, 0, /*
@@ -3110,25 +3295,26 @@
 /* Frame size conversion functions moved here from EmacsFrame.c
    because they're generic and really don't belong in that file.
    Function get_default_char_pixel_size() removed because it's
-   exactly the same as default_face_height_and_width(). */
+   exactly the same as default_face_height_and_width().
+
+   Convert between total pixel size, displayable pixel size and
+   character-cell size.  Variables are either "in" or "out"
+   depending on the value of PIXEL_TO_CHAR.
+*/
 static void
-frame_conversion_internal (struct frame *f,
-			   pixel_to_char_mode_t pixel_to_char,
-			   int *pixel_width, int *pixel_height,
-			   int *char_width, int *char_height,
-			   int real_face)
+frame_conversion_internal_1 (struct frame *f,
+			     pixel_to_char_mode_t pixel_to_char,
+			     int *total_pixel_width, int *total_pixel_height,
+			     int *disp_pixel_width, int *disp_pixel_height,
+			     int *char_width, int *char_height)
 {
-  int cpw;
-  int cph;
+  int cpw, cph;
   int egw;
   int obw, obh, bdr;
   Lisp_Object frame, window;
 
   frame = wrap_frame (f);
-  if (real_face)
-    default_face_height_and_width (frame, &cph, &cpw);
-  else
-    default_face_height_and_width_1 (frame, &cph, &cpw);
+  default_face_height_and_width (frame, &cph, &cpw);
 
   window = FRAME_SELECTED_WINDOW (f);
 
@@ -3154,34 +3340,115 @@
     {
     case DISPLAYABLE_PIXEL_TO_CHAR:
       if (char_width)
-	*char_width = ROUND_UP (*pixel_width, cpw) / cpw;
+	*char_width = ROUND_UP (*disp_pixel_width, cpw) / cpw;
       if (char_height)
-	*char_height = ROUND_UP (*pixel_height, cph) / cph;
+	*char_height = ROUND_UP (*disp_pixel_height, cph) / cph;
+      break;
+    case CHAR_TO_DISPLAYABLE_PIXEL:
+      if (disp_pixel_width)
+	*disp_pixel_width = *char_width * cpw;
+      if (disp_pixel_height)
+	*disp_pixel_height = *char_height * cph;
       break;
     case TOTAL_PIXEL_TO_CHAR:
       /* Convert to chars so that the total frame size is pixel_width x
 	 pixel_height. */
       if (char_width)
-	*char_width = 1 + ((*pixel_width - egw) - bdr - obw) / cpw;
+	*char_width = 1 + ((*total_pixel_width - egw) - bdr - obw) / cpw;
       if (char_height)
-	*char_height = (*pixel_height - bdr - obh) / cph;
+	*char_height = (*total_pixel_height - bdr - obh) / cph;
       break;
     case CHAR_TO_TOTAL_PIXEL:
-      if (pixel_width)
-	*pixel_width = (*char_width - 1) * cpw + egw + bdr + obw;
-      if (pixel_height)
-	*pixel_height = *char_height * cph + bdr + obh;
+      if (total_pixel_width)
+	*total_pixel_width = (*char_width - 1) * cpw + egw + bdr + obw;
+      if (total_pixel_height)
+	*total_pixel_height = *char_height * cph + bdr + obh;
       break;
-    case CHAR_TO_DISPLAYABLE_PIXEL:
-      if (pixel_width)
-	*pixel_width = *char_width * cpw;
-      if (pixel_height)
-	*pixel_height = *char_height * cph;
+    case TOTAL_PIXEL_TO_DISPLAYABLE_PIXEL:
+      /* Convert to chars so that the total frame size is pixel_width x
+	 pixel_height. */
+      if (disp_pixel_width)
+	*disp_pixel_width = cpw + (*total_pixel_width - egw) - bdr - obw;
+      if (disp_pixel_height)
+	*disp_pixel_height = *total_pixel_height - bdr - obh;
+      break;
+    case DISPLAYABLE_PIXEL_TO_TOTAL_PIXEL:
+      if (total_pixel_width)
+	*total_pixel_width = *disp_pixel_width - cpw + egw + bdr + obw;
+      if (total_pixel_height)
+	*total_pixel_height = *disp_pixel_height + bdr + obh;
       break;
     }
 }
 
-/* This takes the size in pixels of the text area, and returns the number
+
+static enum frame_size_type
+canonicalize_frame_size_type (enum frame_size_type type, int pixgeom)
+{
+  if (type == SIZE_FRAME_UNIT)
+    {
+      if (pixgeom)
+	type = SIZE_DISPLAYABLE_PIXEL;
+      else
+	type = SIZE_CHAR_CELL;
+    }
+  return type;
+}
+
+/* Basic frame conversion function.  Convert source size to destination
+   size, where either of them can be in total pixels, displayable pixels,
+   frame units or character-cell units. */
+
+static void
+frame_conversion_internal (struct frame *f,
+			   enum frame_size_type source,
+			   int source_width, int source_height,
+			   enum frame_size_type dest,
+			   int *dest_width, int *dest_height)
+{
+  int pixgeom = window_system_pixelated_geometry (wrap_frame (f));
+  dest = canonicalize_frame_size_type (dest, pixgeom);
+  source = canonicalize_frame_size_type (source, pixgeom);
+  if (source == dest)
+    {
+      *dest_width = source_width;
+      *dest_height = source_height;
+    }
+  else if (source == SIZE_TOTAL_PIXEL && dest == SIZE_CHAR_CELL)
+    frame_conversion_internal_1 (f, TOTAL_PIXEL_TO_CHAR,
+				 &source_width, &source_height, 0, 0,
+				 dest_width, dest_height);
+  else if (source == SIZE_DISPLAYABLE_PIXEL && dest == SIZE_CHAR_CELL)
+    frame_conversion_internal_1 (f, DISPLAYABLE_PIXEL_TO_CHAR, 0, 0,
+				 &source_width, &source_height,
+				 dest_width, dest_height);
+  else if (source == SIZE_TOTAL_PIXEL && dest == SIZE_DISPLAYABLE_PIXEL)
+    frame_conversion_internal_1 (f, TOTAL_PIXEL_TO_DISPLAYABLE_PIXEL,
+				 &source_width, &source_height,
+				 dest_width, dest_height, 0, 0);
+  else if (dest == SIZE_TOTAL_PIXEL && source == SIZE_CHAR_CELL)
+    frame_conversion_internal_1 (f, CHAR_TO_TOTAL_PIXEL,
+				 dest_width, dest_height, 0, 0,
+				 &source_width, &source_height);
+  else if (dest == SIZE_DISPLAYABLE_PIXEL && source == SIZE_CHAR_CELL)
+    frame_conversion_internal_1 (f, CHAR_TO_DISPLAYABLE_PIXEL, 0, 0,
+				 dest_width, dest_height,
+				 &source_width, &source_height);
+  else if (dest == SIZE_TOTAL_PIXEL && source == SIZE_DISPLAYABLE_PIXEL)
+    frame_conversion_internal_1 (f, DISPLAYABLE_PIXEL_TO_TOTAL_PIXEL,
+				 dest_width, dest_height,
+				 &source_width, &source_height, 0, 0);
+  else
+    {
+      ABORT ();
+      if (dest_width)
+	*dest_width = 0;
+      if (dest_height)
+	*dest_height = 0;
+    }
+}
+
+/* This takes the size in pixels of the client area, and returns the number
    of characters that will fit there, taking into account the internal
    border width, and the pixel width of the line terminator glyphs (which
    always count as one "character" wide, even if they are not the same size
@@ -3192,35 +3459,56 @@
 
    Therefore the result is not necessarily a multiple of anything in
    particular.  */
+
 void
 pixel_to_char_size (struct frame *f, int pixel_width, int pixel_height,
 		    int *char_width, int *char_height)
 {
-  frame_conversion_internal (f, TOTAL_PIXEL_TO_CHAR,
-			     &pixel_width, &pixel_height, char_width,
-			     char_height, 0);
+  frame_conversion_internal (f, SIZE_TOTAL_PIXEL, pixel_width, pixel_height,
+			     SIZE_CHAR_CELL, char_width, char_height);
 }
 
-/* Given a character size, this returns the minimum number of pixels
-   necessary to display that many characters, taking into account the
-   internal border width, scrollbar height and width, toolbar heights and
-   widths and the size of the line terminator glyphs (assuming the line
-   terminators take up exactly one character position).
+/* Given a character size, this returns the minimum pixel size of the
+   client area necessary to display that many characters, taking into
+   account the internal border width, scrollbar height and width, toolbar
+   heights and widths and the size of the line terminator glyphs (assuming
+   the line terminators take up exactly one character position).
 
    Therefore the result is not necessarily a multiple of anything in
    particular.  */
+
 void
 char_to_pixel_size (struct frame *f, int char_width, int char_height,
 		    int *pixel_width, int *pixel_height)
 {
-  frame_conversion_internal (f, CHAR_TO_TOTAL_PIXEL,
-			     pixel_width, pixel_height, &char_width,
-			     &char_height, 0);
+  frame_conversion_internal (f, SIZE_CHAR_CELL, char_width, char_height,
+			     SIZE_TOTAL_PIXEL, pixel_width, pixel_height);
 }
 
-/* Given a pixel size, rounds DOWN to the smallest size in pixels necessary
-   to display the same number of characters as are displayable now.
- */
+/* Versions of the above that operate in "frame units" instead of
+   characters.  frame units are the same as characters except on
+   MS Windows and MS Printer frames, where they are displayable-area
+   pixels. */
+
+void
+pixel_to_frame_unit_size (struct frame *f, int pixel_width, int pixel_height,
+			 int *frame_unit_width, int *frame_unit_height)
+{
+  frame_conversion_internal (f, SIZE_TOTAL_PIXEL, pixel_width, pixel_height,
+			     SIZE_FRAME_UNIT, frame_unit_width,
+			     frame_unit_height);
+}
+
+void
+frame_unit_to_pixel_size (struct frame *f, int frame_unit_width,
+			 int frame_unit_height,
+			 int *pixel_width, int *pixel_height)
+{
+  frame_conversion_internal (f, SIZE_FRAME_UNIT, frame_unit_width,
+			     frame_unit_height,
+			     SIZE_TOTAL_PIXEL, pixel_width, pixel_height);
+}
+
 void
 round_size_to_char (struct frame *f, int in_width, int in_height,
 		    int *out_width, int *out_height)
@@ -3231,44 +3519,49 @@
   char_to_pixel_size (f, char_width, char_height, out_width, out_height);
 }
 
-/* Versions of the above which always account for real font metrics.
- */
-void
-pixel_to_real_char_size (struct frame *f, int pixel_width, int pixel_height,
-			 int *char_width, int *char_height)
+/* Get the frame size in character cells, recalculating on the fly.
+   #### The logic of this function follows former logic elsewhere,
+   which used FRAME_PIXWIDTH() on pixelated-geometry systems but
+   FRAME_WIDTH() on non-pixelated-geometry systems.  Not clear why not
+   always just use one or the other.
+
+   Why don't we just use FRAME_CHARWIDTH() etc. in get_frame_char_size()?
+   That wouldn't work because change_frame_size_1() depends on the
+   following function to *set* the values of FRAME_CHARWIDTH() etc.
+
+   But elsewhere I suppose we could use it.
+*/
+
+static void
+get_frame_char_size (struct frame *f, int *out_width, int *out_height)
 {
-  frame_conversion_internal (f, TOTAL_PIXEL_TO_CHAR,
-			     &pixel_width, &pixel_height, char_width,
-			     char_height, 1);
+  if (window_system_pixelated_geometry (wrap_frame (f)))
+    pixel_to_char_size (f, FRAME_PIXWIDTH (f), FRAME_PIXHEIGHT (f),
+			out_width, out_height);
+  else
+    {
+      *out_width = FRAME_WIDTH (f);
+      *out_height = FRAME_HEIGHT (f);
+    }
 }
 
-void
-char_to_real_pixel_size (struct frame *f, int char_width, int char_height,
-			 int *pixel_width, int *pixel_height)
+static void
+get_frame_displayable_pixel_size (struct frame *f, int *out_width,
+				  int *out_height)
 {
-  frame_conversion_internal (f, CHAR_TO_TOTAL_PIXEL,
-			     pixel_width, pixel_height, &char_width,
-			     &char_height, 1);
-}
-
-void
-round_size_to_real_char (struct frame *f, int in_width, int in_height,
-			 int *out_width, int *out_height)
-{
-  int char_width;
-  int char_height;
-  pixel_to_real_char_size (f, in_width, in_height, &char_width, &char_height);
-  char_to_real_pixel_size (f, char_width, char_height, out_width, out_height);
+  frame_conversion_internal (f, SIZE_FRAME_UNIT, FRAME_WIDTH (f),
+			     FRAME_HEIGHT (f), SIZE_DISPLAYABLE_PIXEL,
+			     out_width, out_height);
 }
 
 /* Change the frame height and/or width.  Values may be given as zero to
    indicate no change is to take place. */
 static void
-change_frame_size_1 (struct frame *f, int newheight, int newwidth)
+change_frame_size_1 (struct frame *f, int newwidth, int newheight)
 {
   Lisp_Object frame;
   int new_pixheight, new_pixwidth;
-  int font_height, real_font_height, font_width;
+  int real_font_height, real_font_width;
 
   /* #### Chuck -- shouldn't we be checking to see if the frame
      is being "changed" to its existing size, and do nothing if so? */
@@ -3279,18 +3572,29 @@
   if (in_display || hold_frame_size_changes)
     ABORT ();
 
+  /* If we don't have valid values, exit. */
+  if (!newheight && !newwidth)
+    return;
+
   frame = wrap_frame (f);
 
-  default_face_height_and_width (frame, &real_font_height, 0);
-  default_face_height_and_width_1 (frame, &font_height, &font_width);
+  default_face_height_and_width (frame, &real_font_height, &real_font_width);
+  if (window_system_pixelated_geometry (frame))
+    {
+      new_pixheight = newheight;
+      new_pixwidth = newwidth - real_font_width;
+    }
+  else
+    {
+      new_pixheight = newheight * real_font_height;
+      new_pixwidth = (newwidth - 1) * real_font_width;
+    }
 
   /* This size-change overrides any pending one for this frame.  */
   f->size_change_pending = 0;
   FRAME_NEW_HEIGHT (f) = 0;
   FRAME_NEW_WIDTH (f) = 0;
 
-  new_pixheight = newheight * font_height;
-  new_pixwidth = (newwidth - 1) * font_width;
 
   /* #### dependency on FRAME_WIN_P should be removed. */
   if (FRAME_WIN_P (f))
@@ -3338,16 +3642,12 @@
     cont_width = glyph_width (Vcontinuation_glyph,
 			      FRAME_SELECTED_WINDOW (f));
     adjustment = max (trunc_width, cont_width);
-    adjustment = max (adjustment, font_width);
+    adjustment = max (adjustment, real_font_width);
 
     new_pixwidth += adjustment;
   }
 
-  /* If we don't have valid values, exit. */
-  if (!new_pixheight && !new_pixwidth)
-    return;
-
-  if (new_pixheight)
+  if (newheight)
     {
       /* Adjust for gutters here so that we always get set
 	 properly. */
@@ -3398,7 +3698,7 @@
 	f->pixheight = newheight;
     }
 
-  if (new_pixwidth)
+  if (newwidth)
     {
       /* Adjust for gutters here so that we always get set
 	 properly. */
@@ -3422,14 +3722,7 @@
 	f->pixwidth = newwidth;
     }
 
-  if (window_system_pixelated_geometry (frame))
-    pixel_to_real_char_size (f, FRAME_PIXWIDTH (f), FRAME_PIXHEIGHT (f),
-			     &FRAME_CHARWIDTH (f), &FRAME_CHARHEIGHT (f));
-  else
-    {
-      FRAME_CHARWIDTH (f) = FRAME_WIDTH (f);
-      FRAME_CHARHEIGHT (f) = FRAME_HEIGHT (f);
-    }
+  get_frame_char_size (f, &FRAME_CHARWIDTH (f), &FRAME_CHARHEIGHT (f));
 
   MARK_FRAME_TOOLBARS_CHANGED (f);
   MARK_FRAME_GUTTERS_CHANGED (f);
@@ -3438,7 +3731,7 @@
 }
 
 void
-change_frame_size (struct frame *f, int newheight, int newwidth, int delay)
+change_frame_size (struct frame *f, int newwidth, int newheight, int delay)
 {
   /* sometimes we get passed a size that's too small (esp. when a
      client widget gets resized, since we have no control over this).
@@ -3470,10 +3763,10 @@
       Lisp_Object frmcons;
 
       DEVICE_FRAME_LOOP (frmcons, XDEVICE (FRAME_DEVICE (f)))
-	change_frame_size_1 (XFRAME (XCAR (frmcons)), newheight, newwidth);
+	change_frame_size_1 (XFRAME (XCAR (frmcons)), newwidth, newheight);
     }
   else
-    change_frame_size_1 (f, newheight, newwidth);
+    change_frame_size_1 (f, newwidth, newheight);
 }