Finish wiring up the TagOverlay
We had to fix a couple of compile errors that weren't showing while it wasn't wired up (since I never just tried to compile TagOverlay.zig on its own). We also changed the lifecycle to re-create/destroy the surface to show/hide it, similar to the way that river-tag-overlay actually did it. Finally, I added @branchHint(.cold) to a few places in the event loop where, if we're in the branch, the wm is definitely exiting, so it's fine if they're cold (should almost never happen).
This commit is contained in:
parent
2bef233d8f
commit
dbf32e793c
7 changed files with 158 additions and 23 deletions
|
|
@ -15,6 +15,7 @@ These are in rough order of my priority, though no promises I do them in this or
|
||||||
- [ ] Save window positions between restarts
|
- [ ] Save window positions between restarts
|
||||||
- [ ] Support multiple seats
|
- [ ] Support multiple seats
|
||||||
- [ ] Support clipping floating windows on edge of/between outputs
|
- [ ] Support clipping floating windows on edge of/between outputs
|
||||||
|
- [ ] Use per-output timerfds for tag overlay instead of a single shared one
|
||||||
- [x] Support changeable primary ratio
|
- [x] Support changeable primary ratio
|
||||||
- [x] Support changeable primary count
|
- [x] Support changeable primary count
|
||||||
- [x] Support multiple outputs
|
- [x] Support multiple outputs
|
||||||
|
|
|
||||||
|
|
@ -111,10 +111,10 @@ pub fn borderedRectangle(
|
||||||
const render_border_width: u16 = @intCast(border_width * scale);
|
const render_border_width: u16 = @intCast(border_width * scale);
|
||||||
|
|
||||||
// Background fill
|
// Background fill
|
||||||
_ = pixman.Image.fillRectangles(.src, buffer.image, background_color, 1, &[1]pixman.Rectangle16{.{ .x = render_x, .y = render_y, .width = render_width, .height = render_height }});
|
_ = pixman.Image.fillRectangles(.src, buffer.pixman_image, background_color, 1, &[1]pixman.Rectangle16{.{ .x = render_x, .y = render_y, .width = render_width, .height = render_height }});
|
||||||
|
|
||||||
// Border: top, bottom, left, right
|
// Border: top, bottom, left, right
|
||||||
_ = pixman.Image.fillRectangles(.src, buffer.image, border_color, 4, &[4]pixman.Rectangle16{
|
_ = pixman.Image.fillRectangles(.src, buffer.pixman_image, border_color, 4, &[4]pixman.Rectangle16{
|
||||||
.{
|
.{
|
||||||
.x = render_x,
|
.x = render_x,
|
||||||
.y = render_y,
|
.y = render_y,
|
||||||
|
|
|
||||||
|
|
@ -117,8 +117,8 @@ pub const TagOverlayConfig = struct {
|
||||||
pub fn toTagOverlayOptions(self: TagOverlayConfig) TagOverlay.Options {
|
pub fn toTagOverlayOptions(self: TagOverlayConfig) TagOverlay.Options {
|
||||||
return .{
|
return .{
|
||||||
.border_width = self.border_width,
|
.border_width = self.border_width,
|
||||||
.tag_amount = @intCast(std.math.clamp(@as(u32, self.tag_amount), 1, 32) - 1),
|
.tag_amount = @intCast(std.math.clamp(@as(u32, self.tag_amount), 1, 32)),
|
||||||
.tags_per_row = @intCast(std.math.clamp(@as(u32, self.tags_per_row), 1, 32) - 1),
|
.tags_per_row = @intCast(std.math.clamp(@as(u32, self.tags_per_row), 1, 32)),
|
||||||
.square_size = self.square_size,
|
.square_size = self.square_size,
|
||||||
.square_inner_padding = self.square_inner_padding,
|
.square_inner_padding = self.square_inner_padding,
|
||||||
.square_padding = self.square_padding,
|
.square_padding = self.square_padding,
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,10 @@ wallpaper_image: ?*WallpaperImage,
|
||||||
// WM Configuration
|
// WM Configuration
|
||||||
config: *Config,
|
config: *Config,
|
||||||
|
|
||||||
|
/// Shared timerfd for hiding tag overlays after their timeout expires.
|
||||||
|
/// This stays null if no tag overlays exist.
|
||||||
|
tag_overlay_timer_fd: ?posix.fd_t,
|
||||||
|
|
||||||
/// State consumed in manage() phase, reset at end of manage().
|
/// State consumed in manage() phase, reset at end of manage().
|
||||||
pending_manage: PendingManage = .{},
|
pending_manage: PendingManage = .{},
|
||||||
|
|
||||||
|
|
@ -74,6 +78,14 @@ pub fn create(options: Options) !*Context {
|
||||||
const env = try process.getEnvMap(utils.gpa);
|
const env = try process.getEnvMap(utils.gpa);
|
||||||
errdefer env.deinit();
|
errdefer env.deinit();
|
||||||
|
|
||||||
|
const tag_overlay_timer_fd: ?posix.fd_t = if (options.config.tag_overlay) |_|
|
||||||
|
posix.timerfd_create(.MONOTONIC, .{ .CLOEXEC = true }) catch |e| blk: {
|
||||||
|
log.err("Failed to create tag overlay timer: {}", .{e});
|
||||||
|
break :blk null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
null;
|
||||||
|
|
||||||
context.* = .{
|
context.* = .{
|
||||||
.initialized = false,
|
.initialized = false,
|
||||||
.env = env,
|
.env = env,
|
||||||
|
|
@ -89,6 +101,7 @@ pub fn create(options: Options) !*Context {
|
||||||
.wm = wm,
|
.wm = wm,
|
||||||
.xkb_bindings = xkb_bindings,
|
.xkb_bindings = xkb_bindings,
|
||||||
.config = options.config,
|
.config = options.config,
|
||||||
|
.tag_overlay_timer_fd = tag_overlay_timer_fd,
|
||||||
};
|
};
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
|
|
@ -103,6 +116,7 @@ pub fn destroy(context: *Context) void {
|
||||||
if (context.wallpaper_image) |wallpaper_image| {
|
if (context.wallpaper_image) |wallpaper_image| {
|
||||||
wallpaper_image.destroy();
|
wallpaper_image.destroy();
|
||||||
}
|
}
|
||||||
|
if (context.tag_overlay_timer_fd) |fd| posix.close(fd);
|
||||||
context.buffer_pool.deinit();
|
context.buffer_pool.deinit();
|
||||||
|
|
||||||
utils.gpa.destroy(context);
|
utils.gpa.destroy(context);
|
||||||
|
|
@ -135,6 +149,42 @@ pub fn manage(context: *Context) void {
|
||||||
libinput_device.should_manage = true;
|
libinput_device.should_manage = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle tag overlay config changes
|
||||||
|
const had_overlay = context.config.tag_overlay != null;
|
||||||
|
const has_overlay = new_config.tag_overlay != null;
|
||||||
|
|
||||||
|
if (!had_overlay and has_overlay) {
|
||||||
|
// Create timerfd for newly enabled tag overlay
|
||||||
|
context.tag_overlay_timer_fd = posix.timerfd_create(.MONOTONIC, .{ .CLOEXEC = true }) catch |e| blk: {
|
||||||
|
log.err("Failed to create tag overlay timer: {}", .{e});
|
||||||
|
break :blk null;
|
||||||
|
};
|
||||||
|
} else if (had_overlay and !has_overlay) {
|
||||||
|
// Close timerfd for disabled tag overlay
|
||||||
|
if (context.tag_overlay_timer_fd) |fd| posix.close(fd);
|
||||||
|
context.tag_overlay_timer_fd = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recreate or destroy tag overlays on all outputs
|
||||||
|
if (had_overlay or has_overlay) {
|
||||||
|
var out_it = context.wm.outputs.iterator(.forward);
|
||||||
|
while (out_it.next()) |output| {
|
||||||
|
// Destroy existing overlay
|
||||||
|
if (output.tag_overlay) |*tag_overlay| {
|
||||||
|
tag_overlay.deinit();
|
||||||
|
output.tag_overlay = null;
|
||||||
|
}
|
||||||
|
// Create new overlay if configured
|
||||||
|
// Create new overlay struct if configured (surfaces created on-demand)
|
||||||
|
if (new_config.tag_overlay) |tag_overlay_config| {
|
||||||
|
output.tag_overlay = TagOverlay.init(context, output, tag_overlay_config.toTagOverlayOptions()) catch |e| {
|
||||||
|
log.err("Failed to create tag overlay: {}", .{e});
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (wallpaper_changed) {
|
if (wallpaper_changed) {
|
||||||
if (context.wallpaper_image) |img| img.destroy();
|
if (context.wallpaper_image) |img| img.destroy();
|
||||||
context.wallpaper_image = loadWallpaperImage(new_config);
|
context.wallpaper_image = loadWallpaperImage(new_config);
|
||||||
|
|
@ -180,6 +230,7 @@ fn pathsEqual(a: ?[]const u8, b: ?[]const u8) bool {
|
||||||
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
|
const posix = std.posix;
|
||||||
const process = std.process;
|
const process = std.process;
|
||||||
|
|
||||||
const wayland = @import("wayland");
|
const wayland = @import("wayland");
|
||||||
|
|
@ -191,6 +242,8 @@ const utils = @import("utils.zig");
|
||||||
const BufferPool = @import("BufferPool.zig");
|
const BufferPool = @import("BufferPool.zig");
|
||||||
const Config = @import("Config.zig");
|
const Config = @import("Config.zig");
|
||||||
const InputManager = @import("InputManager.zig");
|
const InputManager = @import("InputManager.zig");
|
||||||
|
const Output = @import("Output.zig");
|
||||||
|
const TagOverlay = @import("TagOverlay.zig");
|
||||||
const WallpaperImage = @import("WallpaperImage.zig");
|
const WallpaperImage = @import("WallpaperImage.zig");
|
||||||
const WindowManager = @import("WindowManager.zig");
|
const WindowManager = @import("WindowManager.zig");
|
||||||
const XkbBindings = @import("XkbBindings.zig");
|
const XkbBindings = @import("XkbBindings.zig");
|
||||||
|
|
|
||||||
|
|
@ -39,8 +39,8 @@ surfaces: ?struct {
|
||||||
} = null,
|
} = null,
|
||||||
|
|
||||||
// TODO: Make Bar a user option, can disable if they want
|
// TODO: Make Bar a user option, can disable if they want
|
||||||
// This Output's bar
|
|
||||||
bar: ?Bar,
|
bar: ?Bar,
|
||||||
|
tag_overlay: ?TagOverlay,
|
||||||
|
|
||||||
/// Proportion of output width taken by the primary stack
|
/// Proportion of output width taken by the primary stack
|
||||||
primary_ratio: f32,
|
primary_ratio: f32,
|
||||||
|
|
@ -92,16 +92,26 @@ pub fn create(context: *Context, river_output_v1: *river.OutputV1) !*Output {
|
||||||
var output = try utils.gpa.create(Output);
|
var output = try utils.gpa.create(Output);
|
||||||
errdefer utils.gpa.destroy(output);
|
errdefer utils.gpa.destroy(output);
|
||||||
|
|
||||||
const bar = Bar.init(context, output) catch |e| blk: {
|
var bar = Bar.init(context, output) catch |e| blk: {
|
||||||
log.err("Failed to create a bar: {}", .{e});
|
log.err("Failed to create a bar: {}", .{e});
|
||||||
break :blk null;
|
break :blk null;
|
||||||
};
|
};
|
||||||
|
errdefer if (bar) |*b| b.deinit();
|
||||||
|
|
||||||
|
var tag_overlay = if (context.config.tag_overlay) |tag_overlay_config| blk: {
|
||||||
|
break :blk TagOverlay.init(context, output, tag_overlay_config.toTagOverlayOptions()) catch |e| {
|
||||||
|
log.err("Failed to create a tag overlay: {}", .{e});
|
||||||
|
break :blk null;
|
||||||
|
};
|
||||||
|
} else null;
|
||||||
|
errdefer if (tag_overlay) |*to| to.deinit();
|
||||||
|
|
||||||
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),
|
.river_layer_shell_output_v1 = try context.river_layer_shell_v1.getOutput(river_output_v1),
|
||||||
.bar = bar,
|
.bar = bar,
|
||||||
|
.tag_overlay = tag_overlay,
|
||||||
.primary_count = context.config.primary_count,
|
.primary_count = context.config.primary_count,
|
||||||
.primary_ratio = context.config.primary_ratio,
|
.primary_ratio = context.config.primary_ratio,
|
||||||
.windows = undefined, // we will initialize this shortly
|
.windows = undefined, // we will initialize this shortly
|
||||||
|
|
@ -122,6 +132,10 @@ pub fn destroy(output: *Output) void {
|
||||||
window.link.remove();
|
window.link.remove();
|
||||||
window.destroy();
|
window.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (output.bar) |*bar| bar.deinit();
|
||||||
|
if (output.tag_overlay) |*tag_overlay| tag_overlay.deinit();
|
||||||
|
|
||||||
output.tag_layout_overrides.deinit(utils.gpa);
|
output.tag_layout_overrides.deinit(utils.gpa);
|
||||||
output.deinitWallpaperLayerSurface();
|
output.deinitWallpaperLayerSurface();
|
||||||
output.river_output_v1.destroy();
|
output.river_output_v1.destroy();
|
||||||
|
|
@ -230,6 +244,8 @@ fn riverOutputListener(river_output_v1: *river.OutputV1, event: river.OutputV1.E
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
// Tag overlay surfaces are created on-demand when tags change,
|
||||||
|
// so we don't init them here.
|
||||||
},
|
},
|
||||||
.dimensions => |ev| {
|
.dimensions => |ev| {
|
||||||
// Protocol guarantees that width and height are strictly greater than zero
|
// Protocol guarantees that width and height are strictly greater than zero
|
||||||
|
|
@ -553,6 +569,33 @@ pub fn manage(output: *Output) void {
|
||||||
}
|
}
|
||||||
|
|
||||||
output.tags = new_tags;
|
output.tags = new_tags;
|
||||||
|
|
||||||
|
// Show tag overlay and arm the hide timer
|
||||||
|
if (output.tag_overlay) |*tag_overlay| {
|
||||||
|
if (tag_overlay.surfaces) |_| {
|
||||||
|
// The overlay is arleady visible, but we still need to re-render
|
||||||
|
tag_overlay.render() catch |err| {
|
||||||
|
log.err("tag_overlay render failed: {}", .{err});
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// Create surface; the configure handler renders for us
|
||||||
|
tag_overlay.initSurface() catch |err| {
|
||||||
|
log.err("tag_overlay initSurface failed: {}", .{err});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (output.context.tag_overlay_timer_fd) |fd| {
|
||||||
|
const timeout_ms: isize = tag_overlay.options.timeout;
|
||||||
|
posix.timerfd_settime(fd, .{}, &.{
|
||||||
|
.it_interval = .{ .sec = 0, .nsec = 0 },
|
||||||
|
.it_value = .{
|
||||||
|
.sec = @divFloor(timeout_ms, 1000),
|
||||||
|
.nsec = @mod(timeout_ms, 1000) * std.time.ns_per_ms,
|
||||||
|
},
|
||||||
|
}, null) catch |err| {
|
||||||
|
log.err("Failed to arm tag overlay timer: {}", .{err});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate layout before managing windows
|
// Calculate layout before managing windows
|
||||||
|
|
@ -701,6 +744,7 @@ pub fn occupiedTags(output: *Output) u32 {
|
||||||
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;
|
||||||
|
const posix = std.posix;
|
||||||
const DoublyLinkedList = std.DoublyLinkedList;
|
const DoublyLinkedList = std.DoublyLinkedList;
|
||||||
|
|
||||||
const wayland = @import("wayland");
|
const wayland = @import("wayland");
|
||||||
|
|
@ -713,6 +757,7 @@ const utils = @import("utils.zig");
|
||||||
const Bar = @import("Bar.zig");
|
const Bar = @import("Bar.zig");
|
||||||
const Buffer = @import("Buffer.zig");
|
const Buffer = @import("Buffer.zig");
|
||||||
const Context = @import("Context.zig");
|
const Context = @import("Context.zig");
|
||||||
|
const TagOverlay = @import("TagOverlay.zig");
|
||||||
const Window = @import("Window.zig");
|
const Window = @import("Window.zig");
|
||||||
|
|
||||||
const log = std.log.scoped(.Output);
|
const log = std.log.scoped(.Output);
|
||||||
|
|
|
||||||
|
|
@ -30,12 +30,10 @@ configured: bool = false,
|
||||||
pub const Options = struct {
|
pub const Options = struct {
|
||||||
/// Width of the widget border in pixels
|
/// Width of the widget border in pixels
|
||||||
border_width: u8,
|
border_width: u8,
|
||||||
/// Number of displayed tags
|
/// Number of displayed tags (1-32)
|
||||||
/// Put in config as 1-32 but we subtract 1 to store it in a u5
|
tag_amount: u6,
|
||||||
tag_amount: u5,
|
/// Amount of tags per row (1-32)
|
||||||
/// Amount of tags per row
|
tags_per_row: u6,
|
||||||
/// Put in config as 1-32 but we subtract 1 to store it in a u5
|
|
||||||
tags_per_row: u5,
|
|
||||||
/// Size of tag squares in pixels
|
/// Size of tag squares in pixels
|
||||||
square_size: u8,
|
square_size: u8,
|
||||||
/// Padding around the tag occupied indicator in pixels
|
/// Padding around the tag occupied indicator in pixels
|
||||||
|
|
@ -109,29 +107,36 @@ pub fn initSurface(tag_overlay: *TagOverlay) !void {
|
||||||
defer empty_region.destroy();
|
defer empty_region.destroy();
|
||||||
wl_surface.setInputRegion(empty_region);
|
wl_surface.setInputRegion(empty_region);
|
||||||
|
|
||||||
const surface_width = (@min(options.tag_amount, options.tags_per_row) * (options.square_size + options.square_padding)) + options.square_padding + (2 * options.border_width);
|
const surface_width: u31 = @as(u31, @min(options.tag_amount, options.tags_per_row)) * (@as(u31, options.square_size) + options.square_padding) + options.square_padding + 2 * @as(u31, options.border_width);
|
||||||
const surface_height = (options.rows * (options.square_size + options.square_padding)) + options.square_padding + (2 * options.border_width);
|
const surface_height: u31 = @as(u31, tag_overlay.rows) * (@as(u31, options.square_size) + options.square_padding) + options.square_padding + 2 * @as(u31, options.border_width);
|
||||||
layer_surface.setSize(surface_width, surface_height);
|
layer_surface.setSize(surface_width, surface_height);
|
||||||
|
|
||||||
layer_surface.setAnchor(options.anchors);
|
layer_surface.setAnchor(options.anchors);
|
||||||
layer_surface.setMargin(options.margins);
|
layer_surface.setMargin(options.margins.top, options.margins.right, options.margins.bottom, options.margins.left);
|
||||||
|
|
||||||
tag_overlay.surfaces = .{ .wl_surface = wl_surface, .layer_surface = layer_surface };
|
tag_overlay.surfaces = .{ .wl_surface = wl_surface, .layer_surface = layer_surface };
|
||||||
context.buffer_pool.surface_count += 1;
|
context.buffer_pool.surface_count += 1;
|
||||||
|
|
||||||
// layer_surface.setListener(*Bar, layerSurfaceListener, bar);
|
layer_surface.setListener(*TagOverlay, layerSurfaceListener, tag_overlay);
|
||||||
wl_surface.commit();
|
wl_surface.commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(tag_overlay: *TagOverlay) void {
|
/// Destroy surfaces only (used to hide the overlay). The TagOverlay struct stays valid
|
||||||
|
/// and can be re-shown by calling initSurface() again.
|
||||||
|
pub fn deinitSurfaces(tag_overlay: *TagOverlay) void {
|
||||||
tag_overlay.configured = false;
|
tag_overlay.configured = false;
|
||||||
if (tag_overlay.surfaces) |surfaces| {
|
if (tag_overlay.surfaces) |surfaces| {
|
||||||
surfaces.wl_surface.destroy();
|
|
||||||
surfaces.layer_surface.destroy();
|
surfaces.layer_surface.destroy();
|
||||||
|
surfaces.wl_surface.destroy();
|
||||||
tag_overlay.context.buffer_pool.surface_count -= 1;
|
tag_overlay.context.buffer_pool.surface_count -= 1;
|
||||||
|
tag_overlay.surfaces = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn deinit(tag_overlay: *TagOverlay) void {
|
||||||
|
tag_overlay.deinitSurfaces();
|
||||||
|
}
|
||||||
|
|
||||||
pub fn layerSurfaceListener(
|
pub fn layerSurfaceListener(
|
||||||
layer_surface: *zwlr.LayerSurfaceV1,
|
layer_surface: *zwlr.LayerSurfaceV1,
|
||||||
event: zwlr.LayerSurfaceV1.Event,
|
event: zwlr.LayerSurfaceV1.Event,
|
||||||
|
|
@ -193,7 +198,7 @@ pub fn render(tag_overlay: *TagOverlay) !void {
|
||||||
}
|
}
|
||||||
const buffer = try context.buffer_pool.nextBuffer(context.wl_shm, render_width, render_height);
|
const buffer = try context.buffer_pool.nextBuffer(context.wl_shm, render_width, render_height);
|
||||||
|
|
||||||
buffer.borderedRectangle(0, 0, tag_overlay.width, tag_overlay.height, options.border_width, scale, options.background_color, options.border_color);
|
buffer.borderedRectangle(0, 0, tag_overlay.width, tag_overlay.height, options.border_width, scale, &options.background_color, &options.border_color);
|
||||||
|
|
||||||
const focused_tags = tag_overlay.output.tags;
|
const focused_tags = tag_overlay.output.tags;
|
||||||
const occupied_tags = tag_overlay.output.occupiedTags();
|
const occupied_tags = tag_overlay.output.occupiedTags();
|
||||||
|
|
@ -210,8 +215,8 @@ pub fn render(tag_overlay: *TagOverlay) !void {
|
||||||
else
|
else
|
||||||
.{ &options.square_inactive_background_color, &options.square_inactive_border_color, &options.square_inactive_occupied_color };
|
.{ &options.square_inactive_background_color, &options.square_inactive_border_color, &options.square_inactive_occupied_color };
|
||||||
|
|
||||||
const x = options.border_width + ((tag + 1) * options.square_padding) + (tag * options.square_size);
|
const x = options.border_width + @as(u31, @intCast((tag + 1) * options.square_padding)) + @as(u31, @intCast(tag * options.square_size));
|
||||||
const y = options.border_width + ((row + 1) * options.square_padding) + (row * options.square_size);
|
const y = options.border_width + @as(u31, @intCast((row + 1) * options.square_padding)) + @as(u31, @intCast(row * options.square_size));
|
||||||
|
|
||||||
buffer.borderedRectangle(x, y, options.square_size, options.square_size, options.square_border_width, scale, bg_color, border_color);
|
buffer.borderedRectangle(x, y, options.square_size, options.square_size, options.square_border_width, scale, bg_color, border_color);
|
||||||
|
|
||||||
|
|
|
||||||
35
src/main.zig
35
src/main.zig
|
|
@ -115,12 +115,13 @@ fn run(wl_display: *wl.Display, context: *Context) !void {
|
||||||
|
|
||||||
posix.sigprocmask(posix.SIG.BLOCK, &mask, null);
|
posix.sigprocmask(posix.SIG.BLOCK, &mask, null);
|
||||||
|
|
||||||
const sig_fd = try posix.signalfd(-1, &mask, 0);
|
const sig_fd = try posix.signalfd(-1, &mask, @as(u32, @bitCast(posix.O{ .CLOEXEC = true })));
|
||||||
|
|
||||||
const poll_wayland = 0;
|
const poll_wayland = 0;
|
||||||
const poll_sig = 1;
|
const poll_sig = 1;
|
||||||
|
const poll_tag_overlay_timer = 2;
|
||||||
|
|
||||||
var pollfds: [2]posix.pollfd = undefined;
|
var pollfds: [3]posix.pollfd = undefined;
|
||||||
|
|
||||||
pollfds[poll_wayland] = .{
|
pollfds[poll_wayland] = .{
|
||||||
.fd = wl_display.getFd(),
|
.fd = wl_display.getFd(),
|
||||||
|
|
@ -132,6 +133,12 @@ fn run(wl_display: *wl.Display, context: *Context) !void {
|
||||||
.events = posix.POLL.IN,
|
.events = posix.POLL.IN,
|
||||||
.revents = 0,
|
.revents = 0,
|
||||||
};
|
};
|
||||||
|
pollfds[poll_tag_overlay_timer] = .{
|
||||||
|
// poll ignores negative fds
|
||||||
|
.fd = context.tag_overlay_timer_fd orelse -1,
|
||||||
|
.events = posix.POLL.IN,
|
||||||
|
.revents = 0,
|
||||||
|
};
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
const errno = wl_display.flush();
|
const errno = wl_display.flush();
|
||||||
|
|
@ -165,22 +172,46 @@ fn run(wl_display: *wl.Display, context: *Context) !void {
|
||||||
|
|
||||||
// Handle fds that became ready
|
// Handle fds that became ready
|
||||||
if (pollfds[poll_wayland].revents & posix.POLL.HUP != 0) {
|
if (pollfds[poll_wayland].revents & posix.POLL.HUP != 0) {
|
||||||
|
@branchHint(.cold);
|
||||||
log.info("Disconnected by compositor", .{});
|
log.info("Disconnected by compositor", .{});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (pollfds[poll_wayland].revents & posix.POLL.IN != 0) {
|
if (pollfds[poll_wayland].revents & posix.POLL.IN != 0) {
|
||||||
if (wl_display.dispatch() != .SUCCESS) {
|
if (wl_display.dispatch() != .SUCCESS) {
|
||||||
|
@branchHint(.cold);
|
||||||
fatal("Wayland display dispatch failed", .{});
|
fatal("Wayland display dispatch failed", .{});
|
||||||
}
|
}
|
||||||
|
// Re-sync in case a config reload created or destroyed the timerfd
|
||||||
|
pollfds[poll_tag_overlay_timer].fd = context.tag_overlay_timer_fd orelse -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pollfds[poll_sig].revents & posix.POLL.HUP != 0) {
|
if (pollfds[poll_sig].revents & posix.POLL.HUP != 0) {
|
||||||
|
@branchHint(.cold);
|
||||||
fatal("Signal fd hung up", .{});
|
fatal("Signal fd hung up", .{});
|
||||||
}
|
}
|
||||||
if (pollfds[poll_sig].revents & posix.POLL.IN != 0) {
|
if (pollfds[poll_sig].revents & posix.POLL.IN != 0) {
|
||||||
|
@branchHint(.cold);
|
||||||
log.info("Exiting beansprout", .{});
|
log.info("Exiting beansprout", .{});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pollfds[poll_tag_overlay_timer].revents & posix.POLL.HUP != 0) {
|
||||||
|
@branchHint(.cold);
|
||||||
|
fatal("Tag overlay timer fd hung up", .{});
|
||||||
|
}
|
||||||
|
if (pollfds[poll_tag_overlay_timer].revents & posix.POLL.IN != 0) {
|
||||||
|
// Read to consume the timer event
|
||||||
|
var buf: [8]u8 = undefined;
|
||||||
|
_ = posix.read(context.tag_overlay_timer_fd.?, &buf) catch {};
|
||||||
|
|
||||||
|
// Hide all tag overlays by destroying their surfaces
|
||||||
|
var it = context.wm.outputs.iterator(.forward);
|
||||||
|
while (it.next()) |output| {
|
||||||
|
if (output.tag_overlay) |*tag_overlay| {
|
||||||
|
tag_overlay.deinitSurfaces();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue