]> git.eshelyaron.com Git - emacs.git/commitdiff
Avoid triple buffering with Xdbe in cairo
authorYAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp>
Sat, 18 May 2019 23:35:40 +0000 (08:35 +0900)
committerYAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp>
Sat, 18 May 2019 23:35:40 +0000 (08:35 +0900)
* src/xterm.h (struct x_output): Remove member cr_surface.
Add members cr_surface_desired_width and cr_surface_desired_height.
(x_cr_destroy_frame_context) [USE_CAIRO]: Add extern.

* src/xterm.c (x_free_cr_resources): Remove function.
(FRAME_CR_SURFACE) [USE_CAIRO]: Remove macro.
(FRAME_CR_SURFACE_DESIRED_WIDTH, FRAME_CR_SURFACE_DESIRED_HEIGHT) [USE_CAIRO]:
New macros.
(x_cr_destroy_frame_context) [USE_CAIRO]: Rename from x_cr_destroy_surface.
All Uses changed.  Don't use FRAME_CR_SURFACE.  Make non-static.
(x_cr_update_surface_desired_size) [USE_CAIRO]: New function.
(x_begin_cr_clip) [USE_CAIRO]: Create Xlib surface if Xdbe is in use.
Use FRAME_CR_SURFACE_DESIRED_WIDTH and FRAME_CR_SURFACE_DESIRED_HEIGHT.
(x_end_cr_clip) [USE_CAIRO]: Call x_mark_frame_dirty if Xdbe is in use.
(x_cr_draw_frame, x_cr_export_frames) [USE_CAIRO]: Save and restore cairo
context instead of freeing and clearing it.
(x_update_begin) [USE_CAIRO]: Don't create cairo surface here.
(show_back_buffer) [USE_CAIRO]: Call cairo_surface_flush before swapping.
(x_update_end) [USE_CAIRO]: Don't copy image surface if Xdbe is in use.
Get image surface by cairo_get_target instead of FRAME_CR_SURFACE.
(x_scroll_run) [USE_CAIRO]: Use XCopyArea if Xdbe is in use.
(handle_one_xevent) [USE_CAIRO] <ConfigureNotify>: Call
x_cr_update_surface_desired_size instead of x_cr_destroy_surface.
(x_free_frame_resources) [USE_CAIRO]: Call x_cr_destroy_frame_context instead
of x_free_cr_resources.

* src/xfns.c (set_up_x_back_buffer, tear_down_x_back_buffer) [USE_CAIRO]:
Call x_cr_destroy_frame_context.

src/xfns.c
src/xterm.c
src/xterm.h

index 2ceb55a30adb6129e168b4da46de066a271d8083..c8cc1704a473a73ec3d303cb73ab35b90071bfb4 100644 (file)
@@ -2784,6 +2784,9 @@ set_up_x_back_buffer (struct frame *f)
   block_input ();
   if (FRAME_X_WINDOW (f) && !FRAME_X_DOUBLE_BUFFERED_P (f))
     {
+#ifdef USE_CAIRO
+      x_cr_destroy_frame_context (f);
+#endif
       FRAME_X_RAW_DRAWABLE (f) = FRAME_X_WINDOW (f);
       if (FRAME_DISPLAY_INFO (f)->supports_xdbe)
         {
@@ -2813,6 +2816,9 @@ tear_down_x_back_buffer (struct frame *f)
     {
       if (FRAME_X_DOUBLE_BUFFERED_P (f))
         {
+#ifdef USE_CAIRO
+         x_cr_destroy_frame_context (f);
+#endif
           XdbeDeallocateBackBufferName (FRAME_X_DISPLAY (f),
                                         FRAME_X_DRAWABLE (f));
           FRAME_X_RAW_DRAWABLE (f) = FRAME_X_WINDOW (f);
index 9371d47c95e4ad4931296e0f72a7c6a85c2d2efa..4f4a1d6d02a7559b57504278d754fdebebb0eef8 100644 (file)
@@ -201,7 +201,6 @@ enum xembed_message
     XEMBED_ACTIVATE_ACCELERATOR   = 14
   };
 
-static void x_free_cr_resources (struct frame *);
 static bool x_alloc_nearest_color_1 (Display *, Colormap, XColor *);
 static void x_raise_frame (struct frame *);
 static void x_lower_frame (struct frame *);
@@ -298,7 +297,10 @@ record_event (char *locus, int type)
 #ifdef USE_CAIRO
 
 #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,19 +335,28 @@ x_extension_initialize (struct x_display_info *dpyinfo)
   dpyinfo->ext_codes = ext_codes;
 }
 
-static void
-x_cr_destroy_surface (struct frame *f)
+void
+x_cr_destroy_frame_context (struct frame *f)
 {
-  if (FRAME_CR_SURFACE (f))
+  if (FRAME_CR_CONTEXT (f))
     {
-      cairo_t *cr = FRAME_CR_CONTEXT (f);
-      cairo_surface_destroy (FRAME_CR_SURFACE (f));
-      FRAME_CR_SURFACE (f) = 0;
-      if (cr) cairo_destroy (cr);
+      cairo_destroy (FRAME_CR_CONTEXT (f));
       FRAME_CR_CONTEXT (f) = NULL;
     }
 }
 
+static void
+x_cr_update_surface_desired_size (struct frame *f, int width, int height)
+{
+  if (FRAME_CR_SURFACE_DESIRED_WIDTH (f) != width
+      || FRAME_CR_SURFACE_DESIRED_HEIGHT (f) != height)
+    {
+      x_cr_destroy_frame_context (f);
+      FRAME_CR_SURFACE_DESIRED_WIDTH (f) = width;
+      FRAME_CR_SURFACE_DESIRED_HEIGHT (f) = height;
+    }
+}
+
 cairo_t *
 x_begin_cr_clip (struct frame *f, GC gc)
 {
@@ -353,21 +364,19 @@ x_begin_cr_clip (struct frame *f, GC gc)
 
   if (!cr)
     {
-
-      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,
-                                       scale * FRAME_PIXEL_WIDTH (f),
-                                       scale * FRAME_PIXEL_HEIGHT (f));
-       }
-      cr = cairo_create (FRAME_CR_SURFACE (f));
-      FRAME_CR_CONTEXT (f) = cr;
+      int width = FRAME_CR_SURFACE_DESIRED_WIDTH (f);
+      int height = FRAME_CR_SURFACE_DESIRED_HEIGHT (f);
+      cairo_surface_t *surface;
+      if (FRAME_X_DOUBLE_BUFFERED_P (f))
+       surface = cairo_xlib_surface_create (FRAME_X_DISPLAY (f),
+                                            FRAME_X_RAW_DRAWABLE (f),
+                                            FRAME_X_VISUAL (f),
+                                            width, height);
+      else
+       surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+                                             width, height);
+      cr = FRAME_CR_CONTEXT (f) = cairo_create (surface);
+      cairo_surface_destroy (surface);
     }
   cairo_save (cr);
 
