/* * Support for system colors * * Copyright David W. Metcalfe, 1993 * Copyright Alexandre Julliard, 1994 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include "windef.h" #include "winbase.h" #include "wingdi.h" #include "wine/winbase16.h" #include "wine/winuser16.h" #include "winuser.h" #include "wownt32.h" #include "winreg.h" #include "local.h" #include "user.h" #include "gdi.h" /* sic */ #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(syscolor); static const char * const DefSysColors[] = { "Scrollbar", "192 192 192", /* COLOR_SCROLLBAR */ "Background", "0 128 128", /* COLOR_BACKGROUND */ "ActiveTitle", "0 0 128", /* COLOR_ACTIVECAPTION */ "InactiveTitle", "128 128 128", /* COLOR_INACTIVECAPTION */ "Menu", "192 192 192", /* COLOR_MENU */ "Window", "255 255 255", /* COLOR_WINDOW */ "WindowFrame", "0 0 0", /* COLOR_WINDOWFRAME */ "MenuText", "0 0 0", /* COLOR_MENUTEXT */ "WindowText", "0 0 0", /* COLOR_WINDOWTEXT */ "TitleText", "255 255 255", /* COLOR_CAPTIONTEXT */ "ActiveBorder", "192 192 192", /* COLOR_ACTIVEBORDER */ "InactiveBorder", "192 192 192", /* COLOR_INACTIVEBORDER */ "AppWorkspace", "128 128 128", /* COLOR_APPWORKSPACE */ "Hilight", "0 0 128", /* COLOR_HIGHLIGHT */ "HilightText", "255 255 255", /* COLOR_HIGHLIGHTTEXT */ "ButtonFace", "192 192 192", /* COLOR_BTNFACE */ "ButtonShadow", "128 128 128", /* COLOR_BTNSHADOW */ "GrayText", "128 128 128", /* COLOR_GRAYTEXT */ "ButtonText", "0 0 0", /* COLOR_BTNTEXT */ "InactiveTitleText", "192 192 192",/* COLOR_INACTIVECAPTIONTEXT */ "ButtonHilight", "255 255 255", /* COLOR_BTNHIGHLIGHT */ "3DDarkShadow", "0 0 0", /* COLOR_3DDKSHADOW */ "3DLight", "224 224 224", /* COLOR_3DLIGHT */ "InfoText", "0 0 0", /* COLOR_INFOTEXT */ "InfoBackground", "255 255 225", /* COLOR_INFOBK */ "AlternateButtonFace", "180 180 180", /* COLOR_ALTERNATEBTNFACE */ "HotTrackingColor", "0 0 255", /* COLOR_HOTLIGHT */ "GradientActiveTitle", "16 132 208", /* COLOR_GRADIENTACTIVECAPTION */ "GradientInactiveTitle", "181 181 181" /* COLOR_GRADIENTINACTIVECAPTION */ }; #define NUM_SYS_COLORS (COLOR_GRADIENTINACTIVECAPTION+1) static COLORREF SysColors[NUM_SYS_COLORS]; static HBRUSH SysColorBrushes[NUM_SYS_COLORS]; static HPEN SysColorPens[NUM_SYS_COLORS]; /************************************************************************* * SYSCOLOR_MakeObjectSystem * * OK, now for a very ugly hack. * USER somehow has to tell GDI that its system brushes and pens are * non-deletable. * We don't want to export a function from GDI doing this for us, * so we just do that ourselves by "wildly flipping some bits in memory". * For a description of the GDI object magics and their flags, * see "Undocumented Windows" (wrong about the OBJECT_NOSYSTEM flag, though). */ static void SYSCOLOR_MakeObjectSystem( HGDIOBJ16 handle, BOOL set) { static WORD heap_sel = 0; LPWORD ptr; if (!heap_sel) heap_sel = LoadLibrary16( "gdi" ); if (heap_sel >= 32) { ptr = (LPWORD)LOCAL_Lock(heap_sel, handle); /* touch the "system" bit of the wMagic field of a GDIOBJHDR */ if (set) *(ptr+1) &= ~OBJECT_NOSYSTEM; else *(ptr+1) |= OBJECT_NOSYSTEM; LOCAL_Unlock( heap_sel, handle ); } } /************************************************************************* * SYSCOLOR_SetColor */ static void SYSCOLOR_SetColor( int index, COLORREF color ) { if (index < 0 || index >= NUM_SYS_COLORS) return; SysColors[index] = color; if (SysColorBrushes[index]) { SYSCOLOR_MakeObjectSystem( HBRUSH_16(SysColorBrushes[index]), FALSE); DeleteObject( SysColorBrushes[index] ); } SysColorBrushes[index] = CreateSolidBrush( color ); SYSCOLOR_MakeObjectSystem( HBRUSH_16(SysColorBrushes[index]), TRUE); if (SysColorPens[index]) { SYSCOLOR_MakeObjectSystem( HPEN_16(SysColorPens[index]), FALSE); DeleteObject( SysColorPens[index] ); } SysColorPens[index] = CreatePen( PS_SOLID, 1, color ); SYSCOLOR_MakeObjectSystem( HPEN_16(SysColorPens[index]), TRUE); } /************************************************************************* * SYSCOLOR_Init */ void SYSCOLOR_Init(void) { int i, r, g, b; char buffer[100]; BOOL bOk = FALSE, bNoReg = FALSE; HKEY hKey; /* first, try to read the values from the registry */ if (RegCreateKeyExA(HKEY_CURRENT_USER, "Control Panel\\Colors", 0, 0, 0, KEY_ALL_ACCESS, 0, &hKey, 0)) bNoReg = TRUE; for (i = 0; i < NUM_SYS_COLORS; i++) { bOk = FALSE; /* first try, registry */ if (!bNoReg) { DWORD dwDataSize = sizeof(buffer); if (!(RegQueryValueExA(hKey,(LPSTR)DefSysColors[i*2], 0, 0, buffer, &dwDataSize))) if (sscanf( buffer, "%d %d %d", &r, &g, &b ) == 3) bOk = TRUE; } /* second try, win.ini */ if (!bOk) { GetProfileStringA( "colors", DefSysColors[i*2], DefSysColors[i*2+1], buffer, 100 ); if (sscanf( buffer, " %d %d %d", &r, &g, &b ) == 3) bOk = TRUE; } /* last chance, take the default */ if (!bOk) { int iNumColors = sscanf( DefSysColors[i*2+1], " %d %d %d", &r, &g, &b ); assert (iNumColors==3); } SYSCOLOR_SetColor( i, RGB(r,g,b) ); } if (!bNoReg) RegCloseKey(hKey); } /************************************************************************* * GetSysColor (USER.180) */ COLORREF WINAPI GetSysColor16( INT16 nIndex ) { return GetSysColor (nIndex); } /************************************************************************* * GetSysColor (USER32.@) */ COLORREF WINAPI GetSysColor( INT nIndex ) { if (nIndex >= 0 && nIndex < NUM_SYS_COLORS) return SysColors[nIndex]; else return 0; } /************************************************************************* * SetSysColors (USER.181) */ VOID WINAPI SetSysColors16( INT16 nChanges, const INT16 *lpSysColor, const COLORREF *lpColorValues ) { int i; for (i = 0; i < nChanges; i++) { SYSCOLOR_SetColor( lpSysColor[i], lpColorValues[i] ); } /* Send WM_SYSCOLORCHANGE message to all windows */ SendMessageTimeoutW( HWND_BROADCAST, WM_SYSCOLORCHANGE, 0, 0, SMTO_ABORTIFHUNG, 2000, NULL ); /* Repaint affected portions of all visible windows */ RedrawWindow( GetDesktopWindow(), NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_ALLCHILDREN ); } /************************************************************************* * SetSysColors (USER32.@) */ BOOL WINAPI SetSysColors( INT nChanges, const INT *lpSysColor, const COLORREF *lpColorValues ) { int i; for (i = 0; i < nChanges; i++) { SYSCOLOR_SetColor( lpSysColor[i], lpColorValues[i] ); } /* Send WM_SYSCOLORCHANGE message to all windows */ SendMessageTimeoutW( HWND_BROADCAST, WM_SYSCOLORCHANGE, 0, 0, SMTO_ABORTIFHUNG, 2000, NULL ); /* Repaint affected portions of all visible windows */ RedrawWindow( GetDesktopWindow(), NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_ALLCHILDREN ); return TRUE; } /************************************************************************* * SetSysColorsTemp (USER32.@) * * UNDOCUMENTED !! * * Called by W98SE desk.cpl Control Panel Applet: * handle = SetSysColorsTemp(ptr, ptr, nCount); ("set" call) * result = SetSysColorsTemp(NULL, NULL, handle); ("restore" call) * * pPens is an array of COLORREF values, which seems to be used * to indicate the color values to create new pens with. * * pBrushes is an array of solid brush handles (returned by a previous * CreateSolidBrush), which seems to contain the brush handles to set * for the system colors. * * n seems to be used for * a) indicating the number of entries to operate on (length of pPens, * pBrushes) * b) passing the handle that points to the previously used color settings. * I couldn't figure out in hell what kind of handle this is on * Windows. I just use a heap handle instead. Shouldn't matter anyway. * * RETURNS * heap handle of our own copy of the current syscolors in case of * "set" call, i.e. pPens, pBrushes != NULL. * TRUE (unconditionally !) in case of "restore" call, * i.e. pPens, pBrushes == NULL. * FALSE in case of either pPens != NULL and pBrushes == NULL * or pPens == NULL and pBrushes != NULL. * * I'm not sure whether this implementation is 100% correct. [AM] */ DWORD WINAPI SetSysColorsTemp( const COLORREF *pPens, const HBRUSH *pBrushes, DWORD n) { int i; if (pPens && pBrushes) /* "set" call */ { /* allocate our structure to remember old colors */ LPVOID pOldCol = HeapAlloc(GetProcessHeap(), 0, sizeof(DWORD)+n*sizeof(HPEN)+n*sizeof(HBRUSH)); LPVOID p = pOldCol; *(DWORD *)p = n; p = (char*)p + sizeof(DWORD); memcpy(p, SysColorPens, n*sizeof(HPEN)); p = (char*)p + n*sizeof(HPEN); memcpy(p, SysColorBrushes, n*sizeof(HBRUSH)); p = (char*)p + n*sizeof(HBRUSH); for (i=0; i < n; i++) { SysColorPens[i] = CreatePen( PS_SOLID, 1, pPens[i] ); SysColorBrushes[i] = pBrushes[i]; } return (DWORD)pOldCol; } if ((!pPens) && (!pBrushes)) /* "restore" call */ { LPVOID pOldCol = (LPVOID)n; LPVOID p = pOldCol; DWORD nCount = *(DWORD *)p; p = (char*)p + sizeof(DWORD); for (i=0; i < nCount; i++) { DeleteObject(SysColorPens[i]); SysColorPens[i] = *(HPEN *)p; p = (char*)p + sizeof(HPEN); } for (i=0; i < nCount; i++) { SysColorBrushes[i] = *(HBRUSH *)p; p = (char*)p + sizeof(HBRUSH); } /* get rid of storage structure */ HeapFree(GetProcessHeap(), 0, pOldCol); return TRUE; } return FALSE; } /*********************************************************************** * GetSysColorBrush (USER32.@) */ HBRUSH WINAPI GetSysColorBrush( INT index ) { if (0 <= index && index < NUM_SYS_COLORS) return SysColorBrushes[index]; WARN("Unknown index(%d)\n", index ); return GetStockObject(LTGRAY_BRUSH); } /*********************************************************************** * SYSCOLOR_GetPen */ HPEN SYSCOLOR_GetPen( INT index ) { /* We can assert here, because this function is internal to Wine */ assert (0 <= index && index < NUM_SYS_COLORS); return SysColorPens[index]; }