aboutsummaryrefslogtreecommitdiff
path: root/sys/cmd/wm/monitor.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/cmd/wm/monitor.c')
-rw-r--r--sys/cmd/wm/monitor.c199
1 files changed, 197 insertions, 2 deletions
diff --git a/sys/cmd/wm/monitor.c b/sys/cmd/wm/monitor.c
index 7fa4d57..9287bfc 100644
--- a/sys/cmd/wm/monitor.c
+++ b/sys/cmd/wm/monitor.c
@@ -1,5 +1,194 @@
#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)
{
@@ -27,9 +216,8 @@ tile(Monitor *monitor)
n = 0;
wl_list_for_each(client, &server.client.list, link) {
- if(VISIBLE_ON(client, monitor) && !client->isfloating) {
+ if(VISIBLE_ON(client, monitor) && !client->isfloating)
n++;
- }
}
if(!n) return;
@@ -54,3 +242,10 @@ tile(Monitor *monitor)
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;
+}