Skip to content

Commit edcd6e7

Browse files
committed
JBR-8422: A temporary workaround for crash in SystemHotkey setup on macOS 15.4 beta
1 parent 4e0a566 commit edcd6e7

3 files changed

Lines changed: 77 additions & 81 deletions

File tree

src/java.desktop/macosx/native/libawt_lwawt/awt/LWCToolkit.m

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@
3636
#import "NSApplicationAWT.h"
3737
#import "PropertiesUtilities.h"
3838
#import "ApplicationDelegate.h"
39-
#import "SystemHotkey.h"
4039

4140
#import "sun_lwawt_macosx_LWCToolkit.h"
4241

@@ -263,8 +262,6 @@ static void setUpAWTAppKit(BOOL installObservers)
263262
CFRelease(notBusyObserver);
264263

265264
setBusy(YES);
266-
267-
[SystemHotkey setUp];
268265
}
269266

270267
JNIEnv* env = [ThreadUtilities getJNIEnv];

src/java.desktop/macosx/native/libawt_lwawt/awt/SystemHotkey.h

Lines changed: 0 additions & 34 deletions
This file was deleted.

src/java.desktop/macosx/native/libawt_lwawt/awt/SystemHotkey.m

Lines changed: 77 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#include "SystemHotkey.h"
1+
#include <pthread.h>
22

33
#import <Foundation/Foundation.h>
44
#import <Carbon/Carbon.h>
@@ -15,6 +15,10 @@
1515

1616
extern JavaVM *jvm;
1717

18+
@interface SystemHotkey : NSObject
19+
+ (void)subscribeToChanges;
20+
@end
21+
1822
enum LOG_LEVEL {
1923
LL_TRACE,
2024
LL_DEBUG,
@@ -23,7 +27,7 @@
2327
LL_ERROR
2428
};
2529

