aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorIsaac Freund <ifreund@ifreund.xyz>2020-04-16 20:54:57 +0200
committerIsaac Freund <ifreund@ifreund.xyz>2020-04-17 13:02:18 +0200
commit09762433722c168dfe999c85840b27fd454caf28 (patch)
tree55253a6cb0ada02901645264c1c6949a8376e90c /src
parent414a0764107377fe5e925ebc1f01d563fe7ca977 (diff)
downloadriver-09762433722c168dfe999c85840b27fd454caf28.tar.gz
river-09762433722c168dfe999c85840b27fd454caf28.tar.xz
Handle destruction of outputs
Diffstat (limited to 'src')
-rw-r--r--src/output.zig54
1 files changed, 54 insertions, 0 deletions
diff --git a/src/output.zig b/src/output.zig
index 81fbfbe..5751421 100644
--- a/src/output.zig
+++ b/src/output.zig
@@ -35,6 +35,8 @@ pub const Output = struct {
/// Percentage of the total screen that the master section takes up.
master_factor: f64,
+ // All listeners for this output, in alphabetical order
+ listen_destroy: c.wl_listener,
listen_frame: c.wl_listener,
listen_mode: c.wl_listener,
@@ -81,6 +83,9 @@ pub const Output = struct {
self.master_factor = 0.6;
// Set up listeners
+ self.listen_destroy.notify = handleDestroy;
+ c.wl_signal_add(&wlr_output.events.destroy, &self.listen_destroy);
+
self.listen_frame.notify = handleFrame;
c.wl_signal_add(&wlr_output.events.frame, &self.listen_frame);
@@ -368,6 +373,55 @@ pub const Output = struct {
}
}
+ /// Called when the output is destroyed. Evacuate all views from the output
+ /// and then remove it from the list of outputs.
+ fn handleDestroy(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void {
+ const destroyed_output = @fieldParentPtr(Output, "listen_destroy", listener.?);
+ const root = destroyed_output.root;
+
+ // Use the first output in the list that is not the one being destroyed.
+ // If there is no other real output, use the noop output.
+ var output_it = root.outputs.first;
+ const fallback_output = while (output_it) |output_node| : (output_it = output_node.next) {
+ if (&output_node.data != destroyed_output) {
+ break &output_node.data;
+ }
+ } else &root.noop_output;
+
+ // Move all views from the destroyed output to the fallback one
+ while (destroyed_output.views.last) |node| {
+ destroyed_output.views.remove(node);
+ fallback_output.views.push(node);
+ node.view.output = fallback_output;
+ }
+
+ // If any seat has the destroyed output focused, focus the fallback one
+ var seat_it = root.server.input_manager.seats.first;
+ while (seat_it) |seat_node| : (seat_it = seat_node.next) {
+ const seat = &seat_node.data;
+ if (seat.focused_output == destroyed_output) {
+ seat.focused_output = fallback_output;
+ seat.focus(null);
+ }
+ }
+
+ // Remove all listeners
+ c.wl_list_remove(&destroyed_output.listen_destroy.link);
+ c.wl_list_remove(&destroyed_output.listen_frame.link);
+ c.wl_list_remove(&destroyed_output.listen_mode.link);
+
+ // Clean up the wlr_output
+ destroyed_output.wlr_output.data = null;
+
+ // Remove the destroyed output from the list
+ const node = @fieldParentPtr(std.TailQueue(Output).Node, "data", destroyed_output);
+ root.outputs.remove(node);
+ root.server.allocator.destroy(node);
+
+ // Arrange the root in case evacuated views affect the layout
+ root.arrange();
+ }
+
fn handleFrame(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void {
// This function is called every time an output is ready to display a frame,
// generally at the output's refresh rate (e.g. 60Hz).