| ... | ... | @@ -1,7 +1,8 @@ |
| 1 | 1 | // AppKit that winit, AccessKit and the app call and 10.6 lacks, added at load time with |
| 2 | 2 | // the neutral answer: scale 1, no precise scrolling, no appearances, no tabbing, no full |
| 3 | | // screen. `remote.sh selectors` lists what a binary names that 10.6 lacks. Linked from |
| 4 | | // the archive by the appearance name winit imports, so only AppKit binaries carry it. |
| 3 | // screen; window drags are done here. `remote.sh selectors` lists what a binary names |
| 4 | // that 10.6 lacks. Linked from the archive by the appearance name winit imports, so only |
| 5 | // AppKit binaries carry it. |
| 5 | 6 | // class_addMethod adds nothing where the system already has the method. |
| 6 | 7 | #include <ApplicationServices/ApplicationServices.h> |
| 7 | 8 | #include <objc/message.h> |
| ... | ... | @@ -53,6 +54,37 @@ static CGPoint point_from_screen(id self, SEL _cmd, CGPoint point) { |
| 53 | 54 | return CGPointMake(point.x - frame.origin.x, point.y - frame.origin.y); |
| 54 | 55 | } |
| 55 | 56 | |
| 57 | // 10.11: the window follows the pointer until the button comes up, as a press on its |
| 58 | // title does. |
| 59 | static void window_drag(id self, SEL _cmd, id event) { |
| 60 | typedef CGPoint (*SendPoint)(id, SEL); |
| 61 | typedef CGRect (*SendRect)(id, SEL); |
| 62 | id event_class = (id)objc_getClass("NSEvent"); |
| 63 | CGPoint start = ((SendPoint)objc_msgSend)(event_class, sel_registerName("mouseLocation")); |
| 64 | CGRect frame = ((SendRect)objc_msgSend_stret)(self, sel_registerName("frame")); |
| 65 | id app = SEND(objc_getClass("NSApplication"), "sharedApplication"); |
| 66 | id forever = SEND(objc_getClass("NSDate"), "distantFuture"); |
| 67 | for (;;) { |
| 68 | // NSLeftMouseDraggedMask | NSLeftMouseUpMask. |
| 69 | id next = ((id (*)(id, SEL, unsigned long long, id, CFStringRef, BOOL))objc_msgSend)( |
| 70 | app, sel_registerName("nextEventMatchingMask:untilDate:inMode:dequeue:"), |
| 71 | 1 << 6 | 1 << 2, forever, CFSTR("NSEventTrackingRunLoopMode"), YES); |
| 72 | // NSLeftMouseUp. |
| 73 | if (((unsigned long (*)(id, SEL))objc_msgSend)(next, sel_registerName("type")) == 2) { |
| 74 | // The button's release stays in the queue for whoever asked for the drag. |
| 75 | ((void (*)(id, SEL, id, BOOL))objc_msgSend)(app, sel_registerName("postEvent:atStart:"), next, YES); |
| 76 | return; |
| 77 | } |
| 78 | CGPoint now = ((SendPoint)objc_msgSend)(event_class, sel_registerName("mouseLocation")); |
| 79 | CGRect moved = frame; |
| 80 | moved.origin.x += now.x - start.x; |
| 81 | moved.origin.y += now.y - start.y; |
| 82 | moved = ((CGRect (*)(id, SEL, CGRect, id))objc_msgSend_stret)( |
| 83 | self, sel_registerName("constrainFrameRect:toScreen:"), moved, SEND(self, "screen")); |
| 84 | ((void (*)(id, SEL, CGPoint))objc_msgSend)(self, sel_registerName("setFrameOrigin:"), moved.origin); |
| 85 | } |
| 86 | } |
| 87 | |
| 56 | 88 | static id srgb_color(id self, SEL _cmd, CGFloat red, CGFloat green, CGFloat blue, CGFloat alpha) { |
| 57 | 89 | CGFloat components[] = {red, green, blue, alpha}; |
| 58 | 90 | return ((id (*)(id, SEL, id, CGFloat *, long))objc_msgSend)( |
| ... | ... | @@ -106,7 +138,7 @@ __attribute__((constructor)) static void polyfill(void) { |
| 106 | 138 | add("NSWindow", 0, "backingScaleFactor", one, "d@:"); |
| 107 | 139 | add("NSWindow", 0, "convertRectToScreen:", rect_to_screen, RECT "@:" RECT); |
| 108 | 140 | add("NSWindow", 0, "convertPointFromScreen:", point_from_screen, "{CGPoint=dd}@:{CGPoint=dd}"); |
| 109 | | add("NSWindow", 0, "performWindowDragWithEvent:", ignore, "v@:@"); |
| 141 | add("NSWindow", 0, "performWindowDragWithEvent:", window_drag, "v@:@"); |
| 110 | 142 | add("NSWindow", 0, "toggleFullScreen:", ignore, "v@:@"); |
| 111 | 143 | add("NSWindow", 0, "setTabbingMode:", ignore, "v@:q"); |
| 112 | 144 | add("NSWindow", 0, "setTabbingIdentifier:", ignore, "v@:@"); |