Correct some of the system metrics to more closely match Windows
[wine] / windows / sysparams.c
1 /*
2  * System parameters functions
3  *
4  * Copyright 1994 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winnls.h"
29 #include "wingdi.h"
30 #include "winreg.h"
31 #include "wine/winuser16.h"
32 #include "winerror.h"
33
34 #include "controls.h"
35 #include "user.h"
36 #include "wine/debug.h"
37 #include "sysmetrics.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(system);
40
41 /* System parameter indexes */
42 #define SPI_SETBEEP_IDX                         0
43 #define SPI_SETMOUSE_IDX                        1
44 #define SPI_SETBORDER_IDX                       2
45 #define SPI_SETKEYBOARDSPEED_IDX                3
46 #define SPI_ICONHORIZONTALSPACING_IDX           4
47 #define SPI_SETSCREENSAVETIMEOUT_IDX            5
48 #define SPI_SETGRIDGRANULARITY_IDX              6
49 #define SPI_SETKEYBOARDDELAY_IDX                7
50 #define SPI_ICONVERTICALSPACING_IDX             8
51 #define SPI_SETICONTITLEWRAP_IDX                9
52 #define SPI_SETMENUDROPALIGNMENT_IDX            10
53 #define SPI_SETDOUBLECLKWIDTH_IDX               11
54 #define SPI_SETDOUBLECLKHEIGHT_IDX              12
55 #define SPI_SETDOUBLECLICKTIME_IDX              13
56 #define SPI_SETMOUSEBUTTONSWAP_IDX              14
57 #define SPI_SETDRAGFULLWINDOWS_IDX              15
58 #define SPI_SETWORKAREA_IDX                     16
59 #define SPI_SETSHOWSOUNDS_IDX                   17
60 #define SPI_SETKEYBOARDPREF_IDX                 18
61 #define SPI_SETSCREENREADER_IDX                 19
62 #define SPI_SETSCREENSAVERRUNNING_IDX           20
63 #define SPI_WINE_IDX                            SPI_SETSCREENSAVERRUNNING_IDX
64
65 /**
66  * Names of the registry subkeys of HKEY_CURRENT_USER key and value names
67  * for the system parameters.
68  * Names of the keys are created by adding string "_REGKEY" to
69  * "SET" action names, value names are created by adding "_REG_NAME"
70  * to the "SET" action name.
71  */
72 #define SPI_SETBEEP_REGKEY              "Control Panel\\Sound"
73 #define SPI_SETBEEP_VALNAME             "Beep"
74 #define SPI_SETMOUSE_REGKEY             "Control Panel\\Mouse"
75 #define SPI_SETMOUSE_VALNAME1           "MouseThreshold1"
76 #define SPI_SETMOUSE_VALNAME2           "MouseThreshold2"
77 #define SPI_SETMOUSE_VALNAME3           "MouseSpeed"
78 #define SPI_SETBORDER_REGKEY            "Control Panel\\Desktop"
79 #define SPI_SETBORDER_VALNAME           "BorderWidth"
80 #define SPI_SETKEYBOARDSPEED_REGKEY             "Control Panel\\Keyboard"
81 #define SPI_SETKEYBOARDSPEED_VALNAME            "KeyboardSpeed"
82 #define SPI_ICONHORIZONTALSPACING_REGKEY        "Control Panel\\Desktop"
83 #define SPI_ICONHORIZONTALSPACING_VALNAME       "IconSpacing"
84 #define SPI_SETSCREENSAVETIMEOUT_REGKEY         "Control Panel\\Desktop"
85 #define SPI_SETSCREENSAVETIMEOUT_VALNAME        "ScreenSaveTimeOut"
86 #define SPI_SETSCREENSAVEACTIVE_REGKEY          "Control Panel\\Desktop"
87 #define SPI_SETSCREENSAVEACTIVE_VALNAME         "ScreenSaveActive"
88 #define SPI_SETGRIDGRANULARITY_REGKEY           "Control Panel\\Desktop"
89 #define SPI_SETGRIDGRANULARITY_VALNAME          "GridGranularity"
90 #define SPI_SETKEYBOARDDELAY_REGKEY             "Control Panel\\Keyboard"
91 #define SPI_SETKEYBOARDDELAY_VALNAME            "KeyboardDelay"
92 #define SPI_ICONVERTICALSPACING_REGKEY          "Control Panel\\Desktop"
93 #define SPI_ICONVERTICALSPACING_VALNAME         "IconVerticalSpacing"
94 #define SPI_SETICONTITLEWRAP_REGKEY             "Control Panel\\Desktop"
95 #define SPI_SETICONTITLEWRAP_VALNAME            "IconTitleWrap"
96 #define SPI_SETMENUDROPALIGNMENT_REGKEY         "Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows"
97 #define SPI_SETMENUDROPALIGNMENT_VALNAME        "MenuDropAlignment"
98 #define SPI_SETDOUBLECLKWIDTH_REGKEY            "Control Panel\\Mouse"
99 #define SPI_SETDOUBLECLKWIDTH_VALNAME           "DoubleClickWidth"
100 #define SPI_SETDOUBLECLKHEIGHT_REGKEY           "Control Panel\\Mouse"
101 #define SPI_SETDOUBLECLKHEIGHT_VALNAME          "DoubleClickHeight"
102 #define SPI_SETDOUBLECLICKTIME_REGKEY           "Control Panel\\Mouse"
103 #define SPI_SETDOUBLECLICKTIME_VALNAME          "DoubleClickSpeed"
104 #define SPI_SETMOUSEBUTTONSWAP_REGKEY           "Control Panel\\Mouse"
105 #define SPI_SETMOUSEBUTTONSWAP_VALNAME          "SwapMouseButtons"
106 #define SPI_SETDRAGFULLWINDOWS_REGKEY           "Control Panel\\Desktop"
107 #define SPI_SETDRAGFULLWINDOWS_VALNAME          "DragFullWindows"
108 #define SPI_SETWORKAREA_REGKEY                  "Control Panel\\Desktop"
109 #define SPI_SETWORKAREA_VALNAME                 "WINE_WorkArea"
110 #define SPI_SETSHOWSOUNDS_REGKEY        "Control Panel\\Accessibility\\ShowSounds"
111 #define SPI_SETSHOWSOUNDS_VALNAME       "On"
112 #define SPI_SETDESKWALLPAPER_REGKEY     "Control Panel\\Desktop"
113 #define SPI_SETDESKWALLPAPER_VALNAME    "Wallpaper"
114 /* FIXME - real values */
115 #define SPI_SETKEYBOARDPREF_REGKEY      "Control Panel\\Desktop"
116 #define SPI_SETKEYBOARDPREF_VALNAME     "WINE_KeyboardPref"
117 #define SPI_SETSCREENREADER_REGKEY      "Control Panel\\Desktop"
118 #define SPI_SETSCREENREADER_VALNAME     "WINE_ScreenReader"
119 #define SPI_SETSCREENSAVERRUNNING_REGKEY        "Control Panel\\Desktop"
120 #define SPI_SETSCREENSAVERRUNNING_VALNAME       "WINE_ScreenSaverRunning"
121
122 /* volatile registry branch under CURRENT_USER_REGKEY for temporary values storage */
123 #define WINE_CURRENT_USER_REGKEY     "Wine"
124
125 /* Indicators whether system parameter value is loaded */
126 static char spi_loaded[SPI_WINE_IDX + 1];
127
128 static BOOL notify_change = TRUE;
129
130 /* System parameters storage */
131 static BOOL beep_active = TRUE;
132 static int mouse_threshold1 = 6;
133 static int mouse_threshold2 = 10;
134 static int mouse_speed = 1;
135 static int border = 1;
136 static int keyboard_speed = 31;
137 static int screensave_timeout = 300;
138 static int grid_granularity = 0;
139 static int keyboard_delay = 1;
140 static BOOL icon_title_wrap = TRUE;
141 static int double_click_time = 500;
142 static BOOL drag_full_windows = FALSE;
143 static RECT work_area;
144 static BOOL keyboard_pref = TRUE;
145 static BOOL screen_reader = FALSE;
146 static BOOL screensaver_running = FALSE;
147
148 /***********************************************************************
149  *              GetTimerResolution (USER.14)
150  */
151 LONG WINAPI GetTimerResolution16(void)
152 {
153         return (1000);
154 }
155
156 /***********************************************************************
157  *              ControlPanelInfo (USER.273)
158  */
159 void WINAPI ControlPanelInfo16( INT16 nInfoType, WORD wData, LPSTR lpBuffer )
160 {
161         FIXME("(%d, %04x, %p): stub.\n", nInfoType, wData, lpBuffer);
162 }
163
164 /* This function is a copy of the one in objects/font.c */
165 static void SYSPARAMS_LogFont32ATo16( const LOGFONTA* font32, LPLOGFONT16 font16 )
166 {
167     font16->lfHeight = font32->lfHeight;
168     font16->lfWidth = font32->lfWidth;
169     font16->lfEscapement = font32->lfEscapement;
170     font16->lfOrientation = font32->lfOrientation;
171     font16->lfWeight = font32->lfWeight;
172     font16->lfItalic = font32->lfItalic;
173     font16->lfUnderline = font32->lfUnderline;
174     font16->lfStrikeOut = font32->lfStrikeOut;
175     font16->lfCharSet = font32->lfCharSet;
176     font16->lfOutPrecision = font32->lfOutPrecision;
177     font16->lfClipPrecision = font32->lfClipPrecision;
178     font16->lfQuality = font32->lfQuality;
179     font16->lfPitchAndFamily = font32->lfPitchAndFamily;
180     lstrcpynA( font16->lfFaceName, font32->lfFaceName, LF_FACESIZE );
181 }
182
183 static void SYSPARAMS_LogFont32ATo32W( const LOGFONTA* font32A, LPLOGFONTW font32W )
184 {
185     font32W->lfHeight = font32A->lfHeight;
186     font32W->lfWidth = font32A->lfWidth;
187     font32W->lfEscapement = font32A->lfEscapement;
188     font32W->lfOrientation = font32A->lfOrientation;
189     font32W->lfWeight = font32A->lfWeight;
190     font32W->lfItalic = font32A->lfItalic;
191     font32W->lfUnderline = font32A->lfUnderline;
192     font32W->lfStrikeOut = font32A->lfStrikeOut;
193     font32W->lfCharSet = font32A->lfCharSet;
194     font32W->lfOutPrecision = font32A->lfOutPrecision;
195     font32W->lfClipPrecision = font32A->lfClipPrecision;
196     font32W->lfQuality = font32A->lfQuality;
197     font32W->lfPitchAndFamily = font32A->lfPitchAndFamily;
198     MultiByteToWideChar( CP_ACP, 0, font32A->lfFaceName, -1, font32W->lfFaceName, LF_FACESIZE );
199     font32W->lfFaceName[LF_FACESIZE-1] = 0;
200 }
201
202 static void SYSPARAMS_NonClientMetrics32ATo16( const NONCLIENTMETRICSA* lpnm32, LPNONCLIENTMETRICS16 lpnm16 )
203 {
204     lpnm16->iBorderWidth        = lpnm32->iBorderWidth;
205     lpnm16->iScrollWidth        = lpnm32->iScrollWidth;
206     lpnm16->iScrollHeight       = lpnm32->iScrollHeight;
207     lpnm16->iCaptionWidth       = lpnm32->iCaptionWidth;
208     lpnm16->iCaptionHeight      = lpnm32->iCaptionHeight;
209     SYSPARAMS_LogFont32ATo16( &lpnm32->lfCaptionFont,   &lpnm16->lfCaptionFont );
210     lpnm16->iSmCaptionWidth     = lpnm32->iSmCaptionWidth;
211     lpnm16->iSmCaptionHeight    = lpnm32->iSmCaptionHeight;
212     SYSPARAMS_LogFont32ATo16( &lpnm32->lfSmCaptionFont, &lpnm16->lfSmCaptionFont );
213     lpnm16->iMenuWidth          = lpnm32->iMenuWidth;
214     lpnm16->iMenuHeight         = lpnm32->iMenuHeight;
215     SYSPARAMS_LogFont32ATo16( &lpnm32->lfMenuFont,      &lpnm16->lfMenuFont );
216     SYSPARAMS_LogFont32ATo16( &lpnm32->lfStatusFont,    &lpnm16->lfStatusFont );
217     SYSPARAMS_LogFont32ATo16( &lpnm32->lfMessageFont,   &lpnm16->lfMessageFont );
218 }
219
220 static void SYSPARAMS_NonClientMetrics32ATo32W( const NONCLIENTMETRICSA* lpnm32A, LPNONCLIENTMETRICSW lpnm32W )
221 {
222     lpnm32W->iBorderWidth       = lpnm32A->iBorderWidth;
223     lpnm32W->iScrollWidth       = lpnm32A->iScrollWidth;
224     lpnm32W->iScrollHeight      = lpnm32A->iScrollHeight;
225     lpnm32W->iCaptionWidth      = lpnm32A->iCaptionWidth;
226     lpnm32W->iCaptionHeight     = lpnm32A->iCaptionHeight;
227     SYSPARAMS_LogFont32ATo32W( &lpnm32A->lfCaptionFont,         &lpnm32W->lfCaptionFont );
228     lpnm32W->iSmCaptionWidth    = lpnm32A->iSmCaptionWidth;
229     lpnm32W->iSmCaptionHeight   = lpnm32A->iSmCaptionHeight;
230     SYSPARAMS_LogFont32ATo32W( &lpnm32A->lfSmCaptionFont,       &lpnm32W->lfSmCaptionFont );
231     lpnm32W->iMenuWidth         = lpnm32A->iMenuWidth;
232     lpnm32W->iMenuHeight        = lpnm32A->iMenuHeight;
233     SYSPARAMS_LogFont32ATo32W( &lpnm32A->lfMenuFont,            &lpnm32W->lfMenuFont );
234     SYSPARAMS_LogFont32ATo32W( &lpnm32A->lfStatusFont,          &lpnm32W->lfStatusFont );
235     SYSPARAMS_LogFont32ATo32W( &lpnm32A->lfMessageFont,         &lpnm32W->lfMessageFont );
236 }
237
238 /***********************************************************************
239  *           SYSPARAMS_Reset
240  *
241  * Sets the system parameter which should be always loaded to
242  * current value stored in registry.
243  * Invalidates lazy loaded parameter, so it will be loaded the next time
244  * it is requested.
245  *
246  * Parameters:
247  * uiAction - system parameter to reload value for.
248  *      Note, only "SET" values can be used for this parameter.
249  *      If uiAction is 0 all system parameters are reset.
250  */
251 void SYSPARAMS_Reset( UINT uiAction )
252 {
253 #define WINE_RELOAD_SPI(x) \
254     case x: \
255         spi_loaded[x##_IDX] = FALSE; \
256         SystemParametersInfoA( x, 0, dummy_buf, 0 );\
257         if (uiAction) \
258             break
259
260 #define WINE_IGNORE_SPI(x) \
261     case x: \
262         if (uiAction) \
263             break
264
265 #define WINE_INVALIDATE_SPI(x) \
266     case x: \
267         spi_loaded[x##_IDX] = FALSE; \
268         break
269
270     BOOL not_all_processed = TRUE;
271     char dummy_buf[10];
272
273     /* Execution falls through all the branches for uiAction == 0 */
274     switch (uiAction)
275     {
276     case 0:
277         memset( spi_loaded, 0, sizeof(spi_loaded) );
278
279     WINE_RELOAD_SPI(SPI_SETBORDER);
280     WINE_RELOAD_SPI(SPI_ICONHORIZONTALSPACING);
281     WINE_RELOAD_SPI(SPI_ICONVERTICALSPACING);
282     WINE_IGNORE_SPI(SPI_SETSCREENSAVEACTIVE);
283     WINE_RELOAD_SPI(SPI_SETDOUBLECLKWIDTH);
284     WINE_RELOAD_SPI(SPI_SETDOUBLECLKHEIGHT);
285     WINE_RELOAD_SPI(SPI_SETMOUSEBUTTONSWAP);
286     WINE_RELOAD_SPI(SPI_SETSHOWSOUNDS);
287     WINE_RELOAD_SPI(SPI_SETMENUDROPALIGNMENT);
288
289     default:
290         if (uiAction)
291         {
292             /* lazy loaded parameters */
293             switch (uiAction)
294             {
295             WINE_INVALIDATE_SPI(SPI_SETBEEP);
296             WINE_INVALIDATE_SPI(SPI_SETMOUSE);
297             WINE_INVALIDATE_SPI(SPI_SETKEYBOARDSPEED);
298             WINE_INVALIDATE_SPI(SPI_SETSCREENSAVETIMEOUT);
299             WINE_INVALIDATE_SPI(SPI_SETGRIDGRANULARITY);
300             WINE_INVALIDATE_SPI(SPI_SETKEYBOARDDELAY);
301             WINE_INVALIDATE_SPI(SPI_SETICONTITLEWRAP);
302             WINE_INVALIDATE_SPI(SPI_SETDOUBLECLICKTIME);
303             WINE_INVALIDATE_SPI(SPI_SETDRAGFULLWINDOWS);
304             WINE_INVALIDATE_SPI(SPI_SETWORKAREA);
305             WINE_INVALIDATE_SPI(SPI_SETKEYBOARDPREF);
306             WINE_INVALIDATE_SPI(SPI_SETSCREENREADER);
307             WINE_INVALIDATE_SPI(SPI_SETSCREENSAVERRUNNING);
308             default:
309                 FIXME( "Unknown action reset: %u\n", uiAction );
310                 break;
311             }
312         }
313         else
314             not_all_processed = FALSE;
315         break;
316     }
317
318     if (!uiAction && not_all_processed)
319         ERR( "Incorrect implementation of SYSPARAMS_Reset. "
320              "Not all params are reloaded.\n" );
321 #undef WINE_INVALIDATE_SPI
322 #undef WINE_IGNORE_SPI
323 #undef WINE_RELOAD_SPI
324 }
325
326 /***********************************************************************
327  *           get_volatile_regkey
328  *
329  * Return a handle to the volatile registry key used to store
330  * non-permanently modified parameters.
331  */
332 static HKEY get_volatile_regkey(void)
333 {
334     static HKEY volatile_key;
335
336     if (!volatile_key)
337     {
338         if (RegCreateKeyExA( HKEY_CURRENT_USER, WINE_CURRENT_USER_REGKEY,
339                              0, 0, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, 0,
340                              &volatile_key, 0 ) != ERROR_SUCCESS)
341             ERR("Can't create wine configuration registry branch\n");
342     }
343     return volatile_key;
344 }
345
346 /***********************************************************************
347  *           SYSPARAMS_NotifyChange
348  *
349  * Sends notification about system parameter update.
350  */
351 void SYSPARAMS_NotifyChange( UINT uiAction, UINT fWinIni )
352 {
353     if (notify_change)
354     {
355         if (fWinIni & SPIF_UPDATEINIFILE)
356         {
357             if (fWinIni & (SPIF_SENDWININICHANGE | SPIF_SENDCHANGE))
358                 SendMessageA(HWND_BROADCAST, WM_SETTINGCHANGE,
359                              uiAction, (LPARAM) "");
360         }
361         else
362         {
363             /* FIXME notify other wine processes with internal message */
364         }
365     }
366 }
367
368
369 /***********************************************************************
370  * Loads system parameter from user profile.
371  */
372 BOOL SYSPARAMS_Load( LPSTR lpRegKey, LPSTR lpValName, LPSTR lpBuf )
373 {
374     BOOL ret = FALSE;
375     DWORD type;
376     HKEY hKey;
377     DWORD count;
378
379     if ((RegOpenKeyA( get_volatile_regkey(), lpRegKey,
380                      &hKey ) == ERROR_SUCCESS) ||
381         (RegOpenKeyA( HKEY_CURRENT_USER, lpRegKey,
382                       &hKey ) == ERROR_SUCCESS))
383     {
384         ret = !RegQueryValueExA( hKey, lpValName, NULL, &type, lpBuf, &count );
385         RegCloseKey( hKey );
386     }
387     return ret;
388 }
389
390 /***********************************************************************
391  * Saves system parameter to user profile.
392  */
393 BOOL SYSPARAMS_Save( LPSTR lpRegKey, LPSTR lpValName, LPSTR lpValue,
394                      UINT fWinIni )
395 {
396     HKEY hKey;
397     HKEY hBaseKey;
398     DWORD dwOptions;
399     BOOL ret = FALSE;
400
401     if (fWinIni & SPIF_UPDATEINIFILE)
402     {
403         hBaseKey = HKEY_CURRENT_USER;
404         dwOptions = 0;
405     }
406     else
407     {
408         hBaseKey = get_volatile_regkey();
409         dwOptions = REG_OPTION_VOLATILE;
410     }
411
412     if (RegCreateKeyExA( hBaseKey, lpRegKey,
413                          0, 0, dwOptions, KEY_ALL_ACCESS,
414                          0, &hKey, 0 ) == ERROR_SUCCESS)
415     {
416         if (RegSetValueExA( hKey, lpValName, 0, REG_SZ,
417                             lpValue, strlen(lpValue) + 1 ) == ERROR_SUCCESS)
418         {
419             ret = TRUE;
420             if (hBaseKey == HKEY_CURRENT_USER)
421                 RegDeleteKeyA( get_volatile_regkey(), lpRegKey );
422         }
423         RegCloseKey( hKey );
424     }
425     return ret;
426 }
427
428
429 /***********************************************************************
430  *           SYSPARAMS_GetDoubleClickSize
431  *
432  * There is no SPI_GETDOUBLECLK* so we export this function instead.
433  */
434 void SYSPARAMS_GetDoubleClickSize( INT *width, INT *height )
435 {
436     char buf[10];
437
438     if (!spi_loaded[SPI_SETDOUBLECLKWIDTH_IDX])
439     {
440         char buf[10];
441
442         if (SYSPARAMS_Load( SPI_SETDOUBLECLKWIDTH_REGKEY,
443                             SPI_SETDOUBLECLKWIDTH_VALNAME, buf ))
444         {
445             SYSMETRICS_Set( SM_CXDOUBLECLK, atoi( buf ) );
446         }
447         spi_loaded[SPI_SETDOUBLECLKWIDTH_IDX] = TRUE;
448     }
449     if (!spi_loaded[SPI_SETDOUBLECLKHEIGHT_IDX])
450     {
451         if (SYSPARAMS_Load( SPI_SETDOUBLECLKHEIGHT_REGKEY,
452                             SPI_SETDOUBLECLKHEIGHT_VALNAME, buf ))
453         {
454             SYSMETRICS_Set( SM_CYDOUBLECLK, atoi( buf ) );
455         }
456         spi_loaded[SPI_SETDOUBLECLKHEIGHT_IDX] = TRUE;
457     }
458     *width  = GetSystemMetrics( SM_CXDOUBLECLK );
459     *height = GetSystemMetrics( SM_CYDOUBLECLK );
460 }
461
462
463 /***********************************************************************
464  *           SYSPARAMS_GetMouseButtonSwap
465  *
466  * There is no SPI_GETMOUSEBUTTONSWAP so we export this function instead.
467  */
468 INT SYSPARAMS_GetMouseButtonSwap( void )
469 {
470         int spi_idx = SPI_SETMOUSEBUTTONSWAP_IDX;
471
472         if (!spi_loaded[spi_idx])
473         {
474             char buf[5];
475
476             if (SYSPARAMS_Load( SPI_SETMOUSEBUTTONSWAP_REGKEY,
477                                 SPI_SETMOUSEBUTTONSWAP_VALNAME, buf ))
478             {
479                 SYSMETRICS_Set( SM_SWAPBUTTON, atoi( buf ) );
480             }
481             spi_loaded[spi_idx] = TRUE;
482         }
483
484         return GetSystemMetrics( SM_SWAPBUTTON );
485 }
486
487 /***********************************************************************
488  *
489  *      SYSPARAMS_GetGUIFont
490  *
491  *  fills LOGFONT with 'default GUI font'.
492  */
493
494 static void SYSPARAMS_GetGUIFont( LOGFONTA* plf )
495 {
496         HFONT   hf;
497
498         memset( plf, 0, sizeof(LOGFONTA) );
499         hf = (HFONT)GetStockObject( DEFAULT_GUI_FONT );
500         if ( GetObjectA( hf, sizeof(LOGFONTA), plf ) != sizeof(LOGFONTA) )
501         {
502                 /*
503                  * GetObjectA() would be succeeded always
504                  * since this is a stock object
505                  */
506                 ERR("GetObjectA() failed\n");
507         }
508 }
509
510 /***********************************************************************
511  *              SystemParametersInfoA (USER32.@)
512  *
513  *     Each system parameter has flag which shows whether the parameter
514  * is loaded or not. Parameters, stored directly in SysParametersInfo are
515  * loaded from registry only when they are requested and the flag is
516  * "false", after the loading the flag is set to "true". On interprocess
517  * notification of the parameter change the corresponding parameter flag is
518  * set to "false". The parameter value will be reloaded when it is requested
519  * the next time.
520  *     Parameters, backed by or depend on GetSystemMetrics are processed
521  * differently. These parameters are always loaded. They are reloaded right
522  * away on interprocess change notification. We can't do lazy loading because
523  * we don't want to complicate GetSystemMetrics.
524  *     Parameters, backed by X settings are read from corresponding setting.
525  * On the parameter change request the setting is changed. Interprocess change
526  * notifications are ignored.
527  *     When parameter value is updated the changed value is stored in permanent
528  * registry branch if saving is requested. Otherwise it is stored
529  * in temporary branch
530  *
531  */
532 BOOL WINAPI SystemParametersInfoA( UINT uiAction, UINT uiParam,
533                                    PVOID pvParam, UINT fWinIni )
534 {
535 #define WINE_SPI_FIXME(x) \
536     case x: \
537         FIXME( "Unimplemented action: %u (%s)\n", x, #x ); \
538         SetLastError( ERROR_INVALID_SPI_VALUE ); \
539         ret = FALSE; \
540         break
541 #define WINE_SPI_WARN(x) \
542     case x: \
543         WARN( "Ignored action: %u (%s)\n", x, #x ); \
544         break
545
546     BOOL ret = TRUE;
547     unsigned spi_idx = 0;
548
549     TRACE("(%u, %u, %p, %u)\n", uiAction, uiParam, pvParam, fWinIni);
550
551     switch (uiAction)
552     {
553     case SPI_GETBEEP:                           /*      1 */
554         spi_idx = SPI_SETBEEP_IDX;
555         if (!spi_loaded[spi_idx])
556         {
557             char buf[5];
558
559             if (SYSPARAMS_Load( SPI_SETBEEP_REGKEY, SPI_SETBEEP_VALNAME, buf ))
560                 beep_active  = !strcasecmp( "Yes", buf );
561             spi_loaded[spi_idx] = TRUE;
562         }
563
564         *(BOOL *)pvParam = beep_active;
565         break;
566
567     case SPI_SETBEEP:                           /*      2 */
568         spi_idx = SPI_SETBEEP_IDX;
569         if (SYSPARAMS_Save( SPI_SETBEEP_REGKEY, SPI_SETBEEP_VALNAME,
570                             (uiParam ? "Yes" : "No"), fWinIni ))
571         {
572             beep_active = uiParam;
573             spi_loaded[spi_idx] = TRUE;
574         }
575         else
576             ret = FALSE;
577         break;
578
579     case SPI_GETMOUSE:                          /*      3 */
580         spi_idx = SPI_SETMOUSE_IDX;
581         if (!spi_loaded[spi_idx])
582         {
583             char buf[10];
584
585             if (SYSPARAMS_Load( SPI_SETMOUSE_REGKEY, SPI_SETMOUSE_VALNAME1,
586                                 buf ))
587                 mouse_threshold1 = atoi( buf );
588             if (SYSPARAMS_Load( SPI_SETMOUSE_REGKEY, SPI_SETMOUSE_VALNAME2,
589                                 buf ))
590                 mouse_threshold2 = atoi( buf );
591             if (SYSPARAMS_Load( SPI_SETMOUSE_REGKEY, SPI_SETMOUSE_VALNAME3,
592                                 buf ))
593                 mouse_speed = atoi( buf );
594             spi_loaded[spi_idx] = TRUE;
595         }
596         ((INT *)pvParam)[0] = mouse_threshold1;
597         ((INT *)pvParam)[1] = mouse_threshold2;
598         ((INT *)pvParam)[2] = mouse_speed;
599         break;
600
601     case SPI_SETMOUSE:                          /*      4 */
602     {
603         char buf[10];
604
605         spi_idx = SPI_SETMOUSE_IDX;
606         sprintf(buf, "%d", ((INT *)pvParam)[0]);
607
608         if (SYSPARAMS_Save( SPI_SETMOUSE_REGKEY, SPI_SETMOUSE_VALNAME1,
609                             buf, fWinIni ))
610         {
611             mouse_threshold1 = ((INT *)pvParam)[0];
612             spi_loaded[spi_idx] = TRUE;
613
614             sprintf(buf, "%d", ((INT *)pvParam)[1]);
615             SYSPARAMS_Save( SPI_SETMOUSE_REGKEY, SPI_SETMOUSE_VALNAME2,
616                             buf, fWinIni );
617             mouse_threshold2 = ((INT *)pvParam)[1];
618
619             sprintf(buf, "%d", ((INT *)pvParam)[2]);
620             SYSPARAMS_Save( SPI_SETMOUSE_REGKEY, SPI_SETMOUSE_VALNAME3,
621                             buf, fWinIni );
622             mouse_speed = ((INT *)pvParam)[2];
623         }
624         else
625             ret = FALSE;
626         break;
627     }
628
629     case SPI_GETBORDER:                         /*      5 */
630         spi_idx = SPI_SETBORDER_IDX;
631         if (!spi_loaded[spi_idx])
632         {
633             char buf[10];
634
635             if (SYSPARAMS_Load( SPI_SETBORDER_REGKEY, SPI_SETBORDER_VALNAME,
636                                 buf ))
637             {
638                 int i = atoi( buf );
639                 if (i > 0) border = i;
640             }
641             spi_loaded[spi_idx] = TRUE;
642             if (TWEAK_WineLook > WIN31_LOOK)
643             {
644                 SYSMETRICS_Set( SM_CXFRAME, border + GetSystemMetrics( SM_CXDLGFRAME ) );
645                 SYSMETRICS_Set( SM_CYFRAME, border + GetSystemMetrics( SM_CXDLGFRAME ) );
646             }
647         }
648         *(INT *)pvParam = border;
649         break;
650
651     case SPI_SETBORDER:                         /*      6 */
652     {
653         char buf[10];
654
655         spi_idx = SPI_SETBORDER_IDX;
656         sprintf(buf, "%u", uiParam);
657
658         if (SYSPARAMS_Save( SPI_SETBORDER_REGKEY, SPI_SETBORDER_VALNAME,
659                             buf, fWinIni ))
660         {
661             if (uiParam > 0)
662             {
663                 border = uiParam;
664                 spi_loaded[spi_idx] = TRUE;
665                 if (TWEAK_WineLook > WIN31_LOOK)
666                 {
667                     SYSMETRICS_Set( SM_CXFRAME, uiParam + GetSystemMetrics( SM_CXDLGFRAME ) );
668                     SYSMETRICS_Set( SM_CYFRAME, uiParam + GetSystemMetrics( SM_CXDLGFRAME ) );
669                 }
670             }
671         }
672         else
673             ret = FALSE;
674         break;
675     }
676
677     case SPI_GETKEYBOARDSPEED:                  /*     10 */
678         spi_idx = SPI_SETKEYBOARDSPEED_IDX;
679         if (!spi_loaded[spi_idx])
680         {
681             char buf[10];
682
683             if (SYSPARAMS_Load( SPI_SETKEYBOARDSPEED_REGKEY,
684                                 SPI_SETKEYBOARDSPEED_VALNAME,
685                                 buf ))
686                 keyboard_speed = atoi( buf );
687             spi_loaded[spi_idx] = TRUE;
688         }
689         *(INT *)pvParam = keyboard_speed;
690         break;
691
692     case SPI_SETKEYBOARDSPEED:                  /*     11 */
693     {
694         char buf[10];
695
696         spi_idx = SPI_SETKEYBOARDSPEED_IDX;
697         if (uiParam > 31)
698             uiParam = 31;
699         sprintf(buf, "%u", uiParam);
700
701         if (SYSPARAMS_Save( SPI_SETKEYBOARDSPEED_REGKEY,
702                             SPI_SETKEYBOARDSPEED_VALNAME,
703                             buf, fWinIni ))
704         {
705             keyboard_speed = uiParam;
706             spi_loaded[spi_idx] = TRUE;
707         }
708         else
709             ret = FALSE;
710         break;
711     }
712
713     /* not implemented in Windows */
714     WINE_SPI_WARN(SPI_LANGDRIVER);              /*     12 */
715
716     case SPI_ICONHORIZONTALSPACING:             /*     13 */
717         spi_idx = SPI_ICONHORIZONTALSPACING_IDX;
718         if (pvParam != NULL)
719         {
720             if (!spi_loaded[spi_idx])
721             {
722                 char buf[10];
723
724                 if (SYSPARAMS_Load( SPI_ICONHORIZONTALSPACING_REGKEY,
725                                     SPI_ICONHORIZONTALSPACING_VALNAME, buf ))
726                 {
727                     SYSMETRICS_Set( SM_CXICONSPACING, atoi( buf ) );
728                 }
729                 spi_loaded[spi_idx] = TRUE;
730             }
731
732             *(INT *)pvParam = GetSystemMetrics( SM_CXICONSPACING );
733         }
734         else
735         {
736             char buf[10];
737
738             if (uiParam < 32) uiParam = 32;
739
740             sprintf(buf, "%u", uiParam);
741             if (SYSPARAMS_Save( SPI_ICONHORIZONTALSPACING_REGKEY,
742                                 SPI_ICONHORIZONTALSPACING_VALNAME,
743                                 buf, fWinIni ))
744             {
745                 SYSMETRICS_Set( SM_CXICONSPACING, uiParam );
746                 spi_loaded[spi_idx] = TRUE;
747             }
748             else
749                 ret = FALSE;
750         }
751         break;
752
753     case SPI_GETSCREENSAVETIMEOUT:              /*     14 */
754         spi_idx = SPI_SETSCREENSAVETIMEOUT_IDX;
755         if (!spi_loaded[spi_idx])
756         {
757             char buf[10];
758
759             if (SYSPARAMS_Load( SPI_SETSCREENSAVETIMEOUT_REGKEY,
760                                 SPI_SETSCREENSAVETIMEOUT_VALNAME,
761                                 buf ))
762                 screensave_timeout = atoi( buf );
763
764             spi_loaded[spi_idx] = TRUE;
765         }
766         *(INT *)pvParam = screensave_timeout;
767         break;
768
769     case SPI_SETSCREENSAVETIMEOUT:              /*     15 */
770     {
771         char buf[10];
772
773         spi_idx = SPI_SETSCREENSAVETIMEOUT_IDX;
774         sprintf(buf, "%u", uiParam);
775
776         if (SYSPARAMS_Save( SPI_SETSCREENSAVETIMEOUT_REGKEY,
777                             SPI_SETSCREENSAVETIMEOUT_VALNAME,
778                             buf, fWinIni ))
779         {
780             screensave_timeout = uiParam;
781             spi_loaded[spi_idx] = TRUE;
782         }
783         else
784             ret = FALSE;
785         break;
786     }
787
788     case SPI_GETSCREENSAVEACTIVE:               /*     16 */
789         *(BOOL *)pvParam = USER_Driver.pGetScreenSaveActive();
790         break;
791
792     case SPI_SETSCREENSAVEACTIVE:               /*     17 */
793     {
794         char buf[5];
795
796         sprintf(buf, "%u", uiParam);
797         USER_Driver.pSetScreenSaveActive( uiParam );
798         /* saved value does not affect Wine */
799         SYSPARAMS_Save( SPI_SETSCREENSAVEACTIVE_REGKEY,
800                         SPI_SETSCREENSAVEACTIVE_VALNAME,
801                         buf, fWinIni );
802         break;
803     }
804
805     case SPI_GETGRIDGRANULARITY:                /*     18 */
806         spi_idx = SPI_SETGRIDGRANULARITY_IDX;
807         if (!spi_loaded[spi_idx])
808         {
809             char buf[10];
810
811             if (SYSPARAMS_Load( SPI_SETGRIDGRANULARITY_REGKEY,
812                                 SPI_SETGRIDGRANULARITY_VALNAME,
813                                 buf ))
814                 grid_granularity = atoi( buf );
815
816             spi_loaded[spi_idx] = TRUE;
817         }
818         *(INT *)pvParam = grid_granularity;
819         break;
820
821     case SPI_SETGRIDGRANULARITY:                /*     19 */
822     {
823         char buf[10];
824
825         spi_idx = SPI_SETGRIDGRANULARITY_IDX;
826         sprintf(buf, "%u", uiParam);
827
828         if (SYSPARAMS_Save( SPI_SETGRIDGRANULARITY_REGKEY,
829                             SPI_SETGRIDGRANULARITY_VALNAME,
830                             buf, fWinIni ))
831         {
832             grid_granularity = uiParam;
833             spi_loaded[spi_idx] = TRUE;
834         }
835         else
836             ret = FALSE;
837         break;
838     }
839
840     case SPI_SETDESKWALLPAPER:                  /*     20 */
841         SYSPARAMS_Save(SPI_SETDESKWALLPAPER_REGKEY, SPI_SETDESKWALLPAPER_VALNAME, pvParam, fWinIni);
842         ret = SetDeskWallPaper( (LPSTR)pvParam );
843         break;
844     case SPI_SETDESKPATTERN:                    /*     21 */
845         /* FIXME: the ability to specify a pattern in pvParam
846            doesn't seem to be documented for Win32 */
847         if ((INT16)uiParam == -1)
848         {
849             char buffer[256];
850             GetProfileStringA( "Desktop", "Pattern",
851                                "170 85 170 85 170 85 170 85",
852                                buffer, sizeof(buffer) );
853             ret = DESKTOP_SetPattern( (LPSTR)buffer );
854         } else
855             ret = DESKTOP_SetPattern( (LPSTR)pvParam );
856         break;
857
858     case SPI_GETKEYBOARDDELAY:                  /*     22 */
859         spi_idx = SPI_SETKEYBOARDDELAY_IDX;
860         if (!spi_loaded[spi_idx])
861         {
862             char buf[10];
863
864             if (SYSPARAMS_Load( SPI_SETKEYBOARDDELAY_REGKEY,
865                                 SPI_SETKEYBOARDDELAY_VALNAME,
866                                 buf ))
867             {
868                 int i = atoi( buf );
869                 if ( (i >= 0) && (i <= 3)) keyboard_delay = i;
870             }
871
872             spi_loaded[spi_idx] = TRUE;
873         }
874         *(INT *)pvParam = keyboard_delay;
875         break;
876
877     case SPI_SETKEYBOARDDELAY:                  /*     23 */
878     {
879         char buf[10];
880
881         spi_idx = SPI_SETKEYBOARDDELAY_IDX;
882         sprintf(buf, "%u", uiParam);
883
884         if (SYSPARAMS_Save( SPI_SETKEYBOARDDELAY_REGKEY,
885                             SPI_SETKEYBOARDDELAY_VALNAME,
886                             buf, fWinIni ))
887         {
888             if (uiParam <= 3)
889                 keyboard_delay = uiParam;
890             spi_loaded[spi_idx] = TRUE;
891         }
892         else
893             ret = FALSE;
894         break;
895     }
896
897     case SPI_ICONVERTICALSPACING:               /*     24 */
898         spi_idx = SPI_ICONVERTICALSPACING_IDX;
899         if (pvParam != NULL)
900         {
901             if (!spi_loaded[spi_idx])
902             {
903                 char buf[10];
904
905                 if (SYSPARAMS_Load( SPI_ICONVERTICALSPACING_REGKEY,
906                                     SPI_ICONVERTICALSPACING_VALNAME, buf ))
907                 {
908                     SYSMETRICS_Set( SM_CYICONSPACING, atoi( buf ) );
909                 }
910                 spi_loaded[spi_idx] = TRUE;
911             }
912
913             *(INT *)pvParam = GetSystemMetrics( SM_CYICONSPACING );
914         }
915         else
916         {
917             char buf[10];
918
919             if (uiParam < 32) uiParam = 32;
920
921             sprintf(buf, "%u", uiParam);
922             if (SYSPARAMS_Save( SPI_ICONVERTICALSPACING_REGKEY,
923                                 SPI_ICONVERTICALSPACING_VALNAME,
924                                 buf, fWinIni ))
925             {
926                 SYSMETRICS_Set( SM_CYICONSPACING, uiParam );
927                 spi_loaded[spi_idx] = TRUE;
928             }
929             else
930                 ret = FALSE;
931         }
932
933         break;
934
935     case SPI_GETICONTITLEWRAP:                  /*     25 */
936         spi_idx = SPI_SETICONTITLEWRAP_IDX;
937         if (!spi_loaded[spi_idx])
938         {
939             char buf[5];
940
941             if (SYSPARAMS_Load( SPI_SETICONTITLEWRAP_REGKEY,
942                                 SPI_SETICONTITLEWRAP_VALNAME, buf ))
943                 icon_title_wrap  = atoi(buf);
944             spi_loaded[spi_idx] = TRUE;
945         }
946
947         *(BOOL *)pvParam = icon_title_wrap;
948         break;
949
950     case SPI_SETICONTITLEWRAP:                  /*     26 */
951     {
952         char buf[5];
953
954         spi_idx = SPI_SETICONTITLEWRAP_IDX;
955         sprintf(buf, "%u", uiParam);
956         if (SYSPARAMS_Save( SPI_SETICONTITLEWRAP_REGKEY,
957                             SPI_SETICONTITLEWRAP_VALNAME,
958                             buf, fWinIni ))
959         {
960             icon_title_wrap = uiParam;
961             spi_loaded[spi_idx] = TRUE;
962         }
963         else
964             ret = FALSE;
965         break;
966     }
967
968     case SPI_GETMENUDROPALIGNMENT:              /*     27 */
969         spi_idx = SPI_SETMENUDROPALIGNMENT_IDX;
970
971         if (!spi_loaded[spi_idx])
972         {
973             char buf[5];
974
975             if (SYSPARAMS_Load( SPI_SETMENUDROPALIGNMENT_REGKEY,
976                                 SPI_SETMENUDROPALIGNMENT_VALNAME, buf ))
977             {
978                 SYSMETRICS_Set( SM_MENUDROPALIGNMENT, atoi( buf ) );
979             }
980             spi_loaded[spi_idx] = TRUE;
981         }
982
983
984         *(BOOL *)pvParam = GetSystemMetrics( SM_MENUDROPALIGNMENT );
985         break;
986
987     case SPI_SETMENUDROPALIGNMENT:              /*     28 */
988     {
989         char buf[5];
990         spi_idx = SPI_SETMENUDROPALIGNMENT_IDX;
991
992         sprintf(buf, "%u", uiParam);
993         if (SYSPARAMS_Save( SPI_SETMENUDROPALIGNMENT_REGKEY,
994                             SPI_SETMENUDROPALIGNMENT_VALNAME,
995                             buf, fWinIni ))
996         {
997             SYSMETRICS_Set( SM_MENUDROPALIGNMENT, uiParam );
998             spi_loaded[spi_idx] = TRUE;
999         }
1000         else
1001             ret = FALSE;
1002         break;
1003     }
1004
1005     case SPI_SETDOUBLECLKWIDTH:                 /*     29 */
1006     {
1007         char buf[10];
1008         spi_idx = SPI_SETDOUBLECLKWIDTH_IDX;
1009
1010         sprintf(buf, "%u", uiParam);
1011         if (SYSPARAMS_Save( SPI_SETDOUBLECLKWIDTH_REGKEY,
1012                             SPI_SETDOUBLECLKWIDTH_VALNAME,
1013                             buf, fWinIni ))
1014         {
1015             SYSMETRICS_Set( SM_CXDOUBLECLK, uiParam );
1016             spi_loaded[spi_idx] = TRUE;
1017         }
1018         else
1019             ret = FALSE;
1020         break;
1021     }
1022
1023     case SPI_SETDOUBLECLKHEIGHT:                /*     30 */
1024     {
1025         char buf[10];
1026         spi_idx = SPI_SETDOUBLECLKHEIGHT_IDX;
1027
1028         sprintf(buf, "%u", uiParam);
1029         if (SYSPARAMS_Save( SPI_SETDOUBLECLKHEIGHT_REGKEY,
1030                             SPI_SETDOUBLECLKHEIGHT_VALNAME,
1031                             buf, fWinIni ))
1032         {
1033             SYSMETRICS_Set( SM_CYDOUBLECLK, uiParam );
1034             spi_loaded[spi_idx] = TRUE;
1035         }
1036         else
1037             ret = FALSE;
1038         break;
1039     }
1040
1041     case SPI_GETICONTITLELOGFONT:               /*     31 */
1042     {
1043         LPLOGFONTA lpLogFont = (LPLOGFONTA)pvParam;
1044         LOGFONTA        lfDefault;
1045
1046         /*
1047          * The 'default GDI fonts' seems to be returned.
1048          * If a returned font is not a correct font in your environment,
1049          * please try to fix objects/gdiobj.c at first.
1050          */
1051         SYSPARAMS_GetGUIFont( &lfDefault );
1052
1053         GetProfileStringA( "Desktop", "IconTitleFaceName",
1054                            lfDefault.lfFaceName,
1055                            lpLogFont->lfFaceName, LF_FACESIZE );
1056         lpLogFont->lfHeight = -GetProfileIntA( "Desktop", "IconTitleSize", 11 );
1057         lpLogFont->lfWidth = 0;
1058         lpLogFont->lfEscapement = lpLogFont->lfOrientation = 0;
1059         lpLogFont->lfWeight = FW_NORMAL;
1060         lpLogFont->lfItalic = FALSE;
1061         lpLogFont->lfStrikeOut = FALSE;
1062         lpLogFont->lfUnderline = FALSE;
1063         lpLogFont->lfCharSet = lfDefault.lfCharSet; /* at least 'charset' should not be hard-coded */
1064         lpLogFont->lfOutPrecision = OUT_DEFAULT_PRECIS;
1065         lpLogFont->lfClipPrecision = CLIP_DEFAULT_PRECIS;
1066         lpLogFont->lfPitchAndFamily = DEFAULT_PITCH;
1067         break;
1068     }
1069
1070     case SPI_SETDOUBLECLICKTIME:                /*     32 */
1071     {
1072         char buf[10];
1073
1074         spi_idx = SPI_SETDOUBLECLICKTIME_IDX;
1075         sprintf(buf, "%u", uiParam);
1076
1077         if (SYSPARAMS_Save( SPI_SETDOUBLECLICKTIME_REGKEY,
1078                             SPI_SETDOUBLECLICKTIME_VALNAME,
1079                             buf, fWinIni ))
1080         {
1081             if (!uiParam)
1082                 uiParam = 500;
1083             double_click_time = uiParam;
1084             spi_loaded[spi_idx] = TRUE;
1085         }
1086         else
1087             ret = FALSE;
1088         break;
1089     }
1090
1091     case SPI_SETMOUSEBUTTONSWAP:                /*     33 */
1092     {
1093         char buf[5];
1094         spi_idx = SPI_SETMOUSEBUTTONSWAP_IDX;
1095
1096         sprintf(buf, "%u", uiParam);
1097         if (SYSPARAMS_Save( SPI_SETMOUSEBUTTONSWAP_REGKEY,
1098                             SPI_SETMOUSEBUTTONSWAP_VALNAME,
1099                             buf, fWinIni ))
1100         {
1101             SYSMETRICS_Set( SM_SWAPBUTTON, uiParam );
1102             spi_loaded[spi_idx] = TRUE;
1103         }
1104         else
1105             ret = FALSE;
1106         break;
1107     }
1108
1109     WINE_SPI_FIXME(SPI_SETICONTITLELOGFONT);    /*     34 */
1110
1111     case SPI_GETFASTTASKSWITCH:                 /*     35 */
1112         *(BOOL *)pvParam = 1;
1113         break;
1114
1115     case SPI_SETFASTTASKSWITCH:                 /*     36 */
1116         /* the action is disabled */
1117         ret = FALSE;
1118         break;
1119
1120     case SPI_SETDRAGFULLWINDOWS:                /*     37  WINVER >= 0x0400 */
1121     {
1122         char buf[5];
1123
1124         spi_idx = SPI_SETDRAGFULLWINDOWS_IDX;
1125         sprintf(buf, "%u", uiParam);
1126         if (SYSPARAMS_Save( SPI_SETDRAGFULLWINDOWS_REGKEY,
1127                             SPI_SETDRAGFULLWINDOWS_VALNAME,
1128                             buf, fWinIni ))
1129         {
1130             drag_full_windows = uiParam;
1131             spi_loaded[spi_idx] = TRUE;
1132         }
1133         else
1134             ret = FALSE;
1135         break;
1136     }
1137
1138     case SPI_GETDRAGFULLWINDOWS:                /*     38  WINVER >= 0x0400 */
1139         spi_idx = SPI_SETDRAGFULLWINDOWS_IDX;
1140         if (!spi_loaded[spi_idx])
1141         {
1142             char buf[5];
1143
1144             if (SYSPARAMS_Load( SPI_SETDRAGFULLWINDOWS_REGKEY,
1145                                 SPI_SETDRAGFULLWINDOWS_VALNAME, buf ))
1146                 drag_full_windows  = atoi(buf);
1147             spi_loaded[spi_idx] = TRUE;
1148         }
1149
1150         *(BOOL *)pvParam = drag_full_windows;
1151         break;
1152
1153     case SPI_GETNONCLIENTMETRICS:               /*     41  WINVER >= 0x400 */
1154     {
1155         LPNONCLIENTMETRICSA lpnm = (LPNONCLIENTMETRICSA)pvParam;
1156
1157         if (lpnm->cbSize == sizeof(NONCLIENTMETRICSA))
1158         {
1159             /* clear the struct, so we have 'sane' members */
1160             memset(
1161                 (char *)pvParam + sizeof(lpnm->cbSize),
1162                 0,
1163                 lpnm->cbSize - sizeof(lpnm->cbSize)
1164                 );
1165
1166             /* initialize geometry entries */
1167             lpnm->iBorderWidth = 1;
1168             lpnm->iScrollWidth = GetSystemMetrics(SM_CXVSCROLL);
1169             lpnm->iScrollHeight = GetSystemMetrics(SM_CYHSCROLL);
1170
1171             /* size of the normal caption buttons */
1172             lpnm->iCaptionWidth = GetSystemMetrics(SM_CXSIZE);
1173             lpnm->iCaptionHeight = GetSystemMetrics(SM_CYSIZE);
1174
1175             /* caption font metrics */
1176             SystemParametersInfoA( SPI_GETICONTITLELOGFONT, 0, (LPVOID)&(lpnm->lfCaptionFont), 0 );
1177             lpnm->lfCaptionFont.lfWeight = FW_BOLD;
1178
1179             /* size of the small caption buttons */
1180             lpnm->iSmCaptionWidth = GetSystemMetrics(SM_CXSMSIZE);
1181             lpnm->iSmCaptionHeight = GetSystemMetrics(SM_CYSMSIZE);
1182
1183             /* small caption font metrics */
1184             SystemParametersInfoA( SPI_GETICONTITLELOGFONT, 0, (LPVOID)&(lpnm->lfSmCaptionFont), 0 );
1185
1186             /* menus, FIXME: names of wine.conf entries are bogus */
1187
1188             /* size of the menu (MDI) buttons */
1189             lpnm->iMenuWidth = GetSystemMetrics(SM_CXMENUSIZE);
1190             lpnm->iMenuHeight = GetSystemMetrics(SM_CYMENUSIZE);
1191
1192             /* menu font metrics */
1193             SystemParametersInfoA( SPI_GETICONTITLELOGFONT, 0, (LPVOID)&(lpnm->lfMenuFont), 0 );
1194             GetProfileStringA( "Desktop", "MenuFont",
1195                                (TWEAK_WineLook > WIN31_LOOK) ? lpnm->lfCaptionFont.lfFaceName : "System",
1196                                lpnm->lfMenuFont.lfFaceName, LF_FACESIZE );
1197             lpnm->lfMenuFont.lfHeight = -GetProfileIntA( "Desktop", "MenuFontSize", 11 );
1198             lpnm->lfMenuFont.lfWeight = (TWEAK_WineLook > WIN31_LOOK) ? FW_NORMAL : FW_BOLD;
1199
1200             /* status bar font metrics */
1201             SystemParametersInfoA( SPI_GETICONTITLELOGFONT, 0,
1202                                    (LPVOID)&(lpnm->lfStatusFont), 0 );
1203             /* message font metrics */
1204             SystemParametersInfoA( SPI_GETICONTITLELOGFONT, 0,
1205                                    (LPVOID)&(lpnm->lfMessageFont), 0 );
1206         }
1207         else
1208         {
1209             WARN("size mismatch !! (is %d; should be %d)\n", lpnm->cbSize, sizeof(NONCLIENTMETRICSA));
1210             /* FIXME: SetLastError? */
1211             ret = FALSE;
1212         }
1213         break;
1214     }
1215     WINE_SPI_FIXME(SPI_SETNONCLIENTMETRICS);    /*     42  WINVER >= 0x400 */
1216
1217     WINE_SPI_FIXME(SPI_GETMINIMIZEDMETRICS);    /*     43  WINVER >= 0x400 */
1218     WINE_SPI_FIXME(SPI_SETMINIMIZEDMETRICS);    /*     44  WINVER >= 0x400 */
1219
1220     case SPI_GETICONMETRICS:                    /*     45  WINVER >= 0x400 */
1221     {
1222         LPICONMETRICSA lpIcon = pvParam;
1223         if(lpIcon && lpIcon->cbSize == sizeof(*lpIcon))
1224         {
1225             SystemParametersInfoA( SPI_ICONHORIZONTALSPACING, 0,
1226                                    &lpIcon->iHorzSpacing, FALSE );
1227             SystemParametersInfoA( SPI_ICONVERTICALSPACING, 0,
1228                                    &lpIcon->iVertSpacing, FALSE );
1229             SystemParametersInfoA( SPI_GETICONTITLEWRAP, 0,
1230                                    &lpIcon->iTitleWrap, FALSE );
1231             SystemParametersInfoA( SPI_GETICONTITLELOGFONT, 0,
1232                                    &lpIcon->lfFont, FALSE );
1233         }
1234         else
1235         {
1236             ret = FALSE;
1237         }
1238         break;
1239     }
1240     WINE_SPI_FIXME(SPI_SETICONMETRICS);         /*     46  WINVER >= 0x400 */
1241
1242     case SPI_SETWORKAREA:                       /*     47  WINVER >= 0x400 */
1243     {
1244         char buf[20];
1245         RECT *pr = (RECT *) pvParam;
1246
1247         spi_idx = SPI_SETWORKAREA_IDX;
1248         sprintf(buf, "%d %d %d %d",
1249                 pr->left, pr->top,
1250                 pr->right, pr->bottom );
1251
1252         if (SYSPARAMS_Save( SPI_SETWORKAREA_REGKEY,
1253                             SPI_SETWORKAREA_VALNAME,
1254                             buf, fWinIni ))
1255         {
1256             CopyRect( &work_area, (RECT *)pvParam );
1257             spi_loaded[spi_idx] = TRUE;
1258         }
1259         else
1260             ret = FALSE;
1261         break;
1262     }
1263
1264     case SPI_GETWORKAREA:                       /*     48  WINVER >= 0x400 */
1265       spi_idx = SPI_SETWORKAREA_IDX;
1266       if (!spi_loaded[spi_idx])
1267       {
1268           char buf[20];
1269
1270           SetRect( &work_area, 0, 0,
1271                    GetSystemMetrics( SM_CXSCREEN ),
1272                    GetSystemMetrics( SM_CYSCREEN ) );
1273
1274           if (SYSPARAMS_Load( SPI_SETWORKAREA_REGKEY,
1275                               SPI_SETWORKAREA_VALNAME,
1276                               buf ))
1277           {
1278               sscanf( buf, "%d %d %d %d",
1279                       &work_area.left, &work_area.top,
1280                       &work_area.right, &work_area.bottom );
1281           }
1282           spi_loaded[spi_idx] = TRUE;
1283       }
1284       CopyRect( (RECT *)pvParam, &work_area );
1285
1286       break;
1287
1288     WINE_SPI_FIXME(SPI_SETPENWINDOWS);          /*     49  WINVER >= 0x400 */
1289
1290     case SPI_GETFILTERKEYS:                     /*     50 */
1291     {
1292         LPFILTERKEYS lpFilterKeys = (LPFILTERKEYS)pvParam;
1293         WARN("SPI_GETFILTERKEYS not fully implemented\n");
1294         if (lpFilterKeys->cbSize == sizeof(FILTERKEYS))
1295         {
1296             /* Indicate that no FilterKeys feature available */
1297             lpFilterKeys->dwFlags = 0;
1298             lpFilterKeys->iWaitMSec = 0;
1299             lpFilterKeys->iDelayMSec = 0;
1300             lpFilterKeys->iRepeatMSec = 0;
1301             lpFilterKeys->iBounceMSec = 0;
1302          }
1303         else
1304         {
1305             ret = FALSE;
1306         }
1307         break;
1308     }
1309     WINE_SPI_FIXME(SPI_SETFILTERKEYS);          /*     51 */
1310
1311     case SPI_GETTOGGLEKEYS:                     /*     52 */
1312     {
1313         LPTOGGLEKEYS lpToggleKeys = (LPTOGGLEKEYS)pvParam;
1314         WARN("SPI_GETTOGGLEKEYS not fully implemented\n");
1315         if (lpToggleKeys->cbSize == sizeof(TOGGLEKEYS))
1316         {
1317             /* Indicate that no ToggleKeys feature available */
1318             lpToggleKeys->dwFlags = 0;
1319         }
1320         else
1321         {
1322             ret = FALSE;
1323         }
1324         break;
1325     }
1326     WINE_SPI_FIXME(SPI_SETTOGGLEKEYS);          /*     53 */
1327
1328     case SPI_GETMOUSEKEYS:                      /*     54 */
1329     {
1330         LPMOUSEKEYS lpMouseKeys = (LPMOUSEKEYS)pvParam;
1331         WARN("SPI_GETMOUSEKEYS not fully implemented\n");
1332         if (lpMouseKeys->cbSize == sizeof(MOUSEKEYS))
1333         {
1334             /* Indicate that no MouseKeys feature available */
1335             lpMouseKeys->dwFlags = 0;
1336             lpMouseKeys->iMaxSpeed = 360;
1337             lpMouseKeys->iTimeToMaxSpeed = 1000;
1338             lpMouseKeys->iCtrlSpeed = 0;
1339             lpMouseKeys->dwReserved1 = 0;
1340             lpMouseKeys->dwReserved2 = 0;
1341         }
1342         else
1343         {
1344             ret = FALSE;
1345         }
1346         break;
1347     }
1348     WINE_SPI_FIXME(SPI_SETMOUSEKEYS);           /*     55 */
1349
1350     case SPI_GETSHOWSOUNDS:                     /*     56 */
1351         spi_idx = SPI_SETSHOWSOUNDS_IDX;
1352
1353         if (!spi_loaded[spi_idx])
1354         {
1355             char buf[10];
1356
1357             if (SYSPARAMS_Load( SPI_SETSHOWSOUNDS_REGKEY,
1358                                 SPI_SETSHOWSOUNDS_VALNAME, buf ))
1359             {
1360                 SYSMETRICS_Set( SM_SHOWSOUNDS, atoi( buf ) );
1361             }
1362             spi_loaded[spi_idx] = TRUE;
1363         }
1364
1365
1366         *(INT *)pvParam = GetSystemMetrics( SM_SHOWSOUNDS );
1367         break;
1368
1369     case SPI_SETSHOWSOUNDS:                     /*     57 */
1370     {
1371         char buf[10];
1372         spi_idx = SPI_SETSHOWSOUNDS_IDX;
1373
1374         sprintf(buf, "%u", uiParam);
1375         if (SYSPARAMS_Save( SPI_SETSHOWSOUNDS_REGKEY,
1376                             SPI_SETSHOWSOUNDS_VALNAME,
1377                             buf, fWinIni ))
1378         {
1379             SYSMETRICS_Set( SM_SHOWSOUNDS, uiParam );
1380             spi_loaded[spi_idx] = TRUE;
1381         }
1382         else
1383             ret = FALSE;
1384         break;
1385     }
1386
1387     case SPI_GETSTICKYKEYS:                     /*     58 */
1388     {
1389         LPSTICKYKEYS lpStickyKeys = (LPSTICKYKEYS)pvParam;
1390         WARN("SPI_GETSTICKYKEYS not fully implemented\n");
1391         if (lpStickyKeys->cbSize == sizeof(STICKYKEYS))
1392         {
1393             /* Indicate that no StickyKeys feature available */
1394             lpStickyKeys->dwFlags = 0;
1395         }
1396         else
1397         {
1398             ret = FALSE;
1399         }
1400         break;
1401     }
1402     WINE_SPI_FIXME(SPI_SETSTICKYKEYS);          /*     59 */
1403
1404     case SPI_GETACCESSTIMEOUT:                  /*     60 */
1405     {
1406         LPACCESSTIMEOUT lpAccessTimeout = (LPACCESSTIMEOUT)pvParam;
1407         WARN("SPI_GETACCESSTIMEOUT not fully implemented\n");
1408         if (lpAccessTimeout->cbSize == sizeof(ACCESSTIMEOUT))
1409         {
1410             /* Indicate that no accessibility features timeout is available */
1411             lpAccessTimeout->dwFlags = 0;
1412             lpAccessTimeout->iTimeOutMSec = 0;
1413         }
1414         else
1415         {
1416             ret = FALSE;
1417         }
1418         break;
1419     }
1420     WINE_SPI_FIXME(SPI_SETACCESSTIMEOUT);       /*     61 */
1421
1422     case SPI_GETSERIALKEYS:                     /*     62  WINVER >= 0x400 */
1423     {
1424         LPSERIALKEYSA lpSerialKeysA = (LPSERIALKEYSA)pvParam;
1425         WARN("SPI_GETSERIALKEYS not fully implemented\n");
1426         if (lpSerialKeysA->cbSize == sizeof(SERIALKEYSA))
1427         {
1428             /* Indicate that no SerialKeys feature available */
1429             lpSerialKeysA->dwFlags = 0;
1430             lpSerialKeysA->lpszActivePort = NULL;
1431             lpSerialKeysA->lpszPort = NULL;
1432             lpSerialKeysA->iBaudRate = 0;
1433             lpSerialKeysA->iPortState = 0;
1434         }
1435         else
1436         {
1437             ret = FALSE;
1438         }
1439         break;
1440     }
1441     WINE_SPI_FIXME(SPI_SETSERIALKEYS);          /*     63  WINVER >= 0x400 */
1442
1443     case SPI_GETSOUNDSENTRY:                    /*     64 */
1444     {
1445         LPSOUNDSENTRYA lpSoundSentryA = (LPSOUNDSENTRYA)pvParam;
1446         WARN("SPI_GETSOUNDSENTRY not fully implemented\n");
1447         if (lpSoundSentryA->cbSize == sizeof(SOUNDSENTRYA))
1448         {
1449             /* Indicate that no SoundSentry feature available */
1450             lpSoundSentryA->dwFlags = 0;
1451             lpSoundSentryA->iFSTextEffect = 0;
1452             lpSoundSentryA->iFSTextEffectMSec = 0;
1453             lpSoundSentryA->iFSTextEffectColorBits = 0;
1454             lpSoundSentryA->iFSGrafEffect = 0;
1455             lpSoundSentryA->iFSGrafEffectMSec = 0;
1456             lpSoundSentryA->iFSGrafEffectColor = 0;
1457             lpSoundSentryA->iWindowsEffect = 0;
1458             lpSoundSentryA->iWindowsEffectMSec = 0;
1459             lpSoundSentryA->lpszWindowsEffectDLL = 0;
1460             lpSoundSentryA->iWindowsEffectOrdinal = 0;
1461         }
1462         else
1463         {
1464             ret = FALSE;
1465         }
1466         break;
1467     }
1468     WINE_SPI_FIXME(SPI_SETSOUNDSENTRY);         /*     65 */
1469
1470     case SPI_GETHIGHCONTRAST:                   /*     66  WINVER >= 0x400 */
1471     {
1472         LPHIGHCONTRASTA lpHighContrastA = (LPHIGHCONTRASTA)pvParam;
1473         WARN("SPI_GETHIGHCONTRAST not fully implemented\n");
1474         if (lpHighContrastA->cbSize == sizeof(HIGHCONTRASTA))
1475         {
1476             /* Indicate that no high contrast feature available */
1477             lpHighContrastA->dwFlags = 0;
1478             lpHighContrastA->lpszDefaultScheme = NULL;
1479         }
1480         else
1481         {
1482             ret = FALSE;
1483         }
1484         break;
1485     }
1486     WINE_SPI_FIXME(SPI_SETHIGHCONTRAST);        /*     67  WINVER >= 0x400 */
1487
1488     case SPI_GETKEYBOARDPREF:                   /*     68  WINVER >= 0x400 */
1489         spi_idx = SPI_SETKEYBOARDPREF_IDX;
1490         if (!spi_loaded[spi_idx])
1491         {
1492             char buf[5];
1493
1494             if (SYSPARAMS_Load( SPI_SETKEYBOARDPREF_REGKEY,
1495                                 SPI_SETKEYBOARDPREF_VALNAME, buf ))
1496                 keyboard_pref  = atoi(buf);
1497             spi_loaded[spi_idx] = TRUE;
1498         }
1499
1500         *(BOOL *)pvParam = keyboard_pref;
1501         break;
1502
1503     case SPI_SETKEYBOARDPREF:                   /*     69  WINVER >= 0x400 */
1504     {
1505         char buf[5];
1506
1507         spi_idx = SPI_SETKEYBOARDPREF_IDX;
1508         sprintf(buf, "%u", uiParam);
1509         if (SYSPARAMS_Save( SPI_SETKEYBOARDPREF_REGKEY,
1510                             SPI_SETKEYBOARDPREF_VALNAME,
1511                             buf, fWinIni ))
1512         {
1513             keyboard_pref = uiParam;
1514             spi_loaded[spi_idx] = TRUE;
1515         }
1516         else
1517             ret = FALSE;
1518         break;
1519     }
1520
1521     case SPI_GETSCREENREADER:                   /*     70  WINVER >= 0x400 */
1522         spi_idx = SPI_SETSCREENREADER_IDX;
1523         if (!spi_loaded[spi_idx])
1524         {
1525             char buf[5];
1526
1527             if (SYSPARAMS_Load( SPI_SETSCREENREADER_REGKEY,
1528                                 SPI_SETSCREENREADER_VALNAME, buf ))
1529                 screen_reader  = atoi(buf);
1530             spi_loaded[spi_idx] = TRUE;
1531         }
1532
1533         *(BOOL *)pvParam = screen_reader;
1534         break;
1535
1536     case SPI_SETSCREENREADER:                   /*     71  WINVER >= 0x400 */
1537     {
1538         char buf[5];
1539
1540         spi_idx = SPI_SETSCREENREADER_IDX;
1541         sprintf(buf, "%u", uiParam);
1542         if (SYSPARAMS_Save( SPI_SETSCREENREADER_REGKEY,
1543                             SPI_SETSCREENREADER_VALNAME,
1544                             buf, fWinIni ))
1545         {
1546             screen_reader = uiParam;
1547             spi_loaded[spi_idx] = TRUE;
1548         }
1549         else
1550             ret = FALSE;
1551         break;
1552     }
1553
1554     case SPI_GETANIMATION:                      /*     72  WINVER >= 0x400 */
1555     {
1556         LPANIMATIONINFO lpAnimInfo = (LPANIMATIONINFO)pvParam;
1557
1558         /* Tell it "disabled" */
1559         if (lpAnimInfo->cbSize == sizeof(ANIMATIONINFO))
1560             lpAnimInfo->iMinAnimate = 0; /* Minimise and restore animation is disabled (nonzero == enabled) */
1561         else
1562             ret = FALSE;
1563         break;
1564     }
1565     WINE_SPI_WARN(SPI_SETANIMATION);            /*     73  WINVER >= 0x400 */
1566
1567     WINE_SPI_FIXME(SPI_GETFONTSMOOTHING);       /*     74  WINVER >= 0x400 */
1568     WINE_SPI_FIXME(SPI_SETFONTSMOOTHING);       /*     75  WINVER >= 0x400 */
1569
1570     WINE_SPI_FIXME(SPI_SETDRAGWIDTH);           /*     76  WINVER >= 0x400 */
1571     WINE_SPI_FIXME(SPI_SETDRAGHEIGHT);          /*     77  WINVER >= 0x400 */
1572
1573     WINE_SPI_FIXME(SPI_SETHANDHELD);            /*     78  WINVER >= 0x400 */
1574
1575     WINE_SPI_FIXME(SPI_GETLOWPOWERTIMEOUT);     /*     79  WINVER >= 0x400 */
1576     WINE_SPI_FIXME(SPI_GETPOWEROFFTIMEOUT);     /*     80  WINVER >= 0x400 */
1577     WINE_SPI_FIXME(SPI_SETLOWPOWERTIMEOUT);     /*     81  WINVER >= 0x400 */
1578     WINE_SPI_FIXME(SPI_SETPOWEROFFTIMEOUT);     /*     82  WINVER >= 0x400 */
1579     WINE_SPI_FIXME(SPI_GETLOWPOWERACTIVE);      /*     83  WINVER >= 0x400 */
1580     WINE_SPI_FIXME(SPI_GETPOWEROFFACTIVE);      /*     84  WINVER >= 0x400 */
1581     WINE_SPI_FIXME(SPI_SETLOWPOWERACTIVE);      /*     85  WINVER >= 0x400 */
1582     WINE_SPI_FIXME(SPI_SETPOWEROFFACTIVE);      /*     86  WINVER >= 0x400 */
1583
1584     WINE_SPI_FIXME(SPI_SETCURSORS);             /*     87  WINVER >= 0x400 */
1585     WINE_SPI_FIXME(SPI_SETICONS);               /*     88  WINVER >= 0x400 */
1586
1587     case SPI_GETDEFAULTINPUTLANG:       /*     89  WINVER >= 0x400 */
1588         ret = GetKeyboardLayout(0);
1589         break;
1590
1591     WINE_SPI_FIXME(SPI_SETDEFAULTINPUTLANG);    /*     90  WINVER >= 0x400 */
1592
1593     WINE_SPI_FIXME(SPI_SETLANGTOGGLE);          /*     91  WINVER >= 0x400 */
1594
1595     case SPI_GETWINDOWSEXTENSION:               /*     92  WINVER >= 0x400 */
1596         WARN("pretend no support for Win9x Plus! for now.\n");
1597         ret = FALSE; /* yes, this is the result value */
1598         break;
1599
1600     WINE_SPI_FIXME(SPI_SETMOUSETRAILS);         /*     93  WINVER >= 0x400 */
1601     WINE_SPI_FIXME(SPI_GETMOUSETRAILS);         /*     94  WINVER >= 0x400 */
1602
1603     case SPI_SETSCREENSAVERRUNNING:             /*     97  WINVER >= 0x400 */
1604         {
1605         /* SPI_SCREENSAVERRUNNING is an alias for SPI_SETSCREENSAVERRUNNING */
1606         char buf[5];
1607
1608         spi_idx = SPI_SETSCREENSAVERRUNNING_IDX;
1609         sprintf(buf, "%u", uiParam);
1610
1611         /* save only temporarily */
1612         if (SYSPARAMS_Save( SPI_SETSCREENSAVERRUNNING_REGKEY,
1613                             SPI_SETSCREENSAVERRUNNING_VALNAME,
1614                             buf, 0 ))
1615         {
1616             screensaver_running = uiParam;
1617             spi_loaded[spi_idx] = TRUE;
1618         }
1619         else
1620             ret = FALSE;
1621         break;
1622     }
1623
1624     case SPI_GETMOUSEHOVERWIDTH:                /*     98  _WIN32_WINNT >= 0x400 || _WIN32_WINDOW > 0x400 */
1625         *(UINT *)pvParam = 4;
1626         break;
1627     WINE_SPI_FIXME(SPI_SETMOUSEHOVERWIDTH);     /*     99  _WIN32_WINNT >= 0x400 || _WIN32_WINDOW > 0x400 */
1628
1629     case SPI_GETMOUSEHOVERHEIGHT:               /*    100  _WIN32_WINNT >= 0x400 || _WIN32_WINDOW > 0x400 */
1630         *(UINT *)pvParam = 4;
1631         break;
1632     WINE_SPI_FIXME(SPI_SETMOUSEHOVERHEIGHT);    /*    101  _WIN32_WINNT >= 0x400 || _WIN32_WINDOW > 0x400 */
1633
1634     case SPI_GETMOUSEHOVERTIME:                 /*    102  _WIN32_WINNT >= 0x400 || _WIN32_WINDOW > 0x400 */
1635         *(UINT *)pvParam = 400; /* default for menu dropdowns */
1636         break;
1637     WINE_SPI_FIXME(SPI_SETMOUSEHOVERTIME);      /*    103  _WIN32_WINNT >= 0x400 || _WIN32_WINDOW > 0x400 */
1638
1639     case SPI_GETWHEELSCROLLLINES:               /*    104  _WIN32_WINNT >= 0x400 || _WIN32_WINDOW > 0x400 */
1640         *(UINT *)pvParam = 3; /* default for num scroll lines */
1641         break;
1642
1643     WINE_SPI_FIXME(SPI_SETWHEELSCROLLLINES);    /*    105  _WIN32_WINNT >= 0x400 || _WIN32_WINDOW > 0x400 */
1644
1645     case SPI_GETMENUSHOWDELAY:                  /*    106  _WIN32_WINNT >= 0x400 || _WIN32_WINDOW > 0x400 */
1646         *(UINT *)pvParam = 400; /* Tested against Windows NT 4.0 and Windows 2000 */
1647         break;
1648
1649     WINE_SPI_FIXME(SPI_GETSHOWIMEUI);           /*    110  _WIN32_WINNT >= 0x400 || _WIN32_WINDOW > 0x400 */
1650     WINE_SPI_FIXME(SPI_SETSHOWIMEUI);           /*    111  _WIN32_WINNT >= 0x400 || _WIN32_WINDOW > 0x400 */
1651
1652     case SPI_GETSCREENSAVERRUNNING:             /*    114  _WIN32_WINNT >= 0x500 || _WIN32_WINDOW > 0x400 */
1653         spi_idx = SPI_SETSCREENSAVERRUNNING_IDX;
1654         if (!spi_loaded[spi_idx])
1655         {
1656             char buf[5];
1657
1658             if (SYSPARAMS_Load( SPI_SETSCREENSAVERRUNNING_REGKEY,
1659                                 SPI_SETSCREENSAVERRUNNING_VALNAME, buf ))
1660                 screensaver_running  = atoi( buf );
1661             spi_loaded[spi_idx] = TRUE;
1662         }
1663
1664         *(BOOL *)pvParam = screensaver_running;
1665         break;
1666
1667     case SPI_GETDESKWALLPAPER:                  /*    115  _WIN32_WINNT >= 0x500 || _WIN32_WINDOW > 0x400 */
1668     {
1669         char buf[MAX_PATH];
1670
1671         if (uiParam > MAX_PATH)
1672         {
1673             uiParam = MAX_PATH;
1674         }
1675
1676         if (SYSPARAMS_Load(SPI_SETDESKWALLPAPER_REGKEY, SPI_SETDESKWALLPAPER_VALNAME, buf))
1677         {
1678             strncpy((char*)pvParam, buf, uiParam);
1679         }
1680         else
1681         {
1682             /* Return an empty string */
1683             memset((char*)pvParam, 0, uiParam);
1684         }
1685
1686         break;
1687     }
1688
1689     WINE_SPI_FIXME(SPI_GETACTIVEWINDOWTRACKING);/* 0x1000  _WIN32_WINNT >= 0x500 || _WIN32_WINDOW > 0x400 */
1690     WINE_SPI_FIXME(SPI_SETACTIVEWINDOWTRACKING);/* 0x1001  _WIN32_WINNT >= 0x500 || _WIN32_WINDOW > 0x400 */
1691     WINE_SPI_FIXME(SPI_GETMENUANIMATION);       /* 0x1002  _WIN32_WINNT >= 0x500 || _WIN32_WINDOW > 0x400 */
1692     WINE_SPI_FIXME(SPI_SETMENUANIMATION);       /* 0x1003  _WIN32_WINNT >= 0x500 || _WIN32_WINDOW > 0x400 */
1693     WINE_SPI_FIXME(SPI_GETCOMBOBOXANIMATION);   /* 0x1004  _WIN32_WINNT >= 0x500 || _WIN32_WINDOW > 0x400 */
1694     WINE_SPI_FIXME(SPI_SETCOMBOBOXANIMATION);   /* 0x1005  _WIN32_WINNT >= 0x500 || _WIN32_WINDOW > 0x400 */
1695     WINE_SPI_FIXME(SPI_GETLISTBOXSMOOTHSCROLLING);/* 0x1006  _WIN32_WINNT >= 0x500 || _WIN32_WINDOW > 0x400 */
1696     WINE_SPI_FIXME(SPI_SETLISTBOXSMOOTHSCROLLING);/* 0x1007  _WIN32_WINNT >= 0x500 || _WIN32_WINDOW > 0x400 */
1697     WINE_SPI_FIXME(SPI_GETGRADIENTCAPTIONS);    /* 0x1008  _WIN32_WINNT >= 0x500 || _WIN32_WINDOW > 0x400 */
1698     WINE_SPI_FIXME(SPI_SETGRADIENTCAPTIONS);    /* 0x1009  _WIN32_WINNT >= 0x500 || _WIN32_WINDOW > 0x400 */
1699     WINE_SPI_FIXME(SPI_GETMENUUNDERLINES);      /* 0x100A  _WIN32_WINNT >= 0x500 || _WIN32_WINDOW > 0x400 */
1700     WINE_SPI_FIXME(SPI_SETMENUUNDERLINES);      /* 0x100B  _WIN32_WINNT >= 0x500 || _WIN32_WINDOW > 0x400 */
1701     WINE_SPI_FIXME(SPI_GETACTIVEWNDTRKZORDER);  /* 0x100C  _WIN32_WINNT >= 0x500 || _WIN32_WINDOW > 0x400 */
1702     WINE_SPI_FIXME(SPI_SETACTIVEWNDTRKZORDER);  /* 0x100D  _WIN32_WINNT >= 0x500 || _WIN32_WINDOW > 0x400 */
1703     WINE_SPI_FIXME(SPI_GETHOTTRACKING);         /* 0x100E  _WIN32_WINNT >= 0x500 || _WIN32_WINDOW > 0x400 */
1704     WINE_SPI_FIXME(SPI_SETHOTTRACKING);         /* 0x100F  _WIN32_WINNT >= 0x500 || _WIN32_WINDOW > 0x400 */
1705     WINE_SPI_FIXME(SPI_GETFOREGROUNDLOCKTIMEOUT);/* 0x2000  _WIN32_WINNT >= 0x500 || _WIN32_WINDOW > 0x400 */
1706     WINE_SPI_FIXME(SPI_SETFOREGROUNDLOCKTIMEOUT);/* 0x2001  _WIN32_WINNT >= 0x500 || _WIN32_WINDOW > 0x400 */
1707     WINE_SPI_FIXME(SPI_GETACTIVEWNDTRKTIMEOUT); /* 0x2002  _WIN32_WINNT >= 0x500 || _WIN32_WINDOW > 0x400 */
1708     WINE_SPI_FIXME(SPI_SETACTIVEWNDTRKTIMEOUT); /* 0x2003  _WIN32_WINNT >= 0x500 || _WIN32_WINDOW > 0x400 */
1709     WINE_SPI_FIXME(SPI_GETFOREGROUNDFLASHCOUNT);/* 0x2004  _WIN32_WINNT >= 0x500 || _WIN32_WINDOW > 0x400 */
1710     WINE_SPI_FIXME(SPI_SETFOREGROUNDFLASHCOUNT);/* 0x2005  _WIN32_WINNT >= 0x500 || _WIN32_WINDOW > 0x400 */
1711
1712     default:
1713         FIXME( "Unknown action: %u\n", uiAction );
1714         SetLastError( ERROR_INVALID_SPI_VALUE );
1715         ret = FALSE;
1716         break;
1717     }
1718
1719     if (ret)
1720         SYSPARAMS_NotifyChange( uiAction, fWinIni );
1721     return ret;
1722
1723 #undef WINE_SPI_FIXME
1724 #undef WINE_SPI_WARN
1725 }
1726
1727
1728 /***********************************************************************
1729  *              SystemParametersInfo (USER.483)
1730  */
1731 BOOL16 WINAPI SystemParametersInfo16( UINT16 uAction, UINT16 uParam,
1732                                       LPVOID lpvParam, UINT16 fuWinIni )
1733 {
1734     BOOL16 ret;
1735
1736     TRACE("(%u, %u, %p, %u)\n", uAction, uParam, lpvParam, fuWinIni);
1737
1738     switch (uAction)
1739     {
1740     case SPI_GETBEEP:                           /*      1 */
1741     case SPI_GETSCREENSAVEACTIVE:               /*     16 */
1742     case SPI_GETICONTITLEWRAP:                  /*     25 */
1743     case SPI_GETMENUDROPALIGNMENT:              /*     27 */
1744     case SPI_GETFASTTASKSWITCH:                 /*     35 */
1745     case SPI_GETDRAGFULLWINDOWS:                /*     38  WINVER >= 0x0400 */
1746     {
1747         BOOL tmp;
1748         ret = SystemParametersInfoA( uAction, uParam, lpvParam ? &tmp : NULL, fuWinIni );
1749         if (ret && lpvParam)
1750             *(BOOL16 *)lpvParam = tmp;
1751         break;
1752     }
1753
1754     case SPI_GETBORDER:                         /*      5 */
1755     case SPI_ICONHORIZONTALSPACING:             /*     13 */
1756     case SPI_GETSCREENSAVETIMEOUT:              /*     14 */
1757     case SPI_GETGRIDGRANULARITY:                /*     18 */
1758     case SPI_GETKEYBOARDDELAY:                  /*     22 */
1759     case SPI_ICONVERTICALSPACING:               /*     24 */
1760     {
1761         INT tmp;
1762         ret = SystemParametersInfoA( uAction, uParam, lpvParam ? &tmp : NULL, fuWinIni );
1763         if (ret && lpvParam)
1764             *(INT16 *)lpvParam = tmp;
1765         break;
1766     }
1767
1768     case SPI_GETKEYBOARDSPEED:                  /*     10 */
1769     {
1770         DWORD tmp;
1771         ret = SystemParametersInfoA( uAction, uParam, lpvParam ? &tmp : NULL, fuWinIni );
1772         if (ret && lpvParam)
1773             *(WORD *)lpvParam = tmp;
1774         break;
1775     }
1776
1777     case SPI_GETICONTITLELOGFONT:               /*     31 */
1778     {
1779         LOGFONTA tmp;
1780         ret = SystemParametersInfoA( uAction, uParam, lpvParam ? &tmp : NULL, fuWinIni );
1781         if (ret && lpvParam)
1782             SYSPARAMS_LogFont32ATo16( &tmp, (LPLOGFONT16)lpvParam );
1783         break;
1784     }
1785
1786     case SPI_GETNONCLIENTMETRICS:               /*     41  WINVER >= 0x400 */
1787     {
1788         NONCLIENTMETRICSA tmp;
1789         LPNONCLIENTMETRICS16 lpnm16 = (LPNONCLIENTMETRICS16)lpvParam;
1790         if (lpnm16 && lpnm16->cbSize == sizeof(NONCLIENTMETRICS16))
1791         {
1792             tmp.cbSize = sizeof(NONCLIENTMETRICSA);
1793             ret = SystemParametersInfoA( uAction, uParam, &tmp, fuWinIni );
1794             if (ret)
1795                 SYSPARAMS_NonClientMetrics32ATo16( &tmp, lpnm16 );
1796         }
1797         else /* winfile 95 sets cbSize to 340 */
1798             ret = SystemParametersInfoA( uAction, uParam, lpvParam, fuWinIni );
1799         break;
1800     }
1801
1802     case SPI_GETWORKAREA:                       /*     48  WINVER >= 0x400 */
1803     {
1804         RECT tmp;
1805         ret = SystemParametersInfoA( uAction, uParam, lpvParam ? &tmp : NULL, fuWinIni );
1806         if (ret && lpvParam)
1807             CONV_RECT32TO16( &tmp, (RECT16 *)lpvParam );
1808         break;
1809     }
1810
1811     case SPI_GETMOUSEHOVERWIDTH:                /*     98  _WIN32_WINNT >= 0x400 || _WIN32_WINDOW > 0x400 */
1812     case SPI_GETMOUSEHOVERHEIGHT:               /*    100  _WIN32_WINNT >= 0x400 || _WIN32_WINDOW > 0x400 */
1813     case SPI_GETMOUSEHOVERTIME:                 /*    102  _WIN32_WINNT >= 0x400 || _WIN32_WINDOW > 0x400 */
1814     {
1815         UINT tmp;
1816         ret = SystemParametersInfoA( uAction, uParam, lpvParam ? &tmp : NULL, fuWinIni );
1817         if (ret && lpvParam)
1818             *(UINT16 *)lpvParam = tmp;
1819         break;
1820     }
1821
1822     default:
1823         ret = SystemParametersInfoA( uAction, uParam, lpvParam, fuWinIni );
1824     }
1825
1826     return ret;
1827 }
1828
1829 /***********************************************************************
1830  *              SystemParametersInfoW (USER32.@)
1831  */
1832 BOOL WINAPI SystemParametersInfoW( UINT uiAction, UINT uiParam,
1833                                    PVOID pvParam, UINT fuWinIni )
1834 {
1835     BOOL ret;
1836
1837     TRACE("(%u, %u, %p, %u)\n", uiAction, uiParam, pvParam, fuWinIni);
1838
1839     switch (uiAction)
1840     {
1841     case SPI_SETDESKWALLPAPER:                  /*     20 */
1842     case SPI_SETDESKPATTERN:                    /*     21 */
1843     {
1844         char buffer[256];
1845         if (pvParam)
1846             if (!WideCharToMultiByte( CP_ACP, 0, (LPWSTR)pvParam, -1,
1847                                       buffer, sizeof(buffer), NULL, NULL ))
1848                 buffer[sizeof(buffer)-1] = 0;
1849         ret = SystemParametersInfoA( uiAction, uiParam, pvParam ? buffer : NULL, fuWinIni );
1850         break;
1851     }
1852
1853     case SPI_GETICONTITLELOGFONT:               /*     31 */
1854     {
1855         LOGFONTA tmp;
1856         ret = SystemParametersInfoA( uiAction, uiParam, pvParam ? &tmp : NULL, fuWinIni );
1857         if (ret && pvParam)
1858             SYSPARAMS_LogFont32ATo32W( &tmp, (LPLOGFONTW)pvParam );
1859         break;
1860     }
1861
1862     case SPI_GETNONCLIENTMETRICS:               /*     41  WINVER >= 0x400 */
1863     {
1864         NONCLIENTMETRICSA tmp;
1865         LPNONCLIENTMETRICSW lpnmW = (LPNONCLIENTMETRICSW)pvParam;
1866         if (lpnmW && lpnmW->cbSize == sizeof(NONCLIENTMETRICSW))
1867         {
1868             tmp.cbSize = sizeof(NONCLIENTMETRICSA);
1869             ret = SystemParametersInfoA( uiAction, uiParam, &tmp, fuWinIni );
1870             if (ret)
1871                 SYSPARAMS_NonClientMetrics32ATo32W( &tmp, lpnmW );
1872         }
1873         else
1874             ret = FALSE;
1875         break;
1876     }
1877
1878     case SPI_GETICONMETRICS:                    /*     45  WINVER >= 0x400 */
1879     {
1880         ICONMETRICSA tmp;
1881         LPICONMETRICSW lpimW = (LPICONMETRICSW)pvParam;
1882         if (lpimW && lpimW->cbSize == sizeof(ICONMETRICSW))
1883         {
1884             tmp.cbSize = sizeof(ICONMETRICSA);
1885             ret = SystemParametersInfoA( uiAction, uiParam, &tmp, fuWinIni );
1886             if (ret)
1887             {
1888                 lpimW->iHorzSpacing = tmp.iHorzSpacing;
1889                 lpimW->iVertSpacing = tmp.iVertSpacing;
1890                 lpimW->iTitleWrap   = tmp.iTitleWrap;
1891                 SYSPARAMS_LogFont32ATo32W( &tmp.lfFont, &lpimW->lfFont );
1892             }
1893         }
1894         else
1895             ret = FALSE;
1896         break;
1897     }
1898
1899     case SPI_GETHIGHCONTRAST:                   /*     66  WINVER >= 0x400 */
1900     {
1901         HIGHCONTRASTA tmp;
1902         LPHIGHCONTRASTW lphcW = (LPHIGHCONTRASTW)pvParam;
1903         if (lphcW && lphcW->cbSize == sizeof(HIGHCONTRASTW))
1904         {
1905             tmp.cbSize = sizeof(HIGHCONTRASTA);
1906             ret = SystemParametersInfoA( uiAction, uiParam, &tmp, fuWinIni );
1907             if (ret)
1908             {
1909                 lphcW->dwFlags = tmp.dwFlags;
1910                 lphcW->lpszDefaultScheme = NULL;  /* FIXME? */
1911             }
1912         }
1913         else
1914             ret = FALSE;
1915         break;
1916     }
1917
1918     default:
1919         ret = SystemParametersInfoA( uiAction, uiParam, pvParam, fuWinIni );
1920         break;
1921     }
1922     return ret;
1923 }
1924
1925
1926 /**********************************************************************
1927  *              SetDoubleClickTime (USER32.@)
1928  */
1929 BOOL WINAPI SetDoubleClickTime( UINT interval )
1930 {
1931     return SystemParametersInfoA(SPI_SETDOUBLECLICKTIME, interval, 0, 0);
1932 }
1933
1934
1935 /**********************************************************************
1936  *              GetDoubleClickTime (USER32.@)
1937  */
1938 UINT WINAPI GetDoubleClickTime(void)
1939 {
1940     char buf[10];
1941
1942     if (!spi_loaded[SPI_SETDOUBLECLICKTIME_IDX])
1943     {
1944         if (SYSPARAMS_Load( SPI_SETDOUBLECLICKTIME_REGKEY,
1945                             SPI_SETDOUBLECLICKTIME_VALNAME,
1946                             buf ))
1947         {
1948             double_click_time = atoi( buf );
1949             if (!double_click_time) double_click_time = 500;
1950         }
1951         spi_loaded[SPI_SETDOUBLECLICKTIME_IDX] = TRUE;
1952     }
1953     return double_click_time;
1954 }