Got rid of GetSysColorPen.
[wine] / windows / syscolor.c
1 /*
2  * Support for system colors
3  *
4  * Copyright  David W. Metcalfe, 1993
5  * Copyright  Alexandre Julliard, 1994
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include <assert.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25
26 #include "windef.h"
27 #include "wingdi.h"
28 #include "wine/winbase16.h"
29 #include "wine/winuser16.h"
30 #include "sysmetrics.h"
31 #include "winbase.h"
32 #include "winuser.h"
33 #include "wine/debug.h"
34 #include "winreg.h"
35 #include "local.h"
36 #include "user.h"
37 #include "gdi.h" /* sic */
38
39 WINE_DEFAULT_DEBUG_CHANNEL(syscolor);
40
41 static const char * const DefSysColors[] =
42 {
43     "Scrollbar", "224 224 224",      /* COLOR_SCROLLBAR           */
44     "Background", "192 192 192",     /* COLOR_BACKGROUND          */
45     "ActiveTitle", "0 64 128",       /* COLOR_ACTIVECAPTION       */
46     "InactiveTitle", "255 255 255",  /* COLOR_INACTIVECAPTION     */
47     "Menu", "255 255 255",           /* COLOR_MENU                */
48     "Window", "255 255 255",         /* COLOR_WINDOW              */
49     "WindowFrame", "0 0 0",          /* COLOR_WINDOWFRAME         */
50     "MenuText", "0 0 0",             /* COLOR_MENUTEXT            */
51     "WindowText", "0 0 0",           /* COLOR_WINDOWTEXT          */
52     "TitleText", "255 255 255",      /* COLOR_CAPTIONTEXT         */
53     "ActiveBorder", "128 128 128",   /* COLOR_ACTIVEBORDER        */
54     "InactiveBorder", "255 255 255", /* COLOR_INACTIVEBORDER      */
55     "AppWorkspace", "255 255 232",   /* COLOR_APPWORKSPACE        */
56     "Hilight", "224 224 224",        /* COLOR_HIGHLIGHT           */
57     "HilightText", "0 0 0",          /* COLOR_HIGHLIGHTTEXT       */
58     "ButtonFace", "192 192 192",     /* COLOR_BTNFACE             */
59     "ButtonShadow", "128 128 128",   /* COLOR_BTNSHADOW           */
60     "GrayText", "192 192 192",       /* COLOR_GRAYTEXT            */
61     "ButtonText", "0 0 0",           /* COLOR_BTNTEXT             */
62     "InactiveTitleText", "0 0 0",    /* COLOR_INACTIVECAPTIONTEXT */
63     "ButtonHilight", "255 255 255",  /* COLOR_BTNHIGHLIGHT        */
64     "3DDarkShadow", "32 32 32",      /* COLOR_3DDKSHADOW          */
65     "3DLight", "192 192 192",        /* COLOR_3DLIGHT             */
66     "InfoText", "0 0 0",             /* COLOR_INFOTEXT            */
67     "InfoBackground", "255 255 192", /* COLOR_INFOBK              */
68     "AlternateButtonFace", "184 180 184",  /* COLOR_ALTERNATEBTNFACE */
69     "HotTrackingColor", "0 0 255",         /* COLOR_HOTLIGHT */
70     "GradientActiveTitle", "16 132 208",   /* COLOR_GRADIENTACTIVECAPTION */
71     "GradientInactiveTitle", "181 181 181" /* COLOR_GRADIENTINACTIVECAPTION */
72 };
73
74 static const char * const DefSysColors95[] =
75 {
76     "Scrollbar", "192 192 192",      /* COLOR_SCROLLBAR           */
77     "Background", "0 128 128",       /* COLOR_BACKGROUND          */
78     "ActiveTitle", "0 0 128",        /* COLOR_ACTIVECAPTION       */
79     "InactiveTitle", "128 128 128",  /* COLOR_INACTIVECAPTION     */
80     "Menu", "192 192 192",           /* COLOR_MENU                */
81     "Window", "255 255 255",         /* COLOR_WINDOW              */
82     "WindowFrame", "0 0 0",          /* COLOR_WINDOWFRAME         */
83     "MenuText", "0 0 0",             /* COLOR_MENUTEXT            */
84     "WindowText", "0 0 0",           /* COLOR_WINDOWTEXT          */
85     "TitleText", "255 255 255",      /* COLOR_CAPTIONTEXT         */
86     "ActiveBorder", "192 192 192",   /* COLOR_ACTIVEBORDER        */
87     "InactiveBorder", "192 192 192", /* COLOR_INACTIVEBORDER      */
88     "AppWorkspace", "128 128 128",   /* COLOR_APPWORKSPACE        */
89     "Hilight", "0 0 128",            /* COLOR_HIGHLIGHT           */
90     "HilightText", "255 255 255",    /* COLOR_HIGHLIGHTTEXT       */
91     "ButtonFace", "192 192 192",     /* COLOR_BTNFACE             */
92     "ButtonShadow", "128 128 128",   /* COLOR_BTNSHADOW           */
93     "GrayText", "128 128 128",       /* COLOR_GRAYTEXT            */
94     "ButtonText", "0 0 0",           /* COLOR_BTNTEXT             */
95     "InactiveTitleText", "192 192 192",/* COLOR_INACTIVECAPTIONTEXT */
96     "ButtonHilight", "255 255 255",  /* COLOR_BTNHIGHLIGHT        */
97     "3DDarkShadow", "0 0 0",         /* COLOR_3DDKSHADOW          */
98     "3DLight", "224 224 224",        /* COLOR_3DLIGHT             */
99     "InfoText", "0 0 0",             /* COLOR_INFOTEXT            */
100     "InfoBackground", "255 255 225", /* COLOR_INFOBK              */
101     "AlternateButtonFace", "180 180 180",  /* COLOR_ALTERNATEBTNFACE */
102     "HotTrackingColor", "0 0 255",         /* COLOR_HOTLIGHT */
103     "GradientActiveTitle", "16 132 208",   /* COLOR_GRADIENTACTIVECAPTION */
104     "GradientInactiveTitle", "181 181 181" /* COLOR_GRADIENTINACTIVECAPTION */
105 };
106
107
108 #define NUM_SYS_COLORS     (COLOR_GRADIENTINACTIVECAPTION+1)
109
110 static COLORREF SysColors[NUM_SYS_COLORS];
111 static HBRUSH SysColorBrushes[NUM_SYS_COLORS];
112 static HPEN   SysColorPens[NUM_SYS_COLORS];
113
114
115 /*************************************************************************
116  * SYSCOLOR_MakeObjectSystem
117  *
118  * OK, now for a very ugly hack.
119  * USER somehow has to tell GDI that its system brushes and pens are
120  * non-deletable.
121  * We don't want to export a function from GDI doing this for us,
122  * so we just do that ourselves by "wildly flipping some bits in memory".
123  * For a description of the GDI object magics and their flags,
124  * see "Undocumented Windows" (wrong about the OBJECT_NOSYSTEM flag, though).
125  */
126 static void SYSCOLOR_MakeObjectSystem( HGDIOBJ handle, BOOL set)
127 {
128     static WORD GDI_heap_sel = 0;
129     LPWORD ptr;
130
131     if (!GDI_heap_sel)
132     {
133         GDI_heap_sel = LoadLibrary16("gdi");
134         FreeLibrary16(GDI_heap_sel);
135     }
136
137     ptr = (LPWORD)LOCAL_Lock(GDI_heap_sel, handle);
138
139     /* touch the "system" bit of the wMagic field of a GDIOBJHDR */
140     if (set)
141         *(ptr+1) &= ~OBJECT_NOSYSTEM;
142     else
143         *(ptr+1) |= OBJECT_NOSYSTEM;
144     LOCAL_Unlock( GDI_heap_sel, handle );
145 }
146
147 /*************************************************************************
148  *             SYSCOLOR_SetColor
149  */
150 static void SYSCOLOR_SetColor( int index, COLORREF color )
151 {
152     if (index < 0 || index >= NUM_SYS_COLORS) return;
153     SysColors[index] = color;
154     if (SysColorBrushes[index])
155     {
156         SYSCOLOR_MakeObjectSystem(SysColorBrushes[index], FALSE);
157         DeleteObject( SysColorBrushes[index] );
158     }
159     SysColorBrushes[index] = CreateSolidBrush( color );
160     SYSCOLOR_MakeObjectSystem(SysColorBrushes[index], TRUE);
161
162     if (SysColorPens[index])
163     {
164         SYSCOLOR_MakeObjectSystem(SysColorPens[index], FALSE);
165         DeleteObject( SysColorPens[index] ); 
166     }
167     SysColorPens[index] = CreatePen( PS_SOLID, 1, color );
168     SYSCOLOR_MakeObjectSystem(SysColorPens[index], TRUE);
169 }
170
171
172 /*************************************************************************
173  *             SYSCOLOR_Init
174  */
175 void SYSCOLOR_Init(void)
176 {
177     int i, r, g, b;
178     const char * const *p;
179     char buffer[100];
180     BOOL bOk = FALSE, bNoReg = FALSE;
181     HKEY  hKey;
182
183     p = (TWEAK_WineLook == WIN31_LOOK) ? DefSysColors : DefSysColors95;
184
185     /* first, try to read the values from the registry */
186     if (RegCreateKeyExA(HKEY_CURRENT_USER, "Control Panel\\Colors", 0, 0, 0, KEY_ALL_ACCESS, 0, &hKey, 0))
187       bNoReg = TRUE;
188     for (i = 0; i < NUM_SYS_COLORS; i++)
189     { bOk = FALSE;
190
191       /* first try, registry */
192       if (!bNoReg)
193       {
194         DWORD dwDataSize = sizeof(buffer);
195         if (!(RegQueryValueExA(hKey,(LPSTR)p[i*2], 0, 0, buffer, &dwDataSize)))
196           if (sscanf( buffer, "%d %d %d", &r, &g, &b ) == 3) 
197             bOk = TRUE;
198       }
199
200       /* second try, win.ini */
201       if (!bOk)
202       { GetProfileStringA( "colors", p[i*2], p[i*2+1], buffer, 100 );
203         if (sscanf( buffer, " %d %d %d", &r, &g, &b ) == 3)
204           bOk = TRUE;
205       }
206       
207       /* last chance, take the default */
208       if (!bOk)
209       { int iNumColors = sscanf( p[i*2+1], " %d %d %d", &r, &g, &b );
210         assert (iNumColors==3);
211       }
212       
213       SYSCOLOR_SetColor( i, RGB(r,g,b) );
214     }
215     if (!bNoReg)
216       RegCloseKey(hKey);
217 }
218
219
220 /*************************************************************************
221  *              GetSysColor (USER.180)
222  */
223 COLORREF WINAPI GetSysColor16( INT16 nIndex )
224 {
225     return GetSysColor (nIndex);
226 }
227
228
229 /*************************************************************************
230  *              GetSysColor (USER32.@)
231  */
232 COLORREF WINAPI GetSysColor( INT nIndex )
233 {
234     if (nIndex >= 0 && nIndex < NUM_SYS_COLORS)
235         return SysColors[nIndex];
236     else
237         return 0;
238 }
239
240
241 /*************************************************************************
242  *              SetSysColors (USER.181)
243  */
244 VOID WINAPI SetSysColors16( INT16 nChanges, const INT16 *lpSysColor,
245                             const COLORREF *lpColorValues )
246 {
247     int i;
248
249     for (i = 0; i < nChanges; i++)
250     {
251         SYSCOLOR_SetColor( lpSysColor[i], lpColorValues[i] );
252     }
253
254     /* Send WM_SYSCOLORCHANGE message to all windows */
255
256     SendMessageA( HWND_BROADCAST, WM_SYSCOLORCHANGE, 0, 0 );
257
258     /* Repaint affected portions of all visible windows */
259
260     RedrawWindow( GetDesktopWindow(), NULL, 0,
261                 RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_ALLCHILDREN );
262 }
263
264
265 /*************************************************************************
266  *              SetSysColors (USER32.@)
267  */
268 BOOL WINAPI SetSysColors( INT nChanges, const INT *lpSysColor,
269                               const COLORREF *lpColorValues )
270 {
271     int i;
272
273     for (i = 0; i < nChanges; i++)
274     {
275         SYSCOLOR_SetColor( lpSysColor[i], lpColorValues[i] );
276     }
277
278     /* Send WM_SYSCOLORCHANGE message to all windows */
279
280     SendMessageA( HWND_BROADCAST, WM_SYSCOLORCHANGE, 0, 0 );
281
282     /* Repaint affected portions of all visible windows */
283
284     RedrawWindow( GetDesktopWindow(), NULL, 0,
285                 RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_ALLCHILDREN );
286     return TRUE;
287 }
288
289 /*************************************************************************
290  *              SetSysColorsTemp (USER32.@)
291  *
292  * UNDOCUMENTED !!
293  * 
294  * Called by W98SE desk.cpl Control Panel Applet:
295  * handle = SetSysColorsTemp(ptr, ptr, nCount);     ("set" call)
296  * result = SetSysColorsTemp(NULL, NULL, handle);   ("restore" call)
297  *
298  * pPens is an array of COLORREF values, which seems to be used
299  * to indicate the color values to create new pens with.
300  *
301  * pBrushes is an array of solid brush handles (returned by a previous
302  * CreateSolidBrush), which seems to contain the brush handles to set
303  * for the system colors.
304  *
305  * n seems to be used for
306  *   a) indicating the number of entries to operate on (length of pPens,
307  *      pBrushes)
308  *   b) passing the handle that points to the previously used color settings.
309  *      I couldn't figure out in hell what kind of handle this is on
310  *      Windows. I just use a heap handle instead. Shouldn't matter anyway.
311  *
312  * RETURNS
313  *     heap handle of our own copy of the current syscolors in case of
314  *                 "set" call, i.e. pPens, pBrushes != NULL.
315  *     TRUE (unconditionally !) in case of "restore" call,
316  *          i.e. pPens, pBrushes == NULL.
317  *     FALSE in case of either pPens != NULL and pBrushes == NULL
318  *          or pPens == NULL and pBrushes != NULL.
319  *
320  * I'm not sure whether this implementation is 100% correct. [AM]
321  */
322 DWORD WINAPI SetSysColorsTemp( const COLORREF *pPens, const HBRUSH *pBrushes, DWORD n)
323 {
324         int i;
325
326         if (pPens && pBrushes) /* "set" call */
327         {
328             /* allocate our structure to remember old colors */
329             LPVOID pOldCol = HeapAlloc(GetProcessHeap(), 0, sizeof(DWORD)+n*sizeof(HPEN)+n*sizeof(HBRUSH));
330             LPVOID p = pOldCol;
331             *(DWORD *)p = n; p += sizeof(DWORD);
332             memcpy(p, SysColorPens, n*sizeof(HPEN)); p += n*sizeof(HPEN);
333             memcpy(p, SysColorBrushes, n*sizeof(HBRUSH)); p += n*sizeof(HBRUSH);
334
335             for (i=0; i < n; i++)
336             {
337                 SysColorPens[i] = CreatePen( PS_SOLID, 1, pPens[i] );
338                 SysColorBrushes[i] = pBrushes[i];
339             }
340
341             return (DWORD)pOldCol;
342         }
343         if ((!pPens) && (!pBrushes)) /* "restore" call */
344         {
345             LPVOID pOldCol = (LPVOID)n;
346             LPVOID p = pOldCol;
347             DWORD nCount = *(DWORD *)p;
348             p += sizeof(DWORD);
349
350             for (i=0; i < nCount; i++)
351             {
352                 DeleteObject(SysColorPens[i]);
353                 SysColorPens[i] = *(HPEN *)p; p += sizeof(HPEN);
354             }
355             for (i=0; i < nCount; i++)
356             {
357                 SysColorBrushes[i] = *(HBRUSH *)p; p += sizeof(HBRUSH);
358             }
359             /* get rid of storage structure */
360             HeapFree(GetProcessHeap(), 0, pOldCol);
361
362             return TRUE;
363         }
364         return FALSE;
365 }
366
367 /***********************************************************************
368  *              GetSysColorBrush (USER.281)
369  */
370 HBRUSH16 WINAPI GetSysColorBrush16( INT16 index )
371 {
372     return (HBRUSH16)GetSysColorBrush(index);
373 }
374
375
376 /***********************************************************************
377  *              GetSysColorBrush (USER32.@)
378  */
379 HBRUSH WINAPI GetSysColorBrush( INT index )
380 {
381     if (0 <= index && index < NUM_SYS_COLORS)
382         return SysColorBrushes[index];
383     WARN("Unknown index(%d)\n", index );
384     return GetStockObject(LTGRAY_BRUSH);
385 }
386
387
388 /***********************************************************************
389  *              SYSCOLOR_GetPen
390  */
391 HPEN SYSCOLOR_GetPen( INT index )
392 {
393     /* We can assert here, because this function is internal to Wine */
394     assert (0 <= index && index < NUM_SYS_COLORS);
395     return SysColorPens[index];
396
397 }
398
399