Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.desktop/macosx/native/libosxapp/NSApplicationAWT.m
41149 views
1
/*
2
* Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
#import "NSApplicationAWT.h"
27
28
#import <objc/runtime.h>
29
#import <JavaRuntimeSupport/JavaRuntimeSupport.h>
30
31
#import "PropertiesUtilities.h"
32
#import "ThreadUtilities.h"
33
#import "QueuingApplicationDelegate.h"
34
#import "AWTIconData.h"
35
36
/*
37
* Declare library specific JNI_Onload entry if static build
38
*/
39
DEF_STATIC_JNI_OnLoad
40
41
static BOOL sUsingDefaultNIB = YES;
42
static NSString *SHARED_FRAMEWORK_BUNDLE = @"/System/Library/Frameworks/JavaVM.framework";
43
static id <NSApplicationDelegate> applicationDelegate = nil;
44
static QueuingApplicationDelegate * qad = nil;
45
46
// Flag used to indicate to the Plugin2 event synthesis code to do a postEvent instead of sendEvent
47
BOOL postEventDuringEventSynthesis = NO;
48
49
/**
50
* Subtypes of NSApplicationDefined, which are used for custom events.
51
*/
52
enum {
53
ExecuteBlockEvent = 777, NativeSyncQueueEvent
54
};
55
56
@implementation NSApplicationAWT
57
58
- (id) init
59
{
60
// Headless: NO
61
// Embedded: NO
62
// Multiple Calls: NO
63
// Caller: +[NSApplication sharedApplication]
64
65
AWT_ASSERT_APPKIT_THREAD;
66
fApplicationName = nil;
67
dummyEventTimestamp = 0.0;
68
seenDummyEventLock = nil;
69
70
71
// NSApplication will call _RegisterApplication with the application's bundle, but there may not be one.
72
// So, we need to call it ourselves to ensure the app is set up properly.
73
[self registerWithProcessManager];
74
75
return [super init];
76
}
77
78
- (void)dealloc
79
{
80
[fApplicationName release];
81
fApplicationName = nil;
82
83
[super dealloc];
84
}
85
86
- (void)finishLaunching
87
{
88
AWT_ASSERT_APPKIT_THREAD;
89
90
JNIEnv *env = [ThreadUtilities getJNIEnv];
91
92
SEL appearanceSel = @selector(setAppearance:); // macOS 10.14+
93
if ([self respondsToSelector:appearanceSel]) {
94
NSString *appearanceProp = [PropertiesUtilities
95
javaSystemPropertyForKey:@"apple.awt.application.appearance"
96
withEnv:env];
97
if (![@"system" isEqual:appearanceProp]) {
98
// by default use light mode, because dark mode is not supported yet
99
NSAppearance *appearance = [NSAppearance appearanceNamed:NSAppearanceNameAqua];
100
if (appearanceProp != nil) {
101
NSAppearance *requested = [NSAppearance appearanceNamed:appearanceProp];
102
if (requested != nil) {
103
appearance = requested;
104
}
105
}
106
// [self setAppearance:appearance];
107
[self performSelector:appearanceSel withObject:appearance];
108
}
109
}
110
111
// Get default nib file location
112
// NOTE: This should learn about the current java.version. Probably best thru
113
// the Makefile system's -DFRAMEWORK_VERSION define. Need to be able to pass this
114
// thru to PB from the Makefile system and for local builds.
115
NSString *defaultNibFile = [PropertiesUtilities javaSystemPropertyForKey:@"apple.awt.application.nib" withEnv:env];
116
if (!defaultNibFile) {
117
NSBundle *javaBundle = [NSBundle bundleWithPath:SHARED_FRAMEWORK_BUNDLE];
118
defaultNibFile = [javaBundle pathForResource:@"DefaultApp" ofType:@"nib"];
119
} else {
120
sUsingDefaultNIB = NO;
121
}
122
123
[NSBundle loadNibFile:defaultNibFile externalNameTable: [NSDictionary dictionaryWithObject:self forKey:@"NSOwner"] withZone:nil];
124
125
// Set user defaults to not try to parse application arguments.
126
NSUserDefaults * defs = [NSUserDefaults standardUserDefaults];
127
NSDictionary * noOpenDict = [NSDictionary dictionaryWithObject:@"NO" forKey:@"NSTreatUnknownArgumentsAsOpen"];
128
[defs registerDefaults:noOpenDict];
129
130
// Fix up the dock icon now that we are registered with CAS and the Dock.
131
[self setDockIconWithEnv:env];
132
133
// If we are using our nib (the default application NIB) we need to put the app name into
134
// the application menu, which has placeholders for the name.
135
if (sUsingDefaultNIB) {
136
NSUInteger i, itemCount;
137
NSMenu *theMainMenu = [NSApp mainMenu];
138
139
// First submenu off the main menu is the application menu.
140
NSMenuItem *appMenuItem = [theMainMenu itemAtIndex:0];
141
NSMenu *appMenu = [appMenuItem submenu];
142
itemCount = [appMenu numberOfItems];
143
144
for (i = 0; i < itemCount; i++) {
145
NSMenuItem *anItem = [appMenu itemAtIndex:i];
146
NSString *oldTitle = [anItem title];
147
[anItem setTitle:[NSString stringWithFormat:oldTitle, fApplicationName]];
148
}
149
}
150
151
if (applicationDelegate) {
152
[self setDelegate:applicationDelegate];
153
} else {
154
qad = [QueuingApplicationDelegate sharedDelegate];
155
[self setDelegate:qad];
156
}
157
158
[super finishLaunching];
159
}
160
161
162
- (void) registerWithProcessManager
163
{
164
// Headless: NO
165
// Embedded: NO
166
// Multiple Calls: NO
167
// Caller: -[NSApplicationAWT init]
168
169
AWT_ASSERT_APPKIT_THREAD;
170
JNIEnv *env = [ThreadUtilities getJNIEnv];
171
172
char envVar[80];
173
174
// The following environment variable is set from the -Xdock:name param. It should be UTF8.
175
snprintf(envVar, sizeof(envVar), "APP_NAME_%d", getpid());
176
char *appName = getenv(envVar);
177
if (appName != NULL) {
178
fApplicationName = [NSString stringWithUTF8String:appName];
179
unsetenv(envVar);
180
}
181
182
// If it wasn't specified as an argument, see if it was specified as a system property.
183
if (fApplicationName == nil) {
184
fApplicationName = [PropertiesUtilities javaSystemPropertyForKey:@"apple.awt.application.name" withEnv:env];
185
}
186
187
// If we STILL don't have it, the app name is retrieved from an environment variable (set in java.c) It should be UTF8.
188
if (fApplicationName == nil) {
189
char mainClassEnvVar[80];
190
snprintf(mainClassEnvVar, sizeof(mainClassEnvVar), "JAVA_MAIN_CLASS_%d", getpid());
191
char *mainClass = getenv(mainClassEnvVar);
192
if (mainClass != NULL) {
193
fApplicationName = [NSString stringWithUTF8String:mainClass];
194
unsetenv(mainClassEnvVar);
195
196
NSRange lastPeriod = [fApplicationName rangeOfString:@"." options:NSBackwardsSearch];
197
if (lastPeriod.location != NSNotFound) {
198
fApplicationName = [fApplicationName substringFromIndex:lastPeriod.location + 1];
199
}
200
}
201
}
202
203
// The dock name is nil for double-clickable Java apps (bundled and Web Start apps)
204
// When that happens get the display name, and if that's not available fall back to
205
// CFBundleName.
206
NSBundle *mainBundle = [NSBundle mainBundle];
207
if (fApplicationName == nil) {
208
fApplicationName = (NSString *)[mainBundle objectForInfoDictionaryKey:@"CFBundleDisplayName"];
209
210
if (fApplicationName == nil) {
211
fApplicationName = (NSString *)[mainBundle objectForInfoDictionaryKey:(NSString *)kCFBundleNameKey];
212
213
if (fApplicationName == nil) {
214
fApplicationName = (NSString *)[mainBundle objectForInfoDictionaryKey: (NSString *)kCFBundleExecutableKey];
215
216
if (fApplicationName == nil) {
217
// Name of last resort is the last part of the applicatoin name without the .app (consistent with CopyProcessName)
218
fApplicationName = [[mainBundle bundlePath] lastPathComponent];
219
220
if ([fApplicationName hasSuffix:@".app"]) {
221
fApplicationName = [fApplicationName stringByDeletingPathExtension];
222
}
223
}
224
}
225
}
226
}
227
228
// We're all done trying to determine the app name. Hold on to it.
229
[fApplicationName retain];
230
231
NSDictionary *registrationOptions = [NSMutableDictionary dictionaryWithObject:fApplicationName forKey:@"JRSAppNameKey"];
232
233
NSString *launcherType = [PropertiesUtilities javaSystemPropertyForKey:@"sun.java.launcher" withEnv:env];
234
if ([@"SUN_STANDARD" isEqualToString:launcherType]) {
235
[registrationOptions setValue:[NSNumber numberWithBool:YES] forKey:@"JRSAppIsCommandLineKey"];
236
}
237
238
NSString *uiElementProp = [PropertiesUtilities javaSystemPropertyForKey:@"apple.awt.UIElement" withEnv:env];
239
if ([@"true" isCaseInsensitiveLike:uiElementProp]) {
240
[registrationOptions setValue:[NSNumber numberWithBool:YES] forKey:@"JRSAppIsUIElementKey"];
241
}
242
243
NSString *backgroundOnlyProp = [PropertiesUtilities javaSystemPropertyForKey:@"apple.awt.BackgroundOnly" withEnv:env];
244
if ([@"true" isCaseInsensitiveLike:backgroundOnlyProp]) {
245
[registrationOptions setValue:[NSNumber numberWithBool:YES] forKey:@"JRSAppIsBackgroundOnlyKey"];
246
}
247
248
// TODO replace with direct call
249
// [JRSAppKitAWT registerAWTAppWithOptions:registrationOptions];
250
// and remove below transform/activate/run hack
251
252
id jrsAppKitAWTClass = objc_getClass("JRSAppKitAWT");
253
SEL registerSel = @selector(registerAWTAppWithOptions:);
254
if ([jrsAppKitAWTClass respondsToSelector:registerSel]) {
255
[jrsAppKitAWTClass performSelector:registerSel withObject:registrationOptions];
256
return;
257
}
258
259
// HACK BEGIN
260
// The following is necessary to make the java process behave like a
261
// proper foreground application...
262
[ThreadUtilities performOnMainThreadWaiting:NO block:^(){
263
ProcessSerialNumber psn;
264
GetCurrentProcess(&psn);
265
TransformProcessType(&psn, kProcessTransformToForegroundApplication);
266
267
[NSApp activateIgnoringOtherApps:YES];
268
[NSApp run];
269
}];
270
// HACK END
271
}
272
273
- (void) setDockIconWithEnv:(JNIEnv *)env {
274
NSString *theIconPath = nil;
275
276
// The following environment variable is set in java.c. It is probably UTF8.
277
char envVar[80];
278
snprintf(envVar, sizeof(envVar), "APP_ICON_%d", getpid());
279
char *appIcon = getenv(envVar);
280
if (appIcon != NULL) {
281
theIconPath = [NSString stringWithUTF8String:appIcon];
282
unsetenv(envVar);
283
}
284
285
if (theIconPath == nil) {
286
theIconPath = [PropertiesUtilities javaSystemPropertyForKey:@"apple.awt.application.icon" withEnv:env];
287
}
288
289
// Use the path specified to get the icon image
290
NSImage* iconImage = nil;
291
if (theIconPath != nil) {
292
iconImage = [[NSImage alloc] initWithContentsOfFile:theIconPath];
293
}
294
295
// If no icon file was specified or we failed to get the icon image
296
// and there is no bundle's icon, then use the default icon
297
if (iconImage == nil) {
298
NSString* bundleIcon = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleIconFile"];
299
if (bundleIcon == nil) {
300
NSData* iconData;
301
iconData = [[NSData alloc] initWithBytesNoCopy: sAWTIconData length: sizeof(sAWTIconData) freeWhenDone: NO];
302
iconImage = [[NSImage alloc] initWithData: iconData];
303
[iconData release];
304
}
305
}
306
307
// Set up the dock icon if we have an icon image.
308
if (iconImage != nil) {
309
[NSApp setApplicationIconImage:iconImage];
310
[iconImage release];
311
}
312
}
313
314
+ (void) runAWTLoopWithApp:(NSApplication*)app {
315
NSAutoreleasePool *pool = [NSAutoreleasePool new];
316
317
// Make sure that when we run in javaRunLoopMode we don't exit randomly
318
[[NSRunLoop currentRunLoop] addPort:[NSPort port] forMode:[ThreadUtilities javaRunLoopMode]];
319
320
do {
321
@try {
322
[app run];
323
} @catch (NSException* e) {
324
NSLog(@"Apple AWT Startup Exception: %@", [e description]);
325
NSLog(@"Apple AWT Startup Exception callstack: %@", [e callStackSymbols]);
326
NSLog(@"Apple AWT Restarting Native Event Thread");
327
328
[app stop:app];
329
}
330
} while (YES);
331
332
[pool drain];
333
}
334
335
- (BOOL)usingDefaultNib {
336
return sUsingDefaultNIB;
337
}
338
339
- (void)orderFrontStandardAboutPanelWithOptions:(NSDictionary *)optionsDictionary {
340
if (!optionsDictionary) {
341
optionsDictionary = [NSMutableDictionary dictionaryWithCapacity:2];
342
[optionsDictionary setValue:[[[[[NSApp mainMenu] itemAtIndex:0] submenu] itemAtIndex:0] title] forKey:@"ApplicationName"];
343
if (![NSImage imageNamed:@"NSApplicationIcon"]) {
344
[optionsDictionary setValue:[NSApp applicationIconImage] forKey:@"ApplicationIcon"];
345
}
346
}
347
348
[super orderFrontStandardAboutPanelWithOptions:optionsDictionary];
349
}
350
351
#define DRAGMASK (NSMouseMovedMask | NSLeftMouseDraggedMask | NSRightMouseDownMask | NSRightMouseDraggedMask | NSLeftMouseUpMask | NSRightMouseUpMask | NSFlagsChangedMask | NSKeyDownMask)
352
353
#if defined(MAC_OS_X_VERSION_10_12) && __LP64__
354
// 10.12 changed `mask` to NSEventMask (unsigned long long) for x86_64 builds.
355
- (NSEvent *)nextEventMatchingMask:(NSEventMask)mask
356
#else
357
- (NSEvent *)nextEventMatchingMask:(NSUInteger)mask
358
#endif
359
untilDate:(NSDate *)expiration inMode:(NSString *)mode dequeue:(BOOL)deqFlag {
360
if (mask == DRAGMASK && [((NSString *)kCFRunLoopDefaultMode) isEqual:mode]) {
361
postEventDuringEventSynthesis = YES;
362
}
363
364
NSEvent *event = [super nextEventMatchingMask:mask untilDate:expiration inMode:mode dequeue: deqFlag];
365
postEventDuringEventSynthesis = NO;
366
367
return event;
368
}
369
370
// NSTimeInterval has microseconds precision
371
#define TS_EQUAL(ts1, ts2) (fabs((ts1) - (ts2)) < 1e-6)
372
373
- (void)sendEvent:(NSEvent *)event
374
{
375
if ([event type] == NSApplicationDefined
376
&& TS_EQUAL([event timestamp], dummyEventTimestamp)
377
&& (short)[event subtype] == NativeSyncQueueEvent
378
&& [event data1] == NativeSyncQueueEvent
379
&& [event data2] == NativeSyncQueueEvent) {
380
[seenDummyEventLock lockWhenCondition:NO];
381
[seenDummyEventLock unlockWithCondition:YES];
382
} else if ([event type] == NSApplicationDefined
383
&& (short)[event subtype] == ExecuteBlockEvent
384
&& [event data1] != 0 && [event data2] == ExecuteBlockEvent) {
385
void (^block)() = (void (^)()) [event data1];
386
block();
387
[block release];
388
} else if ([event type] == NSKeyUp && ([event modifierFlags] & NSCommandKeyMask)) {
389
// Cocoa won't send us key up event when releasing a key while Cmd is down,
390
// so we have to do it ourselves.
391
[[self keyWindow] sendEvent:event];
392
} else {
393
[super sendEvent:event];
394
}
395
}
396
397
/*
398
* Posts the block to the AppKit event queue which will be executed
399
* on the main AppKit loop.
400
* While running nested loops this event will be ignored.
401
*/
402
- (void)postRunnableEvent:(void (^)())block
403
{
404
void (^copy)() = [block copy];
405
NSInteger encode = (NSInteger) copy;
406
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
407
NSEvent* event = [NSEvent otherEventWithType: NSApplicationDefined
408
location: NSMakePoint(0,0)
409
modifierFlags: 0
410
timestamp: 0
411
windowNumber: 0
412
context: nil
413
subtype: ExecuteBlockEvent
414
data1: encode
415
data2: ExecuteBlockEvent];
416
417
[NSApp postEvent: event atStart: NO];
418
[pool drain];
419
}
420
421
- (void)postDummyEvent:(bool)useCocoa {
422
seenDummyEventLock = [[NSConditionLock alloc] initWithCondition:NO];
423
dummyEventTimestamp = [NSProcessInfo processInfo].systemUptime;
424
425
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
426
NSEvent* event = [NSEvent otherEventWithType: NSApplicationDefined
427
location: NSMakePoint(0,0)
428
modifierFlags: 0
429
timestamp: dummyEventTimestamp
430
windowNumber: 0
431
context: nil
432
subtype: NativeSyncQueueEvent
433
data1: NativeSyncQueueEvent
434
data2: NativeSyncQueueEvent];
435
if (useCocoa) {
436
[NSApp postEvent:event atStart:NO];
437
} else {
438
ProcessSerialNumber psn;
439
GetCurrentProcess(&psn);
440
CGEventPostToPSN(&psn, [event CGEvent]);
441
}
442
[pool drain];
443
}
444
445
- (void)waitForDummyEvent:(double)timeout {
446
bool unlock = true;
447
if (timeout >= 0) {
448
double sec = timeout / 1000;
449
unlock = [seenDummyEventLock lockWhenCondition:YES
450
beforeDate:[NSDate dateWithTimeIntervalSinceNow:sec]];
451
} else {
452
[seenDummyEventLock lockWhenCondition:YES];
453
}
454
if (unlock) {
455
[seenDummyEventLock unlock];
456
}
457
[seenDummyEventLock release];
458
459
seenDummyEventLock = nil;
460
}
461
462
@end
463
464
465
void OSXAPP_SetApplicationDelegate(id <NSApplicationDelegate> newdelegate)
466
{
467
AWT_ASSERT_APPKIT_THREAD;
468
applicationDelegate = newdelegate;
469
470
if (NSApp != nil) {
471
[NSApp setDelegate: applicationDelegate];
472
473
if (applicationDelegate && qad) {
474
[qad processQueuedEventsWithTargetDelegate: applicationDelegate];
475
qad = nil;
476
}
477
}
478
}
479
480