1const std = @import("std");2const log = std.log;34const zriver = @import("wayland").client.zriver;5const pixman = @import("pixman");67const Monitor = @import("Monitor.zig");8const render = @import("render.zig");9const Input = @import("Input.zig");10const Tags = @This();1112const state = &@import("root").state;1314monitor: *Monitor,15output_status: *zriver.OutputStatusV1,16tags: [9]Tag,1718pub const Tag = struct {19 label: u8,20 focused: bool = false,21 occupied: bool = false,22 urgent: bool = false,2324 pub fn bgColor(self: *const Tag) *pixman.Color {25 if (self.focused) {26 return &state.config.focusBgColor;27 } else if (self.urgent) {28 return &state.config.normalFgColor;29 } else {30 return &state.config.normalBgColor;31 }32 }3334 pub fn fgColor(self: *const Tag) *pixman.Color {35 if (self.focused) {36 return &state.config.focusFgColor;37 } else if (self.urgent) {38 return &state.config.normalBgColor;39 } else {40 return &state.config.normalFgColor;41 }42 }43};4445pub fn create(monitor: *Monitor) !*Tags {46 const self = try state.gpa.create(Tags);47 const manager = state.wayland.status_manager.?;4849 self.monitor = monitor;50 self.output_status = try manager.getRiverOutputStatus(monitor.output);51 for (&self.tags, 0..) |*tag, i| {52 tag.label = '1' + @as(u8, @intCast(i));53 }5455 self.output_status.setListener(*Tags, outputStatusListener, self);56 return self;57}5859pub fn destroy(self: *Tags) void {60 self.output_status.destroy();61 state.gpa.destroy(self);62}6364fn outputStatusListener(65 _: *zriver.OutputStatusV1,66 event: zriver.OutputStatusV1.Event,67 tags: *Tags,68) void {69 switch (event) {70 .focused_tags => |data| {71 for (&tags.tags, 0..) |*tag, i| {72 const mask = @as(u32, 1) << @as(u5, @intCast(i));73 tag.focused = data.tags & mask != 0;74 }75 },76 .urgent_tags => |data| {77 for (&tags.tags, 0..) |*tag, i| {78 const mask = @as(u32, 1) << @as(u5, @intCast(i));79 tag.urgent = data.tags & mask != 0;80 }81 },82 .view_tags => |data| {83 for (&tags.tags) |*tag| {84 tag.occupied = false;85 }86 for (data.tags.slice(u32)) |view| {87 for (&tags.tags, 0..) |*tag, i| {88 const mask = @as(u32, 1) << @as(u5, @intCast(i));89 if (view & mask != 0) tag.occupied = true;90 }91 }92 },93 }94 if (tags.monitor.confBar()) |bar| {95 render.renderTags(bar) catch |err| {96 log.err("renderTags failed for monitor {}: {s}", .{ tags.monitor.globalName, @errorName(err) });97 return;98 };99100 bar.tags.surface.commit();101 bar.background.surface.commit();102 }103}104105pub fn handleClick(self: *Tags, x: u32) !void {106 const control = state.wayland.control.?;107108 if (self.monitor.bar) |bar| {109 const index = x / bar.height;110 const payload = try std.fmt.allocPrintSentinel(111 state.gpa,112 "{d}",113 .{@as(u32, 1) << @as(u5, @intCast(index))},114 0,115 );116 defer state.gpa.free(payload);117118 control.addArgument("set-focused-tags");119 control.addArgument(payload);120 const callback = try control.runCommand(state.wayland.seat.?);121 _ = callback;122 }123}