@@ -395,6 +404,8 @@ void
 x_end_cr_clip (struct frame *f)
 {
   cairo_restore (FRAME_CR_CONTEXT (f));
+  if (FRAME_X_DOUBLE_BUFFERED_P (f))
+    x_mark_frame_dirty (f);
 }
 
 void
@@ -532,11 +543,11 @@ x_cr_draw_frame (cairo_t *cr, struct frame *f)
   width = FRAME_PIXEL_WIDTH (f);
   height = FRAME_PIXEL_HEIGHT (f);
 
-  x_free_cr_resources (f);
+  cairo_t *saved_cr = FRAME_CR_CONTEXT (f);
   FRAME_CR_CONTEXT (f) = cr;
   x_clear_area (f, 0, 0, width, height);
   expose_frame (f, 0, 0, width, height);
-  FRAME_CR_CONTEXT (f) = NULL;
+  FRAME_CR_CONTEXT (f) = saved_cr;
 }
 
 static cairo_status_t
@@ -615,11 +626,11 @@ x_cr_export_frames (Lisp_Object frames, cairo_surface_type_t surface_type)
 
   while (1)
     {
-      x_free_cr_resources (f);
+      cairo_t *saved_cr = FRAME_CR_CONTEXT (f);
       FRAME_CR_CONTEXT (f) = cr;
       x_clear_area (f, 0, 0, width, height);
       expose_frame (f, 0, 0, width, height);
-      FRAME_CR_CONTEXT (f) = NULL;
+      FRAME_CR_CONTEXT (f) = saved_cr;
 
       if (NILP (frames))
        break;
@@ -653,35 +664,6 @@ x_cr_export_frames (Lisp_Object frames, cairo_surface_type_t surface_type)
 
 #endif /* USE_CAIRO */
 
-static void
-x_free_cr_resources (struct frame *f)
-{
-#ifdef USE_CAIRO
-  if (f == NULL)
-    {
-      Lisp_Object rest, frame;
-      FOR_EACH_FRAME (rest, frame)
-       if (FRAME_X_P (XFRAME (frame)))
-         x_free_cr_resources (XFRAME (frame));
-    }
-  else
-    {
-      cairo_t *cr = FRAME_CR_CONTEXT (f);
-
-      if (cr)
-       {
-         cairo_surface_t *surface = cairo_get_target (cr);
-
-         if (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_XLIB)
-           {
-             cairo_destroy (cr);
-             FRAME_CR_CONTEXT (f) = NULL;
-           }
-       }
-    }
-#endif
-}
-
 static void
 x_set_clip_rectangles (struct frame *f, GC gc, XRectangle *rectangles, int n)
 {
@@ -996,41 +978,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.  */
 }
 
 /* Draw a vertical window border from (x,y0) to (x,y1)  */
@@ -1122,6 +1070,11 @@ show_back_buffer (struct frame *f)
   if (FRAME_X_DOUBLE_BUFFERED_P (f))
     {
 #ifdef HAVE_XDBE
+#ifdef USE_CAIRO
+      cairo_t *cr = FRAME_CR_CONTEXT (f);
+      if (cr)
+       cairo_surface_flush (cairo_get_target (cr));
+#endif
       XdbeSwapInfo swap_info;
       memset (&swap_info, 0, sizeof (swap_info));
       swap_info.swap_window = FRAME_X_WINDOW (f);
@@ -1158,30 +1111,33 @@ x_update_end (struct frame *f)
   MOUSE_HL_INFO (f)->mouse_face_defer = false;
 
 #ifdef USE_CAIRO
-  if (FRAME_CR_SURFACE (f))
+  if (!FRAME_X_DOUBLE_BUFFERED_P (f))
     {
-      cairo_t *cr;
-      cairo_surface_t *surface;
-      int width, height;
-
       block_input ();
-      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);
-      surface = cairo_xlib_surface_create (FRAME_X_DISPLAY (f),
-                                          FRAME_X_DRAWABLE (f),
-                                          FRAME_DISPLAY_INFO (f)->visual,
-                                          width,
-                                          height);
-      cr = cairo_create (surface);
-      cairo_surface_destroy (surface);
-
-      cairo_set_source_surface (cr, FRAME_CR_SURFACE (f), 0, 0);
-      cairo_paint (cr);
-      cairo_destroy (cr);
+      cairo_surface_t *source_surface = cairo_get_target (FRAME_CR_CONTEXT (f));
+      if (source_surface)
+       {
+         cairo_t *cr;
+         cairo_surface_t *surface;
+         int width, height;
+
+         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);
+         surface = cairo_xlib_surface_create (FRAME_X_DISPLAY (f),
+                                              FRAME_X_DRAWABLE (f),
+                                              FRAME_X_VISUAL (f),
+                                              width, height);
+         cr = cairo_create (surface);
+         cairo_surface_destroy (surface);
+
+         cairo_set_source_surface (cr, source_surface, 0, 0);
+         cairo_paint (cr);
+         cairo_destroy (cr);
+       }
       unblock_input ();
     }
 #endif
