aboutsummaryrefslogtreecommitdiff
path: root/sys/cmd/dwm/output.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/cmd/dwm/output.c')
-rw-r--r--sys/cmd/dwm/output.c257
1 files changed, 257 insertions, 0 deletions
diff --git a/sys/cmd/dwm/output.c b/sys/cmd/dwm/output.c
new file mode 100644
index 0000000..918d9a6
--- /dev/null
+++ b/sys/cmd/dwm/output.c
@@ -0,0 +1,257 @@
+#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);
+}