diff options
author | treectrl <treectrl> | 2005-05-01 01:45:18 (GMT) |
---|---|---|
committer | treectrl <treectrl> | 2005-05-01 01:45:18 (GMT) |
commit | 89740421a006f4f0fb4768647dfa72fea1307b44 (patch) | |
tree | fab882964621a3123e7cd9b640823e74f35f43ad /generic/tkTreeTheme.c | |
parent | 5c6503a2729b9497a4dbc1b22be8ae82cfe26e19 (diff) | |
download | tktreectrl-89740421a006f4f0fb4768647dfa72fea1307b44.zip tktreectrl-89740421a006f4f0fb4768647dfa72fea1307b44.tar.gz tktreectrl-89740421a006f4f0fb4768647dfa72fea1307b44.tar.bz2 |
Initial import of Theme API file.
Diffstat (limited to 'generic/tkTreeTheme.c')
-rw-r--r-- | generic/tkTreeTheme.c | 657 |
1 files changed, 657 insertions, 0 deletions
diff --git a/generic/tkTreeTheme.c b/generic/tkTreeTheme.c new file mode 100644 index 0000000..7c1028d --- /dev/null +++ b/generic/tkTreeTheme.c @@ -0,0 +1,657 @@ +/* + * tkTreeTheme.c -- + * + * This module implements platform-specific visual themes. + * + * Copyright (c) 2005 Tim Baker + * + * RCS: @(#) $Id: tkTreeTheme.c,v 1.1 2005/05/01 01:45:18 treectrl Exp $ + */ + +#ifdef WIN32 + +#define WINVER 0x0501 /* Cygwin */ +#include "tkTreeCtrl.h" +#include "tkWinInt.h" + +#include <uxtheme.h> +#include <tmschema.h> + +#include <basetyps.h> /* Cygwin */ +#ifndef TMT_CONTENTMARGINS +#define TMT_CONTENTMARGINS 3602 +#endif + +typedef HTHEME (STDAPICALLTYPE OpenThemeDataProc)(HWND hwnd, + LPCWSTR pszClassList); +typedef HRESULT (STDAPICALLTYPE CloseThemeDataProc)(HTHEME hTheme); +typedef HRESULT (STDAPICALLTYPE DrawThemeBackgroundProc)(HTHEME hTheme, + HDC hdc, int iPartId, int iStateId, const RECT *pRect, + OPTIONAL const RECT *pClipRect); +typedef HRESULT (STDAPICALLTYPE DrawThemeBackgroundExProc)(HTHEME hTheme, + HDC hdc, int iPartId, int iStateId, const RECT *pRect, + DTBGOPTS *PDTBGOPTS); +typedef HRESULT (STDAPICALLTYPE DrawThemeParentBackgroundProc)(HWND hwnd, + HDC hdc, OPTIONAL const RECT *prc); +typedef HRESULT (STDAPICALLTYPE DrawThemeEdgeProc)(HTHEME hTheme, HDC hdc, + int iPartId, int iStateId, const RECT *pDestRect, + UINT uEdge, UINT uFlags, RECT *pContentRect); +typedef HRESULT (STDAPICALLTYPE DrawThemeTextProc)(HTHEME hTheme, HDC hdc, + int iPartId, int iStateId, LPCWSTR pszText, int iCharCount, + DWORD dwTextFlags, DWORD dwTextFlags2, const RECT *pRect); +typedef HRESULT (STDAPICALLTYPE GetThemeBackgroundContentRectProc)( + HTHEME hTheme, HDC hdc, int iPartId, int iStateId, + const RECT *pBoundingRect, RECT *pContentRect); +typedef HRESULT (STDAPICALLTYPE GetThemeBackgroundExtentProc)(HTHEME hTheme, + HDC hdc, int iPartId, int iStateId, const RECT *pContentRect, + RECT *pExtentRect); +typedef HRESULT (STDAPICALLTYPE GetThemeMarginsProc)(HTHEME, HDC, + int iPartId, int iStateId, int iPropId, OPTIONAL RECT *prc, + MARGINS *pMargins); +typedef HRESULT (STDAPICALLTYPE GetThemePartSizeProc)(HTHEME, HDC, int iPartId, + int iStateId, RECT *prc, enum THEMESIZE eSize, SIZE *psz); +typedef HRESULT (STDAPICALLTYPE GetThemeTextExtentProc)(HTHEME hTheme, HDC hdc, + int iPartId, int iStateId, LPCWSTR pszText, int iCharCount, + DWORD dwTextFlags, const RECT *pBoundingRect, RECT *pExtentRect); +typedef BOOL (STDAPICALLTYPE IsThemeActiveProc)(VOID); +typedef BOOL (STDAPICALLTYPE IsThemePartDefinedProc)(HTHEME, int, int); +typedef HRESULT (STDAPICALLTYPE IsThemeBackgroundPartiallyTransparentProc)( + HTHEME, int, int); + +typedef struct +{ + OpenThemeDataProc *OpenThemeData; + CloseThemeDataProc *CloseThemeData; + DrawThemeBackgroundProc *DrawThemeBackground; + DrawThemeBackgroundExProc *DrawThemeBackgroundEx; + DrawThemeParentBackgroundProc *DrawThemeParentBackground; + DrawThemeEdgeProc *DrawThemeEdge; + DrawThemeTextProc *DrawThemeText; + GetThemeBackgroundContentRectProc *GetThemeBackgroundContentRect; + GetThemeBackgroundExtentProc *GetThemeBackgroundExtent; + GetThemeMarginsProc *GetThemeMargins; + GetThemePartSizeProc *GetThemePartSize; + GetThemeTextExtentProc *GetThemeTextExtent; + IsThemeActiveProc *IsThemeActive; + IsThemePartDefinedProc *IsThemePartDefined; + IsThemeBackgroundPartiallyTransparentProc *IsThemeBackgroundPartiallyTransparent; +} XPThemeProcs; + +typedef struct +{ + HINSTANCE hlibrary; + XPThemeProcs *procs; + int registered; + int themeEnabled; +} XPThemeData; + +static XPThemeProcs *procs = NULL; +static XPThemeData *themeData = NULL; +TCL_DECLARE_MUTEX(themeMutex) + +/* + *---------------------------------------------------------------------- + * + * LoadXPThemeProcs -- + * Initialize XP theming support. + * + * XP theme support is included in UXTHEME.DLL + * We dynamically load this DLL at runtime instead of linking + * to it at build-time. + * + * Returns: + * A pointer to an XPThemeProcs table if successful, NULL otherwise. + */ + +static XPThemeProcs * +LoadXPThemeProcs(HINSTANCE *phlib) +{ + OSVERSIONINFO os; + + /* + * We have to check whether we are running at least on Windows XP. + * In order to determine this we call GetVersionEx directly, although + * it would be a good idea to wrap it inside a function similar to + * TkWinGetPlatformId... + */ + ZeroMemory(&os, sizeof(os)); + os.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&os); + if (os.dwMajorVersion >= 5 && os.dwMinorVersion >= 1) { + /* + * We are running under Windows XP or a newer version. + * Load the library "uxtheme.dll", where the native widget + * drawing routines are implemented. + */ + HINSTANCE handle; + *phlib = handle = LoadLibrary("uxtheme.dll"); + if (handle != 0) + { + /* + * We have successfully loaded the library. Proceed in storing the + * addresses of the functions we want to use. + */ + XPThemeProcs *procs = (XPThemeProcs*)ckalloc(sizeof(XPThemeProcs)); +#define LOADPROC(name) \ + (0 != (procs->name = (name ## Proc *)GetProcAddress(handle, #name) )) + + if ( LOADPROC(OpenThemeData) + && LOADPROC(CloseThemeData) + && LOADPROC(DrawThemeBackground) + && LOADPROC(DrawThemeBackgroundEx) + && LOADPROC(DrawThemeParentBackground) + && LOADPROC(DrawThemeEdge) + && LOADPROC(DrawThemeText) + && LOADPROC(GetThemeBackgroundContentRect) + && LOADPROC(GetThemeBackgroundExtent) + && LOADPROC(GetThemeMargins) + && LOADPROC(GetThemePartSize) + && LOADPROC(GetThemeTextExtent) + && LOADPROC(IsThemeActive) + && LOADPROC(IsThemePartDefined) + && LOADPROC(IsThemeBackgroundPartiallyTransparent) + ) + { + return procs; + } +#undef LOADPROC + ckfree((char*)procs); + } + } + return 0; +} + +int TreeTheme_DrawHeaderItem(TreeCtrl *tree, Drawable drawable, int state, + int x, int y, int width, int height) +{ + Window win = Tk_WindowId(tree->tkwin); + HWND hwnd = Tk_GetHWND(win); + HTHEME hTheme; + HDC hDC; + TkWinDCState dcState; + RECT rc; + HRESULT hr; + + int iPartId = HP_HEADERITEM; + int iStateId = HIS_NORMAL; + + switch (state) + { + case 1 : iStateId = HIS_HOT; break; + case 2 : iStateId = HIS_PRESSED; break; + } + + if (!themeData->themeEnabled || !procs) + return TCL_ERROR; + + hTheme = procs->OpenThemeData(hwnd, L"HEADER"); + if (!hTheme) + return TCL_ERROR; + +#if 0 /* Always returns FALSE */ + if (!procs->IsThemePartDefined( + hTheme, + iPartId, + iStateId)) + { + procs->CloseThemeData(hTheme); + return TCL_ERROR; + } +#endif + + rc.left = x; + rc.top = y; + rc.right = x + width; + rc.bottom = y + height; + + /* Is transparent for the default XP style. */ + if (procs->IsThemeBackgroundPartiallyTransparent( + hTheme, + iPartId, + iStateId)) + { +#if 1 + /* What color should I use? */ + Tk_Fill3DRectangle(tree->tkwin, drawable, tree->border, x, y, width, height, 0, TK_RELIEF_FLAT); +#else + /* This draws nothing, maybe because the parent window is not + * themed */ + procs->DrawThemeParentBackground( + hwnd, + hDC, + &rc); +#endif + } + + hDC = TkWinGetDrawableDC(tree->display, drawable, &dcState); + +#if 0 + { + /* Default XP theme gives rect 3 pixels narrower than rc */ + RECT contentRect, extentRect; + hr = procs->GetThemeBackgroundContentRect( + hTheme, + hDC, + iPartId, + iStateId, + &rc, + &contentRect + ); + dbwin("GetThemeBackgroundContentRect width=%d height=%d\n", + contentRect.right - contentRect.left, + contentRect.bottom - contentRect.top); + + /* Gives rc */ + hr = procs->GetThemeBackgroundExtent( + hTheme, + hDC, + iPartId, + iStateId, + &contentRect, + &extentRect + ); + dbwin("GetThemeBackgroundExtent width=%d height=%d\n", + extentRect.right - extentRect.left, + extentRect.bottom - extentRect.top); + } +#endif + + hr = procs->DrawThemeBackground( + hTheme, + hDC, + iPartId, + iStateId, + &rc, + NULL); + + procs->CloseThemeData(hTheme); + TkWinReleaseDrawableDC(drawable, hDC, &dcState); + + if (hr != S_OK) + return TCL_ERROR; + + return TCL_OK; +} + +int TreeTheme_GetHeaderContentMargins(TreeCtrl *tree, int state, int bounds[4]) +{ + Window win = Tk_WindowId(tree->tkwin); + HWND hwnd = Tk_GetHWND(win); + HTHEME hTheme; + HDC hDC; + TkWinDCState dcState; + HRESULT hr; + MARGINS margins; + + int iPartId = HP_HEADERITEM; + int iStateId = HIS_NORMAL; + + switch (state) + { + case 1 : iStateId = HIS_HOT; break; + case 2 : iStateId = HIS_PRESSED; break; + } + + if (!themeData->themeEnabled || !procs) + return TCL_ERROR; + + hTheme = procs->OpenThemeData(hwnd, L"HEADER"); + if (!hTheme) + return TCL_ERROR; + + hDC = TkWinGetDrawableDC(tree->display, win, &dcState); + + /* The default XP themes give 3,0,0,0 which makes little sense since + * it is the *right* side that should not be drawn over by text; the + * 2-pixel wide header divider is on the right */ + hr = procs->GetThemeMargins( + hTheme, + hDC, + iPartId, + iStateId, + TMT_CONTENTMARGINS, + NULL, + &margins); + + procs->CloseThemeData(hTheme); + TkWinReleaseDrawableDC(win, hDC, &dcState); + + if (hr != S_OK) + return TCL_ERROR; + + bounds[0] = margins.cxLeftWidth; + bounds[1] = margins.cyTopHeight; + bounds[2] = margins.cxRightWidth; + bounds[3] = margins.cyBottomHeight; +/* +dbwin("margins %d %d %d %d\n", bounds[0], bounds[1], bounds[2], bounds[3]); +*/ + return TCL_OK; +} + +int TreeTheme_DrawHeaderArrow(TreeCtrl *tree, Drawable drawable, int up, + int x, int y, int width, int height) +{ + /* Doesn't seem that Microsoft actually implemented this */ + return TCL_ERROR; + +#if 0 + Window win = Tk_WindowId(tree->tkwin); + HWND hwnd = Tk_GetHWND(win); + HTHEME hTheme; + HDC hDC; + TkWinDCState dcState; + RECT rc; + HRESULT hr; + + int iPartId = HP_HEADERSORTARROW; + int iStateId = up ? HSAS_SORTEDUP : HSAS_SORTEDDOWN; + + if (!themeData->themeEnabled || !procs) + return TCL_ERROR; + + hTheme = procs->OpenThemeData(hwnd, L"HEADER"); + if (!hTheme) + return TCL_ERROR; + + if (!procs->IsThemePartDefined( + hTheme, + iPartId, + iStateId)) + { + procs->CloseThemeData(hTheme); + return TCL_ERROR; + } + + hDC = TkWinGetDrawableDC(tree->display, drawable, &dcState); + + rc.left = x; + rc.top = y; + rc.right = x + width; + rc.bottom = y + height; + + hr = procs->DrawThemeBackground( + hTheme, + hDC, + iPartId, + iStateId, + &rc, + NULL); + + procs->CloseThemeData(hTheme); + TkWinReleaseDrawableDC(drawable, hDC, &dcState); + return TCL_OK; +#endif /* 0 */ +} + +int TreeTheme_DrawButton(TreeCtrl *tree, Drawable drawable, int open, + int x, int y, int width, int height) +{ + Window win = Tk_WindowId(tree->tkwin); + HWND hwnd = Tk_GetHWND(win); + HTHEME hTheme; + HDC hDC; + TkWinDCState dcState; + RECT rc; + HRESULT hr; + + if (!themeData->themeEnabled || !procs) + return TCL_ERROR; + + int iPartId = TVP_GLYPH; + int iStateId = open ? GLPS_OPENED : GLPS_CLOSED; + + hTheme = procs->OpenThemeData(hwnd, L"TREEVIEW"); + if (!hTheme) + return TCL_ERROR; + +#if 0 /* Always returns FALSE */ + if (!procs->IsThemePartDefined( + hTheme, + iPartId, + iStateId)) + { + procs->CloseThemeData(hTheme); + return TCL_ERROR; + } +#endif + + hDC = TkWinGetDrawableDC(tree->display, drawable, &dcState); + + rc.left = x; + rc.top = y; + rc.right = x + width; + rc.bottom = y + height; + hr = procs->DrawThemeBackground( + hTheme, + hDC, + iPartId, + iStateId, + &rc, + NULL); + + procs->CloseThemeData(hTheme); + TkWinReleaseDrawableDC(drawable, hDC, &dcState); + + if (hr != S_OK) + return TCL_ERROR; + + return TCL_OK; +} + +int TreeTheme_GetButtonSize(TreeCtrl *tree, Drawable drawable, int open, + int *widthPtr, int *heightPtr) +{ + Window win = Tk_WindowId(tree->tkwin); + HWND hwnd = Tk_GetHWND(win); + HTHEME hTheme; + HDC hDC; + TkWinDCState dcState; + HRESULT hr; + SIZE size; + + if (!themeData->themeEnabled || !procs) + return TCL_ERROR; + + int iPartId = TVP_GLYPH; + int iStateId = open ? GLPS_OPENED : GLPS_CLOSED; + + hTheme = procs->OpenThemeData(hwnd, L"TREEVIEW"); + if (!hTheme) + return TCL_ERROR; + +#if 0 /* Always returns FALSE */ + if (!procs->IsThemePartDefined( + hTheme, + iPartId, + iStateId)) + { + procs->CloseThemeData(hTheme); + return TCL_ERROR; + } +#endif + + hDC = TkWinGetDrawableDC(tree->display, drawable, &dcState); + + /* Returns 9x9 for default XP style */ + hr = procs->GetThemePartSize( + hTheme, + hDC, + iPartId, + iStateId, + NULL, + TS_DRAW, + &size + ); + + procs->CloseThemeData(hTheme); + TkWinReleaseDrawableDC(drawable, hDC, &dcState); + + if (hr != S_OK) + return TCL_ERROR; + + /* Gave me 0,0 for a non-default theme, even though glyph existed */ + if ((size.cx <= 1) && (size.cy <= 1)) + return TCL_ERROR; + + *widthPtr = size.cx; + *heightPtr = size.cy; + return TCL_OK; +} + +#if !defined(WM_THEMECHANGED) +#define WM_THEMECHANGED 0x031A +#endif + +static LRESULT WINAPI +WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) +{ + Tcl_Interp *interp = (Tcl_Interp *)GetWindowLong(hwnd, GWL_USERDATA); + + switch (msg) { + case WM_THEMECHANGED: + Tcl_MutexLock(&themeMutex); + themeData->themeEnabled = procs->IsThemeActive(); + Tcl_MutexUnlock(&themeMutex); + Tree_TheWorldHasChanged(interp); + break; + } + return DefWindowProc(hwnd, msg, wp, lp); +} + +static CHAR windowClassName[32] = "TreeCtrlMonitorClass"; + +static BOOL +RegisterThemeMonitorWindowClass(HINSTANCE hinst) +{ + WNDCLASSEX wc; + + wc.cbSize = sizeof(WNDCLASSEX); + wc.style = CS_HREDRAW | CS_VREDRAW; + wc.lpfnWndProc = (WNDPROC)WndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = hinst; + wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); + wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hbrBackground = (HBRUSH)COLOR_WINDOW; + wc.lpszMenuName = windowClassName; + wc.lpszClassName = windowClassName; + + return RegisterClassEx(&wc); +} + +static HWND +CreateThemeMonitorWindow(HINSTANCE hinst, Tcl_Interp *interp) +{ + CHAR title[32] = "TreeCtrlMonitorWindow"; + HWND hwnd; + + hwnd = CreateWindow(windowClassName, title, WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, + NULL, NULL, hinst, NULL); + if (!hwnd) + return NULL; + + SetWindowLong(hwnd, GWL_USERDATA, (LONG)interp); + ShowWindow(hwnd, SW_HIDE); + UpdateWindow(hwnd); + + return hwnd; +} + +typedef struct PerInterpData PerInterpData; +struct PerInterpData +{ + HWND hwnd; +}; + +static void FreeAssocData(ClientData clientData, Tcl_Interp *interp) +{ + PerInterpData *data = (PerInterpData *) clientData; + +dbwin("FreeAssocData\n"); + DestroyWindow(data->hwnd); + ckfree((char *) data); +} + +int TreeTheme_Init(Tcl_Interp *interp) +{ + HWND hwnd; + PerInterpData *data; + + Tcl_MutexLock(&themeMutex); + + /* This is done once per-application */ + if (themeData == NULL) + { +dbwin("alloc themeData\n"); + themeData = (XPThemeData *) ckalloc(sizeof(XPThemeData)); + themeData->procs = LoadXPThemeProcs(&themeData->hlibrary); + themeData->registered = FALSE; + themeData->themeEnabled = FALSE; + + procs = themeData->procs; + + if (themeData->procs) { + /* Check this again if WM_THEMECHANGED arrives */ + themeData->themeEnabled = procs->IsThemeActive(); + + themeData->registered = + RegisterThemeMonitorWindowClass(Tk_GetHINSTANCE()); + } + } + + Tcl_MutexUnlock(&themeMutex); + + if (!procs || !themeData->registered) + return TCL_ERROR; + + /* Per-interp */ + hwnd = CreateThemeMonitorWindow(Tk_GetHINSTANCE(), interp); + if (!hwnd) + return TCL_ERROR; +dbwin("Tcl_SetAssocData TreeTheme\n"); + + data = (PerInterpData *) ckalloc(sizeof(PerInterpData)); + data->hwnd = hwnd; + Tcl_SetAssocData(interp, "TreeTheme", FreeAssocData, (ClientData) data); + + return TCL_OK; +} + +#else /* WIN32 */ + +int TreeTheme_DrawHeaderItem(TreeCtrl *tree, Drawable drawable, int state, int x, int y, int width, int height) +{ + return TCL_ERROR; +} + +int TreeTheme_GetHeaderContentMargins(TreeCtrl *tree, int state, int bounds[4]) +{ + return TCL_ERROR; +} + +int TreeTheme_DrawHeaderArrow(TreeCtrl *tree, Drawable drawable, int up, int x, int y, int width, int height) +{ + return TCL_ERROR; +} + +int TreeTheme_DrawButton(TreeCtrl *tree, Drawable drawable, int open, int x, int y, int width, int height) +{ + return TCL_ERROR; +} + +int TreeTheme_GetButtonSize(TreeCtrl *tree, Drawable drawable, int open, int *widthPtr, int *heightPtr) +{ + return TCL_ERROR; +} + +int TreeTheme_Init(Tcl_Interp *interp) +{ + return TCL_ERROR; +} + +#endif /* WIN32 */ + |