syscolor.c 13.6 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1 2 3 4
/*
 * Support for system colors
 *
 * Copyright  David W. Metcalfe, 1993
Alexandre Julliard's avatar
Alexandre Julliard committed
5
 * Copyright  Alexandre Julliard, 1994
Alexandre Julliard's avatar
Alexandre Julliard committed
6
 *
7 8 9 10 11 12 13 14 15 16 17 18 19
 * 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
Alexandre Julliard's avatar
Alexandre Julliard committed
20 21
 */

Alexandre Julliard's avatar
Alexandre Julliard committed
22
#include <assert.h>
23
#include <stdarg.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
24
#include <stdio.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
25
#include <stdlib.h>
Patrik Stridvall's avatar
Patrik Stridvall committed
26

27
#include "windef.h"
28
#include "winbase.h"
29
#include "wingdi.h"
Patrik Stridvall's avatar
Patrik Stridvall committed
30 31
#include "wine/winbase16.h"
#include "wine/winuser16.h"
32
#include "winuser.h"
33
#include "wownt32.h"
34
#include "winreg.h"
35
#include "local.h"
36
#include "user.h"
37
#include "gdi.h" /* sic */
38
#include "wine/debug.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
39

40
WINE_DEFAULT_DEBUG_CHANNEL(syscolor);
41

Alexandre Julliard's avatar
Alexandre Julliard committed
42
static const char * const DefSysColors[] =
Alexandre Julliard's avatar
Alexandre Julliard committed
43
{
Alexandre Julliard's avatar
Alexandre Julliard committed
44 45 46 47
    "Scrollbar", "224 224 224",      /* COLOR_SCROLLBAR           */
    "Background", "192 192 192",     /* COLOR_BACKGROUND          */
    "ActiveTitle", "0 64 128",       /* COLOR_ACTIVECAPTION       */
    "InactiveTitle", "255 255 255",  /* COLOR_INACTIVECAPTION     */
Alexandre Julliard's avatar
Alexandre Julliard committed
48
    "Menu", "255 255 255",           /* COLOR_MENU                */
Alexandre Julliard's avatar
Alexandre Julliard committed
49 50 51 52 53 54 55 56
    "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", "128 128 128",   /* COLOR_ACTIVEBORDER        */
    "InactiveBorder", "255 255 255", /* COLOR_INACTIVEBORDER      */
    "AppWorkspace", "255 255 232",   /* COLOR_APPWORKSPACE        */
Alexandre Julliard's avatar
Alexandre Julliard committed
57
    "Hilight", "224 224 224",        /* COLOR_HIGHLIGHT           */
Alexandre Julliard's avatar
Alexandre Julliard committed
58 59 60 61 62 63
    "HilightText", "0 0 0",          /* COLOR_HIGHLIGHTTEXT       */
    "ButtonFace", "192 192 192",     /* COLOR_BTNFACE             */
    "ButtonShadow", "128 128 128",   /* COLOR_BTNSHADOW           */
    "GrayText", "192 192 192",       /* COLOR_GRAYTEXT            */
    "ButtonText", "0 0 0",           /* COLOR_BTNTEXT             */
    "InactiveTitleText", "0 0 0",    /* COLOR_INACTIVECAPTIONTEXT */
Alexandre Julliard's avatar
Alexandre Julliard committed
64 65 66 67
    "ButtonHilight", "255 255 255",  /* COLOR_BTNHIGHLIGHT        */
    "3DDarkShadow", "32 32 32",      /* COLOR_3DDKSHADOW          */
    "3DLight", "192 192 192",        /* COLOR_3DLIGHT             */
    "InfoText", "0 0 0",             /* COLOR_INFOTEXT            */
Alexandre Julliard's avatar
Alexandre Julliard committed
68 69 70 71
    "InfoBackground", "255 255 192", /* COLOR_INFOBK              */
    "AlternateButtonFace", "184 180 184",  /* COLOR_ALTERNATEBTNFACE */
    "HotTrackingColor", "0 0 255",         /* COLOR_HOTLIGHT */
    "GradientActiveTitle", "16 132 208",   /* COLOR_GRADIENTACTIVECAPTION */
72
    "GradientInactiveTitle", "181 181 181" /* COLOR_GRADIENTINACTIVECAPTION */
Alexandre Julliard's avatar
Alexandre Julliard committed
73 74
};

