summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPo Lu <luangruo@yahoo.com>2022-01-24 12:44:55 +0800
committerPo Lu <luangruo@yahoo.com>2022-01-24 12:44:55 +0800
commit45208755d13f23f92edcab4d6959e0fd9423843b (patch)
tree95bdca80a788eeedd491e2ae54941ba2af3a7644
parent3a7b158ffd8d468eb92de1de6418b3831f10142b (diff)
downloademacs-45208755d13f23f92edcab4d6959e0fd9423843b.tar.gz
Add some code for transparent frame backgrounds without Cairo
* src/image.c (svg_load_image): Fix build without native image transforms. * src/xfns.c (set_up_x_back_buffer): (tear_down_x_back_buffer): Free XR picture if present. * src/xftfont.c (xftfont_get_xft_draw): Fix formatting issue. * src/xterm.c (x_xr_ensure_picture): New function. (FRAME_CR_CONTEXT, FRAME_CR_CONTEXT): (FRAME_CR_SURFACE_DESIRED_WIDTH) (FRAME_CR_SURFACE_DESIRED_HEIGHT): Move to separate USE_CAIRO block so the ext data code can be used on builds with XRender as well. (x_xr_apply_ext_clip): (x_xr_reset_ext_clip): New functions. (x_set_clip_rectangles): (x_reset_clip_rectangles): Set ext data on XRender as well. (x_term_init): Look for a picture format appropriate for our purposes. (x_clear_area): Use XRenderFillRectangle to draw backgrounds if available. (x_xrender_color_from_gc_foreground): (x_xrender_color_from_gc_background): New functions. * src/xterm.h (FRAME_X_PICTURE): (FRAME_X_PICTURE_FORMAT) (FRAME_CHECK_XR_VERSION): New macros. (struct x_gc_ext_data): Define on XRender as well. (struct x_display_info): Define ext_codes when using XRender and add new field `pict_format'. (struct x_output): New field `picture'.
-rw-r--r--src/image.c5
-rw-r--r--src/xfns.c30
-rw-r--r--src/xftfont.c8
-rw-r--r--src/xterm.c132
-rw-r--r--src/xterm.h38
5 files changed, 188 insertions, 25 deletions
diff --git a/src/image.c b/src/image.c
index 7ee595297fa..951531505e6 100644
--- a/src/image.c
+++ b/src/image.c
@@ -10672,11 +10672,16 @@ svg_load_image (struct frame *f, struct image *img, char *contents,
viewbox_height = dimension_data.height;
#endif
+#ifdef HAVE_NATIVE_TRANSFORMS
compute_image_size (viewbox_width, viewbox_height, img,
&width, &height);
width = scale_image_size (width, 1, FRAME_SCALE_FACTOR (f));
height = scale_image_size (height, 1, FRAME_SCALE_FACTOR (f));
+#else
+ width = viewbox_width;
+ height = viewbox_height;
+#endif
if (! check_image_size (f, width, height))
{
diff --git a/src/xfns.c b/src/xfns.c
index 7123198724a..92aed2d46a7 100644
--- a/src/xfns.c
+++ b/src/xfns.c
@@ -3267,6 +3267,17 @@ x_mark_frame_dirty (struct frame *f)
static void
set_up_x_back_buffer (struct frame *f)
{
+#ifdef HAVE_XRENDER
+ block_input ();
+ if (FRAME_X_PICTURE (f) != None)
+ {
+ XRenderFreePicture (FRAME_X_DISPLAY (f),
+ FRAME_X_PICTURE (f));
+ FRAME_X_PICTURE (f) = None;
+ }
+ unblock_input ();
+#endif
+
#ifdef HAVE_XDBE
block_input ();
if (FRAME_X_WINDOW (f) && !FRAME_X_DOUBLE_BUFFERED_P (f))
@@ -3281,10 +3292,10 @@ set_up_x_back_buffer (struct frame *f)
server ran out of memory or we don't have the right kind
of visual, just use single-buffered rendering. */
x_catch_errors (FRAME_X_DISPLAY (f));
- FRAME_X_RAW_DRAWABLE (f) = XdbeAllocateBackBufferName (
- FRAME_X_DISPLAY (f),
- FRAME_X_WINDOW (f),
- XdbeCopied);
+ FRAME_X_RAW_DRAWABLE (f)
+ = XdbeAllocateBackBufferName (FRAME_X_DISPLAY (f),
+ FRAME_X_WINDOW (f),
+ XdbeCopied);
if (x_had_errors_p (FRAME_X_DISPLAY (f)))
FRAME_X_RAW_DRAWABLE (f) = FRAME_X_WINDOW (f);
x_uncatch_errors_after_check ();
@@ -3297,6 +3308,17 @@ set_up_x_back_buffer (struct frame *f)
void
tear_down_x_back_buffer (struct frame *f)
{
+#ifdef HAVE_XRENDER
+ block_input ();
+ if (FRAME_X_PICTURE (f) != None)
+ {
+ XRenderFreePicture (FRAME_X_DISPLAY (f),
+ FRAME_X_PICTURE (f));
+ FRAME_X_PICTURE (f) = None;
+ }
+ unblock_input ();
+#endif
+
#ifdef HAVE_XDBE
block_input ();
if (FRAME_X_WINDOW (f) && FRAME_X_DOUBLE_BUFFERED_P (f))
diff --git a/src/xftfont.c b/src/xftfont.c
index f305738410e..c2175d96141 100644
--- a/src/xftfont.c
+++ b/src/xftfont.c
@@ -441,10 +441,10 @@ xftfont_get_xft_draw (struct frame *f)
if (! xft_draw)
{
block_input ();
- xft_draw= XftDrawCreate (FRAME_X_DISPLAY (f),
- FRAME_X_DRAWABLE (f),
- FRAME_X_VISUAL (f),
- FRAME_X_COLORMAP (f));
+ xft_draw = XftDrawCreate (FRAME_X_DISPLAY (f),
+ FRAME_X_DRAWABLE (f),
+ FRAME_X_VISUAL (f),
+ FRAME_X_COLORMAP (f));
unblock_input ();
eassert (xft_draw != NULL);
font_put_frame_data (f, Qxft, xft_draw);
diff --git a/src/xterm.c b/src/xterm.c
index cc0e1a4485d..436238c4a17 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -358,6 +358,22 @@ x_flush (struct frame *f)
unblock_input ();
}
+#ifdef HAVE_XRENDER
+MAYBE_UNUSED static void
+x_xr_ensure_picture (struct frame *f)
+{
+ if (FRAME_X_PICTURE (f) == None && FRAME_X_PICTURE_FORMAT (f))
+ {
+ XRenderPictureAttributes attrs;
+ attrs.clip_mask = None;
+
+ FRAME_X_PICTURE (f) = XRenderCreatePicture (FRAME_X_DISPLAY (f),
+ FRAME_X_RAW_DRAWABLE (f),
+ FRAME_X_PICTURE_FORMAT (f),
+ CPClipMask, &attrs);
+ }
+}
+#endif
/* Remove calls to XFlush by defining XFlush to an empty replacement.
Calls to XFlush should be unnecessary because the X output buffer
@@ -401,14 +417,7 @@ record_event (char *locus, int type)
#endif
-#ifdef USE_CAIRO
-
-#define FRAME_CR_CONTEXT(f) ((f)->output_data.x->cr_context)
-#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)
-
+#if defined USE_CAIRO || defined HAVE_XRENDER
static struct x_gc_ext_data *
x_gc_get_ext_data (struct frame *f, GC gc, int create_if_not_found_p)
{
@@ -441,6 +450,15 @@ x_extension_initialize (struct x_display_info *dpyinfo)
dpyinfo->ext_codes = ext_codes;
}
+#endif
+
+#ifdef USE_CAIRO
+
+#define FRAME_CR_CONTEXT(f) ((f)->output_data.x->cr_context)
+#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)
#endif /* HAVE_CAIRO */
@@ -1184,11 +1202,37 @@ x_cr_export_frames (Lisp_Object frames, cairo_surface_type_t surface_type)
#endif /* USE_CAIRO */
+#if defined HAVE_XRENDER && !defined USE_CAIRO
+MAYBE_UNUSED static void
+x_xr_apply_ext_clip (struct frame *f, GC gc)
+{
+ eassert (FRAME_X_PICTURE (f) != None);
+
+ struct x_gc_ext_data *data = x_gc_get_ext_data (f, gc, 1);
+
+ if (data->n_clip_rects)
+ XRenderSetPictureClipRectangles (FRAME_X_DISPLAY (f),
+ FRAME_X_PICTURE (f),
+ 0, 0, data->clip_rects,
+ data->n_clip_rects);
+}
+
+MAYBE_UNUSED static void
+x_xr_reset_ext_clip (struct frame *f)
+{
+ XRenderPictureAttributes attrs = { .clip_mask = None };
+
+ XRenderChangePicture (FRAME_X_DISPLAY (f),
+ FRAME_X_PICTURE (f),
+ CPClipMask, &attrs);
+}
+#endif
+
static void
x_set_clip_rectangles (struct frame *f, GC gc, XRectangle *rectangles, int n)
{
XSetClipRectangles (FRAME_X_DISPLAY (f), gc, 0, 0, rectangles, n, Unsorted);
-#ifdef USE_CAIRO
+#if defined USE_CAIRO || defined HAVE_XRENDER
eassert (n >= 0 && n <= MAX_CLIP_RECTS);
{
@@ -1204,7 +1248,7 @@ static void
x_reset_clip_rectangles (struct frame *f, GC gc)
{
XSetClipMask (FRAME_X_DISPLAY (f), gc, None);
-#ifdef USE_CAIRO
+#if defined USE_CAIRO || defined HAVE_XRENDER
{
struct x_gc_ext_data *gc_ext = x_gc_get_ext_data (f, gc, 0);
@@ -4510,10 +4554,31 @@ x_clear_area (struct frame *f, int x, int y, int width, int height)
#ifndef USE_GTK
if (FRAME_X_DOUBLE_BUFFERED_P (f))
#endif
- XFillRectangle (FRAME_X_DISPLAY (f),
- FRAME_X_DRAWABLE (f),
- f->output_data.x->reverse_gc,
- x, y, width, height);
+ {
+#if defined HAVE_XRENDER && \
+ (RENDER_MAJOR > 0 || (RENDER_MINOR >= 2))
+ x_xr_ensure_picture (f);
+ if (FRAME_X_PICTURE (f) != None
+ && FRAME_CHECK_XR_VERSION (f, 0, 2))
+ {
+ XRenderColor xc;
+ GC gc = f->output_data.x->reverse_gc;
+
+ x_xr_apply_ext_clip (f, gc);
+ x_xrender_color_from_gc_foreground (f, gc, &xc);
+ XRenderFillRectangle (FRAME_X_DISPLAY (f),
+ PictOpSrc, FRAME_X_PICTURE (f),
+ &xc, x, y, width, height);
+ x_xr_reset_ext_clip (f);
+ x_mark_frame_dirty (f);
+ }
+ else
+#endif
+ XFillRectangle (FRAME_X_DISPLAY (f),
+ FRAME_X_DRAWABLE (f),
+ f->output_data.x->reverse_gc,
+ x, y, width, height);
+ }
#ifndef USE_GTK
else
x_clear_area1 (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
@@ -15431,6 +15496,9 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name)
if (!XRenderQueryVersion (dpyinfo->display, &dpyinfo->xrender_major,
&dpyinfo->xrender_minor))
dpyinfo->xrender_supported_p = false;
+ else
+ dpyinfo->pict_format = XRenderFindVisualFormat (dpyinfo->display,
+ dpyinfo->visual);
}
#endif
@@ -15714,7 +15782,7 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name)
x_session_initialize (dpyinfo);
#endif
-#ifdef USE_CAIRO
+#if defined USE_CAIRO || defined HAVE_XRENDER
x_extension_initialize (dpyinfo);
#endif
@@ -16090,6 +16158,40 @@ init_xterm (void)
}
#endif
+#ifdef HAVE_XRENDER
+void
+x_xrender_color_from_gc_foreground (struct frame *f, GC gc, XRenderColor *color)
+{
+ XGCValues xgcv;
+ XColor xc;
+
+ XGetGCValues (FRAME_X_DISPLAY (f), gc, GCForeground, &xgcv);
+ xc.pixel = xgcv.foreground;
+ x_query_colors (f, &xc, 1);
+
+ color->alpha = 65535;
+ color->red = xc.red;
+ color->blue = xc.blue;
+ color->green = xc.green;
+}
+
+void
+x_xrender_color_from_gc_background (struct frame *f, GC gc, XRenderColor *color)
+{
+ XGCValues xgcv;
+ XColor xc;
+
+ XGetGCValues (FRAME_X_DISPLAY (f), gc, GCBackground, &xgcv);
+ xc.pixel = xgcv.foreground;
+ x_query_colors (f, &xc, 1);
+
+ color->alpha = 65535;
+ color->red = xc.red;
+ color->blue = xc.blue;
+ color->green = xc.green;
+}
+#endif
+
void
syms_of_xterm (void)
{
diff --git a/src/xterm.h b/src/xterm.h
index a4ad57eddaa..33887be52b0 100644
--- a/src/xterm.h
+++ b/src/xterm.h
@@ -54,6 +54,10 @@ typedef Widget xt_or_gtk_widget;
#define GTK_CHECK_VERSION(i, j, k) false
#endif
+#ifdef HAVE_XRENDER
+#include <X11/extensions/Xrender.h>
+#endif
+
#ifdef USE_GTK
/* Some definitions to reduce conditionals. */
typedef GtkWidget *xt_or_gtk_widget;
@@ -148,7 +152,7 @@ struct x_bitmap_record
int height, width, depth;
};
-#ifdef USE_CAIRO
+#if defined USE_CAIRO || defined HAVE_XRENDER
struct x_gc_ext_data
{
#define MAX_CLIP_RECTS 2
@@ -158,7 +162,9 @@ struct x_gc_ext_data
/* Clipping rectangles. */
XRectangle clip_rects[MAX_CLIP_RECTS];
};
+#endif
+#ifdef USE_CAIRO
extern cairo_pattern_t *x_bitmap_stipple (struct frame *, Pixmap);
#endif
@@ -239,6 +245,11 @@ struct x_display_info
/* The Visual being used for this display. */
Visual *visual;
+#ifdef HAVE_XRENDER
+ /* The picture format for this display. */
+ XRenderPictFormat *pict_format;
+#endif
+
/* The colormap being used. */
Colormap cmap;
@@ -509,7 +520,7 @@ struct x_display_info
int xrandr_minor_version;
#endif
-#ifdef USE_CAIRO
+#if defined USE_CAIRO || defined HAVE_XRENDER
XExtCodes *ext_codes;
#endif
@@ -616,6 +627,13 @@ struct x_output
window's back buffer. */
Drawable draw_desc;
+#ifdef HAVE_XRENDER
+ /* The Xrender picture that corresponds to this drawable. None
+ means no picture format was found, or the Xrender extension is
+ not present. */
+ Picture picture;
+#endif
+
/* Flag that indicates whether we've modified the back buffer and
need to publish our modifications to the front buffer at a
convenient time. */
@@ -933,6 +951,17 @@ extern void x_mark_frame_dirty (struct frame *f);
/* This is the Visual which frame F is on. */
#define FRAME_X_VISUAL(f) FRAME_DISPLAY_INFO (f)->visual
+#ifdef HAVE_XRENDER
+#define FRAME_X_PICTURE_FORMAT(f) FRAME_DISPLAY_INFO (f)->pict_format
+#define FRAME_X_PICTURE(f) ((f)->output_data.x->picture)
+#define FRAME_CHECK_XR_VERSION(f, major, minor) \
+ (FRAME_DISPLAY_INFO (f)->xrender_supported_p \
+ && ((FRAME_DISPLAY_INFO (f)->xrender_major == (major) \
+ && FRAME_DISPLAY_INFO (f)->xrender_minor >= (minor)) \
+ || (FRAME_DISPLAY_INFO (f)->xrender_major > (major))))
+#endif
+
+
/* This is the Colormap which frame F uses. */
#define FRAME_X_COLORMAP(f) FRAME_DISPLAY_INFO (f)->cmap
@@ -1212,6 +1241,11 @@ extern void x_cr_draw_frame (cairo_t *, struct frame *);
extern Lisp_Object x_cr_export_frames (Lisp_Object, cairo_surface_type_t);
#endif
+#ifdef HAVE_XRENDER
+extern void x_xrender_color_from_gc_foreground (struct frame *, GC, XRenderColor *);
+extern void x_xrender_color_from_gc_background (struct frame *, GC, XRenderColor *);
+#endif
+
INLINE int
x_display_pixel_height (struct x_display_info *dpyinfo)
{