void update_root(monitor_t *m, xcb_rectangle_t *rect) { xcb_rectangle_t last_rect = m->rectangle; m->rectangle = *rect; if (m->root == XCB_NONE) { uint32_t values[] = {XCB_EVENT_MASK_ENTER_WINDOW}; m->root = xcb_generate_id(dpy); xcb_create_window(dpy, XCB_COPY_FROM_PARENT, m->root, root, rect->x, rect->y, rect->width, rect->height, 0, XCB_WINDOW_CLASS_INPUT_ONLY, XCB_COPY_FROM_PARENT, XCB_CW_EVENT_MASK, values); xcb_icccm_set_wm_class(dpy, m->root, sizeof(ROOT_WINDOW_IC), ROOT_WINDOW_IC); window_lower(m->root); if (focus_follows_pointer) { window_show(m->root); } } else { window_move_resize(m->root, rect->x, rect->y, rect->width, rect->height); put_status(SBSC_MASK_MONITOR_GEOMETRY, "monitor_geometry 0x%08X %ux%u+%i+%i\n", m->id, rect->width, rect->height, rect->x, rect->y); } for (desktop_t *d = m->desk_head; d != NULL; d = d->next) { for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root)) { if (n->client == NULL) { continue; } adapt_geometry(&last_rect, rect, n); } arrange(m, d); } }
static int action_window (Display *disp, Window win, char mode) {/*{{{*/ p_verbose("Using window: 0x%.8lx\n", win); switch (mode) { case 'a': return activate_window(disp, win, True); case 'c': return close_window(disp, win); case 'e': /* resize/move the window around the desktop => -r -e */ return window_move_resize(disp, win, options.param); case 't': /* move the window to the specified desktop => -r -t */ return window_to_desktop(disp, win, atoi(options.param)); case 'R': /* move the window to the current desktop and activate it => -r */ if (window_to_desktop(disp, win, -1) == EXIT_SUCCESS) { usleep(100000); /* 100 ms - make sure the WM has enough time to move the window, before we activate it */ return activate_window(disp, win, False); } else { return EXIT_FAILURE; } default: fprintf(stderr, "Unknown action: '%c'\n", mode); return EXIT_FAILURE; } }/*}}}*/
void transfer_node(monitor_t *ms, desktop_t *ds, monitor_t *md, desktop_t *dd, node_t *n) { if (n == NULL || ds == NULL || dd == NULL || ms == NULL || md == NULL || (ms == md && dd == ds)) return; PRINTF("transfer node %X\n", n->client->window); unlink_node(ds, n); insert_node(md, dd, n); ewmh_set_wm_desktop(n, dd); if (ds == ms->desk && dd != md->desk) { window_hide(n->client->window); } fit_monitor(md, n->client); if (n->client->fullscreen) window_move_resize(n->client->window, md->rectangle.x, md->rectangle.y, md->rectangle.width, md->rectangle.height); if (ds != ms->desk && dd == md->desk) { window_show(n->client->window); focus_node(md, dd, n, true); } else { focus_node(md, dd, n, false); } if (ds == ms->desk || dd == md->desk) update_current(); }
void draw_presel_feedback(monitor_t *m, desktop_t *d, node_t *n) { if (n == NULL || n->presel == NULL || d->layout == LAYOUT_MONOCLE) { return; } if (focus_follows_pointer) { listen_enter_notify(d->root, false); } bool exists = (n->presel->feedback != XCB_NONE); if (!exists) { initialize_presel_feedback(n); } int gap = gapless_monocle && IS_MONOCLE(d) ? 0 : d->window_gap; presel_t *p = n->presel; xcb_rectangle_t rect = n->rectangle; rect.x = rect.y = 0; rect.width -= gap; rect.height -= gap; xcb_rectangle_t presel_rect = rect; switch (p->split_dir) { case DIR_NORTH: presel_rect.height = p->split_ratio * rect.height; break; case DIR_EAST: presel_rect.width = (1 - p->split_ratio) * rect.width; presel_rect.x = rect.width - presel_rect.width; break; case DIR_SOUTH: presel_rect.height = (1 - p->split_ratio) * rect.height; presel_rect.y = rect.height - presel_rect.height; break; case DIR_WEST: presel_rect.width = p->split_ratio * rect.width; break; } window_move_resize(p->feedback, n->rectangle.x + presel_rect.x, n->rectangle.y + presel_rect.y, presel_rect.width, presel_rect.height); if (!exists && m->desk == d) { window_show(p->feedback); } if (focus_follows_pointer) { listen_enter_notify(d->root, true); } }
void update_root(monitor_t *m) { xcb_rectangle_t rect = m->rectangle; window_move_resize(m->root, rect.x, rect.y, rect.width, rect.height); }
void track_pointer(int root_x, int root_y) { if (frozen_pointer->action == ACTION_NONE) return; int16_t delta_x, delta_y, x = 0, y = 0, w = 1, h = 1; uint16_t width, height; pointer_action_t pac = frozen_pointer->action; monitor_t *m = frozen_pointer->monitor; desktop_t *d = frozen_pointer->desktop; node_t *n = frozen_pointer->node; client_t *c = frozen_pointer->client; xcb_window_t win = frozen_pointer->window; xcb_rectangle_t rect = frozen_pointer->rectangle; node_t *vertical_fence = frozen_pointer->vertical_fence; node_t *horizontal_fence = frozen_pointer->horizontal_fence; delta_x = root_x - frozen_pointer->position.x; delta_y = root_y - frozen_pointer->position.y; switch (pac) { case ACTION_MOVE: if (frozen_pointer->is_tiled) { xcb_window_t pwin = XCB_NONE; query_pointer(&pwin, NULL); if (pwin == win) return; coordinates_t loc; bool is_managed = (pwin == XCB_NONE ? false : locate_window(pwin, &loc)); if (is_managed && is_tiled(loc.node->client) && loc.monitor == m) { swap_nodes(m, d, n, m, d, loc.node); arrange(m, d); } else { if (is_managed && loc.monitor == m) { return; } else if (!is_managed) { xcb_point_t pt = (xcb_point_t) {root_x, root_y}; monitor_t *pmon = monitor_from_point(pt); if (pmon == NULL || pmon == m) { return; } else { loc.monitor = pmon; loc.desktop = pmon->desk; } } bool focused = (n == mon->desk->focus); transfer_node(m, d, n, loc.monitor, loc.desktop, loc.desktop->focus); if (focused) focus_node(loc.monitor, loc.desktop, n); frozen_pointer->monitor = loc.monitor; frozen_pointer->desktop = loc.desktop; } } else { x = rect.x + delta_x; y = rect.y + delta_y; window_move(win, x, y); c->floating_rectangle.x = x; c->floating_rectangle.y = y; xcb_point_t pt = (xcb_point_t) {root_x, root_y}; monitor_t *pmon = monitor_from_point(pt); if (pmon == NULL || pmon == m) return; bool focused = (n == mon->desk->focus); transfer_node(m, d, n, pmon, pmon->desk, pmon->desk->focus); if (focused) focus_node(pmon, pmon->desk, n); frozen_pointer->monitor = pmon; frozen_pointer->desktop = pmon->desk; } break; case ACTION_RESIZE_SIDE: case ACTION_RESIZE_CORNER: if (frozen_pointer->is_tiled) { if (vertical_fence != NULL) { double sr = frozen_pointer->vertical_ratio + (double) delta_x / vertical_fence->rectangle.width; sr = MAX(0, sr); sr = MIN(1, sr); vertical_fence->split_ratio = sr; } if (horizontal_fence != NULL) { double sr = frozen_pointer->horizontal_ratio + (double) delta_y / horizontal_fence->rectangle.height; sr = MAX(0, sr); sr = MIN(1, sr); horizontal_fence->split_ratio = sr; } arrange(mon, mon->desk); } else { if (pac == ACTION_RESIZE_SIDE) { switch (frozen_pointer->side) { case SIDE_TOP: x = rect.x; y = rect.y + delta_y; w = rect.width; h = rect.height - delta_y; break; case SIDE_RIGHT: x = rect.x; y = rect.y; w = rect.width + delta_x; h = rect.height; break; case SIDE_BOTTOM: x = rect.x; y = rect.y; w = rect.width; h = rect.height + delta_y; break; case SIDE_LEFT: x = rect.x + delta_x; y = rect.y; w = rect.width - delta_x; h = rect.height; break; } width = MAX(1, w); height = MAX(1, h); window_move_resize(win, x, y, width, height); c->floating_rectangle = (xcb_rectangle_t) {x, y, width, height}; window_draw_border(n, d->focus == n, mon == m); } else if (pac == ACTION_RESIZE_CORNER) { switch (frozen_pointer->corner) { case CORNER_TOP_LEFT: x = rect.x + delta_x; y = rect.y + delta_y; w = rect.width - delta_x; h = rect.height - delta_y; break; case CORNER_TOP_RIGHT: x = rect.x; y = rect.y + delta_y; w = rect.width + delta_x; h = rect.height - delta_y; break; case CORNER_BOTTOM_LEFT: x = rect.x + delta_x; y = rect.y; w = rect.width - delta_x; h = rect.height + delta_y; break; case CORNER_BOTTOM_RIGHT: x = rect.x; y = rect.y; w = rect.width + delta_x; h = rect.height + delta_y; break; } width = MAX(1, w); height = MAX(1, h); window_move_resize(win, x, y, width, height); c->floating_rectangle = (xcb_rectangle_t) {x, y, width, height}; window_draw_border(n, d->focus == n, mon == m); } } break; case ACTION_FOCUS: case ACTION_NONE: break; } }
bool resize_client(coordinates_t *loc, resize_handle_t rh, int dx, int dy) { node_t *n = loc->node; if (n == NULL || n->client == NULL || n->client->state == STATE_FULLSCREEN) { return false; } node_t *horizontal_fence = NULL, *vertical_fence = NULL; xcb_rectangle_t rect = get_rectangle(NULL, n); uint16_t width = rect.width, height = rect.height; int16_t x = rect.x, y = rect.y; if (n->client->state == STATE_TILED) { if (rh & HANDLE_LEFT) { vertical_fence = find_fence(n, DIR_WEST); } else if (rh & HANDLE_RIGHT) { vertical_fence = find_fence(n, DIR_EAST); } if (rh & HANDLE_TOP) { horizontal_fence = find_fence(n, DIR_NORTH); } else if (rh & HANDLE_BOTTOM) { horizontal_fence = find_fence(n, DIR_SOUTH); } if (vertical_fence == NULL && horizontal_fence == NULL) { return false; } if (vertical_fence != NULL) { double sr = vertical_fence->split_ratio + (double) dx / vertical_fence->rectangle.width; sr = MAX(0, sr); sr = MIN(1, sr); vertical_fence->split_ratio = sr; } if (horizontal_fence != NULL) { double sr = horizontal_fence->split_ratio + (double) dy / horizontal_fence->rectangle.height; sr = MAX(0, sr); sr = MIN(1, sr); horizontal_fence->split_ratio = sr; } arrange(loc->monitor, loc->desktop); } else { int w = width + dx * (rh & HANDLE_LEFT ? -1 : (rh & HANDLE_RIGHT ? 1 : 0)); int h = height + dy * (rh & HANDLE_TOP ? -1 : (rh & HANDLE_BOTTOM ? 1 : 0)); width = MAX(1, w); height = MAX(1, h); apply_size_hints(n->client, &width, &height); if (rh & HANDLE_LEFT) { x += rect.width - width; } if (rh & HANDLE_TOP) { y += rect.height - height; } n->client->floating_rectangle = (xcb_rectangle_t) {x, y, width, height}; if (n->client->state == STATE_FLOATING) { if (focus_follows_pointer) { listen_enter_notify(loc->desktop->root, false); } window_move_resize(n->id, x, y, width, height); if (focus_follows_pointer) { listen_enter_notify(loc->desktop->root, true); } 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); } } else { arrange(loc->monitor, loc->desktop); } } return true; }
void apply_layout(monitor_t *m, desktop_t *d, node_t *n, xcb_rectangle_t rect, xcb_rectangle_t root_rect) { if (n == NULL) return; n->rectangle = rect; if (is_leaf(n)) { if (n->client->fullscreen) return; if (is_floating(n->client) && n->client->border_width != border_width) { int ds = 2 * (border_width - n->client->border_width); n->client->floating_rectangle.width += ds; n->client->floating_rectangle.height += ds; } if (borderless_monocle && is_tiled(n->client) && d->layout == LAYOUT_MONOCLE) n->client->border_width = 0; else n->client->border_width = border_width; xcb_rectangle_t r; if (is_tiled(n->client)) { if (d->layout == LAYOUT_TILED) r = rect; else if (d->layout == LAYOUT_MONOCLE) r = root_rect; int wg = (gapless_monocle && d->layout == LAYOUT_MONOCLE ? 0 : window_gap); int bleed = wg + 2 * n->client->border_width; r.width = (bleed < r.width ? r.width - bleed : 1); r.height = (bleed < r.height ? r.height - bleed : 1); n->client->tiled_rectangle = r; } else { r = n->client->floating_rectangle; } window_move_resize(n->client->window, r.x, r.y, r.width, r.height); window_border_width(n->client->window, n->client->border_width); window_draw_border(n, n == d->focus, m == mon); } else { xcb_rectangle_t first_rect; xcb_rectangle_t second_rect; if (n->first_child->vacant || n->second_child->vacant) { first_rect = second_rect = rect; } else { unsigned int fence; if (n->split_type == TYPE_VERTICAL) { fence = rect.width * n->split_ratio; first_rect = (xcb_rectangle_t) {rect.x, rect.y, fence, rect.height}; second_rect = (xcb_rectangle_t) {rect.x + fence, rect.y, rect.width - fence, rect.height}; } else if (n->split_type == TYPE_HORIZONTAL) { fence = rect.height * n->split_ratio; first_rect = (xcb_rectangle_t) {rect.x, rect.y, rect.width, fence}; second_rect = (xcb_rectangle_t) {rect.x, rect.y + fence, rect.width, rect.height - fence}; } } apply_layout(m, d, n->first_child, first_rect, root_rect); apply_layout(m, d, n->second_child, second_rect, root_rect); } }