Subject: Re: bug#23925: 25.0.95; display broken when maximizing frame

From: YAMAMOTO Mitsuharu <[email-masked]>
Date: Tue, 26 Mar 2019 11:12:25 +0900

On Tue, 18 Dec 2018 04:28:17 +0900,
Clément Pit-Claudel wrote:
> 
> >> I have just tried a --with-cairo build of the latest master, and can't repro any of the symptoms described here, as long as Emacs is launched with GDK_SCALE=1 (I have a HiDPI screen, and redisplay with scale=2 looks very broken).
> > 
> > And with the current emacs-26 branch, even that is not a problem.
> > 
> > So to sum up, I'm failing to reproduce any of the problems described in this bug report. Could any of the previous commenters try?
> 
> I just tried it again, on master.  I can't reproduce the problem any more.

With cairo, I can still see the problem that enlarging the frame by
mouse does not update the newly added area on master, with XQuartz on
macOS.  The following patch works for me.

Does the OP still have the similar problem on master?  If so, could
you try the patch below?

				     YAMAMOTO Mitsuharu
				[email-masked]

diff --git a/src/xterm.c b/src/xterm.c
index 1b0c2f5ec5..ec89091d2a 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -299,6 +299,10 @@ record_event (char *locus, int type)
 
 #define FRAME_CR_CONTEXT(f)	((f)->output_data.x->cr_context)
 #define FRAME_CR_SURFACE(f)	((f)->output_data.x->cr_surface)
+#define FRAME_CR_SURFACE_DESIRED_WIDTH(f) \
+  ((f)->output_data.x->cr_surface_desired_width)
+#define FRAME_CR_SURFACE_DESIRED_HEIGHT(f) \
+  ((f)->output_data.x->cr_surface_desired_height)
 
 static struct x_gc_ext_data *
 x_gc_get_ext_data (struct frame *f, GC gc, int create_if_not_found_p)
@@ -333,6 +337,22 @@ x_extension_initialize (struct x_display_info *dpyinfo)
   dpyinfo->ext_codes = ext_codes;
 }
 
+static void
+x_cr_set_surface_desired_size (struct frame *f, int width, int height)
+{
+  cairo_surface_t *surface = FRAME_CR_SURFACE (f);
+
+  if (surface
+      && cairo_image_surface_get_width (surface) == width
+      && cairo_image_surface_get_height (surface) == height)
+    FRAME_CR_SURFACE_DESIRED_WIDTH (f) = 0;
+  else
+    {
+      FRAME_CR_SURFACE_DESIRED_WIDTH (f) = width;
+      FRAME_CR_SURFACE_DESIRED_HEIGHT (f) = height;
+    }
+}
+
 static void
 x_cr_destroy_surface (struct frame *f)
 {
@@ -350,22 +370,24 @@ cairo_t *
 x_begin_cr_clip (struct frame *f, GC gc)
 {
   cairo_t *cr = FRAME_CR_CONTEXT (f);
+  cairo_surface_t *surface = FRAME_CR_SURFACE (f);
 
-  if (!cr)
+  if (! surface || FRAME_CR_SURFACE_DESIRED_WIDTH (f))
     {
+      if (surface)
+	cairo_surface_destroy (surface);
 
-      if (! FRAME_CR_SURFACE (f))
-        {
-	  int scale = 1;
-#ifdef USE_GTK
-	  scale = xg_get_scale (f);
-#endif
+      FRAME_CR_SURFACE (f) =
+	cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+				    FRAME_CR_SURFACE_DESIRED_WIDTH (f),
+				    FRAME_CR_SURFACE_DESIRED_HEIGHT (f));
+      FRAME_CR_SURFACE_DESIRED_WIDTH (f) = 0;
 
-	  FRAME_CR_SURFACE (f) =
-	    cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
-					scale * FRAME_PIXEL_WIDTH (f),
-					scale * FRAME_PIXEL_HEIGHT (f));
-	}
+      if (cr) cairo_destroy (cr);
+      cr = NULL;
+    }
+  if (!cr)
+    {
       cr = cairo_create (FRAME_CR_SURFACE (f));
       FRAME_CR_CONTEXT (f) = cr;
     }
@@ -989,41 +1011,7 @@ x_set_frame_alpha (struct frame *f)
 static void
 x_update_begin (struct frame *f)
 {
-#ifdef USE_CAIRO
-  if (FRAME_TOOLTIP_P (f) && !FRAME_VISIBLE_P (f))
-    return;
-
-  if (! FRAME_CR_SURFACE (f))
-    {
-      int width, height;
-#ifdef USE_GTK
-      if (FRAME_GTK_WIDGET (f))
-        {
-          GdkWindow *w = gtk_widget_get_window (FRAME_GTK_WIDGET (f));
-	  int scale = xg_get_scale (f);
-	  width = scale * gdk_window_get_width (w);
-	  height = scale * gdk_window_get_height (w);
-        }
-      else
-#endif
-        {
-          width = FRAME_PIXEL_WIDTH (f);
-          height = FRAME_PIXEL_HEIGHT (f);
-          if (! FRAME_EXTERNAL_TOOL_BAR (f))
-            height += FRAME_TOOL_BAR_HEIGHT (f);
-          if (! FRAME_EXTERNAL_MENU_BAR (f))
-            height += FRAME_MENU_BAR_HEIGHT (f);
-        }
-
-      if (width > 0 && height > 0)
-        {
-          block_input();
-          FRAME_CR_SURFACE (f) = cairo_image_surface_create
-            (CAIRO_FORMAT_ARGB32, width, height);
-          unblock_input();
-        }
-    }
-#endif /* USE_CAIRO */
+  /* Nothing to do.  */
 }
 
 /* Start update of window W.  */
@@ -8772,7 +8760,9 @@ handle_one_xevent (struct x_display_info *dpyinfo,
         font_drop_xrender_surfaces (f);
       unblock_input ();
 #ifdef USE_CAIRO
-      if (f) x_cr_destroy_surface (f);
+      if (f)
+	x_cr_set_surface_desired_size (f, configureEvent.xconfigure.width,
+				       configureEvent.xconfigure.height);
 #endif
 #ifdef USE_GTK
       if (!f
@@ -8786,7 +8776,8 @@ handle_one_xevent (struct x_display_info *dpyinfo,
           xg_frame_resized (f, configureEvent.xconfigure.width,
                             configureEvent.xconfigure.height);
 #ifdef USE_CAIRO
-          x_cr_destroy_surface (f);
+	  x_cr_set_surface_desired_size (f, configureEvent.xconfigure.width,
+					 configureEvent.xconfigure.height);
 #endif
           f = 0;
         }
@@ -11834,7 +11825,7 @@ x_free_frame_resources (struct frame *f)
 	free_frame_xic (f);
 #endif
 
-      x_free_cr_resources (f);
+      x_cr_destroy_surface (f);
 #ifdef USE_X_TOOLKIT
       if (f->output_data.x->widget)
 	{
diff --git a/src/xterm.h b/src/xterm.h
index 972a10f4d4..3456e12d84 100644
--- a/src/xterm.h
+++ b/src/xterm.h
@@ -744,6 +744,10 @@ struct x_output
   cairo_t *cr_context;
   /* Cairo surface for double buffering */
   cairo_surface_t *cr_surface;
+  /* Size reported by the last ConfigureNotify event.  The value of
+     cr_surface_desired_width is 0 when the size matches with that of
+     cr_surface above.  */
+  int cr_surface_desired_width, cr_surface_desired_height;
 #endif
 };