diff --git a/README.md b/README.md index c9ed713..a3f7577 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ River is a dynamic tiling Wayland compositor with flexible runtime configuration. -Install from your [package manager](https://repology.org/project/river/versions) — +Check [packaging status](https://repology.org/project/river/versions) — Join us at [#river](https://web.libera.chat/?channels=#river) on irc.libera.chat — Read our man pages, [wiki](https://codeberg.org/river/wiki), and [Code of Conduct](CODE_OF_CONDUCT.md) diff --git a/build.zig.zon b/build.zig.zon index a1c2a92..28e5165 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -12,8 +12,8 @@ .hash = "1220687c8c47a48ba285d26a05600f8700d37fc637e223ced3aa8324f3650bf52242", }, .@"zig-wlroots" = .{ - .url = "https://codeberg.org/ifreund/zig-wlroots/archive/v0.17.1.tar.gz", - .hash = "1220c65ab884c236cc950b564c70f6cd04046d86485ee76e0cde886cef7438021b4f", + .url = "https://codeberg.org/ifreund/zig-wlroots/archive/084736cd92364b5fa7d8161611d085ce272fa707.tar.gz", + .hash = "12208383c1cf42e9b932b90f68cd4f378582cf966355a6377fd8f913852e7bc2d7c6", }, .@"zig-xkbcommon" = .{ .url = "https://codeberg.org/ifreund/zig-xkbcommon/archive/v0.2.0.tar.gz", diff --git a/river/Output.zig b/river/Output.zig index b235c1e..c9d8add 100644 --- a/river/Output.zig +++ b/river/Output.zig @@ -474,6 +474,7 @@ pub fn applyState(output: *Output, state: *wlr.Output.State) error{CommitFailed} fn handleEnableDisable(output: *Output) void { output.updateLockRenderStateOnEnableDisable(); + output.gamma_dirty = true; if (output.wlr_output.enabled) { // Add the output to root.active_outputs and the output layout if it has not @@ -539,18 +540,23 @@ fn renderAndCommit(output: *Output, scene_output: *wlr.SceneOutput) !void { 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", .{}); + const control = server.root.gamma_control_manager.getControl(output.wlr_output); + if (!wlr.GammaControlV1.apply(control, &state)) return error.OutOfMemory; + + if (!output.wlr_output.testState(&state)) { + wlr.GammaControlV1.sendFailedAndDestroy(control); state.clearGammaLut(); + // If the backend does not support gamma LUTs it will reject any + // state with the gamma LUT committed bit set even if the state + // has a null LUT. The wayland backend for example has this behavior. + state.committed.gamma_lut = false; } if (!scene_output.buildState(&state, null)) return error.CommitFailed; if (!output.wlr_output.commitState(&state)) return error.CommitFailed; + // TODO(wlroots) remove this rotate() call when updating to wlroots 0.18 scene_output.damage_ring.rotate(); output.gamma_dirty = false; } else { diff --git a/river/Root.zig b/river/Root.zig index e906982..149e67f 100644 --- a/river/Root.zig +++ b/river/Root.zig @@ -897,6 +897,7 @@ fn handlePowerManagerSetMode( } output.updateLockRenderStateOnEnableDisable(); + output.gamma_dirty = true; } fn handleSetGamma( diff --git a/river/Seat.zig b/river/Seat.zig index 95d3dcc..7bb3aaf 100644 --- a/river/Seat.zig +++ b/river/Seat.zig @@ -165,14 +165,21 @@ pub fn focus(seat: *Seat, _target: ?*View) void { // Views may not receive focus while locked. if (server.lock_manager.state != .unlocked) return; - // While a layer surface is exclusively focused, views may not receive focus + // A layer surface with exclusive focus will prevent any view from gaining + // focus if it is on the top or overlay layer. Otherwise, only steal focus + // from a focused layer surface if there is an explicit target view. if (seat.focused == .layer) { const wlr_layer_surface = seat.focused.layer.wlr_layer_surface; assert(wlr_layer_surface.surface.mapped); - if (wlr_layer_surface.current.keyboard_interactive == .exclusive and - (wlr_layer_surface.current.layer == .top or wlr_layer_surface.current.layer == .overlay)) - { - return; + switch (wlr_layer_surface.current.keyboard_interactive) { + .none => {}, + .exclusive => switch (wlr_layer_surface.current.layer) { + .top, .overlay => return, + .bottom, .background => if (target == null) return, + _ => {}, + }, + .on_demand => if (target == null) return, + _ => {}, } } diff --git a/river/XdgPopup.zig b/river/XdgPopup.zig index 5198e9b..fd82fbe 100644 --- a/river/XdgPopup.zig +++ b/river/XdgPopup.zig @@ -35,6 +35,7 @@ root: *wlr.SceneTree, tree: *wlr.SceneTree, destroy: wl.Listener(void) = wl.Listener(void).init(handleDestroy), +commit: wl.Listener(*wlr.Surface) = wl.Listener(*wlr.Surface).init(handleCommit), new_popup: wl.Listener(*wlr.XdgPopup) = wl.Listener(*wlr.XdgPopup).init(handleNewPopup), reposition: wl.Listener(void) = wl.Listener(void).init(handleReposition), @@ -54,22 +55,30 @@ pub fn create( }; wlr_xdg_popup.base.events.destroy.add(&xdg_popup.destroy); + wlr_xdg_popup.base.surface.events.commit.add(&xdg_popup.commit); wlr_xdg_popup.base.events.new_popup.add(&xdg_popup.new_popup); wlr_xdg_popup.events.reposition.add(&xdg_popup.reposition); - - handleReposition(&xdg_popup.reposition); } fn handleDestroy(listener: *wl.Listener(void)) void { const xdg_popup: *XdgPopup = @fieldParentPtr("destroy", listener); xdg_popup.destroy.link.remove(); + xdg_popup.commit.link.remove(); xdg_popup.new_popup.link.remove(); xdg_popup.reposition.link.remove(); util.gpa.destroy(xdg_popup); } +fn handleCommit(listener: *wl.Listener(*wlr.Surface), _: *wlr.Surface) void { + const xdg_popup: *XdgPopup = @fieldParentPtr("commit", listener); + + if (xdg_popup.wlr_xdg_popup.base.initial_commit) { + handleReposition(&xdg_popup.reposition); + } +} + fn handleNewPopup(listener: *wl.Listener(*wlr.XdgPopup), wlr_xdg_popup: *wlr.XdgPopup) void { const xdg_popup: *XdgPopup = @fieldParentPtr("new_popup", listener); diff --git a/river/XwaylandView.zig b/river/XwaylandView.zig index 9a94ae4..1ca8d0e 100644 --- a/river/XwaylandView.zig +++ b/river/XwaylandView.zig @@ -106,10 +106,10 @@ pub fn configure(xwayland_view: XwaylandView) bool { } xwayland_view.xwayland_surface.configure( - @intCast(inflight.box.x + output_box.x), - @intCast(inflight.box.y + output_box.y), - @intCast(inflight.box.width), - @intCast(inflight.box.height), + math.lossyCast(i16, inflight.box.x + output_box.x), + math.lossyCast(i16, inflight.box.y + output_box.y), + math.lossyCast(u16, inflight.box.width), + math.lossyCast(u16, inflight.box.height), ); xwayland_view.setActivated(inflight.focus != 0);