Alexandre Julliard's avatar
Alexandre Julliard committed
75 76
static const char * const DefSysColors95[] =
{
77 78
    "Scrollbar", "192 192 192",      /* COLOR_SCROLLBAR           */
    "Background", "0 128 128",       /* COLOR_BACKGROUND          */
Alexandre Julliard's avatar
Alexandre Julliard committed
79 80
    "ActiveTitle", "0 0 128",        /* COLOR_ACTIVECAPTION       */
    "InactiveTitle", "128 128 128",  /* COLOR_INACTIVECAPTION     */
Alexandre Julliard's avatar
Alexandre Julliard committed
81 82 83 84 85 86
    "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         */
Alexandre Julliard's avatar
Alexandre Julliard committed
87 88
    "ActiveBorder", "192 192 192",   /* COLOR_ACTIVEBORDER        */
    "InactiveBorder", "192 192 192", /* COLOR_INACTIVEBORDER      */
Alexandre Julliard's avatar
Alexandre Julliard committed
89
    "AppWorkspace", "128 128 128",   /* COLOR_APPWORKSPACE        */
Alexandre Julliard's avatar
Alexandre Julliard committed
90 91
    "Hilight", "0 0 128",            /* COLOR_HIGHLIGHT           */
    "HilightText", "255 255 255",    /* COLOR_HIGHLIGHTTEXT       */
Alexandre Julliard's avatar
Alexandre Julliard committed
92 93
    "ButtonFace", "192 192 192",     /* COLOR_BTNFACE             */
    "ButtonShadow", "128 128 128",   /* COLOR_BTNSHADOW           */
94
    "GrayText", "128 128 128",       /* COLOR_GRAYTEXT            */
Alexandre Julliard's avatar
Alexandre Julliard committed
95
    "ButtonText", "0 0 0",           /* COLOR_BTNTEXT             */
96
    "InactiveTitleText", "192 192 192",/* COLOR_INACTIVECAPTIONTEXT */
Alexandre Julliard's avatar
Alexandre Julliard committed
97
    "ButtonHilight", "255 255 255",  /* COLOR_BTNHIGHLIGHT        */
Alexandre Julliard's avatar
Alexandre Julliard committed
98
    "3DDarkShadow", "0 0 0",         /* COLOR_3DDKSHADOW          */
99
    "3DLight", "224 224 224",        /* COLOR_3DLIGHT             */
Alexandre Julliard's avatar
Alexandre Julliard committed
100
    "InfoText", "0 0 0",             /* COLOR_INFOTEXT            */
101 102
    "InfoBackground", "255 255 225", /* COLOR_INFOBK              */
    "AlternateButtonFace", "180 180 180",  /* COLOR_ALTERNATEBTNFACE */
Alexandre Julliard's avatar
Alexandre Julliard committed
103 104
    "HotTrackingColor", "0 0 255",         /* COLOR_HOTLIGHT */
    "GradientActiveTitle", "16 132 208",   /* COLOR_GRADIENTACTIVECAPTION */
105
    "GradientInactiveTitle", "181 181 181" /* COLOR_GRADIENTINACTIVECAPTION */
Alexandre Julliard's avatar
Alexandre Julliard committed
106 107 108
};


Alexandre Julliard's avatar
Alexandre Julliard committed
109
#define NUM_SYS_COLORS     (COLOR_GRADIENTINACTIVECAPTION+1)
Alexandre Julliard's avatar
Alexandre Julliard committed
110 111

static COLORREF SysColors[NUM_SYS_COLORS];
112 113
static HBRUSH SysColorBrushes[NUM_SYS_COLORS];
static HPEN   SysColorPens[NUM_SYS_COLORS];
Alexandre Julliard's avatar
Alexandre Julliard committed
114

115 116 117 118 119 120 121 122 123 124 125 126

/*************************************************************************
 * 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).
 */
127
static void SYSCOLOR_MakeObjectSystem( HGDIOBJ16 handle, BOOL set)
128
{
129
    static WORD heap_sel = 0;
130 131
    LPWORD ptr;

132 133
    if (!heap_sel) heap_sel = LoadLibrary16( "gdi" );
    if (heap_sel >= 32)
134
    {
135
        ptr = (LPWORD)LOCAL_Lock(heap_sel, handle);
136

137 138 139 140 141 142 143
        /* 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 );
    }
144 145
}

Alexandre Julliard's avatar
Alexandre Julliard committed
146 147 148 149 150
/*************************************************************************
 *             SYSCOLOR_SetColor
 */
static void SYSCOLOR_SetColor( int index, COLORREF color )
{
Alexandre Julliard's avatar
Alexandre Julliard committed
151
    if (index < 0 || index >= NUM_SYS_COLORS) return;
Alexandre Julliard's avatar
Alexandre Julliard committed
152
    SysColors[index] = color;
153 154
    if (SysColorBrushes[index])
    {
155
	SYSCOLOR_MakeObjectSystem( HBRUSH_16(SysColorBrushes[index]), FALSE);
156 157
	DeleteObject( SysColorBrushes[index] );
    }
158
    SysColorBrushes[index] = CreateSolidBrush( color );
159
    SYSCOLOR_MakeObjectSystem( HBRUSH_16(SysColorBrushes[index]), TRUE);
160 161 162

    if (SysColorPens[index])
    {
163
        SYSCOLOR_MakeObjectSystem( HPEN_16(SysColorPens[index]), FALSE);
164
	DeleteObject( SysColorPens[index] );
165
    }
166
    SysColorPens[index] = CreatePen( PS_SOLID, 1, color );
167
    SYSCOLOR_MakeObjectSystem( HPEN_16(SysColorPens[index]), TRUE);
Alexandre Julliard's avatar
Alexandre Julliard committed
168 169 170
}


Alexandre Julliard's avatar
Alexandre Julliard committed
171 172 173
/*************************************************************************
 *             SYSCOLOR_Init
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
174
void SYSCOLOR_Init(void)
Alexandre Julliard's avatar
Alexandre Julliard committed
175
{
Alexandre Julliard's avatar
Alexandre Julliard committed
176
    int i, r, g, b;
Alexandre Julliard's avatar
Alexandre Julliard committed
177
    const char * const *p;
Alexandre Julliard's avatar
Alexandre Julliard committed
178
    char buffer[100];
179 180
    BOOL bOk = FALSE, bNoReg = FALSE;
    HKEY  hKey;
Alexandre Julliard's avatar
Alexandre Julliard committed
181

Alexandre Julliard's avatar
Alexandre Julliard committed
182
    p = (TWEAK_WineLook == WIN31_LOOK) ? DefSysColors : DefSysColors95;
183 184

    /* first, try to read the values from the registry */
185 186 187 188 189 190 191 192 193 194
    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)p[i*2], 0, 0, buffer, &dwDataSize)))
195
	  if (sscanf( buffer, "%d %d %d", &r, &g, &b ) == 3)
196
	    bOk = TRUE;
197 198
      }

199 200 201 202 203 204
      /* second try, win.ini */
      if (!bOk)
      { GetProfileStringA( "colors", p[i*2], p[i*2+1], buffer, 100 );
	if (sscanf( buffer, " %d %d %d", &r, &g, &b ) == 3)
	  bOk = TRUE;
      }
205

206 207 208 209 210
      /* last chance, take the default */
      if (!bOk)
      { int iNumColors = sscanf( p[i*2+1], " %d %d %d", &r, &g, &b );
	assert (iNumColors==3);
      }
211

212 213 214 215
      SYSCOLOR_SetColor( i, RGB(r,g,b) );
    }
    if (!bNoReg)
      RegCloseKey(hKey);
Alexandre Julliard's avatar
Alexandre Julliard committed
216 217 218 219
}


/*************************************************************************
220
 *		GetSysColor (USER.180)
Alexandre Julliard's avatar
Alexandre Julliard committed
221
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
222
COLORREF WINAPI GetSysColor16( INT16 nIndex )
Alexandre Julliard's avatar
Alexandre Julliard committed
223
{
224
    return GetSysColor (nIndex);
Alexandre Julliard's avatar
Alexandre Julliard committed
225
}
Alexandre Julliard's avatar
Alexandre Julliard committed
226

Alexandre Julliard's avatar
Alexandre Julliard committed
227 228

/*************************************************************************
229
 *		GetSysColor (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
230
 */
231
COLORREF WINAPI GetSysColor( INT nIndex )
Alexandre Julliard's avatar
Alexandre Julliard committed
232
{
Alexandre Julliard's avatar
Alexandre Julliard committed
233 234 235 236
    if (nIndex >= 0 && nIndex < NUM_SYS_COLORS)
	return SysColors[nIndex];
    else
	return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
237 238 239 240
}


/*************************************************************************
241
 *		SetSysColors (USER.181)
Alexandre Julliard's avatar
Alexandre Julliard committed
242
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
243
VOID WINAPI SetSysColors16( INT16 nChanges, const INT16 *lpSysColor,
Alexandre Julliard's avatar
Alexandre Julliard committed
244
			    const COLORREF *lpColorValues )
Alexandre Julliard's avatar
Alexandre Julliard committed
245 246
{
    int i;
Alexandre Julliard's avatar
Alexandre Julliard committed
247

Alexandre Julliard's avatar
Alexandre Julliard committed
248 249 250 251 252 253 254
    for (i = 0; i < nChanges; i++)
    {
	SYSCOLOR_SetColor( lpSysColor[i], lpColorValues[i] );
    }

    /* Send WM_SYSCOLORCHANGE message to all windows */

255 256
    SendMessageTimeoutW( HWND_BROADCAST, WM_SYSCOLORCHANGE, 0, 0,
                         SMTO_ABORTIFHUNG, 2000, NULL );
Alexandre Julliard's avatar
Alexandre Julliard committed
257 258 259

    /* Repaint affected portions of all visible windows */

260
    RedrawWindow( GetDesktopWindow(), NULL, 0,
Alexandre Julliard's avatar
Alexandre Julliard committed
261 262 263 264 265
                RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_ALLCHILDREN );
}


/*************************************************************************
266
 *		SetSysColors (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
267
 */
268
BOOL WINAPI SetSysColors( INT nChanges, const INT *lpSysColor,
Alexandre Julliard's avatar
Alexandre Julliard committed
269
                              const COLORREF *lpColorValues )
Alexandre Julliard's avatar
Alexandre Julliard committed
270 271 272 273 274
{
    int i;

    for (i = 0; i < nChanges; i++)
    {
Alexandre Julliard's avatar
Alexandre Julliard committed
275
	SYSCOLOR_SetColor( lpSysColor[i], lpColorValues[i] );
Alexandre Julliard's avatar
Alexandre Julliard committed
276 277 278 279
    }

    /* Send WM_SYSCOLORCHANGE message to all windows */

280 281
    SendMessageTimeoutW( HWND_BROADCAST, WM_SYSCOLORCHANGE, 0, 0,
                         SMTO_ABORTIFHUNG, 2000, NULL );
Alexandre Julliard's avatar
Alexandre Julliard committed
282 283 284

    /* Repaint affected portions of all visible windows */

285
    RedrawWindow( GetDesktopWindow(), NULL, 0,
Alexandre Julliard's avatar
Alexandre Julliard committed
286 287
                RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_ALLCHILDREN );
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
288
}
Alexandre Julliard's avatar
Alexandre Julliard committed
289

290
/*************************************************************************
291
 *		SetSysColorsTemp (USER32.@)
292 293
 *
 * UNDOCUMENTED !!
294
 *
295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321
 * 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]
322
 */
323
DWORD WINAPI SetSysColorsTemp( const COLORREF *pPens, const HBRUSH *pBrushes, DWORD n)
324
{
325 326 327 328 329 330 331
	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;
332 333 334
           *(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);
335 336 337 338 339 340 341 342 343 344 345 346 347 348

	    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;
349
           p = (char*)p + sizeof(DWORD);
350 351 352 353

	    for (i=0; i < nCount; i++)
	    {
		DeleteObject(SysColorPens[i]);
354
               SysColorPens[i] = *(HPEN *)p; p = (char*)p + sizeof(HPEN);
355 356 357
	    }
	    for (i=0; i < nCount; i++)
	    {
358
               SysColorBrushes[i] = *(HBRUSH *)p; p = (char*)p + sizeof(HBRUSH);
359 360 361 362 363 364 365
	    }
	    /* get rid of storage structure */
	    HeapFree(GetProcessHeap(), 0, pOldCol);

	    return TRUE;
	}
	return FALSE;
366
}
Alexandre Julliard's avatar
Alexandre Julliard committed
367 368

/***********************************************************************
369
 *		GetSysColorBrush (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
370
 */
371
HBRUSH WINAPI GetSysColorBrush( INT index )
Alexandre Julliard's avatar
Alexandre Julliard committed
372 373 374
{
    if (0 <= index && index < NUM_SYS_COLORS)
        return SysColorBrushes[index];
375
    WARN("Unknown index(%d)\n", index );
376
    return GetStockObject(LTGRAY_BRUSH);
Alexandre Julliard's avatar
Alexandre Julliard committed
377 378 379 380
}


/***********************************************************************
381
 *		SYSCOLOR_GetPen
Alexandre Julliard's avatar
Alexandre Julliard committed
382
 */
383
HPEN SYSCOLOR_GetPen( INT index )
Alexandre Julliard's avatar
Alexandre Julliard committed
384 385 386 387 388 389
{
    /* We can assert here, because this function is internal to Wine */
    assert (0 <= index && index < NUM_SYS_COLORS);
    return SysColorPens[index];

}