@@ -4253,7 +4209,21 @@ x_scroll_run (struct window *w, struct run *run)
   gui_clear_cursor (w);
 
 #ifdef USE_CAIRO
-  if (FRAME_CR_CONTEXT (f))
+  if (FRAME_X_DOUBLE_BUFFERED_P (f))
+    {
+      cairo_t *cr = FRAME_CR_CONTEXT (f);
+      if (cr)
+       cairo_surface_flush (cairo_get_target (cr));
+      XCopyArea (FRAME_X_DISPLAY (f),
+                FRAME_X_DRAWABLE (f), FRAME_X_DRAWABLE (f),
+                f->output_data.x->normal_gc,
+                x, from_y,
+                width, height,
+                x, to_y);
+      if (cr)
+       cairo_surface_mark_dirty (cairo_get_target (cr));
+    }
+  else if (FRAME_CR_CONTEXT (f))
     {
       cairo_surface_t *s = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
                                                       width, height);
@@ -8711,7 +8681,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_update_surface_desired_size (f, configureEvent.xconfigure.width,
+                                         configureEvent.xconfigure.height);
 #endif
 #ifdef USE_GTK
       if (!f
@@ -8725,7 +8697,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_update_surface_desired_size (f, configureEvent.xconfigure.width,
+                                           configureEvent.xconfigure.height);
 #endif
           f = 0;
         }
@@ -11835,7 +11808,9 @@ x_free_frame_resources (struct frame *f)
        free_frame_xic (f);
 #endif
 
-      x_free_cr_resources (f);
+#ifdef USE_CAIRO
+      x_cr_destroy_frame_context (f);
+#endif
 #ifdef USE_X_TOOLKIT
       if (f->output_data.x->widget)
        {
index 266a42afa08030ab5b26cb0f9287958191a20b64..84030d5c25e49e15333484b9e4a50588cbf4a3a1 100644 (file)
@@ -725,8 +725,9 @@ struct x_output
 #ifdef USE_CAIRO
   /* Cairo drawing context.  */
   cairo_t *cr_context;
-  /* Cairo surface for double buffering */
-  cairo_surface_t *cr_surface;
+  /* Width and height reported by the last ConfigureNotify event.
+     They are used when creating the cairo surface next time.  */
+  int cr_surface_desired_width, cr_surface_desired_height;
 #endif
 };
 
@@ -1107,6 +1108,7 @@ extern int x_dispatch_event (XEvent *, Display *);
 #endif
 extern int x_x_to_emacs_modifiers (struct x_display_info *, int);
 #ifdef USE_CAIRO
+extern void x_cr_destroy_frame_context (struct frame *);
 extern cairo_t *x_begin_cr_clip (struct frame *, GC);
 extern void x_end_cr_clip (struct frame *);
 extern void x_set_cr_source_with_gc_foreground (struct frame *, GC);