aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--river/Output.zig59
-rw-r--r--river/Root.zig53
2 files changed, 63 insertions, 49 deletions
diff --git a/river/Output.zig b/river/Output.zig
index e65d4d0..155ce62 100644
--- a/river/Output.zig
+++ b/river/Output.zig
@@ -72,6 +72,10 @@ attach_mode: AttachMode = .top,
/// List of status tracking objects relaying changes to this output to clients.
status_trackers: std.SinglyLinkedList(OutputStatus) = .{},
+/// Whether or not the output is active
+/// An active output can have focus (e.g. an output turned off by dpms is active)
+active: bool = false,
+
// All listeners for this output, in alphabetical order
listen_destroy: c.wl_listener = undefined,
listen_frame: c.wl_listener = undefined,
@@ -503,45 +507,10 @@ fn handleDestroy(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void {
const root = self.root;
log.debug(.server, "output '{}' destroyed", .{self.wlr_output.name});
-
- // 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 != self) {
- break &output_node.data;
- }
- } else &root.noop_output;
-
- // Move all views from the destroyed output to the fallback one
- while (self.views.last) |node| {
- const view = &node.view;
- view.sendToOutput(fallback_output);
- }
-
- // Close all layer surfaces on the destroyed output
- for (self.layers) |*layer, layer_idx| {
- while (layer.pop()) |node| {
- const layer_surface = &node.data;
- // We need to move the closing layer surface to the noop output
- // since it may not be immediately destoryed. This just a request
- // to close which will trigger unmap and destroy events in
- // response, and the LayerSurface needs a valid output to
- // handle them.
- root.noop_output.layers[layer_idx].prepend(node);
- layer_surface.output = &root.noop_output;
- c.wlr_layer_surface_v1_close(layer_surface.wlr_layer_surface);
- }
- }
-
- // 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 == self) {
- seat.focusOutput(fallback_output);
- seat.focus(null);
- }
+ // Remove the destroyed output from root if it wasn't already removed
+ const node = @fieldParentPtr(std.TailQueue(Self).Node, "data", self);
+ if (self.active) {
+ root.removeOutput(node);
}
// Remove all listeners
@@ -549,20 +518,12 @@ fn handleDestroy(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void {
c.wl_list_remove(&self.listen_frame.link);
c.wl_list_remove(&self.listen_mode.link);
- // Clean up the wlr_output
- self.wlr_output.data = null;
-
// Free the layout command
util.gpa.free(self.layout);
- // Remove the destroyed output from the list
- const node = @fieldParentPtr(std.TailQueue(Self).Node, "data", self);
- root.outputs.remove(node);
+ // Clean up the wlr_output
+ self.wlr_output.data = null;
util.gpa.destroy(node);
-
- // Arrange the root in case evacuated views affect the layout
- fallback_output.arrangeViews();
- root.startTransaction();
}
fn handleFrame(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void {
diff --git a/river/Root.zig b/river/Root.zig
index 0c6f6e8..b707143 100644
--- a/river/Root.zig
+++ b/river/Root.zig
@@ -35,6 +35,11 @@ const DragIcon = @import("DragIcon.zig");
server: *Server,
wlr_output_layout: *c.wlr_output_layout,
+
+/// A list of all outputs
+all_outputs: std.TailQueue(*Output) = .{},
+
+/// A list of all active outputs. See Output.active
outputs: std.TailQueue(Output) = .{},
/// This output is used internally when no real outputs are available.
@@ -91,10 +96,58 @@ pub fn deinit(self: *Self) void {
if (c.wl_event_source_remove(self.transaction_timer) < 0) unreachable;
}
+/// Removes the output in node.data from self.outputs
+/// The node is not freed
+pub fn removeOutput(self: *Self, node: *std.TailQueue(Output).Node) void {
+ const output = &node.data;
+ self.outputs.remove(node);
+ output.active = false;
+
+ // Use the first output in the list as fallback.
+ // If there is no other real output, use the noop output.
+ const fallback_output = if (self.outputs.first) |output_node| &output_node.data else &self.noop_output;
+
+ // Move all views from the destroyed output to the fallback one
+ while (output.views.last) |view_node| {
+ const view = &view_node.view;
+ view.sendToOutput(fallback_output);
+ }
+
+ // Close all layer surfaces on the removed output
+ for (output.layers) |*layer, layer_idx| {
+ while (layer.pop()) |layer_node| {
+ const layer_surface = &layer_node.data;
+ // We need to move the closing layer surface to the noop output
+ // since it may not be immediately destoryed. This just a request
+ // to close which will trigger unmap and destroy events in
+ // response, and the LayerSurface needs a valid output to
+ // handle them.
+ self.noop_output.layers[layer_idx].prepend(layer_node);
+ layer_surface.output = &self.noop_output;
+ c.wlr_layer_surface_v1_close(layer_surface.wlr_layer_surface);
+ }
+ }
+
+ // If any seat has the removed output focused, focus the fallback one
+ var seat_it = self.server.input_manager.seats.first;
+ while (seat_it) |seat_node| : (seat_it = seat_node.next) {
+ const seat = &seat_node.data;
+ if (seat.focused_output == output) {
+ seat.focusOutput(fallback_output);
+ seat.focus(null);
+ }
+ }
+
+ // Arrange the root in case evacuated views affect the layout
+ fallback_output.arrangeViews();
+ self.startTransaction();
+}
+
/// Adds the output in node.data to self.outputs
/// The Output in node.data must be initalized
pub fn addOutput(self: *Self, node: *std.TailQueue(Output).Node) void {
self.outputs.append(node);
+ node.data.active = true;
// Add the new output to the layout. The add_auto function arranges outputs
// from left-to-right in the order they appear. A more sophisticated