Handle destruction of outputs
This commit is contained in:
parent
414a076410
commit
0976243372
@ -35,6 +35,8 @@ pub const Output = struct {
|
|||||||
/// Percentage of the total screen that the master section takes up.
|
/// Percentage of the total screen that the master section takes up.
|
||||||
master_factor: f64,
|
master_factor: f64,
|
||||||
|
|
||||||
|
// All listeners for this output, in alphabetical order
|
||||||
|
listen_destroy: c.wl_listener,
|
||||||
listen_frame: c.wl_listener,
|
listen_frame: c.wl_listener,
|
||||||
listen_mode: c.wl_listener,
|
listen_mode: c.wl_listener,
|
||||||
|
|
||||||
@ -81,6 +83,9 @@ pub const Output = struct {
|
|||||||
self.master_factor = 0.6;
|
self.master_factor = 0.6;
|
||||||
|
|
||||||
// Set up listeners
|
// Set up listeners
|
||||||
|
self.listen_destroy.notify = handleDestroy;
|
||||||
|
c.wl_signal_add(&wlr_output.events.destroy, &self.listen_destroy);
|
||||||
|
|
||||||
self.listen_frame.notify = handleFrame;
|
self.listen_frame.notify = handleFrame;
|
||||||
c.wl_signal_add(&wlr_output.events.frame, &self.listen_frame);
|
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 {
|
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,
|
// This function is called every time an output is ready to display a frame,
|
||||||
// generally at the output's refresh rate (e.g. 60Hz).
|
// generally at the output's refresh rate (e.g. 60Hz).
|
||||||
|
Loading…
Reference in New Issue
Block a user