Subject: bug#52493: 29.0.50; Setting Inconsolata up in init.el makes default face rendered wrong

From: martin rudalics <[email-masked]>
Date: Fri, 6 Jan 2023 18:47:10 +0100

> So I double-checked -- and both behaviors with the latest patch match
 > what the current (unpatched) emacs-29 does.

With one subtle difference: In the unpatched version the WM shrinks the
size.  In the patched version we do it ourselves and the WM does what we
are asking for.

   x_new_font old char size 18x36 new char size 21x45 text chars 102x36 old text pixels 1836x1296 new text pixels 2142x1620
   xg_wm_set_size_hint scale 2 char width 21 toolbar 0 vscroll 32 fringes 16 borders 0 base width 34 width inc 10
       char height 45 menubar 50 toolbar 82 hscroll 0 borders 0 base height 88 height inc 22
   xg_frame_set_char_size old native pixels 1884x1296 new native pixels 2190x1620 outer pixels 1094x858 outer rest 0x0
   xg_frame_resized old native pixels 1884x1296 new native pixels 2188x1584
   adjust_frame_size old native pixels 1884x1296 new native pixels 2188x1584 old text pixels 1836x1296 new text pixels 2140x1584 old text chars 102x36 new text chars 101x35

Here we round down the outer pixel sizes from 1095x876 to 1094x858 to
meet the WM requirements (outer rest is 0x0 in all your steps).  So
incidentally, I reverse-engineered the WM.  Now let's try to round up
instead.  I'm quite confident that this will make your frames grow.

martin

diff --git a/lisp/window.el b/lisp/window.el
index a11293d372..706c988b2e 100644
--- a/lisp/window.el
+++ b/lisp/window.el
@@ -10596,6 +10596,21 @@ window-prefix-map
   "0" #'delete-windows-on)
 (define-key ctl-x-map "w" window-prefix-map)
 
+(defun foo-it (&rest rest)
+  (with-current-buffer (get-buffer-create "*foo*")
+    (goto-char (point-max))
+    (when rest
+      (if (consp (car rest))
+          (insert (format "%sx%s" (caar rest) (cdar rest)))
+        (insert (format "%s" (car rest))))
+      (setq rest (cdr rest))
+      (while rest
+        (if (consp (car rest))
+            (insert (format " %sx%s" (caar rest) (cdar rest)))
+	  (insert (format " %s" (car rest))))
+	(setq rest (cdr rest)))
+      (insert "\n"))))
+
 (provide 'window)
 
 ;;; window.el ends here
diff --git a/src/frame.c b/src/frame.c
index b57b296be5..d7d069d908 100644
--- a/src/frame.c
+++ b/src/frame.c
@@ -906,6 +906,32 @@ adjust_frame_size (struct frame *f, int new_text_width, int new_text_height,
 
   unblock_input ();
 
+  if (old_native_width != new_native_width
+      || old_native_height != new_native_height
+      || old_text_width != new_text_width
+      || old_text_height != new_text_height
+      || old_text_cols != new_text_cols
+      || old_text_lines != new_text_lines)
+    CALLN (Ffuncall, Qfoo_it, intern ("adjust_frame_size"),
+	   intern ("old native pixels"),
+	   Fcons (make_fixnum (old_native_width),
+		  make_fixnum (old_native_height)),
+	   intern ("new native pixels"),
+	   Fcons (make_fixnum (new_native_width),
+		  make_fixnum (new_native_height)),
+	   intern ("old text pixels"),
+	   Fcons (make_fixnum (old_text_width),
+		  make_fixnum (old_text_height)),
+	   intern ("new text pixels"),
+	   Fcons (make_fixnum (new_text_width),
+		  make_fixnum (new_text_height)),
+	   intern ("old text chars"),
+	   Fcons (make_fixnum (old_text_cols),
+		  make_fixnum (old_text_lines)),
+	   intern ("new text chars"),
+	   Fcons (make_fixnum (new_text_cols),
+		  make_fixnum (new_text_lines)));
+
 #ifdef HAVE_WINDOW_SYSTEM
   {
     /* Adjust size of F's child frames.  */
diff --git a/src/gtkutil.c b/src/gtkutil.c
index a6bba096a4..0900fdfd72 100644
--- a/src/gtkutil.c
+++ b/src/gtkutil.c
@@ -1149,6 +1149,14 @@ xg_frame_resized (struct frame *f, int width, int height)
 	   f->new_size_p ? f->new_height : -1);
 
       FRAME_RIF (f)->clear_under_internal_border (f);
+
+      CALLN (Ffuncall, Qfoo_it, intern ("xg_frame_resized"),
+	     intern ("old native pixels"),
+	     Fcons (make_fixnum (FRAME_PIXEL_WIDTH (f)),
+		    make_fixnum (FRAME_PIXEL_HEIGHT (f))),
+	     intern ("new native pixels"),
+	     Fcons (make_fixnum (width), make_fixnum (height)));
+
       change_frame_size (f, width, height, false, true, false);
       SET_FRAME_GARBAGED (f);
       cancel_mouse_face (f);
@@ -1174,6 +1182,8 @@ xg_frame_set_char_size (struct frame *f, int width, int height)
   int outer_width = width + FRAME_TOOLBAR_WIDTH (f);
   bool was_visible = false;
   bool hide_child_frame;
+  int scale = xg_get_scale (f);
+  GdkGeometry size_hints = f->output_data.xp->size_hints;
 
 #ifndef HAVE_PGTK
   gtk_window_get_size (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
@@ -1196,8 +1206,41 @@ xg_frame_set_char_size (struct frame *f, int width, int height)
   /* Do this before resize, as we don't know yet if we will be resized.  */
   FRAME_RIF (f)->clear_under_internal_border (f);
 
-  outer_height /= xg_get_scale (f);
-  outer_width /= xg_get_scale (f);
+  outer_height /= scale;
+  outer_width /= scale;
+
+  if (scale != 1 && !frame_resize_pixelwise)
+    {
+      int base_width = (FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, 1)
+			+ FRAME_TOOLBAR_WIDTH (f)) / scale;
+      int base_height = (FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, 1)
+			 + FRAME_MENUBAR_HEIGHT (f)
+			 + FRAME_TOOLBAR_HEIGHT (f)) / scale;
+      int width_inc = FRAME_COLUMN_WIDTH (f) / scale;
+      int height_inc = FRAME_LINE_HEIGHT (f) / scale;
+      int width_rest, height_rest;
+
+
+      if (width_inc < 1)
+	width_inc = 1;
+
+      if (height_inc < 1)
+	height_inc = 1;
+
+      if (outer_width < base_width)
+	outer_width = base_width;
+
+      if (outer_height < base_height)
+	outer_height = base_height;
+
+      width_rest = (outer_width - base_width) % width_inc;
+      height_rest = (outer_height - base_height) % height_inc;
+
+      if (width_rest > 0)
+	outer_width = outer_width + width_inc - width_rest;
+      if (height_rest > 0)
+	outer_height = outer_height + height_inc - height_rest;
+    }
 
   xg_wm_set_size_hint (f, 0, 0);
 
@@ -1317,6 +1360,30 @@ xg_frame_set_char_size (struct frame *f, int width, int height)
   SET_FRAME_GARBAGED (f);
   cancel_mouse_face (f);
 
+  size_hints = f->output_data.xp->size_hints;
+  if (outer_width > 0 && size_hints.base_width > 0 && size_hints.width_inc > 0
+      && outer_height > 0 && size_hints.base_height > 0 && size_hints.height_inc > 0)
+    CALLN (Ffuncall, Qfoo_it, intern ("xg_frame_set_char_size"),
+	   intern ("old native pixels"),
+	   Fcons (make_fixnum (FRAME_PIXEL_WIDTH (f)),
+		  make_fixnum (FRAME_PIXEL_HEIGHT (f))),
+	   intern ("new native pixels"),
+	   Fcons (make_fixnum (width), make_fixnum (height)),
+	   intern ("outer pixels"),
+	   Fcons (make_fixnum (outer_width), make_fixnum (outer_height)),
+	   intern ("outer rest"),
+	   Fcons (make_fixnum ((outer_width - size_hints.base_width) % size_hints.width_inc),
+		  make_fixnum ((outer_height - size_hints.base_height) % size_hints.height_inc)));
+  else
+    CALLN (Ffuncall, Qfoo_it, intern ("xg_frame_set_char_size"),
+	   intern ("old native pixels"),
+	   Fcons (make_fixnum (FRAME_PIXEL_WIDTH (f)),
+		  make_fixnum (FRAME_PIXEL_HEIGHT (f))),
+	   intern ("new native pixels"),
+	   Fcons (make_fixnum (width), make_fixnum (height)),
+	   intern ("outer pixels"),
+	   Fcons (make_fixnum (outer_width), make_fixnum (outer_height)));
+
   /* We can not call change_frame_size for a mapped frame,
      we can not set pixel width/height either.  The window manager may
      override our resize request, XMonad does this all the time.
@@ -2028,6 +2095,24 @@ xg_wm_set_size_hint (struct frame *f, long int flags, bool user_position)
 		 &f->output_data.xp->size_hints,
 		 sizeof (size_hints)) != 0)
     {
+      CALLN (Ffuncall, Qfoo_it, intern ("xg_wm_set_size_hint"),
+	     intern ("scale"), make_fixnum (scale),
+	     intern ("char width"), make_fixnum (FRAME_COLUMN_WIDTH (f)),
+	     intern ("toolbar"), make_fixnum (FRAME_TOOLBAR_WIDTH (f)),
+	     intern ("vscroll"), make_fixnum (FRAME_SCROLL_BAR_AREA_WIDTH (f)),
+	     intern ("fringes"), make_fixnum (FRAME_TOTAL_FRINGE_WIDTH (f)),
+	     intern ("borders"), make_fixnum (2 * FRAME_INTERNAL_BORDER_WIDTH (f)),
+	     intern ("base width"), make_fixnum (size_hints.base_width),
+	     intern ("width inc"), make_fixnum (size_hints.width_inc));
+      CALLN (Ffuncall, Qfoo_it, intern ("   "),
+	     intern ("char height"), make_fixnum (FRAME_LINE_HEIGHT (f)),
+	     intern ("menubar"), make_fixnum (FRAME_MENUBAR_HEIGHT (f)),
+	     intern ("toolbar"), make_fixnum (FRAME_TOOLBAR_HEIGHT (f)),
+	     intern ("hscroll"), make_fixnum (FRAME_SCROLL_BAR_AREA_HEIGHT (f)),
+	     intern ("borders"), make_fixnum (2 * FRAME_INTERNAL_BORDER_WIDTH (f)),
+	     intern ("base height"), make_fixnum (size_hints.base_height),
+	     intern ("height inc"), make_fixnum (size_hints.height_inc));
+
       block_input ();
       gtk_window_set_geometry_hints (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
                                      NULL, &size_hints, hint_flags);
diff --git a/src/window.c b/src/window.c
index f116b9a9d7..c090f29461 100644
--- a/src/window.c
+++ b/src/window.c
@@ -8394,6 +8394,7 @@ syms_of_window (void)
   DEFSYM (Qheader_line_format, "header-line-format");
   DEFSYM (Qtab_line_format, "tab-line-format");
   DEFSYM (Qno_other_window, "no-other-window");
+  DEFSYM (Qfoo_it, "foo-it");
 
   DEFVAR_LISP ("temp-buffer-show-function", Vtemp_buffer_show_function,
 	       doc: /* Non-nil means call as function to display a help buffer.
diff --git a/src/xterm.c b/src/xterm.c
index 7eaf59d54b..b2e689fe84 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -26160,6 +26160,8 @@ x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
 {
   struct font *font = XFONT_OBJECT (font_object);
   int unit, font_ascent, font_descent;
+  int old_width = FRAME_COLUMN_WIDTH (f);
+  int old_height = FRAME_LINE_HEIGHT (f);
 
   if (fontset < 0)
     fontset = fontset_from_font (font_object);
@@ -26197,9 +26199,27 @@ x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
      because it's done in Fx_show_tip, and it leads to problems because
      the tip frame has no widget.  */
   if (FRAME_X_WINDOW (f) != 0 && !FRAME_TOOLTIP_P (f))
-    adjust_frame_size
-      (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
-       FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 3, false, Qfont);
+    {
+      CALLN (Ffuncall, Qfoo_it, intern ("\nx_new_font"),
+	     intern ("old char size"),
+	     Fcons (make_fixnum (old_width), make_fixnum (old_height)),
+	     intern ("new char size"),
+	     Fcons (make_fixnum (FRAME_COLUMN_WIDTH (f)),
+		    make_fixnum (FRAME_LINE_HEIGHT (f))),
+	     intern ("text chars"),
+	     Fcons (make_fixnum (FRAME_COLS (f)),
+		    make_fixnum (FRAME_LINES (f))),
+	     intern ("old text pixels"),
+	     Fcons (make_fixnum (FRAME_TEXT_WIDTH (f)),
+		    make_fixnum (FRAME_TEXT_HEIGHT (f))),
+	     intern ("new text pixels"),
+	     Fcons (make_fixnum (FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f)),
+		    make_fixnum (FRAME_LINES (f) * FRAME_LINE_HEIGHT (f))));
+
+      adjust_frame_size
+	(f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
+	 FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 3, false, Qfont);
+    }
 
 #ifdef HAVE_X_I18N
   if (FRAME_XIC (f)