Skip to content

Commit 64b8d87

Browse files
fix rvlinklauncher and multiple windows
Signed-off-by: Cédrik Fuoco <[email protected]>
1 parent 14a10ca commit 64b8d87

File tree

1 file changed

+60
-21
lines changed

1 file changed

+60
-21
lines changed

src/bin/nsapps/rvlinklauncher/RVLinkLauncher.mm

Lines changed: 60 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,22 @@
88

99
@interface RVLinkURLHandler : NSObject {
1010
BOOL urlProcessed;
11+
NSAlert *currentAlert;
1112
}
1213
- (void)handleGetURLEvent:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent;
1314
- (void)processRVLinkURL:(NSString *)rvlinkURL;
1415
- (BOOL)hasProcessedURL;
1516
- (NSMutableArray<NSURL *> *)findRVAppsUsingMDFind;
1617
- (NSMutableArray<NSURL *> *)findRVAppsUsingWorkspace:(NSString *)rvlinkURL;
18+
+ (BOOL)terminateOtherInstancesIfNeeded;
1719
@end
1820

1921
@implementation RVLinkURLHandler
2022
- (instancetype)init {
2123
self = [super init];
2224
if (self) {
2325
urlProcessed = NO;
26+
currentAlert = nil;
2427
}
2528
return self;
2629
}
@@ -29,9 +32,39 @@ - (BOOL)hasProcessedURL {
2932
return urlProcessed;
3033
}
3134

