#include "dwm.h" /* local callbacks */ static void delete(struct wl_listener *ev, void *arg); static void draw(struct wl_listener *ev, void *arg); /* global variables */ Monitor *monitor = nil; // ----------------------------------------------------------------------- // methods void damageat(Monitor* m, double x, double y) { /* TODO: don't damage the whole screen */ wlr_output_damage_add_whole(&m->damage); } void arrange(Monitor *m) { m->area.all = *wlr_output_layout_get_box(dwm.layout, m->dev); m->area.win = m->area.all; if (m->lt[m->sellt]->arrange) m->lt[m->sellt]->arrange(m); } void setmonitor(Client *c, Monitor *m, uint newtags) { int hadfocus; Monitor *old; old = c->m; if (old == m) return; hadfocus = (c == getclient()); c->m = m; if (old) { wlr_surface_send_leave(c->surf->surface, old->dev); arrange(old); } if (m) { applybounds(c, &m->area.all); wlr_surface_send_enter(c->surf->surface, m->dev); c->tags = newtags ? newtags : m->tagset[m->seltags]; arrange(m); } if (hadfocus || (c == getclient())) setfocus(lastfocus(), nil, 1); } Monitor* getmonitor(int dir) { Monitor *m; if (dir > 0) { if (monitor->link.next == &dwm.odevs) return wl_container_of(dwm.odevs.next, m, link); return wl_container_of(monitor->link.next, m, link); } if (monitor->link.prev == &dwm.odevs) return wl_container_of(dwm.odevs.prev, m, link); return wl_container_of(monitor->link.prev, m, link); } Monitor * monitorat(double x, double y) { struct wlr_output *dev; dev = wlr_output_layout_output_at(dwm.layout, x, y); return dev ? dev->data : nil; } // ----------------------------------------------------------------------- // callback function implementations void ev·newmonitor(struct wl_listener *ev, void *arg) { Monitor *m; const MonitorRule *r; struct wlr_output *dev; struct wlr_output_mode *mode; dev = arg; wlr_output_set_mode(dev, wlr_output_preferred_mode(dev)); m = dev->data = calloc(1, sizeof(*m)); m->dev = dev; m->tagset[0] = m->tagset[1] = 1; /* look for rules to apply */ for (r = monitorrules; r < arrend(monitorrules); r++) { if (!r->name || strstr(dev->name, r->name)) { m->mfact = r->mfact; m->nmaster = r->nmaster; wlr_output_set_scale(dev, r->scale); wlr_xcursor_manager_load(mouse.manager, r->scale); m->lt[0] = m->lt[1] = r->lt; wlr_output_set_transform(dev, r->rr); break; } } /* install callbacks */ m->ev.draw.notify = draw; m->ev.free.notify = delete; wl_signal_add(&dev->events.frame, &m->ev.draw); wl_signal_add(&dev->events.destroy, &m->ev.free); wl_list_insert(&dwm.odevs, &m->link); wl_list_init(&m->layers[0]); wl_list_init(&m->layers[1]); wl_list_init(&m->layers[2]); wl_list_init(&m->layers[3]); wlr_output_enable(dev, 1); if (!wlr_output_commit(dev)) return; wl_signal_init(&m->sig.kill); wlr_output_layout_add_auto(dwm.layout, dev); dwm.dim = *wlr_output_layout_get_box(dwm.layout, nil); } static void delete(struct wl_listener *ev, void *arg) { Monitor *m; m = wl_container_of(ev, m, ev.free); wl_signal_emit(&m->sig.kill, m); wl_list_remove(&m->link); wl_list_remove(&m->ev.draw.link); wl_list_remove(&m->ev.free.link); free(m); } static void render(struct wlr_surface *surf, int sx, int sy, void *arg) { Payload *data; double x, y; float mtx[9]; struct wlr_box box; struct wlr_output *dev; struct wlr_texture *tex; enum wl_output_transform transform; data = arg; dev = data->dev; tex = wlr_surface_get_texture(surf); if (!tex) return; /* convert to device local coord */ wlr_output_layout_output_coords(dwm.layout, dev, &x, &y); box.x = x + data->x + sx; box.y = y + data->y + sy; box.width = surf->current.width; box.height = surf->current.height; scale(&box, dev->scale); /* orthographic projection */ transform = wlr_output_transform_invert(surf->current.transform); wlr_matrix_project_box(mtx, &box, transform, 0, dev->transform_matrix); /* render with GPU */ wlr_render_texture_with_matrix(dwm.draw, tex, mtx, 1); /* notify the client we are done */ wlr_surface_send_frame_done(surf, data->now); } static void renderclients(Monitor *m, struct timespec *now) { Client *c; double x, y; int i, w, h; Payload data; struct wlr_box *borders; wl_list_for_each_reverse(c, &dwm.stack, link.stack) { if (!VISIBLEON(c, c->m) || !wlr_output_layout_intersects(dwm.layout, m->dev, &c->dim)) continue; x = c->dim.x; y = c->dim.y; wlr_output_layout_output_coords(dwm.layout, m->dev, &x, &y); w = c->surf->surface->current.width; h = c->surf->surface->current.height; borders = (struct wlr_box[4]) { {x, y, w + 2 * c->bw, c->bw}, /* top */ {x, y + c->bw, c->bw, h}, /* left */ {x + c->bw + w, y + c->bw, c->bw, h}, /* right */ {x, y + c->bw + h, w + 2 * c->bw, c->bw}, /* bottom */ }; for (i = 0; i < 4; i++) { scale(&borders[i], m->dev->scale); wlr_render_rect(dwm.draw, &borders[i], bordercolor, m->dev->transform_matrix); } data.dev = m->dev; data.now = now; data.x = c->dim.x + c->bw; data.y = c->dim.y + c->bw; wlr_xdg_surface_for_each_surface(c->surf, render, &data); } } static void draw(struct wl_listener *ev, void *arg) { int w, h; Monitor *m; struct timespec now; m = wl_container_of(ev, m, ev.draw); if (!wlr_output_attach_render(m->dev, nil)) return; clock_gettime(CLOCK_MONOTONIC, &now); wlr_output_effective_resolution(m->dev, &w, &h); wlr_renderer_begin(dwm.draw, w, h); wlr_renderer_clear(dwm.draw, rootcolor); renderclients(m, &now); wlr_output_render_software_cursors(m->dev, nil); wlr_renderer_end(dwm.draw); wlr_output_commit(m->dev); }