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