diff --git a/build.zig b/build.zig index 293c65d..0cc7931 100644 --- a/build.zig +++ b/build.zig @@ -11,9 +11,15 @@ pub fn build(b: *std.build.Builder) void { // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. const mode = b.standardReleaseOptions(); - const exe = b.addExecutable("clipboard", "src/main.zig"); + const exe = switch (target.getOs().tag) { + .linux => b.addExecutable("clipboard", "src/main-linux.zig"), + .windows => b.addExecutable("clipboard", "src/main-windows.zig"), + else => std.os.exit(1), + }; + exe.setTarget(target); exe.setBuildMode(mode); + exe.linkLibC(); if (target.getOs().tag == .linux) { // LibX11 1.7.2: https://gitlab.freedesktop.org/xorg/lib/libx11/-/archive/libX11-1.7.2/libx11-libX11-1.7.2.tar.gz // LibXfixes 5.0.3: https://gitlab.freedesktop.org/xorg/lib/libxfixes/-/archive/libXfixes-5.0.3/libxfixes-libXfixes-5.0.3.tar.gz @@ -21,7 +27,6 @@ pub fn build(b: *std.build.Builder) void { // We can download the above by taking each url and processing in a // command e.g.: // curl | tar xz --wildcards '*.h' - exe.linkLibC(); exe.addIncludeDir("libx11-libX11-1.7.2/include"); exe.addIncludeDir("libxfixes-libXfixes-5.0.3/include"); exe.addIncludeDir("xorgproto-xorgproto-2021.5/include"); diff --git a/src/linux.zig b/src/main-linux.zig similarity index 78% rename from src/linux.zig rename to src/main-linux.zig index 6315172..be94ba7 100644 --- a/src/linux.zig +++ b/src/main-linux.zig @@ -5,6 +5,62 @@ const c = @cImport({ @cInclude("X11/extensions/Xfixes.h"); }); +pub fn main() !u8 { + var watch = false; + var gpa = std.heap.GeneralPurposeAllocator(.{}){}; + defer _ = gpa.deinit(); + const allocator = &gpa.allocator; + var args = std.process.args(); + defer args.deinit(); + while (args.next(allocator)) |arg_or_err| { + const arg = try arg_or_err; + defer allocator.free(arg); + if (std.mem.eql(u8, arg, "-w")) { + watch = true; + break; + } + } + clipboardAction(watch) catch return 1; + return 0; +} + +pub fn clipboardAction(watch: bool) !void { + const stdout = std.io.getStdOut().writer(); + var display: *c.Display = c.XOpenDisplay(null).?; + defer _ = c.XCloseDisplay(display); + const default_screen = c.XDefaultScreen(display); + var color = c.XBlackPixel(display, default_screen); + var window = c.XCreateSimpleWindow(display, c.XDefaultRootWindow(display), 0, 0, 1, 1, 0, color, color); + defer _ = c.XDestroyWindow(display, window); + // Watch will not return + if (watch) try watchClip(display, window, "CLIPBOARD", stdout); + var result = (try printSelection(display, window, "CLIPBOARD", "UTF8_STRING", stdout)) or + (try printSelection(display, window, "CLIPBOARD", "STRING", stdout)); + if (!result) return error.ClipboardActionFailed; +} + +fn watchClip(display: *c.Display, window: c.Window, bufname: [*c]const u8, writer: anytype) !void { + var event_base: c_int = undefined; + var error_base: c_int = undefined; + var event: c.XEvent = undefined; + var bufid = c.XInternAtom(display, bufname, c.False); + + _ = c.XFixesQueryExtension(display, &event_base, &error_base); + _ = c.XFixesSelectSelectionInput(display, c.XDefaultRootWindow(display), bufid, c.XFixesSetSelectionOwnerNotifyMask); + + while (true) { + _ = c.XNextEvent(display, &event); + + if (event.type == event_base + c.XFixesSelectionNotify and + event.xselection.property == bufid) + { + _ = try writer.print("y", .{}); + if (!try printSelection(display, window, bufname, "UTF8_STRING", writer)) + _ = try printSelection(display, window, bufname, "STRING", writer); + } + } +} + fn printSelection(display: *c.Display, window: c.Window, bufname: [*c]const u8, fmtname: [*c]const u8, writer: anytype) !bool { var ressize: c_ulong = undefined; var restail: c_ulong = undefined; @@ -30,6 +86,13 @@ fn printSelection(display: *c.Display, window: c.Window, bufname: [*c]const u8, if (fmtid == incrid) { ressize = 1; + var gpa = std.heap.GeneralPurposeAllocator(.{}){}; + defer _ = gpa.deinit(); + var arena_allocator = std.heap.ArenaAllocator.init(&gpa.allocator); + defer arena_allocator.deinit(); + var buffer = std.ArrayList(u8).init(&arena_allocator.allocator); + defer buffer.deinit(); + // try writer.print("BIG:", .{}); while (ressize > 0) { _ = c.XNextEvent(display, &event); while (event.type != c.PropertyNotify or event.xproperty.atom != propid or event.xproperty.state != c.PropertyNewValue) { @@ -37,61 +100,12 @@ fn printSelection(display: *c.Display, window: c.Window, bufname: [*c]const u8, } _ = c.XGetWindowProperty(display, window, propid, 0, c.LONG_MAX / 4, c.True, c.AnyPropertyType, &fmtid, &resbits, &ressize, &restail, &result); - defer _ = c.XFree(result); - try writer.print("{s}", .{result}); + //defer _ = c.XFree(result); // Creates double free error, but not sure why + try buffer.appendSlice(try std.fmt.allocPrint(&arena_allocator.allocator, "{s}", .{result})); } + try writer.print("{s}", .{buffer.items}); } return true; } else // request failed, e.g. owner can't convert to the target format return false; } - -fn watch(display: *c.Display, window: c.Window, bufname: [*c]const u8, writer: anytype) !void { - var event_base: c_int = undefined; - var error_base: c_int = undefined; - var event: c.XEvent = undefined; - var bufid = c.XInternAtom(display, bufname, c.False); - - _ = c.XFixesQueryExtension(display, &event_base, &error_base); - _ = c.XFixesSelectSelectionInput(display, c.XDefaultRootWindow(display), bufid, c.XFixesSetSelectionOwnerNotifyMask); - - while (true) { - _ = c.XNextEvent(display, &event); - - // _ = try writer.print("{d} == {d} + {d}. {d} == {d}", .{ event.type, event_base, c.XFixesSelectionNotify, event.xselection.selection, bufid }); - // _ = std.debug.print("{}", .{event.xselection}); - - if (event.type == event_base + c.XFixesSelectionNotify and - event.xselection.property == bufid) - { - _ = try writer.print("y", .{}); - if (!try printSelection(display, window, bufname, "UTF8_STRING", writer)) - _ = try printSelection(display, window, bufname, "STRING", writer); - } - } -} - -pub fn clipboardAction() !void { - const stdout = std.io.getStdOut().writer(); - var display: *c.Display = c.XOpenDisplay(null).?; - defer _ = c.XCloseDisplay(display); - const default_screen = c.XDefaultScreen(display); - var color = c.XBlackPixel(display, default_screen); - var window = c.XCreateSimpleWindow(display, c.XDefaultRootWindow(display), 0, 0, 1, 1, 0, color, color); - defer _ = c.XDestroyWindow(display, window); - var gpa = std.heap.GeneralPurposeAllocator(.{}){}; - defer _ = gpa.deinit(); - const allocator = &gpa.allocator; - var args = std.process.args(); - defer args.deinit(); - while (args.next(allocator)) |arg_or_err| { - const arg = try arg_or_err; - defer allocator.free(arg); - if (std.mem.eql(u8, arg, "-w")) { - try watch(display, window, "CLIPBOARD", stdout); - } - } - var result = (try printSelection(display, window, "CLIPBOARD", "UTF8_STRING", stdout)) or - (try printSelection(display, window, "CLIPBOARD", "STRING", stdout)); - if (!result) return error.ClipboardActionFailed; -} diff --git a/src/main-windows.zig b/src/main-windows.zig new file mode 100644 index 0000000..6e06409 --- /dev/null +++ b/src/main-windows.zig @@ -0,0 +1,10 @@ +const std = @import("std"); +const win = @cImport({ + @cInclude("windows.h"); +}); +pub fn clipboardAction(watch: bool) !void { + _ = watch; + const stdout = std.io.getStdOut().writer(); + try stdout.print("All your codebase are belong to us", .{}); + try stdout.print("{d}", .{win.HINSTANCE}); +} diff --git a/src/main.zig b/src/main.zig deleted file mode 100644 index 05282c6..0000000 --- a/src/main.zig +++ /dev/null @@ -1,11 +0,0 @@ -const std = @import("std"); - -pub fn main() !u8 { - if (std.builtin.os.tag == .linux) { - @import("linux.zig").clipboardAction() catch return 1; - } - if (std.builtin.os.tag == .windows) { - @import("windows.zig").clipboardAction() catch return 1; - } - return 0; -} diff --git a/src/windows.zig b/src/windows.zig deleted file mode 100644 index 4694d06..0000000 --- a/src/windows.zig +++ /dev/null @@ -1,6 +0,0 @@ -const std = @import("std"); - -pub fn clipboardAction() !void { - const stdout = std.io.getStdOut().writer(); - try stdout.print("All your codebase are belong to us", .{}); -}