diff --git a/deps/zig-wlroots b/deps/zig-wlroots index 5581b95..96dfdc1 160000 --- a/deps/zig-wlroots +++ b/deps/zig-wlroots @@ -1 +1 @@ -Subproject commit 5581b9522eb2b3d2fca8e02a581932f6b9eb4876 +Subproject commit 96dfdc14e99468f4aa6560c8397cd4d0eb0c2827 diff --git a/river/Output.zig b/river/Output.zig index a51201e..3b083c6 100644 --- a/river/Output.zig +++ b/river/Output.zig @@ -101,6 +101,10 @@ lock_render_state: enum { lock_surface, } = .blanked, +/// Set to true if a gamma control client makes a set gamma request. +/// This request is handled while rendering the next frame in handleFrame(). +gamma_dirty: bool = false, + /// The state of the output that is directly acted upon/modified through user input. /// /// Pending state will be copied to the inflight state and communicated to clients @@ -476,45 +480,71 @@ fn handleFrame(listener: *wl.Listener(*wlr.Output), _: *wlr.Output) void { const output = @fieldParentPtr(Self, "frame", listener); const scene_output = server.root.scene.getSceneOutput(output.wlr_output).?; - if (scene_output.commit(null)) { - if (server.lock_manager.state == .locked or - (server.lock_manager.state == .waiting_for_lock_surfaces and output.locked_content.node.enabled) or - server.lock_manager.state == .waiting_for_blank) - { - assert(!output.normal_content.node.enabled); - assert(output.locked_content.node.enabled); - - switch (server.lock_manager.state) { - .unlocked => unreachable, - .locked => switch (output.lock_render_state) { - .pending_unlock, .unlocked, .pending_blank, .pending_lock_surface => unreachable, - .blanked, .lock_surface => {}, - }, - .waiting_for_blank => { - if (output.lock_render_state != .blanked) { - output.lock_render_state = .pending_blank; - } - }, - .waiting_for_lock_surfaces => { - if (output.lock_render_state != .lock_surface) { - output.lock_render_state = .pending_lock_surface; - } - }, - } - } else { - if (output.lock_render_state != .unlocked) { - output.lock_render_state = .pending_unlock; - } - } - } else { - log.err("output commit failed for {s}", .{output.wlr_output.name}); - } + // TODO this should probably be retried on failure + output.renderAndCommit(scene_output) catch |err| switch (err) { + error.OutOfMemory => log.err("out of memory", .{}), + error.CommitFailed => log.err("output commit failed for {s}", .{output.wlr_output.name}), + }; var now: std.os.timespec = undefined; std.os.clock_gettime(std.os.CLOCK.MONOTONIC, &now) catch @panic("CLOCK_MONOTONIC not supported"); scene_output.sendFrameDone(&now); } +fn renderAndCommit(output: *Self, scene_output: *wlr.SceneOutput) !void { + if (output.gamma_dirty) { + var state = wlr.Output.State.init(); + defer state.finish(); + + if (server.root.gamma_control_manager.getControl(output.wlr_output)) |control| { + log.info("applying gamma settings from client", .{}); + if (!control.apply(&state)) return error.OutOfMemory; + } else { + log.info("clearing gamma settings from client", .{}); + state.clearGammaLut(); + } + + if (!scene_output.buildState(&state, null)) return error.CommitFailed; + + if (!output.wlr_output.commitState(&state)) return error.CommitFailed; + + scene_output.damage_ring.rotate(); + output.gamma_dirty = false; + } else { + if (!scene_output.commit(null)) return error.CommitFailed; + } + + if (server.lock_manager.state == .locked or + (server.lock_manager.state == .waiting_for_lock_surfaces and output.locked_content.node.enabled) or + server.lock_manager.state == .waiting_for_blank) + { + assert(!output.normal_content.node.enabled); + assert(output.locked_content.node.enabled); + + switch (server.lock_manager.state) { + .unlocked => unreachable, + .locked => switch (output.lock_render_state) { + .pending_unlock, .unlocked, .pending_blank, .pending_lock_surface => unreachable, + .blanked, .lock_surface => {}, + }, + .waiting_for_blank => { + if (output.lock_render_state != .blanked) { + output.lock_render_state = .pending_blank; + } + }, + .waiting_for_lock_surfaces => { + if (output.lock_render_state != .lock_surface) { + output.lock_render_state = .pending_lock_surface; + } + }, + } + } else { + if (output.lock_render_state != .unlocked) { + output.lock_render_state = .pending_unlock; + } + } +} + fn handlePresent( listener: *wl.Listener(*wlr.Output.event.Present), event: *wlr.Output.event.Present, diff --git a/river/Root.zig b/river/Root.zig index aa3b4df..71cc1ef 100644 --- a/river/Root.zig +++ b/river/Root.zig @@ -102,6 +102,10 @@ power_manager: *wlr.OutputPowerManagerV1, power_manager_set_mode: wl.Listener(*wlr.OutputPowerManagerV1.event.SetMode) = wl.Listener(*wlr.OutputPowerManagerV1.event.SetMode).init(handlePowerManagerSetMode), +gamma_control_manager: *wlr.GammaControlManagerV1, +gamma_control_set_gamma: wl.Listener(*wlr.GammaControlManagerV1.event.SetGamma) = + wl.Listener(*wlr.GammaControlManagerV1.event.SetGamma).init(handleSetGamma), + /// A list of all outputs all_outputs: wl.list.Head(Output, .all_link), @@ -177,6 +181,7 @@ pub fn init(self: *Self) !void { .active_outputs = undefined, .output_manager = try wlr.OutputManagerV1.create(server.wl_server), .power_manager = try wlr.OutputPowerManagerV1.create(server.wl_server), + .gamma_control_manager = try wlr.GammaControlManagerV1.create(server.wl_server), .transaction_timeout = transaction_timeout, }; self.hidden.pending.focus_stack.init(); @@ -198,6 +203,7 @@ pub fn init(self: *Self) !void { self.output_manager.events.@"test".add(&self.manager_test); self.output_layout.events.change.add(&self.layout_change); self.power_manager.events.set_mode.add(&self.power_manager_set_mode); + self.gamma_control_manager.events.set_gamma.add(&self.gamma_control_set_gamma); } pub fn deinit(self: *Self) void { @@ -846,3 +852,15 @@ fn handlePowerManagerSetMode( std.log.scoped(.server).err("output commit failed for {s}", .{event.output.name}); }; } + +fn handleSetGamma( + _: *wl.Listener(*wlr.GammaControlManagerV1.event.SetGamma), + event: *wlr.GammaControlManagerV1.event.SetGamma, +) void { + const output: *Output = @ptrFromInt(event.output.data); + + std.log.debug("client requested to set gamma", .{}); + + output.gamma_dirty = true; + output.wlr_output.scheduleFrame(); +} diff --git a/river/Server.zig b/river/Server.zig index f17f2c1..44e26fd 100644 --- a/river/Server.zig +++ b/river/Server.zig @@ -142,7 +142,6 @@ pub fn init(self: *Self) !void { _ = try wlr.DataDeviceManager.create(self.wl_server); _ = try wlr.DataControlManagerV1.create(self.wl_server); _ = try wlr.ExportDmabufManagerV1.create(self.wl_server); - _ = try wlr.GammaControlManagerV1.create(self.wl_server); _ = try wlr.ScreencopyManagerV1.create(self.wl_server); _ = try wlr.SinglePixelBufferManagerV1.create(self.wl_server); _ = try wlr.Viewporter.create(self.wl_server);