Static control [10/10]: Support the Windows XP mode of the static
control
Michael Kaufmann
hallo at michael-kaufmann.ch
Wed Jan 11 16:45:48 CST 2006
Changelog:
- Detect if the image of the current process has a manifest. If yes,
enable some Windows XP-specific features (as described in MSDN)
- Destruction of the control window: Destroy bitmaps loaded at control
creation time (removed a resource leak)
- Always stretch bitmaps and icons to the whole client area
- Windows XP mode: Different bitmap background, different icon
background.
- Add some notes
-------------- next part --------------
--- static-old.c 2006-01-11 22:57:48.000000000 +0100
+++ static.c 2006-01-11 22:58:43.000000000 +0100
@@ -25,14 +25,22 @@
* Unless otherwise noted, we believe this code to be complete, as per
* the specification mentioned above.
* If you discover missing features, or bugs, please note them below.
- *
- * TODO:
*
- * Styles
- * - SS_RIGHTJUST
+ * Notes:
+ * - Windows XP introduced new behavior: The background of centered
+ * icons and bitmaps is painted differently. This is only done if
+ * a manifest is present.
+ * - The application is responsible to delete the old icon/bitmap/metafile
+ * when it sends STM_SETICON or STM_SETIMAGE. The static control deletes
+ * only bitmaps which were loaded at control creation time.
+ * - Controls with SS_SIMPLE but without SS_NOPREFIX:
+ * The text should not be changed. Windows doesn't clear the
+ * client rectangle, so the new text must be larger than the old one.
+ * - The SS_RIGHTJUST style is currently not implemented by Windows
+ * (or it does something different than documented).
*
- * Messages
- * - STM_SETIMAGE: IMAGE_CURSOR
+ * TODO:
+ * - Animated cursors
*/
#include <stdarg.h>
@@ -62,7 +70,11 @@
/* offsets for GetWindowLong for static private information */
#define HFONT_GWL_OFFSET 0
#define HICON_GWL_OFFSET (sizeof(HFONT))
-#define STATIC_EXTRA_BYTES (HICON_GWL_OFFSET + sizeof(HICON))
+#define FLAGS_GWL_OFFSET (HICON_GWL_OFFSET + sizeof(HICON))
+#define STATIC_EXTRA_BYTES (FLAGS_GWL_OFFSET + sizeof(LONG_PTR))
+
+#define FLAG_MANIFEST 0x01
+#define FLAG_BITMAP_OWNER 0x02
typedef void (*pfPaint)( HWND hwnd, HDC hdc, DWORD style );
@@ -357,6 +369,23 @@
}
/***********************************************************************
+ * hasManifest
+ *
+ * Tests if the image associated with the current process contains
+ * a manifest.
+ */
+static BOOL hasManifest( void )
+{
+ /* Usually the resource ID is 1.
+ There are some more IDs for special purposes
+ (look for "Using Windows XP Visual Styles" on MSDN) */
+ /* FIXME: Support manifests in external files and parse the manfiest */
+ return (FindResourceW(NULL, MAKEINTRESOURCEW(1),
+ MAKEINTRESOURCEW(RT_MANIFEST)) != NULL);
+}
+
+
+/***********************************************************************
* StaticWndProc_common
*/
static LRESULT StaticWndProc_common( HWND hwnd, UINT uMsg, WPARAM wParam,
@@ -378,19 +407,27 @@
break;
case WM_NCDESTROY:
- if (style == SS_ICON) {
-/*
- * FIXME
- * DestroyIcon32( STATIC_SetIcon( wndPtr, 0 ) );
- *
- * We don't want to do this yet because DestroyIcon32 is broken. If the icon
- * had already been loaded by the application the last thing we want to do is
- * GlobalFree16 the handle.
- */
- break;
+ /* SS_ICON:
+ The initially loaded icons are shared. If the application sets
+ an own icon, it must destroy the icon itself.
+
+ SS_ENHMETAFILE:
+ The static control doesn't own the handle, because it was always
+ set by STM_SETIMAGE. The application has to free it.
+
+ SS_BITMAP:
+ The bitmap must be destroyed if the application has not changed
+ it with STM_SETIMAGE.
+ */
+ if ((style == SS_BITMAP) &&
+ (GetWindowLongPtrW( hwnd, FLAGS_GWL_OFFSET ) &
+ FLAG_BITMAP_OWNER) != 0)
+ {
+ HBITMAP bitmap = STATIC_SetBitmap(hwnd, NULL, full_style);
+ if (bitmap) DeleteObject(bitmap);
}
- else return unicode ? DefWindowProcW(hwnd, uMsg, wParam, lParam) :
- DefWindowProcA(hwnd, uMsg, wParam, lParam);
+ return unicode ? DefWindowProcW(hwnd, uMsg, wParam, lParam) :
+ DefWindowProcA(hwnd, uMsg, wParam, lParam);
case WM_PRINTCLIENT:
case WM_PAINT:
@@ -426,11 +463,17 @@
{
LPCSTR textA;
LPCWSTR textW;
+ LONG_PTR flags;
if (full_style & SS_SUNKEN)
SetWindowLongW( hwnd, GWL_EXSTYLE,
GetWindowLongW( hwnd, GWL_EXSTYLE ) | WS_EX_STATICEDGE );
+ /* Initialize the flags */
+ flags = FLAG_BITMAP_OWNER;
+ if (hasManifest()) flags |= FLAG_MANIFEST;
+ SetWindowLongPtrW( hwnd, FLAGS_GWL_OFFSET, flags );
+
if(unicode)
{
textA = NULL;
@@ -529,14 +572,17 @@
case STM_SETIMAGE:
switch(wParam) {
case IMAGE_BITMAP:
+ {
+ LONG_PTR flags = GetWindowLongPtrW( hwnd, FLAGS_GWL_OFFSET );
+ flags &= ~FLAG_BITMAP_OWNER;
+ SetWindowLongPtrW( hwnd, FLAGS_GWL_OFFSET, flags );
lResult = (LRESULT)STATIC_SetBitmap( hwnd, (HBITMAP)lParam, full_style );
break;
- case IMAGE_CURSOR:
- FIXME("STM_SETIMAGE: Unhandled type IMAGE_CURSOR\n");
- break;
+ }
case IMAGE_ENHMETAFILE:
lResult = (LRESULT)STATIC_SetEnhMetaFile( hwnd, (HENHMETAFILE)lParam, full_style );
break;
+ case IMAGE_CURSOR:
case IMAGE_ICON:
lResult = (LRESULT)STATIC_SetIcon( hwnd, (HICON)lParam, full_style );
break;
@@ -595,7 +641,7 @@
GetClientRect( hwnd, &dis.rcItem );
font = (HFONT)GetWindowLongPtrW( hwnd, HFONT_GWL_OFFSET );
- if (font) oldFont = SelectObject( hdc, font );
+ if (font) oldFont = (HFONT)SelectObject( hdc, font );
SendMessageW( GetParent(hwnd), WM_CTLCOLORSTATIC, (WPARAM)hdc, (LPARAM)hwnd );
SendMessageW( GetParent(hwnd), WM_DRAWITEM, id, (LPARAM)&dis );
if (font) SelectObject( hdc, oldFont );
@@ -733,66 +779,124 @@
static void STATIC_PaintIconfn( HWND hwnd, HDC hdc, DWORD style )
{
- RECT rc;
+ RECT rc, iconRect;
HBRUSH hbrush;
HICON hIcon;
- INT x, y;
+ CURSORICONINFO * info;
GetClientRect( hwnd, &rc );
- hbrush = (HBRUSH)SendMessageW( GetParent(hwnd), WM_CTLCOLORSTATIC,
- (WPARAM)hdc, (LPARAM)hwnd );
- FillRect( hdc, &rc, hbrush );
+ hbrush = STATIC_SendWmCtlColorStatic(hwnd, hdc);
hIcon = (HICON)GetWindowLongPtrW( hwnd, HICON_GWL_OFFSET );
- if (style & SS_CENTERIMAGE)
+ info = hIcon ? (CURSORICONINFO *)GlobalLock16(HICON_16(hIcon)) : NULL;
+ if (!hIcon || !info)
{
- CURSORICONINFO *info = hIcon ? (CURSORICONINFO *)GlobalLock16(HICON_16(hIcon)) : NULL;
- x = (rc.right - rc.left)/2 - (info ? info->nWidth/2 : 0);
- y = (rc.bottom - rc.top)/2 - (info ? info->nHeight/2 : 0);
+ FillRect(hdc, &rc, hbrush);
}
else
{
- x = rc.left;
- y = rc.top;
+ if (style & SS_CENTERIMAGE)
+ {
+ BOOL hasManifest = (GetWindowLongPtrW( hwnd, FLAGS_GWL_OFFSET ) &
+ FLAG_MANIFEST) != 0;
+ iconRect.left = (rc.right - rc.left) / 2 - info->nWidth / 2;
+ iconRect.top = (rc.bottom - rc.top) / 2 - info->nHeight / 2;
+ iconRect.right = iconRect.left + info->nWidth;
+ iconRect.bottom = iconRect.top + info->nHeight;
+ if (hasManifest)
+ FillRect( hdc, &rc, hbrush );
+ else
+ FillRect( hdc, &iconRect, hbrush );
+ DrawIcon( hdc, iconRect.left, iconRect.top, hIcon );
+ }
+ else
+ {
+ FillRect( hdc, &rc, hbrush );
+ DrawIconEx( hdc, rc.left, rc.top, hIcon, rc.right - rc.left,
+ rc.bottom - rc.top, 0, NULL, DI_NORMAL );
+ }
}
- if (hIcon)
- DrawIcon( hdc, x, y, hIcon );
+ if (info) GlobalUnlock16(HICON_16(hIcon));
}
static void STATIC_PaintBitmapfn(HWND hwnd, HDC hdc, DWORD style )
{
HDC hMemDC;
HBITMAP hBitmap, oldbitmap;
+ HBRUSH hbrush;
+ BOOL hasManifest = (GetWindowLongPtrW( hwnd, FLAGS_GWL_OFFSET ) &
+ FLAG_MANIFEST) != 0;
/* message is still sent, even if the returned brush is not used */
- SendMessageW( GetParent(hwnd), WM_CTLCOLORSTATIC,
- (WPARAM)hdc, (LPARAM)hwnd );
+ hbrush = STATIC_SendWmCtlColorStatic(hwnd, hdc);
- if ((hBitmap = (HBITMAP)GetWindowLongPtrW( hwnd, HICON_GWL_OFFSET )))
+ if ((hBitmap = (HBITMAP)GetWindowLongPtrW( hwnd, HICON_GWL_OFFSET ))
+ && (GetObjectType(hBitmap) == OBJ_BITMAP)
+ && (hMemDC = CreateCompatibleDC( hdc )))
{
- INT x, y;
BITMAP bm;
-
- if(GetObjectType(hBitmap) != OBJ_BITMAP) return;
- if (!(hMemDC = CreateCompatibleDC( hdc ))) return;
+ RECT rcClient;
+
GetObjectW(hBitmap, sizeof(bm), &bm);
oldbitmap = SelectObject(hMemDC, hBitmap);
+
+ if (hasManifest)
+ {
+ /* Set the background color for monochrome bitmaps
+ to the color of the background brush */
+ LOGBRUSH brush;
+ if (GetObjectW( hbrush, sizeof(brush), &brush ))
+ {
+ if (brush.lbStyle == BS_SOLID)
+ SetBkColor(hdc, brush.lbColor);
+ }
+ }
+ GetClientRect(hwnd, &rcClient);
if (style & SS_CENTERIMAGE)
{
- RECT rcClient;
- GetClientRect(hwnd, &rcClient);
+ INT x, y;
x = (rcClient.right - rcClient.left)/2 - bm.bmWidth/2;
y = (rcClient.bottom - rcClient.top)/2 - bm.bmHeight/2;
+ if (hasManifest)
+ {
+ FillRect( hdc, &rcClient, hbrush );
+ }
+ else
+ {
+ /* Use the color of the top-left pixel to fill the
+ client area */
+ HBRUSH fillBrush;
+ COLORREF topLeftColor = GetPixel(hMemDC, 0, 0);
+ if (topLeftColor != CLR_INVALID)
+ {
+ fillBrush = CreateSolidBrush(topLeftColor);
+ if (fillBrush)
+ {
+ FillRect( hdc, &rcClient, fillBrush );
+ DeleteObject(fillBrush);
+ }
+ }
+ }
+ BitBlt(hdc, x, y, bm.bmWidth, bm.bmHeight, hMemDC, 0, 0,
+ SRCCOPY);
}
else
{
- x = 0;
- y = 0;
+ StretchBlt(hdc, 0, 0, rcClient.right - rcClient.left,
+ rcClient.bottom - rcClient.top, hMemDC,
+ 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);
}
- BitBlt(hdc, x, y, bm.bmWidth, bm.bmHeight, hMemDC, 0, 0,
- SRCCOPY);
SelectObject(hMemDC, oldbitmap);
DeleteDC(hMemDC);
}
+ else
+ {
+ if (hasManifest)
+ {
+ RECT rcClient;
+ GetClientRect( hwnd, &rcClient );
+ FillRect( hdc, &rcClient, hbrush );
+ }
+ }
}
More information about the wine-patches
mailing list