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