Merge pull request #713 from nick87720z/fix-ugly-frame

Fix ugly frame
master^2
Nikos Tsipinakis 2 years ago committed by GitHub
commit 813417915c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 61
      src/draw.c
  2. 2
      src/draw.h
  3. 141
      src/x11/x.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,26 +488,31 @@ static cairo_surface_t *render_background(cairo_surface_t *srf,
else
height += settings.separator_height;
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);
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);
/* adding frame */
x += settings.frame_width;
if (first) {
y += settings.frame_width;
height -= settings.frame_width;
}
/* adding frame */
x += settings.frame_width;
if (first) {
y += settings.frame_width;
height -= settings.frame_width;
}
width -= 2 * settings.frame_width;
width -= 2 * settings.frame_width;
if (last)
height -= settings.frame_width;
else
height -= settings.separator_height;
if (last)
height -= settings.frame_width;
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

@ -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;
GC shape_gc = XCreateGC(xctx.dpy, mask, 0, &xgcv);
XSetForeground(xctx.dpy, shape_gc, 0);
XFillRectangle(xctx.dpy,
mask,
shape_gc,
0,
0,
width,
height);
XSetForeground(xctx.dpy, shape_gc, 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,
rad,
0,
width-dia,
height);
XFillRectangle(xctx.dpy,
mask,
shape_gc,
0,
rad,
width,
height-dia);
Pixmap mask;
cairo_surface_t * cxbm;
cairo_t * cr;
Screen * scr;
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);
cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
cairo_set_source_rgba(cr, 0, 0, 0, 0);
cairo_paint(cr);
cairo_set_source_rgba(cr, 1, 1, 1, 1);
draw_rounded_rect(cr, 0, 0,
width, height,
rad,
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…
Cancel
Save