Hi, to see how easy (or not) it would be to make the controls use themes, I tried to get themed buttons; the result is the attached patch (to try it out, you need an .msstyles file and appropriate registry setup). It's probably not perfect as it is, comments/questions are welcome.
Screenshot: http://img87.exs.cx/my.php?loc=img87&image=winewiththemedbuttons3xh.png
Some funny side effect when theming is enabled: applications show up in standard colors, but as soon as the first button is created, the colors switch to the theme's colors. I guess opening the theme data in the button code triggers some uxtheme initialization that in turn changes the system colors.
Also, all applications get themed buttons, which diverges from WinXPs behaviour and may or may not be desired for some apps.
-f.r.
Index: dlls/user/Makefile.in =================================================================== RCS file: /home/wine/wine/dlls/user/Makefile.in,v retrieving revision 1.88 diff -u -r1.88 Makefile.in --- dlls/user/Makefile.in 10 Mar 2005 15:47:53 -0000 1.88 +++ dlls/user/Makefile.in 21 Mar 2005 18:46:31 -0000 @@ -4,7 +4,7 @@ SRCDIR = @srcdir@ VPATH = @srcdir@ MODULE = user32.dll -IMPORTS = gdi32 advapi32 kernel32 ntdll +IMPORTS = gdi32 advapi32 kernel32 uxtheme ntdll EXTRALIBS = $(LIBUNICODE)
SPEC_SRCS16 = \ Index: dlls/user/button.c =================================================================== RCS file: /home/wine/wine/dlls/user/button.c,v retrieving revision 1.6 diff -u -r1.6 button.c --- dlls/user/button.c 23 Dec 2004 17:21:05 -0000 1.6 +++ dlls/user/button.c 21 Mar 2005 18:46:32 -0000 @@ -71,6 +71,9 @@ #include "windef.h" #include "winbase.h" #include "wingdi.h" +#include "winuser.h" /* Indirectly required by uxtheme.h */ +#include "uxtheme.h" +#include "tmschema.h" #include "wine/winuser16.h" #include "controls.h" #include "user_private.h" @@ -79,7 +82,8 @@ #define STATE_GWL_OFFSET 0 #define HFONT_GWL_OFFSET (sizeof(LONG)) #define HIMAGE_GWL_OFFSET (HFONT_GWL_OFFSET+sizeof(HFONT)) -#define NB_EXTRA_BYTES (HIMAGE_GWL_OFFSET+sizeof(HANDLE)) +#define HTHEME_GWL_OFFSET (HIMAGE_GWL_OFFSET+sizeof(HANDLE)) +#define NB_EXTRA_BYTES (HTHEME_GWL_OFFSET+sizeof(HTHEME))
/* Button state values */ #define BUTTON_UNCHECKED 0x00 @@ -95,6 +99,7 @@
static UINT BUTTON_CalcLabelRect( HWND hwnd, HDC hdc, RECT *rc ); static void PB_Paint( HWND hwnd, HDC hDC, UINT action ); +static void PB_PaintThemed( HWND hwnd, HDC hDC, UINT action ); static void CB_Paint( HWND hwnd, HDC hDC, UINT action ); static void GB_Paint( HWND hwnd, HDC hDC, UINT action ); static void UB_Paint( HWND hwnd, HDC hDC, UINT action ); @@ -123,7 +128,7 @@
typedef void (*pfPaint)( HWND hwnd, HDC hdc, UINT action );
-static const pfPaint btnPaintFunc[MAX_BTN_TYPE] = +static const pfPaint btnUnthemedPaintFunc[MAX_BTN_TYPE] = { PB_Paint, /* BS_PUSHBUTTON */ PB_Paint, /* BS_DEFPUSHBUTTON */ @@ -139,6 +144,22 @@ OB_Paint /* BS_OWNERDRAW */ };
+static const pfPaint btnThemedPaintFunc[MAX_BTN_TYPE] = +{ + PB_PaintThemed, /* BS_PUSHBUTTON */ + PB_PaintThemed, /* BS_DEFPUSHBUTTON */ + CB_Paint, /* BS_CHECKBOX */ + CB_Paint, /* BS_AUTOCHECKBOX */ + CB_Paint, /* BS_RADIOBUTTON */ + CB_Paint, /* BS_3STATE */ + CB_Paint, /* BS_AUTO3STATE */ + GB_Paint, /* BS_GROUPBOX */ + UB_Paint, /* BS_USERBUTTON */ + CB_Paint, /* BS_AUTORADIOBUTTON */ + NULL, /* Not defined */ + OB_Paint /* BS_OWNERDRAW */ +}; + static HBITMAP hbitmapCheckBoxes = 0; static WORD checkBoxWidth = 0, checkBoxHeight = 0;
@@ -183,9 +204,26 @@ return (window_style & 0x0f); }
+inline static HTHEME get_button_theme( HWND hwnd ) +{ + return (HTHEME)GetWindowLongPtrW( hwnd, HTHEME_GWL_OFFSET ); +} + +inline static void set_button_theme( HWND hwnd, HTHEME theme ) +{ + SetWindowLongPtrW( hwnd, HTHEME_GWL_OFFSET, (ULONG_PTR)theme ); +} + +inline static const pfPaint* get_paint_funcs ( HWND hwnd ) +{ + HTHEME theme = get_button_theme( hwnd ); + return ( theme != NULL ) ? btnThemedPaintFunc : btnUnthemedPaintFunc; +} + /* paint a button of any type */ inline static void paint_button( HWND hwnd, LONG style, UINT action ) { + const pfPaint* btnPaintFunc = get_paint_funcs( hwnd ); if (btnPaintFunc[style] && IsWindowVisible(hwnd)) { HDC hdc = GetDC( hwnd ); @@ -215,6 +253,9 @@ UINT btn_type = get_button_type( style ); LONG state; HANDLE oldHbitmap; + static const WCHAR themeClass[] = { 'B','u','t','t','o','n',0 }; + HTHEME theme; + const pfPaint* btnPaintFunc = get_paint_funcs( hWnd );
pt.x = LOWORD(lParam); pt.y = HIWORD(lParam); @@ -249,8 +290,24 @@ if (btn_type >= MAX_BTN_TYPE) return -1; /* abort */ set_button_state( hWnd, BUTTON_UNCHECKED ); + theme = OpenThemeData( hWnd, themeClass ); + set_button_theme( hWnd, theme ); return 0; + + case WM_DESTROY: + theme = get_button_theme( hWnd ); + if ( theme != NULL ) + CloseThemeData ( theme ); + break;
+ case WM_THEMECHANGED: + theme = get_button_theme( hWnd ); + if ( theme != NULL ) + CloseThemeData ( theme ); + theme = OpenThemeData( hWnd, themeClass ); + set_button_theme( hWnd, theme ); + break; + case WM_ERASEBKGND: if (btn_type == BS_OWNERDRAW) { @@ -842,6 +899,39 @@ SetBkMode(hDC, oldBkMode); }
+static void PB_PaintThemed( HWND hwnd, HDC hDC, UINT action ) +{ + LONG state = get_button_state( hwnd ); + LONG style = GetWindowLongW( hwnd, GWL_STYLE ); + BOOL pushedState = (state & BUTTON_HIGHLIGHTED); + HTHEME theme = get_button_theme( hwnd ); + int partID = BP_PUSHBUTTON; + int stateID; + RECT rc; + WCHAR *text = NULL; + BOOL disabledState = !IsWindowEnabled( hwnd ); + + GetClientRect( hwnd, &rc ); + if (disabledState) + stateID = PBS_DISABLED; + else if (pushedState) + stateID = PBS_PRESSED; + else if (( get_button_type(style) == BS_DEFPUSHBUTTON ) + || ( state & BUTTON_HASFOCUS )) + stateID = PBS_DEFAULTED; + else + stateID = PBS_NORMAL; + + DrawThemeBackground( theme, hDC, partID, stateID, &rc, NULL); + + if (( text = get_button_text( hwnd ) ) != NULL ) + { + if ((style & (BS_ICON|BS_BITMAP)) == BS_TEXT) + DrawThemeText( theme, hDC, partID, stateID, text, -1, + BUTTON_BStoDT(style), 0, &rc ); + } +} + /********************************************************************** * Check Box & Radio Button Functions */