react-native-nswindow 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,683 @@
1
+ #import "RNNSWindowHelper.h"
2
+ #import "RNNSWindow.h"
3
+ #import <RCTAppDelegate.h>
4
+ #import <React/RCTConvert.h>
5
+ #import <React/RCTRootView.h>
6
+
7
+ @implementation RNNSWindowHelper {
8
+ NSMutableDictionary<NSString *, NSWindow *> *_windows;
9
+ NSMutableDictionary<NSString *, NSString *> *_windowNames;
10
+ NSMutableSet<NSString *> *_preventCloseWindows;
11
+ }
12
+
13
+ + (instancetype)shared {
14
+ static RNNSWindowHelper *instance = nil;
15
+ static dispatch_once_t onceToken;
16
+ dispatch_once(&onceToken, ^{
17
+ instance = [[RNNSWindowHelper alloc] init];
18
+ });
19
+ return instance;
20
+ }
21
+
22
+ - (instancetype)init {
23
+ self = [super init];
24
+ if (self) {
25
+ _windows = [NSMutableDictionary new];
26
+ _windowNames = [NSMutableDictionary new];
27
+ _preventCloseWindows = [NSMutableSet new];
28
+
29
+ NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
30
+ [nc addObserver:self
31
+ selector:@selector(notificationWindowWillClose:)
32
+ name:NSWindowWillCloseNotification
33
+ object:nil];
34
+ [nc addObserver:self
35
+ selector:@selector(notificationWindowDidBecomeKey:)
36
+ name:NSWindowDidBecomeKeyNotification
37
+ object:nil];
38
+ [nc addObserver:self
39
+ selector:@selector(notificationWindowDidResignKey:)
40
+ name:NSWindowDidResignKeyNotification
41
+ object:nil];
42
+ [nc addObserver:self
43
+ selector:@selector(notificationWindowDidMove:)
44
+ name:NSWindowDidMoveNotification
45
+ object:nil];
46
+ [nc addObserver:self
47
+ selector:@selector(notificationWindowDidResize:)
48
+ name:NSWindowDidResizeNotification
49
+ object:nil];
50
+ [nc addObserver:self
51
+ selector:@selector(notificationWindowDidMiniaturize:)
52
+ name:NSWindowDidMiniaturizeNotification
53
+ object:nil];
54
+ [nc addObserver:self
55
+ selector:@selector(notificationWindowDidDeminiaturize:)
56
+ name:NSWindowDidDeminiaturizeNotification
57
+ object:nil];
58
+ [nc addObserver:self
59
+ selector:@selector(notificationWindowDidEnterFullScreen:)
60
+ name:NSWindowDidEnterFullScreenNotification
61
+ object:nil];
62
+ [nc addObserver:self
63
+ selector:@selector(notificationWindowDidExitFullScreen:)
64
+ name:NSWindowDidExitFullScreenNotification
65
+ object:nil];
66
+ [nc addObserver:self
67
+ selector:@selector(notificationWindowDidChangeOcclusionState:)
68
+ name:NSWindowDidChangeOcclusionStateNotification
69
+ object:nil];
70
+ [nc addObserver:self
71
+ selector:@selector(notificationWindowDidChangeBackingProperties:)
72
+ name:NSWindowDidChangeBackingPropertiesNotification
73
+ object:nil];
74
+ [nc addObserver:self
75
+ selector:@selector(notificationScreenParametersDidChange:)
76
+ name:NSApplicationDidChangeScreenParametersNotification
77
+ object:nil];
78
+ }
79
+ return self;
80
+ }
81
+
82
+ - (NSString *)windowIdForWindow:(NSWindow *)window {
83
+ for (NSString *key in _windows) {
84
+ if (_windows[key] == window) {
85
+ return key;
86
+ }
87
+ }
88
+ NSString *windowId = [[NSUUID UUID] UUIDString];
89
+ _windows[windowId] = window;
90
+ NSString *name = window.title.length > 0
91
+ ? window.title
92
+ : NSStringFromClass([window class]) ?: @"unknown";
93
+ _windowNames[windowId] = name;
94
+ return windowId;
95
+ }
96
+
97
+ - (void)notificationWindowWillClose:(NSNotification *)notification {
98
+ NSWindow *window = notification.object;
99
+ if (!window) {
100
+ return;
101
+ }
102
+ NSString *windowId = [self windowIdForWindow:window];
103
+ [_preventCloseWindows removeObject:windowId];
104
+ [_windows removeObjectForKey:windowId];
105
+ [_windowNames removeObjectForKey:windowId];
106
+ if (self.module) {
107
+ self.module->emitOnWindowClose(std::string([windowId UTF8String]));
108
+ }
109
+ }
110
+
111
+ - (void)notificationWindowDidBecomeKey:(NSNotification *)notification {
112
+ NSWindow *window = notification.object;
113
+ NSString *windowId = [self windowIdForWindow:window];
114
+ if (self.module) {
115
+ self.module->emitOnWindowFocus(std::string([windowId UTF8String]));
116
+ }
117
+ }
118
+
119
+ - (void)notificationWindowDidResignKey:(NSNotification *)notification {
120
+ NSWindow *window = notification.object;
121
+ NSString *windowId = [self windowIdForWindow:window];
122
+ if (!windowId) {
123
+ return;
124
+ }
125
+ if (self.module) {
126
+ self.module->emitOnWindowBlur(std::string([windowId UTF8String]));
127
+ }
128
+ }
129
+
130
+ - (void)notificationWindowDidMove:(NSNotification *)notification {
131
+ NSWindow *window = notification.object;
132
+ NSString *windowId = [self windowIdForWindow:window];
133
+ if (!windowId) {
134
+ return;
135
+ }
136
+ if (self.module) {
137
+ NSRect frame = window.frame;
138
+ facebook::react::WindowMovePayload payload{
139
+ std::string([windowId UTF8String]), frame.origin.x, frame.origin.y};
140
+ self.module->emitOnWindowMove(payload);
141
+ }
142
+ }
143
+
144
+ - (void)notificationWindowDidResize:(NSNotification *)notification {
145
+ NSWindow *window = notification.object;
146
+ NSString *windowId = [self windowIdForWindow:window];
147
+ if (self.module) {
148
+ NSRect frame = window.frame;
149
+ facebook::react::WindowResizePayload payload{
150
+ std::string([windowId UTF8String]), frame.size.width,
151
+ frame.size.height};
152
+ self.module->emitOnWindowResize(payload);
153
+ }
154
+ }
155
+
156
+ - (void)notificationWindowDidMiniaturize:(NSNotification *)notification {
157
+ NSWindow *window = notification.object;
158
+ NSString *windowId = [self windowIdForWindow:window];
159
+ if (self.module) {
160
+ self.module->emitOnWindowMinimize(std::string([windowId UTF8String]));
161
+ }
162
+ }
163
+
164
+ - (void)notificationWindowDidDeminiaturize:(NSNotification *)notification {
165
+ NSWindow *window = notification.object;
166
+ NSString *windowId = [self windowIdForWindow:window];
167
+ if (self.module) {
168
+ self.module->emitOnWindowDeminimize(std::string([windowId UTF8String]));
169
+ }
170
+ }
171
+
172
+ - (void)notificationWindowDidEnterFullScreen:(NSNotification *)notification {
173
+ NSWindow *window = notification.object;
174
+ NSString *windowId = [self windowIdForWindow:window];
175
+ if (self.module) {
176
+ self.module->emitOnWindowEnterFullScreen(
177
+ std::string([windowId UTF8String]));
178
+ }
179
+ }
180
+
181
+ - (void)notificationWindowDidExitFullScreen:(NSNotification *)notification {
182
+ NSWindow *window = notification.object;
183
+ NSString *windowId = [self windowIdForWindow:window];
184
+ if (self.module) {
185
+ self.module->emitOnWindowExitFullScreen(std::string([windowId UTF8String]));
186
+ }
187
+ }
188
+
189
+ - (void)notificationWindowDidChangeOcclusionState:
190
+ (NSNotification *)notification {
191
+ NSWindow *window = notification.object;
192
+ NSString *windowId = [self windowIdForWindow:window];
193
+ if (self.module) {
194
+ bool isVisible =
195
+ (window.occlusionState & NSWindowOcclusionStateVisible) != 0;
196
+ facebook::react::WindowOcclusionStatePayload payload{
197
+ std::string([windowId UTF8String]), isVisible};
198
+ self.module->emitOnWindowOcclusionStateChange(payload);
199
+ }
200
+ }
201
+
202
+ - (void)notificationWindowDidChangeBackingProperties:
203
+ (NSNotification *)notification {
204
+ NSWindow *window = notification.object;
205
+ NSString *windowId = [self windowIdForWindow:window];
206
+ if (self.module) {
207
+ self.module->emitOnWindowBackingPropertiesChange(
208
+ std::string([windowId UTF8String]));
209
+ }
210
+ }
211
+
212
+ - (void)notificationScreenParametersDidChange:(NSNotification *)notification {
213
+ if (self.module) {
214
+ self.module->emitOnScreenInfoChange();
215
+ }
216
+ }
217
+
218
+ - (void)syncWithAppWindows {
219
+ NSArray<NSWindow *> *appWindows = [NSApp windows];
220
+
221
+ // Add untracked windows (windowIdForWindow auto-registers)
222
+ for (NSWindow *window in appWindows) {
223
+ [self windowIdForWindow:window];
224
+ }
225
+
226
+ // Remove gone windows
227
+ NSMutableArray<NSString *> *toRemove = [NSMutableArray new];
228
+ for (NSString *key in _windows) {
229
+ if (![appWindows containsObject:_windows[key]]) {
230
+ [toRemove addObject:key];
231
+ }
232
+ }
233
+ for (NSString *key in toRemove) {
234
+ [_windows removeObjectForKey:key];
235
+ [_windowNames removeObjectForKey:key];
236
+ }
237
+ }
238
+
239
+ - (NSWindow *_Nullable)windowForId:(NSString *)windowId {
240
+ return _windows[windowId];
241
+ }
242
+
243
+ - (NSArray<NSString *> *)allWindowIds {
244
+ [self syncWithAppWindows];
245
+ return [_windows allKeys];
246
+ }
247
+
248
+ - (NSString *_Nullable)windowNameForId:(NSString *)windowId {
249
+ return _windowNames[windowId];
250
+ }
251
+
252
+ - (void)removeWindowForId:(NSString *)windowId {
253
+ [_windows removeObjectForKey:windowId];
254
+ [_windowNames removeObjectForKey:windowId];
255
+ }
256
+
257
+ - (NSString *)createWindowWithComponent:(NSString *)componentName
258
+ windowName:(NSString *)windowName
259
+ initialProps:(NSDictionary *_Nullable)initialProps
260
+ x:(NSNumber *_Nullable)x
261
+ y:(NSNumber *_Nullable)y
262
+ width:(NSNumber *_Nullable)width
263
+ height:(NSNumber *_Nullable)height
264
+ minWidth:(NSNumber *_Nullable)minWidth
265
+ minHeight:(NSNumber *_Nullable)minHeight
266
+ maxWidth:(NSNumber *_Nullable)maxWidth
267
+ maxHeight:(NSNumber *_Nullable)maxHeight
268
+ center:(BOOL)center
269
+ title:(NSString *_Nullable)title
270
+ titleBarStyle:(NSString *_Nullable)titleBarStyle
271
+ vibrancy:(NSString *_Nullable)vibrancy
272
+ backgroundColor:(NSString *_Nullable)backgroundColor
273
+ transparent:(BOOL)transparent
274
+ hasShadow:(BOOL)hasShadow
275
+ resizable:(BOOL)resizable
276
+ movable:(BOOL)movable
277
+ minimizable:(BOOL)minimizable
278
+ closable:(BOOL)closable
279
+ zoomable:(BOOL)zoomable
280
+ alwaysOnTop:(BOOL)alwaysOnTop
281
+ level:(NSString *_Nullable)level
282
+ show:(BOOL)show
283
+ focusOnCreate:(BOOL)focusOnCreate
284
+ autoSaveFrame:(NSString *_Nullable)autoSaveFrame {
285
+
286
+ NSString *windowId = [[NSUUID UUID] UUIDString];
287
+
288
+ CGFloat w = width ? width.doubleValue : 400;
289
+ CGFloat h = height ? height.doubleValue : 300;
290
+ CGFloat originX = x ? x.doubleValue : 100;
291
+ CGFloat originY = y ? y.doubleValue : 100;
292
+
293
+ NSWindowStyleMask styleMask = NSWindowStyleMaskTitled;
294
+ if (closable) {
295
+ styleMask |= NSWindowStyleMaskClosable;
296
+ }
297
+ if (minimizable) {
298
+ styleMask |= NSWindowStyleMaskMiniaturizable;
299
+ }
300
+ if (resizable) {
301
+ styleMask |= NSWindowStyleMaskResizable;
302
+ }
303
+
304
+ NSRect frame = NSMakeRect(originX, originY, w, h);
305
+ NSWindow *window =
306
+ [[NSWindow alloc] initWithContentRect:frame
307
+ styleMask:styleMask
308
+ backing:NSBackingStoreBuffered
309
+ defer:NO];
310
+
311
+ window.delegate = self;
312
+ window.releasedWhenClosed = NO;
313
+ window.movable = movable;
314
+ window.hasShadow = hasShadow;
315
+
316
+ if (title) {
317
+ window.title = title;
318
+ } else {
319
+ window.title = windowName;
320
+ }
321
+
322
+ // Title bar style
323
+ if ([titleBarStyle isEqualToString:@"hidden"]) {
324
+ window.titlebarAppearsTransparent = YES;
325
+ window.titleVisibility = NSWindowTitleHidden;
326
+ } else if ([titleBarStyle isEqualToString:@"hiddenInset"]) {
327
+ window.titlebarAppearsTransparent = YES;
328
+ window.titleVisibility = NSWindowTitleHidden;
329
+ styleMask |= NSWindowStyleMaskFullSizeContentView;
330
+ window.styleMask = styleMask;
331
+ } else if ([titleBarStyle isEqualToString:@"transparent"]) {
332
+ window.titlebarAppearsTransparent = YES;
333
+ }
334
+
335
+ // Transparent window
336
+ if (transparent) {
337
+ window.opaque = NO;
338
+ }
339
+ if (backgroundColor) {
340
+ window.backgroundColor = [RCTConvert NSColor:backgroundColor];
341
+ }
342
+
343
+ // Min/Max sizes
344
+ if (minWidth || minHeight) {
345
+ window.minSize = NSMakeSize(minWidth ? minWidth.doubleValue : 0,
346
+ minHeight ? minHeight.doubleValue : 0);
347
+ }
348
+ if (maxWidth || maxHeight) {
349
+ window.maxSize =
350
+ NSMakeSize(maxWidth ? maxWidth.doubleValue : CGFLOAT_MAX,
351
+ maxHeight ? maxHeight.doubleValue : CGFLOAT_MAX);
352
+ }
353
+
354
+ // Window level
355
+ if (alwaysOnTop || [level isEqualToString:@"floating"]) {
356
+ window.level = NSFloatingWindowLevel;
357
+ } else if ([level isEqualToString:@"modalPanel"]) {
358
+ window.level = NSModalPanelWindowLevel;
359
+ } else if ([level isEqualToString:@"mainMenu"]) {
360
+ window.level = NSMainMenuWindowLevel;
361
+ } else if ([level isEqualToString:@"statusBar"]) {
362
+ window.level = NSStatusWindowLevel;
363
+ } else if ([level isEqualToString:@"screenSaver"]) {
364
+ window.level = NSScreenSaverWindowLevel;
365
+ }
366
+
367
+ // Vibrancy
368
+ if (vibrancy && ![vibrancy isEqualToString:@"none"]) {
369
+ NSVisualEffectView *effectView =
370
+ [[NSVisualEffectView alloc] initWithFrame:window.contentView.bounds];
371
+ effectView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
372
+ effectView.blendingMode = NSVisualEffectBlendingModeBehindWindow;
373
+ effectView.state = NSVisualEffectStateActive;
374
+
375
+ if ([vibrancy isEqualToString:@"sidebar"]) {
376
+ effectView.material = NSVisualEffectMaterialSidebar;
377
+ } else if ([vibrancy isEqualToString:@"menu"]) {
378
+ effectView.material = NSVisualEffectMaterialMenu;
379
+ } else if ([vibrancy isEqualToString:@"popover"]) {
380
+ effectView.material = NSVisualEffectMaterialPopover;
381
+ } else if ([vibrancy isEqualToString:@"fullScreenUI"]) {
382
+ effectView.material = NSVisualEffectMaterialFullScreenUI;
383
+ } else if ([vibrancy isEqualToString:@"underWindowBackground"]) {
384
+ effectView.material = NSVisualEffectMaterialUnderWindowBackground;
385
+ } else if ([vibrancy isEqualToString:@"hudWindow"]) {
386
+ effectView.material = NSVisualEffectMaterialHUDWindow;
387
+ }
388
+
389
+ window.contentView = effectView;
390
+ }
391
+
392
+ // Auto-save frame
393
+ if (autoSaveFrame) {
394
+ [window setFrameAutosaveName:autoSaveFrame];
395
+ }
396
+
397
+ // Center
398
+ if (center) {
399
+ [window center];
400
+ }
401
+
402
+ // Create React root view via RCTRootViewFactory
403
+ #pragma clang diagnostic push
404
+ #pragma clang diagnostic ignored "-Wdeprecated-declarations"
405
+ RCTAppDelegate *appDelegate = (RCTAppDelegate *)[NSApp delegate];
406
+ #pragma clang diagnostic pop
407
+ RCTRootViewFactory *factory = [appDelegate rootViewFactory];
408
+ NSView *rootView = [factory viewWithModuleName:componentName
409
+ initialProperties:initialProps];
410
+
411
+ if (vibrancy && ![vibrancy isEqualToString:@"none"]) {
412
+ rootView.frame = window.contentView.bounds;
413
+ rootView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
414
+ [window.contentView addSubview:rootView];
415
+ } else {
416
+ window.contentView = rootView;
417
+ }
418
+
419
+ _windows[windowId] = window;
420
+ _windowNames[windowId] = windowName;
421
+
422
+ // Zoomable
423
+ if (!zoomable) {
424
+ NSButton *zoomBtn = [window standardWindowButton:NSWindowZoomButton];
425
+ if (zoomBtn) {
426
+ zoomBtn.enabled = NO;
427
+ }
428
+ }
429
+
430
+ // Show/focus
431
+ if (show) {
432
+ if (focusOnCreate) {
433
+ [window makeKeyAndOrderFront:nil];
434
+ } else {
435
+ [window orderFront:nil];
436
+ }
437
+ }
438
+
439
+ return windowId;
440
+ }
441
+
442
+ - (BOOL)modifyWindow:(NSString *)windowId
443
+ x:(NSNumber *_Nullable)x
444
+ y:(NSNumber *_Nullable)y
445
+ width:(NSNumber *_Nullable)width
446
+ height:(NSNumber *_Nullable)height
447
+ minWidth:(NSNumber *_Nullable)minWidth
448
+ minHeight:(NSNumber *_Nullable)minHeight
449
+ maxWidth:(NSNumber *_Nullable)maxWidth
450
+ maxHeight:(NSNumber *_Nullable)maxHeight
451
+ center:(NSNumber *_Nullable)center
452
+ title:(NSString *_Nullable)title
453
+ titleBarStyle:(NSString *_Nullable)titleBarStyle
454
+ vibrancy:(NSString *_Nullable)vibrancy
455
+ backgroundColor:(NSString *_Nullable)backgroundColor
456
+ transparent:(NSNumber *_Nullable)transparent
457
+ hasShadow:(NSNumber *_Nullable)hasShadow
458
+ resizable:(NSNumber *_Nullable)resizable
459
+ movable:(NSNumber *_Nullable)movable
460
+ minimizable:(NSNumber *_Nullable)minimizable
461
+ closable:(NSNumber *_Nullable)closable
462
+ zoomable:(NSNumber *_Nullable)zoomable
463
+ alwaysOnTop:(NSNumber *_Nullable)alwaysOnTop
464
+ level:(NSString *_Nullable)level
465
+ show:(NSNumber *_Nullable)show
466
+ focusOnCreate:(NSNumber *_Nullable)focusOnCreate
467
+ autoSaveFrame:(NSString *_Nullable)autoSaveFrame
468
+ stopShouldClose:(NSNumber *_Nullable)stopShouldClose {
469
+
470
+ NSWindow *window = [self windowForId:windowId];
471
+ if (!window) {
472
+ return NO;
473
+ }
474
+
475
+ NSRect frame = window.frame;
476
+ BOOL frameChanged = NO;
477
+ if (x) {
478
+ frame.origin.x = x.doubleValue;
479
+ frameChanged = YES;
480
+ }
481
+ if (y) {
482
+ frame.origin.y = y.doubleValue;
483
+ frameChanged = YES;
484
+ }
485
+ if (width) {
486
+ frame.size.width = width.doubleValue;
487
+ frameChanged = YES;
488
+ }
489
+ if (height) {
490
+ frame.size.height = height.doubleValue;
491
+ frameChanged = YES;
492
+ }
493
+ if (frameChanged) {
494
+ [window setFrame:frame display:YES animate:YES];
495
+ }
496
+
497
+ if (minWidth || minHeight) {
498
+ window.minSize =
499
+ NSMakeSize(minWidth ? minWidth.doubleValue : window.minSize.width,
500
+ minHeight ? minHeight.doubleValue : window.minSize.height);
501
+ }
502
+ if (maxWidth || maxHeight) {
503
+ window.maxSize =
504
+ NSMakeSize(maxWidth ? maxWidth.doubleValue : window.maxSize.width,
505
+ maxHeight ? maxHeight.doubleValue : window.maxSize.height);
506
+ }
507
+
508
+ if (center && center.boolValue) {
509
+ [window center];
510
+ }
511
+ if (title) {
512
+ window.title = title;
513
+ }
514
+
515
+ // Title bar style
516
+ if (titleBarStyle) {
517
+ if ([titleBarStyle isEqualToString:@"hidden"]) {
518
+ window.titlebarAppearsTransparent = YES;
519
+ window.titleVisibility = NSWindowTitleHidden;
520
+ window.styleMask &= ~NSWindowStyleMaskFullSizeContentView;
521
+ } else if ([titleBarStyle isEqualToString:@"hiddenInset"]) {
522
+ window.titlebarAppearsTransparent = YES;
523
+ window.titleVisibility = NSWindowTitleHidden;
524
+ window.styleMask |= NSWindowStyleMaskFullSizeContentView;
525
+ } else if ([titleBarStyle isEqualToString:@"transparent"]) {
526
+ window.titlebarAppearsTransparent = YES;
527
+ window.titleVisibility = NSWindowTitleVisible;
528
+ window.styleMask &= ~NSWindowStyleMaskFullSizeContentView;
529
+ } else {
530
+ window.titlebarAppearsTransparent = NO;
531
+ window.titleVisibility = NSWindowTitleVisible;
532
+ window.styleMask &= ~NSWindowStyleMaskFullSizeContentView;
533
+ }
534
+ }
535
+
536
+ // Background color
537
+ if (transparent) {
538
+ window.opaque = !transparent.boolValue;
539
+ }
540
+ if (backgroundColor) {
541
+ window.backgroundColor = [RCTConvert NSColor:backgroundColor];
542
+ }
543
+
544
+ // Shadow
545
+ if (hasShadow) {
546
+ window.hasShadow = hasShadow.boolValue;
547
+ }
548
+
549
+ // Vibrancy
550
+ if (vibrancy) {
551
+ NSView *content = window.contentView;
552
+ if ([content isKindOfClass:[NSVisualEffectView class]]) {
553
+ NSArray<NSView *> *subs = [content.subviews copy];
554
+ if ([vibrancy isEqualToString:@"none"]) {
555
+ if (subs.count > 0) {
556
+ window.contentView = subs[0];
557
+ }
558
+ } else {
559
+ NSVisualEffectView *ev = (NSVisualEffectView *)content;
560
+ ev.material = [self materialForVibrancy:vibrancy];
561
+ }
562
+ } else if (![vibrancy isEqualToString:@"none"]) {
563
+ NSVisualEffectView *ev =
564
+ [[NSVisualEffectView alloc] initWithFrame:content.bounds];
565
+ ev.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
566
+ ev.blendingMode = NSVisualEffectBlendingModeBehindWindow;
567
+ ev.state = NSVisualEffectStateActive;
568
+ ev.material = [self materialForVibrancy:vibrancy];
569
+ content.frame = ev.bounds;
570
+ content.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
571
+ window.contentView = ev;
572
+ [ev addSubview:content];
573
+ }
574
+ }
575
+
576
+ if (resizable) {
577
+ if (resizable.boolValue) {
578
+ window.styleMask |= NSWindowStyleMaskResizable;
579
+ } else {
580
+ window.styleMask &= ~NSWindowStyleMaskResizable;
581
+ }
582
+ }
583
+ if (movable) {
584
+ window.movable = movable.boolValue;
585
+ }
586
+ if (minimizable) {
587
+ if (minimizable.boolValue) {
588
+ window.styleMask |= NSWindowStyleMaskMiniaturizable;
589
+ } else {
590
+ window.styleMask &= ~NSWindowStyleMaskMiniaturizable;
591
+ }
592
+ }
593
+ if (closable) {
594
+ if (closable.boolValue) {
595
+ window.styleMask |= NSWindowStyleMaskClosable;
596
+ } else {
597
+ window.styleMask &= ~NSWindowStyleMaskClosable;
598
+ }
599
+ }
600
+ if (zoomable) {
601
+ NSButton *zoomBtn = [window standardWindowButton:NSWindowZoomButton];
602
+ if (zoomBtn) {
603
+ zoomBtn.enabled = zoomable.boolValue;
604
+ }
605
+ }
606
+ if (alwaysOnTop) {
607
+ window.level =
608
+ alwaysOnTop.boolValue ? NSFloatingWindowLevel : NSNormalWindowLevel;
609
+ } else if (level) {
610
+ if ([level isEqualToString:@"floating"]) {
611
+ window.level = NSFloatingWindowLevel;
612
+ } else if ([level isEqualToString:@"modalPanel"]) {
613
+ window.level = NSModalPanelWindowLevel;
614
+ } else if ([level isEqualToString:@"mainMenu"]) {
615
+ window.level = NSMainMenuWindowLevel;
616
+ } else if ([level isEqualToString:@"statusBar"]) {
617
+ window.level = NSStatusWindowLevel;
618
+ } else if ([level isEqualToString:@"screenSaver"]) {
619
+ window.level = NSScreenSaverWindowLevel;
620
+ } else {
621
+ window.level = NSNormalWindowLevel;
622
+ }
623
+ }
624
+ if (show) {
625
+ if (show.boolValue) {
626
+ if (focusOnCreate && focusOnCreate.boolValue) {
627
+ [window makeKeyAndOrderFront:nil];
628
+ } else {
629
+ [window orderFront:nil];
630
+ }
631
+ } else {
632
+ [window orderOut:nil];
633
+ }
634
+ }
635
+ if (autoSaveFrame) {
636
+ [window setFrameAutosaveName:autoSaveFrame];
637
+ }
638
+ if (stopShouldClose) {
639
+ [self setStopShouldClose:stopShouldClose.boolValue forWindowId:windowId];
640
+ }
641
+
642
+ return YES;
643
+ }
644
+
645
+ - (NSVisualEffectMaterial)materialForVibrancy:(NSString *)vibrancy {
646
+ if ([vibrancy isEqualToString:@"sidebar"]) {
647
+ return NSVisualEffectMaterialSidebar;
648
+ } else if ([vibrancy isEqualToString:@"menu"]) {
649
+ return NSVisualEffectMaterialMenu;
650
+ } else if ([vibrancy isEqualToString:@"popover"]) {
651
+ return NSVisualEffectMaterialPopover;
652
+ } else if ([vibrancy isEqualToString:@"fullScreenUI"]) {
653
+ return NSVisualEffectMaterialFullScreenUI;
654
+ } else if ([vibrancy isEqualToString:@"underWindowBackground"]) {
655
+ return NSVisualEffectMaterialUnderWindowBackground;
656
+ } else if ([vibrancy isEqualToString:@"hudWindow"]) {
657
+ return NSVisualEffectMaterialHUDWindow;
658
+ }
659
+ return NSVisualEffectMaterialWindowBackground;
660
+ }
661
+
662
+ #pragma mark - NSWindowDelegate
663
+
664
+ - (BOOL)windowShouldClose:(NSWindow *)sender {
665
+ NSString *windowId = [self windowIdForWindow:sender];
666
+ if (self.module) {
667
+ self.module->emitOnWindowWillClose(std::string([windowId UTF8String]));
668
+ }
669
+ if ([_preventCloseWindows containsObject:windowId]) {
670
+ return NO;
671
+ }
672
+ return YES;
673
+ }
674
+
675
+ - (void)setStopShouldClose:(BOOL)stop forWindowId:(NSString *)windowId {
676
+ if (stop) {
677
+ [_preventCloseWindows addObject:windowId];
678
+ } else {
679
+ [_preventCloseWindows removeObject:windowId];
680
+ }
681
+ }
682
+
683
+ @end
@@ -0,0 +1,19 @@
1
+ #include "RNNSWindow.h"
2
+ #import <Foundation/Foundation.h>
3
+ #include <ReactCommon/CxxTurboModuleUtils.h>
4
+
5
+ @interface RNNSWindowLoader : NSObject
6
+ @end
7
+
8
+ @implementation RNNSWindowLoader
9
+
10
+ + (void)load {
11
+ facebook::react::registerCxxModuleToGlobalModuleMap(
12
+ "NSWindowModule",
13
+ [](std::shared_ptr<facebook::react::CallInvoker> jsInvoker) {
14
+ return std::make_shared<facebook::react::RNNSWindow>(
15
+ std::move(jsInvoker));
16
+ });
17
+ }
18
+
19
+ @end