zig 0.9.0 and allocator passdown/separate clipboard common logic
This commit is contained in:
		
							parent
							
								
									69d7d0611e
								
							
						
					
					
						commit
						eb8058c930
					
				
					 3 changed files with 79 additions and 43 deletions
				
			
		
							
								
								
									
										28
									
								
								src/clipboard.zig
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/clipboard.zig
									
										
									
									
									
										Normal 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"); | ||||
| } | ||||
|  | @ -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 | ||||
|  |  | |||
|  | @ -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 | ||||
| } | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue