]> git.lizzy.rs Git - bspwm.git/blobdiff - src/window.c
bspwm: port rounded corners patch to latest version
[bspwm.git] / src / window.c
index 9461151840d5967e0e6dfa337939ccdc120b7456..1b9aa368414787b5b0a1e0777f420c96c07bbb13 100644 (file)
@@ -30,6 +30,7 @@
 #include "bspwm.h"
 #include "ewmh.h"
 #include "monitor.h"
+#include "desktop.h"
 #include "query.h"
 #include "rule.h"
 #include "settings.h"
@@ -40,6 +41,8 @@
 #include "parse.h"
 #include "window.h"
 
+#include <xcb/shape.h>
+
 void schedule_window(xcb_window_t win)
 {
        coordinates_t loc;
@@ -62,7 +65,7 @@ void schedule_window(xcb_window_t win)
                }
        }
 
-       rule_consequence_t *csq = make_rule_conquence();
+       rule_consequence_t *csq = make_rule_consequence();
        apply_rules(win, csq);
        if (!schedule_rules(win, csq)) {
                manage_window(win, csq, -1);
@@ -78,9 +81,11 @@ bool manage_window(xcb_window_t win, rule_consequence_t *csq, int fd)
 
        parse_rule_consequence(fd, csq);
 
-       if (ewmh_handle_struts(win)) {
+       if (!ignore_ewmh_struts && ewmh_handle_struts(win)) {
                for (monitor_t *m = mon_head; m != NULL; m = m->next) {
-                       arrange(m, m->desk);
+                       for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
+                               arrange(m, d);
+                       }
                }
        }
 
@@ -123,11 +128,8 @@ bool manage_window(xcb_window_t win, rule_consequence_t *csq, int fd)
                f = mon->desk->focus;
        }
 
