diff --git a/README.md b/README.md index 620f595..7a3eef0 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ distribution. - [zig](https://ziglang.org/download/) 0.9 - wayland - wayland-protocols -- [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots) 0.15 +- [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots) 0.16 - xkbcommon - libevdev - pixman diff --git a/deps/zig-wayland b/deps/zig-wayland index c19ffc5..f64abbd 160000 --- a/deps/zig-wayland +++ b/deps/zig-wayland @@ -1 +1 @@ -Subproject commit c19ffc58a88573df3e47c08599c472eb715ef7a5 +Subproject commit f64abbd016a918fe6e74e0cf337410cecad5eb5d diff --git a/deps/zig-wlroots b/deps/zig-wlroots index 0629720..916aa50 160000 --- a/deps/zig-wlroots +++ b/deps/zig-wlroots @@ -1 +1 @@ -Subproject commit 06297208176ac530b4882c92d6b064bda467c001 +Subproject commit 916aa5041f4300c0e7a0e34d4f256528cdbd0507 diff --git a/deps/zig-xkbcommon b/deps/zig-xkbcommon index 0f6eda0..c97f8e1 160000 --- a/deps/zig-xkbcommon +++ b/deps/zig-xkbcommon @@ -1 +1 @@ -Subproject commit 0f6eda023e6f52ea001c597fda0a7c3e7a2ccce0 +Subproject commit c97f8e18dddda04414067cf8fbfdaa7682dcb44a diff --git a/river/Box.zig b/river/Box.zig deleted file mode 100644 index ecfe5fd..0000000 --- a/river/Box.zig +++ /dev/null @@ -1,42 +0,0 @@ -// This file is part of river, a dynamic tiling wayland compositor. -// -// Copyright 2020 The River Developers -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 3. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -const Self = @This(); - -const wlr = @import("wlroots"); - -x: i32, -y: i32, -width: u32, -height: u32, - -pub fn fromWlrBox(wlr_box: wlr.Box) Self { - return Self{ - .x = @intCast(i32, wlr_box.x), - .y = @intCast(i32, wlr_box.y), - .width = @intCast(u32, wlr_box.width), - .height = @intCast(u32, wlr_box.height), - }; -} - -pub fn toWlrBox(self: Self) wlr.Box { - return wlr.Box{ - .x = @intCast(c_int, self.x), - .y = @intCast(c_int, self.y), - .width = @intCast(c_int, self.width), - .height = @intCast(c_int, self.height), - }; -} diff --git a/river/Config.zig b/river/Config.zig index 7916621..f654f99 100644 --- a/river/Config.zig +++ b/river/Config.zig @@ -47,7 +47,7 @@ pub const HideCursorWhenTypingMode = enum { background_color: [4]f32 = [_]f32{ 0.0, 0.16862745, 0.21176471, 1.0 }, // Solarized base03 /// Width of borders in pixels -border_width: u32 = 2, +border_width: u31 = 2, /// Color of border of focused window in RGBA border_color_focused: [4]f32 = [_]f32{ 0.57647059, 0.63137255, 0.63137255, 1.0 }, // Solarized base1 diff --git a/river/Cursor.zig b/river/Cursor.zig index 49ae33c..b885d2d 100644 --- a/river/Cursor.zig +++ b/river/Cursor.zig @@ -30,7 +30,6 @@ const c = @import("c.zig"); const server = &@import("main.zig").server; const util = @import("util.zig"); -const Box = @import("Box.zig"); const Config = @import("Config.zig"); const LayerSurface = @import("LayerSurface.zig"); const Output = @import("Output.zig"); @@ -855,8 +854,8 @@ pub fn enterMode(self: *Self, mode: enum { move, resize }, view: *View) void { const cur_box = &view.current.box; self.mode = .{ .resize = .{ .view = view, - .offset_x = cur_box.x + @intCast(i32, cur_box.width) - @floatToInt(i32, self.wlr_cursor.x), - .offset_y = cur_box.y + @intCast(i32, cur_box.height) - @floatToInt(i32, self.wlr_cursor.y), + .offset_x = cur_box.x + cur_box.width - @floatToInt(i32, self.wlr_cursor.x), + .offset_y = cur_box.y + cur_box.height - @floatToInt(i32, self.wlr_cursor.y), } }; view.setResizing(true); }, @@ -971,23 +970,25 @@ fn processMotion(self: *Self, device: *wlr.InputDevice, time: u32, delta_x: f64, const border_width = if (data.view.draw_borders) server.config.border_width else 0; // Set width/height of view, clamp to view size constraints and output dimensions - const box = &data.view.pending.box; - box.width = @intCast(u32, math.max(0, @intCast(i32, box.width) + @floatToInt(i32, dx))); - box.height = @intCast(u32, math.max(0, @intCast(i32, box.height) + @floatToInt(i32, dy))); - + data.view.pending.box.width += @floatToInt(i32, dx); + data.view.pending.box.height += @floatToInt(i32, dy); data.view.applyConstraints(); - const output_resolution = data.view.output.getEffectiveResolution(); - box.width = math.min(box.width, output_resolution.width - border_width - @intCast(u32, box.x)); - box.height = math.min(box.height, output_resolution.height - border_width - @intCast(u32, box.y)); + var output_width: i32 = undefined; + var output_height: i32 = undefined; + data.view.output.wlr_output.effectiveResolution(&output_width, &output_height); + + const box = &data.view.pending.box; + box.width = math.min(box.width, output_width - border_width - box.x); + box.height = math.min(box.height, output_height - border_width - box.y); data.view.applyPending(); // Keep cursor locked to the original offset from the bottom right corner self.wlr_cursor.warpClosest( device, - @intToFloat(f64, box.x + @intCast(i32, box.width) - data.offset_x), - @intToFloat(f64, box.y + @intCast(i32, box.height) - data.offset_y), + @intToFloat(f64, box.x + box.width - data.offset_x), + @intToFloat(f64, box.y + box.height - data.offset_y), ); }, } @@ -1025,7 +1026,7 @@ pub fn updateState(self: *Self) void { var now: os.timespec = undefined; os.clock_gettime(os.CLOCK.MONOTONIC, &now) catch @panic("CLOCK_MONOTONIC not supported"); const msec = @intCast(u32, now.tv_sec * std.time.ms_per_s + - @divFloor(now.tv_nsec, std.time.ns_per_ms)); + @divTrunc(now.tv_nsec, std.time.ns_per_ms)); self.passthrough(msec); } } diff --git a/river/InputConfig.zig b/river/InputConfig.zig index 0467d95..13432d4 100644 --- a/river/InputConfig.zig +++ b/river/InputConfig.zig @@ -40,14 +40,14 @@ pub const EventState = enum { @"disabled-on-external-mouse", pub fn apply(event_state: EventState, device: *c.libinput_device) void { - const want = switch (event_state) { + const want: u32 = switch (event_state) { .enabled => c.LIBINPUT_CONFIG_SEND_EVENTS_ENABLED, .disabled => c.LIBINPUT_CONFIG_SEND_EVENTS_DISABLED, .@"disabled-on-external-mouse" => c.LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE, }; const current = c.libinput_device_config_send_events_get_mode(device); if (want != current) { - _ = c.libinput_device_config_send_events_set_mode(device, @intCast(u32, want)); + _ = c.libinput_device_config_send_events_set_mode(device, want); } } }; @@ -259,7 +259,7 @@ pub const ScrollButton = struct { pub fn apply(scroll_button: ScrollButton, device: *c.libinput_device) void { const supports = c.libinput_device_config_scroll_get_methods(device); - if (supports & ~@intCast(u32, c.LIBINPUT_CONFIG_SCROLL_NO_SCROLL) == 0) return; + if (supports & ~@as(u32, c.LIBINPUT_CONFIG_SCROLL_NO_SCROLL) == 0) return; _ = c.libinput_device_config_scroll_set_button(device, scroll_button.button); } }; diff --git a/river/InputDevice.zig b/river/InputDevice.zig index 83da4ed..42514f5 100644 --- a/river/InputDevice.zig +++ b/river/InputDevice.zig @@ -50,12 +50,6 @@ pub fn init(device: *InputDevice, seat: *Seat, wlr_device: *wlr.InputDevice) !vo else => @tagName(wlr_device.type), }; - // wlroots 0.15 leaves wlr_input_device->name NULL for keyboard groups. - // This wart has been cleaned up in 0.16, so just work around it until that is released. - // TODO(wlroots): Remove this hack - - const name = if (isKeyboardGroup(wlr_device)) "wlr_keyboard_group" else wlr_device.name; - const identifier = try std.fmt.allocPrint( util.gpa, "{s}-{}-{}-{s}", @@ -63,7 +57,7 @@ pub fn init(device: *InputDevice, seat: *Seat, wlr_device: *wlr.InputDevice) !vo device_type, wlr_device.vendor, wlr_device.product, - mem.trim(u8, mem.span(name), &ascii.spaces), + mem.trim(u8, mem.span(wlr_device.name), &ascii.spaces), }, ); errdefer util.gpa.free(identifier); @@ -115,7 +109,7 @@ pub fn deinit(device: *InputDevice) void { fn isKeyboardGroup(wlr_device: *wlr.InputDevice) bool { return wlr_device.type == .keyboard and - wlr.KeyboardGroup.fromKeyboard(wlr_device.device.keyboard) != null; + wlr.KeyboardGroup.fromKeyboard(wlr_device.toKeyboard()) != null; } fn handleDestroy(listener: *wl.Listener(*wlr.InputDevice), _: *wlr.InputDevice) void { diff --git a/river/InputManager.zig b/river/InputManager.zig index 055ccdf..1c34239 100644 --- a/river/InputManager.zig +++ b/river/InputManager.zig @@ -210,7 +210,7 @@ fn handleNewVirtualPointer( log.debug("Ignoring output suggestion from virtual pointer", .{}); } - self.defaultSeat().addDevice(&event.new_pointer.input_device); + self.defaultSeat().addDevice(&event.new_pointer.pointer.base); } fn handleNewVirtualKeyboard( @@ -218,5 +218,5 @@ fn handleNewVirtualKeyboard( virtual_keyboard: *wlr.VirtualKeyboardV1, ) void { const seat = @intToPtr(*Seat, virtual_keyboard.seat.data); - seat.addDevice(&virtual_keyboard.input_device); + seat.addDevice(&virtual_keyboard.keyboard.base); } diff --git a/river/Keyboard.zig b/river/Keyboard.zig index eeec2ee..22f3d0b 100644 --- a/river/Keyboard.zig +++ b/river/Keyboard.zig @@ -54,7 +54,7 @@ pub fn init(self: *Self, seat: *Seat, wlr_device: *wlr.InputDevice) !void { const keymap = xkb.Keymap.newFromNames(context, null, .no_flags) orelse return error.XkbKeymapFailed; defer keymap.unref(); - const wlr_keyboard = self.device.wlr_device.device.keyboard; + const wlr_keyboard = self.device.wlr_device.toKeyboard(); wlr_keyboard.data = @ptrToInt(self); if (!wlr_keyboard.setKeymap(keymap)) return error.SetKeymapFailed; @@ -77,7 +77,7 @@ pub fn deinit(self: *Self) void { fn handleKey(listener: *wl.Listener(*wlr.Keyboard.event.Key), event: *wlr.Keyboard.event.Key) void { // This event is raised when a key is pressed or released. const self = @fieldParentPtr(Self, "key", listener); - const wlr_keyboard = self.device.wlr_device.device.keyboard; + const wlr_keyboard = self.device.wlr_device.toKeyboard(); // If the keyboard is in a group, this event will be handled by the group's Keyboard instance. if (wlr_keyboard.group != null) return; @@ -125,7 +125,7 @@ fn handleKey(listener: *wl.Listener(*wlr.Keyboard.event.Key), event: *wlr.Keyboa if (!eaten) { // If key was not handled, we pass it along to the client. const wlr_seat = self.device.seat.wlr_seat; - wlr_seat.setKeyboard(self.device.wlr_device); + wlr_seat.setKeyboard(self.device.wlr_device.toKeyboard()); wlr_seat.keyboardNotifyKey(event.time_msec, event.keycode, event.state); } } @@ -136,12 +136,12 @@ fn isModifier(keysym: xkb.Keysym) bool { fn handleModifiers(listener: *wl.Listener(*wlr.Keyboard), _: *wlr.Keyboard) void { const self = @fieldParentPtr(Self, "modifiers", listener); - const wlr_keyboard = self.device.wlr_device.device.keyboard; + const wlr_keyboard = self.device.wlr_device.toKeyboard(); // If the keyboard is in a group, this event will be handled by the group's Keyboard instance. if (wlr_keyboard.group != null) return; - self.device.seat.wlr_seat.setKeyboard(self.device.wlr_device); + self.device.seat.wlr_seat.setKeyboard(self.device.wlr_device.toKeyboard()); self.device.seat.wlr_seat.keyboardNotifyModifiers(&wlr_keyboard.modifiers); } diff --git a/river/KeyboardGroup.zig b/river/KeyboardGroup.zig index e759bc0..617c042 100644 --- a/river/KeyboardGroup.zig +++ b/river/KeyboardGroup.zig @@ -55,7 +55,7 @@ pub fn create(seat: *Seat, name: []const u8) !void { .seat = seat, }; - seat.addDevice(wlr_group.input_device); + seat.addDevice(&wlr_group.keyboard.base); seat.keyboard_groups.append(node); } @@ -95,8 +95,7 @@ pub fn addIdentifier(group: *KeyboardGroup, new_id: []const u8) !void { if (mem.eql(u8, new_id, device.identifier)) { log.debug("found existing matching keyboard; adding to group", .{}); - const wlr_keyboard = device.wlr_device.device.keyboard; - if (!group.wlr_group.addKeyboard(wlr_keyboard)) { + if (!group.wlr_group.addKeyboard(device.wlr_device.toKeyboard())) { // wlroots logs an error message to explain why this failed. continue; } @@ -119,7 +118,7 @@ pub fn removeIdentifier(group: *KeyboardGroup, id: []const u8) !void { if (device.wlr_device.type != .keyboard) continue; if (mem.eql(u8, device.identifier, id)) { - const wlr_keyboard = device.wlr_device.device.keyboard; + const wlr_keyboard = device.wlr_device.toKeyboard(); assert(wlr_keyboard.group == group.wlr_group); group.wlr_group.removeKeyboard(wlr_keyboard); } diff --git a/river/LayerSurface.zig b/river/LayerSurface.zig index 4231bad..7c78ed3 100644 --- a/river/LayerSurface.zig +++ b/river/LayerSurface.zig @@ -25,7 +25,6 @@ const zwlr = @import("wayland").server.zwlr; const server = &@import("main.zig").server; const util = @import("util.zig"); -const Box = @import("Box.zig"); const Output = @import("Output.zig"); const Subsurface = @import("Subsurface.zig"); const XdgPopup = @import("XdgPopup.zig"); @@ -35,7 +34,7 @@ const log = std.log.scoped(.layer_shell); output: *Output, wlr_layer_surface: *wlr.LayerSurfaceV1, -box: Box = undefined, +box: wlr.Box = undefined, layer: zwlr.LayerShellV1.Layer, destroy: wl.Listener(*wlr.LayerSurfaceV1) = wl.Listener(*wlr.LayerSurfaceV1).init(handleDestroy), diff --git a/river/Layout.zig b/river/Layout.zig index c6ecded..1dfc136 100644 --- a/river/Layout.zig +++ b/river/Layout.zig @@ -18,6 +18,7 @@ const Self = @This(); const std = @import("std"); const assert = std.debug.assert; +const math = std.math; const mem = std.mem; const wlr = @import("wlroots"); const wayland = @import("wayland"); @@ -27,7 +28,6 @@ const river = wayland.server.river; const server = &@import("main.zig").server; const util = @import("util.zig"); -const Box = @import("Box.zig"); const Server = @import("Server.zig"); const Output = @import("Output.zig"); const View = @import("View.zig"); @@ -111,8 +111,8 @@ pub fn startLayoutDemand(self: *Self, views: u32) void { self.layout.sendLayoutDemand( views, - self.output.usable_box.width, - self.output.usable_box.height, + @intCast(u32, self.output.usable_box.width), + @intCast(u32, self.output.usable_box.height), self.output.pending.tags, self.output.layout_demand.?.serial, ); @@ -137,7 +137,13 @@ fn handleRequest(layout: *river.LayoutV3, request: river.LayoutV3.Request, self: // because we do not keep track of old serials server-side. // Therefore, simply ignore requests with old/wrong serials. if (layout_demand.serial != req.serial) return; - layout_demand.pushViewDimensions(self.output, req.x, req.y, req.width, req.height); + layout_demand.pushViewDimensions( + self.output, + req.x, + req.y, + @intCast(u31, math.min(math.maxInt(u31), req.width)), + @intCast(u31, math.min(math.maxInt(u31), req.height)), + ); } }, diff --git a/river/LayoutDemand.zig b/river/LayoutDemand.zig index 4ad65e7..2a3ee8f 100644 --- a/river/LayoutDemand.zig +++ b/river/LayoutDemand.zig @@ -26,7 +26,6 @@ const server = &@import("main.zig").server; const util = @import("util.zig"); const Layout = @import("Layout.zig"); -const Box = @import("Box.zig"); const Server = @import("Server.zig"); const Output = @import("Output.zig"); const View = @import("View.zig"); @@ -43,7 +42,7 @@ serial: u32, /// This will go negative if the client pushes too many dimensions. views: i32, /// Proposed view dimensions -view_boxen: []Box, +view_boxen: []wlr.Box, timeout_timer: *wl.EventSource, pub fn init(layout: *Layout, views: u32) !Self { @@ -55,7 +54,7 @@ pub fn init(layout: *Layout, views: u32) !Self { return Self{ .serial = server.wl_server.nextSerial(), .views = @intCast(i32, views), - .view_boxen = try util.gpa.alloc(Box, views), + .view_boxen = try util.gpa.alloc(wlr.Box, views), .timeout_timer = timeout_timer, }; } @@ -81,7 +80,7 @@ fn handleTimeout(layout: *Layout) callconv(.C) c_int { } /// Push a set of proposed view dimensions and position to the list -pub fn pushViewDimensions(self: *Self, output: *Output, x: i32, y: i32, width: u32, height: u32) void { +pub fn pushViewDimensions(self: *Self, output: *Output, x: i32, y: i32, width: u31, height: u31) void { // The client pushed too many dimensions if (self.views <= 0) { self.views -= 1; @@ -92,8 +91,8 @@ pub fn pushViewDimensions(self: *Self, output: *Output, x: i32, y: i32, width: u // usable area and shrink the dimensions to accomodate the border size. const border_width = server.config.border_width; self.view_boxen[self.view_boxen.len - @intCast(usize, self.views)] = .{ - .x = x + output.usable_box.x + @intCast(i32, border_width), - .y = y + output.usable_box.y + @intCast(i32, border_width), + .x = x + output.usable_box.x + border_width, + .y = y + output.usable_box.y + border_width, .width = if (width > 2 * border_width) width - 2 * border_width else width, .height = if (height > 2 * border_width) height - 2 * border_width else height, }; diff --git a/river/Output.zig b/river/Output.zig index ac69dd7..ca4dbff 100644 --- a/river/Output.zig +++ b/river/Output.zig @@ -18,6 +18,7 @@ const Self = @This(); const std = @import("std"); const assert = std.debug.assert; +const math = std.math; const mem = std.mem; const fmt = std.fmt; const wlr = @import("wlroots"); @@ -29,7 +30,6 @@ const render = @import("render.zig"); const server = &@import("main.zig").server; const util = @import("util.zig"); -const Box = @import("Box.zig"); const LayerSurface = @import("LayerSurface.zig"); const Layout = @import("Layout.zig"); const LayoutDemand = @import("LayoutDemand.zig"); @@ -62,7 +62,7 @@ layers: [4]std.TailQueue(LayerSurface) = [1]std.TailQueue(LayerSurface){.{}} ** /// The area left for views and other layer surfaces after applying the /// exclusive zones of exclusive layer surfaces. /// TODO: this should be part of the output's State -usable_box: Box, +usable_box: wlr.Box, /// The top of the stack is the "most important" view. views: ViewStack(View) = .{}, @@ -86,7 +86,7 @@ layouts: std.TailQueue(Layout) = .{}, layout_namespace: ?[]const u8 = null, /// Bitmask that whitelists tags for newly spawned views -spawn_tagmask: u32 = std.math.maxInt(u32), +spawn_tagmask: u32 = math.maxInt(u32), /// List of status tracking objects relaying changes to this output to clients. status_trackers: std.SinglyLinkedList(OutputStatus) = .{}, @@ -145,13 +145,13 @@ pub fn init(self: *Self, wlr_output: *wlr.Output) !void { std.log.scoped(.cursor).err("failed to load xcursor theme at scale {}", .{wlr_output.scale}); } - const effective_resolution = self.getEffectiveResolution(); self.usable_box = .{ .x = 0, .y = 0, - .width = effective_resolution.width, - .height = effective_resolution.height, + .width = undefined, + .height = undefined, }; + self.wlr_output.effectiveResolution(&self.usable_box.width, &self.usable_box.height); self.setTitle(); } @@ -230,13 +230,13 @@ const ArrangeLayersTarget = enum { mapped, unmapped }; /// If target is unmapped, this function is pure aside from the /// wlr.LayerSurfaceV1.configure() calls made on umapped layer surfaces. pub fn arrangeLayers(self: *Self, target: ArrangeLayersTarget) void { - const effective_resolution = self.getEffectiveResolution(); - const full_box: Box = .{ + var full_box: wlr.Box = .{ .x = 0, .y = 0, - .width = effective_resolution.width, - .height = effective_resolution.height, + .width = undefined, + .height = undefined, }; + self.wlr_output.effectiveResolution(&full_box.width, &full_box.height); // This box is modified as exclusive zones are applied var usable_box = full_box; @@ -296,8 +296,8 @@ pub fn arrangeLayers(self: *Self, target: ArrangeLayersTarget) void { /// Arrange the layer surfaces of a given layer fn arrangeLayer( layer: std.TailQueue(LayerSurface), - full_box: Box, - usable_box: *Box, + full_box: wlr.Box, + usable_box: *wlr.Box, exclusive: bool, target: ArrangeLayersTarget, ) void { @@ -306,6 +306,9 @@ fn arrangeLayer( const layer_surface = &node.data; const current_state = layer_surface.wlr_layer_surface.current; + const desired_width = @intCast(u31, math.min(math.maxInt(u31), current_state.desired_width)); + const desired_height = @intCast(u31, math.min(math.maxInt(u31), current_state.desired_height)); + // If the value of exclusive_zone is greater than zero, then it exclusivly // occupies some area of the screen. if (exclusive != (current_state.exclusive_zone > 0)) continue; @@ -314,46 +317,40 @@ fn arrangeLayer( // to ignore any exclusive zones and use the full area of the output. const bounds = if (current_state.exclusive_zone == -1) &full_box else usable_box; - var new_box: Box = undefined; + var new_box: wlr.Box = undefined; // Horizontal alignment - if (current_state.desired_width == 0) { + if (desired_width == 0) { assert(current_state.anchor.right and current_state.anchor.left); - new_box.x = bounds.x + @intCast(i32, current_state.margin.left); + new_box.x = bounds.x + current_state.margin.left; new_box.width = bounds.width - (current_state.margin.left + current_state.margin.right); } else if (current_state.anchor.left == current_state.anchor.right) { - new_box.x = bounds.x + @intCast(i32, bounds.width / 2 -| current_state.desired_width / 2); - new_box.width = current_state.desired_width; + new_box.x = bounds.x + @divTrunc(bounds.width, 2) - desired_width / 2; + new_box.width = desired_width; } else if (current_state.anchor.left) { - new_box.x = bounds.x + @intCast(i32, current_state.margin.left); - new_box.width = current_state.desired_width; + new_box.x = bounds.x + current_state.margin.left; + new_box.width = desired_width; } else { assert(current_state.anchor.right); - new_box.x = bounds.x + @intCast(i32, bounds.width) - - @intCast(i32, current_state.desired_width) - - // TODO(wlroots) this type has been corrected to i32 for the next release - @intCast(i32, current_state.margin.right); - new_box.width = current_state.desired_width; + new_box.x = bounds.x + bounds.width - desired_width - current_state.margin.right; + new_box.width = desired_width; } // Vertical alignment - if (current_state.desired_height == 0) { + if (desired_height == 0) { assert(current_state.anchor.top and current_state.anchor.bottom); - new_box.y = bounds.y + @intCast(i32, current_state.margin.top); + new_box.y = bounds.y + current_state.margin.top; new_box.height = bounds.height - (current_state.margin.top + current_state.margin.bottom); } else if (current_state.anchor.top == current_state.anchor.bottom) { - new_box.y = bounds.y + @intCast(i32, bounds.height / 2 -| current_state.desired_height / 2); - new_box.height = current_state.desired_height; + new_box.y = bounds.y + @divTrunc(bounds.height, 2) - desired_height / 2; + new_box.height = desired_height; } else if (current_state.anchor.top) { - new_box.y = bounds.y + @intCast(i32, current_state.margin.top); - new_box.height = current_state.desired_height; + new_box.y = bounds.y + current_state.margin.top; + new_box.height = desired_height; } else { assert(current_state.anchor.bottom); - new_box.y = bounds.y + @intCast(i32, bounds.height) - - @intCast(i32, current_state.desired_height) - - // TODO(wlroots) this type has been corrected to i32 for the next release - @intCast(i32, current_state.margin.bottom); - new_box.height = current_state.desired_height; + new_box.y = bounds.y + bounds.height - desired_height - current_state.margin.bottom; + new_box.height = desired_height; } // Apply the exclusive zone to the current bounds @@ -361,8 +358,8 @@ fn arrangeLayer( single: zwlr.LayerSurfaceV1.Anchor, triple: zwlr.LayerSurfaceV1.Anchor, to_increase: ?*i32, - to_decrease: *u32, - margin: u32, + to_decrease: *i32, + margin: i32, }{ .{ .single = .{ .top = true }, @@ -396,11 +393,11 @@ fn arrangeLayer( for (edges) |edge| { if ((std.meta.eql(current_state.anchor, edge.single) or std.meta.eql(current_state.anchor, edge.triple)) and - current_state.exclusive_zone + @intCast(i32, edge.margin) > 0) + current_state.exclusive_zone + edge.margin > 0) { - const delta = current_state.exclusive_zone + @intCast(i32, edge.margin); + const delta = current_state.exclusive_zone + edge.margin; if (edge.to_increase) |value| value.* += delta; - edge.to_decrease.* -= @intCast(u32, delta); + edge.to_decrease.* -= delta; break; } } @@ -409,10 +406,16 @@ fn arrangeLayer( .mapped => { assert(layer_surface.wlr_layer_surface.mapped); layer_surface.box = new_box; - _ = layer_surface.wlr_layer_surface.configure(new_box.width, new_box.height); + _ = layer_surface.wlr_layer_surface.configure( + @intCast(u32, new_box.width), + @intCast(u32, new_box.height), + ); }, .unmapped => if (!layer_surface.wlr_layer_surface.mapped) { - _ = layer_surface.wlr_layer_surface.configure(new_box.width, new_box.height); + _ = layer_surface.wlr_layer_surface.configure( + @intCast(u32, new_box.width), + @intCast(u32, new_box.height), + ); }, } } @@ -484,16 +487,6 @@ fn handleMode(listener: *wl.Listener(*wlr.Output), _: *wlr.Output) void { server.root.startTransaction(); } -pub fn getEffectiveResolution(self: *Self) struct { width: u32, height: u32 } { - var width: c_int = undefined; - var height: c_int = undefined; - self.wlr_output.effectiveResolution(&width, &height); - return .{ - .width = @intCast(u32, width), - .height = @intCast(u32, height), - }; -} - fn setTitle(self: Self) void { const title = fmt.allocPrintZ(util.gpa, "river - {s}", .{self.wlr_output.name}) catch return; defer util.gpa.free(title); diff --git a/river/PointerConstraint.zig b/river/PointerConstraint.zig index 62147e9..450de21 100644 --- a/river/PointerConstraint.zig +++ b/river/PointerConstraint.zig @@ -80,7 +80,8 @@ fn constrainToRegion(self: *Self) void { if (self.cursor.constraint != self.constraint) return; if (View.fromWlrSurface(self.constraint.surface)) |view| { const output = view.output; - const output_box = server.root.output_layout.getBox(output.wlr_output).?; + var output_box: wlr.Box = undefined; + server.root.output_layout.getBox(output.wlr_output, &output_box); const surface_lx = @intToFloat(f64, output_box.x + view.current.box.x - view.surface_box.x); const surface_ly = @intToFloat(f64, output_box.y + view.current.box.y - view.surface_box.y); @@ -126,7 +127,8 @@ pub fn warpToHint(cursor: *Cursor) void { if (constraint.current.committed.cursor_hint) { if (View.fromWlrSurface(constraint.surface)) |view| { const output = view.output; - const output_box = server.root.output_layout.getBox(output.wlr_output).?; + var output_box: wlr.Box = undefined; + server.root.output_layout.getBox(output.wlr_output, &output_box); const surface_lx = @intToFloat(f64, output_box.x + view.current.box.x - view.surface_box.x); const surface_ly = @intToFloat(f64, output_box.y + view.current.box.y - view.surface_box.y); diff --git a/river/Root.zig b/river/Root.zig index 73fb80b..21849a7 100644 --- a/river/Root.zig +++ b/river/Root.zig @@ -527,12 +527,12 @@ fn currentOutputConfig(self: *Self) !*wlr.OutputConfigurationV1 { const output = node.data; const head = try wlr.OutputConfigurationV1.Head.create(config, output.wlr_output); - // If the output is not part of the layout (and thus disabled) we dont care - // about the position - if (self.output_layout.getBox(output.wlr_output)) |box| { - head.state.x = box.x; - head.state.y = box.y; - } + // If the output is not part of the layout (and thus disabled) + // the box will be zeroed out. + var box: wlr.Box = undefined; + self.output_layout.getBox(output.wlr_output, &box); + head.state.x = box.x; + head.state.y = box.y; } return config; diff --git a/river/Seat.zig b/river/Seat.zig index 4881092..78981fc 100644 --- a/river/Seat.zig +++ b/river/Seat.zig @@ -316,11 +316,14 @@ pub fn focusOutput(self: *Self, output: *Output) void { switch (server.config.warp_cursor) { .disabled => {}, .@"on-output-change" => { - const layout_box = server.root.output_layout.getBox(output.wlr_output).?; + var layout_box: wlr.Box = undefined; + server.root.output_layout.getBox(output.wlr_output, &layout_box); if (!layout_box.containsPoint(self.cursor.wlr_cursor.x, self.cursor.wlr_cursor.y)) { - const eff_res = output.getEffectiveResolution(); - const lx = @intToFloat(f32, layout_box.x + @intCast(i32, eff_res.width / 2)); - const ly = @intToFloat(f32, layout_box.y + @intCast(i32, eff_res.height / 2)); + var output_width: i32 = undefined; + var output_height: i32 = undefined; + output.wlr_output.effectiveResolution(&output_width, &output_height); + const lx = @intToFloat(f64, layout_box.x + @divTrunc(output_width, 2)); + const ly = @intToFloat(f64, layout_box.y + @divTrunc(output_height, 2)); if (!self.cursor.wlr_cursor.warp(null, lx, ly)) { log.err("failed to warp cursor on output change", .{}); } @@ -482,7 +485,7 @@ fn tryAddDevice(self: *Self, wlr_device: *wlr.InputDevice) !void { try keyboard.init(self, wlr_device); - self.wlr_seat.setKeyboard(keyboard.device.wlr_device); + self.wlr_seat.setKeyboard(keyboard.device.wlr_device.toKeyboard()); if (self.wlr_seat.keyboard_state.focused_surface) |wlr_surface| { self.wlr_seat.keyboardNotifyClearFocus(); self.keyboardNotifyEnter(wlr_surface); diff --git a/river/Server.zig b/river/Server.zig index 09595a2..c795013 100644 --- a/river/Server.zig +++ b/river/Server.zig @@ -97,8 +97,9 @@ pub fn init(self: *Self) !void { errdefer self.allocator.destroy(); const compositor = try wlr.Compositor.create(self.wl_server, self.renderer); + _ = try wlr.Subcompositor.create(self.wl_server); - self.xdg_shell = try wlr.XdgShell.create(self.wl_server); + self.xdg_shell = try wlr.XdgShell.create(self.wl_server, 2); self.new_xdg_surface.setNotify(handleNewXdgSurface); self.xdg_shell.events.new_surface.add(&self.new_xdg_surface); @@ -188,7 +189,7 @@ fn handleNewXdgSurface(listener: *wl.Listener(*wlr.XdgSurface), xdg_surface: *wl log.debug("new xdg_toplevel", .{}); const output = self.input_manager.defaultSeat().focused_output; - XdgToplevel.create(output, xdg_surface) catch { + XdgToplevel.create(output, xdg_surface.role_data.toplevel) catch { log.err("out of memory", .{}); xdg_surface.resource.postNoMemory(); return; diff --git a/river/Switch.zig b/river/Switch.zig index 157e3bc..d36fd69 100644 --- a/river/Switch.zig +++ b/river/Switch.zig @@ -59,7 +59,7 @@ pub fn init(self: *Self, seat: *Seat, wlr_device: *wlr.InputDevice) !void { try self.device.init(seat, wlr_device); errdefer self.device.deinit(); - wlr_device.device.switch_device.events.toggle.add(&self.toggle); + wlr_device.toSwitch().events.toggle.add(&self.toggle); } pub fn deinit(self: *Self) void { @@ -83,7 +83,6 @@ fn handleToggle(listener: *wl.Listener(*wlr.Switch.event.Toggle), event: *wlr.Sw switch_state = switch (event.switch_state) { .off => .{ .lid = .open }, .on => .{ .lid = .close }, - .toggle => unreachable, }; }, .tablet_mode => { @@ -91,7 +90,6 @@ fn handleToggle(listener: *wl.Listener(*wlr.Switch.event.Toggle), event: *wlr.Sw switch_state = switch (event.switch_state) { .off => .{ .tablet = .off }, .on => .{ .tablet = .on }, - .toggle => unreachable, }; }, } diff --git a/river/View.zig b/river/View.zig index 272d384..61cecf4 100644 --- a/river/View.zig +++ b/river/View.zig @@ -27,7 +27,6 @@ const wl = @import("wayland").server.wl; const server = &@import("main.zig").server; const util = @import("util.zig"); -const Box = @import("Box.zig"); const Output = @import("Output.zig"); const Seat = @import("Seat.zig"); const ViewStack = @import("view_stack.zig").ViewStack; @@ -37,10 +36,10 @@ const XwaylandView = if (build_options.xwayland) @import("XwaylandView.zig") els const log = std.log.scoped(.view); pub const Constraints = struct { - min_width: u32, - max_width: u32, - min_height: u32, - max_height: u32, + min_width: u31, + max_width: u31, + min_height: u31, + max_height: u31, }; const Impl = union(enum) { @@ -52,7 +51,7 @@ const State = struct { /// The output-relative effective coordinates and effective dimensions of the view. The /// surface itself may have other dimensions which are stored in the /// surface_box member. - box: Box = Box{ .x = 0, .y = 0, .width = 0, .height = 0 }, + box: wlr.Box = wlr.Box{ .x = 0, .y = 0, .width = 0, .height = 0 }, /// The tags of the view, as a bitmask tags: u32, @@ -68,7 +67,7 @@ const State = struct { const SavedBuffer = struct { client_buffer: *wlr.ClientBuffer, /// x/y relative to the root surface in the surface tree. - surface_box: Box, + surface_box: wlr.Box, source_box: wlr.FBox, transform: wl.Output.Transform, }; @@ -95,22 +94,22 @@ pending_serial: ?u32 = null, /// The currently commited geometry of the surface. The x/y may be negative if /// for example the client has decided to draw CSD shadows a la GTK. -surface_box: Box = undefined, +surface_box: wlr.Box = undefined, /// The geometry the view's surface had when the transaction started and /// buffers were saved. -saved_surface_box: Box = undefined, +saved_surface_box: wlr.Box = undefined, /// These are what we render while a transaction is in progress saved_buffers: std.ArrayListUnmanaged(SavedBuffer) = .{}, /// The floating dimensions the view, saved so that they can be restored if the /// view returns to floating mode. -float_box: Box = undefined, +float_box: wlr.Box = undefined, /// This state exists purely to allow for more intuitive behavior when /// exiting fullscreen if there is no active layout. -post_fullscreen_box: Box = undefined, +post_fullscreen_box: wlr.Box = undefined, draw_borders: bool = true, @@ -172,13 +171,14 @@ pub fn applyPending(self: *Self) void { // If switching to fullscreen, set the dimensions to the full area of the output self.setFullscreen(true); self.post_fullscreen_box = self.current.box; - const dimensions = self.output.getEffectiveResolution(); + self.pending.box = .{ .x = 0, .y = 0, - .width = dimensions.width, - .height = dimensions.height, + .width = undefined, + .height = undefined, }; + self.output.wlr_output.effectiveResolution(&self.pending.box.width, &self.pending.box.height); } else if (self.lastSetFullscreenState() and !self.pending.fullscreen) { self.setFullscreen(false); self.pending.box = self.post_fullscreen_box; @@ -246,8 +246,8 @@ fn saveBuffersIterator( .surface_box = .{ .x = surface_x, .y = surface_y, - .width = @intCast(u32, surface.current.width), - .height = @intCast(u32, surface.current.height), + .width = surface.current.width, + .height = surface.current.height, }, .source_box = source_box, .transform = surface.current.transform, @@ -284,22 +284,19 @@ pub fn sendToOutput(self: *Self, destination_output: *Output) void { } self.output = destination_output; - const dimensions = destination_output.getEffectiveResolution(); + + var output_width: i32 = undefined; + var output_height: i32 = undefined; + destination_output.wlr_output.effectiveResolution(&output_width, &output_height); if (self.pending.float) { // Adapt dimensions of view to new output. Only necessary when floating, // because for tiled views the output will be rearranged, taking care // of this. if (self.pending.fullscreen) self.pending.box = self.post_fullscreen_box; - const border_width = if (self.draw_borders) @intCast(i32, server.config.border_width) else 0; - self.pending.box.width = math.min( - self.pending.box.width, - @intCast(i32, dimensions.width) - (2 * border_width), - ); - self.pending.box.height = math.min( - self.pending.box.height, - @intCast(i32, dimensions.height) - (2 * border_width), - ); + const border_width = if (self.draw_borders) server.config.border_width else 0; + self.pending.box.width = math.min(self.pending.box.width, output_width - (2 * border_width)); + self.pending.box.height = math.min(self.pending.box.height, output_height - (2 * border_width)); // Adjust position of view so that it is fully inside the target output. self.move(0, 0); @@ -313,8 +310,8 @@ pub fn sendToOutput(self: *Self, destination_output: *Output) void { self.pending.box = .{ .x = 0, .y = 0, - .width = dimensions.width, - .height = dimensions.height, + .width = output_width, + .height = output_height, }; } } @@ -374,7 +371,7 @@ pub inline fn forEachSurface( ) void { switch (self.impl) { .xdg_toplevel => |xdg_toplevel| { - xdg_toplevel.xdg_surface.forEachSurface(T, iterator, user_data); + xdg_toplevel.xdg_toplevel.base.forEachSurface(T, iterator, user_data); }, .xwayland_view => { assert(build_options.xwayland); @@ -427,16 +424,18 @@ pub fn getConstraints(self: Self) Constraints { /// Modify the pending x/y of the view by the given deltas, clamping to the /// bounds of the output. pub fn move(self: *Self, delta_x: i32, delta_y: i32) void { - const border_width = if (self.draw_borders) @intCast(i32, server.config.border_width) else 0; - const output_resolution = self.output.getEffectiveResolution(); + const border_width = if (self.draw_borders) server.config.border_width else 0; + var output_width: i32 = undefined; + var output_height: i32 = undefined; + self.output.wlr_output.effectiveResolution(&output_width, &output_height); - const max_x = @intCast(i32, output_resolution.width) - @intCast(i32, self.pending.box.width) - border_width; + const max_x = output_width - self.pending.box.width - border_width; self.pending.box.x += delta_x; self.pending.box.x = math.max(self.pending.box.x, border_width); self.pending.box.x = math.min(self.pending.box.x, max_x); self.pending.box.x = math.max(self.pending.box.x, 0); - const max_y = @intCast(i32, output_resolution.height) - @intCast(i32, self.pending.box.height) - border_width; + const max_y = output_height - self.pending.box.height - border_width; self.pending.box.y += delta_y; self.pending.box.y = math.max(self.pending.box.y, border_width); self.pending.box.y = math.min(self.pending.box.y, max_y); diff --git a/river/VoidView.zig b/river/VoidView.zig index dfd9e82..4337763 100644 --- a/river/VoidView.zig +++ b/river/VoidView.zig @@ -19,7 +19,6 @@ const Self = @This(); const std = @import("std"); const wlr = @import("wlroots"); -const Box = @import("Box.zig"); const View = @import("View.zig"); pub fn needsConfigure(_: Self) bool { diff --git a/river/XdgPopup.zig b/river/XdgPopup.zig index 8ac250f..4b85561 100644 --- a/river/XdgPopup.zig +++ b/river/XdgPopup.zig @@ -31,9 +31,9 @@ parent: Parent, wlr_xdg_popup: *wlr.XdgPopup, // Always active -surface_destroy: wl.Listener(*wlr.XdgSurface) = wl.Listener(*wlr.XdgSurface).init(handleDestroy), -map: wl.Listener(*wlr.XdgSurface) = wl.Listener(*wlr.XdgSurface).init(handleMap), -unmap: wl.Listener(*wlr.XdgSurface) = wl.Listener(*wlr.XdgSurface).init(handleUnmap), +surface_destroy: wl.Listener(void) = wl.Listener(void).init(handleDestroy), +map: wl.Listener(void) = wl.Listener(void).init(handleMap), +unmap: wl.Listener(void) = wl.Listener(void).init(handleUnmap), new_popup: wl.Listener(*wlr.XdgPopup) = wl.Listener(*wlr.XdgPopup).init(handleNewPopup), new_subsurface: wl.Listener(*wlr.Subsurface) = wl.Listener(*wlr.Subsurface).init(handleNewSubsurface), @@ -55,25 +55,25 @@ pub fn create(wlr_xdg_popup: *wlr.XdgPopup, parent: Parent) void { switch (parent) { .xdg_toplevel => |xdg_toplevel| { - const output_dimensions = xdg_toplevel.view.output.getEffectiveResolution(); // The output box relative to the parent of the xdg_popup var box = wlr.Box{ .x = xdg_toplevel.view.surface_box.x - xdg_toplevel.view.pending.box.x, .y = xdg_toplevel.view.surface_box.y - xdg_toplevel.view.pending.box.y, - .width = @intCast(c_int, output_dimensions.width), - .height = @intCast(c_int, output_dimensions.height), + .width = undefined, + .height = undefined, }; + xdg_toplevel.view.output.wlr_output.effectiveResolution(&box.width, &box.height); wlr_xdg_popup.unconstrainFromBox(&box); }, .layer_surface => |layer_surface| { - const output_dimensions = layer_surface.output.getEffectiveResolution(); // The output box relative to the parent of the xdg_popup var box = wlr.Box{ .x = -layer_surface.box.x, .y = -layer_surface.box.y, - .width = @intCast(c_int, output_dimensions.width), - .height = @intCast(c_int, output_dimensions.height), + .width = undefined, + .height = undefined, }; + layer_surface.output.wlr_output.effectiveResolution(&box.width, &box.height); wlr_xdg_popup.unconstrainFromBox(&box); }, .drag_icon => unreachable, @@ -111,19 +111,19 @@ pub fn destroyPopups(wlr_xdg_surface: *wlr.XdgSurface) void { } } -fn handleDestroy(listener: *wl.Listener(*wlr.XdgSurface), _: *wlr.XdgSurface) void { +fn handleDestroy(listener: *wl.Listener(void)) void { const xdg_popup = @fieldParentPtr(XdgPopup, "surface_destroy", listener); xdg_popup.destroy(); } -fn handleMap(listener: *wl.Listener(*wlr.XdgSurface), _: *wlr.XdgSurface) void { +fn handleMap(listener: *wl.Listener(void)) void { const xdg_popup = @fieldParentPtr(XdgPopup, "map", listener); xdg_popup.wlr_xdg_popup.base.surface.events.commit.add(&xdg_popup.commit); xdg_popup.parent.damageWholeOutput(); } -fn handleUnmap(listener: *wl.Listener(*wlr.XdgSurface), _: *wlr.XdgSurface) void { +fn handleUnmap(listener: *wl.Listener(void)) void { const xdg_popup = @fieldParentPtr(XdgPopup, "unmap", listener); xdg_popup.commit.link.remove(); diff --git a/river/XdgToplevel.zig b/river/XdgToplevel.zig index 9793adb..5579323 100644 --- a/river/XdgToplevel.zig +++ b/river/XdgToplevel.zig @@ -24,7 +24,6 @@ const wl = @import("wayland").server.wl; const server = &@import("main.zig").server; const util = @import("util.zig"); -const Box = @import("Box.zig"); const Output = @import("Output.zig"); const Seat = @import("Seat.zig"); const Subsurface = @import("Subsurface.zig"); @@ -38,15 +37,15 @@ const log = std.log.scoped(.xdg_shell); view: *View, /// The corresponding wlroots object -xdg_surface: *wlr.XdgSurface, +xdg_toplevel: *wlr.XdgToplevel, /// Set to true when the client acks the configure with serial View.pending_serial. acked_pending_serial: bool = false, // Listeners that are always active over the view's lifetime -destroy: wl.Listener(*wlr.XdgSurface) = wl.Listener(*wlr.XdgSurface).init(handleDestroy), -map: wl.Listener(*wlr.XdgSurface) = wl.Listener(*wlr.XdgSurface).init(handleMap), -unmap: wl.Listener(*wlr.XdgSurface) = wl.Listener(*wlr.XdgSurface).init(handleUnmap), +destroy: wl.Listener(void) = wl.Listener(void).init(handleDestroy), +map: wl.Listener(void) = wl.Listener(void).init(handleMap), +unmap: wl.Listener(void) = wl.Listener(void).init(handleUnmap), new_popup: wl.Listener(*wlr.XdgPopup) = wl.Listener(*wlr.XdgPopup).init(handleNewPopup), new_subsurface: wl.Listener(*wlr.Subsurface) = wl.Listener(*wlr.Subsurface).init(handleNewSubsurface), @@ -54,42 +53,41 @@ new_subsurface: wl.Listener(*wlr.Subsurface) = wl.Listener(*wlr.Subsurface).init ack_configure: wl.Listener(*wlr.XdgSurface.Configure) = wl.Listener(*wlr.XdgSurface.Configure).init(handleAckConfigure), commit: wl.Listener(*wlr.Surface) = wl.Listener(*wlr.Surface).init(handleCommit), -request_fullscreen: wl.Listener(*wlr.XdgToplevel.event.SetFullscreen) = - wl.Listener(*wlr.XdgToplevel.event.SetFullscreen).init(handleRequestFullscreen), +request_fullscreen: wl.Listener(void) = wl.Listener(void).init(handleRequestFullscreen), request_move: wl.Listener(*wlr.XdgToplevel.event.Move) = wl.Listener(*wlr.XdgToplevel.event.Move).init(handleRequestMove), request_resize: wl.Listener(*wlr.XdgToplevel.event.Resize) = wl.Listener(*wlr.XdgToplevel.event.Resize).init(handleRequestResize), -set_title: wl.Listener(*wlr.XdgSurface) = wl.Listener(*wlr.XdgSurface).init(handleSetTitle), -set_app_id: wl.Listener(*wlr.XdgSurface) = wl.Listener(*wlr.XdgSurface).init(handleSetAppId), +set_title: wl.Listener(void) = wl.Listener(void).init(handleSetTitle), +set_app_id: wl.Listener(void) = wl.Listener(void).init(handleSetAppId), /// The View will add itself to the output's view stack on map -pub fn create(output: *Output, xdg_surface: *wlr.XdgSurface) error{OutOfMemory}!void { +pub fn create(output: *Output, xdg_toplevel: *wlr.XdgToplevel) error{OutOfMemory}!void { const node = try util.gpa.create(ViewStack(View).Node); const view = &node.view; view.init(output, .{ .xdg_toplevel = .{ .view = view, - .xdg_surface = xdg_surface, + .xdg_toplevel = xdg_toplevel, } }); const self = &node.view.impl.xdg_toplevel; - xdg_surface.data = @ptrToInt(self); + xdg_toplevel.base.data = @ptrToInt(self); // Add listeners that are active over the view's entire lifetime - xdg_surface.events.destroy.add(&self.destroy); - xdg_surface.events.map.add(&self.map); - xdg_surface.events.unmap.add(&self.unmap); - xdg_surface.events.new_popup.add(&self.new_popup); - xdg_surface.surface.events.new_subsurface.add(&self.new_subsurface); + xdg_toplevel.base.events.destroy.add(&self.destroy); + xdg_toplevel.base.events.map.add(&self.map); + xdg_toplevel.base.events.unmap.add(&self.unmap); + xdg_toplevel.base.events.new_popup.add(&self.new_popup); + xdg_toplevel.base.surface.events.new_subsurface.add(&self.new_subsurface); - Subsurface.handleExisting(xdg_surface.surface, .{ .xdg_toplevel = self }); + Subsurface.handleExisting(xdg_toplevel.base.surface, .{ .xdg_toplevel = self }); } /// Returns true if a configure must be sent to ensure that the pending /// dimensions are applied. pub fn needsConfigure(self: Self) bool { - const scheduled = &self.xdg_surface.role_data.toplevel.scheduled; + const scheduled = &self.xdg_toplevel.scheduled; const state = &self.view.pending; // We avoid a special case for newly mapped views which we have not yet @@ -100,38 +98,37 @@ pub fn needsConfigure(self: Self) bool { /// Send a configure event, applying the pending state of the view. pub fn configure(self: *Self) void { - const toplevel = self.xdg_surface.role_data.toplevel; const state = &self.view.pending; - self.view.pending_serial = toplevel.setSize(state.box.width, state.box.height); + self.view.pending_serial = self.xdg_toplevel.setSize(state.box.width, state.box.height); self.acked_pending_serial = false; } pub fn lastSetFullscreenState(self: Self) bool { - return self.xdg_surface.role_data.toplevel.scheduled.fullscreen; + return self.xdg_toplevel.scheduled.fullscreen; } /// Close the view. This will lead to the unmap and destroy events being sent pub fn close(self: Self) void { - self.xdg_surface.role_data.toplevel.sendClose(); + self.xdg_toplevel.sendClose(); } pub fn setActivated(self: Self, activated: bool) void { - _ = self.xdg_surface.role_data.toplevel.setActivated(activated); + _ = self.xdg_toplevel.setActivated(activated); } pub fn setFullscreen(self: Self, fullscreen: bool) void { - _ = self.xdg_surface.role_data.toplevel.setFullscreen(fullscreen); + _ = self.xdg_toplevel.setFullscreen(fullscreen); } pub fn setResizing(self: Self, resizing: bool) void { - _ = self.xdg_surface.role_data.toplevel.setResizing(resizing); + _ = self.xdg_toplevel.setResizing(resizing); } /// Return the surface at output coordinates ox, oy and set sx, sy to the /// corresponding surface-relative coordinates, if there is a surface. pub fn surfaceAt(self: Self, ox: f64, oy: f64, sx: *f64, sy: *f64) ?*wlr.Surface { const view = self.view; - return self.xdg_surface.surfaceAt( + return self.xdg_toplevel.base.surfaceAt( ox - @intToFloat(f64, view.current.box.x - view.surface_box.x), oy - @intToFloat(f64, view.current.box.y - view.surface_box.y), sx, @@ -141,26 +138,26 @@ pub fn surfaceAt(self: Self, ox: f64, oy: f64, sx: *f64, sy: *f64) ?*wlr.Surface /// Return the current title of the toplevel if any. pub fn getTitle(self: Self) ?[*:0]const u8 { - return self.xdg_surface.role_data.toplevel.title; + return self.xdg_toplevel.title; } /// Return the current app_id of the toplevel if any . pub fn getAppId(self: Self) ?[*:0]const u8 { - return self.xdg_surface.role_data.toplevel.app_id; + return self.xdg_toplevel.app_id; } /// Return bounds on the dimensions of the toplevel. pub fn getConstraints(self: Self) View.Constraints { - const state = &self.xdg_surface.role_data.toplevel.current; + const state = &self.xdg_toplevel.current; return .{ - .min_width = math.max(state.min_width, 1), - .max_width = if (state.max_width > 0) state.max_width else math.maxInt(u32), - .min_height = math.max(state.min_height, 1), - .max_height = if (state.max_height > 0) state.max_height else math.maxInt(u32), + .min_width = @intCast(u31, math.max(state.min_width, 1)), + .max_width = if (state.max_width > 0) @intCast(u31, state.max_width) else math.maxInt(u31), + .min_height = @intCast(u31, math.max(state.min_height, 1)), + .max_height = if (state.max_height > 0) @intCast(u31, state.max_height) else math.maxInt(u31), }; } -fn handleDestroy(listener: *wl.Listener(*wlr.XdgSurface), _: *wlr.XdgSurface) void { +fn handleDestroy(listener: *wl.Listener(void)) void { const self = @fieldParentPtr(Self, "destroy", listener); // Remove listeners that are active for the entire lifetime of the view @@ -170,55 +167,55 @@ fn handleDestroy(listener: *wl.Listener(*wlr.XdgSurface), _: *wlr.XdgSurface) vo self.new_popup.link.remove(); self.new_subsurface.link.remove(); - Subsurface.destroySubsurfaces(self.xdg_surface.surface); - XdgPopup.destroyPopups(self.xdg_surface); + Subsurface.destroySubsurfaces(self.xdg_toplevel.base.surface); + XdgPopup.destroyPopups(self.xdg_toplevel.base); self.view.destroy(); } -fn handleMap(listener: *wl.Listener(*wlr.XdgSurface), xdg_surface: *wlr.XdgSurface) void { +fn handleMap(listener: *wl.Listener(void)) void { const self = @fieldParentPtr(Self, "map", listener); const view = self.view; - const toplevel = self.xdg_surface.role_data.toplevel; // Add listeners that are only active while mapped - self.xdg_surface.events.ack_configure.add(&self.ack_configure); - self.xdg_surface.surface.events.commit.add(&self.commit); - toplevel.events.request_fullscreen.add(&self.request_fullscreen); - toplevel.events.request_move.add(&self.request_move); - toplevel.events.request_resize.add(&self.request_resize); - toplevel.events.set_title.add(&self.set_title); - toplevel.events.set_app_id.add(&self.set_app_id); + self.xdg_toplevel.base.events.ack_configure.add(&self.ack_configure); + self.xdg_toplevel.base.surface.events.commit.add(&self.commit); + self.xdg_toplevel.events.request_fullscreen.add(&self.request_fullscreen); + self.xdg_toplevel.events.request_move.add(&self.request_move); + self.xdg_toplevel.events.request_resize.add(&self.request_resize); + self.xdg_toplevel.events.set_title.add(&self.set_title); + self.xdg_toplevel.events.set_app_id.add(&self.set_app_id); // Use the view's initial size centered on the output as the default // floating dimensions var initial_box: wlr.Box = undefined; - self.xdg_surface.getGeometry(&initial_box); - view.float_box.width = @intCast(u32, initial_box.width); - view.float_box.height = @intCast(u32, initial_box.height); - view.float_box.x = math.max(0, @divTrunc(@intCast(i32, view.output.usable_box.width) - - @intCast(i32, view.float_box.width), 2)); - view.float_box.y = math.max(0, @divTrunc(@intCast(i32, view.output.usable_box.height) - - @intCast(i32, view.float_box.height), 2)); + self.xdg_toplevel.base.getGeometry(&initial_box); + + view.float_box = .{ + .x = @divTrunc(math.max(0, view.output.usable_box.width - initial_box.width), 2), + .y = @divTrunc(math.max(0, view.output.usable_box.height - initial_box.height), 2), + .width = initial_box.width, + .height = initial_box.height, + }; // We initialize these to avoid special-casing newly mapped views in // the check preformed in needsConfigure(). - toplevel.scheduled.width = @intCast(u32, initial_box.width); - toplevel.scheduled.height = @intCast(u32, initial_box.height); + self.xdg_toplevel.scheduled.width = initial_box.width; + self.xdg_toplevel.scheduled.height = initial_box.height; - view.surface = self.xdg_surface.surface; - view.surface_box = Box.fromWlrBox(initial_box); + view.surface = self.xdg_toplevel.base.surface; + view.surface_box = initial_box; // Also use the view's "natural" size as the initial regular dimensions, // for the case that it does not get arranged by a lyaout. view.pending.box = view.float_box; - const state = &toplevel.current; + const state = &self.xdg_toplevel.current; const has_fixed_size = state.min_width != 0 and state.min_height != 0 and (state.min_width == state.max_width or state.min_height == state.max_height); - if (toplevel.parent != null or has_fixed_size) { - // If the toplevel has a parent or has a fixed size make it float + if (self.xdg_toplevel.parent != null or has_fixed_size) { + // If the self.xdg_toplevel has a parent or has a fixed size make it float view.current.float = true; view.pending.float = true; view.pending.box = view.float_box; @@ -233,17 +230,17 @@ fn handleMap(listener: *wl.Listener(*wlr.XdgSurface), xdg_surface: *wlr.XdgSurfa if (server.config.csdAllowed(view)) { view.draw_borders = false; } else { - _ = toplevel.setTiled(.{ .top = true, .bottom = true, .left = true, .right = true }); + _ = self.xdg_toplevel.setTiled(.{ .top = true, .bottom = true, .left = true, .right = true }); } view.map() catch { log.err("out of memory", .{}); - xdg_surface.resource.getClient().postNoMemory(); + self.xdg_toplevel.resource.getClient().postNoMemory(); }; } /// Called when the surface is unmapped and will no longer be displayed. -fn handleUnmap(listener: *wl.Listener(*wlr.XdgSurface), _: *wlr.XdgSurface) void { +fn handleUnmap(listener: *wl.Listener(void)) void { const self = @fieldParentPtr(Self, "unmap", listener); // Remove listeners that are only active while mapped @@ -274,9 +271,8 @@ fn handleCommit(listener: *wl.Listener(*wlr.Surface), _: *wlr.Surface) void { const self = @fieldParentPtr(Self, "commit", listener); const view = self.view; - var wlr_box: wlr.Box = undefined; - self.xdg_surface.getGeometry(&wlr_box); - const new_box = Box.fromWlrBox(wlr_box); + var new_box: wlr.Box = undefined; + self.xdg_toplevel.base.getGeometry(&new_box); // If we have sent a configure changing the size if (view.pending_serial != null) { @@ -338,13 +334,10 @@ fn handleNewSubsurface(listener: *wl.Listener(*wlr.Subsurface), new_wlr_subsurfa /// Called when the client asks to be fullscreened. We always honor the request /// for now, perhaps it should be denied in some cases in the future. -fn handleRequestFullscreen( - listener: *wl.Listener(*wlr.XdgToplevel.event.SetFullscreen), - event: *wlr.XdgToplevel.event.SetFullscreen, -) void { +fn handleRequestFullscreen(listener: *wl.Listener(void)) void { const self = @fieldParentPtr(Self, "request_fullscreen", listener); - if (self.view.pending.fullscreen != event.fullscreen) { - self.view.pending.fullscreen = event.fullscreen; + if (self.view.pending.fullscreen != self.xdg_toplevel.requested.fullscreen) { + self.view.pending.fullscreen = self.xdg_toplevel.requested.fullscreen; self.view.applyPending(); } } @@ -370,13 +363,13 @@ fn handleRequestResize(listener: *wl.Listener(*wlr.XdgToplevel.event.Resize), ev } /// Called when the client sets / updates its title -fn handleSetTitle(listener: *wl.Listener(*wlr.XdgSurface), _: *wlr.XdgSurface) void { +fn handleSetTitle(listener: *wl.Listener(void)) void { const self = @fieldParentPtr(Self, "set_title", listener); self.view.notifyTitle(); } /// Called when the client sets / updates its app_id -fn handleSetAppId(listener: *wl.Listener(*wlr.XdgSurface), _: *wlr.XdgSurface) void { +fn handleSetAppId(listener: *wl.Listener(void)) void { const self = @fieldParentPtr(Self, "set_app_id", listener); self.view.notifyAppId(); } diff --git a/river/XwaylandOverrideRedirect.zig b/river/XwaylandOverrideRedirect.zig index 3436c4e..9710824 100644 --- a/river/XwaylandOverrideRedirect.zig +++ b/river/XwaylandOverrideRedirect.zig @@ -25,7 +25,6 @@ const wl = @import("wayland").server.wl; const server = &@import("main.zig").server; const util = @import("util.zig"); -const Box = @import("Box.zig"); const View = @import("View.zig"); const XwaylandView = @import("XwaylandView.zig"); const ViewStack = @import("view_stack.zig").ViewStack; diff --git a/river/XwaylandView.zig b/river/XwaylandView.zig index 4a00da3..84c8d7c 100644 --- a/river/XwaylandView.zig +++ b/river/XwaylandView.zig @@ -26,7 +26,6 @@ const wl = @import("wayland").server.wl; const server = &@import("main.zig").server; const util = @import("util.zig"); -const Box = @import("Box.zig"); const Output = @import("Output.zig"); const View = @import("View.zig"); const ViewStack = @import("view_stack.zig").ViewStack; @@ -90,7 +89,8 @@ pub fn create(output: *Output, xwayland_surface: *wlr.XwaylandSurface) error{Out pub fn needsConfigure(self: Self) bool { const output = self.view.output; - const output_box = server.root.output_layout.getBox(output.wlr_output).?; + var output_box: wlr.Box = undefined; + server.root.output_layout.getBox(output.wlr_output, &output_box); return self.xwayland_surface.x != self.view.pending.box.x + output_box.x or self.xwayland_surface.y != self.view.pending.box.y + output_box.y or self.xwayland_surface.width != self.view.pending.box.width or @@ -101,7 +101,8 @@ pub fn needsConfigure(self: Self) bool { /// shouldTrackConfigure() is always false for xwayland views. pub fn configure(self: Self) void { const output = self.view.output; - const output_box = server.root.output_layout.getBox(output.wlr_output).?; + var output_box: wlr.Box = undefined; + server.root.output_layout.getBox(output.wlr_output, &output_box); const state = &self.view.pending; self.xwayland_surface.configure( @@ -161,22 +162,14 @@ pub fn getConstraints(self: Self) View.Constraints { const hints = self.xwayland_surface.size_hints orelse return .{ .min_width = 1, .min_height = 1, - .max_width = math.maxInt(u32), - .max_height = math.maxInt(u32), + .max_width = math.maxInt(u31), + .max_height = math.maxInt(u31), }; return .{ - .min_width = @intCast(u32, math.max(hints.min_width, 1)), - .min_height = @intCast(u32, math.max(hints.min_height, 1)), - - .max_width = if (hints.max_width > 0) - @intCast(u32, hints.max_width) - else - math.maxInt(u32), - - .max_height = if (hints.max_height > 0) - @intCast(u32, hints.max_height) - else - math.maxInt(u32), + .min_width = @intCast(u31, math.max(hints.min_width, 1)), + .min_height = @intCast(u31, math.max(hints.min_height, 1)), + .max_width = if (hints.max_width > 0) @intCast(u31, hints.max_width) else math.maxInt(u31), + .max_height = if (hints.max_height > 0) @intCast(u31, hints.max_height) else math.maxInt(u31), }; } @@ -211,18 +204,18 @@ pub fn handleMap(listener: *wl.Listener(*wlr.XwaylandSurface), xwayland_surface: self.view.surface_box = .{ .x = 0, .y = 0, - .width = @intCast(u32, surface.current.width), - .height = @intCast(u32, surface.current.height), + .width = surface.current.width, + .height = surface.current.height, }; // Use the view's "natural" size centered on the output as the default // floating dimensions - view.float_box.width = self.xwayland_surface.width; - view.float_box.height = self.xwayland_surface.height; - view.float_box.x = math.max(0, @divTrunc(@intCast(i32, view.output.usable_box.width) - - @intCast(i32, view.float_box.width), 2)); - view.float_box.y = math.max(0, @divTrunc(@intCast(i32, view.output.usable_box.height) - - @intCast(i32, view.float_box.height), 2)); + view.float_box = .{ + .x = @divTrunc(math.max(0, view.output.usable_box.width - self.xwayland_surface.width), 2), + .y = @divTrunc(math.max(0, view.output.usable_box.height - self.xwayland_surface.height), 2), + .width = self.xwayland_surface.width, + .height = self.xwayland_surface.height, + }; const has_fixed_size = if (self.xwayland_surface.size_hints) |size_hints| size_hints.min_width != 0 and size_hints.min_height != 0 and @@ -312,8 +305,8 @@ fn handleCommit(listener: *wl.Listener(*wlr.Surface), surface: *wlr.Surface) voi self.view.surface_box = .{ .x = 0, .y = 0, - .width = @intCast(u32, surface.current.width), - .height = @intCast(u32, surface.current.height), + .width = surface.current.width, + .height = surface.current.height, }; } diff --git a/river/command/config.zig b/river/command/config.zig index 3580048..d2d2b43 100644 --- a/river/command/config.zig +++ b/river/command/config.zig @@ -32,7 +32,7 @@ pub fn borderWidth( if (args.len < 2) return Error.NotEnoughArguments; if (args.len > 2) return Error.TooManyArguments; - server.config.border_width = try fmt.parseInt(u32, args[1], 10); + server.config.border_width = try fmt.parseInt(u31, args[1], 10); server.root.arrangeAll(); server.root.startTransaction(); } diff --git a/river/command/filter.zig b/river/command/filter.zig index 678ff62..ad9bef2 100644 --- a/river/command/filter.zig +++ b/river/command/filter.zig @@ -120,7 +120,7 @@ fn csdFilterUpdateViews(kind: FilterKind, pattern: []const u8, operation: enum { const view = @intToPtr(*View, xdg_toplevel_decoration.surface.data); if (viewMatchesPattern(kind, pattern, view)) { - const toplevel = view.impl.xdg_toplevel.xdg_surface.role_data.toplevel; + const toplevel = view.impl.xdg_toplevel.xdg_toplevel; switch (operation) { .add => { _ = xdg_toplevel_decoration.setMode(.client_side); diff --git a/river/command/move.zig b/river/command/move.zig index cc09a54..b621131 100644 --- a/river/command/move.zig +++ b/river/command/move.zig @@ -24,7 +24,6 @@ const PhysicalDirection = @import("../command.zig").PhysicalDirection; const Orientation = @import("../command.zig").Orientation; const Seat = @import("../Seat.zig"); const View = @import("../View.zig"); -const Box = @import("../Box.zig"); pub fn move( seat: *Seat, @@ -61,15 +60,15 @@ pub fn snap( return Error.InvalidPhysicalDirection; const view = getView(seat) orelse return; - const border_width = @intCast(i32, server.config.border_width); - const output_box = view.output.getEffectiveResolution(); + const border_width = server.config.border_width; + var output_width: i32 = undefined; + var output_height: i32 = undefined; + view.output.wlr_output.effectiveResolution(&output_width, &output_height); switch (direction) { .up => view.pending.box.y = border_width, - .down => view.pending.box.y = - @intCast(i32, output_box.height - view.pending.box.height) - border_width, + .down => view.pending.box.y = output_width - view.pending.box.height - border_width, .left => view.pending.box.x = border_width, - .right => view.pending.box.x = - @intCast(i32, output_box.width - view.pending.box.width) - border_width, + .right => view.pending.box.x = output_height - view.pending.box.width - border_width, } apply(view); @@ -88,44 +87,27 @@ pub fn resize( return Error.InvalidOrientation; const view = getView(seat) orelse return; - const border_width = @intCast(i32, server.config.border_width); - const output_box = view.output.getEffectiveResolution(); + var output_width: i32 = undefined; + var output_height: i32 = undefined; + view.output.wlr_output.effectiveResolution(&output_width, &output_height); switch (orientation) { .horizontal => { - var real_delta: i32 = @intCast(i32, view.pending.box.width); - if (delta > 0) { - view.pending.box.width += @intCast(u32, delta); - } else { - // Prevent underflow - view.pending.box.width -= - math.min(view.pending.box.width, @intCast(u32, -1 * delta)); - } + view.pending.box.width += delta; view.applyConstraints(); // Do not grow bigger than the output view.pending.box.width = math.min( view.pending.box.width, - output_box.width - @intCast(u32, 2 * border_width), + output_width - 2 * server.config.border_width, ); - real_delta -= @intCast(i32, view.pending.box.width); - view.move(@divFloor(real_delta, 2), 0); }, .vertical => { - var real_delta: i32 = @intCast(i32, view.pending.box.height); - if (delta > 0) { - view.pending.box.height += @intCast(u32, delta); - } else { - // Prevent underflow - view.pending.box.height -= - math.min(view.pending.box.height, @intCast(u32, -1 * delta)); - } + view.pending.box.height += delta; view.applyConstraints(); // Do not grow bigger than the output view.pending.box.height = math.min( view.pending.box.height, - output_box.height - @intCast(u32, 2 * border_width), + output_height - 2 * server.config.border_width, ); - real_delta -= @intCast(i32, view.pending.box.height); - view.move(0, @divFloor(real_delta, 2)); }, } diff --git a/river/command/output.zig b/river/command/output.zig index 34fa108..da7f921 100644 --- a/river/command/output.zig +++ b/river/command/output.zig @@ -86,12 +86,15 @@ fn getOutput(seat: *Seat, str: []const u8) !?*Output { .previous => if (focused_node.prev) |node| &node.data else &server.root.outputs.last.?.data, }; } else if (std.meta.stringToEnum(wlr.OutputLayout.Direction, str)) |direction| { // Spacial direction - const focus_box = server.root.output_layout.getBox(seat.focused_output.wlr_output) orelse return null; + var focus_box: wlr.Box = undefined; + server.root.output_layout.getBox(seat.focused_output.wlr_output, &focus_box); + if (focus_box.empty()) return null; + const wlr_output = server.root.output_layout.adjacentOutput( direction, seat.focused_output.wlr_output, - @intToFloat(f64, focus_box.x + @divFloor(focus_box.width, 2)), - @intToFloat(f64, focus_box.y + @divFloor(focus_box.height, 2)), + @intToFloat(f64, focus_box.x + @divTrunc(focus_box.width, 2)), + @intToFloat(f64, focus_box.y + @divTrunc(focus_box.height, 2)), ) orelse return null; return @intToPtr(*Output, wlr_output.data); } else { diff --git a/river/command/set_repeat.zig b/river/command/set_repeat.zig index 86f8730..e58908f 100644 --- a/river/command/set_repeat.zig +++ b/river/command/set_repeat.zig @@ -39,7 +39,7 @@ pub fn setRepeat( var it = server.input_manager.devices.iterator(.forward); while (it.next()) |device| { if (device.wlr_device.type == .keyboard) { - device.wlr_device.device.keyboard.setRepeatInfo(rate, delay); + device.wlr_device.toKeyboard().setRepeatInfo(rate, delay); } } } diff --git a/river/command/toggle_fullscreen.zig b/river/command/toggle_fullscreen.zig index a4ae724..3f2d5f9 100644 --- a/river/command/toggle_fullscreen.zig +++ b/river/command/toggle_fullscreen.zig @@ -18,7 +18,6 @@ const std = @import("std"); const server = &@import("../main.zig").server; -const Box = @import("../Box.zig"); const Error = @import("../command.zig").Error; const Seat = @import("../Seat.zig"); diff --git a/river/render.zig b/river/render.zig index 96ab4a5..31a43b2 100644 --- a/river/render.zig +++ b/river/render.zig @@ -24,7 +24,6 @@ const pixman = @import("pixman"); const server = &@import("main.zig").server; const util = @import("util.zig"); -const Box = @import("Box.zig"); const LayerSurface = @import("LayerSurface.zig"); const Output = @import("Output.zig"); const Server = @import("Server.zig"); @@ -201,8 +200,8 @@ fn renderView(output: *const Output, view: *View, now: *os.timespec) void { .{ .x = saved_buffer.surface_box.x + view.current.box.x - view.saved_surface_box.x, .y = saved_buffer.surface_box.y + view.current.box.y - view.saved_surface_box.y, - .width = @intCast(c_int, saved_buffer.surface_box.width), - .height = @intCast(c_int, saved_buffer.surface_box.height), + .width = saved_buffer.surface_box.width, + .height = saved_buffer.surface_box.height, }, &saved_buffer.source_box, saved_buffer.transform, @@ -223,7 +222,8 @@ fn renderView(output: *const Output, view: *View, now: *os.timespec) void { } fn renderDragIcons(output: *const Output, now: *os.timespec) void { - const output_box = server.root.output_layout.getBox(output.wlr_output).?; + var output_box: wlr.Box = undefined; + server.root.output_layout.getBox(output.wlr_output, &output_box); var it = server.root.drag_icons.first; while (it) |node| : (it = node.next) { @@ -243,7 +243,8 @@ fn renderDragIcons(output: *const Output, now: *os.timespec) void { /// Render all override redirect xwayland windows that appear on the output fn renderXwaylandOverrideRedirect(output: *const Output, now: *os.timespec) void { - const output_box = server.root.output_layout.getBox(output.wlr_output).?; + var output_box: wlr.Box = undefined; + server.root.output_layout.getBox(output.wlr_output, &output_box); var it = server.root.xwayland_override_redirect_views.last; while (it) |node| : (it = node.prev) { @@ -321,42 +322,41 @@ fn renderBorders(output: *const Output, view: *View) void { if (view.current.focus != 0) break :blk &config.border_color_focused; break :blk &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; - var border: Box = undefined; + var border: wlr.Box = undefined; // left and right, covering the corners as well - border.y = view.current.box.y - @intCast(i32, border_width); - border.width = border_width; - border.height = actual_box.height + border_width * 2; + border.y = view.current.box.y - config.border_width; + border.width = config.border_width; + border.height = actual_box.height + config.border_width * 2; // left - border.x = view.current.box.x - @intCast(i32, border_width); + border.x = view.current.box.x - config.border_width; renderRect(output, border, color); // right - border.x = view.current.box.x + @intCast(i32, actual_box.width); + border.x = view.current.box.x + actual_box.width; renderRect(output, border, color); // top and bottom border.x = view.current.box.x; border.width = actual_box.width; - border.height = border_width; + border.height = config.border_width; // top - border.y = view.current.box.y - @intCast(i32, border_width); + border.y = view.current.box.y - config.border_width; renderRect(output, border, color); // bottom border - border.y = view.current.box.y + @intCast(i32, actual_box.height); + border.y = view.current.box.y + actual_box.height; renderRect(output, border, color); } -fn renderRect(output: *const Output, box: Box, color: *const [4]f32) void { - var wlr_box = box.toWlrBox(); - scaleBox(&wlr_box, output.wlr_output.scale); - server.renderer.renderRect(&wlr_box, color, &output.wlr_output.transform_matrix); +fn renderRect(output: *const Output, box: wlr.Box, color: *const [4]f32) void { + var scaled = box; + scaleBox(&scaled, output.wlr_output.scale); + server.renderer.renderRect(&scaled, color, &output.wlr_output.transform_matrix); } /// Scale a wlr_box, taking the possibility of fractional scaling into account.