commit
813417915c
63
src/draw.c
63
src/draw.c
@ -388,12 +388,35 @@ static int layout_get_height(struct colored_layout *cl)
|
|||||||
return MAX(h, h_icon);
|
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.
|
* 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.
|
* The top corners will get rounded by `corner_radius`, if `first` is set.
|
||||||
* Respectably the same for `last` with the bottom corners.
|
* 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;
|
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 *ret_width)
|
||||||
{
|
{
|
||||||
int x = 0;
|
int x = 0;
|
||||||
|
int radius_int = corner_radius;
|
||||||
|
|
||||||
cairo_t *c = cairo_create(srf);
|
cairo_t *c = cairo_create(srf);
|
||||||
|
|
||||||
@ -464,26 +488,31 @@ static cairo_surface_t *render_background(cairo_surface_t *srf,
|
|||||||
else
|
else
|
||||||
height += settings.separator_height;
|
height += settings.separator_height;
|
||||||
|
|
||||||
cairo_set_source_rgb(c, cl->frame.r, cl->frame.g, cl->frame.b);
|
if (settings.frame_width > 0)
|
||||||
draw_rounded_rect(c, x, y, width, height, corner_radius, first, last);
|
{
|
||||||
cairo_fill(c);
|
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);
|
||||||
|
|
||||||
/* adding frame */
|
/* adding frame */
|
||||||
x += settings.frame_width;
|
x += settings.frame_width;
|
||||||
if (first) {
|
if (first) {
|
||||||
y += settings.frame_width;
|
y += settings.frame_width;
|
||||||
height -= settings.frame_width;
|
height -= settings.frame_width;
|
||||||
|
}
|
||||||
|
|
||||||
|
width -= 2 * settings.frame_width;
|
||||||
|
|
||||||
|
if (last)
|
||||||
|
height -= settings.frame_width;
|
||||||
|
else
|
||||||
|
height -= settings.separator_height;
|
||||||
|
|
||||||
|
radius_int = frame_internal_radius (corner_radius, settings.frame_width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
width -= 2 * settings.frame_width;
|
|
||||||
|
|
||||||
if (last)
|
|
||||||
height -= settings.frame_width;
|
|
||||||
else
|
|
||||||
height -= settings.separator_height;
|
|
||||||
|
|
||||||
cairo_set_source_rgb(c, cl->bg.r, cl->bg.g, cl->bg.b);
|
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);
|
cairo_fill(c);
|
||||||
|
|
||||||
if ( settings.sep_color.type != SEP_FRAME
|
if ( settings.sep_color.type != SEP_FRAME
|
||||||
|
@ -8,6 +8,8 @@ void draw_setup(void);
|
|||||||
|
|
||||||
void draw(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);
|
void draw_deinit(void);
|
||||||
|
|
||||||
#endif
|
#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 width = win->dim.w;
|
||||||
const int height = win->dim.h;
|
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);
|
Pixmap mask;
|
||||||
XGCValues xgcv;
|
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);
|
cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
|
||||||
XFillRectangle(xctx.dpy,
|
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
|
||||||
mask,
|
|
||||||
shape_gc,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
width,
|
|
||||||
height);
|
|
||||||
|
|
||||||
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
|
draw_rounded_rect(cr, 0, 0,
|
||||||
* use a circle for every corner and two overlapping rectangles */
|
width, height,
|
||||||
unsigned const int centercoords[] = {
|
rad,
|
||||||
0, 0,
|
true, true);
|
||||||
width - dia - 1, 0,
|
cairo_fill(cr);
|
||||||
0, height - dia - 1,
|
|
||||||
width - dia - 1, height - dia - 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
for (int i = 0; i < sizeof(centercoords)/sizeof(unsigned int); i = i+2) {
|
cairo_show_page(cr);
|
||||||
XFillArc(xctx.dpy,
|
cairo_destroy(cr);
|
||||||
mask,
|
cairo_surface_flush(cxbm);
|
||||||
shape_gc,
|
cairo_surface_destroy(cxbm);
|
||||||
centercoords[i],
|
|
||||||
centercoords[i+1],
|
|
||||||
dia,
|
|
||||||
dia,
|
|
||||||
degrees * 0,
|
|
||||||
degrees * 360);
|
|
||||||
}
|
|
||||||
XFillRectangle(xctx.dpy,
|
|
||||||
mask,
|
|
||||||
shape_gc,
|
|
||||||
rad,
|
|
||||||
0,
|
|
||||||
width-dia,
|
|
||||||
height);
|
|
||||||
XFillRectangle(xctx.dpy,
|
|
||||||
mask,
|
|
||||||
shape_gc,
|
|
||||||
0,
|
|
||||||
rad,
|
|
||||||
width,
|
|
||||||
height-dia);
|
|
||||||
|
|
||||||
XShapeCombineMask(xctx.dpy, win->xwin, ShapeBounding, 0, 0, mask, ShapeSet);
|
XShapeCombineMask(xctx.dpy, win->xwin, ShapeBounding, 0, 0, mask, ShapeSet);
|
||||||
|
|
||||||
XFreeGC(xctx.dpy, shape_gc);
|
|
||||||
XFreePixmap(xctx.dpy, mask);
|
XFreePixmap(xctx.dpy, mask);
|
||||||
|
|
||||||
XShapeSelectInput(xctx.dpy,
|
XShapeSelectInput(xctx.dpy,
|
||||||
win->xwin, ShapeNotifyMask);
|
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)
|
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);
|
x_win_move(win, dim->x, dim->y, dim->w, dim->h);
|
||||||
cairo_xlib_surface_set_size(win->root_surface, 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_set_source_surface(win->c_ctx, srf, 0, 0);
|
||||||
cairo_paint(win->c_ctx);
|
cairo_paint(win->c_ctx);
|
||||||
cairo_show_page(win->c_ctx);
|
cairo_show_page(win->c_ctx);
|
||||||
|
|
||||||
if (settings.corner_radius != 0)
|
if (settings.corner_radius != 0 && ! x_win_composited(win))
|
||||||
x_win_round_corners(win, dim->corner_radius);
|
x_win_corners_shape(win, dim->corner_radius);
|
||||||
|
else
|
||||||
|
x_win_corners_unshape(win);
|
||||||
|
|
||||||
XFlush(xctx.dpy);
|
XFlush(xctx.dpy);
|
||||||
|
|
||||||
@ -641,12 +643,27 @@ struct window_x11 *x_win_create(void)
|
|||||||
struct window_x11 *win = g_malloc0(sizeof(struct window_x11));
|
struct window_x11 *win = g_malloc0(sizeof(struct window_x11));
|
||||||
|
|
||||||
Window root;
|
Window root;
|
||||||
|
int scr_n;
|
||||||
|
int depth;
|
||||||
|
Visual * vis;
|
||||||
|
XVisualInfo vi;
|
||||||
XSetWindowAttributes wa;
|
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.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 =
|
wa.event_mask =
|
||||||
ExposureMask | KeyPressMask | VisibilityChangeMask |
|
ExposureMask | KeyPressMask | VisibilityChangeMask |
|
||||||
ButtonReleaseMask | FocusChangeMask| StructureNotifyMask;
|
ButtonReleaseMask | FocusChangeMask| StructureNotifyMask;
|
||||||
@ -659,10 +676,10 @@ struct window_x11 *x_win_create(void)
|
|||||||
scr->w,
|
scr->w,
|
||||||
1,
|
1,
|
||||||
0,
|
0,
|
||||||
DefaultDepth(xctx.dpy, DefaultScreen(xctx.dpy)),
|
depth,
|
||||||
CopyFromParent,
|
CopyFromParent,
|
||||||
DefaultVisual(xctx.dpy, DefaultScreen(xctx.dpy)),
|
vis,
|
||||||
CWOverrideRedirect | CWBackPixmap | CWEventMask,
|
CWOverrideRedirect | CWBackPixmap | CWBackPixel | CWBorderPixel | CWColormap | CWEventMask,
|
||||||
&wa);
|
&wa);
|
||||||
|
|
||||||
x_set_wm(win->xwin);
|
x_set_wm(win->xwin);
|
||||||
@ -673,7 +690,7 @@ struct window_x11 *x_win_create(void)
|
|||||||
(0xffffffff / 100)));
|
(0xffffffff / 100)));
|
||||||
|
|
||||||
win->root_surface = cairo_xlib_surface_create(xctx.dpy, win->xwin,
|
win->root_surface = cairo_xlib_surface_create(xctx.dpy, win->xwin,
|
||||||
DefaultVisual(xctx.dpy, 0),
|
vis,
|
||||||
WIDTH, HEIGHT);
|
WIDTH, HEIGHT);
|
||||||
win->c_ctx = cairo_create(win->root_surface);
|
win->c_ctx = cairo_create(win->root_surface);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user