From 74d138072d9b6ed07a06c697d36716df4a9977e5 Mon Sep 17 00:00:00 2001 From: Josh <36625023+JoshuaBrest@users.noreply.github.com> Date: Fri, 17 May 2024 13:50:33 -0700 Subject: [PATCH 1/5] Set application name in macOS driver --- dlls/winemac.drv/cocoa_app.h | 2 + dlls/winemac.drv/cocoa_app.m | 134 ++++++++++++++++++++++++++++++++ dlls/winemac.drv/macdrv_cocoa.h | 1 + dlls/winemac.drv/window.c | 28 +++++++ 4 files changed, 165 insertions(+) diff --git a/dlls/winemac.drv/cocoa_app.h b/dlls/winemac.drv/cocoa_app.h index 8a06ca551663..dcd7f8fbc29d 100644 --- a/dlls/winemac.drv/cocoa_app.h +++ b/dlls/winemac.drv/cocoa_app.h @@ -128,6 +128,8 @@ enum { NSImage* applicationIcon; + NSString* applicationName; + BOOL beenActive; NSMutableSet* windowsBeingDragged; diff --git a/dlls/winemac.drv/cocoa_app.m b/dlls/winemac.drv/cocoa_app.m index f2a811fbe49e..1cc9ba06ca8d 100644 --- a/dlls/winemac.drv/cocoa_app.m +++ b/dlls/winemac.drv/cocoa_app.m @@ -92,6 +92,7 @@ @interface WineApplicationController () @property (retain, nonatomic) NSTimer* cursorTimer; @property (retain, nonatomic) NSCursor* cursor; @property (retain, nonatomic) NSImage* applicationIcon; +@property (copy, nonatomic) NSString* applicationName; @property (readonly, nonatomic) BOOL inputSourceIsInputMethod; @property (retain, nonatomic) WineWindow* mouseCaptureWindow; @@ -108,6 +109,7 @@ @implementation WineApplicationController @synthesize keyboardType, lastFlagsChanged; @synthesize displaysTemporarilyUncapturedForDialog, temporarilyIgnoreResignEventsForDialog; @synthesize applicationIcon; + @synthesize applicationName; @synthesize cursorFrames, cursorTimer, cursor; @synthesize mouseCaptureWindow; @synthesize lastSetCursorPositionTime; @@ -201,6 +203,7 @@ - (void) dealloc [cursor release]; [screenFrameCGRects release]; [applicationIcon release]; + [applicationName release]; [clipCursorHandler release]; [cursorTimer release]; [cursorFrames release]; @@ -384,6 +387,13 @@ - (void) transformProcessToForeground:(BOOL)activateIfTransformed [self changeEditMenuKeyEquivalentsForWindow:[NSApp keyWindow]]; [NSApp setApplicationIconImage:self.applicationIcon]; + + // Set application name + NSString* appName = [NSString stringWithFormat:@"WhiskyWine (%@)", self.applicationName]; + bool success = [self setProcessName:appName]; + if (!success) + ERR(@"Failed to set process name to %@", appName); + [appName release]; } } @@ -833,6 +843,109 @@ - (void) sendDisplaysChanged:(BOOL)activating macdrv_release_event(event); } + - (BOOL) setProcessName:(NSString*)name + { + // Convert the name to a CFString + CFStringRef cfName = (CFStringRef)name; + + // Must be called on the main thread + if (![NSThread isMainThread]) { + ERR(@"setProcessName: must be called on the main thread"); + return false; + } + + // New name can't be NULL or empty + if (!cfName || CFStringGetLength(cfName) == 0) { + ERR(@"setProcessName: Invalid process name"); + return false; + } + + // Private types used in calls to launch services + typedef CFTypeRef PrivateLaunchRef; + typedef PrivateLaunchRef (*LSGetCurrentApplicationASNType)(void); + typedef OSStatus (*LSSetApplicationInformationItemType)( + int, + PrivateLaunchRef, + CFStringRef, + CFStringRef, + CFDictionaryRef + ); + + // Static so we can reuse the same function pointers + static bool initialized = false; + static LSGetCurrentApplicationASNType getCurrentAppASNFunc = NULL; + static LSSetApplicationInformationItemType setAppInfoFunc = NULL; + static CFStringRef launchServicesDisplayNameKey = NULL; + + // Initialize the function pointers + if (!initialized) { + initialized = true; + + // Get the bundle for the LaunchServices framework + CFBundleRef launchServicesBundle = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.LaunchServices")); + if (!launchServicesBundle) { + ERR(@"setProcessName: Failed to get LaunchServices bundle"); + return false; + } + + // Get the function pointers + getCurrentAppASNFunc = (LSGetCurrentApplicationASNType)( + CFBundleGetFunctionPointerForName(launchServicesBundle, CFSTR("_LSGetCurrentApplicationASN")) + ); + if (!getCurrentAppASNFunc) { + ERR(@"setProcessName: Failed to get _LSGetCurrentApplicationASN in LaunchServices"); + return false; + } + setAppInfoFunc = (LSSetApplicationInformationItemType)( + CFBundleGetFunctionPointerForName(launchServicesBundle, CFSTR("_LSSetApplicationInformationItem")) + ); + if (!setAppInfoFunc) { + ERR(@"setProcessName: Failed to get _LSSetApplicationInformationItem in LaunchServices"); + return false; + } + + // Get the display name key + const CFStringRef* displayNameKey = (const CFStringRef*)( + CFBundleGetDataPointerForName(launchServicesBundle, CFSTR("_kLSDisplayNameKey")) + ); + launchServicesDisplayNameKey = displayNameKey ? *displayNameKey : NULL; + if (!launchServicesDisplayNameKey) { + ERR(@"setProcessName: Failed to get _kLSDisplayNameKey in LaunchServices"); + return false; + } + + // Force symbols to be loaded in the LaunchServices framework + ProcessSerialNumber psn = {0, kCurrentProcess}; + GetCurrentProcess(&psn); + } + + // If any of the function pointers are NULL, we can't continue + if (!getCurrentAppASNFunc || !setAppInfoFunc || !launchServicesDisplayNameKey) { + ERR(@"setProcessName: Failed to get all required LaunchServices functions"); + return false; + } + + // Get the current application's ASN + PrivateLaunchRef currentAppASN = getCurrentAppASNFunc(); + + // Set the display name + OSErr err = setAppInfoFunc( + -2, // WebKit uses -2 + currentAppASN, + launchServicesDisplayNameKey, + cfName, + NULL // Output parameter + ); + + // Log any errors + if (err != noErr) { + ERR(@"WHISKYEXTRA: Failed to set process name: %d", err); + return false; + } + + return true; + } + // We can compare two modes directly using CFEqual, but that may require that // they are identical to a level that we don't need. In particular, when the // OS switches between the integrated and discrete GPUs, the set of display @@ -1176,6 +1289,12 @@ - (void) setApplicationIconFromCGImageArray:(NSArray*)images self.applicationIcon = nsimage; } + - (void) setApplicationName:(NSString*)name + { + [applicationName release]; + applicationName = [name copy]; + } + - (void) handleCommandTab { if ([NSApp isActive]) @@ -2634,6 +2753,21 @@ void macdrv_set_application_icon(CFArrayRef images, CFURLRef urlRef) }); } +/*********************************************************************** + * macdrv_set_application_name + * + * Set the application name. + */ +void macdrv_set_application_name(CFStringRef name) +{ + NSString* nsName = (NSString*)name; + + OnMainThreadAsync(^{ + WineApplicationController* controller = [WineApplicationController sharedController]; + [controller setApplicationName:nsName]; + }); +} + /*********************************************************************** * macdrv_quit_reply */ diff --git a/dlls/winemac.drv/macdrv_cocoa.h b/dlls/winemac.drv/macdrv_cocoa.h index 4a2e3d1edd97..6ccd5d551b9e 100644 --- a/dlls/winemac.drv/macdrv_cocoa.h +++ b/dlls/winemac.drv/macdrv_cocoa.h @@ -266,6 +266,7 @@ extern int macdrv_start_cocoa_app(unsigned long long tickcount) DECLSPEC_HIDDEN; extern void macdrv_window_rejected_focus(const struct macdrv_event *event) DECLSPEC_HIDDEN; extern void macdrv_beep(void) DECLSPEC_HIDDEN; extern void macdrv_set_application_icon(CFArrayRef images, CFURLRef url /* CrossOver Hack 13440 */) DECLSPEC_HIDDEN; +extern void macdrv_set_application_name(CFStringRef name) DECLSPEC_HIDDEN; extern void macdrv_quit_reply(int reply) DECLSPEC_HIDDEN; extern int macdrv_using_input_method(void) DECLSPEC_HIDDEN; extern void macdrv_set_mouse_capture_window(macdrv_window window) DECLSPEC_HIDDEN; diff --git a/dlls/winemac.drv/window.c b/dlls/winemac.drv/window.c index c5d1712d0066..6c54df916b6c 100644 --- a/dlls/winemac.drv/window.c +++ b/dlls/winemac.drv/window.c @@ -1355,6 +1355,33 @@ static void set_app_icon(void) } } +/*********************************************************************** + * set_app_name + */ +static void set_app_name(void) +{ + WCHAR app_name[MAX_PATH]; + DWORD len = GetModuleFileNameW(0, app_name, ARRAY_SIZE(app_name)); + + // Get offset to the last backslash + DWORD last_char_pos = 0; + for (DWORD i = 0; i < len; i++) + { + if (app_name[i] == '\\') + last_char_pos = i; + } + + if (len && len < ARRAY_SIZE(app_name)) + { + CFStringRef name = CFStringCreateWithCharacters(NULL, app_name + last_char_pos + 1, len - last_char_pos - 1); + if (name) + { + macdrv_set_application_name(name); + CFRelease(name); + } + } +} + /********************************************************************** * set_capture_window_for_move @@ -1661,6 +1688,7 @@ BOOL macdrv_CreateDesktopWindow(HWND hwnd) } set_app_icon(); + set_app_name(); return TRUE; } From d8f71459bdb29e1dbaed29097746700c7881f961 Mon Sep 17 00:00:00 2001 From: Josh <36625023+JoshuaBrest@users.noreply.github.com> Date: Fri, 17 May 2024 14:00:12 -0700 Subject: [PATCH 2/5] Add hack comments --- dlls/winemac.drv/cocoa_app.h | 2 +- dlls/winemac.drv/cocoa_app.m | 10 +++++++--- dlls/winemac.drv/macdrv_cocoa.h | 2 +- dlls/winemac.drv/window.c | 2 ++ 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/dlls/winemac.drv/cocoa_app.h b/dlls/winemac.drv/cocoa_app.h index dcd7f8fbc29d..64efa407398c 100644 --- a/dlls/winemac.drv/cocoa_app.h +++ b/dlls/winemac.drv/cocoa_app.h @@ -128,7 +128,7 @@ enum { NSImage* applicationIcon; - NSString* applicationName; + NSString* applicationName; /* Whisky hack #9 */ BOOL beenActive; diff --git a/dlls/winemac.drv/cocoa_app.m b/dlls/winemac.drv/cocoa_app.m index 1cc9ba06ca8d..dc2afe672b49 100644 --- a/dlls/winemac.drv/cocoa_app.m +++ b/dlls/winemac.drv/cocoa_app.m @@ -92,7 +92,7 @@ @interface WineApplicationController () @property (retain, nonatomic) NSTimer* cursorTimer; @property (retain, nonatomic) NSCursor* cursor; @property (retain, nonatomic) NSImage* applicationIcon; -@property (copy, nonatomic) NSString* applicationName; +@property (copy, nonatomic) NSString* applicationName; /* Whisky hack #9 */ @property (readonly, nonatomic) BOOL inputSourceIsInputMethod; @property (retain, nonatomic) WineWindow* mouseCaptureWindow; @@ -109,7 +109,7 @@ @implementation WineApplicationController @synthesize keyboardType, lastFlagsChanged; @synthesize displaysTemporarilyUncapturedForDialog, temporarilyIgnoreResignEventsForDialog; @synthesize applicationIcon; - @synthesize applicationName; + @synthesize applicationName; /* Whisky hack #9 */ @synthesize cursorFrames, cursorTimer, cursor; @synthesize mouseCaptureWindow; @synthesize lastSetCursorPositionTime; @@ -203,7 +203,7 @@ - (void) dealloc [cursor release]; [screenFrameCGRects release]; [applicationIcon release]; - [applicationName release]; + [applicationName release]; /* Whisky hack #9 */ [clipCursorHandler release]; [cursorTimer release]; [cursorFrames release]; @@ -388,6 +388,7 @@ - (void) transformProcessToForeground:(BOOL)activateIfTransformed [NSApp setApplicationIconImage:self.applicationIcon]; + /* Whisky hack #9 */ // Set application name NSString* appName = [NSString stringWithFormat:@"WhiskyWine (%@)", self.applicationName]; bool success = [self setProcessName:appName]; @@ -843,6 +844,7 @@ - (void) sendDisplaysChanged:(BOOL)activating macdrv_release_event(event); } + /* Whisky hack #9 */ - (BOOL) setProcessName:(NSString*)name { // Convert the name to a CFString @@ -1289,6 +1291,7 @@ - (void) setApplicationIconFromCGImageArray:(NSArray*)images self.applicationIcon = nsimage; } + /* Whisky hack #9 */ - (void) setApplicationName:(NSString*)name { [applicationName release]; @@ -2753,6 +2756,7 @@ void macdrv_set_application_icon(CFArrayRef images, CFURLRef urlRef) }); } +/* Whisky hack #9 */ /*********************************************************************** * macdrv_set_application_name * diff --git a/dlls/winemac.drv/macdrv_cocoa.h b/dlls/winemac.drv/macdrv_cocoa.h index 6ccd5d551b9e..6ab9abf7a7c3 100644 --- a/dlls/winemac.drv/macdrv_cocoa.h +++ b/dlls/winemac.drv/macdrv_cocoa.h @@ -266,7 +266,7 @@ extern int macdrv_start_cocoa_app(unsigned long long tickcount) DECLSPEC_HIDDEN; extern void macdrv_window_rejected_focus(const struct macdrv_event *event) DECLSPEC_HIDDEN; extern void macdrv_beep(void) DECLSPEC_HIDDEN; extern void macdrv_set_application_icon(CFArrayRef images, CFURLRef url /* CrossOver Hack 13440 */) DECLSPEC_HIDDEN; -extern void macdrv_set_application_name(CFStringRef name) DECLSPEC_HIDDEN; +extern void macdrv_set_application_name(CFStringRef name) DECLSPEC_HIDDEN; /** Whisky hack #9 */ extern void macdrv_quit_reply(int reply) DECLSPEC_HIDDEN; extern int macdrv_using_input_method(void) DECLSPEC_HIDDEN; extern void macdrv_set_mouse_capture_window(macdrv_window window) DECLSPEC_HIDDEN; diff --git a/dlls/winemac.drv/window.c b/dlls/winemac.drv/window.c index 6c54df916b6c..6a4c8ca733d7 100644 --- a/dlls/winemac.drv/window.c +++ b/dlls/winemac.drv/window.c @@ -1355,6 +1355,7 @@ static void set_app_icon(void) } } +/* Whisky hack #9 */ /*********************************************************************** * set_app_name */ @@ -1688,6 +1689,7 @@ BOOL macdrv_CreateDesktopWindow(HWND hwnd) } set_app_icon(); + /* Whisky hack #9 */ set_app_name(); return TRUE; } From 0118600bcddb1273574e8ab01a44a996dc2cb2bb Mon Sep 17 00:00:00 2001 From: Josh <36625023+JoshuaBrest@users.noreply.github.com> Date: Fri, 17 May 2024 14:02:53 -0700 Subject: [PATCH 3/5] Add hack comments --- dlls/winemac.drv/macdrv_cocoa.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/winemac.drv/macdrv_cocoa.h b/dlls/winemac.drv/macdrv_cocoa.h index 6ab9abf7a7c3..a8c5171db5d1 100644 --- a/dlls/winemac.drv/macdrv_cocoa.h +++ b/dlls/winemac.drv/macdrv_cocoa.h @@ -266,7 +266,7 @@ extern int macdrv_start_cocoa_app(unsigned long long tickcount) DECLSPEC_HIDDEN; extern void macdrv_window_rejected_focus(const struct macdrv_event *event) DECLSPEC_HIDDEN; extern void macdrv_beep(void) DECLSPEC_HIDDEN; extern void macdrv_set_application_icon(CFArrayRef images, CFURLRef url /* CrossOver Hack 13440 */) DECLSPEC_HIDDEN; -extern void macdrv_set_application_name(CFStringRef name) DECLSPEC_HIDDEN; /** Whisky hack #9 */ +extern void macdrv_set_application_name(CFStringRef name) DECLSPEC_HIDDEN; /* Whisky hack #9 */ extern void macdrv_quit_reply(int reply) DECLSPEC_HIDDEN; extern int macdrv_using_input_method(void) DECLSPEC_HIDDEN; extern void macdrv_set_mouse_capture_window(macdrv_window window) DECLSPEC_HIDDEN; From 6e9aaec2ecb22f6319862aabcda5737653b655c5 Mon Sep 17 00:00:00 2001 From: Josh <36625023+JoshuaBrest@users.noreply.github.com> Date: Sat, 18 May 2024 13:51:00 -0700 Subject: [PATCH 4/5] Use NSLog instead of ERR (doesn't support NSString) --- dlls/winemac.drv/cocoa_app.h | 4 ++++ dlls/winemac.drv/cocoa_app.m | 20 ++++++++++---------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/dlls/winemac.drv/cocoa_app.h b/dlls/winemac.drv/cocoa_app.h index 64efa407398c..4b6003990cd7 100644 --- a/dlls/winemac.drv/cocoa_app.h +++ b/dlls/winemac.drv/cocoa_app.h @@ -66,6 +66,10 @@ enum { WineApplicationEventWakeQuery, }; +/* Whisky hack #9 */ +#define kAppNameText @"%@ (Whi" \ + @"sky)" + @class WineEventQueue; @class WineWindow; diff --git a/dlls/winemac.drv/cocoa_app.m b/dlls/winemac.drv/cocoa_app.m index dc2afe672b49..b58318cebd4b 100644 --- a/dlls/winemac.drv/cocoa_app.m +++ b/dlls/winemac.drv/cocoa_app.m @@ -390,10 +390,10 @@ - (void) transformProcessToForeground:(BOOL)activateIfTransformed /* Whisky hack #9 */ // Set application name - NSString* appName = [NSString stringWithFormat:@"WhiskyWine (%@)", self.applicationName]; + NSString* appName = [NSString stringWithFormat:kAppNameText, self.applicationName]; bool success = [self setProcessName:appName]; if (!success) - ERR(@"Failed to set process name to %@", appName); + NSLog(@"Failed to set process name to %@", appName); [appName release]; } } @@ -852,13 +852,13 @@ - (BOOL) setProcessName:(NSString*)name // Must be called on the main thread if (![NSThread isMainThread]) { - ERR(@"setProcessName: must be called on the main thread"); + NSLog(@"setProcessName: must be called on the main thread"); return false; } // New name can't be NULL or empty if (!cfName || CFStringGetLength(cfName) == 0) { - ERR(@"setProcessName: Invalid process name"); + NSLog(@"setProcessName: Invalid process name"); return false; } @@ -886,7 +886,7 @@ typedef OSStatus (*LSSetApplicationInformationItemType)( // Get the bundle for the LaunchServices framework CFBundleRef launchServicesBundle = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.LaunchServices")); if (!launchServicesBundle) { - ERR(@"setProcessName: Failed to get LaunchServices bundle"); + NSLog(@"setProcessName: Failed to get LaunchServices bundle"); return false; } @@ -895,14 +895,14 @@ typedef OSStatus (*LSSetApplicationInformationItemType)( CFBundleGetFunctionPointerForName(launchServicesBundle, CFSTR("_LSGetCurrentApplicationASN")) ); if (!getCurrentAppASNFunc) { - ERR(@"setProcessName: Failed to get _LSGetCurrentApplicationASN in LaunchServices"); + NSLog(@"setProcessName: Failed to get _LSGetCurrentApplicationASN in LaunchServices"); return false; } setAppInfoFunc = (LSSetApplicationInformationItemType)( CFBundleGetFunctionPointerForName(launchServicesBundle, CFSTR("_LSSetApplicationInformationItem")) ); if (!setAppInfoFunc) { - ERR(@"setProcessName: Failed to get _LSSetApplicationInformationItem in LaunchServices"); + NSLog(@"setProcessName: Failed to get _LSSetApplicationInformationItem in LaunchServices"); return false; } @@ -912,7 +912,7 @@ typedef OSStatus (*LSSetApplicationInformationItemType)( ); launchServicesDisplayNameKey = displayNameKey ? *displayNameKey : NULL; if (!launchServicesDisplayNameKey) { - ERR(@"setProcessName: Failed to get _kLSDisplayNameKey in LaunchServices"); + NSLog(@"setProcessName: Failed to get _kLSDisplayNameKey in LaunchServices"); return false; } @@ -923,7 +923,7 @@ typedef OSStatus (*LSSetApplicationInformationItemType)( // If any of the function pointers are NULL, we can't continue if (!getCurrentAppASNFunc || !setAppInfoFunc || !launchServicesDisplayNameKey) { - ERR(@"setProcessName: Failed to get all required LaunchServices functions"); + NSLog(@"setProcessName: Failed to get all required LaunchServices functions"); return false; } @@ -941,7 +941,7 @@ typedef OSStatus (*LSSetApplicationInformationItemType)( // Log any errors if (err != noErr) { - ERR(@"WHISKYEXTRA: Failed to set process name: %d", err); + NSLog(@"setProcessName: Failed to set display name: %d", err); return false; } From fefb3e479160b649fe22230d9059967f003b40b7 Mon Sep 17 00:00:00 2001 From: Josh <36625023+JoshuaBrest@users.noreply.github.com> Date: Tue, 18 Jun 2024 23:43:44 +0800 Subject: [PATCH 5/5] Remove free that causes crash --- dlls/winemac.drv/cocoa_app.m | 1 - 1 file changed, 1 deletion(-) diff --git a/dlls/winemac.drv/cocoa_app.m b/dlls/winemac.drv/cocoa_app.m index b58318cebd4b..8a3334a32c3e 100644 --- a/dlls/winemac.drv/cocoa_app.m +++ b/dlls/winemac.drv/cocoa_app.m @@ -394,7 +394,6 @@ - (void) transformProcessToForeground:(BOOL)activateIfTransformed bool success = [self setProcessName:appName]; if (!success) NSLog(@"Failed to set process name to %@", appName); - [appName release]; } }