Add background transparency support for GTK+Cairo

This commit is contained in:
Håkon Flatval 2022-01-29 16:13:06 +01:00 committed by Po Lu
parent 35cd9197fc
commit b944841173
11 changed files with 157 additions and 15 deletions

View file

@ -149,6 +149,15 @@ various X toolkits (GTK+, Lucid, etc.)---we indicate below when this
is the case.
@table @asis
@item @code{alpha} (class @code{Alpha})
Sets the @samp{alpha} frame parameter, determining frame transparency
(@pxref{Frame Parameters,,, elisp, The Emacs Lisp Reference Manual}).
@item @code{alphaBackground} (class @code{AlphaBackground})
Sets the @samp{alpha-background} frame parameter, determining background
transparency
(@pxref{Frame Parameters,,, elisp, The Emacs Lisp Reference Manual}).
@item @code{background} (class @code{Background})
Background color (@pxref{Colors}).

View file

@ -2433,6 +2433,16 @@ opacity when it is not selected.
Some window systems do not support the @code{alpha} parameter for child
frames (@pxref{Child Frames}).
@vindex alpha-background@r{, a frame parameter}
@item alpha-background
@cindex opacity, frame
@cindex transparency, frame
Sets the background transparency of the frame. Unlike the @code{alpha}
frame parameter, this only controls the transparency of the background
while keeping foreground elements such as text fully opaque. It
should be an integer between 0 and 100, where 0 means
completely transparent and 100 means completely opaque (default).
@end table
The following frame parameters are semi-obsolete in that they are

View file

@ -3907,6 +3907,7 @@ static const struct frame_parm_table frame_parms[] =
{"z-group", SYMBOL_INDEX (Qz_group)},
{"override-redirect", SYMBOL_INDEX (Qoverride_redirect)},
{"no-special-glyphs", SYMBOL_INDEX (Qno_special_glyphs)},
{"alpha-background", SYMBOL_INDEX (Qalpha_background)},
#ifdef NS_IMPL_COCOA
{"ns-appearance", SYMBOL_INDEX (Qns_appearance)},
{"ns-transparent-titlebar", SYMBOL_INDEX (Qns_transparent_titlebar)},
@ -5024,6 +5025,33 @@ gui_set_alpha (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
}
}
void
gui_set_alpha_background (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
{
double alpha = 1.0;
if (NILP (arg))
alpha = 1.0;
else if (FLOATP (arg))
{
alpha = XFLOAT_DATA (arg);
if (! (0 <= alpha && alpha <= 1.0))
args_out_of_range (make_float (0.0), make_float (1.0));
}
else if (FIXNUMP (arg))
{
EMACS_INT ialpha = XFIXNUM (arg);
if (! (0 <= ialpha && ialpha <= 100))
args_out_of_range (make_fixnum (0), make_fixnum (100));
alpha = ialpha / 100.0;
}
else
wrong_type_argument (Qnumberp, arg);
f->alpha_background = alpha;
SET_FRAME_GARBAGED (f);
}
/**
* gui_set_no_special_glyphs:
@ -6100,6 +6128,7 @@ syms_of_frame (void)
#endif
DEFSYM (Qalpha, "alpha");
DEFSYM (Qalpha_background, "alpha-background");
DEFSYM (Qauto_lower, "auto-lower");
DEFSYM (Qauto_raise, "auto-raise");
DEFSYM (Qborder_color, "border-color");

View file

@ -637,6 +637,9 @@ struct frame
Negative values mean not to change alpha. */
double alpha[2];
/* Background opacity */
double alpha_background;
/* Exponent for gamma correction of colors. 1/(VIEWING_GAMMA *
SCREEN_GAMMA) where viewing_gamma is 0.4545 and SCREEN_GAMMA is a
frame parameter. 0 means don't do gamma correction. */
@ -1669,6 +1672,7 @@ extern void gui_set_scroll_bar_height (struct frame *, Lisp_Object, Lisp_Object)
extern long gui_figure_window_size (struct frame *, Lisp_Object, bool, bool);
extern void gui_set_alpha (struct frame *, Lisp_Object, Lisp_Object);
extern void gui_set_alpha_background (struct frame *, Lisp_Object, Lisp_Object);
extern void gui_set_no_special_glyphs (struct frame *, Lisp_Object, Lisp_Object);
extern void validate_x_resource_name (void);

View file

@ -1467,6 +1467,10 @@ xg_create_frame_widgets (struct frame *f)
}
wtop = gtk_window_new (type);
gtk_widget_add_events (wtop, GDK_ALL_EVENTS_MASK);
/* This prevents GTK from painting the window's background, which
would interfere with transparent background in some environments */
gtk_widget_set_app_paintable (wtop, TRUE);
#endif
/* gtk_window_set_has_resize_grip is a Gtk+ 3.0 function but Ubuntu
@ -1587,6 +1591,15 @@ xg_create_frame_widgets (struct frame *f)
#endif
| GDK_VISIBILITY_NOTIFY_MASK);
GdkScreen *screen = gtk_widget_get_screen (wtop);
if (FRAME_DISPLAY_INFO (f)->n_planes == 32)
{
GdkVisual *visual = gdk_screen_get_rgba_visual (screen);
gtk_widget_set_visual (wtop, visual);
gtk_widget_set_visual (wfixed, visual);
}
#ifndef HAVE_PGTK
/* Must realize the windows so the X window gets created. It is used
by callers of this function. */
@ -1651,7 +1664,6 @@ xg_create_frame_widgets (struct frame *f)
#endif
{
GdkScreen *screen = gtk_widget_get_screen (wtop);
GtkSettings *gs = gtk_settings_get_for_screen (screen);
/* Only connect this signal once per screen. */
if (! g_signal_handler_find (G_OBJECT (gs),

View file

@ -830,6 +830,8 @@ haiku_create_frame (Lisp_Object parms)
RES_TYPE_NUMBER);
gui_default_parameter (f, parms, Qalpha, Qnil,
"alpha", "Alpha", RES_TYPE_NUMBER);
gui_default_parameter (f, parms, Qalpha_background, Qnil,
"alphaBackground", "AlphaBackground", RES_TYPE_NUMBER);
gui_default_parameter (f, parms, Qfullscreen, Qnil,
"fullscreen", "Fullscreen", RES_TYPE_SYMBOL);
@ -1043,6 +1045,8 @@ haiku_create_tip_frame (Lisp_Object parms)
"cursorType", "CursorType", RES_TYPE_SYMBOL);
gui_default_parameter (f, parms, Qalpha, Qnil,
"alpha", "Alpha", RES_TYPE_NUMBER);
gui_default_parameter (f, parms, Qalpha_background, Qnil,
"alphaBackground", "AlphaBackground", RES_TYPE_NUMBER);
initial_setup_back_buffer (f);
@ -2609,7 +2613,8 @@ frame_parm_handler haiku_frame_parm_handlers[] =
haiku_set_no_accept_focus,
NULL, /* set z group */
haiku_set_override_redirect,
gui_set_no_special_glyphs
gui_set_no_special_glyphs,
gui_set_alpha_background,
};
void

View file

@ -1004,6 +1004,7 @@ Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side.
ns_set_z_group,
0, /* x_set_override_redirect */
gui_set_no_special_glyphs,
gui_set_alpha_background,
#ifdef NS_IMPL_COCOA
ns_set_appearance,
ns_set_transparent_titlebar,
@ -1436,6 +1437,8 @@ Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side.
RES_TYPE_NUMBER);
gui_default_parameter (f, parms, Qalpha, Qnil,
"alpha", "Alpha", RES_TYPE_NUMBER);
gui_default_parameter (f, parms, Qalpha_background, Qnil,
"alphaBackground", "AlphaBackground", RES_TYPE_NUMBER);
gui_default_parameter (f, parms, Qfullscreen, Qnil,
"fullscreen", "Fullscreen", RES_TYPE_SYMBOL);

View file

@ -1043,6 +1043,7 @@ frame_parm_handler pgtk_frame_parm_handlers[] = {
x_set_z_group,
x_set_override_redirect,
gui_set_no_special_glyphs,
gui_set_alpha_background,
};
@ -1667,6 +1668,8 @@ This function is an internal primitive--use `make-frame' instead. */ )
RES_TYPE_NUMBER);
gui_default_parameter (f, parms, Qalpha, Qnil,
"alpha", "Alpha", RES_TYPE_NUMBER);
gui_default_parameter (f, parms, Qalpha, Qnil,
"alphaBackground", "AlphaBackground", RES_TYPE_NUMBER);
if (!NILP (parent_frame))
{
@ -2936,6 +2939,8 @@ x_create_tip_frame (struct pgtk_display_info *dpyinfo, Lisp_Object parms, struct
"cursorType", "CursorType", RES_TYPE_SYMBOL);
gui_default_parameter (f, parms, Qalpha, Qnil,
"alpha", "Alpha", RES_TYPE_NUMBER);
gui_default_parameter (f, parms, Qalpha_background, Qnil,
"alphaBackground", "AlphaBackground", RES_TYPE_NUMBER);
/* Add `tooltip' frame parameter's default value. */
if (NILP (Fframe_parameter (frame, Qtooltip)))

View file

@ -6018,6 +6018,8 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
NULL, NULL, RES_TYPE_BOOLEAN);
gui_default_parameter (f, parameters, Qno_special_glyphs, Qnil,
NULL, NULL, RES_TYPE_BOOLEAN);
gui_default_parameter (f, parameters, Qalpha_background, Qnil,
"alphaBackground", "AlphaBackground", RES_TYPE_NUMBER);
/* Process alpha here (Bug#16619). On XP this fails with child
frames. For `no-focus-on-map' frames delay processing of alpha
@ -6155,6 +6157,9 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
gui_default_parameter (f, parameters, Qz_group, Qnil,
NULL, NULL, RES_TYPE_SYMBOL);
gui_default_parameter (f, parameters, Qalpha_background, Qnil,
"alphaBackground", "AlphaBackground", RES_TYPE_NUMBER);
/* Make the window appear on the frame and enable display, unless
the caller says not to. However, with explicit parent, Emacs
cannot control visibility, so don't try. */
@ -7089,6 +7094,8 @@ w32_create_tip_frame (struct w32_display_info *dpyinfo, Lisp_Object parms)
/* Process alpha here (Bug#17344). */
gui_default_parameter (f, parms, Qalpha, Qnil,
"alpha", "Alpha", RES_TYPE_NUMBER);
gui_default_parameter (f, parms, Qalpha_background, Qnil,
"alphaBackground", "AlphaBackground", RES_TYPE_NUMBER);
/* Add `tooltip' frame parameter's default value. */
if (NILP (Fframe_parameter (frame, Qtooltip)))
@ -10436,6 +10443,7 @@ frame_parm_handler w32_frame_parm_handlers[] =
w32_set_z_group,
0, /* x_set_override_redirect */
gui_set_no_special_glyphs,
gui_set_alpha_background,
};
void

View file

@ -4598,6 +4598,8 @@ This function is an internal primitive--use `make-frame' instead. */)
RES_TYPE_NUMBER);
gui_default_parameter (f, parms, Qalpha, Qnil,
"alpha", "Alpha", RES_TYPE_NUMBER);
gui_default_parameter (f, parms, Qalpha_background, Qnil,
"alphaBackground", "AlphaBackground", RES_TYPE_NUMBER);
if (!NILP (parent_frame))
{
@ -6371,10 +6373,29 @@ select_visual (struct x_display_info *dpyinfo)
int n_visuals;
XVisualInfo *vinfo, vinfo_template;
dpyinfo->visual = DefaultVisualOfScreen (screen);
vinfo_template.visualid = XVisualIDFromVisual (dpyinfo->visual);
vinfo_template.screen = XScreenNumberOfScreen (screen);
#if defined (USE_GTK)
/* First attempt to use 32-bit visual if available */
vinfo_template.depth = 32;
vinfo = XGetVisualInfo (dpy, VisualScreenMask | VisualDepthMask,
&vinfo_template, &n_visuals);
if (n_visuals > 0)
{
dpyinfo->n_planes = vinfo->depth;
dpyinfo->visual = vinfo->visual;
XFree (vinfo);
return;
}
#endif /* defined (USE_GTK) */
/* 32-bit visual not available, fallback to default visual */
dpyinfo->visual = DefaultVisualOfScreen (screen);
vinfo_template.visualid = XVisualIDFromVisual (dpyinfo->visual);
vinfo = XGetVisualInfo (dpy, VisualIDMask | VisualScreenMask,
&vinfo_template, &n_visuals);
if (n_visuals <= 0)
@ -7232,6 +7253,8 @@ x_create_tip_frame (struct x_display_info *dpyinfo, Lisp_Object parms)
"cursorType", "CursorType", RES_TYPE_SYMBOL);
gui_default_parameter (f, parms, Qalpha, Qnil,
"alpha", "Alpha", RES_TYPE_NUMBER);
gui_default_parameter (f, parms, Qalpha_background, Qnil,
"alphaBackground", "AlphaBackground", RES_TYPE_NUMBER);
/* Add `tooltip' frame parameter's default value. */
if (NILP (Fframe_parameter (frame, Qtooltip)))
@ -8560,6 +8583,7 @@ frame_parm_handler x_frame_parm_handlers[] =
x_set_z_group,
x_set_override_redirect,
gui_set_no_special_glyphs,
gui_set_alpha_background,
};
void

View file

@ -874,12 +874,27 @@ x_set_cr_source_with_gc_background (struct frame *f, GC gc)
{
XGCValues xgcv;
XColor color;
unsigned int depth;
XGetGCValues (FRAME_X_DISPLAY (f), gc, GCBackground, &xgcv);
color.pixel = xgcv.background;
x_query_colors (f, &color, 1);
cairo_set_source_rgb (FRAME_CR_CONTEXT (f), color.red / 65535.0,
color.green / 65535.0, color.blue / 65535.0);
depth = FRAME_DISPLAY_INFO (f)->n_planes;
if (f->alpha_background < 1.0 && depth == 32)
{
cairo_set_source_rgba (FRAME_CR_CONTEXT (f), color.red / 65535.0,
color.green / 65535.0, color.blue / 65535.0,
f->alpha_background);
cairo_set_operator (FRAME_CR_CONTEXT (f), CAIRO_OPERATOR_SOURCE);
}
else
cairo_set_source_rgb (FRAME_CR_CONTEXT (f), color.red / 65535.0,
color.green / 65535.0, color.blue / 65535.0);
}
static const cairo_user_data_key_t xlib_surface_key, saved_drawable_key;
@ -1318,6 +1333,29 @@ x_fill_rectangle (struct frame *f, GC gc, int x, int y, int width, int height)
#endif
}
static void
x_clear_rectangle (struct frame *f, GC gc, int x, int y, int width, int height)
{
#ifdef USE_CAIRO
cairo_t *cr;
cr = x_begin_cr_clip (f, gc);
x_set_cr_source_with_gc_background (f, gc);
cairo_rectangle (cr, x, y, width, height);
cairo_fill (cr);
x_end_cr_clip (f);
#else
XGCValues xgcv;
Display *dpy = FRAME_X_DISPLAY (f);
XGetGCValues (dpy, gc, GCBackground | GCForeground, &xgcv);
XSetForeground (dpy, gc, xgcv.background);
XFillRectangle (dpy, FRAME_X_DRAWABLE (f),
gc, x, y, width, height);
XSetForeground (dpy, gc, xgcv.foreground);
#endif
}
static void
x_draw_rectangle (struct frame *f, GC gc, int x, int y, int width, int height)
{
@ -1898,9 +1936,9 @@ x_draw_fringe_bitmap (struct window *w, struct glyph_row *row, struct draw_fring
if (face->stipple)
XSetFillStyle (display, face->gc, FillOpaqueStippled);
else
XSetForeground (display, face->gc, face->background);
XSetBackground (display, face->gc, face->background);
x_fill_rectangle (f, face->gc, p->bx, p->by, p->nx, p->ny);
x_clear_rectangle (f, face->gc, p->bx, p->by, p->nx, p->ny);
if (!face->stipple)
XSetForeground (display, face->gc, face->foreground);
@ -2201,12 +2239,7 @@ x_compute_glyph_string_overhangs (struct glyph_string *s)
static void
x_clear_glyph_string_rect (struct glyph_string *s, int x, int y, int w, int h)
{
Display *display = FRAME_X_DISPLAY (s->f);
XGCValues xgcv;
XGetGCValues (display, s->gc, GCForeground | GCBackground, &xgcv);
XSetForeground (display, s->gc, xgcv.background);
x_fill_rectangle (s->f, s->gc, x, y, w, h);
XSetForeground (display, s->gc, xgcv.foreground);
x_clear_rectangle (s->f, s->gc, x, y, w, h);
}