#include "wm.h" /* callbacks */ void monitor_change(struct wl_listener *l, void *data) { Monitor *monitor; struct wlr_output_configuration_v1 *config; config = wlr_output_configuration_v1_create(); server.monitor.geometry = *wlr_output_layout_get_box(server.monitor.layout, nil); wl_list_for_each(monitor, &server.monitor.list, link) { struct wlr_output_configuration_head_v1 *head = wlr_output_configuration_head_v1_create(config, monitor->output); monitor->geometry = monitor->window = *wlr_output_layout_get_box(server.monitor.layout, monitor->output); arrange(monitor); head->state.enabled = monitor->output->enabled; head->state.mode = monitor->output->current_mode; head->state.x = monitor->geometry.x; head->state.y = monitor->geometry.y; } wlr_output_manager_v1_set_configuration(server.monitor.manager, config); } static void trylayout(struct wlr_output_configuration_v1 *config, int force) { int ok; struct wlr_output_configuration_head_v1 *head; ok = 1; wl_list_for_each(head, &config->heads, link) { struct wlr_output *output= head->state.output; wlr_output_enable(output, head->state.enabled); if (head->state.enabled) { if (head->state.mode) wlr_output_set_mode(output, head->state.mode); else wlr_output_set_custom_mode( output, head->state.custom_mode.width, head->state.custom_mode.height, head->state.custom_mode.refresh ); wlr_output_layout_move(server.monitor.layout, output, head->state.x, head->state.y); wlr_output_set_transform(output, head->state.transform); } if(!(ok=wlr_output_test(output))) break; } wl_list_for_each(head, &config->heads, link) { if(ok && force) wlr_output_commit(head->state.output); else wlr_output_rollback(head->state.output); } if(ok) wlr_output_configuration_v1_send_succeeded(config); else wlr_output_configuration_v1_send_failed(config); wlr_output_configuration_v1_destroy(config); } void monitor_apply(struct wl_listener *l, void *data) { struct wlr_output_configuration_v1 *config = data; trylayout(config, 1); } void monitor_test(struct wl_listener *l, void *data) { struct wlr_output_configuration_v1 *config = data; trylayout(config, 0); } 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 = output->data = calloc(1, sizeof(*monitor)); monitor->output = output; monitor->tag.set[0] = monitor->tag.set[1] = 1; 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 free_monitor(struct wl_listener *l, void *data) { int i, len; Client *client; 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); for(i=0, len=wl_list_length(&server.monitor.list); i < len; i++) { server.monitor.selected = wl_container_of(server.monitor.list.prev, server.monitor.selected, link); if(server.monitor.selected->output->enabled) break; } focus(focused_client(server.monitor.selected), 1); /* move closed monitor's clients to newly selected one */ wl_list_for_each(client, &server.client.list, link) { if(client->isfloating && client->geometry.x > monitor->geometry.width) resize(client, client->geometry.x - monitor->window.width, client->geometry.y, client->geometry.width, client->geometry.height, 0 ); if(client->monitor == monitor) attach(client, monitor, client->tags); } free(monitor); } /* methods */ void arrange(Monitor *monitor) { if(monitor->layout->arrange) monitor->layout->arrange(monitor); } Client * focused_client(Monitor *monitor) { Client *client; wl_list_for_each(client, &server.client.focus, focus) { if(VISIBLE_ON(client, monitor)) return client; } return nil; } void tile(Monitor *monitor) { Client *client; uint i, n, h, mw, my, ty; n = 0; wl_list_for_each(client, &server.client.list, link) { if(VISIBLE_ON(client, monitor) && !client->isfloating) n++; } if(!n) return; if(n > monitor->master.len) mw = monitor->master.len ? monitor->window.width * monitor->master.frac : 0; else mw = monitor->window.width; i = my = ty = 0; wl_list_for_each(client, &server.client.list, link) { if(!VISIBLE_ON(client,monitor) || client->isfloating || client->isfullscreen) continue; if(i < monitor->master.len) { h = (monitor->window.height - my) / (MIN(n, monitor->master.len) - i); resize(client, monitor->window.x, monitor->window.y + my, mw, h, 0); my += client->geometry.height; } else { h = (monitor->window.height - ty) / (n - i); resize(client, monitor->window.x + mw, monitor->window.y + ty, monitor->window.width - mw, h, 0); ty += client->geometry.height; } i++; } } Monitor * monitor_at(double x, double y) { struct wlr_output *output = wlr_output_layout_output_at(server.monitor.layout, x, y); return output ? output->data : nil; }