|
1 | 1 | #import <Cocoa/Cocoa.h> |
| 2 | +#import <objc/runtime.h> |
2 | 3 | #include <cstring> |
3 | 4 | #include <iostream> |
4 | 5 | #include <string> |
|
23 | 24 | private: |
24 | 25 | WindowManager* manager_; |
25 | 26 | NativeAPIWindowManagerDelegate* delegate_; |
| 27 | + |
| 28 | + // Optional pre-show/hide hooks |
| 29 | + std::optional<WindowManager::WindowWillShowHook> will_show_hook_; |
| 30 | + std::optional<WindowManager::WindowWillHideHook> will_hide_hook_; |
| 31 | + |
| 32 | + friend class WindowManager; |
26 | 33 | }; |
27 | 34 |
|
28 | 35 | } // namespace nativeapi |
29 | 36 |
|
| 37 | +// MARK: - NSWindow Swizzling |
| 38 | + |
| 39 | +// Swizzled implementations call into WindowManager hooks, then forward to original implementations |
| 40 | +@interface NSWindow (NativeAPISwizzle) |
| 41 | +- (void)na_swizzled_makeKeyAndOrderFront:(id)sender; |
| 42 | +- (void)na_swizzled_orderOut:(id)sender; |
| 43 | +@end |
| 44 | + |
| 45 | +@implementation NSWindow (NativeAPISwizzle) |
| 46 | + |
| 47 | +- (void)na_swizzled_makeKeyAndOrderFront:(id)sender { |
| 48 | + // Invoke hook before showing |
| 49 | + nativeapi::WindowManager::GetInstance().InvokeWillShowHook([self windowNumber]); |
| 50 | + // Call original implementation (swapped) |
| 51 | + [self na_swizzled_makeKeyAndOrderFront:sender]; |
| 52 | +} |
| 53 | + |
| 54 | +- (void)na_swizzled_orderOut:(id)sender { |
| 55 | + // Invoke hook before hiding |
| 56 | + nativeapi::WindowManager::GetInstance().InvokeWillHideHook([self windowNumber]); |
| 57 | + // Call original implementation (swapped) |
| 58 | + [self na_swizzled_orderOut:sender]; |
| 59 | +} |
| 60 | + |
| 61 | +@end |
| 62 | + |
| 63 | +static void NativeAPIInstallNSWindowWillShowSwizzleOnce() { |
| 64 | + static dispatch_once_t onceTokenShow; |
| 65 | + dispatch_once(&onceTokenShow, ^{ |
| 66 | + Class cls = [NSWindow class]; |
| 67 | + SEL originalSel = @selector(makeKeyAndOrderFront:); |
| 68 | + SEL swizzledSel = @selector(na_swizzled_makeKeyAndOrderFront:); |
| 69 | + Method original = class_getInstanceMethod(cls, originalSel); |
| 70 | + Method swizzled = class_getInstanceMethod(cls, swizzledSel); |
| 71 | + if (original && swizzled) { |
| 72 | + method_exchangeImplementations(original, swizzled); |
| 73 | + } |
| 74 | + }); |
| 75 | +} |
| 76 | + |
| 77 | +static void NativeAPIInstallNSWindowWillHideSwizzleOnce() { |
| 78 | + static dispatch_once_t onceTokenHide; |
| 79 | + dispatch_once(&onceTokenHide, ^{ |
| 80 | + Class cls = [NSWindow class]; |
| 81 | + SEL originalSel = @selector(orderOut:); |
| 82 | + SEL swizzledSel = @selector(na_swizzled_orderOut:); |
| 83 | + Method original = class_getInstanceMethod(cls, originalSel); |
| 84 | + Method swizzled = class_getInstanceMethod(cls, swizzledSel); |
| 85 | + if (original && swizzled) { |
| 86 | + method_exchangeImplementations(original, swizzled); |
| 87 | + } |
| 88 | + }); |
| 89 | +} |
| 90 | + |
30 | 91 | // Objective-C delegate class to handle NSWindow notifications |
31 | 92 | @interface NativeAPIWindowManagerDelegate : NSObject |
32 | 93 | @property(nonatomic, assign) void* impl; // Use void* instead of private class |
@@ -286,19 +347,29 @@ - (void)windowWillClose:(NSNotification*)notification { |
286 | 347 | } |
287 | 348 |
|
288 | 349 | void WindowManager::SetWillShowHook(std::optional<WindowWillShowHook> hook) { |
289 | | - // Empty implementation |
| 350 | + pimpl_->will_show_hook_ = std::move(hook); |
| 351 | + if (pimpl_->will_show_hook_) { |
| 352 | + NativeAPIInstallNSWindowWillShowSwizzleOnce(); |
| 353 | + } |
290 | 354 | } |
291 | 355 |
|
292 | 356 | void WindowManager::SetWillHideHook(std::optional<WindowWillHideHook> hook) { |
293 | | - // Empty implementation |
| 357 | + pimpl_->will_hide_hook_ = std::move(hook); |
| 358 | + if (pimpl_->will_hide_hook_) { |
| 359 | + NativeAPIInstallNSWindowWillHideSwizzleOnce(); |
| 360 | + } |
294 | 361 | } |
295 | 362 |
|
296 | 363 | void WindowManager::InvokeWillShowHook(WindowId id) { |
297 | | - // Empty implementation |
| 364 | + if (pimpl_->will_show_hook_) { |
| 365 | + (*pimpl_->will_show_hook_)(id); |
| 366 | + } |
298 | 367 | } |
299 | 368 |
|
300 | 369 | void WindowManager::InvokeWillHideHook(WindowId id) { |
301 | | - // Empty implementation |
| 370 | + if (pimpl_->will_hide_hook_) { |
| 371 | + (*pimpl_->will_hide_hook_)(id); |
| 372 | + } |
302 | 373 | } |
303 | 374 |
|
304 | 375 | } // namespace nativeapi |
0 commit comments