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