Fix wallpaper and bar rendering when scale >1
We track the scale for wallpaper and render now and have to re-render when the scale changes. For the bar, this includes recreated the fcft fonts.
This commit is contained in:
parent
1cfafc4fb3
commit
83946ce97a
5 changed files with 77 additions and 18 deletions
|
|
@ -3,7 +3,7 @@
|
||||||
These are in rough order of my priority, though no promises I do them in this order.
|
These are in rough order of my priority, though no promises I do them in this order.
|
||||||
|
|
||||||
- [ ] Implement a river-tag-overlay clone
|
- [ ] Implement a river-tag-overlay clone
|
||||||
- [ ] Implement an optional clock bar
|
- [ ] Add options to the bar and river-tag-overlay
|
||||||
- [ ] Make a Rect struct to combine x, y, width, and height
|
- [ ] 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
|
||||||
|
|
@ -28,3 +28,4 @@ These are in rough order of my priority, though no promises I do them in this or
|
||||||
- [x] Support per-host config using properties
|
- [x] Support per-host config using properties
|
||||||
- [x] Implement primary count/ratio per tagmask
|
- [x] Implement primary count/ratio per tagmask
|
||||||
- [x] Add primary_count and primary_ratio to Config
|
- [x] Add primary_count and primary_ratio to Config
|
||||||
|
- [x] Implement an optional clock bar
|
||||||
|
|
|
||||||
44
src/Bar.zig
44
src/Bar.zig
|
|
@ -4,14 +4,17 @@
|
||||||
|
|
||||||
const Bar = @This();
|
const Bar = @This();
|
||||||
|
|
||||||
|
/// Standard base DPI at a scale of 1
|
||||||
|
const base_dpi = 96;
|
||||||
|
|
||||||
context: *Context,
|
context: *Context,
|
||||||
|
|
||||||
// TODO: Get this in Config then save in Context
|
|
||||||
fonts: *fcft.Font,
|
|
||||||
/// The timezone of the computer.
|
/// The timezone of the computer.
|
||||||
timezone: zeit.timezone.TimeZone,
|
timezone: zeit.timezone.TimeZone,
|
||||||
|
|
||||||
/// The output that this Bar is on
|
fonts: *fcft.Font,
|
||||||
|
font_scale: u31 = 0,
|
||||||
|
|
||||||
output: *Output,
|
output: *Output,
|
||||||
|
|
||||||
// Bar geometry
|
// Bar geometry
|
||||||
|
|
@ -34,7 +37,7 @@ pub fn init(context: *Context, output: *Output) !Bar {
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
.context = context,
|
.context = context,
|
||||||
.fonts = try getFcftFonts("monospace:size=14"),
|
.fonts = try getFcftFonts("monospace:size=14", 1),
|
||||||
.timezone = timezone,
|
.timezone = timezone,
|
||||||
.output = output,
|
.output = output,
|
||||||
};
|
};
|
||||||
|
|
@ -50,8 +53,8 @@ pub fn initSurface(bar: *Bar) !void {
|
||||||
const context = bar.context;
|
const context = bar.context;
|
||||||
|
|
||||||
// TODO: Add padding to config
|
// TODO: Add padding to config
|
||||||
const padding = 5;
|
const vertical_padding = 5;
|
||||||
const bar_height: u31 = @intCast(bar.fonts.height + 2 * padding);
|
const bar_height: u31 = @intCast(bar.fonts.height + 2 * vertical_padding);
|
||||||
|
|
||||||
const wl_surface = try context.wl_compositor.createSurface();
|
const wl_surface = try context.wl_compositor.createSurface();
|
||||||
errdefer wl_surface.destroy();
|
errdefer wl_surface.destroy();
|
||||||
|
|
@ -99,7 +102,11 @@ pub fn layerSurfaceListener(
|
||||||
const width: u31 = @intCast(ev.width);
|
const width: u31 = @intCast(ev.width);
|
||||||
const height: u31 = @intCast(ev.height);
|
const height: u31 = @intCast(ev.height);
|
||||||
|
|
||||||
if (bar.configured and bar.width == width and bar.height == height) {
|
if (bar.configured and
|
||||||
|
bar.width == width and
|
||||||
|
bar.height == height and
|
||||||
|
bar.output.scale == bar.font_scale)
|
||||||
|
{
|
||||||
if (bar.wl_surface) |wl_surface| {
|
if (bar.wl_surface) |wl_surface| {
|
||||||
wl_surface.commit();
|
wl_surface.commit();
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -143,6 +150,13 @@ pub fn render(bar: *Bar) !void {
|
||||||
|
|
||||||
const scale = bar.output.scale;
|
const scale = bar.output.scale;
|
||||||
|
|
||||||
|
// Recreate fonts at the output's new scale
|
||||||
|
if (scale != bar.font_scale) {
|
||||||
|
bar.fonts.destroy();
|
||||||
|
bar.fonts = try getFcftFonts("monospace:size=14", scale);
|
||||||
|
bar.font_scale = scale;
|
||||||
|
}
|
||||||
|
|
||||||
// Scaled width/height
|
// Scaled width/height
|
||||||
const render_width = bar.width * scale;
|
const render_width = bar.width * scale;
|
||||||
const render_height = bar.height * scale;
|
const render_height = bar.height * scale;
|
||||||
|
|
@ -210,8 +224,9 @@ pub fn render(bar: *Bar) !void {
|
||||||
|
|
||||||
// Finally, attach the buffer to the surface
|
// Finally, attach the buffer to the surface
|
||||||
const wl_surface = bar.wl_surface orelse return;
|
const wl_surface = bar.wl_surface orelse return;
|
||||||
|
wl_surface.setBufferScale(scale);
|
||||||
wl_surface.attach(buffer.wl_buffer, 0, 0);
|
wl_surface.attach(buffer.wl_buffer, 0, 0);
|
||||||
wl_surface.damageBuffer(0, 0, bar.width, bar.height);
|
wl_surface.damageBuffer(0, 0, render_width, render_height);
|
||||||
wl_surface.commit();
|
wl_surface.commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -318,8 +333,8 @@ fn renderGlyphs(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Borrowed from https://git.sr.ht/~novakane/zig-fcft-example
|
// Borrowed and modified from https://git.sr.ht/~novakane/zig-fcft-example
|
||||||
fn getFcftFonts(fonts: []const u8) !*fcft.Font {
|
fn getFcftFonts(fonts: []const u8, scale: u31) !*fcft.Font {
|
||||||
// Create an arena to free just for this function;
|
// Create an arena to free just for this function;
|
||||||
// It makes cleaning up the ArrayList easier.
|
// It makes cleaning up the ArrayList easier.
|
||||||
var arena = std.heap.ArenaAllocator.init(utils.gpa);
|
var arena = std.heap.ArenaAllocator.init(utils.gpa);
|
||||||
|
|
@ -330,8 +345,17 @@ fn getFcftFonts(fonts: []const u8) !*fcft.Font {
|
||||||
|
|
||||||
var it = mem.tokenizeScalar(u8, fonts, ',');
|
var it = mem.tokenizeScalar(u8, fonts, ',');
|
||||||
while (it.next()) |font| {
|
while (it.next()) |font| {
|
||||||
|
if (scale > 1) {
|
||||||
|
// If scale >1, we append :dpi so we can scale the font
|
||||||
|
const scaled = try arena_alloc.dupeZ(
|
||||||
|
u8,
|
||||||
|
try std.fmt.allocPrint(arena_alloc, "{s}:dpi={}", .{ font, @as(u32, base_dpi) * scale }),
|
||||||
|
);
|
||||||
|
try list.append(arena_alloc, scaled);
|
||||||
|
} else {
|
||||||
try list.append(arena_alloc, try arena_alloc.dupeZ(u8, font));
|
try list.append(arena_alloc, try arena_alloc.dupeZ(u8, font));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const fcft_fonts = try fcft.Font.fromName(list.items[0..], null);
|
const fcft_fonts = try fcft.Font.fromName(list.items[0..], null);
|
||||||
errdefer fcft_fonts.destroy();
|
errdefer fcft_fonts.destroy();
|
||||||
|
|
|
||||||
|
|
@ -477,7 +477,22 @@ fn loadKeybindsChildBlock(config: *Config, parser: *kdl.Parser, hostname: ?[]con
|
||||||
logWarnMissingNodeArg(name, "command");
|
logWarnMissingNodeArg(name, "command");
|
||||||
continue;
|
continue;
|
||||||
});
|
});
|
||||||
const split_exec = try utils.tokenizeToOwnedSlices(exec_str, ' ');
|
var split_exec = try utils.tokenizeToOwnedSlices(exec_str, ' ');
|
||||||
|
if (split_exec.len > 0) {
|
||||||
|
// Expand ~ in executable paths
|
||||||
|
const expanded = expandTilde(split_exec[0]) catch |e| {
|
||||||
|
if (e == error.HomeNotSet) {
|
||||||
|
// No ~, just return what we had.
|
||||||
|
break :sw .{ .spawn = split_exec };
|
||||||
|
} else {
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// tokenizeToOwnedSlices dupes each token, so we have to
|
||||||
|
// free the original value before replacing it.
|
||||||
|
utils.gpa.free(split_exec[0]);
|
||||||
|
split_exec[0] = expanded;
|
||||||
|
}
|
||||||
break :sw .{ .spawn = split_exec };
|
break :sw .{ .spawn = split_exec };
|
||||||
},
|
},
|
||||||
.change_ratio => {
|
.change_ratio => {
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ usable_width: u31 = 0,
|
||||||
usable_height: u31 = 0,
|
usable_height: u31 = 0,
|
||||||
|
|
||||||
// Information for this Output's wallpaper
|
// Information for this Output's wallpaper
|
||||||
|
wallpaper_render_scale: u31 = 0,
|
||||||
wallpaper_render_width: u31 = 0,
|
wallpaper_render_width: u31 = 0,
|
||||||
wallpaper_render_height: u31 = 0,
|
wallpaper_render_height: u31 = 0,
|
||||||
wl_surface: ?*wl.Surface = null,
|
wl_surface: ?*wl.Surface = null,
|
||||||
|
|
@ -265,6 +266,18 @@ fn wlOutputListener(_: *wl.Output, event: wl.Output.Event, output: *Output) void
|
||||||
log.err("failed to init bar for {s}: {}", .{ output_name, err });
|
log.err("failed to init bar for {s}: {}", .{ output_name, err });
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
// Re-render bar if the scale changed
|
||||||
|
if (bar.configured and output.scale != bar.font_scale) {
|
||||||
|
bar.render() catch |err| {
|
||||||
|
log.err("Bar render failed: {}", .{err});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Re-render wallpaper if scale changed
|
||||||
|
if (output.configured and output.scale != output.wallpaper_render_scale) {
|
||||||
|
output.renderWallpaper() catch |err| {
|
||||||
|
log.err("Wallpaper render failed: {}", .{err});
|
||||||
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.scale => |ev| {
|
.scale => |ev| {
|
||||||
|
|
@ -361,7 +374,11 @@ fn wallpaperLayerSurfaceListener(layer_surface: *zwlr.LayerSurfaceV1, event: zwl
|
||||||
const width: u31 = @intCast(ev.width);
|
const width: u31 = @intCast(ev.width);
|
||||||
const height: u31 = @intCast(ev.height);
|
const height: u31 = @intCast(ev.height);
|
||||||
|
|
||||||
if (output.configured and output.wallpaper_render_width == width and output.wallpaper_render_height == height) {
|
if (output.configured and
|
||||||
|
output.wallpaper_render_width == width and
|
||||||
|
output.wallpaper_render_height == height and
|
||||||
|
output.scale == output.wallpaper_render_scale)
|
||||||
|
{
|
||||||
if (output.wl_surface) |wl_surface| {
|
if (output.wl_surface) |wl_surface| {
|
||||||
wl_surface.commit();
|
wl_surface.commit();
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -393,7 +410,7 @@ fn calculateScale(image_dimension: c_int, output_dimension: u31, scale: u31) f64
|
||||||
return numerator / denominator;
|
return numerator / denominator;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Calculates (image_dimension / dimension_scale - output_dimension) / 2 / dimension_scale;
|
/// Calculates (image_dimension / dimension_scale - output_dimension) / 2 / dimension_scale
|
||||||
fn calculateTransform(image_dimension: c_int, output_dimension: u31, dimension_scale: f64) f64 {
|
fn calculateTransform(image_dimension: c_int, output_dimension: u31, dimension_scale: f64) f64 {
|
||||||
const numerator1: f64 = @floatFromInt(image_dimension);
|
const numerator1: f64 = @floatFromInt(image_dimension);
|
||||||
const denominator1: f64 = dimension_scale;
|
const denominator1: f64 = dimension_scale;
|
||||||
|
|
@ -441,8 +458,8 @@ pub fn renderWallpaper(output: *Output) !void {
|
||||||
|
|
||||||
// Calculate translation offsets to center the image on the output.
|
// Calculate translation offsets to center the image on the output.
|
||||||
// If the scaled image is larger than the output, the offset crops equally from both sides.
|
// If the scaled image is larger than the output, the offset crops equally from both sides.
|
||||||
const tx: f64 = calculateTransform(image_width, width, sx);
|
const tx: f64 = calculateTransform(image_width, width * scale, sx);
|
||||||
const ty: f64 = calculateTransform(image_height, height, sy);
|
const ty: f64 = calculateTransform(image_height, height * scale, sy);
|
||||||
|
|
||||||
// Build a combined source-to-destination transform matrix.
|
// Build a combined source-to-destination transform matrix.
|
||||||
// Pixman transforms map destination pixels back to source pixels, so:
|
// Pixman transforms map destination pixels back to source pixels, so:
|
||||||
|
|
@ -473,6 +490,8 @@ pub fn renderWallpaper(output: *Output) !void {
|
||||||
wl_surface.attach(buffer.wl_buffer, 0, 0);
|
wl_surface.attach(buffer.wl_buffer, 0, 0);
|
||||||
wl_surface.damageBuffer(0, 0, width * scale, height * scale);
|
wl_surface.damageBuffer(0, 0, width * scale, height * scale);
|
||||||
wl_surface.commit();
|
wl_surface.commit();
|
||||||
|
|
||||||
|
output.wallpaper_render_scale = scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn manage(output: *Output) void {
|
pub fn manage(output: *Output) void {
|
||||||
|
|
|
||||||
|
|
@ -103,7 +103,7 @@ pub fn parseModifiers(s: []const u8) !?river.SeatV1.Modifiers {
|
||||||
return modifiers;
|
return modifiers;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tokenizeToOwnedSlices(input: []const u8, delimiter: u8) ![]const []const u8 {
|
pub fn tokenizeToOwnedSlices(input: []const u8, delimiter: u8) ![][]const u8 {
|
||||||
var list: std.ArrayList([]const u8) = .empty;
|
var list: std.ArrayList([]const u8) = .empty;
|
||||||
var it = std.mem.tokenizeScalar(u8, input, delimiter);
|
var it = std.mem.tokenizeScalar(u8, input, delimiter);
|
||||||
while (it.next()) |part| {
|
while (it.next()) |part| {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue