diff --git a/river/Config.zig b/river/Config.zig index 8028009..1be9ba0 100644 --- a/river/Config.zig +++ b/river/Config.zig @@ -52,6 +52,9 @@ modes: std.ArrayList(std.ArrayList(Mapping)), /// List of app_ids which will be started floating float_filter: std.ArrayList([*:0]const u8), +/// List of app_ids which are allowed to use client side decorations +csd_filter: std.ArrayList([]const u8), + pub fn init(self: *Self) !void { self.background_color = [_]f32{ 0.0, 0.16862745, 0.21176471, 1.0 }; // Solarized base03 self.border_width = 2; @@ -73,8 +76,14 @@ pub fn init(self: *Self) !void { self.float_filter = std.ArrayList([*:0]const u8).init(util.gpa); errdefer self.float_filter.deinit(); + self.csd_filter = std.ArrayList([]const u8).init(util.gpa); + errdefer self.csd_filter.deinit(); + // Float views with app_id "float" try self.float_filter.append("float"); + + // Client side decorations for views with app_id "csd" + try self.csd_filter.append("csd"); } pub fn deinit(self: Self) void { @@ -89,4 +98,5 @@ pub fn deinit(self: Self) void { self.modes.deinit(); self.float_filter.deinit(); + self.csd_filter.deinit(); } diff --git a/river/Decoration.zig b/river/Decoration.zig index 44f48c2..7223117 100644 --- a/river/Decoration.zig +++ b/river/Decoration.zig @@ -22,6 +22,10 @@ const std = @import("std"); const c = @import("c.zig"); const util = @import("util.zig"); +const Server = @import("Server.zig"); + +server: *Server, + wlr_xdg_toplevel_decoration: *c.wlr_xdg_toplevel_decoration_v1, listen_destroy: c.wl_listener, @@ -29,8 +33,11 @@ listen_request_mode: c.wl_listener, pub fn init( self: *Self, + server: *Server, wlr_xdg_toplevel_decoration: *c.wlr_xdg_toplevel_decoration_v1, ) void { + self.server = server; + self.wlr_xdg_toplevel_decoration = wlr_xdg_toplevel_decoration; self.listen_destroy.notify = handleDestroy; @@ -49,8 +56,24 @@ fn handleDestroy(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void { fn handleRequestMode(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void { const self = @fieldParentPtr(Self, "listen_request_mode", listener.?); - _ = c.wlr_xdg_toplevel_decoration_v1_set_mode( - self.wlr_xdg_toplevel_decoration, - .WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE, - ); + + const wlr_xdg_surface: *c.wlr_xdg_surface = self.wlr_xdg_toplevel_decoration.surface; + const wlr_xdg_toplevel: *c.wlr_xdg_toplevel = @field(wlr_xdg_surface, c.wlr_xdg_surface_union).toplevel; + const app_id: [*:0]const u8 = if (wlr_xdg_toplevel.app_id) |id| id else "NULL"; + + const use_csd = for (self.server.config.csd_filter.items) |filter_app_id| { + if (std.mem.eql(u8, std.mem.span(app_id), filter_app_id)) break true; + } else false; + + if (use_csd) { + _ = c.wlr_xdg_toplevel_decoration_v1_set_mode( + self.wlr_xdg_toplevel_decoration, + .WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE, + ); + } else { + _ = c.wlr_xdg_toplevel_decoration_v1_set_mode( + self.wlr_xdg_toplevel_decoration, + .WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE, + ); + } } diff --git a/river/DecorationManager.zig b/river/DecorationManager.zig index b44dcef..aa191d7 100644 --- a/river/DecorationManager.zig +++ b/river/DecorationManager.zig @@ -25,6 +25,8 @@ const util = @import("util.zig"); const Decoration = @import("Decoration.zig"); const Server = @import("Server.zig"); +server: *Server, + wlr_xdg_decoration_manager: *c.wlr_xdg_decoration_manager_v1, decorations: std.SinglyLinkedList(Decoration), @@ -35,6 +37,8 @@ pub fn init(self: *Self, server: *Server) !void { self.wlr_xdg_decoration_manager = c.wlr_xdg_decoration_manager_v1_create(server.wl_display) orelse return error.OutOfMemory; + self.server = server; + self.listen_new_toplevel_decoration.notify = handleNewToplevelDecoration; c.wl_signal_add( &self.wlr_xdg_decoration_manager.events.new_toplevel_decoration, @@ -50,5 +54,5 @@ fn handleNewToplevelDecoration(listener: ?*c.wl_listener, data: ?*c_void) callco c.wl_resource_post_no_memory(wlr_xdg_toplevel_decoration.resource); return; }; - decoration.init(wlr_xdg_toplevel_decoration); + decoration.init(self.server, wlr_xdg_toplevel_decoration); } diff --git a/river/View.zig b/river/View.zig index cdd7d02..b405602 100644 --- a/river/View.zig +++ b/river/View.zig @@ -89,6 +89,8 @@ saved_buffers: std.ArrayList(SavedBuffer), /// view returns to floating mode. float_box: Box, +draw_borders: bool, + pub fn init(self: *Self, output: *Output, tags: u32, surface: var) void { self.output = output; @@ -113,6 +115,8 @@ pub fn init(self: *Self, output: *Output, tags: u32, surface: var) void { self.saved_buffers = std.ArrayList(SavedBuffer).init(util.gpa); + self.draw_borders = true; + if (@TypeOf(surface) == *c.wlr_xdg_surface) { self.impl = .{ .xdg_toplevel = undefined }; self.impl.xdg_toplevel.init(self, surface); diff --git a/river/XdgToplevel.zig b/river/XdgToplevel.zig index 2ef46d3..3dfe837 100644 --- a/river/XdgToplevel.zig +++ b/river/XdgToplevel.zig @@ -189,13 +189,23 @@ fn handleMap(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void { } } - // If the toplevel has no parent, inform it that it is tiled. This + // If the toplevel has no parent and has an app_id which is not configured + // to use client side decorations, inform it that it is tiled. This // prevents firefox, for example, from drawing shadows around itself. - if (wlr_xdg_toplevel.parent == null) - _ = c.wlr_xdg_toplevel_set_tiled( - self.wlr_xdg_surface, - c.WLR_EDGE_LEFT | c.WLR_EDGE_RIGHT | c.WLR_EDGE_TOP | c.WLR_EDGE_BOTTOM, - ); + if (wlr_xdg_toplevel.parent == null) { + const use_csd = for (root.server.config.csd_filter.items) |filter_app_id| { + if (std.mem.eql(u8, std.mem.span(app_id), filter_app_id)) break true; + } else false; + + if (use_csd) { + view.draw_borders = false; + } else { + _ = c.wlr_xdg_toplevel_set_tiled( + self.wlr_xdg_surface, + c.WLR_EDGE_LEFT | c.WLR_EDGE_RIGHT | c.WLR_EDGE_TOP | c.WLR_EDGE_BOTTOM, + ); + } + } view.map(); } diff --git a/river/render.zig b/river/render.zig index 16d9d97..0ef67b5 100644 --- a/river/render.zig +++ b/river/render.zig @@ -88,7 +88,7 @@ pub fn renderOutput(output: *Output) void { if (view.focused) continue; renderView(output.*, view, &now); - renderBorders(output.*, view, &now); + if (view.draw_borders) renderBorders(output.*, view, &now); } // Render focused views @@ -104,7 +104,7 @@ pub fn renderOutput(output: *Output) void { if (!view.focused) continue; renderView(output.*, view, &now); - renderBorders(output.*, view, &now); + if (view.draw_borders) renderBorders(output.*, view, &now); } if (build_options.xwayland) renderXwaylandUnmanaged(output.*, &now);