commit
813417915c
33
src/draw.c
33
src/draw.c
@ -388,12 +388,35 @@ static int layout_get_height(struct colored_layout *cl)
|
||||
return MAX(h, h_icon);
|
||||
}
|
||||
|
||||
/* Attempt to make internal radius more organic.
|
||||
* Simple r-w is not enough for too small r/w ratio.
|
||||
* simplifications: r/2 == r - w + w*w / (r * 2) with (w == r)
|
||||
* r, w - corner radius & frame width,
|
||||
* h - box height
|
||||
*/
|
||||
static int frame_internal_radius (int r, int w, int h)
|
||||
{
|
||||
// Integer precision scaler, using 1/4 of int size
|
||||
const int s = 2 << (8 * sizeof(int) / 4);
|
||||
|
||||
int r1, r2, ret;
|
||||
h *= s;
|
||||
r *= s;
|
||||
w *= s;
|
||||
r1 = r - w + w * w / (r * 2); // w < r
|
||||
r2 = r * h / (h + (w - r) * 2); // w >= r
|
||||
|
||||
ret = (r > w) ? r1 : (r / 2 < r2) ? r / 2 : r2;
|
||||
|
||||
return ret / s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a path on the given cairo context to draw the background of a notification.
|
||||
* The top corners will get rounded by `corner_radius`, if `first` is set.
|
||||
* Respectably the same for `last` with the bottom corners.
|
||||
*/
|
||||
static void draw_rounded_rect(cairo_t *c, int x, int y, int width, int height, int corner_radius, bool first, bool last)
|
||||
void draw_rounded_rect(cairo_t *c, int x, int y, int width, int height, int corner_radius, bool first, bool last)
|
||||
{
|
||||
const float degrees = M_PI / 180.0;
|
||||
|
||||
@ -454,6 +477,7 @@ static cairo_surface_t *render_background(cairo_surface_t *srf,
|
||||
int *ret_width)
|
||||
{
|
||||
int x = 0;
|
||||
int radius_int = corner_radius;
|
||||
|
||||
cairo_t *c = cairo_create(srf);
|
||||
|
||||
@ -464,6 +488,8 @@ static cairo_surface_t *render_background(cairo_surface_t *srf,
|
||||
else
|
||||
height += settings.separator_height;
|
||||
|
||||
if (settings.frame_width > 0)
|
||||
{
|
||||
cairo_set_source_rgb(c, cl->frame.r, cl->frame.g, cl->frame.b);
|
||||
draw_rounded_rect(c, x, y, width, height, corner_radius, first, last);
|
||||
cairo_fill(c);
|
||||
@ -482,8 +508,11 @@ static cairo_surface_t *render_background(cairo_surface_t *srf,
|
||||
else
|
||||
height -= settings.separator_height;
|
||||
|
||||
radius_int = frame_internal_radius (corner_radius, settings.frame_width, height);
|
||||
}
|
||||
|
||||
cairo_set_source_rgb(c, cl->bg.r, cl->bg.g, cl->bg.b);
|
||||
draw_rounded_rect(c, x, y, width, height, corner_radius, first, last);
|
||||
draw_rounded_rect(c, x, y, width, height, radius_int, first, last);
|
||||
cairo_fill(c);
|
||||
|
||||
if ( settings.sep_color.type != SEP_FRAME
|
||||
|
@ -8,6 +8,8 @@ void draw_setup(void);
|
||||
|
||||
void draw(void);
|
||||
|
||||
void draw_rounded_rect(cairo_t *c, int x, int y, int width, int height, int corner_radius, bool first, bool last);
|
||||
|
||||
void draw_deinit(void);
|
||||
|
||||
#endif
|
||||
|
131
src/x11/x.c
131
src/x11/x.c
@ -85,84 +85,86 @@ static void x_win_move(struct window_x11 *win, int x, int y, int width, int heig
|
||||
}
|
||||
}
|
||||
|
||||
static void x_win_round_corners(struct window_x11 *win, const int rad)
|
||||
static void x_win_corners_shape(struct window_x11 *win, const int rad)
|
||||
{
|
||||
const int width = win->dim.w;
|
||||
const int height = win->dim.h;
|
||||
const int dia = 2 * rad;
|
||||
const int degrees = 64; // the factor to convert degrees to XFillArc's angle param
|
||||
|
||||
Pixmap mask = XCreatePixmap(xctx.dpy, win->xwin, width, height, 1);
|
||||
XGCValues xgcv;
|
||||
Pixmap mask;
|
||||
cairo_surface_t * cxbm;
|
||||
cairo_t * cr;
|
||||
Screen * scr;
|
||||
|
||||
GC shape_gc = XCreateGC(xctx.dpy, mask, 0, &xgcv);
|
||||
mask = XCreatePixmap(xctx.dpy, win->xwin, width, height, 1);
|
||||
scr = ScreenOfDisplay(xctx.dpy, win->cur_screen);
|
||||
cxbm = cairo_xlib_surface_create_for_bitmap(xctx.dpy, mask, scr, width, height);
|
||||
cr = cairo_create(cxbm);
|
||||
|
||||
XSetForeground(xctx.dpy, shape_gc, 0);
|
||||
XFillRectangle(xctx.dpy,
|
||||
mask,
|
||||
shape_gc,
|
||||
0,
|
||||
0,
|
||||
width,
|
||||
height);
|
||||
cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
|
||||
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
|
||||
|
||||
XSetForeground(xctx.dpy, shape_gc, 1);
|
||||
cairo_set_source_rgba(cr, 0, 0, 0, 0);
|
||||
cairo_paint(cr);
|
||||
cairo_set_source_rgba(cr, 1, 1, 1, 1);
|
||||
|
||||
/* To mark all pixels, which should get exposed, we
|
||||
* use a circle for every corner and two overlapping rectangles */
|
||||
unsigned const int centercoords[] = {
|
||||
0, 0,
|
||||
width - dia - 1, 0,
|
||||
0, height - dia - 1,
|
||||
width - dia - 1, height - dia - 1,
|
||||
};
|
||||
|
||||
for (int i = 0; i < sizeof(centercoords)/sizeof(unsigned int); i = i+2) {
|
||||
XFillArc(xctx.dpy,
|
||||
mask,
|
||||
shape_gc,
|
||||
centercoords[i],
|
||||
centercoords[i+1],
|
||||
dia,
|
||||
dia,
|
||||
degrees * 0,
|
||||
degrees * 360);
|
||||
}
|
||||
XFillRectangle(xctx.dpy,
|
||||
mask,
|
||||
shape_gc,
|
||||
draw_rounded_rect(cr, 0, 0,
|
||||
width, height,
|
||||
rad,
|
||||
0,
|
||||
width-dia,
|
||||
height);
|
||||
XFillRectangle(xctx.dpy,
|
||||
mask,
|
||||
shape_gc,
|
||||
0,
|
||||
rad,
|
||||
width,
|
||||
height-dia);
|
||||
true, true);
|
||||
cairo_fill(cr);
|
||||
|
||||
cairo_show_page(cr);
|
||||
cairo_destroy(cr);
|
||||
cairo_surface_flush(cxbm);
|
||||
cairo_surface_destroy(cxbm);
|
||||
|
||||
XShapeCombineMask(xctx.dpy, win->xwin, ShapeBounding, 0, 0, mask, ShapeSet);
|
||||
|
||||
XFreeGC(xctx.dpy, shape_gc);
|
||||
XFreePixmap(xctx.dpy, mask);
|
||||
|
||||
XShapeSelectInput(xctx.dpy,
|
||||
win->xwin, ShapeNotifyMask);
|
||||
}
|
||||
|
||||
static void x_win_corners_unshape(struct window_x11 *win)
|
||||
{
|
||||
XRectangle rect = {
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
.width = win->dim.w,
|
||||
.height = win->dim.h };
|
||||
XShapeCombineRectangles(xctx.dpy, win->xwin, ShapeBounding, 0, 0, &rect, 1, ShapeSet, 1);
|
||||
XShapeSelectInput(xctx.dpy,
|
||||
win->xwin, ShapeNotifyMask);
|
||||
}
|
||||
|
||||
static bool x_win_composited(struct window_x11 *win)
|
||||
{
|
||||
char astr[sizeof("_NET_WM_CM_S") / sizeof(char) + 8];
|
||||
Atom cm_sel;
|
||||
|
||||
sprintf(astr, "_NET_WM_CM_S%i", win->cur_screen);
|
||||
cm_sel = XInternAtom(xctx.dpy, astr, true);
|
||||
|
||||
return XGetSelectionOwner(xctx.dpy, cm_sel) != None;
|
||||
}
|
||||
|
||||
void x_display_surface(cairo_surface_t *srf, struct window_x11 *win, const struct dimensions *dim)
|
||||
{
|
||||
x_win_move(win, dim->x, dim->y, dim->w, dim->h);
|
||||
cairo_xlib_surface_set_size(win->root_surface, dim->w, dim->h);
|
||||
|
||||
XClearWindow(xctx.dpy, win->xwin);
|
||||
XFlush(xctx.dpy);
|
||||
|
||||
cairo_set_source_surface(win->c_ctx, srf, 0, 0);
|
||||
cairo_paint(win->c_ctx);
|
||||
cairo_show_page(win->c_ctx);
|
||||
|
||||
if (settings.corner_radius != 0)
|
||||
x_win_round_corners(win, dim->corner_radius);
|
||||
if (settings.corner_radius != 0 && ! x_win_composited(win))
|
||||
x_win_corners_shape(win, dim->corner_radius);
|
||||
else
|
||||
x_win_corners_unshape(win);
|
||||
|
||||
XFlush(xctx.dpy);
|
||||
|
||||
@ -641,12 +643,27 @@ struct window_x11 *x_win_create(void)
|
||||
struct window_x11 *win = g_malloc0(sizeof(struct window_x11));
|
||||
|
||||
Window root;
|
||||
int scr_n;
|
||||
int depth;
|
||||
Visual * vis;
|
||||
XVisualInfo vi;
|
||||
XSetWindowAttributes wa;
|
||||
|
||||
root = RootWindow(xctx.dpy, DefaultScreen(xctx.dpy));
|
||||
scr_n = DefaultScreen(xctx.dpy);
|
||||
root = RootWindow(xctx.dpy, scr_n);
|
||||
if (XMatchVisualInfo(xctx.dpy, scr_n, 32, TrueColor, &vi)) {
|
||||
vis = vi.visual;
|
||||
depth = vi.depth;
|
||||
} else {
|
||||
vis = DefaultVisual(xctx.dpy, scr_n);
|
||||
depth = DefaultDepth(xctx.dpy, scr_n);
|
||||
}
|
||||
|
||||
wa.override_redirect = true;
|
||||
wa.background_pixmap = ParentRelative;
|
||||
wa.background_pixmap = None;
|
||||
wa.background_pixel = 0;
|
||||
wa.border_pixel = 0;
|
||||
wa.colormap = XCreateColormap(xctx.dpy, root, vis, AllocNone);
|
||||
wa.event_mask =
|
||||
ExposureMask | KeyPressMask | VisibilityChangeMask |
|
||||
ButtonReleaseMask | FocusChangeMask| StructureNotifyMask;
|
||||
@ -659,10 +676,10 @@ struct window_x11 *x_win_create(void)
|
||||
scr->w,
|
||||
1,
|
||||
0,
|
||||
DefaultDepth(xctx.dpy, DefaultScreen(xctx.dpy)),
|
||||
depth,
|
||||
CopyFromParent,
|
||||
DefaultVisual(xctx.dpy, DefaultScreen(xctx.dpy)),
|
||||
CWOverrideRedirect | CWBackPixmap | CWEventMask,
|
||||
vis,
|
||||
CWOverrideRedirect | CWBackPixmap | CWBackPixel | CWBorderPixel | CWColormap | CWEventMask,
|
||||
&wa);
|
||||
|
||||
x_set_wm(win->xwin);
|
||||
@ -673,7 +690,7 @@ struct window_x11 *x_win_create(void)
|
||||
(0xffffffff / 100)));
|
||||
|
||||
win->root_surface = cairo_xlib_surface_create(xctx.dpy, win->xwin,
|
||||
DefaultVisual(xctx.dpy, 0),
|
||||
vis,
|
||||
WIDTH, HEIGHT);
|
||||
win->c_ctx = cairo_create(win->root_surface);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user