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 std = @import("std"); | ||||||
|  | const clip = @import("clipboard.zig"); | ||||||
|  | 
 | ||||||
| const c = @cImport({ | const c = @cImport({ | ||||||
|     @cInclude("limits.h"); |     @cInclude("limits.h"); | ||||||
|     @cInclude("X11/Xlib.h"); |     @cInclude("X11/Xlib.h"); | ||||||
|  | @ -9,7 +11,7 @@ pub fn main() !u8 { | ||||||
|     var watch = false; |     var watch = false; | ||||||
|     var gpa = std.heap.GeneralPurposeAllocator(.{}){}; |     var gpa = std.heap.GeneralPurposeAllocator(.{}){}; | ||||||
|     defer _ = gpa.deinit(); |     defer _ = gpa.deinit(); | ||||||
|     const allocator = &gpa.allocator; |     const allocator = gpa.allocator(); | ||||||
|     var args = std.process.args(); |     var args = std.process.args(); | ||||||
|     defer args.deinit(); |     defer args.deinit(); | ||||||
|     while (args.next(allocator)) |arg_or_err| { |     while (args.next(allocator)) |arg_or_err| { | ||||||
|  | @ -20,12 +22,11 @@ pub fn main() !u8 { | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     clipboardAction(watch) catch return 1; |     clipboardAction(allocator, watch) catch return 1; | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn clipboardAction(watch: bool) !void { | pub fn clipboardAction(allocator: std.mem.Allocator, watch: bool) !void { | ||||||
|     const stdout = std.io.getStdOut().writer(); |  | ||||||
|     var display: *c.Display = c.XOpenDisplay(null).?; |     var display: *c.Display = c.XOpenDisplay(null).?; | ||||||
|     defer _ = c.XCloseDisplay(display); |     defer _ = c.XCloseDisplay(display); | ||||||
|     const default_screen = c.XDefaultScreen(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); |     var window = c.XCreateSimpleWindow(display, c.XDefaultRootWindow(display), 0, 0, 1, 1, 0, color, color); | ||||||
|     defer _ = c.XDestroyWindow(display, window); |     defer _ = c.XDestroyWindow(display, window); | ||||||
|     // Watch will not return |     // Watch will not return | ||||||
|     if (watch) try watchClip(display, window, "CLIPBOARD", stdout); |     if (watch) try watchClip(allocator, display, window, "CLIPBOARD"); | ||||||
|     var result = (try printSelection(display, window, "CLIPBOARD", "UTF8_STRING", stdout)) or |     var result = (try printSelection(allocator, display, window, "CLIPBOARD", "UTF8_STRING")) or | ||||||
|         (try printSelection(display, window, "CLIPBOARD", "STRING", stdout)); |         (try printSelection(allocator, display, window, "CLIPBOARD", "STRING")); | ||||||
|     if (!result) return error.ClipboardActionFailed; |     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 event_base: c_int = undefined; | ||||||
|     var error_base: c_int = undefined; |     var error_base: c_int = undefined; | ||||||
|     var event: c.XEvent = 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 |         if (event.type == event_base + c.XFixesSelectionNotify and | ||||||
|             event.xselection.property == bufid) |             event.xselection.property == bufid) | ||||||
|         { |         { | ||||||
|             _ = try writer.print("y", .{}); |             if (!try printSelection(allocator, display, window, bufname, "UTF8_STRING")) | ||||||
|             if (!try printSelection(display, window, bufname, "UTF8_STRING", writer)) |                 _ = try printSelection(allocator, display, window, bufname, "STRING"); | ||||||
|                 _ = 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 { | 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 ressize: c_ulong = undefined; | ||||||
|     var restail: c_ulong = undefined; |     var restail: c_ulong = undefined; | ||||||
|     var resbits: c_int = 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); |         _ = c.XGetWindowProperty(display, window, propid, 0, c.LONG_MAX / 4, c.True, c.AnyPropertyType, &fmtid, &resbits, &ressize, &restail, &result); | ||||||
|         defer _ = c.XFree(result); |         defer _ = c.XFree(result); | ||||||
|         if (fmtid != incrid) |         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) { |         if (fmtid == incrid) { | ||||||
|             ressize = 1; |             ressize = 1; | ||||||
|             var gpa = std.heap.GeneralPurposeAllocator(.{}){}; |             var arena_allocator = std.heap.ArenaAllocator.init(allocator); | ||||||
|             defer _ = gpa.deinit(); |  | ||||||
|             var arena_allocator = std.heap.ArenaAllocator.init(&gpa.allocator); |  | ||||||
|             defer arena_allocator.deinit(); |             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(); |             defer buffer.deinit(); | ||||||
|             // try writer.print("BIG:", .{}); |  | ||||||
|             while (ressize > 0) { |             while (ressize > 0) { | ||||||
|                 _ = c.XNextEvent(display, &event); |                 _ = c.XNextEvent(display, &event); | ||||||
|                 while (event.type != c.PropertyNotify or event.xproperty.atom != propid or event.xproperty.state != c.PropertyNewValue) { |                 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); |                 _ = 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 |                 //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; |         return true; | ||||||
|     } else // request failed, e.g. owner can't convert to the target format |     } else // request failed, e.g. owner can't convert to the target format | ||||||
|  |  | ||||||
|  | @ -1,5 +1,6 @@ | ||||||
| const std = @import("std"); | const std = @import("std"); | ||||||
| const builtin = @import("builtin"); | const builtin = @import("builtin"); | ||||||
|  | const clip = @import("clipboard.zig"); | ||||||
| const w = std.os.windows; | 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; | 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, |     hWndParent: ?w.HWND, | ||||||
|     hMenu: ?w.HMENU, |     hMenu: ?w.HMENU, | ||||||
|     hInstance: ?w.HINSTANCE, |     hInstance: ?w.HINSTANCE, | ||||||
|     lpParam: ?*c_void, |     lpParam: ?*anyopaque, | ||||||
| ) callconv(w.WINAPI) ?w.HWND; | ) callconv(w.WINAPI) ?w.HWND; | ||||||
| 
 | 
 | ||||||
| const WNDPROC = fn ( | const WNDPROC = fn ( | ||||||
|  | @ -643,7 +644,7 @@ extern "KERNEL32" fn GlobalUnlock( | ||||||
| 
 | 
 | ||||||
| extern "KERNEL32" fn GlobalLock( | extern "KERNEL32" fn GlobalLock( | ||||||
|     hMem: isize, |     hMem: isize, | ||||||
| ) callconv(w.WINAPI) ?*c_void; | ) callconv(w.WINAPI) ?*anyopaque; | ||||||
| 
 | 
 | ||||||
| const GLOBAL_ALLOC_FLAGS = enum(u32) { | const GLOBAL_ALLOC_FLAGS = enum(u32) { | ||||||
|     HND = 66, |     HND = 66, | ||||||
|  | @ -951,6 +952,7 @@ pub export fn wWinMain(hInstance: w.HINSTANCE, hPrevInstance: ?w.HINSTANCE, lpCm | ||||||
|     if (hwnd == null) |     if (hwnd == null) | ||||||
|         return 0; |         return 0; | ||||||
| 
 | 
 | ||||||
|  |     UpdateContents(hwnd.?); | ||||||
|     // Run the message loop. |     // Run the message loop. | ||||||
| 
 | 
 | ||||||
|     var msg: MSG = .{ |     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 { | 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) { |     switch (uMsg) { | ||||||
|         WM_PAINT => { |         WM_PAINT => { | ||||||
|  | @ -1035,7 +1037,6 @@ fn MainWndProc(hwnd: w.HWND, uMsg: u32, wParam: w.WPARAM, lParam: w.LPARAM) call | ||||||
|                 }, |                 }, | ||||||
|                 @enumToInt(CF_TEXT) => { |                 @enumToInt(CF_TEXT) => { | ||||||
|                     _ = GetClientRect(hwnd, &rc); |                     _ = GetClientRect(hwnd, &rc); | ||||||
|                     // TODO: copy our lpstr and ship it to our common handler |  | ||||||
|                     _ = DrawTextA(hdc, contents, -1, &rc, DT_LEFT); |                     _ = 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 |         WM_CLIPBOARDUPDATE => { // Message arrives only after AddClipboardFormatListener | ||||||
| 
 |             UpdateContents(hwnd); | ||||||
|             // 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 ""; |  | ||||||
|                 }; |  | ||||||
|             } |  | ||||||
|             if (RedrawWindow(hwnd, null, null, RDW_INVALIDATE) != w.TRUE) { |             if (RedrawWindow(hwnd, null, null, RDW_INVALIDATE) != w.TRUE) { | ||||||
|                 _ = MessageBoxA(hwnd, "Redraw failed", "Error", 0); |                 _ = 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 => { |         WM_DESTROY => { | ||||||
|  |             // remove last item before we go down | ||||||
|  |             if (free_contents) { | ||||||
|  |                 allocator.free(contents); | ||||||
|  |             } | ||||||
|             _ = RemoveClipboardFormatListener(hwnd); |             _ = RemoveClipboardFormatListener(hwnd); | ||||||
|             _ = Shell_NotifyIconA(NIM_DELETE, &icon_data); |             _ = Shell_NotifyIconA(NIM_DELETE, &icon_data); | ||||||
|             PostQuitMessage(0); |             PostQuitMessage(0); | ||||||
|  | @ -1187,3 +1174,26 @@ fn MainWndProc(hwnd: w.HWND, uMsg: u32, wParam: w.WPARAM, lParam: w.LPARAM) call | ||||||
|     } |     } | ||||||
|     return 0; |     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