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 client_message(xcb_generic_event_t *evt) { xcb_client_message_event_t *e = (xcb_client_message_event_t *) evt; if (e->type == ewmh->_NET_CURRENT_DESKTOP) { coordinates_t loc; if (ewmh_locate_desktop(e->data.data32[0], &loc)) { focus_node(loc.monitor, loc.desktop, loc.desktop->focus); } return; } coordinates_t loc; if (!locate_window(e->window, &loc)) { return; } if (e->type == ewmh->_NET_WM_STATE) { handle_state(loc.monitor, loc.desktop, loc.node, e->data.data32[1], e->data.data32[0]); handle_state(loc.monitor, loc.desktop, loc.node, e->data.data32[2], e->data.data32[0]); } else if (e->type == ewmh->_NET_ACTIVE_WINDOW) { if ((ignore_ewmh_focus && e->data.data32[0] == XCB_EWMH_CLIENT_SOURCE_TYPE_NORMAL) || loc.node == mon->desk->focus) { return; } focus_node(loc.monitor, loc.desktop, loc.node); } else if (e->type == ewmh->_NET_WM_DESKTOP) { coordinates_t dloc; if (ewmh_locate_desktop(e->data.data32[0], &dloc)) { transfer_node(loc.monitor, loc.desktop, loc.node, dloc.monitor, dloc.desktop, dloc.desktop->focus); } } else if (e->type == ewmh->_NET_CLOSE_WINDOW) { window_close(loc.node); } }
void set_visibility(monitor_t *m, desktop_t *d, node_t *n, bool visible) { PRINTF("set visibilty %X: %s\n", n->client->window, BOOLSTR(visible)); if (!n->client->floating) { n->vacant = !visible; update_vacant_state(n->parent); if (visible) rotate_brother(n); else unrotate_brother(n); } if (visible) { if (m->desk == d) window_show(n->client->window); if (d->focus == NULL) { if (mon->desk == d) focus_node(m, d, n); else pseudo_focus(d, n); } } else { if (m->desk == d || n->client->sticky) window_hide(n->client->window); if (d->focus == n) { node_t *f = history_get_node(d, n); if (f == NULL) f = closest_visible(d, n); if (mon->desk == d) focus_node(m, d, f); else pseudo_focus(d, f); } } }
bool grab_pointer(pointer_action_t pac) { xcb_window_t win = XCB_NONE; xcb_point_t pos; query_pointer(&win, &pos); coordinates_t loc; if (!locate_window(win, &loc)) { if (pac == ACTION_FOCUS) { monitor_t *m = monitor_from_point(pos); if (m != NULL && m != mon && (win == XCB_NONE || win == m->root)) { focus_node(m, m->desk, m->desk->focus); return true; } } return false; } if (pac == ACTION_FOCUS) { if (loc.node != mon->desk->focus) { focus_node(loc.monitor, loc.desktop, loc.node); return true; } else if (focus_follows_pointer) { stack(loc.desktop, loc.node, true); } return false; } if (loc.node->client->state == STATE_FULLSCREEN) { return true; } xcb_grab_pointer_reply_t *reply = xcb_grab_pointer_reply(dpy, xcb_grab_pointer(dpy, 0, root, XCB_EVENT_MASK_BUTTON_RELEASE|XCB_EVENT_MASK_BUTTON_MOTION, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, XCB_NONE, XCB_NONE, XCB_CURRENT_TIME), NULL); if (reply == NULL || reply->status != XCB_GRAB_STATUS_SUCCESS) { free(reply); return true; } free(reply); if (pac == ACTION_MOVE) { put_status(SBSC_MASK_POINTER_ACTION, "pointer_action 0x%08X 0x%08X 0x%08X move begin\n", loc.monitor->id, loc.desktop->id, loc.node->id); } else if (pac == ACTION_RESIZE_CORNER) { put_status(SBSC_MASK_POINTER_ACTION, "pointer_action 0x%08X 0x%08X 0x%08X resize_corner begin\n", loc.monitor->id, loc.desktop->id, loc.node->id); } else if (pac == ACTION_RESIZE_SIDE) { put_status(SBSC_MASK_POINTER_ACTION, "pointer_action 0x%08X 0x%08X 0x%08X resize_side begin\n", loc.monitor->id, loc.desktop->id, loc.node->id); } track_pointer(loc, pac, pos); return true; }
bool transfer_desktop(monitor_t *ms, monitor_t *md, desktop_t *d) { if (ms == NULL || md == NULL || d == NULL || ms == md) { return false; } bool was_active = (d == ms->desk); unlink_desktop(ms, d); if (md->desk != NULL) { hide_desktop(d); } insert_desktop(md, d); history_transfer_desktop(md, d); if (was_active) { if (mon == ms) { focus_node(ms, NULL, NULL); } else { activate_node(ms, NULL, NULL); } } if (ms->sticky_count > 0 && was_active) { sticky_still = false; transfer_sticky_nodes(ms, d, ms->desk, d->root); sticky_still = true; } adapt_geometry(&ms->rectangle, &md->rectangle, d->root); arrange(md, d); if (md->desk == d) { if (mon == md) { focus_node(md, d, d->focus); } else { activate_node(md, d, d->focus); } } ewmh_update_wm_desktops(); ewmh_update_desktop_names(); ewmh_update_current_desktop(); put_status(SBSC_MASK_DESKTOP_TRANSFER, "desktop_transfer 0x%08X 0x%08X 0x%08X\n", ms->id, d->id, md->id); put_status(SBSC_MASK_REPORT); return true; }
void circulate_leaves(monitor_t *m, desktop_t *d, circulate_dir_t dir) { if (d == NULL || d->root == NULL || is_leaf(d->root)) return; node_t *par = d->focus->parent; bool focus_first_child = is_first_child(d->focus); if (dir == CIRCULATE_FORWARD) for (node_t *s = second_extrema(d->root), *f = prev_leaf(s); f != NULL; s = prev_leaf(f), f = prev_leaf(s)) swap_nodes(f, s); else for (node_t *f = first_extrema(d->root), *s = next_leaf(f); s != NULL; f = next_leaf(s), s = next_leaf(f)) swap_nodes(f, s); if (focus_first_child) focus_node(m, d, par->first_child, true); else focus_node(m, d, par->second_child, true); }
void motion_notify(xcb_generic_event_t *evt) { PUTS("motion notify"); xcb_motion_notify_event_t *e = (xcb_motion_notify_event_t *) evt; int dtime = e->time - last_motion_time; if (dtime > 1000) { last_motion_time = e->time; last_motion_x = e->event_x; last_motion_y = e->event_y; return; } int mdist = abs(e->event_x - last_motion_x) + abs(e->event_y - last_motion_y); if (mdist < 10) return; disable_motion_recorder(); xcb_window_t win = XCB_NONE; xcb_point_t pt = {e->root_x, e->root_y}; query_pointer(&win, NULL); bool backup = pointer_follows_monitor; auto_raise = false; pointer_follows_monitor = false; if (!window_focus(win)) { monitor_t *m = monitor_from_point(pt); if (m != NULL && m != mon) focus_node(m, m->desk, m->desk->focus); } pointer_follows_monitor = backup; auto_raise = true; }
void enter_notify(xcb_generic_event_t *evt) { xcb_enter_notify_event_t *e = (xcb_enter_notify_event_t *) evt; xcb_window_t win = e->event; PRINTF("enter notify %X %d %d\n", win, e->mode, e->detail); if (e->mode != XCB_NOTIFY_MODE_NORMAL || (mon->desk->focus != NULL && mon->desk->focus->client->window == win)) return; bool pfm_backup = pointer_follows_monitor; bool pff_backup = pointer_follows_focus; auto_raise = false; pointer_follows_monitor = false; pointer_follows_focus = false; if (!window_focus(win)) { xcb_point_t pt = {e->root_x, e->root_y}; monitor_t *m = monitor_from_point(pt); if (m != NULL && m != mon) { focus_node(m, m->desk, m->desk->focus); } } pointer_follows_monitor = pfm_backup; pointer_follows_focus = pff_backup; auto_raise = true; }
void update_current(void) { if (mon->desk->focus == NULL) ewmh_update_active_window(); else focus_node(mon, mon->desk, mon->desk->focus, true); put_status(); }
void motion_notify(xcb_generic_event_t *evt) { xcb_motion_notify_event_t *e = (xcb_motion_notify_event_t *) evt; PRINTF("motion notify %X %i %i\n", e->event, e->root_x, e->root_y); int dtime = e->time - last_motion_time; if (dtime > 1000) { last_motion_time = e->time; last_motion_x = e->event_x; last_motion_y = e->event_y; return; } int mdist = abs(e->event_x - last_motion_x) + abs(e->event_y - last_motion_y); if (mdist < 10) { return; } xcb_window_t win = XCB_NONE; xcb_point_t pt = {e->root_x, e->root_y}; query_pointer(&win, NULL); bool pfm_backup = pointer_follows_monitor; bool pff_backup = pointer_follows_focus; auto_raise = false; pointer_follows_monitor = false; pointer_follows_focus = false; coordinates_t loc; if (locate_window(win, &loc)) { if (loc.node != mon->desk->focus) { focus_node(loc.monitor, loc.desktop, loc.node); } } else { monitor_t *m = monitor_from_point(pt); if (m != NULL && m != mon) { focus_node(m, m->desk, m->desk->focus); } } pointer_follows_monitor = pfm_backup; pointer_follows_focus = pff_backup; auto_raise = true; disable_motion_recorder(); }
void client_message(xcb_generic_event_t *evt) { xcb_client_message_event_t *e = (xcb_client_message_event_t *) evt; PRINTF("client message %X %u\n", e->window, e->type); if (e->type == ewmh->_NET_CURRENT_DESKTOP) { coordinates_t loc; if (ewmh_locate_desktop(e->data.data32[0], &loc)) focus_node(loc.monitor, loc.desktop, loc.desktop->focus); return; } coordinates_t loc; if (!locate_window(e->window, &loc)) return; if (e->type == ewmh->_NET_WM_STATE) { handle_state(loc.monitor, loc.desktop, loc.node, e->data.data32[1], e->data.data32[0]); handle_state(loc.monitor, loc.desktop, loc.node, e->data.data32[2], e->data.data32[0]); } else if (e->type == ewmh->_NET_ACTIVE_WINDOW) { if ((ignore_ewmh_focus && e->data.data32[0] == XCB_EWMH_CLIENT_SOURCE_TYPE_NORMAL) || loc.node == mon->desk->focus) return; if (loc.desktop->focus->client->fullscreen && loc.desktop->focus != loc.node) { set_fullscreen(loc.desktop->focus, false); arrange(loc.monitor, loc.desktop); } focus_node(loc.monitor, loc.desktop, loc.node); } else if (e->type == ewmh->_NET_WM_DESKTOP) { coordinates_t dloc; if (ewmh_locate_desktop(e->data.data32[0], &dloc)) transfer_node(loc.monitor, loc.desktop, loc.node, dloc.monitor, dloc.desktop, dloc.desktop->focus); } else if (e->type == ewmh->_NET_CLOSE_WINDOW) { window_close(loc.node); } }
void select_monitor(monitor_t *m) { if (m == NULL || mon == m) return; PRINTF("select monitor %s\n", m->name); focus_node(m, m->desk, m->desk->focus, true); last_mon = mon; mon = m; ewmh_update_current_desktop(); put_status(); }
void remove_monitor(monitor_t *m) { put_status(SBSC_MASK_MONITOR_REMOVE, "monitor_remove 0x%08X\n", m->id); while (m->desk_head != NULL) { remove_desktop(m, m->desk_head); } unlink_monitor(m); xcb_destroy_window(dpy, m->root); free(m); if (mon == NULL) { focus_node(NULL, NULL, NULL); } put_status(SBSC_MASK_REPORT); }
void nearest_leaf(monitor_t *m, desktop_t *d, node_t *n, nearest_arg_t dir, skip_client_t skip) { if (n == NULL) return; PUTS("nearest leaf"); node_t *x = NULL; for (node_t *f = first_extrema(d->root); f != NULL; f = next_leaf(f)) if (skip == CLIENT_SKIP_NONE || (skip == CLIENT_SKIP_TILED && !is_tiled(f->client)) || (skip == CLIENT_SKIP_FLOATING && is_tiled(f->client)) || (skip == CLIENT_SKIP_CLASS_DIFFER && strcmp(f->client->class_name, n->client->class_name) == 0) || (skip == CLIENT_SKIP_CLASS_EQUAL && strcmp(f->client->class_name, n->client->class_name) != 0)) if ((dir == NEAREST_OLDER && (f->client->uid < n->client->uid) && (x == NULL || f->client->uid > x->client->uid)) || (dir == NEAREST_NEWER && (f->client->uid > n->client->uid) && (x == NULL || f->client->uid < x->client->uid))) x = f; focus_node(m, d, x, true); }
void remove_desktop(monitor_t *m, desktop_t *d) { put_status(SBSC_MASK_DESKTOP_REMOVE, "desktop_remove 0x%08X 0x%08X\n", m->id, d->id); remove_node(m, d, d->root); unlink_desktop(m, d); history_remove(d, NULL, false); free(d); ewmh_update_current_desktop(); ewmh_update_number_of_desktops(); ewmh_update_desktop_names(); if (mon != NULL && m->desk == NULL) { if (m == mon) { focus_node(m, NULL, NULL); } else { activate_node(m, NULL, NULL); } } put_status(SBSC_MASK_REPORT); }
void cycle_leaf(monitor_t *m, desktop_t *d, node_t *n, cycle_dir_t dir, skip_client_t skip) { if (n == NULL) return; PUTS("cycle leaf"); node_t *f = (dir == CYCLE_PREV ? prev_leaf(n) : next_leaf(n)); if (f == NULL) f = (dir == CYCLE_PREV ? second_extrema(d->root) : first_extrema(d->root)); while (f != n) { bool tiled = is_tiled(f->client); if (skip == CLIENT_SKIP_NONE || (skip == CLIENT_SKIP_TILED && !tiled) || (skip == CLIENT_SKIP_FLOATING && tiled) || (skip == CLIENT_SKIP_CLASS_DIFFER && strcmp(f->client->class_name, n->client->class_name) == 0) || (skip == CLIENT_SKIP_CLASS_EQUAL && strcmp(f->client->class_name, n->client->class_name) != 0)) { focus_node(m, d, f, true); return; } f = (dir == CYCLE_PREV ? prev_leaf(f) : next_leaf(f)); if (f == NULL) f = (dir == CYCLE_PREV ? second_extrema(d->root) : first_extrema(d->root)); } }
bool move_client(coordinates_t *loc, int dx, int dy) { node_t *n = loc->node; if (n == NULL || n->client == NULL) { return false; } monitor_t *pm = NULL; if (IS_TILED(n->client)) { if (!grabbing) { return false; } xcb_window_t pwin = XCB_NONE; query_pointer(&pwin, NULL); if (pwin == n->id) { return false; } coordinates_t dst; bool is_managed = (pwin != XCB_NONE && locate_window(pwin, &dst)); if (is_managed && dst.monitor == loc->monitor && IS_TILED(dst.node->client)) { swap_nodes(loc->monitor, loc->desktop, n, loc->monitor, loc->desktop, dst.node); return true; } else { if (is_managed && dst.monitor == loc->monitor) { return false; } else { xcb_point_t pt = {0, 0}; query_pointer(NULL, &pt); pm = monitor_from_point(pt); } } } else { client_t *c = n->client; xcb_rectangle_t rect = c->floating_rectangle; int16_t x = rect.x + dx; int16_t y = rect.y + dy; if (focus_follows_pointer) { listen_enter_notify(loc->desktop->root, false); } window_move(n->id, x, y); if (focus_follows_pointer) { listen_enter_notify(loc->desktop->root, true); } c->floating_rectangle.x = x; c->floating_rectangle.y = y; 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, rect.width, rect.height, x, y); } pm = monitor_from_client(c); } if (pm == NULL || pm == loc->monitor) { return true; } bool focused = (n == mon->desk->focus); transfer_node(loc->monitor, loc->desktop, n, pm, pm->desk, pm->desk->focus); loc->monitor = pm; loc->desktop = pm->desk; if (focused) { focus_node(pm, pm->desk, n); } return true; }
void grab_pointer(pointer_action_t pac) { PRINTF("grab pointer %u\n", pac); xcb_window_t win = XCB_NONE; xcb_point_t pos; query_pointer(&win, &pos); coordinates_t loc; if (locate_window(win, &loc)) { client_t *c = NULL; frozen_pointer->position = pos; frozen_pointer->action = pac; c = loc.node->client; frozen_pointer->monitor = loc.monitor; frozen_pointer->desktop = loc.desktop; frozen_pointer->node = loc.node; frozen_pointer->client = c; frozen_pointer->window = c->window; frozen_pointer->horizontal_fence = NULL; frozen_pointer->vertical_fence = NULL; switch (pac) { case ACTION_FOCUS: if (loc.node != mon->desk->focus) { bool backup = pointer_follows_monitor; pointer_follows_monitor = false; focus_node(loc.monitor, loc.desktop, loc.node); pointer_follows_monitor = backup; } else if (focus_follows_pointer) { stack(loc.node, STACK_ABOVE); } frozen_pointer->action = ACTION_NONE; break; case ACTION_MOVE: case ACTION_RESIZE_SIDE: case ACTION_RESIZE_CORNER: if (is_tiled(c)) { frozen_pointer->rectangle = c->tiled_rectangle; frozen_pointer->is_tiled = true; } else if (is_floating(c)) { frozen_pointer->rectangle = c->floating_rectangle; frozen_pointer->is_tiled = false; } else { frozen_pointer->action = ACTION_NONE; return; } if (pac == ACTION_RESIZE_SIDE) { float W = frozen_pointer->rectangle.width; float H = frozen_pointer->rectangle.height; float ratio = W / H; float x = pos.x - frozen_pointer->rectangle.x; float y = pos.y - frozen_pointer->rectangle.y; float diag_a = ratio * y; float diag_b = W - diag_a; if (x < diag_a) { if (x < diag_b) frozen_pointer->side = SIDE_LEFT; else frozen_pointer->side = SIDE_BOTTOM; } else { if (x < diag_b) frozen_pointer->side = SIDE_TOP; else frozen_pointer->side = SIDE_RIGHT; } } else if (pac == ACTION_RESIZE_CORNER) { int16_t mid_x = frozen_pointer->rectangle.x + (frozen_pointer->rectangle.width / 2); int16_t mid_y = frozen_pointer->rectangle.y + (frozen_pointer->rectangle.height / 2); if (pos.x > mid_x) { if (pos.y > mid_y) frozen_pointer->corner = CORNER_BOTTOM_RIGHT; else frozen_pointer->corner = CORNER_TOP_RIGHT; } else { if (pos.y > mid_y) frozen_pointer->corner = CORNER_BOTTOM_LEFT; else frozen_pointer->corner = CORNER_TOP_LEFT; } } if (frozen_pointer->is_tiled) { if (pac == ACTION_RESIZE_SIDE) { switch (frozen_pointer->side) { case SIDE_TOP: frozen_pointer->horizontal_fence = find_fence(loc.node, DIR_UP); break; case SIDE_RIGHT: frozen_pointer->vertical_fence = find_fence(loc.node, DIR_RIGHT); break; case SIDE_BOTTOM: frozen_pointer->horizontal_fence = find_fence(loc.node, DIR_DOWN); break; case SIDE_LEFT: frozen_pointer->vertical_fence = find_fence(loc.node, DIR_LEFT); break; } } else if (pac == ACTION_RESIZE_CORNER) { switch (frozen_pointer->corner) { case CORNER_TOP_LEFT: frozen_pointer->horizontal_fence = find_fence(loc.node, DIR_UP); frozen_pointer->vertical_fence = find_fence(loc.node, DIR_LEFT); break; case CORNER_TOP_RIGHT: frozen_pointer->horizontal_fence = find_fence(loc.node, DIR_UP); frozen_pointer->vertical_fence = find_fence(loc.node, DIR_RIGHT); break; case CORNER_BOTTOM_RIGHT: frozen_pointer->horizontal_fence = find_fence(loc.node, DIR_DOWN); frozen_pointer->vertical_fence = find_fence(loc.node, DIR_RIGHT); break; case CORNER_BOTTOM_LEFT: frozen_pointer->horizontal_fence = find_fence(loc.node, DIR_DOWN); frozen_pointer->vertical_fence = find_fence(loc.node, DIR_LEFT); break; } } if (frozen_pointer->horizontal_fence != NULL) frozen_pointer->horizontal_ratio = frozen_pointer->horizontal_fence->split_ratio; if (frozen_pointer->vertical_fence != NULL) frozen_pointer->vertical_ratio = frozen_pointer->vertical_fence->split_ratio; } break; case ACTION_NONE: break; } } else { if (pac == ACTION_FOCUS) { monitor_t *m = monitor_from_point(pos); if (m != NULL && m != mon) focus_node(m, m->desk, m->desk->focus); } frozen_pointer->action = ACTION_NONE; } }
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; } }
void manage_window(xcb_window_t win, rule_consequence_t *csq, int fd) { monitor_t *m = mon; desktop_t *d = mon->desk; node_t *f = mon->desk->focus; parse_rule_consequence(fd, csq); if (!csq->manage) { free(csq->layer); free(csq->state); window_show(win); return; } if (csq->node_desc[0] != '\0') { coordinates_t ref = {m, d, f}; coordinates_t trg = {NULL, NULL, NULL}; if (node_from_desc(csq->node_desc, &ref, &trg)) { m = trg.monitor; d = trg.desktop; f = trg.node; } } else if (csq->desktop_desc[0] != '\0') { coordinates_t ref = {m, d, NULL}; coordinates_t trg = {NULL, NULL, NULL}; if (desktop_from_desc(csq->desktop_desc, &ref, &trg)) { m = trg.monitor; d = trg.desktop; f = trg.desktop->focus; } } else if (csq->monitor_desc[0] != '\0') { coordinates_t ref = {m, NULL, NULL}; coordinates_t trg = {NULL, NULL, NULL}; if (monitor_from_desc(csq->monitor_desc, &ref, &trg)) { m = trg.monitor; d = trg.monitor->desk; f = trg.monitor->desk->focus; } } if (csq->sticky) { m = mon; d = mon->desk; 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_ratio != 0 && f != NULL) { presel_ratio(m, d, f, csq->split_ratio); } node_t *n = make_node(win); client_t *c = make_client(); c->border_width = csq->border ? d->border_width : 0; n->client = c; initialize_client(n); update_floating_rectangle(n); if (c->floating_rectangle.x == 0 && c->floating_rectangle.y == 0) { csq->center = true; } c->min_width = csq->min_width; c->max_width = csq->max_width; c->min_height = csq->min_height; c->max_height = csq->max_height; monitor_t *mm = monitor_from_client(c); embrace_client(mm, c); adapt_geometry(&mm->rectangle, &m->rectangle, n); if (csq->center) { window_center(m, c); } snprintf(c->class_name, sizeof(c->class_name), "%s", csq->class_name); snprintf(c->instance_name, sizeof(c->instance_name), "%s", csq->instance_name); f = insert_node(m, d, n, f); clients_count++; put_status(SBSC_MASK_NODE_MANAGE, "node_manage %s %s 0x%X 0x%X\n", m->name, d->name, win, f!=NULL?f->id:0); if (f != NULL && f->client != NULL && csq->state != NULL && *(csq->state) == STATE_FLOATING) { c->last_layer = c->layer = f->client->layer; } if (csq->layer != NULL) { c->last_layer = c->layer = *(csq->layer); } if (csq->state != NULL) { set_state(m, d, n, *(csq->state)); c->last_state = c->state; } set_locked(m, d, n, csq->locked); set_sticky(m, d, n, csq->sticky); set_private(m, d, n, csq->private); arrange(m, d); bool give_focus = (csq->focus && (d == mon->desk || csq->follow)); if (give_focus) { focus_node(m, d, n); } else if (csq->focus) { activate_node(m, d, n); } else { stack(d, n, false); } uint32_t values[] = {CLIENT_EVENT_MASK | (focus_follows_pointer ? XCB_EVENT_MASK_ENTER_WINDOW : 0)}; xcb_change_window_attributes(dpy, win, XCB_CW_EVENT_MASK, values); if (d == m->desk) { window_show(n->id); } else { window_hide(n->id); } /* the same function is already called in `focus_node` but has no effects on unmapped windows */ if (give_focus) { xcb_set_input_focus(dpy, XCB_INPUT_FOCUS_POINTER_ROOT, win, XCB_CURRENT_TIME); } ewmh_set_wm_desktop(n, d); ewmh_update_client_list(false); free(csq->layer); free(csq->state); }
void grab_pointer(pointer_action_t pac) { xcb_window_t win = XCB_NONE; xcb_point_t pos; query_pointer(&win, &pos); coordinates_t loc; if (locate_window(win, &loc)) { client_t *c = loc.node->client; frozen_pointer->position = pos; frozen_pointer->action = pac; frozen_pointer->monitor = loc.monitor; frozen_pointer->desktop = loc.desktop; frozen_pointer->node = loc.node; frozen_pointer->client = c; frozen_pointer->window = loc.node->id; frozen_pointer->horizontal_fence = NULL; frozen_pointer->vertical_fence = NULL; switch (pac) { case ACTION_FOCUS: if (loc.node != mon->desk->focus) { bool backup = pointer_follows_monitor; pointer_follows_monitor = false; focus_node(loc.monitor, loc.desktop, loc.node); pointer_follows_monitor = backup; } else if (focus_follows_pointer) { stack(loc.desktop, loc.node, true); } frozen_pointer->action = ACTION_NONE; break; case ACTION_MOVE: case ACTION_RESIZE_SIDE: case ACTION_RESIZE_CORNER: if (IS_FLOATING(c)) { frozen_pointer->rectangle = c->floating_rectangle; frozen_pointer->is_tiled = false; } else if (IS_TILED(c)) { frozen_pointer->rectangle = c->tiled_rectangle; frozen_pointer->is_tiled = (pac == ACTION_MOVE || c->state != STATE_PSEUDO_TILED); } else { frozen_pointer->action = ACTION_NONE; return; } if (pac == ACTION_RESIZE_SIDE) { float W = frozen_pointer->rectangle.width; float H = frozen_pointer->rectangle.height; float ratio = W / H; float x = pos.x - frozen_pointer->rectangle.x; float y = pos.y - frozen_pointer->rectangle.y; float diag_a = ratio * y; float diag_b = W - diag_a; if (x < diag_a) { if (x < diag_b) { frozen_pointer->side = SIDE_LEFT; } else { frozen_pointer->side = SIDE_BOTTOM; } } else { if (x < diag_b) { frozen_pointer->side = SIDE_TOP; } else { frozen_pointer->side = SIDE_RIGHT; } } } else if (pac == ACTION_RESIZE_CORNER) { int16_t mid_x = frozen_pointer->rectangle.x + (frozen_pointer->rectangle.width / 2); int16_t mid_y = frozen_pointer->rectangle.y + (frozen_pointer->rectangle.height / 2); if (pos.x > mid_x) { if (pos.y > mid_y) { frozen_pointer->corner = CORNER_BOTTOM_RIGHT; } else { frozen_pointer->corner = CORNER_TOP_RIGHT; } } else { if (pos.y > mid_y) { frozen_pointer->corner = CORNER_BOTTOM_LEFT; } else { frozen_pointer->corner = CORNER_TOP_LEFT; } } } if (frozen_pointer->is_tiled) { if (pac == ACTION_RESIZE_SIDE) { switch (frozen_pointer->side) { case SIDE_TOP: frozen_pointer->horizontal_fence = find_fence(loc.node, DIR_NORTH); break; case SIDE_RIGHT: frozen_pointer->vertical_fence = find_fence(loc.node, DIR_EAST); break; case SIDE_BOTTOM: frozen_pointer->horizontal_fence = find_fence(loc.node, DIR_SOUTH); break; case SIDE_LEFT: frozen_pointer->vertical_fence = find_fence(loc.node, DIR_WEST); break; } } else if (pac == ACTION_RESIZE_CORNER) { switch (frozen_pointer->corner) { case CORNER_TOP_LEFT: frozen_pointer->horizontal_fence = find_fence(loc.node, DIR_NORTH); frozen_pointer->vertical_fence = find_fence(loc.node, DIR_WEST); break; case CORNER_TOP_RIGHT: frozen_pointer->horizontal_fence = find_fence(loc.node, DIR_NORTH); frozen_pointer->vertical_fence = find_fence(loc.node, DIR_EAST); break; case CORNER_BOTTOM_RIGHT: frozen_pointer->horizontal_fence = find_fence(loc.node, DIR_SOUTH); frozen_pointer->vertical_fence = find_fence(loc.node, DIR_EAST); break; case CORNER_BOTTOM_LEFT: frozen_pointer->horizontal_fence = find_fence(loc.node, DIR_SOUTH); frozen_pointer->vertical_fence = find_fence(loc.node, DIR_WEST); break; } } if (frozen_pointer->horizontal_fence != NULL) { frozen_pointer->horizontal_ratio = frozen_pointer->horizontal_fence->split_ratio; } if (frozen_pointer->vertical_fence != NULL) { frozen_pointer->vertical_ratio = frozen_pointer->vertical_fence->split_ratio; } } break; case ACTION_NONE: break; } } else { if (pac == ACTION_FOCUS) { monitor_t *m = monitor_from_point(pos); if (m != NULL && m != mon && (win == XCB_NONE || win == m->root)) { focus_node(m, m->desk, m->desk->focus); } } frozen_pointer->action = ACTION_NONE; } }
bool swap_desktops(monitor_t *m1, desktop_t *d1, monitor_t *m2, desktop_t *d2) { if (d1 == NULL || d2 == NULL || d1 == d2 || (m1->desk == d1 && m1->sticky_count > 0) || (m2->desk == d2 && m2->sticky_count > 0)) { return false; } put_status(SBSC_MASK_DESKTOP_SWAP, "desktop_swap 0x%08X 0x%08X 0x%08X 0x%08X\n", m1->id, d1->id, m2->id, d2->id); bool d1_focused = (m1->desk == d1); bool d2_focused = (m2->desk == d2); if (m1 != m2) { if (m1->desk == d1) { m1->desk = d2; } if (m1->desk_head == d1) { m1->desk_head = d2; } if (m1->desk_tail == d1) { m1->desk_tail = d2; } if (m2->desk == d2) { m2->desk = d1; } if (m2->desk_head == d2) { m2->desk_head = d1; } if (m2->desk_tail == d2) { m2->desk_tail = d1; } } else { if (m1->desk == d1) { m1->desk = d2; } else if (m1->desk == d2) { m1->desk = d1; } if (m1->desk_head == d1) { m1->desk_head = d2; } else if (m1->desk_head == d2) { m1->desk_head = d1; } if (m1->desk_tail == d1) { m1->desk_tail = d2; } else if (m1->desk_tail == d2) { m1->desk_tail = d1; } } desktop_t *p1 = d1->prev; desktop_t *n1 = d1->next; desktop_t *p2 = d2->prev; desktop_t *n2 = d2->next; if (p1 != NULL && p1 != d2) { p1->next = d2; } if (n1 != NULL && n1 != d2) { n1->prev = d2; } if (p2 != NULL && p2 != d1) { p2->next = d1; } if (n2 != NULL && n2 != d1) { n2->prev = d1; } d1->prev = p2 == d1 ? d2 : p2; d1->next = n2 == d1 ? d2 : n2; d2->prev = p1 == d2 ? d1 : p1; d2->next = n1 == d2 ? d1 : n1; if (m1 != m2) { adapt_geometry(&m1->rectangle, &m2->rectangle, d1->root); adapt_geometry(&m2->rectangle, &m1->rectangle, d2->root); history_swap_desktops(m1, d1, m2, d2); arrange(m1, d2); arrange(m2, d1); } if (d1_focused && !d2_focused) { hide_desktop(d1); show_desktop(d2); } else if (!d1_focused && d2_focused) { show_desktop(d1); hide_desktop(d2); } if (d1 == mon->desk) { focus_node(m2, d1, d1->focus); } else if (d1 == m2->desk) { activate_node(m2, d1, d1->focus); } if (d2 == mon->desk) { focus_node(m1, d2, d2->focus); } else if (d2 == m1->desk) { activate_node(m1, d2, d2->focus); } ewmh_update_wm_desktops(); ewmh_update_desktop_names(); ewmh_update_current_desktop(); put_status(SBSC_MASK_REPORT); return true; }
void manage_window(xcb_window_t win, rule_consequence_t *csq, int fd) { monitor_t *m = mon; desktop_t *d = mon->desk; node_t *f = mon->desk->focus; parse_rule_consequence(fd, csq); if (!csq->manage) { free(csq->layer); free(csq->state); window_show(win); return; } if (csq->node_desc[0] != '\0') { coordinates_t ref = {m, d, f}; coordinates_t trg = {NULL, NULL, NULL}; if (node_from_desc(csq->node_desc, &ref, &trg) == SELECTOR_OK) { m = trg.monitor; d = trg.desktop; f = trg.node; } } else if (csq->desktop_desc[0] != '\0') { coordinates_t ref = {m, d, NULL}; coordinates_t trg = {NULL, NULL, NULL}; if (desktop_from_desc(csq->desktop_desc, &ref, &trg) == SELECTOR_OK) { m = trg.monitor; d = trg.desktop; f = trg.desktop->focus; } } else if (csq->monitor_desc[0] != '\0') { coordinates_t ref = {m, NULL, NULL}; coordinates_t trg = {NULL, NULL, NULL}; if (monitor_from_desc(csq->monitor_desc, &ref, &trg) == SELECTOR_OK) { m = trg.monitor; d = trg.monitor->desk; f = trg.monitor->desk->focus; } } if (csq->sticky) { m = mon; d = mon->desk; 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_ratio != 0 && f != NULL) { presel_ratio(m, d, f, csq->split_ratio); } node_t *n = make_node(win); client_t *c = make_client(); c->border_width = csq->border ? d->border_width : 0; n->client = c; initialize_client(n); initialize_floating_rectangle(n); if (c->floating_rectangle.x == 0 && c->floating_rectangle.y == 0) { csq->center = true; } monitor_t *mm = monitor_from_client(c); embrace_client(mm, c); adapt_geometry(&mm->rectangle, &m->rectangle, n); if (csq->center) { window_center(m, c); } snprintf(c->class_name, sizeof(c->class_name), "%s", csq->class_name); snprintf(c->instance_name, sizeof(c->instance_name), "%s", csq->instance_name); f = insert_node(m, d, n, f); clients_count++; put_status(SBSC_MASK_NODE_MANAGE, "node_manage 0x%08X 0x%08X 0x%08X 0x%08X\n", m->id, d->id, win, f!=NULL?f->id:0); if (f != NULL && f->client != NULL && csq->state != NULL && *(csq->state) == STATE_FLOATING) { c->layer = f->client->layer; } if (csq->layer != NULL) { c->layer = *(csq->layer); } if (csq->state != NULL) { set_state(m, d, n, *(csq->state)); } set_hidden(m, d, n, csq->hidden); set_sticky(m, d, n, csq->sticky); set_private(m, d, n, csq->private); set_locked(m, d, n, csq->locked); arrange(m, d); uint32_t values[] = {CLIENT_EVENT_MASK | (focus_follows_pointer ? XCB_EVENT_MASK_ENTER_WINDOW : 0)}; xcb_change_window_attributes(dpy, win, XCB_CW_EVENT_MASK, values); if (d == m->desk) { show_node(d, n); } else { hide_node(d, n); } if (!csq->hidden && csq->focus) { if (d == mon->desk || csq->follow) { focus_node(m, d, n); } else { activate_node(m, d, n); } } else { stack(d, n, false); } ewmh_set_wm_desktop(n, d); ewmh_update_client_list(false); free(csq->layer); free(csq->state); }