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,570 @@
|
|
|
1
|
+
#import "RNNSWindow.h"
|
|
2
|
+
#import "RNNSWindowHelper.h"
|
|
3
|
+
#import <React/RCTConvert.h>
|
|
4
|
+
|
|
5
|
+
// ─── C++ Implementation ───
|
|
6
|
+
|
|
7
|
+
namespace facebook::react {
|
|
8
|
+
|
|
9
|
+
RNNSWindow::RNNSWindow(std::shared_ptr<CallInvoker> jsInvoker)
|
|
10
|
+
: NativeNSWindowCxxSpec(std::move(jsInvoker)) {
|
|
11
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
12
|
+
[RNNSWindowHelper shared].module = this;
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
RNNSWindow::~RNNSWindow() {
|
|
17
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
18
|
+
if ([RNNSWindowHelper shared].module == this) {
|
|
19
|
+
[RNNSWindowHelper shared].module = nullptr;
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
jsi::Value RNNSWindow::addWindow(jsi::Runtime &rt, jsi::Object props) {
|
|
25
|
+
auto p = NativeNSWindowWindowPropsBridging<WindowProps>::fromJs(rt, props,
|
|
26
|
+
jsInvoker_);
|
|
27
|
+
|
|
28
|
+
NSString *nsComponentName =
|
|
29
|
+
[NSString stringWithUTF8String:p.componentName.c_str()];
|
|
30
|
+
NSString *nsWindowName = [NSString stringWithUTF8String:p.windowName.c_str()];
|
|
31
|
+
|
|
32
|
+
auto toNSString = [](const std::optional<std::string> &s) -> NSString * {
|
|
33
|
+
return s ? [NSString stringWithUTF8String:s->c_str()] : nil;
|
|
34
|
+
};
|
|
35
|
+
auto toNSNumber = [](const std::optional<double> &d) -> NSNumber * {
|
|
36
|
+
return d ? @(*d) : nil;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
// Convert initialProps jsi::Object → NSDictionary (shallow)
|
|
40
|
+
NSDictionary *initialProps = nil;
|
|
41
|
+
{
|
|
42
|
+
auto names = p.initialProps.getPropertyNames(rt);
|
|
43
|
+
if (names.size(rt) > 0) {
|
|
44
|
+
NSMutableDictionary *dict = [NSMutableDictionary new];
|
|
45
|
+
for (size_t i = 0; i < names.size(rt); i++) {
|
|
46
|
+
auto name = names.getValueAtIndex(rt, i).asString(rt);
|
|
47
|
+
auto val = p.initialProps.getProperty(rt, name);
|
|
48
|
+
NSString *key = [NSString stringWithUTF8String:name.utf8(rt).c_str()];
|
|
49
|
+
if (val.isString()) {
|
|
50
|
+
dict[key] =
|
|
51
|
+
[NSString stringWithUTF8String:val.asString(rt).utf8(rt).c_str()];
|
|
52
|
+
} else if (val.isNumber()) {
|
|
53
|
+
dict[key] = @(val.asNumber());
|
|
54
|
+
} else if (val.isBool()) {
|
|
55
|
+
dict[key] = @(val.getBool());
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
initialProps = dict;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
NSNumber *x = toNSNumber(p.x);
|
|
63
|
+
NSNumber *y = toNSNumber(p.y);
|
|
64
|
+
NSNumber *width = toNSNumber(p.width);
|
|
65
|
+
NSNumber *height = toNSNumber(p.height);
|
|
66
|
+
NSNumber *minWidth = toNSNumber(p.minWidth);
|
|
67
|
+
NSNumber *minHeight = toNSNumber(p.minHeight);
|
|
68
|
+
NSNumber *maxWidth = toNSNumber(p.maxWidth);
|
|
69
|
+
NSNumber *maxHeight = toNSNumber(p.maxHeight);
|
|
70
|
+
BOOL center = p.center.value_or(false);
|
|
71
|
+
NSString *title = toNSString(p.title);
|
|
72
|
+
NSString *titleBarStyle = toNSString(p.titleBarStyle);
|
|
73
|
+
NSString *vibrancy = toNSString(p.vibrancy);
|
|
74
|
+
NSString *backgroundColor = toNSString(p.backgroundColor);
|
|
75
|
+
BOOL transparent = p.transparent.value_or(false);
|
|
76
|
+
BOOL hasShadow = p.hasShadow.value_or(true);
|
|
77
|
+
BOOL resizable = p.resizable.value_or(true);
|
|
78
|
+
BOOL movable = p.movable.value_or(true);
|
|
79
|
+
BOOL minimizable = p.minimizable.value_or(true);
|
|
80
|
+
BOOL closable = p.closable.value_or(true);
|
|
81
|
+
BOOL zoomable = p.zoomable.value_or(true);
|
|
82
|
+
BOOL alwaysOnTop = p.alwaysOnTop.value_or(false);
|
|
83
|
+
NSString *level = toNSString(p.level);
|
|
84
|
+
BOOL show = p.show.value_or(true);
|
|
85
|
+
BOOL focusOnCreate = p.focusOnCreate.value_or(true);
|
|
86
|
+
NSString *autoSaveFrame = toNSString(p.autoSaveFrame);
|
|
87
|
+
BOOL stopShouldClose = p.stopShouldClose.value_or(false);
|
|
88
|
+
|
|
89
|
+
return createPromiseAsJSIValue(
|
|
90
|
+
rt, [=, this](jsi::Runtime &, std::shared_ptr<Promise> promise) {
|
|
91
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
92
|
+
NSString *windowId = [[RNNSWindowHelper shared]
|
|
93
|
+
createWindowWithComponent:nsComponentName
|
|
94
|
+
windowName:nsWindowName
|
|
95
|
+
initialProps:initialProps
|
|
96
|
+
x:x
|
|
97
|
+
y:y
|
|
98
|
+
width:width
|
|
99
|
+
height:height
|
|
100
|
+
minWidth:minWidth
|
|
101
|
+
minHeight:minHeight
|
|
102
|
+
maxWidth:maxWidth
|
|
103
|
+
maxHeight:maxHeight
|
|
104
|
+
center:center
|
|
105
|
+
title:title
|
|
106
|
+
titleBarStyle:titleBarStyle
|
|
107
|
+
vibrancy:vibrancy
|
|
108
|
+
backgroundColor:backgroundColor
|
|
109
|
+
transparent:transparent
|
|
110
|
+
hasShadow:hasShadow
|
|
111
|
+
resizable:resizable
|
|
112
|
+
movable:movable
|
|
113
|
+
minimizable:minimizable
|
|
114
|
+
closable:closable
|
|
115
|
+
zoomable:zoomable
|
|
116
|
+
alwaysOnTop:alwaysOnTop
|
|
117
|
+
level:level
|
|
118
|
+
show:show
|
|
119
|
+
focusOnCreate:focusOnCreate
|
|
120
|
+
autoSaveFrame:autoSaveFrame];
|
|
121
|
+
|
|
122
|
+
if (stopShouldClose) {
|
|
123
|
+
[[RNNSWindowHelper shared] setStopShouldClose:YES
|
|
124
|
+
forWindowId:windowId];
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
std::string wid = [windowId UTF8String];
|
|
128
|
+
jsInvoker_->invokeAsync([promise, wid](jsi::Runtime &rt3) {
|
|
129
|
+
promise->resolve(jsi::String::createFromUtf8(rt3, wid));
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
jsi::Value RNNSWindow::closeWindow(jsi::Runtime &rt, jsi::String windowId) {
|
|
136
|
+
std::string wid = windowId.utf8(rt);
|
|
137
|
+
return createPromiseAsJSIValue(
|
|
138
|
+
rt, [=, this](jsi::Runtime &, std::shared_ptr<Promise> promise) {
|
|
139
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
140
|
+
NSString *nsWid = [NSString stringWithUTF8String:wid.c_str()];
|
|
141
|
+
NSWindow *window = [[RNNSWindowHelper shared] windowForId:nsWid];
|
|
142
|
+
[window close];
|
|
143
|
+
|
|
144
|
+
jsInvoker_->invokeAsync([promise](jsi::Runtime &) {
|
|
145
|
+
promise->resolve(jsi::Value::undefined());
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
jsi::Value RNNSWindow::modifyWindow(jsi::Runtime &rt, jsi::String windowId,
|
|
152
|
+
jsi::Object props) {
|
|
153
|
+
std::string wid = windowId.utf8(rt);
|
|
154
|
+
auto p = NativeNSWindowModifyableWindowPropsBridging<ModifyProps>::fromJs(
|
|
155
|
+
rt, props, jsInvoker_);
|
|
156
|
+
|
|
157
|
+
auto toNSString = [](const std::optional<std::string> &s) -> NSString * {
|
|
158
|
+
return s ? [NSString stringWithUTF8String:s->c_str()] : nil;
|
|
159
|
+
};
|
|
160
|
+
auto toNSNumber = [](const std::optional<double> &d) -> NSNumber * {
|
|
161
|
+
return d ? @(*d) : nil;
|
|
162
|
+
};
|
|
163
|
+
auto toNSBool = [](const std::optional<bool> &b) -> NSNumber * {
|
|
164
|
+
return b ? @(*b) : nil;
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
NSString *nsWid = [NSString stringWithUTF8String:wid.c_str()];
|
|
168
|
+
NSNumber *nx = toNSNumber(p.x);
|
|
169
|
+
NSNumber *ny = toNSNumber(p.y);
|
|
170
|
+
NSNumber *nWidth = toNSNumber(p.width);
|
|
171
|
+
NSNumber *nHeight = toNSNumber(p.height);
|
|
172
|
+
NSNumber *nMinWidth = toNSNumber(p.minWidth);
|
|
173
|
+
NSNumber *nMinHeight = toNSNumber(p.minHeight);
|
|
174
|
+
NSNumber *nMaxWidth = toNSNumber(p.maxWidth);
|
|
175
|
+
NSNumber *nMaxHeight = toNSNumber(p.maxHeight);
|
|
176
|
+
NSNumber *nCenter = toNSBool(p.center);
|
|
177
|
+
NSString *title = toNSString(p.title);
|
|
178
|
+
NSString *titleBarStyle = toNSString(p.titleBarStyle);
|
|
179
|
+
NSString *vibrancy = toNSString(p.vibrancy);
|
|
180
|
+
NSString *backgroundColor = toNSString(p.backgroundColor);
|
|
181
|
+
NSNumber *nTransparent = toNSBool(p.transparent);
|
|
182
|
+
NSNumber *nHasShadow = toNSBool(p.hasShadow);
|
|
183
|
+
NSNumber *nResizable = toNSBool(p.resizable);
|
|
184
|
+
NSNumber *nMovable = toNSBool(p.movable);
|
|
185
|
+
NSNumber *nMinimizable = toNSBool(p.minimizable);
|
|
186
|
+
NSNumber *nClosable = toNSBool(p.closable);
|
|
187
|
+
NSNumber *nZoomable = toNSBool(p.zoomable);
|
|
188
|
+
NSNumber *nAlwaysOnTop = toNSBool(p.alwaysOnTop);
|
|
189
|
+
NSString *level = toNSString(p.level);
|
|
190
|
+
NSNumber *nShow = toNSBool(p.show);
|
|
191
|
+
NSNumber *nFocusOnCreate = toNSBool(p.focusOnCreate);
|
|
192
|
+
NSString *autoSaveFrame = toNSString(p.autoSaveFrame);
|
|
193
|
+
NSNumber *nStopShouldClose = toNSBool(p.stopShouldClose);
|
|
194
|
+
|
|
195
|
+
return createPromiseAsJSIValue(
|
|
196
|
+
rt, [=, this](jsi::Runtime &, std::shared_ptr<Promise> promise) {
|
|
197
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
198
|
+
BOOL success =
|
|
199
|
+
[[RNNSWindowHelper shared] modifyWindow:nsWid
|
|
200
|
+
x:nx
|
|
201
|
+
y:ny
|
|
202
|
+
width:nWidth
|
|
203
|
+
height:nHeight
|
|
204
|
+
minWidth:nMinWidth
|
|
205
|
+
minHeight:nMinHeight
|
|
206
|
+
maxWidth:nMaxWidth
|
|
207
|
+
maxHeight:nMaxHeight
|
|
208
|
+
center:nCenter
|
|
209
|
+
title:title
|
|
210
|
+
titleBarStyle:titleBarStyle
|
|
211
|
+
vibrancy:vibrancy
|
|
212
|
+
backgroundColor:backgroundColor
|
|
213
|
+
transparent:nTransparent
|
|
214
|
+
hasShadow:nHasShadow
|
|
215
|
+
resizable:nResizable
|
|
216
|
+
movable:nMovable
|
|
217
|
+
minimizable:nMinimizable
|
|
218
|
+
closable:nClosable
|
|
219
|
+
zoomable:nZoomable
|
|
220
|
+
alwaysOnTop:nAlwaysOnTop
|
|
221
|
+
level:level
|
|
222
|
+
show:nShow
|
|
223
|
+
focusOnCreate:nFocusOnCreate
|
|
224
|
+
autoSaveFrame:autoSaveFrame
|
|
225
|
+
stopShouldClose:nStopShouldClose];
|
|
226
|
+
|
|
227
|
+
if (!success) {
|
|
228
|
+
jsInvoker_->invokeAsync([promise, wid](jsi::Runtime &) {
|
|
229
|
+
promise->reject("Window not found: " + wid);
|
|
230
|
+
});
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
jsInvoker_->invokeAsync([promise](jsi::Runtime &) {
|
|
235
|
+
promise->resolve(jsi::Value::undefined());
|
|
236
|
+
});
|
|
237
|
+
});
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
jsi::Value RNNSWindow::listWindows(jsi::Runtime &rt) {
|
|
242
|
+
return createPromiseAsJSIValue(rt, [this](jsi::Runtime &,
|
|
243
|
+
std::shared_ptr<Promise> promise) {
|
|
244
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
245
|
+
NSArray<NSString *> *ids = [[RNNSWindowHelper shared] allWindowIds];
|
|
246
|
+
std::vector<std::string> vec;
|
|
247
|
+
for (NSString *wid in ids) {
|
|
248
|
+
vec.push_back([wid UTF8String]);
|
|
249
|
+
}
|
|
250
|
+
jsInvoker_->invokeAsync([promise,
|
|
251
|
+
vec = std::move(vec)](jsi::Runtime &rt2) {
|
|
252
|
+
auto arr = jsi::Array(rt2, vec.size());
|
|
253
|
+
for (size_t i = 0; i < vec.size(); i++) {
|
|
254
|
+
arr.setValueAtIndex(rt2, i, jsi::String::createFromUtf8(rt2, vec[i]));
|
|
255
|
+
}
|
|
256
|
+
promise->resolve(std::move(arr));
|
|
257
|
+
});
|
|
258
|
+
});
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
jsi::Value RNNSWindow::getWindowState(jsi::Runtime &rt, jsi::String windowId) {
|
|
263
|
+
std::string wid = windowId.utf8(rt);
|
|
264
|
+
return createPromiseAsJSIValue(rt, [=,
|
|
265
|
+
this](jsi::Runtime &,
|
|
266
|
+
std::shared_ptr<Promise> promise) {
|
|
267
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
268
|
+
NSString *nsWid = [NSString stringWithUTF8String:wid.c_str()];
|
|
269
|
+
NSWindow *window = [[RNNSWindowHelper shared] windowForId:nsWid];
|
|
270
|
+
NSString *name = [[RNNSWindowHelper shared] windowNameForId:nsWid] ?: @"";
|
|
271
|
+
|
|
272
|
+
if (!window) {
|
|
273
|
+
jsInvoker_->invokeAsync([promise, wid](jsi::Runtime &) {
|
|
274
|
+
promise->reject("Window not found: " + wid);
|
|
275
|
+
});
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
NSRect frame = window.frame;
|
|
280
|
+
bool isKey = [window isKeyWindow];
|
|
281
|
+
bool isMini = [window isMiniaturized];
|
|
282
|
+
bool isFS = (window.styleMask & NSWindowStyleMaskFullScreen) != 0;
|
|
283
|
+
bool isVis = [window isVisible];
|
|
284
|
+
bool isOccluded =
|
|
285
|
+
(window.occlusionState & NSWindowOcclusionStateVisible) == 0;
|
|
286
|
+
double scaleFactor = [window backingScaleFactor];
|
|
287
|
+
std::string nameStr = [name UTF8String];
|
|
288
|
+
double x = frame.origin.x;
|
|
289
|
+
double y = frame.origin.y;
|
|
290
|
+
double w = frame.size.width;
|
|
291
|
+
double h = frame.size.height;
|
|
292
|
+
|
|
293
|
+
// Screen frame (nullable)
|
|
294
|
+
bool hasScreen = (window.screen != nil);
|
|
295
|
+
double sx = 0, sy = 0, sw = 0, sh = 0;
|
|
296
|
+
if (hasScreen) {
|
|
297
|
+
NSRect sf = window.screen.frame;
|
|
298
|
+
sx = sf.origin.x;
|
|
299
|
+
sy = sf.origin.y;
|
|
300
|
+
sw = sf.size.width;
|
|
301
|
+
sh = sf.size.height;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
jsInvoker_->invokeAsync([promise, wid, nameStr, x, y, w, h, isKey, isMini,
|
|
305
|
+
isFS, isVis, isOccluded, scaleFactor, hasScreen,
|
|
306
|
+
sx, sy, sw, sh](jsi::Runtime &rt2) {
|
|
307
|
+
auto obj = jsi::Object(rt2);
|
|
308
|
+
obj.setProperty(rt2, "windowId", jsi::String::createFromUtf8(rt2, wid));
|
|
309
|
+
obj.setProperty(rt2, "windowName",
|
|
310
|
+
jsi::String::createFromUtf8(rt2, nameStr));
|
|
311
|
+
obj.setProperty(rt2, "x", x);
|
|
312
|
+
obj.setProperty(rt2, "y", y);
|
|
313
|
+
obj.setProperty(rt2, "width", w);
|
|
314
|
+
obj.setProperty(rt2, "height", h);
|
|
315
|
+
obj.setProperty(rt2, "isKeyWindow", isKey);
|
|
316
|
+
obj.setProperty(rt2, "isMinimized", isMini);
|
|
317
|
+
obj.setProperty(rt2, "isFullScreen", isFS);
|
|
318
|
+
obj.setProperty(rt2, "isVisible", isVis);
|
|
319
|
+
obj.setProperty(rt2, "isOccluded", isOccluded);
|
|
320
|
+
obj.setProperty(rt2, "backingScaleFactor", scaleFactor);
|
|
321
|
+
if (hasScreen) {
|
|
322
|
+
auto screen = jsi::Object(rt2);
|
|
323
|
+
screen.setProperty(rt2, "x", sx);
|
|
324
|
+
screen.setProperty(rt2, "y", sy);
|
|
325
|
+
screen.setProperty(rt2, "width", sw);
|
|
326
|
+
screen.setProperty(rt2, "height", sh);
|
|
327
|
+
obj.setProperty(rt2, "screen", std::move(screen));
|
|
328
|
+
} else {
|
|
329
|
+
obj.setProperty(rt2, "screen", jsi::Value::null());
|
|
330
|
+
}
|
|
331
|
+
promise->resolve(std::move(obj));
|
|
332
|
+
});
|
|
333
|
+
});
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
jsi::Value RNNSWindow::focusWindow(jsi::Runtime &rt, jsi::String windowId) {
|
|
338
|
+
std::string wid = windowId.utf8(rt);
|
|
339
|
+
return createPromiseAsJSIValue(
|
|
340
|
+
rt, [=, this](jsi::Runtime &, std::shared_ptr<Promise> promise) {
|
|
341
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
342
|
+
NSString *nsWid = [NSString stringWithUTF8String:wid.c_str()];
|
|
343
|
+
NSWindow *window = [[RNNSWindowHelper shared] windowForId:nsWid];
|
|
344
|
+
[window makeKeyAndOrderFront:nil];
|
|
345
|
+
|
|
346
|
+
jsInvoker_->invokeAsync([promise](jsi::Runtime &) {
|
|
347
|
+
promise->resolve(jsi::Value::undefined());
|
|
348
|
+
});
|
|
349
|
+
});
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
jsi::Value RNNSWindow::hideWindow(jsi::Runtime &rt, jsi::String windowId) {
|
|
354
|
+
std::string wid = windowId.utf8(rt);
|
|
355
|
+
return createPromiseAsJSIValue(
|
|
356
|
+
rt, [=, this](jsi::Runtime &, std::shared_ptr<Promise> promise) {
|
|
357
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
358
|
+
NSString *nsWid = [NSString stringWithUTF8String:wid.c_str()];
|
|
359
|
+
NSWindow *window = [[RNNSWindowHelper shared] windowForId:nsWid];
|
|
360
|
+
[window orderOut:nil];
|
|
361
|
+
|
|
362
|
+
jsInvoker_->invokeAsync([promise](jsi::Runtime &) {
|
|
363
|
+
promise->resolve(jsi::Value::undefined());
|
|
364
|
+
});
|
|
365
|
+
});
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
jsi::Value RNNSWindow::showWindow(jsi::Runtime &rt, jsi::String windowId) {
|
|
370
|
+
std::string wid = windowId.utf8(rt);
|
|
371
|
+
return createPromiseAsJSIValue(
|
|
372
|
+
rt, [=, this](jsi::Runtime &, std::shared_ptr<Promise> promise) {
|
|
373
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
374
|
+
NSString *nsWid = [NSString stringWithUTF8String:wid.c_str()];
|
|
375
|
+
NSWindow *window = [[RNNSWindowHelper shared] windowForId:nsWid];
|
|
376
|
+
[window orderFront:nil];
|
|
377
|
+
|
|
378
|
+
jsInvoker_->invokeAsync([promise](jsi::Runtime &) {
|
|
379
|
+
promise->resolve(jsi::Value::undefined());
|
|
380
|
+
});
|
|
381
|
+
});
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
jsi::Value RNNSWindow::minimizeWindow(jsi::Runtime &rt, jsi::String windowId) {
|
|
386
|
+
std::string wid = windowId.utf8(rt);
|
|
387
|
+
return createPromiseAsJSIValue(
|
|
388
|
+
rt, [=, this](jsi::Runtime &, std::shared_ptr<Promise> promise) {
|
|
389
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
390
|
+
NSString *nsWid = [NSString stringWithUTF8String:wid.c_str()];
|
|
391
|
+
NSWindow *window = [[RNNSWindowHelper shared] windowForId:nsWid];
|
|
392
|
+
[window miniaturize:nil];
|
|
393
|
+
|
|
394
|
+
jsInvoker_->invokeAsync([promise](jsi::Runtime &) {
|
|
395
|
+
promise->resolve(jsi::Value::undefined());
|
|
396
|
+
});
|
|
397
|
+
});
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
jsi::Value RNNSWindow::deminimizeWindow(jsi::Runtime &rt,
|
|
402
|
+
jsi::String windowId) {
|
|
403
|
+
std::string wid = windowId.utf8(rt);
|
|
404
|
+
return createPromiseAsJSIValue(
|
|
405
|
+
rt, [=, this](jsi::Runtime &, std::shared_ptr<Promise> promise) {
|
|
406
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
407
|
+
NSString *nsWid = [NSString stringWithUTF8String:wid.c_str()];
|
|
408
|
+
NSWindow *window = [[RNNSWindowHelper shared] windowForId:nsWid];
|
|
409
|
+
[window deminiaturize:nil];
|
|
410
|
+
|
|
411
|
+
jsInvoker_->invokeAsync([promise](jsi::Runtime &) {
|
|
412
|
+
promise->resolve(jsi::Value::undefined());
|
|
413
|
+
});
|
|
414
|
+
});
|
|
415
|
+
});
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
jsi::Value RNNSWindow::setFullScreen(jsi::Runtime &rt, jsi::String windowId,
|
|
419
|
+
bool fullscreen) {
|
|
420
|
+
std::string wid = windowId.utf8(rt);
|
|
421
|
+
return createPromiseAsJSIValue(
|
|
422
|
+
rt, [=, this](jsi::Runtime &, std::shared_ptr<Promise> promise) {
|
|
423
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
424
|
+
NSString *nsWid = [NSString stringWithUTF8String:wid.c_str()];
|
|
425
|
+
NSWindow *window = [[RNNSWindowHelper shared] windowForId:nsWid];
|
|
426
|
+
if (window) {
|
|
427
|
+
BOOL isFS = (window.styleMask & NSWindowStyleMaskFullScreen) != 0;
|
|
428
|
+
if (fullscreen != isFS) {
|
|
429
|
+
[window toggleFullScreen:nil];
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
jsInvoker_->invokeAsync([promise](jsi::Runtime &) {
|
|
433
|
+
promise->resolve(jsi::Value::undefined());
|
|
434
|
+
});
|
|
435
|
+
});
|
|
436
|
+
});
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
jsi::Value RNNSWindow::bringToFront(jsi::Runtime &rt, jsi::String windowId) {
|
|
440
|
+
std::string wid = windowId.utf8(rt);
|
|
441
|
+
return createPromiseAsJSIValue(
|
|
442
|
+
rt, [=, this](jsi::Runtime &, std::shared_ptr<Promise> promise) {
|
|
443
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
444
|
+
NSString *nsWid = [NSString stringWithUTF8String:wid.c_str()];
|
|
445
|
+
NSWindow *window = [[RNNSWindowHelper shared] windowForId:nsWid];
|
|
446
|
+
[window orderFront:nil];
|
|
447
|
+
|
|
448
|
+
jsInvoker_->invokeAsync([promise](jsi::Runtime &) {
|
|
449
|
+
promise->resolve(jsi::Value::undefined());
|
|
450
|
+
});
|
|
451
|
+
});
|
|
452
|
+
});
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
jsi::Value RNNSWindow::sendToBack(jsi::Runtime &rt, jsi::String windowId) {
|
|
456
|
+
std::string wid = windowId.utf8(rt);
|
|
457
|
+
return createPromiseAsJSIValue(
|
|
458
|
+
rt, [=, this](jsi::Runtime &, std::shared_ptr<Promise> promise) {
|
|
459
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
460
|
+
NSString *nsWid = [NSString stringWithUTF8String:wid.c_str()];
|
|
461
|
+
NSWindow *window = [[RNNSWindowHelper shared] windowForId:nsWid];
|
|
462
|
+
[window orderBack:nil];
|
|
463
|
+
|
|
464
|
+
jsInvoker_->invokeAsync([promise](jsi::Runtime &) {
|
|
465
|
+
promise->resolve(jsi::Value::undefined());
|
|
466
|
+
});
|
|
467
|
+
});
|
|
468
|
+
});
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
jsi::Value RNNSWindow::getScreenInfo(jsi::Runtime &rt) {
|
|
472
|
+
return createPromiseAsJSIValue(
|
|
473
|
+
rt, [this](jsi::Runtime &, std::shared_ptr<Promise> promise) {
|
|
474
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
475
|
+
NSArray<NSScreen *> *screens = [NSScreen screens];
|
|
476
|
+
|
|
477
|
+
// Compute total bounding rect across all screens
|
|
478
|
+
double minX = CGFLOAT_MAX, minY = CGFLOAT_MAX;
|
|
479
|
+
double maxX = -CGFLOAT_MAX, maxY = -CGFLOAT_MAX;
|
|
480
|
+
double minVX = CGFLOAT_MAX, minVY = CGFLOAT_MAX;
|
|
481
|
+
double maxVX = -CGFLOAT_MAX, maxVY = -CGFLOAT_MAX;
|
|
482
|
+
|
|
483
|
+
struct ScreenData {
|
|
484
|
+
double fx, fy, fw, fh;
|
|
485
|
+
double vx, vy, vw, vh;
|
|
486
|
+
};
|
|
487
|
+
std::vector<ScreenData> screenData;
|
|
488
|
+
|
|
489
|
+
for (NSScreen *s in screens) {
|
|
490
|
+
NSRect f = s.frame;
|
|
491
|
+
NSRect v = s.visibleFrame;
|
|
492
|
+
screenData.push_back({f.origin.x, f.origin.y, f.size.width,
|
|
493
|
+
f.size.height, v.origin.x, v.origin.y,
|
|
494
|
+
v.size.width, v.size.height});
|
|
495
|
+
minX = std::min(minX, f.origin.x);
|
|
496
|
+
minY = std::min(minY, f.origin.y);
|
|
497
|
+
maxX = std::max(maxX, f.origin.x + f.size.width);
|
|
498
|
+
maxY = std::max(maxY, f.origin.y + f.size.height);
|
|
499
|
+
minVX = std::min(minVX, v.origin.x);
|
|
500
|
+
minVY = std::min(minVY, v.origin.y);
|
|
501
|
+
maxVX = std::max(maxVX, v.origin.x + v.size.width);
|
|
502
|
+
maxVY = std::max(maxVY, v.origin.y + v.size.height);
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
double totalX = minX, totalY = minY;
|
|
506
|
+
double totalW = maxX - minX, totalH = maxY - minY;
|
|
507
|
+
double totalVX = minVX, totalVY = minVY;
|
|
508
|
+
double totalVW = maxVX - minVX, totalVH = maxVY - minVY;
|
|
509
|
+
|
|
510
|
+
// Main screen frame
|
|
511
|
+
NSRect mainFrame = NSScreen.mainScreen.frame;
|
|
512
|
+
double mx = mainFrame.origin.x, my = mainFrame.origin.y;
|
|
513
|
+
double mw = mainFrame.size.width, mh = mainFrame.size.height;
|
|
514
|
+
|
|
515
|
+
jsInvoker_->invokeAsync([promise, screenData, totalX, totalY, totalW,
|
|
516
|
+
totalH, totalVX, totalVY, totalVW, totalVH,
|
|
517
|
+
mx, my, mw, mh](jsi::Runtime &rt2) {
|
|
518
|
+
auto obj = jsi::Object(rt2);
|
|
519
|
+
|
|
520
|
+
auto total = jsi::Object(rt2);
|
|
521
|
+
total.setProperty(rt2, "x", totalX);
|
|
522
|
+
total.setProperty(rt2, "y", totalY);
|
|
523
|
+
total.setProperty(rt2, "width", totalW);
|
|
524
|
+
total.setProperty(rt2, "height", totalH);
|
|
525
|
+
obj.setProperty(rt2, "total", std::move(total));
|
|
526
|
+
|
|
527
|
+
auto totalVis = jsi::Object(rt2);
|
|
528
|
+
totalVis.setProperty(rt2, "x", totalVX);
|
|
529
|
+
totalVis.setProperty(rt2, "y", totalVY);
|
|
530
|
+
totalVis.setProperty(rt2, "width", totalVW);
|
|
531
|
+
totalVis.setProperty(rt2, "height", totalVH);
|
|
532
|
+
obj.setProperty(rt2, "totalVisibleFrame", std::move(totalVis));
|
|
533
|
+
|
|
534
|
+
auto screensArr = jsi::Array(rt2, screenData.size());
|
|
535
|
+
for (size_t i = 0; i < screenData.size(); i++) {
|
|
536
|
+
auto &sd = screenData[i];
|
|
537
|
+
auto sObj = jsi::Object(rt2);
|
|
538
|
+
|
|
539
|
+
auto frame = jsi::Object(rt2);
|
|
540
|
+
frame.setProperty(rt2, "x", sd.fx);
|
|
541
|
+
frame.setProperty(rt2, "y", sd.fy);
|
|
542
|
+
frame.setProperty(rt2, "width", sd.fw);
|
|
543
|
+
frame.setProperty(rt2, "height", sd.fh);
|
|
544
|
+
sObj.setProperty(rt2, "frame", std::move(frame));
|
|
545
|
+
|
|
546
|
+
auto vis = jsi::Object(rt2);
|
|
547
|
+
vis.setProperty(rt2, "x", sd.vx);
|
|
548
|
+
vis.setProperty(rt2, "y", sd.vy);
|
|
549
|
+
vis.setProperty(rt2, "width", sd.vw);
|
|
550
|
+
vis.setProperty(rt2, "height", sd.vh);
|
|
551
|
+
sObj.setProperty(rt2, "visibleFrame", std::move(vis));
|
|
552
|
+
|
|
553
|
+
screensArr.setValueAtIndex(rt2, i, std::move(sObj));
|
|
554
|
+
}
|
|
555
|
+
obj.setProperty(rt2, "screens", std::move(screensArr));
|
|
556
|
+
|
|
557
|
+
auto main = jsi::Object(rt2);
|
|
558
|
+
main.setProperty(rt2, "x", mx);
|
|
559
|
+
main.setProperty(rt2, "y", my);
|
|
560
|
+
main.setProperty(rt2, "width", mw);
|
|
561
|
+
main.setProperty(rt2, "height", mh);
|
|
562
|
+
obj.setProperty(rt2, "main", std::move(main));
|
|
563
|
+
|
|
564
|
+
promise->resolve(std::move(obj));
|
|
565
|
+
});
|
|
566
|
+
});
|
|
567
|
+
});
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
} // namespace facebook::react
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#import <AppKit/AppKit.h>
|
|
4
|
+
#import <Foundation/Foundation.h>
|
|
5
|
+
|
|
6
|
+
namespace facebook::react {
|
|
7
|
+
class RNNSWindow;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
@interface RNNSWindowHelper : NSObject <NSWindowDelegate>
|
|
11
|
+
|
|
12
|
+
@property(nonatomic, assign) facebook::react::RNNSWindow *module;
|
|
13
|
+
|
|
14
|
+
+ (instancetype)shared;
|
|
15
|
+
|
|
16
|
+
- (NSString *)createWindowWithComponent:(NSString *)componentName
|
|
17
|
+
windowName:(NSString *)windowName
|
|
18
|
+
initialProps:(NSDictionary *_Nullable)initialProps
|
|
19
|
+
x:(NSNumber *_Nullable)x
|
|
20
|
+
y:(NSNumber *_Nullable)y
|
|
21
|
+
width:(NSNumber *_Nullable)width
|
|
22
|
+
height:(NSNumber *_Nullable)height
|
|
23
|
+
minWidth:(NSNumber *_Nullable)minWidth
|
|
24
|
+
minHeight:(NSNumber *_Nullable)minHeight
|
|
25
|
+
maxWidth:(NSNumber *_Nullable)maxWidth
|
|
26
|
+
maxHeight:(NSNumber *_Nullable)maxHeight
|
|
27
|
+
center:(BOOL)center
|
|
28
|
+
title:(NSString *_Nullable)title
|
|
29
|
+
titleBarStyle:(NSString *_Nullable)titleBarStyle
|
|
30
|
+
vibrancy:(NSString *_Nullable)vibrancy
|
|
31
|
+
backgroundColor:(NSString *_Nullable)backgroundColor
|
|
32
|
+
transparent:(BOOL)transparent
|
|
33
|
+
hasShadow:(BOOL)hasShadow
|
|
34
|
+
resizable:(BOOL)resizable
|
|
35
|
+
movable:(BOOL)movable
|
|
36
|
+
minimizable:(BOOL)minimizable
|
|
37
|
+
closable:(BOOL)closable
|
|
38
|
+
zoomable:(BOOL)zoomable
|
|
39
|
+
alwaysOnTop:(BOOL)alwaysOnTop
|
|
40
|
+
level:(NSString *_Nullable)level
|
|
41
|
+
show:(BOOL)show
|
|
42
|
+
focusOnCreate:(BOOL)focusOnCreate
|
|
43
|
+
autoSaveFrame:(NSString *_Nullable)autoSaveFrame;
|
|
44
|
+
|
|
45
|
+
- (BOOL)modifyWindow:(NSString *)windowId
|
|
46
|
+
x:(NSNumber *_Nullable)x
|
|
47
|
+
y:(NSNumber *_Nullable)y
|
|
48
|
+
width:(NSNumber *_Nullable)width
|
|
49
|
+
height:(NSNumber *_Nullable)height
|
|
50
|
+
minWidth:(NSNumber *_Nullable)minWidth
|
|
51
|
+
minHeight:(NSNumber *_Nullable)minHeight
|
|
52
|
+
maxWidth:(NSNumber *_Nullable)maxWidth
|
|
53
|
+
maxHeight:(NSNumber *_Nullable)maxHeight
|
|
54
|
+
center:(NSNumber *_Nullable)center
|
|
55
|
+
title:(NSString *_Nullable)title
|
|
56
|
+
titleBarStyle:(NSString *_Nullable)titleBarStyle
|
|
57
|
+
vibrancy:(NSString *_Nullable)vibrancy
|
|
58
|
+
backgroundColor:(NSString *_Nullable)backgroundColor
|
|
59
|
+
transparent:(NSNumber *_Nullable)transparent
|
|
60
|
+
hasShadow:(NSNumber *_Nullable)hasShadow
|
|
61
|
+
resizable:(NSNumber *_Nullable)resizable
|
|
62
|
+
movable:(NSNumber *_Nullable)movable
|
|
63
|
+
minimizable:(NSNumber *_Nullable)minimizable
|
|
64
|
+
closable:(NSNumber *_Nullable)closable
|
|
65
|
+
zoomable:(NSNumber *_Nullable)zoomable
|
|
66
|
+
alwaysOnTop:(NSNumber *_Nullable)alwaysOnTop
|
|
67
|
+
level:(NSString *_Nullable)level
|
|
68
|
+
show:(NSNumber *_Nullable)show
|
|
69
|
+
focusOnCreate:(NSNumber *_Nullable)focusOnCreate
|
|
70
|
+
autoSaveFrame:(NSString *_Nullable)autoSaveFrame
|
|
71
|
+
stopShouldClose:(NSNumber *_Nullable)stopShouldClose;
|
|
72
|
+
|
|
73
|
+
- (NSWindow *_Nullable)windowForId:(NSString *)windowId;
|
|
74
|
+
- (NSArray<NSString *> *)allWindowIds;
|
|
75
|
+
- (NSString *_Nullable)windowNameForId:(NSString *)windowId;
|
|
76
|
+
- (void)removeWindowForId:(NSString *)windowId;
|
|
77
|
+
- (void)setStopShouldClose:(BOOL)stop forWindowId:(NSString *)windowId;
|
|
78
|
+
- (NSVisualEffectMaterial)materialForVibrancy:(NSString *)vibrancy;
|
|
79
|
+
|
|
80
|
+
@end
|