26-
void plog(int logLevel, const char *formatMsg, ...) {
30+
static void plog(int logLevel, const char *formatMsg, ...) {
2731
if (!jvm)
2832
return;
2933
if (logLevel < LL_TRACE || logLevel > LL_ERROR || formatMsg == NULL)
@@ -268,12 +272,20 @@ static int symbolicHotKeysModifiers2java(int mask) {
268272

269273
static const int numSymbolicHotkeys = sizeof(defaultSymbolicHotKeys) / sizeof(defaultSymbolicHotKeys[0]);
270274

271-
// Current state of system shortcuts.
272-
// Should only be read and written inside a @synchronized([SystemHotkey class]) block
273-
static struct SymbolicHotKey currentSymbolicHotkeys[numSymbolicHotkeys];
275+
static struct SystemHotkeyState {
276+
bool symbolicHotkeysFilled;
277+
struct SymbolicHotKey currentSymbolicHotkeys[numSymbolicHotkeys];
278+
279+
bool initialized;
280+
bool enabled;
274281

275-
// Should only be read and written inside a @synchronized([SystemHotkey class]) block
276-
static bool subscribedToShortcutUpdates = false;
282+
pthread_mutex_t mutex;
283+
} state = {
284+
.symbolicHotkeysFilled = false,
285+
.initialized = false,
286+
.enabled = false,
287+
.mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER,
288+
};
277289

278290
@interface DefaultParams: NSObject
279291
@property (assign) BOOL enabled;
@@ -457,9 +469,10 @@ static void updateAppleSymbolicHotkeysCache() {
457469
struct SymbolicHotKey hotkeys[numSymbolicHotkeys];
458470
readAppleSymbolicHotkeys(hotkeys);
459471

460-
@synchronized ([SystemHotkey class]) {
461-
memcpy(currentSymbolicHotkeys, hotkeys, numSymbolicHotkeys * sizeof(struct SymbolicHotKey));
462-
}
472+
pthread_mutex_lock(&state.mutex);
473+
memcpy(state.currentSymbolicHotkeys, hotkeys, sizeof(hotkeys));
474+
state.symbolicHotkeysFilled = true;
475+
pthread_mutex_unlock(&state.mutex);
463476
}
464477

465478
static void iterateAppleSymbolicHotkeys(struct SymbolicHotKey hotkeys[numSymbolicHotkeys], Visitor visitorBlock) {
@@ -559,19 +572,46 @@ static void readPbsHotkeys(Visitor visitorBlock) {
559572
}
560573
}
561574

575+
static bool ensureInitializedAndEnabled() {
576+
pthread_mutex_lock(&state.mutex);
577+
if (state.initialized) {
578+
bool enabled = state.enabled;
579+
pthread_mutex_unlock(&state.mutex);
580+
return enabled;
581+
}
582+
583+
// JBR-8422
584+
const NSOperatingSystemVersion macOSVersion = [[NSProcessInfo processInfo] operatingSystemVersion];
585+
if (macOSVersion.majorVersion > 15 || (macOSVersion.majorVersion == 15 && macOSVersion.minorVersion >= 4)) {
586+
state.initialized = true;
587+
state.enabled = false;
588+
pthread_mutex_unlock(&state.mutex);
589+
return false;
590+
}
591+
592+
state.initialized = true;
593+
state.enabled = true;
594+
[SystemHotkey subscribeToChanges];
595+
pthread_mutex_unlock(&state.mutex);
596+
updateAppleSymbolicHotkeysCache();
597+
598+
return true;
599+
}
600+
562601
static void readAppleSymbolicHotkeysCached(struct SymbolicHotKey hotkeys[numSymbolicHotkeys]) {
563-
@synchronized ([SystemHotkey class]) {
564-
if (!subscribedToShortcutUpdates) {
565-
[SystemHotkey setUp];
566-
}
602+
memset(hotkeys, 0, sizeof(struct SymbolicHotKey) * numSymbolicHotkeys);
567603

568-
memcpy(hotkeys, currentSymbolicHotkeys, numSymbolicHotkeys * sizeof(struct SymbolicHotKey));
604+
pthread_mutex_lock(&state.mutex);
605+
if (state.symbolicHotkeysFilled) {
606+
memcpy(hotkeys, state.currentSymbolicHotkeys, sizeof(struct SymbolicHotKey) * numSymbolicHotkeys);
569607
}
608+
pthread_mutex_unlock(&state.mutex);
570609
}
571610

572611
static void readSystemHotkeysImpl(Visitor visitorBlock) {
573-
// Normally, SystemHotkey would get initialized in LWCToolkit initialization.
574-
// But since we can (theoretically) use this API from headless, let's check again.
612+
if (!ensureInitializedAndEnabled()) {
613+
return;
614+
}
575615

576616
struct SymbolicHotKey hotkeys[numSymbolicHotkeys];
577617
readAppleSymbolicHotkeysCached(hotkeys);
@@ -581,40 +621,32 @@ static void readSystemHotkeysImpl(Visitor visitorBlock) {
581621
}
582622

583623
@implementation SystemHotkey
584-
+ (void)setUp {
585-
// This should be called on LWCToolkit initialization.
586-
587-
@synchronized (self) {
588-
if (subscribedToShortcutUpdates) {
589-
return;
590-
}
591-
592-
// Update cached values
593-
updateAppleSymbolicHotkeysCache();
594-
595-
// Subscribe to changes
596-
NSUserDefaults *symbolicHotKeys = [[NSUserDefaults alloc] initWithSuiteName:@"com.apple.symbolichotkeys"];
597-
[symbolicHotKeys addObserver:self forKeyPath:@"AppleSymbolicHotKeys" options:NSKeyValueObservingOptionNew
598-
context:nil];
599-
600-
NSUserDefaults *pbsHotKeys = [[NSUserDefaults alloc] initWithSuiteName:@"pbs"];
601-
[pbsHotKeys addObserver:self forKeyPath:@"NSServicesStatus" options:NSKeyValueObservingOptionNew context:nil];
602-
603-
subscribedToShortcutUpdates = true;
604-
}
624+
+ (void)subscribeToChanges {
625+
// Subscribe to changes
626+
NSUserDefaults *symbolicHotKeys = [[NSUserDefaults alloc] initWithSuiteName:@"com.apple.symbolichotkeys"];
627+
[symbolicHotKeys addObserver:self forKeyPath:@"AppleSymbolicHotKeys" options:NSKeyValueObservingOptionNew
628+
context:nil];
629+
630+
NSUserDefaults *pbsHotKeys = [[NSUserDefaults alloc] initWithSuiteName:@"pbs"];
631+
[pbsHotKeys addObserver:self forKeyPath:@"NSServicesStatus" options:NSKeyValueObservingOptionNew context:nil];
605632
}
606633

607634
+ (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey, id> *)change context:(void *)context {
608635
// Called after AppleSymbolicHotKeys or pbs hotkeys change.
609-
// This method can be called from any thread.
610636

611637
if ([keyPath isEqualToString:@"AppleSymbolicHotKeys"]) {
612638
updateAppleSymbolicHotkeysCache();
613639
}
614640

641+
// This method should only be called from the main thread, but let's check anyway
642+
if (pthread_main_np() == 0) {
643+
return;
644+
}
645+
615646
// Since this notification is sent *after* the configuration was updated,
616647
// the user can safely re-read the hotkeys info after receiving this callback.
617648
// On the Java side, this simply enqueues the change handler to run on the EDT later.
649+
618650
JNIEnv* env = [ThreadUtilities getJNIEnv];
619651
DECLARE_CLASS(jc_SystemHotkey, "java/awt/desktop/SystemHotkey");
620652
DECLARE_STATIC_METHOD(jsm_onChange, jc_SystemHotkey, "onChange", "()V");
@@ -624,12 +656,13 @@ + (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(N
624656
@end
625657

626658
bool isSystemShortcut_NextWindowInApplication(NSUInteger modifiersMask, int keyCode, NSString *chars) {
627-
struct SymbolicHotKey shortcut;
628-
@synchronized ([SystemHotkey class]) {
629-
if (!subscribedToShortcutUpdates) {
630-
[SystemHotkey setUp];
659+
struct SymbolicHotKey shortcut = defaultSymbolicHotKeys[Shortcut_FocusNextApplicationWindow];
660+
if (ensureInitializedAndEnabled()) {
661+
pthread_mutex_lock(&state.mutex);
662+
if (state.symbolicHotkeysFilled) {
663+
shortcut = state.currentSymbolicHotkeys[Shortcut_FocusNextApplicationWindow];
631664
}
632-
shortcut = currentSymbolicHotkeys[Shortcut_FocusNextApplicationWindow];
665+
pthread_mutex_unlock(&state.mutex);
633666
}
634667

635668
int ignoredModifiers = NSAlphaShiftKeyMask | NSFunctionKeyMask | NSNumericPadKeyMask | NSHelpKeyMask;

0 commit comments

Comments
 (0)