#include "wm.h" struct Payload { Client *client; struct wlr_output *output; struct timespec *when; int x, y; }; static void render(struct wlr_surface *surface, int sx, int sy, void *data) { float matrix[9]; double x, y; Client *client; struct Payload *payload; struct wlr_box box; struct wlr_output *output; struct wlr_texture *texture; enum wl_output_transform transform; payload = data; client = payload->client; output = payload->output; texture = wlr_surface_get_texture(surface); if(!texture) return; x = 0, y = 0; wlr_output_layout_output_coords(server.monitor.layout, output, &x, &y); box = (struct wlr_box) { .x = x + payload->x + sx, .y = y + payload->y + sy, .width = surface->current.width, .height = surface->current.height, }; scale_box(&box, output->scale); transform = wlr_output_transform_invert(surface->current.transform); wlr_matrix_project_box(matrix, &box, transform, 0, output->transform_matrix); wlr_render_texture_with_matrix(server.renderer, texture, matrix, 1); wlr_surface_send_frame_done(surface, payload->when); wlr_presentation_surface_sampled_on_output(server.present, surface, output); } static void render_clients(Monitor *monitor, struct timespec *now) { double x, y; int i, w, h, bw; float *color; Client *client; struct wlr_output *output; struct wlr_box *borders; struct wlr_surface *surface; output = monitor->output; wl_list_for_each_reverse(client, &server.client.stack, stack) { if(!client->ismapped) continue; surface = client->xdg->surface; x = client->geometry.x, y = client->geometry.y; wlr_output_layout_output_coords(server.monitor.layout, output, &x, &y); if((bw=client->border)) { w = surface->current.width; h = surface->current.height; borders = (struct wlr_box[4]) { {x, y, w+2*bw, bw}, /* top */ {x, y+bw, bw, h}, /* left */ {x+bw+w, y+bw, bw, h}, /* right */ {x, y+bw+h, w+2*bw, bw}, /* bottom */ }; color = (client == server.selected) ? cfg·focuscolor : cfg·bordercolor; for(i=0; i<4; i++) { scale_box(&borders[i], output->scale); wlr_render_rect(server.renderer, &borders[i], color, output->transform_matrix); } } struct Payload payload = { .output = output, .client = client, .when = now, .x = client->geometry.x + client->border, .y = client->geometry.y + client->border, }; wlr_xdg_surface_for_each_surface(client->xdg, render, &payload); } } static void render_monitor(struct wl_listener *l, void *data) { int w, h; Client *client; Monitor *monitor; struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); monitor = wl_container_of(l, monitor, event.render); wl_list_for_each(client, &server.client.list, link) { if(client->resize) { wlr_surface_send_frame_done(client->xdg->surface, &now); } } if(!wlr_output_attach_render(monitor->output, nil)) return; wlr_output_effective_resolution(monitor->output, &w, &h); /* start of rendering kernel */ wlr_renderer_begin(server.renderer, w, h); wlr_renderer_clear(server.renderer, cfg·rootcolor); render_clients(monitor, &now); wlr_output_render_software_cursors(monitor->output, nil); wlr_renderer_end(server.renderer); wlr_output_commit(monitor->output); } static void free_monitor(struct wl_listener *l, void *data) { /* int len, i = 0; struct wlr_output *output = data; Monitor *monitor = output->data; wl_list_remove(&monitor->event.destroy.link); wl_list_remove(&monitor->event.render.link); wl_list_remove(&monitor->link); wlr_output_layout_remove(server.monitor.layout, monitor->output); len = wl_list_length(&server.monitor.list); */ /* do // don't switch to disabled mons selmon = wl_container_of(mons.prev, selmon, link); while (!selmon->wlr_output->enabled && i++ < nmons); focusclient(focustop(selmon), 1); closemon(m); free(monitor); */ } void make_monitor(struct wl_listener *l, void *data) { Client *client; Monitor *monitor; MonitorRule *rule; struct wlr_output_mode *mode; struct wlr_output *output = data; /* * XXX: needed? if (wl_list_empty(&output->modes)) return; */ monitor = calloc(1, sizeof(*monitor)); monitor->output = output; for(rule=cfg·monitorrule; rule != cfg·endmonitorrule; ++rule) { if(!rule->name || strstr(output->name, rule->name)) { monitor->master.len = rule->master.len; monitor->master.frac = rule->master.frac; wlr_output_set_scale(output, rule->scale); wlr_xcursor_manager_load(server.cursor.manager, rule->scale); monitor->layouts[0] = monitor->layouts[1] = monitor->layout = rule->layout; wlr_output_set_transform(output, rule->transform); break; } } mode = wlr_output_preferred_mode(output); wlr_output_set_mode(output, mode); wlr_output_enable_adaptive_sync(output, true); monitor->event.render.notify = render_monitor; wl_signal_add(&output->events.frame, &monitor->event.render); monitor->event.destroy.notify = free_monitor; wl_signal_add(&output->events.destroy, &monitor->event.destroy); wlr_output_enable(output, true); if (!wlr_output_commit(output)) return; wl_list_insert(&server.monitor.list, &monitor->link); wlr_output_layout_add(server.monitor.layout, output, rule->x, rule->y); server.monitor.geometry = *wlr_output_layout_get_box(server.monitor.layout, nil); /* update the geometries of all monitors */ wl_list_for_each(monitor, &server.monitor.list, link) { /* first monitor in the list = most recently added */ wl_list_for_each(client, &server.client.list, link) { if(client->isfloating) resize(client, client->geometry.x+monitor->window.width, client->geometry.y, client->geometry.width, client->geometry.height, 0); } return; } } void layout_change(struct wl_listener *l, void *data) { }