winemac: Set application Dock icon from first icon resource in process's .exe file.
This commit is contained in:
parent
462721a115
commit
b1de532393
dlls/winemac.drv
|
@ -75,6 +75,8 @@ @interface WineApplication : NSApplication <NSApplicationDelegate>
|
|||
CGPoint synthesizedLocation;
|
||||
NSTimeInterval lastSetCursorPositionTime;
|
||||
NSTimeInterval lastEventTapEventTime;
|
||||
|
||||
NSImage* applicationIcon;
|
||||
}
|
||||
|
||||
@property (nonatomic) CGEventSourceKeyboardType keyboardType;
|
||||
|
|
|
@ -58,6 +58,7 @@ @interface WineApplication ()
|
|||
@property (readwrite, copy, nonatomic) NSEvent* lastFlagsChanged;
|
||||
@property (copy, nonatomic) NSArray* cursorFrames;
|
||||
@property (retain, nonatomic) NSTimer* cursorTimer;
|
||||
@property (retain, nonatomic) NSImage* applicationIcon;
|
||||
|
||||
static void PerformRequest(void *info);
|
||||
|
||||
|
@ -67,7 +68,7 @@ @interface WineApplication ()
|
|||
@implementation WineApplication
|
||||
|
||||
@synthesize keyboardType, lastFlagsChanged;
|
||||
@synthesize orderedWineWindows;
|
||||
@synthesize orderedWineWindows, applicationIcon;
|
||||
@synthesize cursorFrames, cursorTimer;
|
||||
|
||||
- (id) init
|
||||
|
@ -111,6 +112,7 @@ - (id) init
|
|||
|
||||
- (void) dealloc
|
||||
{
|
||||
[applicationIcon release];
|
||||
[warpRecords release];
|
||||
[cursorTimer release];
|
||||
[cursorFrames release];
|
||||
|
@ -169,6 +171,8 @@ - (void) transformProcessToForeground
|
|||
|
||||
[self setMainMenu:mainMenu];
|
||||
[self setWindowsMenu:submenu];
|
||||
|
||||
[self setApplicationIconImage:self.applicationIcon];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -631,6 +635,43 @@ - (void) setCursorWithFrames:(NSArray*)frames
|
|||
}
|
||||
}
|
||||
|
||||
- (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 ----------
|
||||
*
|
||||
|
@ -1422,3 +1463,20 @@ int macdrv_clip_cursor(CGRect rect)
|
|||
|
||||
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 @@
|
|||
|
||||
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
|
||||
|
@ -150,3 +174,253 @@ CGImageRef create_cgimage_from_icon_bitmaps(HDC hdc, HANDLE icon, HBITMAP hbmCol
|
|||
|
||||
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
|
|||
unsigned char *color_bits, int color_size, HBITMAP hbmMask,
|
||||
unsigned char *mask_bits, int mask_size, int width,
|
||||
int height, int istep) DECLSPEC_HIDDEN;
|
||||
extern CFArrayRef create_app_icon_images(void) DECLSPEC_HIDDEN;
|
||||
|
||||
#endif /* __WINE_MACDRV_H */
|
||||
|
|
|
@ -132,6 +132,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) DECLSPEC_HIDDEN;
|
||||
|
||||
|
||||
/* cursor */
|
||||
|
|
|
@ -66,6 +66,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
|
||||
*/
|
||||
|
@ -89,6 +103,7 @@ static BOOL process_attach(void)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
set_app_icon();
|
||||
macdrv_clipboard_process_attach();
|
||||
|
||||
return TRUE;
|
||||
|
|
Loading…
Reference in New Issue