diff --git a/.github/workflows/binary.yml b/.github/workflows/binary.yml index e009012..5a95a58 100644 --- a/.github/workflows/binary.yml +++ b/.github/workflows/binary.yml @@ -20,7 +20,7 @@ jobs: strategy: fail-fast: false matrix: - zig-version: [master] + zig-version: ["0.11.0"] targets: - "x86-windows" - "x86_64-windows" @@ -58,7 +58,7 @@ jobs: strategy: fail-fast: false matrix: - zig-version: [master] + zig-version: ["0.11.0"] targets: - "x86_64-macos" - "aarch64-macos" diff --git a/.tool-versions b/.tool-versions new file mode 100644 index 0000000..8294b3c --- /dev/null +++ b/.tool-versions @@ -0,0 +1 @@ +zig 0.11.0 diff --git a/README.org b/README.org index 700bcc6..e029d20 100644 --- a/README.org +++ b/README.org @@ -1,5 +1,5 @@ #+DATE: 2023-10-21T12:09:48+0800 -#+LASTMOD: 2023-11-09T22:26:31+0800 +#+LASTMOD: 2023-11-10T21:49:29+0800 #+TYPE: docs * Zigcli @@ -24,7 +24,7 @@ This package provides: - =repeat=, repeat a command until it succeeds. - =pidof=, like [[https://man7.org/linux/man-pages/man1/pidof.1.html][pidof]], but for macOS. - =night-shift=, control [[https://support.apple.com/guide/mac-help/use-night-shift-mchl97bc676d/mac][Night Shift]] in macOS. - - =dark-mode=, Get dark mode status in macOS. + - =dark-mode=, control dark mode in macOS. * Install ** Programs diff --git a/build.zig b/build.zig index 473a166..ca09165 100644 --- a/build.zig +++ b/build.zig @@ -198,8 +198,8 @@ fn makeCompileStep( exe.addFrameworkPath(.{ .path = "/System/Library/PrivateFrameworks" }); exe.linkFramework("CoreBrightness"); } else if (std.mem.eql(u8, name, "dark-mode")) { - exe.linkSystemLibrary("objc"); - exe.linkFramework("AppKit"); + exe.addFrameworkPath(.{ .path = "/System/Library/PrivateFrameworks" }); + exe.linkFramework("SkyLight"); } return exe; } diff --git a/docs/content/docs/programs/dark-mode.org b/docs/content/docs/programs/dark-mode.org index 2c8103c..592da47 100644 --- a/docs/content/docs/programs/dark-mode.org +++ b/docs/content/docs/programs/dark-mode.org @@ -1,2 +1,17 @@ * Dark mode Get dark mode status for macOS. +#+begin_src bash + $ dark-mode -h + USAGE: + dark-mode [OPTIONS] [--] + + Available commands: + status View dark mode status + on Turn dark mode on + off Turn dark mode off + toggle Toggle dark mode + + OPTIONS: + -v, --version Print version + -h, --help Print help information +#+end_src diff --git a/src/bin/dark-mode.zig b/src/bin/dark-mode.zig index a72ac66..1a8d664 100644 --- a/src/bin/dark-mode.zig +++ b/src/bin/dark-mode.zig @@ -1,31 +1,80 @@ //! Dark mode status, built for macOS. //! const std = @import("std"); -const c = @cImport({ - @cInclude("objc/objc.h"); - @cInclude("objc/message.h"); -}); +const simargs = @import("simargs"); +const util = @import("util.zig"); -// https://developer.apple.com/documentation/appkit/nsappearancenamedarkaqua -const darkValue = "NSAppearanceNameDarkAqua"; +// https://saagarjha.com/blog/2018/12/01/scheduling-dark-mode/ +extern "c" fn SLSSetAppearanceThemeLegacy(bool) void; +extern "c" fn SLSGetAppearanceThemeLegacy() bool; + +const Command = enum { + Status, + On, + Off, + Toggle, + + const FromString = std.ComptimeStringMap(@This(), .{ + .{ "status", .Status }, + .{ "on", .On }, + .{ "off", .Off }, + .{ "toggle", .Toggle }, + }); +}; pub fn main() !void { - const clazz = c.objc_getClass("NSAppearance"); - - const appearanceName = blk: { - const call: *fn (c.id, c.SEL) callconv(.C) c.id = @constCast(@ptrCast(&c.objc_msgSend)); - const appearance = call(@alignCast(@ptrCast(clazz.?)), c.sel_registerName("currentDrawingAppearance")); - break :blk call(appearance, c.sel_registerName("name")); - }; - - const appearanceValue = blk: { - const call: *fn (c.id, c.SEL) callconv(.C) [*c]const u8 = @constCast(@ptrCast(&c.objc_msgSend)); - break :blk call(appearanceName, c.sel_registerName("UTF8String")); - }; - - if (std.mem.eql(u8, darkValue, std.mem.span(appearanceValue.?))) { - std.debug.print("on", .{}); - } else { - std.debug.print("off", .{}); + var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); + defer arena.deinit(); + const allocator = arena.allocator(); + + const opt = try simargs.parse(allocator, struct { + version: bool = false, + help: bool = false, + + pub const __shorts__ = .{ + .version = .v, + .help = .h, + }; + + pub const __messages__ = .{ + .help = "Print help information", + .version = "Print version", + }; + }, + \\ + \\ + \\ Available commands: + \\ status View dark mode status + \\ on Turn dark mode on + \\ off Turn dark mode off + \\ toggle Toggle dark mode + , util.get_build_info()); + defer opt.deinit(); + + var args_iter = util.SliceIter([]const u8).init(opt.positional_args.items); + const cmd: Command = if (args_iter.next()) |v| + Command.FromString.get(v) orelse return error.UnknownCommand + else + .Status; + + switch (cmd) { + .Status => { + const is_dark = SLSGetAppearanceThemeLegacy(); + if (is_dark) { + std.debug.print("on", .{}); + } else { + std.debug.print("off", .{}); + } + }, + .On => { + SLSSetAppearanceThemeLegacy(true); + }, + .Off => { + SLSSetAppearanceThemeLegacy(false); + }, + .Toggle => { + const is_dark = SLSGetAppearanceThemeLegacy(); + SLSSetAppearanceThemeLegacy(!is_dark); + }, } }