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.
- package/README.md +150 -0
- package/macos/RNNSWindow.h +142 -0
- package/macos/RNNSWindow.mm +570 -0
- package/macos/RNNSWindowHelper.h +80 -0
- package/macos/RNNSWindowHelper.mm +683 -0
- package/macos/RNNSWindowLoader.mm +19 -0
- package/package.json +53 -0
- package/react-native-nswindow.podspec +18 -0
- package/spec/NativeNSWindow.ts +148 -0
- package/src/index.ts +16 -0
|
@@ -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
|