Commit b1de5323 authored by Ken Thomases's avatar Ken Thomases Committed by Alexandre Julliard

winemac: Set application Dock icon from first icon resource in process's .exe file.

parent 462721a1
...@@ -75,6 +75,8 @@ enum { ...@@ -75,6 +75,8 @@ enum {
CGPoint synthesizedLocation; CGPoint synthesizedLocation;
NSTimeInterval lastSetCursorPositionTime; NSTimeInterval lastSetCursorPositionTime;
NSTimeInterval lastEventTapEventTime; NSTimeInterval lastEventTapEventTime;
NSImage* applicationIcon;
} }
@property (nonatomic) CGEventSourceKeyboardType keyboardType; @property (nonatomic) CGEventSourceKeyboardType keyboardType;
......
...@@ -58,6 +58,7 @@ int macdrv_err_on; ...@@ -58,6 +58,7 @@ int macdrv_err_on;
@property (readwrite, copy, nonatomic) NSEvent* lastFlagsChanged; @property (readwrite, copy, nonatomic) NSEvent* lastFlagsChanged;
@property (copy, nonatomic) NSArray* cursorFrames; @property (copy, nonatomic) NSArray* cursorFrames;
@property (retain, nonatomic) NSTimer* cursorTimer; @property (retain, nonatomic) NSTimer* cursorTimer;
@property (retain, nonatomic) NSImage* applicationIcon;
static void PerformRequest(void *info); static void PerformRequest(void *info);
...@@ -67,7 +68,7 @@ int macdrv_err_on; ...@@ -67,7 +68,7 @@ int macdrv_err_on;
@implementation WineApplication @implementation WineApplication
@synthesize keyboardType, lastFlagsChanged; @synthesize keyboardType, lastFlagsChanged;
@synthesize orderedWineWindows; @synthesize orderedWineWindows, applicationIcon;
@synthesize cursorFrames, cursorTimer; @synthesize cursorFrames, cursorTimer;
- (id) init - (id) init
...@@ -111,6 +112,7 @@ int macdrv_err_on; ...@@ -111,6 +112,7 @@ int macdrv_err_on;
- (void) dealloc - (void) dealloc
{ {
[applicationIcon release];
[warpRecords release]; [warpRecords release];
[cursorTimer release]; [cursorTimer release];
[cursorFrames release]; [cursorFrames release];
...@@ -169,6 +171,8 @@ int macdrv_err_on; ...@@ -169,6 +171,8 @@ int macdrv_err_on;
[self setMainMenu:mainMenu]; [self setMainMenu:mainMenu];
[self setWindowsMenu:submenu]; [self setWindowsMenu:submenu];
[self setApplicationIconImage:self.applicationIcon];
} }
} }
...@@ -631,6 +635,43 @@ int macdrv_err_on; ...@@ -631,6 +635,43 @@ int macdrv_err_on;
} }
} }
- (void) setApplicationIconFromCGImageArray:(NSArray*)images
{
NSImage* nsimage = nil;
if ([images count])
{
NSSize bestSize = NSZeroSize;
id image;
nsimage = [[[NSImage alloc] initWithSize:NSZeroSize] autorelease];
for (image in images)
{
CGImageRef cgimage = (CGImageRef)image;
NSBitmapImageRep* imageRep = [[NSBitmapImageRep alloc] initWithCGImage:cgimage];
if (imageRep)
{
NSSize size = [imageRep size];
[nsimage addRepresentation:imageRep];
[imageRep release];
if (MIN(size.width, size.height) > MIN(bestSize.width, bestSize.height))
bestSize = size;
}
}
if ([[nsimage representations] count] && bestSize.width && bestSize.height)
[nsimage setSize:bestSize];
else
nsimage = nil;
}
self.applicationIcon = nsimage;
[self setApplicationIconImage:nsimage];
}
/* /*
* ---------- Cursor clipping methods ---------- * ---------- Cursor clipping methods ----------
* *
...@@ -1422,3 +1463,20 @@ int macdrv_clip_cursor(CGRect rect) ...@@ -1422,3 +1463,20 @@ int macdrv_clip_cursor(CGRect rect)
return ret; return ret;
} }
/***********************************************************************
* macdrv_set_application_icon
*
* Set the application icon. The images array contains CGImages. If
* there are more than one, then they represent different sizes or
* color depths from the icon resource. If images is NULL or empty,
* restores the default application image.
*/
void macdrv_set_application_icon(CFArrayRef images)
{
NSArray* imageArray = (NSArray*)images;
OnMainThreadAsync(^{
[NSApp setApplicationIconFromCGImageArray:imageArray];
});
}
...@@ -25,6 +25,30 @@ ...@@ -25,6 +25,30 @@
WINE_DEFAULT_DEBUG_CHANNEL(image); WINE_DEFAULT_DEBUG_CHANNEL(image);
#include "pshpack1.h"
typedef struct
{
BYTE bWidth;
BYTE bHeight;
BYTE bColorCount;
BYTE bReserved;
WORD wPlanes;
WORD wBitCount;
DWORD dwBytesInRes;
WORD nID;
} GRPICONDIRENTRY;
typedef struct
{
WORD idReserved;
WORD idType;
WORD idCount;
GRPICONDIRENTRY idEntries[1];
} GRPICONDIR;
#include "poppack.h"
/*********************************************************************** /***********************************************************************
* create_cgimage_from_icon_bitmaps * create_cgimage_from_icon_bitmaps
...@@ -150,3 +174,253 @@ CGImageRef create_cgimage_from_icon_bitmaps(HDC hdc, HANDLE icon, HBITMAP hbmCol ...@@ -150,3 +174,253 @@ CGImageRef create_cgimage_from_icon_bitmaps(HDC hdc, HANDLE icon, HBITMAP hbmCol
return cgimage; return cgimage;
} }
/***********************************************************************
* create_cgimage_from_icon
*
* Create a CGImage from a Windows icon.
*/
static CGImageRef create_cgimage_from_icon(HANDLE icon, int width, int height)
{
CGImageRef ret = NULL;
HDC hdc;
char buffer[FIELD_OFFSET(BITMAPINFO, bmiColors[256])];
BITMAPINFO *bitmapinfo = (BITMAPINFO*)buffer;
unsigned char *color_bits, *mask_bits;
HBITMAP hbmColor = 0, hbmMask = 0;
int color_size, mask_size;
TRACE("icon %p width %d height %d\n", icon, width, height);
if (!width && !height)
{
ICONINFO info;
BITMAP bm;
if (!GetIconInfo(icon, &info))
return NULL;
GetObjectW(info.hbmMask, sizeof(bm), &bm);
if (!info.hbmColor) bm.bmHeight = max(1, bm.bmHeight / 2);
width = bm.bmWidth;
height = bm.bmHeight;
DeleteObject(info.hbmColor);
DeleteObject(info.hbmMask);
}
hdc = CreateCompatibleDC(0);
bitmapinfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bitmapinfo->bmiHeader.biWidth = width;
bitmapinfo->bmiHeader.biHeight = -height;
bitmapinfo->bmiHeader.biPlanes = 1;
bitmapinfo->bmiHeader.biCompression = BI_RGB;
bitmapinfo->bmiHeader.biXPelsPerMeter = 0;
bitmapinfo->bmiHeader.biYPelsPerMeter = 0;
bitmapinfo->bmiHeader.biClrUsed = 0;
bitmapinfo->bmiHeader.biClrImportant = 0;
bitmapinfo->bmiHeader.biBitCount = 32;
color_size = width * height * 4;
bitmapinfo->bmiHeader.biSizeImage = color_size;
hbmColor = CreateDIBSection(hdc, bitmapinfo, DIB_RGB_COLORS, (VOID **) &color_bits, NULL, 0);
if (!hbmColor)
{
WARN("failed to create DIB section for cursor color data\n");
goto cleanup;
}
bitmapinfo->bmiHeader.biBitCount = 1;
bitmapinfo->bmiColors[0].rgbRed = 0;
bitmapinfo->bmiColors[0].rgbGreen = 0;
bitmapinfo->bmiColors[0].rgbBlue = 0;
bitmapinfo->bmiColors[0].rgbReserved = 0;
bitmapinfo->bmiColors[1].rgbRed = 0xff;
bitmapinfo->bmiColors[1].rgbGreen = 0xff;
bitmapinfo->bmiColors[1].rgbBlue = 0xff;
bitmapinfo->bmiColors[1].rgbReserved = 0;
mask_size = ((width + 31) / 32 * 4) * height;
bitmapinfo->bmiHeader.biSizeImage = mask_size;
hbmMask = CreateDIBSection(hdc, bitmapinfo, DIB_RGB_COLORS, (VOID **) &mask_bits, NULL, 0);
if (!hbmMask)
{
WARN("failed to create DIB section for cursor mask data\n");
goto cleanup;
}
ret = create_cgimage_from_icon_bitmaps(hdc, icon, hbmColor, color_bits, color_size, hbmMask,
mask_bits, mask_size, width, height, 0);
cleanup:
if (hbmColor) DeleteObject(hbmColor);
if (hbmMask) DeleteObject(hbmMask);
DeleteDC(hdc);
return ret;
}
/***********************************************************************
* get_first_resource
*
* Helper for create_app_icon_images(). Enum proc for EnumResourceNamesW()
* which just gets the handle for the first resource and stops further
* enumeration.
*/
static BOOL CALLBACK get_first_resource(HMODULE module, LPCWSTR type, LPWSTR name, LONG_PTR lparam)
{
HRSRC *res_info = (HRSRC*)lparam;
*res_info = FindResourceW(module, name, (LPCWSTR)RT_GROUP_ICON);
return FALSE;
}
/***********************************************************************
* create_app_icon_images
*/
CFArrayRef create_app_icon_images(void)
{
HRSRC res_info;
HGLOBAL res_data;
GRPICONDIR *icon_dir;
CFMutableArrayRef images = NULL;
int i;
TRACE("()\n");
res_info = NULL;
EnumResourceNamesW(NULL, (LPCWSTR)RT_GROUP_ICON, get_first_resource, (LONG_PTR)&res_info);
if (!res_info)
{
WARN("found no RT_GROUP_ICON resource\n");
return NULL;
}
if (!(res_data = LoadResource(NULL, res_info)))
{
WARN("failed to load RT_GROUP_ICON resource\n");
return NULL;
}
if (!(icon_dir = LockResource(res_data)))
{
WARN("failed to lock RT_GROUP_ICON resource\n");
goto cleanup;
}
images = CFArrayCreateMutable(NULL, icon_dir->idCount, &kCFTypeArrayCallBacks);
if (!images)
{
WARN("failed to create images array\n");
goto cleanup;
}
for (i = 0; i < icon_dir->idCount; i++)
{
int width = icon_dir->idEntries[i].bWidth;
int height = icon_dir->idEntries[i].bHeight;
BOOL found_better_bpp = FALSE;
int j;
LPCWSTR name;
HGLOBAL icon_res_data;
BYTE *icon_bits;
if (!width) width = 256;
if (!height) height = 256;
/* If there's another icon at the same size but with better
color depth, skip this one. We end up making CGImages that
are all 32 bits per pixel, so Cocoa doesn't get the original
color depth info to pick the best representation itself. */
for (j = 0; j < icon_dir->idCount; j++)
{
int jwidth = icon_dir->idEntries[j].bWidth;
int jheight = icon_dir->idEntries[j].bHeight;
if (!jwidth) jwidth = 256;
if (!jheight) jheight = 256;
if (j != i && jwidth == width && jheight == height &&
icon_dir->idEntries[j].wBitCount > icon_dir->idEntries[i].wBitCount)
{
found_better_bpp = TRUE;
break;
}
}
if (found_better_bpp) continue;
name = MAKEINTRESOURCEW(icon_dir->idEntries[i].nID);
res_info = FindResourceW(NULL, name, (LPCWSTR)RT_ICON);
if (!res_info)
{
WARN("failed to find RT_ICON resource %d with ID %hd\n", i, icon_dir->idEntries[i].nID);
continue;
}
icon_res_data = LoadResource(NULL, res_info);
if (!icon_res_data)
{
WARN("failed to load icon %d with ID %hd\n", i, icon_dir->idEntries[i].nID);
continue;
}
icon_bits = LockResource(icon_res_data);
if (icon_bits)
{
static const BYTE png_magic[] = { 0x89, 0x50, 0x4e, 0x47 };
CGImageRef cgimage = NULL;
if (!memcmp(icon_bits, png_magic, sizeof(png_magic)))
{
CFDataRef data = CFDataCreate(NULL, (UInt8*)icon_bits, icon_dir->idEntries[i].dwBytesInRes);
if (data)
{
CGDataProviderRef provider = CGDataProviderCreateWithCFData(data);
CFRelease(data);
if (provider)
{
cgimage = CGImageCreateWithPNGDataProvider(provider, NULL, FALSE,
kCGRenderingIntentDefault);
CGDataProviderRelease(provider);
}
}
}
if (!cgimage)
{
HICON icon;
icon = CreateIconFromResourceEx(icon_bits, icon_dir->idEntries[i].dwBytesInRes,
TRUE, 0x00030000, width, height, 0);
if (icon)
{
cgimage = create_cgimage_from_icon(icon, width, height);
DestroyIcon(icon);
}
else
WARN("failed to create icon %d from resource with ID %hd\n", i, icon_dir->idEntries[i].nID);
}
if (cgimage)
{
CFArrayAppendValue(images, cgimage);
CGImageRelease(cgimage);
}
}
else
WARN("failed to lock RT_ICON resource %d with ID %hd\n", i, icon_dir->idEntries[i].nID);
FreeResource(icon_res_data);
}
cleanup:
if (images && !CFArrayGetCount(images))
{
CFRelease(images);
images = NULL;
}
FreeResource(res_data);
return images;
}
...@@ -177,5 +177,6 @@ extern CGImageRef create_cgimage_from_icon_bitmaps(HDC hdc, HANDLE icon, HBITMAP ...@@ -177,5 +177,6 @@ extern CGImageRef create_cgimage_from_icon_bitmaps(HDC hdc, HANDLE icon, HBITMAP
unsigned char *color_bits, int color_size, HBITMAP hbmMask, unsigned char *color_bits, int color_size, HBITMAP hbmMask,
unsigned char *mask_bits, int mask_size, int width, unsigned char *mask_bits, int mask_size, int width,
int height, int istep) DECLSPEC_HIDDEN; int height, int istep) DECLSPEC_HIDDEN;
extern CFArrayRef create_app_icon_images(void) DECLSPEC_HIDDEN;
#endif /* __WINE_MACDRV_H */ #endif /* __WINE_MACDRV_H */
...@@ -132,6 +132,7 @@ extern int macdrv_err_on; ...@@ -132,6 +132,7 @@ extern int macdrv_err_on;
extern int macdrv_start_cocoa_app(unsigned long long tickcount) DECLSPEC_HIDDEN; 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_window_rejected_focus(const struct macdrv_event *event) DECLSPEC_HIDDEN;
extern void macdrv_beep(void) DECLSPEC_HIDDEN; extern void macdrv_beep(void) DECLSPEC_HIDDEN;
extern void macdrv_set_application_icon(CFArrayRef images) DECLSPEC_HIDDEN;
/* cursor */ /* cursor */
......
...@@ -67,6 +67,20 @@ const char* debugstr_cf(CFTypeRef t) ...@@ -67,6 +67,20 @@ const char* debugstr_cf(CFTypeRef t)
/*********************************************************************** /***********************************************************************
* set_app_icon
*/
static void set_app_icon(void)
{
CFArrayRef images = create_app_icon_images();
if (images)
{
macdrv_set_application_icon(images);
CFRelease(images);
}
}
/***********************************************************************
* process_attach * process_attach
*/ */
static BOOL process_attach(void) static BOOL process_attach(void)
...@@ -89,6 +103,7 @@ static BOOL process_attach(void) ...@@ -89,6 +103,7 @@ static BOOL process_attach(void)
return FALSE; return FALSE;
} }
set_app_icon();
macdrv_clipboard_process_attach(); macdrv_clipboard_process_attach();
return TRUE; return TRUE;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment