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