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