#include "wm.h" static char broken[] = "broken"; // ----------------------------------------------------------------------- // scripts static inline void grab_client(void) { if(server.cursor.mode != CursorNormal) return; if(!(server.grab.client = client_at(server.cursor.dot->x, server.cursor.dot->y))) return; floating(server.grab.client, 1); } void move_client(Arg *arg) { grab_client(); server.cursor.mode = CursorMove; server.grab.x = server.cursor.dot->x - server.grab.client->geometry.x; server.grab.y = server.cursor.dot->y - server.grab.client->geometry.y; wlr_xcursor_manager_set_cursor_image(server.cursor.manager, "fleur", server.cursor.dot); } void float_client(Arg *arg) { Client *client = selected_client(); wlr_log(WLR_DEBUG, "client selected = %lx", (uintptr)client); if(!client) return; floating(client, client->isfloating ? 0 : 1); } void resize_client(Arg *arg) { double x, y; struct wlr_box geometry; grab_client(); server.cursor.mode = CursorResize; wlr_xdg_surface_get_geometry(server.grab.client->xdg, &geometry); x = server.grab.client->geometry.x + geometry.x + geometry.width; y = server.grab.client->geometry.y + geometry.y + geometry.height; server.grab.x = server.cursor.dot->x - x; server.grab.y = server.cursor.dot->y - y; server.grab.box = geometry; server.grab.box.x += server.grab.client->geometry.x; server.grab.box.y += server.grab.client->geometry.y; } // ----------------------------------------------------------------------- // core static inline void activate(struct wlr_surface *surface, int state) { } void focus(Client *client, int lift) { struct wlr_xdg_surface *xdg; struct wlr_surface *old, *new; struct wlr_keyboard *keyboard; if(!client) { wlr_seat_keyboard_notify_clear_focus(server.input.seat); return; } old = server.input.seat->keyboard_state.focused_surface; if(lift) { wl_list_remove(&client->stack); wl_list_insert(&server.client.stack, &client->stack); } new = client->xdg->surface; if(old==new) return; wl_list_remove(&client->focus); wl_list_insert(&server.client.focus, &client->focus); server.monitor.selected = client->monitor; client->isurgent = 0; if(old) { if(wlr_surface_is_xdg_surface(old)) { xdg = wlr_xdg_surface_from_wlr_surface(old); wlr_xdg_toplevel_set_activated(xdg, false); } } keyboard = wlr_seat_get_keyboard(server.input.seat); wlr_seat_keyboard_notify_enter(server.input.seat, new, keyboard->keycodes, keyboard->num_keycodes, &keyboard->modifiers ); wlr_xdg_toplevel_set_activated(client->xdg, true); } Client* client_at(double x, double y) { Client *client; wl_list_for_each(client, &server.client.stack, stack) if(VISIBLE_ON(client, client->monitor) && wlr_box_contains_point(&client->geometry, x, y)) return client; return nil; } static int has(Client *client, double lx, double ly, struct wlr_surface **surface, double *sx, double *sy) { double x, y, vsx = lx - client->geometry.x, vsy = ly - client->geometry.y; struct wlr_surface *find = nil; find = wlr_xdg_surface_surface_at(client->xdg, vsx, vsy, &x, &y); if(find) { *sx = x; *sy = y; *surface = find; return true; } return false; } struct wlr_surface * client_surface_at(Client *client, double cx, double cy, double *sx, double *sy) { return wlr_xdg_surface_surface_at(client->xdg, cx, cy, sx, sy); } static void constrain(Client *client, struct wlr_box *box) { client->geometry.width = MAX(1, client->geometry.width); client->geometry.height = MAX(1, client->geometry.height); if(client->geometry.x >= box->x + box->width) client->geometry.x = box->x + box->width - client->geometry.width; if(client->geometry.y >= box->y + box->height) client->geometry.y = box->y + box->height - client->geometry.height; if(client->geometry.x + client->geometry.width + 2*client->border <= box->x) client->geometry.x = box->x; if(client->geometry.y + client->geometry.height + 2*client->border <= box->y) client->geometry.y = box->y; } void resize(Client *client, int x, int y, int w, int h, int interact) { struct wlr_box *box = interact ? &server.monitor.geometry : &client->monitor->window; client->geometry.x = x; client->geometry.y = y; client->geometry.width = w; client->geometry.height = h; constrain(client, box); client->resize = wlr_xdg_toplevel_set_size(client->xdg, client->geometry.width - 2*client->border, client->geometry.height - 2*client->border ); } void attach(Client *client, Monitor *monitor, uint tags) { Monitor *old = client->monitor; if(old == monitor) return; client->monitor = monitor; if(old) { wlr_surface_send_leave(client->xdg->surface, old->output); arrange(old); } if(monitor) { /* make sure window actually overlaps with the monitor */ constrain(client, &monitor->geometry); wlr_surface_send_enter(client->xdg->surface, monitor->output); client->tags = tags ? tags : monitor->tag.set[monitor->tag.selected]; arrange(monitor); } focus(focused_client(server.monitor.selected), 1); } void rules(Client *client) { /* rule matching */ Rule *rule; uint i, tags; char *id, *title; Monitor *monitor, *it; monitor = server.monitor.selected; if (!(id=client->xdg->toplevel->app_id)) id = broken; if (!(title=client->xdg->toplevel->title)) title = broken; for(tags=0, rule=cfg·rule; rule != cfg·endrule; ++rule) { if ((!rule->title || strstr(title, rule->title)) && (!rule->id || strstr(id, rule->id))) { client->isfloating = rule->isfloating; tags |= rule->tags; i = 0; wl_list_for_each(it, &server.monitor.list, link) if(rule->monitor == i++) monitor = it; } } attach(client, monitor, tags); } void floating(Client *client, int state) { wlr_log(WLR_DEBUG, "client %lx, floating = %d", (uintptr)client, state); client->isfloating = state; arrange(client->monitor); } Client * selected_client(void) { Client *client = wl_container_of(server.client.focus.next, client, focus); if(wl_list_empty(&server.client.focus) || !VISIBLE_ON(client, server.monitor.selected)) return nil; return client; } void request_activate(struct wl_listener *l, void *data) { struct wlr_xdg_activation_v1_request_activate_event *event = data; Client *client; if (!wlr_surface_is_xdg_surface(event->surface)) return; client = wlr_xdg_surface_from_wlr_surface(event->surface)->data; if(client != selected_client()) client->isurgent = 1; }