From eb8058c930b86335c880db683b65485faffcede5 Mon Sep 17 00:00:00 2001 From: Emil Lerch Date: Mon, 3 Jan 2022 11:09:08 -0800 Subject: [PATCH] zig 0.9.0 and allocator passdown/separate clipboard common logic --- src/clipboard.zig | 28 ++++++++++++++++++++++ src/main-linux.zig | 38 ++++++++++++++---------------- src/main-windows.zig | 56 ++++++++++++++++++++++++++------------------ 3 files changed, 79 insertions(+), 43 deletions(-) create mode 100644 src/clipboard.zig diff --git a/src/clipboard.zig b/src/clipboard.zig new file mode 100644 index 0000000..59cc937 --- /dev/null +++ b/src/clipboard.zig @@ -0,0 +1,28 @@ +const std = @import("std"); + +pub fn clipboardChanged(allocator: std.mem.Allocator, contents: []const u8) !void { + var arena_allocator = std.heap.ArenaAllocator.init(allocator); + defer arena_allocator.deinit(); + const aa = arena_allocator.allocator(); + const clip_contents = try aa.dupe(u8, contents); + defer aa.free(clip_contents); + + // Dear lord, change this + const key = [_]u8{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + }; + const in = [_]u8{ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff }; + var out: [16]u8 = undefined; + var ctx = std.crypto.core.aes.Aes256.initEnc(key); + ctx.encrypt(out[0..], in[0..]); + // Do the work. We are assumed here to + const stdout = std.io.getStdOut().writer(); + const writer = stdout; + try writer.print("{s}", .{clip_contents}); +} + +test "full integration" { + var allocator = std.testing.allocator; + try clipboardChanged(allocator, "hello world"); +} diff --git a/src/main-linux.zig b/src/main-linux.zig index be94ba7..7451bec 100644 --- a/src/main-linux.zig +++ b/src/main-linux.zig @@ -1,4 +1,6 @@ const std = @import("std"); +const clip = @import("clipboard.zig"); + const c = @cImport({ @cInclude("limits.h"); @cInclude("X11/Xlib.h"); @@ -9,7 +11,7 @@ pub fn main() !u8 { var watch = false; var gpa = std.heap.GeneralPurposeAllocator(.{}){}; defer _ = gpa.deinit(); - const allocator = &gpa.allocator; + const allocator = gpa.allocator(); var args = std.process.args(); defer args.deinit(); while (args.next(allocator)) |arg_or_err| { @@ -20,12 +22,11 @@ pub fn main() !u8 { break; } } - clipboardAction(watch) catch return 1; + clipboardAction(allocator, watch) catch return 1; return 0; } -pub fn clipboardAction(watch: bool) !void { - const stdout = std.io.getStdOut().writer(); +pub fn clipboardAction(allocator: std.mem.Allocator, watch: bool) !void { var display: *c.Display = c.XOpenDisplay(null).?; defer _ = c.XCloseDisplay(display); const default_screen = c.XDefaultScreen(display); @@ -33,13 +34,13 @@ pub fn clipboardAction(watch: bool) !void { 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 (watch) try watchClip(allocator, display, window, "CLIPBOARD"); + var result = (try printSelection(allocator, display, window, "CLIPBOARD", "UTF8_STRING")) or + (try printSelection(allocator, display, window, "CLIPBOARD", "STRING")); if (!result) return error.ClipboardActionFailed; } -fn watchClip(display: *c.Display, window: c.Window, bufname: [*c]const u8, writer: anytype) !void { +fn watchClip(allocator: std.mem.Allocator, display: *c.Display, window: c.Window, bufname: [*c]const u8) !void { var event_base: c_int = undefined; var error_base: c_int = undefined; var event: c.XEvent = undefined; @@ -54,14 +55,13 @@ fn watchClip(display: *c.Display, window: c.Window, bufname: [*c]const u8, write 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); + if (!try printSelection(allocator, display, window, bufname, "UTF8_STRING")) + _ = try printSelection(allocator, display, window, bufname, "STRING"); } } } -fn printSelection(display: *c.Display, window: c.Window, bufname: [*c]const u8, fmtname: [*c]const u8, writer: anytype) !bool { +fn printSelection(allocator: std.mem.Allocator, display: *c.Display, window: c.Window, bufname: [*c]const u8, fmtname: [*c]const u8) !bool { var ressize: c_ulong = undefined; var restail: c_ulong = undefined; var resbits: c_int = undefined; @@ -82,17 +82,15 @@ 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); if (fmtid != incrid) - try writer.print("{s}", .{result}); + _ = async clip.clipboardChanged(allocator, std.mem.span(result)); // TODO: Ensure we don't start queueing these things up if (fmtid == incrid) { ressize = 1; - var gpa = std.heap.GeneralPurposeAllocator(.{}){}; - defer _ = gpa.deinit(); - var arena_allocator = std.heap.ArenaAllocator.init(&gpa.allocator); + var arena_allocator = std.heap.ArenaAllocator.init(allocator); defer arena_allocator.deinit(); - var buffer = std.ArrayList(u8).init(&arena_allocator.allocator); + var local_allocator = arena_allocator.allocator(); + var buffer = std.ArrayList(u8).init(local_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) { @@ -101,9 +99,9 @@ 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); // Creates double free error, but not sure why - try buffer.appendSlice(try std.fmt.allocPrint(&arena_allocator.allocator, "{s}", .{result})); + try buffer.appendSlice(try std.fmt.allocPrint(local_allocator, "{s}", .{result})); } - try writer.print("{s}", .{buffer.items}); + _ = async clip.clipboardChanged(allocator, buffer.items); } return true; } else // request failed, e.g. owner can't convert to the target format diff --git a/src/main-windows.zig b/src/main-windows.zig index e30d77d..f452ab9 100644 --- a/src/main-windows.zig +++ b/src/main-windows.zig @@ -1,5 +1,6 @@ const std = @import("std"); const builtin = @import("builtin"); +const clip = @import("clipboard.zig"); const w = std.os.windows; extern "user32" fn MessageBoxA(hWnd: ?w.HANDLE, lpText: ?w.LPCSTR, lpCaption: ?w.LPCSTR, uType: w.UINT) callconv(w.WINAPI) c_int; @@ -76,7 +77,7 @@ extern "USER32" fn CreateWindowExA( hWndParent: ?w.HWND, hMenu: ?w.HMENU, hInstance: ?w.HINSTANCE, - lpParam: ?*c_void, + lpParam: ?*anyopaque, ) callconv(w.WINAPI) ?w.HWND; const WNDPROC = fn ( @@ -643,7 +644,7 @@ extern "KERNEL32" fn GlobalUnlock( extern "KERNEL32" fn GlobalLock( hMem: isize, -) callconv(w.WINAPI) ?*c_void; +) callconv(w.WINAPI) ?*anyopaque; const GLOBAL_ALLOC_FLAGS = enum(u32) { HND = 66, @@ -951,6 +952,7 @@ pub export fn wWinMain(hInstance: w.HINSTANCE, hPrevInstance: ?w.HINSTANCE, lpCm if (hwnd == null) return 0; + UpdateContents(hwnd.?); // Run the message loop. var msg: MSG = .{ @@ -974,7 +976,7 @@ pub export fn wWinMain(hInstance: w.HINSTANCE, hPrevInstance: ?w.HINSTANCE, lpCm } fn MainWndProc(hwnd: w.HWND, uMsg: u32, wParam: w.WPARAM, lParam: w.LPARAM) callconv(w.WINAPI) w.LRESULT { //APIENTRY { - const allocator = &gpa.allocator; + const allocator = gpa.allocator(); switch (uMsg) { WM_PAINT => { @@ -1035,7 +1037,6 @@ fn MainWndProc(hwnd: w.HWND, uMsg: u32, wParam: w.WPARAM, lParam: w.LPARAM) call }, @enumToInt(CF_TEXT) => { _ = GetClientRect(hwnd, &rc); - // TODO: copy our lpstr and ship it to our common handler _ = DrawTextA(hdc, contents, -1, &rc, DT_LEFT); }, @@ -1089,25 +1090,7 @@ fn MainWndProc(hwnd: w.HWND, uMsg: u32, wParam: w.WPARAM, lParam: w.LPARAM) call } }, WM_CLIPBOARDUPDATE => { // Message arrives only after AddClipboardFormatListener - - // Get a lock on the clipboard - if (OpenClipboard(hwnd) > 0) { - defer _ = CloseClipboard(); - var hglb = GetClipboardData(uFormat).?; - const hnd = @intCast(isize, @ptrToInt(hglb)); - var lpstr = GlobalLock(hnd).?; - defer _ = GlobalUnlock(hnd); - - if (free_contents) { - allocator.free(contents); - } - free_contents = true; - contents = std.fmt.allocPrintZ(allocator, "{s}", .{@ptrCast([*:0]const u8, lpstr)}) catch blk: { - _ = MessageBoxA(hwnd, "Allocation failed copying clipboard contents", "Error", 0); - free_contents = false; - break :blk ""; - }; - } + UpdateContents(hwnd); if (RedrawWindow(hwnd, null, null, RDW_INVALIDATE) != w.TRUE) { _ = MessageBoxA(hwnd, "Redraw failed", "Error", 0); } @@ -1168,6 +1151,10 @@ fn MainWndProc(hwnd: w.HWND, uMsg: u32, wParam: w.WPARAM, lParam: w.LPARAM) call } }, WM_DESTROY => { + // remove last item before we go down + if (free_contents) { + allocator.free(contents); + } _ = RemoveClipboardFormatListener(hwnd); _ = Shell_NotifyIconA(NIM_DELETE, &icon_data); PostQuitMessage(0); @@ -1187,3 +1174,26 @@ fn MainWndProc(hwnd: w.HWND, uMsg: u32, wParam: w.WPARAM, lParam: w.LPARAM) call } return 0; } + +fn UpdateContents(hwnd: w.HWND) void { + const allocator = gpa.allocator(); + // Get a lock on the clipboard + if (OpenClipboard(hwnd) > 0) { + defer _ = CloseClipboard(); + var hglb = GetClipboardData(uFormat).?; + const hnd = @intCast(isize, @ptrToInt(hglb)); + var lpstr = GlobalLock(hnd).?; + defer _ = GlobalUnlock(hnd); + + if (free_contents) { + allocator.free(contents); + } + free_contents = true; + contents = std.fmt.allocPrintZ(allocator, "{s}", .{@ptrCast([*:0]const u8, lpstr)}) catch blk: { + _ = MessageBoxA(hwnd, "Allocation failed copying clipboard contents", "Error", 0); + free_contents = false; + break :blk ""; + }; + } + _ = async clip.clipboardChanged(allocator, contents); // Notify common handler +}