From e8d643eb835e2883e12032a7f25e94a8a3335c87 Mon Sep 17 00:00:00 2001 From: Po Lu Date: Tue, 10 May 2022 16:50:10 +0800 Subject: [PATCH] Fix X11 relief background clearning when hwidth is larger than vwidth * src/xterm.c (x_fill_triangle, x_make_point, x_inside_rect_p): New functions. (x_draw_relief_rect): Complete rewrite. Use more sensible primitives. --- src/xterm.c | 212 ++++++++++++++++++++++++++++++++++------------------ 1 file changed, 140 insertions(+), 72 deletions(-) diff --git a/src/xterm.c b/src/xterm.c index c22a901ff4c..3e5cd45b431 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -7390,20 +7390,62 @@ x_setup_relief_colors (struct glyph_string *s) } } +#ifndef USE_CAIRO +static void +x_fill_triangle (struct frame *f, GC gc, XPoint point1, + XPoint point2, XPoint point3) +{ + XPoint abc[3]; + + abc[0] = point1; + abc[1] = point2; + abc[2] = point3; + + XFillPolygon (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f), + gc, abc, 3, Convex, CoordModeOrigin); +} + +static XPoint +x_make_point (int x, int y) +{ + XPoint pt; + + pt.x = x; + pt.y = y; + + return pt; +} + +static bool +x_inside_rect_p (XRectangle *rects, int nrects, int x, int y) +{ + int i; + + for (i = 0; i < nrects; ++i) + { + if (x >= rects[i].x && y >= rects[i].y + && x < rects[i].x + rects[i].width + && y < rects[i].y + rects[i].height) + return true; + } + + return false; +} +#endif /* Draw a relief on frame F inside the rectangle given by LEFT_X, - TOP_Y, RIGHT_X, and BOTTOM_Y. WIDTH is the thickness of the relief - to draw, it must be >= 0. RAISED_P means draw a raised - relief. LEFT_P means draw a relief on the left side of - the rectangle. RIGHT_P means draw a relief on the right - side of the rectangle. CLIP_RECT is the clipping rectangle to use - when drawing. */ + TOP_Y, RIGHT_X, and BOTTOM_Y. VWIDTH and HWIDTH are respectively + the thickness of the vertical relief (left and right) and + horizontal relief (top and bottom) to draw, it must be >= 0. + RAISED_P means draw a raised relief. LEFT_P means draw a relief on + the left side of the rectangle. RIGHT_P means draw a relief on the + right side of the rectangle. CLIP_RECT is the clipping rectangle + to use when drawing. */ static void -x_draw_relief_rect (struct frame *f, - int left_x, int top_y, int right_x, int bottom_y, - int hwidth, int vwidth, bool raised_p, bool top_p, bool bot_p, - bool left_p, bool right_p, +x_draw_relief_rect (struct frame *f, int left_x, int top_y, int right_x, + int bottom_y, int hwidth, int vwidth, bool raised_p, + bool top_p, bool bot_p, bool left_p, bool right_p, XRectangle *clip_rect) { #ifdef USE_CAIRO @@ -7479,90 +7521,116 @@ x_draw_relief_rect (struct frame *f, x_reset_clip_rectangles (f, top_left_gc); x_reset_clip_rectangles (f, bottom_right_gc); #else - Display *dpy = FRAME_X_DISPLAY (f); - Drawable drawable = FRAME_X_DRAWABLE (f); - int i; - GC gc; - - if (raised_p) - gc = f->output_data.x->white_relief.gc; - else - gc = f->output_data.x->black_relief.gc; - XSetClipRectangles (dpy, gc, 0, 0, clip_rect, 1, Unsorted); + GC gc, white_gc, black_gc, normal_gc; + Drawable drawable; + Display *dpy; /* This code is more complicated than it has to be, because of two minor hacks to make the boxes look nicer: (i) if width > 1, draw the outermost line using the black relief. (ii) Omit the four corner pixels. */ - /* Top. */ - if (top_p) - { - if (hwidth == 1) - XDrawLine (dpy, drawable, gc, - left_x + left_p, top_y, - right_x + !right_p, top_y); + white_gc = f->output_data.x->white_relief.gc; + black_gc = f->output_data.x->black_relief.gc; + normal_gc = f->output_data.x->normal_gc; - for (i = 1; i < hwidth; ++i) - XDrawLine (dpy, drawable, gc, - left_x + i * left_p, top_y + i, - right_x + 1 - i * right_p, top_y + i); - } + drawable = FRAME_X_DRAWABLE (f); + dpy = FRAME_X_DISPLAY (f); - /* Left. */ - if (left_p) - { - if (vwidth == 1) - XDrawLine (dpy, drawable, gc, left_x, top_y + 1, left_x, bottom_y); + x_set_clip_rectangles (f, white_gc, clip_rect, 1); + x_set_clip_rectangles (f, black_gc, clip_rect, 1); - for (i = 1; i < vwidth; ++i) - XDrawLine (dpy, drawable, gc, - left_x + i, top_y + (i + 1) * top_p, - left_x + i, bottom_y + 1 - (i + 1) * bot_p); - } - - XSetClipMask (dpy, gc, None); if (raised_p) - gc = f->output_data.x->black_relief.gc; + gc = white_gc; else - gc = f->output_data.x->white_relief.gc; - XSetClipRectangles (dpy, gc, 0, 0, clip_rect, 1, Unsorted); + gc = black_gc; - /* Outermost top line. */ - if (top_p && hwidth > 1) - XDrawLine (dpy, drawable, gc, - left_x + left_p, top_y, - right_x + !right_p, top_y); + /* Draw lines. */ - /* Outermost left line. */ - if (left_p && vwidth > 1) - XDrawLine (dpy, drawable, gc, left_x, top_y + 1, left_x, bottom_y); + if (top_p) + x_fill_rectangle (f, gc, left_x, top_y, + right_x - left_x + 1, hwidth, + false); + + if (left_p) + x_fill_rectangle (f, gc, left_x, top_y, vwidth, + bottom_y - top_y + 1, false); + + if (raised_p) + gc = black_gc; + else + gc = white_gc; - /* Bottom. */ if (bot_p) + x_fill_rectangle (f, gc, left_x, bottom_y - hwidth + 1, + right_x - left_x + 1, hwidth, false); + + if (right_p) + x_fill_rectangle (f, gc, right_x - vwidth + 1, top_y, + vwidth, bottom_y - top_y + 1, false); + + /* Draw corners. */ + + if (bot_p && left_p) + x_fill_triangle (f, raised_p ? white_gc : black_gc, + x_make_point (left_x, bottom_y - hwidth), + x_make_point (left_x + vwidth, bottom_y - hwidth), + x_make_point (left_x, bottom_y)); + + if (top_p && right_p) + x_fill_triangle (f, raised_p ? white_gc : black_gc, + x_make_point (right_x - vwidth, top_y), + x_make_point (right_x, top_y), + x_make_point (right_x - vwidth, top_y + hwidth)); + + /* Draw outer line. */ + + if (top_p && left_p && bot_p && right_p + && hwidth > 1 && vwidth > 1) + x_draw_rectangle (f, black_gc, left_x, top_y, + right_x - left_x, top_y - bottom_y); + else { - if (hwidth >= 1) - XDrawLine (dpy, drawable, gc, - left_x + left_p, bottom_y, - right_x + !right_p, bottom_y); + if (top_p && hwidth > 1) + XDrawLine (dpy, drawable, black_gc, left_x, top_y, + right_x + 1, top_y); + + if (bot_p && hwidth > 1) + XDrawLine (dpy, drawable, black_gc, left_x, bottom_y, + right_x + 1, bottom_y); + + if (left_p && vwidth > 1) + XDrawLine (dpy, drawable, black_gc, left_x, top_y, + left_x, bottom_y + 1); - for (i = 1; i < hwidth; ++i) - XDrawLine (dpy, drawable, gc, - left_x + i * left_p, bottom_y - i, - right_x + 1 - i * right_p, bottom_y - i); + if (right_p && vwidth > 1) + XDrawLine (dpy, drawable, black_gc, right_x, top_y, + right_x, bottom_y + 1); } - /* Right. */ - if (right_p) + /* Erase corners. */ + + if (hwidth > 1 && vwidth > 1) { - for (i = 0; i < vwidth; ++i) - XDrawLine (dpy, drawable, gc, - right_x - i, top_y + (i + 1) * top_p, - right_x - i, bottom_y + 1 - (i + 1) * bot_p); - } + if (left_p && top_p && x_inside_rect_p (clip_rect, 1, + left_x, top_y)) + x_clear_rectangle (f, normal_gc, left_x, top_y, 1, 1, false); - x_reset_clip_rectangles (f, gc); + if (left_p && bot_p && x_inside_rect_p (clip_rect, 1, + left_x, bottom_y)) + x_clear_rectangle (f, normal_gc, left_x, bottom_y, 1, 1, false); + + if (right_p && top_p && x_inside_rect_p (clip_rect, 1, + right_x, top_y)) + x_clear_rectangle (f, normal_gc, right_x, top_y, 1, 1, false); + + if (right_p && bot_p && x_inside_rect_p (clip_rect, 1, + right_x, bottom_y)) + x_clear_rectangle (f, normal_gc, right_x, bottom_y, 1, 1, false); + } + x_reset_clip_rectangles (f, white_gc); + x_reset_clip_rectangles (f, black_gc); #endif } -- 2.39.2