Add layer shell support and fix floating windows
Now, I actually save the river-layer-shell-v1 and keep track of the non-exclusive area. The layout calculation uses the usable area instead of the entire output's geometry. I removed boundary clamping for the floating windows because it was a bit janky when hitting the edges. I'll probably add it back at some point. I also made windows default to 75% of the usable area instead of keeping their tiled size so that maximized windows look decent when floating for the first time. Finally, since I removed the clamping, I added a center_float keybind to center a floating window. If you're cycling through focused windows and one isn't on the screen, you can use the center_float bind to get the window visible again. Replaced all divTrunc with divFloor to be consistent. I think they should all be positive, anyways, so they'd be the same, but I like just having one.
This commit is contained in:
parent
6bf607b759
commit
5c427234d7
9 changed files with 108 additions and 71 deletions
|
|
@ -146,6 +146,7 @@ Full command reference:
|
||||||
| `move_right` | pixels | Move floating window right |
|
| `move_right` | pixels | Move floating window right |
|
||||||
| `resize_width` | pixels | Resize floating window width (negative to shrink) |
|
| `resize_width` | pixels | Resize floating window width (negative to shrink) |
|
||||||
| `resize_height` | pixels | Resize floating window height (negative to shrink)|
|
| `resize_height` | pixels | Resize floating window height (negative to shrink)|
|
||||||
|
| `center_float` | | Center the focused floating window on its output |
|
||||||
| `set_output_tags` | tags (u32 bitmask) | Set the tags on the focused output |
|
| `set_output_tags` | tags (u32 bitmask) | Set the tags on the focused output |
|
||||||
| `set_window_tags` | tags (u32 bitmask) | Set the tags on the focused window |
|
| `set_window_tags` | tags (u32 bitmask) | Set the tags on the focused window |
|
||||||
| `toggle_output_tags` | tags (u32 bitmask) | Toggle a tag on the focused output |
|
| `toggle_output_tags` | tags (u32 bitmask) | Toggle a tag on the focused output |
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ These are in rough order of my priority, though no promises I do them in this or
|
||||||
|
|
||||||
- [ ] Implement a river-tag-overlay clone
|
- [ ] Implement a river-tag-overlay clone
|
||||||
- [ ] Implement an optional clock bar
|
- [ ] Implement an optional clock bar
|
||||||
|
- [ ] Make a Rect struct to combine x, y, width, and height
|
||||||
- [ ] Support window rules (float/tags/SSD by app-id/title)
|
- [ ] Support window rules (float/tags/SSD by app-id/title)
|
||||||
- [ ] Support overriding config location
|
- [ ] Support overriding config location
|
||||||
- [ ] Support configuring primary vs secondary stack side
|
- [ ] Support configuring primary vs secondary stack side
|
||||||
|
|
|
||||||
|
|
@ -506,6 +506,7 @@ fn loadKeybindsChildBlock(config: *Config, parser: *kdl.Parser, hostname: ?[]con
|
||||||
.decrement_primary_count,
|
.decrement_primary_count,
|
||||||
.swap_next,
|
.swap_next,
|
||||||
.swap_prev,
|
.swap_prev,
|
||||||
|
.center_float,
|
||||||
=> |cmd| {
|
=> |cmd| {
|
||||||
// None of these have arguments, just create the union and give it back
|
// None of these have arguments, just create the union and give it back
|
||||||
break :sw @unionInit(XkbBindings.Command, @tagName(cmd), {});
|
break :sw @unionInit(XkbBindings.Command, @tagName(cmd), {});
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ wl_registry: *wl.Registry,
|
||||||
wl_shm: *wl.Shm,
|
wl_shm: *wl.Shm,
|
||||||
wl_outputs: *std.AutoHashMapUnmanaged(u32, *wl.Output),
|
wl_outputs: *std.AutoHashMapUnmanaged(u32, *wl.Output),
|
||||||
|
|
||||||
|
river_layer_shell_v1: *river.LayerShellV1,
|
||||||
zwlr_layer_shell_v1: *zwlr.LayerShellV1,
|
zwlr_layer_shell_v1: *zwlr.LayerShellV1,
|
||||||
|
|
||||||
// Wayland globals that we have special structs for
|
// Wayland globals that we have special structs for
|
||||||
|
|
@ -68,6 +69,7 @@ pub fn create(options: Options) !*Context {
|
||||||
.wl_registry = options.wl_registry,
|
.wl_registry = options.wl_registry,
|
||||||
.wl_shm = options.wl_shm,
|
.wl_shm = options.wl_shm,
|
||||||
.wl_outputs = options.wl_outputs,
|
.wl_outputs = options.wl_outputs,
|
||||||
|
.river_layer_shell_v1 = options.river_layer_shell_v1,
|
||||||
.zwlr_layer_shell_v1 = options.zwlr_layer_shell_v1,
|
.zwlr_layer_shell_v1 = options.zwlr_layer_shell_v1,
|
||||||
.wallpaper_image = loadWallpaperImage(options.config),
|
.wallpaper_image = loadWallpaperImage(options.config),
|
||||||
.im = try InputManager.create(context, options.river_input_manager_v1, options.river_libinput_config_v1),
|
.im = try InputManager.create(context, options.river_input_manager_v1, options.river_libinput_config_v1),
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ const Output = @This();
|
||||||
context: *Context,
|
context: *Context,
|
||||||
|
|
||||||
river_output_v1: *river.OutputV1,
|
river_output_v1: *river.OutputV1,
|
||||||
|
river_layer_shell_output_v1: *river.LayerShellOutputV1,
|
||||||
|
|
||||||
// We have to wait for the rwm.wl_output event to get this
|
// We have to wait for the rwm.wl_output event to get this
|
||||||
wl_output: ?*wl.Output = null,
|
wl_output: ?*wl.Output = null,
|
||||||
|
|
@ -16,10 +17,16 @@ name: ?[]const u8 = null,
|
||||||
|
|
||||||
// Output geometry
|
// Output geometry
|
||||||
scale: u31 = 1,
|
scale: u31 = 1,
|
||||||
width: u31 = 0,
|
|
||||||
height: u31 = 0,
|
|
||||||
x: i32 = 0,
|
x: i32 = 0,
|
||||||
y: i32 = 0,
|
y: i32 = 0,
|
||||||
|
width: u31 = 0,
|
||||||
|
height: u31 = 0,
|
||||||
|
|
||||||
|
// Area left after layer shell surfaces take exclusive area
|
||||||
|
usable_x: i32 = 0,
|
||||||
|
usable_y: i32 = 0,
|
||||||
|
usable_width: u31 = 0,
|
||||||
|
usable_height: u31 = 0,
|
||||||
|
|
||||||
// Information for this Output's wallpaper
|
// Information for this Output's wallpaper
|
||||||
wallpaper_render_width: u31 = 0,
|
wallpaper_render_width: u31 = 0,
|
||||||
|
|
@ -62,10 +69,15 @@ pub const TagLayoutOverride = struct {
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const PendingManage = struct {
|
pub const PendingManage = struct {
|
||||||
width: ?u31 = null,
|
|
||||||
height: ?u31 = null,
|
|
||||||
x: ?i32 = null,
|
x: ?i32 = null,
|
||||||
y: ?i32 = null,
|
y: ?i32 = null,
|
||||||
|
width: ?u31 = null,
|
||||||
|
height: ?u31 = null,
|
||||||
|
|
||||||
|
usable_x: ?i32 = null,
|
||||||
|
usable_y: ?i32 = null,
|
||||||
|
usable_width: ?u31 = null,
|
||||||
|
usable_height: ?u31 = null,
|
||||||
|
|
||||||
tags: ?u32 = null,
|
tags: ?u32 = null,
|
||||||
primary_ratio: ?f32 = null,
|
primary_ratio: ?f32 = null,
|
||||||
|
|
@ -84,6 +96,7 @@ pub fn create(context: *Context, river_output_v1: *river.OutputV1) !*Output {
|
||||||
output.* = .{
|
output.* = .{
|
||||||
.context = context,
|
.context = context,
|
||||||
.river_output_v1 = river_output_v1,
|
.river_output_v1 = river_output_v1,
|
||||||
|
.river_layer_shell_output_v1 = try context.river_layer_shell_v1.getOutput(river_output_v1),
|
||||||
.bar = bar,
|
.bar = bar,
|
||||||
.primary_count = context.config.primary_count,
|
.primary_count = context.config.primary_count,
|
||||||
.primary_ratio = context.config.primary_ratio,
|
.primary_ratio = context.config.primary_ratio,
|
||||||
|
|
@ -94,6 +107,7 @@ pub fn create(context: *Context, river_output_v1: *river.OutputV1) !*Output {
|
||||||
output.windows.init();
|
output.windows.init();
|
||||||
|
|
||||||
output.river_output_v1.setListener(*Output, riverOutputListener, output);
|
output.river_output_v1.setListener(*Output, riverOutputListener, output);
|
||||||
|
output.river_layer_shell_output_v1.setListener(*Output, riverLayerShellOutputListener, output);
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
@ -268,6 +282,24 @@ fn wlOutputListener(_: *wl.Output, event: wl.Output.Event, output: *Output) void
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Used for the river_layer_shell_output_v1 interface
|
||||||
|
fn riverLayerShellOutputListener(
|
||||||
|
river_layer_shell_output_v1: *river.LayerShellOutputV1,
|
||||||
|
event: river.LayerShellOutputV1.Event,
|
||||||
|
output: *Output,
|
||||||
|
) void {
|
||||||
|
assert(output.river_layer_shell_output_v1 == river_layer_shell_output_v1);
|
||||||
|
switch (event) {
|
||||||
|
.non_exclusive_area => |ev| {
|
||||||
|
output.pending_manage.usable_x = ev.x;
|
||||||
|
output.pending_manage.usable_y = ev.y;
|
||||||
|
output.pending_manage.usable_width = @intCast(ev.width);
|
||||||
|
output.pending_manage.usable_height = @intCast(ev.height);
|
||||||
|
output.context.wm.river_window_manager_v1.manageDirty();
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn initWallpaperLayerSurface(output: *Output) !void {
|
pub fn initWallpaperLayerSurface(output: *Output) !void {
|
||||||
if (output.context.wallpaper_image == null) {
|
if (output.context.wallpaper_image == null) {
|
||||||
// No wallpaper image, so we don't need any surfaces
|
// No wallpaper image, so we don't need any surfaces
|
||||||
|
|
@ -446,17 +478,30 @@ pub fn renderWallpaper(output: *Output) !void {
|
||||||
pub fn manage(output: *Output) void {
|
pub fn manage(output: *Output) void {
|
||||||
defer output.pending_manage = .{};
|
defer output.pending_manage = .{};
|
||||||
|
|
||||||
|
if (output.pending_manage.x) |x| {
|
||||||
|
output.x = x;
|
||||||
|
}
|
||||||
|
if (output.pending_manage.y) |y| {
|
||||||
|
output.y = y;
|
||||||
|
}
|
||||||
if (output.pending_manage.width) |width| {
|
if (output.pending_manage.width) |width| {
|
||||||
output.width = width;
|
output.width = width;
|
||||||
}
|
}
|
||||||
if (output.pending_manage.height) |height| {
|
if (output.pending_manage.height) |height| {
|
||||||
output.height = height;
|
output.height = height;
|
||||||
}
|
}
|
||||||
if (output.pending_manage.x) |x| {
|
|
||||||
output.x = x;
|
if (output.pending_manage.usable_x) |usable_x| {
|
||||||
|
output.usable_x = usable_x;
|
||||||
}
|
}
|
||||||
if (output.pending_manage.y) |y| {
|
if (output.pending_manage.usable_y) |usable_y| {
|
||||||
output.y = y;
|
output.usable_y = usable_y;
|
||||||
|
}
|
||||||
|
if (output.pending_manage.usable_width) |usable_width| {
|
||||||
|
output.usable_width = usable_width;
|
||||||
|
}
|
||||||
|
if (output.pending_manage.usable_height) |usable_height| {
|
||||||
|
output.usable_height = usable_height;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (output.pending_manage.primary_ratio) |primary_ratio| {
|
if (output.pending_manage.primary_ratio) |primary_ratio| {
|
||||||
|
|
@ -542,12 +587,11 @@ fn calculatePrimaryStackLayout(output: *Output) void {
|
||||||
|
|
||||||
if (active_count == 0) return;
|
if (active_count == 0) return;
|
||||||
|
|
||||||
// Output dimensions come as i32 from the protocol, convert to u31 for window dimensions
|
// We have to use the usable area for the layout so windows don't overlap with widgets
|
||||||
// since they can't be negative.
|
const output_x = output.usable_x;
|
||||||
const output_width: u31 = @intCast(output.width);
|
const output_y = output.usable_y;
|
||||||
const output_height: u31 = @intCast(output.height);
|
const output_width = output.usable_width;
|
||||||
const output_x = output.x;
|
const output_height = output.usable_height;
|
||||||
const output_y = output.y;
|
|
||||||
const border_width = output.context.config.border_width;
|
const border_width = output.context.config.border_width;
|
||||||
|
|
||||||
// Single window: maximize and return early
|
// Single window: maximize and return early
|
||||||
|
|
@ -621,6 +665,15 @@ fn calculatePrimaryStackLayout(output: *Output) void {
|
||||||
assert(active_list.first == null);
|
assert(active_list.first == null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn occupiedTags(output: *Output) u32 {
|
||||||
|
var occupied_tags: u32 = 0x0000;
|
||||||
|
var it = output.windows.iterator(.forward);
|
||||||
|
while (it.next()) |window| {
|
||||||
|
occupied_tags |= window.tags;
|
||||||
|
}
|
||||||
|
return occupied_tags;
|
||||||
|
}
|
||||||
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
|
|
|
||||||
37
src/Seat.zig
37
src/Seat.zig
|
|
@ -159,8 +159,8 @@ pub fn manage(seat: *Seat) void {
|
||||||
// Warp pointer to center of focused window;
|
// Warp pointer to center of focused window;
|
||||||
// because the x and y coords are set during render, we need to check if
|
// because the x and y coords are set during render, we need to check if
|
||||||
// there are new coordinates in window.pending_render.
|
// there are new coordinates in window.pending_render.
|
||||||
const pointer_x: i32 = (window.pending_render.x orelse window.x) + @divTrunc(window.width, 2);
|
const pointer_x: i32 = (window.pending_render.x orelse window.x) + @divFloor(window.width, 2);
|
||||||
const pointer_y: i32 = (window.pending_render.y orelse window.y) + @divTrunc(window.height, 2);
|
const pointer_y: i32 = (window.pending_render.y orelse window.y) + @divFloor(window.height, 2);
|
||||||
seat.river_seat_v1.pointerWarp(pointer_x, pointer_y);
|
seat.river_seat_v1.pointerWarp(pointer_x, pointer_y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -204,17 +204,8 @@ pub fn manage(seat: *Seat) void {
|
||||||
switch (seat.pointer_op) {
|
switch (seat.pointer_op) {
|
||||||
.none => {},
|
.none => {},
|
||||||
.move => |op| {
|
.move => |op| {
|
||||||
const output = op.window.output orelse {
|
op.window.float_x = op.start_x + delta.dx;
|
||||||
log.err("window has no output during move operation", .{});
|
op.window.float_y = op.start_y + delta.dy;
|
||||||
return;
|
|
||||||
};
|
|
||||||
const min_x = output.x;
|
|
||||||
const max_x = output.x + output.width - @as(i32, op.window.float_width);
|
|
||||||
const min_y = output.y;
|
|
||||||
const max_y = output.y + output.height - @as(i32, op.window.float_height);
|
|
||||||
|
|
||||||
op.window.float_x = std.math.clamp(op.start_x + delta.dx, min_x, @max(min_x, max_x));
|
|
||||||
op.window.float_y = std.math.clamp(op.start_y + delta.dy, min_y, @max(min_y, max_y));
|
|
||||||
op.window.pending_render.x = op.window.float_x;
|
op.window.pending_render.x = op.window.float_x;
|
||||||
op.window.pending_render.y = op.window.float_y;
|
op.window.pending_render.y = op.window.float_y;
|
||||||
},
|
},
|
||||||
|
|
@ -238,22 +229,10 @@ pub fn manage(seat: *Seat) void {
|
||||||
|
|
||||||
// Clamp to minimum size
|
// Clamp to minimum size
|
||||||
const min_size: i32 = 50;
|
const min_size: i32 = 50;
|
||||||
if (new_width < min_size) {
|
if (op.edges.left) new_x = @min(new_x, op.start_x + @as(i32, op.start_width) - min_size);
|
||||||
if (op.edges.left) new_x -= min_size - new_width;
|
if (op.edges.top) new_y = @min(new_y, op.start_y + @as(i32, op.start_height) - min_size);
|
||||||
new_width = min_size;
|
new_width = @max(new_width, min_size);
|
||||||
}
|
new_height = @max(new_height, min_size);
|
||||||
if (new_height < min_size) {
|
|
||||||
if (op.edges.top) new_y -= min_size - new_height;
|
|
||||||
new_height = min_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clamp position to output bounds
|
|
||||||
const output = op.window.output orelse {
|
|
||||||
log.err("window has no output during resize operation", .{});
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
new_x = std.math.clamp(new_x, output.x, @max(output.x, output.x + output.width - new_width));
|
|
||||||
new_y = std.math.clamp(new_y, output.y, @max(output.y, output.y + output.height - new_height));
|
|
||||||
|
|
||||||
op.window.float_width = @intCast(new_width);
|
op.window.float_width = @intCast(new_width);
|
||||||
op.window.float_height = @intCast(new_height);
|
op.window.float_height = @intCast(new_height);
|
||||||
|
|
|
||||||
|
|
@ -184,14 +184,17 @@ pub fn manage(window: *Window) void {
|
||||||
river_window_v1.setTiled(.{});
|
river_window_v1.setTiled(.{});
|
||||||
|
|
||||||
if (window.float_width == 0) {
|
if (window.float_width == 0) {
|
||||||
// Never floated before; use current dimensions but centered on output
|
// Never floated before; use 75% of usable area, centered on output
|
||||||
window.float_width = window.width;
|
|
||||||
window.float_height = window.height;
|
|
||||||
if (window.output) |output| {
|
if (window.output) |output| {
|
||||||
// Need to find center and then subtract half of the window's width/height
|
window.float_width = @divFloor(output.usable_width * 3, 4);
|
||||||
window.float_x = output.x + @divTrunc(output.width, 2) - @divTrunc(window.width, 2);
|
window.float_height = @divFloor(output.usable_height * 3, 4);
|
||||||
window.float_y = output.y + @divTrunc(output.height, 2) - @divTrunc(window.height, 2);
|
window.float_x = output.usable_x + @divFloor(output.usable_width, 2) - @divFloor(window.float_width, 2);
|
||||||
|
window.float_y = output.usable_y + @divFloor(output.usable_height, 2) - @divFloor(window.float_height, 2);
|
||||||
|
} else {
|
||||||
|
window.float_width = window.width;
|
||||||
|
window.float_height = window.height;
|
||||||
}
|
}
|
||||||
|
river_window_v1.proposeDimensions(window.float_width, window.float_height);
|
||||||
} else {
|
} else {
|
||||||
// Window has floated before; re-use its old dimensions
|
// Window has floated before; re-use its old dimensions
|
||||||
river_window_v1.proposeDimensions(window.float_width, window.float_height);
|
river_window_v1.proposeDimensions(window.float_width, window.float_height);
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,9 @@ pub const Command = union(enum) {
|
||||||
resize_width: i32,
|
resize_width: i32,
|
||||||
resize_height: i32,
|
resize_height: i32,
|
||||||
|
|
||||||
|
// Center floating window on its output
|
||||||
|
center_float,
|
||||||
|
|
||||||
// Swap window position in stack
|
// Swap window position in stack
|
||||||
swap_next,
|
swap_next,
|
||||||
swap_prev,
|
swap_prev,
|
||||||
|
|
@ -237,6 +240,7 @@ const XkbBinding = struct {
|
||||||
.move_right => |pixels| moveFloatingWindow(context, pixels, 0),
|
.move_right => |pixels| moveFloatingWindow(context, pixels, 0),
|
||||||
.resize_width => |delta| resizeFloatingWindow(context, delta, 0),
|
.resize_width => |delta| resizeFloatingWindow(context, delta, 0),
|
||||||
.resize_height => |delta| resizeFloatingWindow(context, 0, delta),
|
.resize_height => |delta| resizeFloatingWindow(context, 0, delta),
|
||||||
|
.center_float => centerFloatingWindow(context),
|
||||||
.swap_next => swapWindow(context, .next),
|
.swap_next => swapWindow(context, .next),
|
||||||
.swap_prev => swapWindow(context, .prev),
|
.swap_prev => swapWindow(context, .prev),
|
||||||
}
|
}
|
||||||
|
|
@ -336,18 +340,9 @@ const XkbBinding = struct {
|
||||||
const seat = context.wm.seats.first() orelse return;
|
const seat = context.wm.seats.first() orelse return;
|
||||||
const window = seat.focused_window orelse return;
|
const window = seat.focused_window orelse return;
|
||||||
if (!window.floating) return;
|
if (!window.floating) return;
|
||||||
const output = window.output orelse {
|
|
||||||
log.err("focused floating window has no output during move", .{});
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
const min_x = output.x;
|
window.float_x += dx;
|
||||||
const max_x = output.x + output.width - @as(i32, window.float_width);
|
window.float_y += dy;
|
||||||
const min_y = output.y;
|
|
||||||
const max_y = output.y + output.height - @as(i32, window.float_height);
|
|
||||||
|
|
||||||
window.float_x = std.math.clamp(window.float_x + dx, min_x, @max(min_x, max_x));
|
|
||||||
window.float_y = std.math.clamp(window.float_y + dy, min_y, @max(min_y, max_y));
|
|
||||||
window.pending_render.x = window.float_x;
|
window.pending_render.x = window.float_x;
|
||||||
window.pending_render.y = window.float_y;
|
window.pending_render.y = window.float_y;
|
||||||
context.wm.river_window_manager_v1.manageDirty();
|
context.wm.river_window_manager_v1.manageDirty();
|
||||||
|
|
@ -357,25 +352,27 @@ const XkbBinding = struct {
|
||||||
const seat = context.wm.seats.first() orelse return;
|
const seat = context.wm.seats.first() orelse return;
|
||||||
const window = seat.focused_window orelse return;
|
const window = seat.focused_window orelse return;
|
||||||
if (!window.floating) return;
|
if (!window.floating) return;
|
||||||
const output = window.output orelse {
|
|
||||||
log.err("focused floating window has no output during resize", .{});
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
const new_width: i32 = @as(i32, window.float_width) + dw;
|
const new_width: i32 = @as(i32, window.float_width) + dw;
|
||||||
const new_height: i32 = @as(i32, window.float_height) + dh;
|
const new_height: i32 = @as(i32, window.float_height) + dh;
|
||||||
window.float_width = @intCast(@max(50, new_width));
|
window.float_width = @intCast(@max(50, new_width));
|
||||||
window.float_height = @intCast(@max(50, new_height));
|
window.float_height = @intCast(@max(50, new_height));
|
||||||
|
|
||||||
// Clamp position to keep window on screen after resize
|
window.pending_manage.width = window.float_width;
|
||||||
const max_x = output.x + output.width - @as(i32, window.float_width);
|
window.pending_manage.height = window.float_height;
|
||||||
const max_y = output.y + output.height - @as(i32, window.float_height);
|
context.wm.river_window_manager_v1.manageDirty();
|
||||||
window.float_x = std.math.clamp(window.float_x, output.x, @max(output.x, max_x));
|
}
|
||||||
window.float_y = std.math.clamp(window.float_y, output.y, @max(output.y, max_y));
|
|
||||||
|
|
||||||
|
fn centerFloatingWindow(context: *Context) void {
|
||||||
|
const seat = context.wm.seats.first() orelse return;
|
||||||
|
const window = seat.focused_window orelse return;
|
||||||
|
if (!window.floating) return;
|
||||||
|
const output = window.output orelse return;
|
||||||
|
|
||||||
|
window.float_x = output.usable_x + @divFloor(output.usable_width, 2) - @divFloor(window.float_width, 2);
|
||||||
|
window.float_y = output.usable_y + @divFloor(output.usable_height, 2) - @divFloor(window.float_height, 2);
|
||||||
window.pending_render.x = window.float_x;
|
window.pending_render.x = window.float_x;
|
||||||
window.pending_render.y = window.float_y;
|
window.pending_render.y = window.float_y;
|
||||||
window.river_window_v1.proposeDimensions(window.float_width, window.float_height);
|
|
||||||
context.wm.river_window_manager_v1.manageDirty();
|
context.wm.river_window_manager_v1.manageDirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -145,7 +145,7 @@ fn run(wl_display: *wl.Display, context: *Context) !void {
|
||||||
log.err("Got a negative time ({d})", .{time});
|
log.err("Got a negative time ({d})", .{time});
|
||||||
return error.InvalidTime;
|
return error.InvalidTime;
|
||||||
}
|
}
|
||||||
const timeout: i32 = @intCast((@divTrunc(time, 60) * 60 + 60 - time) * 1000);
|
const timeout: i32 = @intCast((@divFloor(time, 60) * 60 + 60 - time) * 1000);
|
||||||
|
|
||||||
const poll_rc = posix.poll(&pollfds, timeout) catch |err| {
|
const poll_rc = posix.poll(&pollfds, timeout) catch |err| {
|
||||||
fatal("Failed to poll {s}", .{@errorName(err)});
|
fatal("Failed to poll {s}", .{@errorName(err)});
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue