#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
+#include <xcb/shape.h>
#include "bspwm.h"
#include "ewmh.h"
#include "monitor.h"
+#include "desktop.h"
#include "query.h"
#include "rule.h"
#include "settings.h"
#include "parse.h"
#include "window.h"
+#include <xcb/shape.h>
+
void schedule_window(xcb_window_t win)
{
coordinates_t loc;
}
}
- 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);
}
}
-void manage_window(xcb_window_t win, rule_consequence_t *csq, int fd)
+bool manage_window(xcb_window_t win, rule_consequence_t *csq, int fd)
{
monitor_t *m = mon;
desktop_t *d = mon->desk;
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);
+ }
}
}
free(csq->layer);
free(csq->state);
window_show(win);
- return;
+ return false;
}
if (csq->node_desc[0] != '\0') {
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) {
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);
snprintf(c->class_name, sizeof(c->class_name), "%s", csq->class_name);
snprintf(c->instance_name, sizeof(c->instance_name), "%s", csq->instance_name);
+ if ((csq->state != NULL && (*(csq->state) == STATE_FLOATING || *(csq->state) == STATE_FULLSCREEN)) || csq->hidden) {
+ n->vacant = true;
+ }
+
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;
put_status(SBSC_MASK_NODE_ADD, "node_add 0x%08X 0x%08X 0x%08X 0x%08X\n", m->id, d->id, f!=NULL?f->id:0, win);
set_sticky(m, d, n, csq->sticky);
set_private(m, d, n, csq->private);
set_locked(m, d, n, csq->locked);
+ set_marked(m, d, n, csq->marked);
arrange(m, d);
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);
draw_border(n, false, (m == mon));
}
- ewmh_set_wm_desktop(n, d);
- ewmh_update_client_list(false);
free(csq->layer);
free(csq->state);
+
+ return true;
}
void set_window_state(xcb_window_t win, xcb_icccm_wm_state_t state)
}
xcb_window_t win = xcb_generate_id(dpy);
- uint32_t mask = XCB_CW_BACK_PIXEL | XCB_CW_SAVE_UNDER | XCB_CW_EVENT_MASK;
- uint32_t values[] = {get_color_pixel(presel_feedback_color), 1, focus_follows_pointer ? XCB_EVENT_MASK_ENTER_WINDOW : 0};
+ uint32_t mask = XCB_CW_BACK_PIXEL | XCB_CW_SAVE_UNDER;
+ uint32_t values[] = {get_color_pixel(presel_feedback_color), 1};
xcb_create_window(dpy, XCB_COPY_FROM_PARENT, win, root, 0, 0, 1, 1, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT,
XCB_COPY_FROM_PARENT, mask, values);
xcb_icccm_set_wm_class(dpy, win, sizeof(PRESEL_FEEDBACK_IC), PRESEL_FEEDBACK_IC);
- window_grab_buttons(win);
+ /* Make presel window's input shape NULL to pass any input to window below */
+ xcb_shape_rectangles(dpy, XCB_SHAPE_SO_SET, XCB_SHAPE_SK_INPUT, XCB_CLIP_ORDERING_UNSORTED, win, 0, 0, 0, NULL);
stacking_list_t *s = stack_tail;
while (s != NULL && !IS_TILED(s->node->client)) {
s = s->prev;
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;
}
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;
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);
}
uint32_t border_color_pxl = get_border_color(focused_node, focused_monitor);
for (node_t *f = first_extrema(n); f != NULL; f = next_leaf(f, n)) {
- if (f->client != NULL && f->client->border_width > 0) {
+ if (f->client != NULL) {
window_draw_border(f->id, border_color_pxl);
}
}
}
+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);
sr = MIN(1, sr);
horizontal_fence->split_ratio = sr;
}
+ node_t *target_fence = horizontal_fence != NULL ? horizontal_fence : vertical_fence;
+ adjust_ratios(target_fence, target_fence->rectangle);
arrange(loc->monitor, loc->desktop);
} else {
int w = width, h = height;
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);
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;
}
}
}
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};