diff --git a/dlls/winemac.drv/cocoa_app.h b/dlls/winemac.drv/cocoa_app.h index 8a06ca551663..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; @@ -128,6 +132,8 @@ enum { NSImage* applicationIcon; + NSString* applicationName; /* Whisky hack #9 */ + BOOL beenActive; NSMutableSet* windowsBeingDragged; diff --git a/dlls/winemac.drv/cocoa_app.m b/dlls/winemac.drv/cocoa_app.m index f2a811fbe49e..8a3334a32c3e 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; /* Whisky hack #9 */ @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; /* Whisky hack #9 */ @synthesize cursorFrames, cursorTimer, cursor; @synthesize mouseCaptureWindow; @synthesize lastSetCursorPositionTime; @@ -201,6 +203,7 @@ - (void) dealloc [cursor release]; [screenFrameCGRects release]; [applicationIcon release]; + [applicationName release]; /* Whisky hack #9 */ [clipCursorHandler release]; [cursorTimer release]; [cursorFrames release]; @@ -384,6 +387,13 @@ - (void) transformProcessToForeground:(BOOL)activateIfTransformed [self changeEditMenuKeyEquivalentsForWindow:[NSApp keyWindow]]; [NSApp setApplicationIconImage:self.applicationIcon]; + + /* Whisky hack #9 */ + // Set application name + NSString* appName = [NSString stringWithFormat:kAppNameText, self.applicationName]; + bool success = [self setProcessName:appName]; + if (!success) + NSLog(@"Failed to set process name to %@", appName); } } @@ -833,6 +843,110 @@ - (void) sendDisplaysChanged:(BOOL)activating macdrv_release_event(event); } + /* Whisky hack #9 */ + - (BOOL) setProcessName:(NSString*)name + { + // Convert the name to a CFString + CFStringRef cfName = (CFStringRef)name; + + // Must be called on the main thread + if (![NSThread isMainThread]) { + NSLog(@"setProcessName: must be called on the main thread"); + return false; + } + + // New name can't be NULL or empty + if (!cfName || CFStringGetLength(cfName) == 0) { + NSLog(@"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) { + NSLog(@"setProcessName: Failed to get LaunchServices bundle"); + return false; + } + + // Get the function pointers + getCurrentAppASNFunc = (LSGetCurrentApplicationASNType)( + CFBundleGetFunctionPointerForName(launchServicesBundle, CFSTR("_LSGetCurrentApplicationASN")) + ); + if (!getCurrentAppASNFunc) { + NSLog(@"setProcessName: Failed to get _LSGetCurrentApplicationASN in LaunchServices"); + return false; + } + setAppInfoFunc = (LSSetApplicationInformationItemType)( + CFBundleGetFunctionPointerForName(launchServicesBundle, CFSTR("_LSSetApplicationInformationItem")) + ); + if (!setAppInfoFunc) { + NSLog(@"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) { + NSLog(@"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) { + NSLog(@"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) { + NSLog(@"setProcessName: Failed to set display 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 +1290,13 @@ - (void) setApplicationIconFromCGImageArray:(NSArray*)images self.applicationIcon = nsimage; } + /* Whisky hack #9 */ + - (void) setApplicationName:(NSString*)name + { + [applicationName release]; + applicationName = [name copy]; + } + - (void) handleCommandTab { if ([NSApp isActive]) @@ -2634,6 +2755,22 @@ void macdrv_set_application_icon(CFArrayRef images, CFURLRef urlRef) }); } +/* Whisky hack #9 */ +/*********************************************************************** + * 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..a8c5171db5d1 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; /* 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 c5d1712d0066..6a4c8ca733d7 100644 --- a/dlls/winemac.drv/window.c +++ b/dlls/winemac.drv/window.c @@ -1355,6 +1355,34 @@ static void set_app_icon(void) } } +/* Whisky hack #9 */ +/*********************************************************************** + * 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 +1689,8 @@ BOOL macdrv_CreateDesktopWindow(HWND hwnd) } set_app_icon(); + /* Whisky hack #9 */ + set_app_name(); return TRUE; }