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