aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--river/Cursor.zig2
-rw-r--r--river/Root.zig2
-rw-r--r--river/Seat.zig18
-rw-r--r--river/View.zig27
-rw-r--r--river/VoidView.zig6
-rw-r--r--river/XdgToplevel.zig24
-rw-r--r--river/XwaylandView.zig18
-rw-r--r--river/render.zig6
8 files changed, 49 insertions, 54 deletions
diff --git a/river/Cursor.zig b/river/Cursor.zig
index 8d549f1..535b9f5 100644
--- a/river/Cursor.zig
+++ b/river/Cursor.zig
@@ -555,7 +555,7 @@ fn viewSurfaceAt(output: Output, ox: f64, oy: f64, sx: *f64, sy: *f64) ?*c.wlr_s
// Focused views are rendered on top, so look for them first.
var it = ViewStack(View).iterator(output.views.first, output.current.tags);
while (it.next()) |node| {
- if (!node.view.focused) continue;
+ if (node.view.current.focus == 0) continue;
if (node.view.surfaceAt(ox, oy, sx, sy)) |found| return found;
}
diff --git a/river/Root.zig b/river/Root.zig
index c286c90..b556a42 100644
--- a/river/Root.zig
+++ b/river/Root.zig
@@ -141,7 +141,7 @@ fn startTransaction(self: *Self) void {
if (view.needsConfigure()) {
view.configure();
- self.pending_configures += 1;
+ if (!view.pending.float) self.pending_configures += 1;
// Send a frame done that the client will commit a new frame
// with the dimensions we sent in the configure. Normally this
diff --git a/river/Seat.zig b/river/Seat.zig
index 886cacc..52aae7c 100644
--- a/river/Seat.zig
+++ b/river/Seat.zig
@@ -17,6 +17,7 @@
const Self = @This();
+const build_options = @import("build_options");
const std = @import("std");
const c = @import("c.zig");
@@ -182,14 +183,24 @@ pub fn setFocusRaw(self: *Self, new_focus: FocusTarget) void {
// still clear the focus.
if (if (target_wlr_surface) |wlr_surface| self.input_manager.inputAllowed(wlr_surface) else true) {
// First clear the current focus
- if (self.focused == .view) self.focused.view.setFocused(false);
+ if (self.focused == .view) {
+ self.focused.view.pending.focus -= 1;
+ // This is needed because xwayland views don't double buffer
+ // activated state.
+ if (build_options.xwayland and self.focused.view.impl == .xwayland_view)
+ c.wlr_xwayland_surface_activate(self.focused.view.impl.xwayland_view.wlr_xwayland_surface, false);
+ }
c.wlr_seat_keyboard_clear_focus(self.wlr_seat);
// Set the new focus
switch (new_focus) {
.view => |target_view| {
std.debug.assert(self.focused_output == target_view.output);
- target_view.setFocused(true);
+ target_view.pending.focus += 1;
+ // This is needed because xwayland views don't double buffer
+ // activated state.
+ if (build_options.xwayland and target_view.impl == .xwayland_view)
+ c.wlr_xwayland_surface_activate(target_view.impl.xwayland_view.wlr_xwayland_surface, true);
},
.layer => |target_layer| std.debug.assert(self.focused_output == target_layer.output),
.none => {},
@@ -212,6 +223,9 @@ pub fn setFocusRaw(self: *Self, new_focus: FocusTarget) void {
// Inform any clients tracking status of the change
var it = self.status_trackers.first;
while (it) |node| : (it = node.next) node.data.sendFocusedView();
+
+ // Start a transaction to apply the pending focus state
+ self.input_manager.server.root.startTransaction();
}
/// Focus the given output, notifying any listening clients of the change.
diff --git a/river/View.zig b/river/View.zig
index 2154829..fd21e08 100644
--- a/river/View.zig
+++ b/river/View.zig
@@ -60,6 +60,9 @@ const State = struct {
/// The tags of the view, as a bitmask
tags: u32,
+ /// Number of seats currently focusing the view
+ focus: u32,
+
float: bool,
fullscreen: bool,
};
@@ -79,9 +82,6 @@ output: *Output,
/// This is non-null exactly when the view is mapped
wlr_surface: ?*c.wlr_surface,
-/// True if the view is currently focused by at least one seat
-focused: bool,
-
/// The double-buffered state of the view
current: State,
pending: State,
@@ -111,8 +111,6 @@ pub fn init(self: *Self, output: *Output, tags: u32, surface: var) void {
self.wlr_surface = null;
- self.focused = false;
-
self.current = .{
.box = .{
.x = 0,
@@ -121,6 +119,7 @@ pub fn init(self: *Self, output: *Output, tags: u32, surface: var) void {
.width = 0,
},
.tags = tags,
+ .focus = 0,
.float = false,
.fullscreen = false,
};
@@ -155,8 +154,8 @@ pub fn needsConfigure(self: Self) bool {
pub fn configure(self: Self) void {
switch (self.impl) {
- .xdg_toplevel => |xdg_toplevel| xdg_toplevel.configure(self.pending.box),
- .xwayland_view => |xwayland_view| xwayland_view.configure(self.pending.box),
+ .xdg_toplevel => |xdg_toplevel| xdg_toplevel.configure(),
+ .xwayland_view => |xwayland_view| xwayland_view.configure(),
}
}
@@ -205,16 +204,6 @@ fn saveBuffersIterator(
}
}
-/// Set the focused bool and the active state of the view if it is a toplevel
-/// TODO: This is insufficient for multi-seat, probably need a focus counter.
-pub fn setFocused(self: *Self, focused: bool) void {
- self.focused = focused;
- switch (self.impl) {
- .xdg_toplevel => |xdg_toplevel| xdg_toplevel.setActivated(focused),
- .xwayland_view => |xwayland_view| xwayland_view.setActivated(focused),
- }
-}
-
/// Set the pending state, set the size, and inform the client.
pub fn setFullscreen(self: *Self, fullscreen: bool) void {
self.pending.fullscreen = fullscreen;
@@ -358,8 +347,6 @@ pub fn unmap(self: *Self) void {
log.debug(.server, "view '{}' unmapped", .{self.getTitle()});
- self.wlr_surface = null;
-
// Inform all seats that the view has been unmapped so they can handle focus
var it = root.server.input_manager.seats.first;
while (it) |node| : (it = node.next) {
@@ -367,6 +354,8 @@ pub fn unmap(self: *Self) void {
seat.handleViewUnmap(self);
}
+ self.wlr_surface = null;
+
// Remove the view from its output's stack
const node = @fieldParentPtr(ViewStack(Self).Node, "view", self);
self.output.views.remove(node);
diff --git a/river/VoidView.zig b/river/VoidView.zig
index 784b9f0..b212dd6 100644
--- a/river/VoidView.zig
+++ b/river/VoidView.zig
@@ -28,11 +28,7 @@ pub fn needsConfigure(self: Self) bool {
unreachable;
}
-pub fn configure(self: Self, pending_box: Box) void {
- unreachable;
-}
-
-pub fn setActivated(self: Self, activated: bool) void {
+pub fn configure(self: Self) void {
unreachable;
}
diff --git a/river/XdgToplevel.zig b/river/XdgToplevel.zig
index 12c5034..af44cf3 100644
--- a/river/XdgToplevel.zig
+++ b/river/XdgToplevel.zig
@@ -63,32 +63,32 @@ pub fn init(self: *Self, view: *View, wlr_xdg_surface: *c.wlr_xdg_surface) void
/// Returns true if a configure must be sent to ensure the dimensions of the
/// pending_box are applied.
pub fn needsConfigure(self: Self) bool {
- const wlr_xdg_toplevel: *c.wlr_xdg_toplevel = @field(
+ const server_pending = &@field(
self.wlr_xdg_surface,
c.wlr_xdg_surface_union,
- ).toplevel;
+ ).toplevel.*.server_pending;
+ const state = &self.view.pending;
// Checking server_pending is sufficient here since it will be either in
// sync with the current dimensions or be the dimensions sent with the
// most recent configure. In both cases server_pending has the values we
// want to check against.
- return self.view.pending.box.width != wlr_xdg_toplevel.server_pending.width or
- self.view.pending.box.height != wlr_xdg_toplevel.server_pending.height;
+ return (state.focus != 0) != server_pending.activated or
+ state.box.width != server_pending.width or
+ state.box.height != server_pending.height;
}
-/// Send a configure event, applying the width/height of the pending box.
-pub fn configure(self: Self, pending_box: Box) void {
+/// Send a configure event, applying the pending state of the view.
+pub fn configure(self: Self) void {
+ const state = &self.view.pending;
+ _ = c.wlr_xdg_toplevel_set_activated(self.wlr_xdg_surface, state.focus != 0);
self.view.pending_serial = c.wlr_xdg_toplevel_set_size(
self.wlr_xdg_surface,
- pending_box.width,
- pending_box.height,
+ state.box.width,
+ state.box.height,
);
}
-pub fn setActivated(self: Self, activated: bool) void {
- _ = c.wlr_xdg_toplevel_set_activated(self.wlr_xdg_surface, activated);
-}
-
pub fn setFullscreen(self: Self, fullscreen: bool) void {
_ = c.wlr_xdg_toplevel_set_fullscreen(self.wlr_xdg_surface, fullscreen);
}
diff --git a/river/XwaylandView.zig b/river/XwaylandView.zig
index 7ae248b..80fb7e3 100644
--- a/river/XwaylandView.zig
+++ b/river/XwaylandView.zig
@@ -63,14 +63,15 @@ pub fn needsConfigure(self: Self) bool {
self.wlr_xwayland_surface.height != self.view.pending.box.height;
}
-/// Tell the client to take a new size
-pub fn configure(self: Self, pending_box: Box) void {
+/// Apply pending state
+pub fn configure(self: Self) void {
+ const state = &self.view.pending;
c.wlr_xwayland_surface_configure(
self.wlr_xwayland_surface,
- @intCast(i16, pending_box.x),
- @intCast(i16, pending_box.y),
- @intCast(u16, pending_box.width),
- @intCast(u16, pending_box.height),
+ @intCast(i16, state.box.x),
+ @intCast(i16, state.box.y),
+ @intCast(u16, state.box.width),
+ @intCast(u16, state.box.height),
);
// Xwayland surfaces don't use serials, so we will just assume they have
// configured the next time they commit. Set pending serial to a dummy
@@ -80,11 +81,6 @@ pub fn configure(self: Self, pending_box: Box) void {
self.view.pending_serial = 0x66666666;
}
-/// Inform the xwayland surface that it has gained focus
-pub fn setActivated(self: Self, activated: bool) void {
- c.wlr_xwayland_surface_activate(self.wlr_xwayland_surface, activated);
-}
-
pub fn setFullscreen(self: Self, fullscreen: bool) void {
c.wlr_xwayland_surface_set_fullscreen(self.wlr_xwayland_surface, fullscreen);
}
diff --git a/river/render.zig b/river/render.zig
index fc72266..76492ab 100644
--- a/river/render.zig
+++ b/river/render.zig
@@ -85,7 +85,7 @@ pub fn renderOutput(output: *Output) void {
if (view.current.box.width == 0 or view.current.box.height == 0) continue;
// Focused views are rendered on top of normal views, skip them for now
- if (view.focused) continue;
+ if (view.current.focus != 0) continue;
renderView(output.*, view, &now);
if (view.draw_borders) renderBorders(output.*, view, &now);
@@ -101,7 +101,7 @@ pub fn renderOutput(output: *Output) void {
if (view.current.box.width == 0 or view.current.box.height == 0) continue;
// Skip unfocused views since we already rendered them
- if (!view.focused) continue;
+ if (view.current.focus == 0) continue;
renderView(output.*, view, &now);
if (view.draw_borders) renderBorders(output.*, view, &now);
@@ -254,7 +254,7 @@ fn renderTexture(
fn renderBorders(output: Output, view: *View, now: *c.timespec) void {
const config = &output.root.server.config;
- const color = if (view.focused) &config.border_color_focused else &config.border_color_unfocused;
+ const color = if (view.current.focus != 0) &config.border_color_focused else &config.border_color_unfocused;
const border_width = config.border_width;
const actual_box = if (view.saved_buffers.items.len != 0) view.saved_surface_box else view.surface_box;