-       if (csq->split_dir[0] != '\0' && f != NULL) {
-               direction_t dir;
-               if (parse_direction(csq->split_dir, &dir)) {
-                       presel_dir(m, d, f, dir);
-               }
+       if (csq->split_dir != NULL && f != NULL) {
+               presel_dir(m, d, f, *csq->split_dir);
        }
 
        if (csq->split_ratio != 0 && f != NULL) {
@@ -137,10 +139,21 @@ bool manage_window(xcb_window_t win, rule_consequence_t *csq, int fd)
        node_t *n = make_node(win);
        client_t *c = make_client();
        c->border_width = csq->border ? d->border_width : 0;
+    c->border_radius = d->border_radius;
        n->client = c;
        initialize_client(n);
        initialize_floating_rectangle(n);
 
+       xcb_shape_query_extents_reply_t* ext = xcb_shape_query_extents_reply(dpy, xcb_shape_query_extents(dpy, n->id), NULL);
+
+       n->client->sets_own_shape = false;
+       if (ext != NULL) {
+         n->client->sets_own_shape = ext->bounding_shaped || ext->clip_shaped;
+
+         free(ext);
+       }
+       fprintf(stderr, "sets shape: %d\n", n->client->sets_own_shape);
+
        if (csq->rect != NULL) {
                c->floating_rectangle = *csq->rect;
                free(csq->rect);
@@ -165,6 +178,9 @@ bool manage_window(xcb_window_t win, rule_consequence_t *csq, int fd)
 
        f = insert_node(m, d, n, f);
        clients_count++;
+       if (single_monocle && d->layout == LAYOUT_MONOCLE && tiled_count(d->root, true) > 1) {
+               set_layout(m, d, d->user_layout, false);
+       }
 
        n->vacant = false;
 
@@ -201,6 +217,11 @@ bool manage_window(xcb_window_t win, rule_consequence_t *csq, int fd)
                hide_node(d, n);
        }
 
+    window_rounded_border(n);
+
+       ewmh_update_client_list(false);
+       ewmh_set_wm_desktop(n, d);
+
        if (!csq->hidden && csq->focus) {
                if (d == mon->desk || csq->follow) {
                        focus_node(m, d, n);
@@ -212,8 +233,6 @@ bool manage_window(xcb_window_t win, rule_consequence_t *csq, int fd)
                draw_border(n, false, (m == mon));
        }
 
-       ewmh_set_wm_desktop(n, d);
-       ewmh_update_client_list(false);
        free(csq->layer);
        free(csq->state);
 
@@ -283,7 +302,7 @@ void initialize_presel_feedback(node_t *n)
 
 void draw_presel_feedback(monitor_t *m, desktop_t *d, node_t *n)
 {
-       if (n == NULL || n->presel == NULL || d->layout == LAYOUT_MONOCLE) {
+       if (n == NULL || n->presel == NULL || d->user_layout == LAYOUT_MONOCLE || !presel_feedback) {
                return;
        }
 
@@ -292,7 +311,7 @@ void draw_presel_feedback(monitor_t *m, desktop_t *d, node_t *n)
                initialize_presel_feedback(n);
        }
 
-       int gap = gapless_monocle && IS_MONOCLE(d) ? 0 : d->window_gap;
+       int gap = gapless_monocle && d->layout == LAYOUT_MONOCLE ? 0 : d->window_gap;
        presel_t *p = n->presel;
        xcb_rectangle_t rect = n->rectangle;
        rect.x = rect.y = 0;
@@ -320,6 +339,8 @@ void draw_presel_feedback(monitor_t *m, desktop_t *d, node_t *n)
        window_move_resize(p->feedback, n->rectangle.x + presel_rect.x, n->rectangle.y + presel_rect.y,
                           presel_rect.width, presel_rect.height);
 
+    window_rounded_border(n);
+
        if (!exists && m->desk == d) {
                window_show(p->feedback);
        }
@@ -412,6 +433,101 @@ void draw_border(node_t *n, bool focused_node, bool focused_monitor)
        }
 }
 
+void window_rounded_border(node_t *n)
+{
+    xcb_window_t win = n->id;
+    unsigned int radius = n->client->drawn_border_radius;
+
+    // Check for compatibility
+    const xcb_query_extension_reply_t *shape_query;
+
+    shape_query = xcb_get_extension_data (dpy, &xcb_shape_id);
+    if (!shape_query->present) return;
+
+    if (n->client->sets_own_shape) return;
+
+    // get geometry
+       xcb_get_geometry_reply_t *geo = xcb_get_geometry_reply(dpy, xcb_get_geometry(dpy, win), NULL);
+    if (geo == NULL) return;
+
+    uint16_t x  = geo->x;
+    uint16_t y  = geo->y;
+       uint16_t w  = geo->width;
+    uint16_t h  = geo->height;
+    uint16_t bw = geo->border_width;
+       uint16_t ow  = w+2*bw;
+       uint16_t oh  = h+2*bw;
+
+       free(geo);
+
+    xcb_pixmap_t bpid = xcb_generate_id(dpy);
+    xcb_pixmap_t cpid = xcb_generate_id(dpy);
+
+    xcb_create_pixmap(dpy, 1, bpid, win, ow, oh);
+    xcb_create_pixmap(dpy, 1, cpid, win, w, h);
+
+    xcb_gcontext_t black = xcb_generate_id(dpy);
+    xcb_gcontext_t white = xcb_generate_id(dpy);
+
+    xcb_create_gc(dpy, black, bpid, XCB_GC_FOREGROUND, (uint32_t[]){0, 0});
+    xcb_create_gc(dpy, white, bpid, XCB_GC_FOREGROUND, (uint32_t[]){1, 0});
+
+    int32_t rad, dia;
+    rad = radius;
+
+    rad += bw; dia = rad*2-1;
+
+    xcb_arc_t barcs[] = {
+        { -1,     -1,     dia, dia, 0, 360 << 6 },
+        { -1,     oh-dia, dia, dia, 0, 360 << 6 },
+        { ow-dia, -1,     dia, dia, 0, 360 << 6 },
+        { ow-dia, oh-dia, dia, dia, 0, 360 << 6 },
+    };
+    xcb_rectangle_t brects[] = {
+        { rad, 0, ow-dia, oh },
+        { 0, rad, ow, oh-dia },
+    };
+
+    rad -= bw; dia = rad*2-1;
+
+    xcb_arc_t carcs[] = {
+        { -1,    -1,    dia, dia, 0, 360 << 6 },
+        { -1,    h-dia, dia, dia, 0, 360 << 6 },
+        { w-dia, -1,    dia, dia, 0, 360 << 6 },
+        { w-dia, h-dia, dia, dia, 0, 360 << 6 },
+    };
+    xcb_rectangle_t crects[] = {
+        { rad, 0, w-dia, h },
+        { 0, rad, w, h-dia },
+    };
+
+    xcb_rectangle_t bounding = {0, 0, w+2*bw, h+2*bw};
+    xcb_poly_fill_rectangle(dpy, bpid, black, 1, &bounding);
+    xcb_poly_fill_rectangle(dpy, bpid, white, 2, brects);
+    xcb_poly_fill_arc(dpy, bpid, white, 4, barcs);
+
+    xcb_rectangle_t clipping = {0, 0, w, h};
+    xcb_poly_fill_rectangle(dpy, cpid, black, 1, &clipping);
+    xcb_poly_fill_rectangle(dpy, cpid, white, 2, crects);
+    xcb_poly_fill_arc(dpy, cpid, white, 4, carcs);
+
+    xcb_shape_mask(dpy, XCB_SHAPE_SO_SET, XCB_SHAPE_SK_BOUNDING,  win, -bw, -bw, bpid);
+    xcb_shape_mask(dpy, XCB_SHAPE_SO_SET, XCB_SHAPE_SK_CLIP, win, 0, 0, cpid);
+
+    if (n->presel != NULL && n->presel != XCB_NONE) {
+        xcb_window_t fb = n->presel->feedback;
+        xcb_get_geometry_reply_t *fb_geo = xcb_get_geometry_reply(dpy, xcb_get_geometry(dpy, fb), NULL);
+
+        if (fb_geo != NULL) {
+            xcb_shape_mask(dpy, XCB_SHAPE_SO_SET, XCB_SHAPE_SK_BOUNDING, fb, x-fb_geo->x, y-fb_geo->y, bpid);
+            free(fb_geo);
+        }
+    }
+
+    xcb_free_pixmap(dpy, bpid);
+    xcb_free_pixmap(dpy, cpid);
+}
+
 void window_draw_border(xcb_window_t win, uint32_t border_color_pxl)
 {
        xcb_change_window_attributes(dpy, win, XCB_CW_BORDER_PIXEL, &border_color_pxl);
@@ -614,6 +730,7 @@ bool resize_client(coordinates_t *loc, resize_handle_t rh, int dx, int dy, bool
                n->client->floating_rectangle = (xcb_rectangle_t) {x, y, width, height};
                if (n->client->state == STATE_FLOATING) {
                        window_move_resize(n->id, x, y, width, height);
+            window_rounded_border(n);
 
                        if (!grabbing) {
                                put_status(SBSC_MASK_NODE_GEOMETRY, "node_geometry 0x%08X 0x%08X 0x%08X %ux%u+%i+%i\n", loc->monitor->id, loc->desktop->id, loc->node->id, width, height, x, y);
@@ -728,18 +845,32 @@ void query_pointer(xcb_window_t *win, xcb_point_t *pt)
 
        if (qpr != NULL) {
                if (win != NULL) {
-                       *win = qpr->child;
-                       xcb_point_t pt = {qpr->root_x, qpr->root_y};
-                       for (stacking_list_t *s = stack_tail; s != NULL; s = s->prev) {
-                               if (!s->node->client->shown || s->node->hidden) {
-                                       continue;
+                       if (qpr->child == XCB_NONE) {
+                               xcb_point_t mpt = (xcb_point_t) {qpr->root_x, qpr->root_y};
+                               monitor_t *m = monitor_from_point(mpt);
+                               if (m != NULL) {
+                                       desktop_t *d = m->desk;
+                                       for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root)) {
+                                               if (n->client == NULL && is_inside(mpt, get_rectangle(m, d, n))) {
+                                                       *win = n->id;
+                                                       break;
+                                               }
+                                       }
                                }
-                               xcb_rectangle_t rect = get_rectangle(NULL, NULL, s->node);
-                               if (is_inside(pt, rect)) {
-                                       if (s->node->id == qpr->child || is_presel_window(qpr->child)) {
-                                               *win = s->node->id;
+                       } else {
+                               *win = qpr->child;
+                               xcb_point_t pt = {qpr->root_x, qpr->root_y};
+                               for (stacking_list_t *s = stack_tail; s != NULL; s = s->prev) {
+                                       if (!s->node->client->shown || s->node->hidden) {
+                                               continue;
+                                       }
+                                       xcb_rectangle_t rect = get_rectangle(NULL, NULL, s->node);
+                                       if (is_inside(pt, rect)) {
+                                               if (s->node->id == qpr->child || is_presel_window(qpr->child)) {
+                                                       *win = s->node->id;
+                                               }
+                                               break;
                                        }
-                                       break;
                                }
                        }
                }
@@ -810,6 +941,11 @@ void window_border_width(xcb_window_t win, uint32_t bw)
        xcb_configure_window(dpy, win, XCB_CONFIG_WINDOW_BORDER_WIDTH, values);
 }
 
+void window_border_radius(client_t *cli, uint32_t br)
+{
+       cli->drawn_border_radius = br;
+}
+
 void window_move(xcb_window_t win, int16_t x, int16_t y)
 {
        uint32_t values[] = {x, y};