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