zig 0.9.0 and allocator passdown/separate clipboard common logic

This commit is contained in:
Emil Lerch 2022-01-03 11:09:08 -08:00
parent 69d7d0611e
commit eb8058c930
Signed by: lobo
GPG Key ID: A7B62D657EF764F8
3 changed files with 79 additions and 43 deletions

28
src/clipboard.zig Normal file
View File

@ -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");
}

View File

@ -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

View File

@ -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
}