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