35+
+ (BOOL)terminateOtherInstancesIfNeeded {
36+
NSString *bundleID = [[NSBundle mainBundle] bundleIdentifier];
37+
NSArray<NSRunningApplication *> *runningInstances =
38+
[NSRunningApplication runningApplicationsWithBundleIdentifier:bundleID];
39+
40+
int currentPID = [[NSProcessInfo processInfo] processIdentifier];
41+
42+
// Terminate any other running instances to prevent multiple dialogs
43+
for (NSRunningApplication *app in runningInstances) {
44+
int instancePID = [app processIdentifier];
45+
46+
if (instancePID != currentPID) {
47+
// Use forceTerminate because the other instance may be blocked in a modal dialog
48+
[app forceTerminate];
49+
[NSThread sleepForTimeInterval:0.3];
50+
}
51+
}
52+
53+
return NO;
54+
}
55+
3256
- (void)handleGetURLEvent:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent
3357
{
3458
NSLog(@"*** RVLinkLauncher Apple Event handler called! ***");
59+
60+
// If we're showing a dialog, close it so we can show a new one with the new URL
61+
if (currentAlert != nil) {
62+
[[NSApplication sharedApplication] stopModal];
63+
[[currentAlert window] close];
64+
urlProcessed = NO;
65+
currentAlert = nil;
66+
}
67+
3568
@try {
3669
NSAppleEventDescriptor *directObjectDescriptor = [event paramDescriptorForKeyword:keyDirectObject];
3770
if (directObjectDescriptor != nil) {
@@ -75,7 +108,6 @@ - (void)handleGetURLEvent:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppl
75108
if ([line length] > 0) {
76109
NSURL *url = [NSURL fileURLWithPath:line];
77110
if (url != nil) {
78-
// Get app details for logging
79111
NSString *displayName = [[NSFileManager defaultManager] displayNameAtPath:line];
80112
NSBundle *bundle = [NSBundle bundleWithURL:url];
81113
NSString *bundleID = [bundle bundleIdentifier];
@@ -143,7 +175,7 @@ - (void)processRVLinkURL:(NSString *)rvlinkURL
143175
}
144176
}
145177

146-
// Add workspace results (skip duplicates)
178+
// Add workspace results (skip duplicates)
147179
for (NSURL *appURL in registeredApps) {
148180
NSString *path = [appURL path];
149181
if (![seenPaths containsObject:path]) {
@@ -156,12 +188,13 @@ - (void)processRVLinkURL:(NSString *)rvlinkURL
156188

157189
// Check if we found any RV apps
158190
if ([appURLs count] == 0) {
159-
NSAlert *noAppsAlert = [[NSAlert alloc] init];
160-
[noAppsAlert setMessageText:@"No RV Applications Found"];
161-
[noAppsAlert setInformativeText:@"Could not find any installed RV applications to open the rvlink URL."];
162-
[noAppsAlert addButtonWithTitle:@"OK"];
163-
[noAppsAlert runModal];
164-
[noAppsAlert release];
191+
currentAlert = [[NSAlert alloc] init];
192+
[currentAlert setMessageText:@"No RV Applications Found"];
193+
[currentAlert setInformativeText:@"Could not find any installed RV applications to open the rvlink URL."];
194+
[currentAlert addButtonWithTitle:@"OK"];
195+
[currentAlert runModal];
196+
[currentAlert release];
197+
currentAlert = nil;
165198
return;
166199
}
167200

@@ -192,11 +225,11 @@ - (void)processRVLinkURL:(NSString *)rvlinkURL
192225
}
193226

194227
// Present chooser UI for multiple apps
195-
NSAlert *alert = [[NSAlert alloc] init];
196-
[alert setMessageText:@"Choose RV Application"];
197-
[alert setInformativeText:[NSString stringWithFormat:@"Opening: %@", rvlinkURL]];
198-
[alert addButtonWithTitle:@"Open"];
199-
[alert addButtonWithTitle:@"Cancel"];
228+
currentAlert = [[NSAlert alloc] init];
229+
[currentAlert setMessageText:@"Choose RV Application"];
230+
[currentAlert setInformativeText:[NSString stringWithFormat:@"Opening: %@", rvlinkURL]];
231+
[currentAlert addButtonWithTitle:@"Open"];
232+
[currentAlert addButtonWithTitle:@"Cancel"];
200233

201234
// Sort apps by path for consistent ordering
202235
NSArray *sortedAppURLs = [appURLs sortedArrayUsingComparator:^NSComparisonResult(NSURL *url1, NSURL *url2) {
@@ -230,9 +263,12 @@ - (void)processRVLinkURL:(NSString *)rvlinkURL
230263
[popup addItemWithTitle:itemTitle];
231264
[[popup lastItem] setRepresentedObject:appURL];
232265
}
233-
[alert setAccessoryView:popup];
266+
[currentAlert setAccessoryView:popup];
234267

235-
NSInteger result = [alert runModal];
268+
NSInteger result = [currentAlert runModal];
269+
NSAlert *alert = currentAlert;
270+
currentAlert = nil;
271+
236272
if (result == NSAlertFirstButtonReturn) {
237273
NSURL *selectedAppURL = [[popup selectedItem] representedObject];
238274
NSURL *targetURL = [NSURL URLWithString:rvlinkURL];
@@ -261,21 +297,21 @@ - (void)processRVLinkURL:(NSString *)rvlinkURL
261297
int main(int argc, const char * argv[])
262298
{
263299
@autoreleasepool {
264-
// 1. Register Apple Event handler for URL events
300+
// Register Apple Event handler for URL events
265301
RVLinkURLHandler *urlHandler = [[RVLinkURLHandler alloc] init];
266302
[[NSAppleEventManager sharedAppleEventManager]
267303
setEventHandler:urlHandler
268304
andSelector:@selector(handleGetURLEvent:withReplyEvent:)
269305
forEventClass:kInternetEventClass
270306
andEventID:kAEGetURL];
271307

272-
// 2. Automate reset of protocol handler on launch
308+
// Register as default handler for rvlink:// URLs
273309
NSString *bundleID = [[NSBundle mainBundle] bundleIdentifier];
274310
CFStringRef scheme = CFSTR("rvlink");
275311
CFStringRef handler = (__bridge CFStringRef)bundleID;
276312
LSSetDefaultHandlerForURLScheme(scheme, handler);
277313

278-
// 3. Check if RVLinkLauncher is the default handler and prompt user if not
314+
// Warn if not the default handler
279315
CFStringRef currentHandler = LSCopyDefaultHandlerForURLScheme(scheme);
280316
if (currentHandler != NULL && !CFEqual(currentHandler, handler)) {
281317
NSAlert *warnAlert = [[NSAlert alloc] init];
@@ -289,7 +325,10 @@ int main(int argc, const char * argv[])
289325
CFRelease(currentHandler);
290326
}
291327

292-
// Check command line arguments for immediate URL processing
328+
// Terminate any other running instances to prevent multiple dialogs
329+
[RVLinkURLHandler terminateOtherInstancesIfNeeded];
330+
331+
// Check for command line URL
293332
NSString *rvlinkURL = nil;
294333
for (int i = 1; i < argc; i++) {
295334
NSString *arg = [NSString stringWithUTF8String:argv[i]];
@@ -303,15 +342,15 @@ int main(int argc, const char * argv[])
303342
if (rvlinkURL != nil) {
304343
NSLog(@"Processing rvlink URL from command line: %@", rvlinkURL);
305344
[urlHandler processRVLinkURL:rvlinkURL];
306-
return 0; // Exit after processing command line URL
345+
return 0;
307346
}
308347

309348
// No immediate URL - register handler and wait briefly for Apple Events
310349
NSLog(@"RVLinkLauncher registered and ready to handle rvlink:// URLs");
311350

312351
// Run the event loop briefly to allow Apple Events to be received
313352
// This is needed when the app is launched by clicking a rvlink:// URL
314-
NSDate *timeout = [NSDate dateWithTimeIntervalSinceNow:2.0]; // Wait up to 2 seconds
353+
NSDate *timeout = [NSDate dateWithTimeIntervalSinceNow:2.0];
315354
while ([timeout timeIntervalSinceNow] > 0 && ![urlHandler hasProcessedURL]) {
316355
NSEvent *event = [[NSApplication sharedApplication]
317356
nextEventMatchingMask:NSEventMaskAny

0 commit comments

Comments
 (0)