lib/sys/src/x11/display.zig

daab053ee43316e1809a84551d573ddd1e5bf3d2

 1 const std = @import("std");
 2 
 3 pub const ParseError = error{
 4     MissingDisplay,
 5     RemoteDisplayUnsupported,
 6     InvalidDisplay,
 7 };
 8 
 9 pub const Target = struct {
10     display: u32,
11     screen: u32,
12 
13     pub fn socketPath(self: Target, buffer: []u8) ![]const u8 {
14         return std.fmt.bufPrint(buffer, "/tmp/.X11-unix/X{d}", .{self.display});
15     }
16 };
17 
18 pub fn parse(value: ?[]const u8) ParseError!Target {
19     const raw = value orelse return error.MissingDisplay;
20     if (raw.len == 0) return error.MissingDisplay;
21 
22     var rest = raw;
23     if (std.mem.indexOfScalar(u8, rest, ':')) |colon| {
24         const host = rest[0..colon];
25         if (host.len != 0 and !std.mem.eql(u8, host, "unix")) {
26             return error.RemoteDisplayUnsupported;
27         }
28         rest = rest[colon + 1 ..];
29     } else {
30         return error.InvalidDisplay;
31     }
32 
33     var display_part = rest;
34     var screen_part: []const u8 = "";
35     if (std.mem.indexOfScalar(u8, rest, '.')) |dot| {
36         display_part = rest[0..dot];
37         screen_part = rest[dot + 1 ..];
38     }
39 
40     const display = std.fmt.parseInt(u32, display_part, 10) catch return error.InvalidDisplay;
41     const screen = if (screen_part.len == 0)
42         0
43     else
44         std.fmt.parseInt(u32, screen_part, 10) catch return error.InvalidDisplay;
45 
46     return .{ .display = display, .screen = screen };
47 }
48 
49 test "parse accepts local display forms" {
50     try std.testing.expectEqual(Target{ .display = 0, .screen = 0 }, try parse(":0"));
51     try std.testing.expectEqual(Target{ .display = 1, .screen = 0 }, try parse(":1"));
52     try std.testing.expectEqual(Target{ .display = 0, .screen = 2 }, try parse(":0.2"));
53     try std.testing.expectEqual(Target{ .display = 10, .screen = 0 }, try parse("unix:10"));
54 }
55 
56 test "parse rejects remote and malformed displays" {
57     try std.testing.expectError(error.MissingDisplay, parse(null));
58     try std.testing.expectError(error.MissingDisplay, parse(""));
59     try std.testing.expectError(error.RemoteDisplayUnsupported, parse("remote.host:0"));
60     try std.testing.expectError(error.InvalidDisplay, parse("0"));
61     try std.testing.expectError(error.InvalidDisplay, parse(":zero"));
62 }
63 
64 test "socket path names the abstract unix socket" {
65     var buffer: [64]u8 = undefined;
66     const target = try parse(":1");
67     try std.testing.expectEqualStrings("/tmp/.X11-unix/X1", try target.socketPath(&buffer));
68 }