1 /* xob - A lightweight overlay volume/anything bar for the X Window System.
2  * Copyright (C) 2021 Florent Ch.
3  * Copyright (C) 2021 Oliver Hattshire
4  *
5  * xob is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * xob is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with xob.  If not, see <https://www.gnu.org/licenses/>.
17  */
18 
19 #include "display.h"
20 #include <X11/extensions/Xrender.h>
21 #include <stdlib.h>
22 
is_alpha_visual(Display_context dc,Visual * visual)23 static Bool is_alpha_visual(Display_context dc, Visual *visual)
24 {
25     XRenderPictFormat *fmt = XRenderFindVisualFormat(dc.x.display, visual);
26     return (fmt->type == PictTypeDirect && fmt->direct.alphaMask);
27 }
28 
get_alpha_depth_if_available(Display_context dc)29 static Depth get_alpha_depth_if_available(Display_context dc)
30 {
31     Depth depth;
32     depth.nvisuals = 0;
33 
34     int depths_list_num;
35     int *depths_list =
36         XListDepths(dc.x.display, dc.x.screen_number, &depths_list_num);
37 
38     for (int i = depths_list_num - 1; i != 0; i--)
39     {
40         if (depths_list[i] == 32)
41         {
42             int visuals_count;
43             XVisualInfo *visuals_available;
44 
45             static long visual_template_mask =
46                 VisualScreenMask | VisualDepthMask | VisualClassMask;
47             XVisualInfo visual_template = {
48                 .screen = dc.x.screen_number, .depth = 32, .class = TrueColor};
49 
50             visuals_available =
51                 XGetVisualInfo(dc.x.display, visual_template_mask,
52                                &visual_template, &visuals_count);
53 
54             for (int i = 0; i < visuals_count; i++)
55             {
56                 if (is_alpha_visual(dc, visuals_available[i].visual))
57                 {
58                     depth.visuals = visuals_available[i].visual;
59                     depth.nvisuals = 1;
60                     depth.depth = 32;
61                     break;
62                 }
63             }
64             XFree(visuals_available);
65             break;
66         }
67     }
68     XFree(depths_list);
69     return depth;
70 }
71 
xrendercolor_from_color(Color color)72 static XRenderColor xrendercolor_from_color(Color color)
73 {
74     unsigned short alpha = color.alpha * 257;
75     return (XRenderColor){.alpha = alpha,
76                           .red = (color.red * 257 * alpha) / 0xffffU,
77                           .green = (color.green * 257 * alpha) / 0xffffU,
78                           .blue = (color.blue * 257 * alpha) / 0xffffU};
79 }
80 
fill_rectangle(X_context xc,Color c,int x,int y,unsigned int w,unsigned int h)81 void fill_rectangle(X_context xc, Color c, int x, int y, unsigned int w,
82                     unsigned int h)
83 {
84     XRenderColor xrc = xrendercolor_from_color(c);
85     XWindowAttributes attrib;
86     XGetWindowAttributes(xc.display, xc.window, &attrib);
87     XRenderPictFormat *pfmt =
88         XRenderFindVisualFormat(xc.display, attrib.visual);
89 
90     Picture pict = XRenderCreatePicture(xc.display, xc.window, pfmt, 0, 0);
91     XRenderFillRectangle(xc.display, PictOpSrc, pict, &xrc, x, y, w, h);
92     XRenderFreePicture(xc.display, pict);
93 }
94 
get_display_context_depth(Display_context dc)95 Depth get_display_context_depth(Display_context dc)
96 {
97     Depth depth = {.depth = DefaultDepth(dc.x.display, dc.x.screen_number),
98                    .visuals = DefaultVisual(dc.x.display, dc.x.screen_number),
99                    .nvisuals = 1};
100     Depth adepth = get_alpha_depth_if_available(dc);
101     return adepth.nvisuals == 1 ? adepth : depth;
102 }
103