Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 15 additions & 7 deletions apps/finicky/src/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,10 @@ import (
var embeddedFiles embed.FS

type ProcessInfo struct {
Name string `json:"name"`
BundleID string `json:"bundleId"`
Path string `json:"path"`
Name string `json:"name"`
BundleID string `json:"bundleId"`
Path string `json:"path"`
WindowTitle string `json:"windowTitle,omitempty"`
}

type UpdateInfo struct {
Expand Down Expand Up @@ -254,7 +255,7 @@ func getConfigOption(optionName string, defaultValue bool) bool {
}

//export HandleURL
func HandleURL(url *C.char, name *C.char, bundleId *C.char, path *C.char, openInBackground C.bool) {
func HandleURL(url *C.char, name *C.char, bundleId *C.char, path *C.char, windowTitle *C.char, openInBackground C.bool) {
var opener ProcessInfo

if name != nil && bundleId != nil && path != nil {
Expand All @@ -263,6 +264,9 @@ func HandleURL(url *C.char, name *C.char, bundleId *C.char, path *C.char, openIn
BundleID: C.GoString(bundleId),
Path: C.GoString(path),
}
if windowTitle != nil {
opener.WindowTitle = C.GoString(windowTitle)
}
}

urlString := C.GoString(url)
Expand Down Expand Up @@ -341,12 +345,16 @@ func evaluateURL(vm *goja.Runtime, url string, opener *ProcessInfo) (*browser.Br
vm.Set("url", resolvedURL)

if opener != nil {
vm.Set("opener", map[string]interface{}{
openerMap := map[string]interface{}{
"name": opener.Name,
"bundleId": opener.BundleID,
"path": opener.Path,
})
slog.Debug("Setting opener", "name", opener.Name, "bundleId", opener.BundleID, "path", opener.Path)
}
if opener.WindowTitle != "" {
openerMap["windowTitle"] = opener.WindowTitle
}
vm.Set("opener", openerMap)
slog.Debug("Setting opener", "name", opener.Name, "bundleId", opener.BundleID, "path", opener.Path, "windowTitle", opener.WindowTitle)
} else {
vm.Set("opener", nil)
slog.Debug("No opener detected")
Expand Down
2 changes: 1 addition & 1 deletion apps/finicky/src/main.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#include <syslog.h>
#include <stdbool.h>

extern void HandleURL(char *url, char *name, char *bundleId, char *path, bool openInBackground);
extern void HandleURL(char *url, char *name, char *bundleId, char *path, char *windowTitle, bool openInBackground);
extern void QueueWindowDisplay(int launchedByUser);
extern void ShowConfigWindow();
extern char* GetCurrentConfigPath();
Expand Down
28 changes: 25 additions & 3 deletions apps/finicky/src/main.m
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "main.h"
#include "util/info.h"
#import <Cocoa/Cocoa.h>
#import <ApplicationServices/ApplicationServices.h>
#import <stdlib.h>
#import <unistd.h>

Expand Down Expand Up @@ -114,7 +115,7 @@ - (bool)application:(NSApplication *)sender openFile:(NSString *)filename {
NSString *urlString = [fileURL absoluteString];

// Handle the file URL the same way we handle other URLs
HandleURL((char*)[urlString UTF8String], NULL, NULL, NULL, false);
HandleURL((char*)[urlString UTF8String], NULL, NULL, NULL, NULL, false);

return true;
}
Expand All @@ -138,6 +139,8 @@ - (void)handleGetURLEvent:(NSAppleEventDescriptor *)event
// to detect if Finicky was launched in the background
bool finickyIsInFront = !self.keepRunning || [frontApp isEqual:[NSRunningApplication currentApplication]];

char *windowTitle = NULL;

if (application) {
NSString *appName = [application localizedName];
NSString *appBundleID = [application bundleIdentifier];
Expand All @@ -146,12 +149,31 @@ - (void)handleGetURLEvent:(NSAppleEventDescriptor *)event
name = [appName UTF8String];
bundleId = [appBundleID UTF8String];
path = [appPath UTF8String];

// Try to get the focused window title via Accessibility API
AXUIElementRef appElement = AXUIElementCreateApplication(pid);
if (appElement) {
AXUIElementRef focusedWindow = NULL;
AXError err = AXUIElementCopyAttributeValue(appElement, kAXFocusedWindowAttribute, (CFTypeRef *)&focusedWindow);
if (err == kAXErrorSuccess && focusedWindow) {
CFTypeRef titleValue = NULL;
AXError titleErr = AXUIElementCopyAttributeValue(focusedWindow, kAXTitleAttribute, &titleValue);
if (titleErr == kAXErrorSuccess && titleValue && CFGetTypeID(titleValue) == CFStringGetTypeID()) {
// strdup to keep a copy alive after CFRelease (no ARC in this project)
windowTitle = strdup([(NSString *)titleValue UTF8String]);
}
if (titleValue) CFRelease(titleValue);
CFRelease(focusedWindow);
}
CFRelease(appElement);
}
} else {
NSLog(@"No running application found with PID: %d", pid);
}

// If Finicky isn't frontmost, we take that to mean that the browser should, by default, be opened in the background
HandleURL((char*)url, (char*)name, (char*)bundleId, (char*)path, !finickyIsInFront);
HandleURL((char*)url, (char*)name, (char*)bundleId, (char*)path, windowTitle, !finickyIsInFront);
free(windowTitle);
}

- (bool)application:(NSApplication *)application willContinueUserActivityWithType:(NSString *)userActivityType {
Expand All @@ -168,7 +190,7 @@ - (bool)application:(NSApplication *)application continueUserActivity:(NSUserAct
return false;
}

HandleURL((char*)[[url absoluteString] UTF8String], NULL, NULL, NULL, false);
HandleURL((char*)[[url absoluteString] UTF8String], NULL, NULL, NULL, NULL, false);
return true;
}

Expand Down
1 change: 1 addition & 0 deletions packages/config-api/src/configSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ const ProcessInfoSchema = z
name: z.string(),
bundleId: z.string(),
path: z.string(),
windowTitle: z.string().optional(),
})
.identifier("ProcessInfo");

Expand Down