xref: /reactos/dll/win32/shell32/dialogs/general.cpp (revision 7f021deb)
1 /*
2  *     'General' tab property sheet of Folder Options
3  *
4  * Copyright 2007 Johannes Anderwald <johannes.anderwald@reactos.org>
5  * Copyright 2016-2018 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21 
22 #include "precomp.h"
23 
24 WINE_DEFAULT_DEBUG_CHANNEL (fprop);
25 
26 static const LPCWSTR s_pszExplorerKey =
27     L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer";
28 
29 /////////////////////////////////////////////////////////////////////////////
30 // Shell settings
31 
32 EXTERN_C void
33 SHELL32_GetDefaultShellState(LPSHELLSTATE pss)
34 {
35     ZeroMemory(pss, sizeof(*pss));
36     pss->fShowAllObjects = TRUE;
37     pss->fShowExtensions = TRUE;
38     pss->fShowCompColor = TRUE;
39     pss->fDoubleClickInWebView = TRUE;
40     pss->fShowAttribCol = TRUE; // ROS defaults to Details view with this column on
41     pss->fShowInfoTip = TRUE;
42     pss->fShowSuperHidden = FALSE;
43     pss->lParamSort = SHFSF_COL_NAME;
44     pss->iSortDirection = 1;
45     pss->version = REGSHELLSTATE_VERSION;
46     pss->fSepProcess = FALSE;
47     pss->fStartPanelOn = FALSE; // Note: This should be changed to TRUE when the modern start menu is implemented
48 }
49 
50 EXTERN_C LSTATUS
51 SHELL32_WriteRegShellState(PREGSHELLSTATE prss)
52 {
53     prss->dwSize = REGSHELLSTATE_SIZE;
54     prss->ss.version = REGSHELLSTATE_VERSION;
55     return SHSetValueW(HKEY_CURRENT_USER, s_pszExplorerKey, L"ShellState",
56                        REG_BINARY, prss, prss->dwSize);
57 }
58 
59 // bDoubleClick is TRUE if "Double-click to open an item (single-click to select)".
60 // bDoubleClick is FALSE if "Single-click to open an item (point to select)".
61 //////////////////////////////////////////////////////////////////////////////
62 // API Monitor:
63 // SHLWAPI.dll	RegOpenKeyExW ( 0x000000c8, NULL, 0, MAXIMUM_ALLOWED, 0x00def234 )	ERROR_SUCCESS		0.0000243
64 // SHLWAPI.dll	RegSetValueExW ( 0x000003e8, "ShellState", 0, REG_BINARY, 0x000c2050, 36 )	ERROR_SUCCESS		0.0001028
65 // SHLWAPI.dll	RegCloseKey ( 0x000003e8 )	ERROR_SUCCESS		0.0000081
66 // Explorer.EXE	SHSettingsChanged ( 0, "ShellState" )			0.0000131
67 static BOOL
68 IntSetShellStateSettings(BOOL bDoubleClick, BOOL bUseCommonTasks)
69 {
70     SHELLSTATE shellstate;
71     shellstate.fDoubleClickInWebView = !!bDoubleClick;
72     shellstate.fWebView = !!bUseCommonTasks;
73     SHGetSetSettings(&shellstate, SSF_DOUBLECLICKINWEBVIEW | SSF_WEBVIEW, TRUE);
74 
75     SHSettingsChanged(0, L"ShellState");
76     return TRUE;
77 }
78 
79 //////////////////////////////////////////////////////////////////////////////
80 // API Monitor:
81 // SHLWAPI.dll	RegOpenKeyExW ( 0x000000c8, NULL, 0, MAXIMUM_ALLOWED, 0x0007e484 )	ERROR_SUCCESS		0.0000388
82 // SHLWAPI.dll	RegQueryValueExW ( 0x000005a8, "ShellState", NULL, 0x0007e474, 0x000c2050, 0x0007e4fc )	ERROR_SUCCESS		0.0000271
83 // SHLWAPI.dll	RegCloseKey ( 0x000005a8 )	ERROR_SUCCESS		0.0000112
84 EXTERN_C BOOL
85 SHELL32_ReadRegShellState(PREGSHELLSTATE prss)
86 {
87     DWORD dwSize = sizeof(REGSHELLSTATE);
88     LSTATUS err = SHGetValueW(HKEY_CURRENT_USER, s_pszExplorerKey,
89                               L"ShellState", NULL, prss, &dwSize);
90     return err == ERROR_SUCCESS && prss->dwSize >= REGSHELLSTATE_SIZE;
91 }
92 
93 // bIconUnderline is TRUE if "Underline icon titles only when I point at them".
94 // bIconUnderline is FALSE if "Underline icon titles consistent with my browser".
95 //////////////////////////////////////////////////////////////////////////////
96 // API Monitor:
97 // SHELL32.dll	SHRegGetUSValueW ( "Software\Microsoft\Windows\CurrentVersion\Explorer", "IconUnderline", NULL, 0x00d2f324, 0x00d2f328, FALSE, 0x00d2f32c, 4 )	ERROR_SUCCESS		0.0002484
98 // SHELL32.dll	IsDlgButtonChecked ( 0x0005009e, 30104 )	BST_CHECKED		0.0000212
99 // SHELL32.dll	SHRegSetUSValueW ( "Software\Microsoft\Windows\CurrentVersion\Explorer", "IconUnderline", 0, 0x00d2f314, 4, 6 )	ERROR_SUCCESS		0.0008300
100 // Explorer.EXE	SHSettingsChanged ( 0, "Software\Microsoft\Windows\CurrentVersion\Explorer\IconUnderline" )			0.0000092
101 static BOOL IntSetUnderlineState(BOOL bIconUnderline)
102 {
103     LSTATUS Status;
104     DWORD dwValue = (bIconUnderline ? 3 : 2), dwSize = sizeof(DWORD);
105     Status = SHRegSetUSValue(s_pszExplorerKey, L"IconUnderline", REG_NONE,
106                              &dwValue, dwSize, SHREGSET_FORCE_HKCU | SHREGSET_HKLM);
107     if (Status != ERROR_SUCCESS)
108         return FALSE;
109 
110     SHSettingsChanged(0, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\IconUnderline");
111     return TRUE;
112 }
113 
114 static BOOL IntGetUnderlineState(VOID)
115 {
116     DWORD dwValue, dwDefault = 2, dwSize = sizeof(DWORD);
117     SHRegGetUSValue(s_pszExplorerKey, L"IconUnderline", NULL, &dwValue, &dwSize, FALSE, &dwDefault, sizeof(DWORD));
118     return dwValue == 3;
119 }
120 
121 // bNewWindowMode is TRUE if "Open each folder in its own window".
122 // bNewWindowMode is FALSE if "Open each folder in the same window".
123 //////////////////////////////////////////////////////////////////////////////
124 // API Monitor:
125 // SHELL32.dll	RegCreateKeyExW ( HKEY_CURRENT_USER, "Software\Microsoft\Windows\CurrentVersion\Explorer\CabinetState", 0, NULL, 0, KEY_SET_VALUE, NULL, 0x00d2f2b8, NULL )	ERROR_SUCCESS		0.0000455
126 // SHELL32.dll	RegSetValueExW ( 0x00000854, "Settings", 0, REG_BINARY, 0x0210f170, 12 )	ERROR_SUCCESS		0.0001472
127 // SHELL32.dll	RegSetValueExW ( 0x00000854, "FullPath", 0, REG_DWORD, 0x00d2f2ac, 4 )	ERROR_SUCCESS		0.0000168
128 // SHELL32.dll	RegCloseKey ( 0x00000854 )	ERROR_SUCCESS		0.0000000
129 static HRESULT IntSetNewWindowMode(BOOL bNewWindowMode)
130 {
131     CABINETSTATE cs;
132     if (!ReadCabinetState(&cs, sizeof(cs)))
133         return E_FAIL;
134 
135     BOOL changed = !!cs.fNewWindowMode != !!bNewWindowMode;
136     cs.fNewWindowMode = !!bNewWindowMode;
137     return WriteCabinetState(&cs) ? (changed ? S_OK : S_FALSE) : E_FAIL;
138 }
139 
140 static BOOL IntGetNewWindowMode(VOID)
141 {
142     CABINETSTATE cs;
143     if (!ReadCabinetState(&cs, sizeof(cs)))
144         return FALSE;
145 
146     return !!cs.fNewWindowMode;
147 }
148 
149 /////////////////////////////////////////////////////////////////////////////
150 // GeneralDlg
151 
152 typedef struct GENERAL_DIALOG
153 {
154     HICON hTaskIcon;
155     HICON hFolderIcon;
156     HICON hClickIcon;
157 } GENERAL_DIALOG, *PGENERAL_DIALOG;
158 
159 static VOID
160 GeneralDlg_UpdateIcons(HWND hDlg, UINT nCtrlID, PGENERAL_DIALOG pGeneral)
161 {
162     HICON hTaskIcon = NULL, hFolderIcon = NULL, hClickIcon = NULL;
163     LPTSTR lpTaskIconName = NULL, lpFolderIconName = NULL, lpClickIconName = NULL;
164 
165     // Show task setting icon.
166     if (IsDlgButtonChecked(hDlg, IDC_FOLDER_OPTIONS_COMMONTASKS) == BST_CHECKED)
167         lpTaskIconName = MAKEINTRESOURCE(IDI_SHELL_SHOW_COMMON_TASKS);
168     else if (IsDlgButtonChecked(hDlg, IDC_FOLDER_OPTIONS_CLASSICFOLDERS) == BST_CHECKED)
169         lpTaskIconName = MAKEINTRESOURCE(IDI_SHELL_CLASSIC_FOLDERS);
170 
171     if (lpTaskIconName)
172     {
173         hTaskIcon = (HICON)LoadImage(shell32_hInstance, lpTaskIconName,
174                                      IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR);
175         if (hTaskIcon)
176         {
177             HWND hwndTaskIcon = GetDlgItem(hDlg, IDC_FOLDER_OPTIONS_TASKICON);
178             SendMessage(hwndTaskIcon, STM_SETIMAGE, IMAGE_ICON, (LPARAM)hTaskIcon);
179         }
180     }
181 
182     // Show Folder setting icons
183     if (IsDlgButtonChecked(hDlg, IDC_FOLDER_OPTIONS_SAMEWINDOW) == BST_CHECKED)
184         lpFolderIconName = MAKEINTRESOURCE(IDI_SHELL_OPEN_IN_SOME_WINDOW);
185     else if (IsDlgButtonChecked(hDlg, IDC_FOLDER_OPTIONS_OWNWINDOW) == BST_CHECKED)
186         lpFolderIconName = MAKEINTRESOURCE(IDI_SHELL_OPEN_IN_NEW_WINDOW);
187 
188     if (lpFolderIconName)
189     {
190         hFolderIcon = (HICON)LoadImage(shell32_hInstance, lpFolderIconName,
191                                        IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR);
192         if (hFolderIcon)
193         {
194             HWND hwndFolderIcon = GetDlgItem(hDlg, IDC_FOLDER_OPTIONS_FOLDERICON);
195             SendMessage(hwndFolderIcon, STM_SETIMAGE, IMAGE_ICON, (LPARAM)hFolderIcon);
196         }
197     }
198 
199     // Show click setting icon
200     if (IsDlgButtonChecked(hDlg, IDC_FOLDER_OPTIONS_SINGLECLICK) == BST_CHECKED)
201         lpClickIconName = MAKEINTRESOURCE(IDI_SHELL_SINGLE_CLICK_TO_OPEN);
202     else if (IsDlgButtonChecked(hDlg, IDC_FOLDER_OPTIONS_DOUBLECLICK) == BST_CHECKED)
203         lpClickIconName = MAKEINTRESOURCE(IDI_SHELL_DOUBLE_CLICK_TO_OPEN);
204 
205     if (lpClickIconName)
206     {
207         hClickIcon = (HICON)LoadImage(shell32_hInstance, lpClickIconName,
208                                       IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR);
209         if (hClickIcon)
210         {
211             HWND hwndClickIcon = GetDlgItem(hDlg, IDC_FOLDER_OPTIONS_CLICKICON);
212             SendMessage(hwndClickIcon, STM_SETIMAGE, IMAGE_ICON, (LPARAM)hClickIcon);
213         }
214     }
215 
216     // Replace icons
217     if (hTaskIcon)
218     {
219         DestroyIcon(pGeneral->hTaskIcon);
220         pGeneral->hTaskIcon = hTaskIcon;
221     }
222     if (hFolderIcon)
223     {
224         DestroyIcon(pGeneral->hFolderIcon);
225         pGeneral->hFolderIcon = hFolderIcon;
226     }
227     if (hClickIcon)
228     {
229         DestroyIcon(pGeneral->hClickIcon);
230         pGeneral->hClickIcon = hClickIcon;
231     }
232 
233     if (nCtrlID == IDC_FOLDER_OPTIONS_SINGLECLICK)
234     {
235         EnableWindow(GetDlgItem(hDlg, IDC_FOLDER_OPTIONS_ULBROWSER), TRUE);
236         EnableWindow(GetDlgItem(hDlg, IDC_FOLDER_OPTIONS_ULPOINT), TRUE);
237     }
238 
239     if (nCtrlID == IDC_FOLDER_OPTIONS_DOUBLECLICK)
240     {
241         CheckRadioButton(hDlg, IDC_FOLDER_OPTIONS_ULBROWSER, IDC_FOLDER_OPTIONS_ULPOINT, IDC_FOLDER_OPTIONS_ULBROWSER);
242         EnableWindow(GetDlgItem(hDlg, IDC_FOLDER_OPTIONS_ULBROWSER), FALSE);
243         EnableWindow(GetDlgItem(hDlg, IDC_FOLDER_OPTIONS_ULPOINT), FALSE);
244     }
245 }
246 
247 static void
248 GeneralDlg_StoreToUI(HWND hwndDlg, BOOL bDoubleClick, BOOL bUseCommonTasks,
249                      BOOL bUnderline, BOOL bNewWindowMode, PGENERAL_DIALOG pGeneral)
250 {
251     EnableWindow(GetDlgItem(hwndDlg, IDC_FOLDER_OPTIONS_COMMONTASKS), bUseCommonTasks); // FIXME: ROS DefView does not support WebView nor the tasks pane
252 
253     if (bUseCommonTasks)
254         CheckRadioButton(hwndDlg, IDC_FOLDER_OPTIONS_COMMONTASKS, IDC_FOLDER_OPTIONS_CLASSICFOLDERS, IDC_FOLDER_OPTIONS_COMMONTASKS);
255     else
256         CheckRadioButton(hwndDlg, IDC_FOLDER_OPTIONS_COMMONTASKS, IDC_FOLDER_OPTIONS_CLASSICFOLDERS, IDC_FOLDER_OPTIONS_CLASSICFOLDERS);
257 
258     if (bDoubleClick)
259         CheckRadioButton(hwndDlg, IDC_FOLDER_OPTIONS_SINGLECLICK, IDC_FOLDER_OPTIONS_DOUBLECLICK, IDC_FOLDER_OPTIONS_DOUBLECLICK);
260     else
261         CheckRadioButton(hwndDlg, IDC_FOLDER_OPTIONS_SINGLECLICK, IDC_FOLDER_OPTIONS_DOUBLECLICK, IDC_FOLDER_OPTIONS_SINGLECLICK);
262 
263     if (bNewWindowMode)
264         CheckRadioButton(hwndDlg, IDC_FOLDER_OPTIONS_SAMEWINDOW, IDC_FOLDER_OPTIONS_OWNWINDOW, IDC_FOLDER_OPTIONS_OWNWINDOW);
265     else
266         CheckRadioButton(hwndDlg, IDC_FOLDER_OPTIONS_SAMEWINDOW, IDC_FOLDER_OPTIONS_OWNWINDOW, IDC_FOLDER_OPTIONS_SAMEWINDOW);
267 
268     if (!bDoubleClick)
269     {
270         EnableWindow(GetDlgItem(hwndDlg, IDC_FOLDER_OPTIONS_ULBROWSER), TRUE);
271         EnableWindow(GetDlgItem(hwndDlg, IDC_FOLDER_OPTIONS_ULPOINT), TRUE);
272         if (bUnderline)
273             CheckRadioButton(hwndDlg, IDC_FOLDER_OPTIONS_ULBROWSER, IDC_FOLDER_OPTIONS_ULPOINT, IDC_FOLDER_OPTIONS_ULPOINT);
274         else
275             CheckRadioButton(hwndDlg, IDC_FOLDER_OPTIONS_ULBROWSER, IDC_FOLDER_OPTIONS_ULPOINT, IDC_FOLDER_OPTIONS_ULBROWSER);
276     }
277     else
278     {
279         EnableWindow(GetDlgItem(hwndDlg, IDC_FOLDER_OPTIONS_ULBROWSER), FALSE);
280         EnableWindow(GetDlgItem(hwndDlg, IDC_FOLDER_OPTIONS_ULPOINT), FALSE);
281         CheckRadioButton(hwndDlg, IDC_FOLDER_OPTIONS_ULBROWSER, IDC_FOLDER_OPTIONS_ULPOINT, IDC_FOLDER_OPTIONS_ULBROWSER);
282     }
283 }
284 
285 static BOOL
286 GeneralDlg_OnInitDialog(HWND hwndDlg, PGENERAL_DIALOG pGeneral)
287 {
288     SHELLSTATE ss;
289     SHGetSetSettings(&ss, SSF_DOUBLECLICKINWEBVIEW | SSF_WEBVIEW, FALSE);
290     BOOL bDoubleClick = !!ss.fDoubleClickInWebView;
291     BOOL bUseCommonTasks = !!ss.fWebView;
292     BOOL bUnderline = IntGetUnderlineState();
293     BOOL bNewWindowMode = IntGetNewWindowMode();
294 
295     GeneralDlg_StoreToUI(hwndDlg, bDoubleClick, bUseCommonTasks, bUnderline, bNewWindowMode, pGeneral);
296     GeneralDlg_UpdateIcons(hwndDlg, 0, pGeneral);
297 
298     return TRUE;
299 }
300 
301 static void
302 GeneralDlg_OnRestoreDefaults(HWND hwndDlg, PGENERAL_DIALOG pGeneral)
303 {
304     // default values
305     BOOL bDoubleClick = TRUE;
306     BOOL bUseCommonTasks = TRUE;
307     BOOL bUnderline = FALSE;
308     BOOL bNewWindowMode = (_WIN32_WINNT < _WIN32_WINNT_WIN2K);
309 
310     GeneralDlg_StoreToUI(hwndDlg, bDoubleClick, bUseCommonTasks, bUnderline, bNewWindowMode, pGeneral);
311     GeneralDlg_UpdateIcons(hwndDlg, 0, pGeneral);
312 }
313 
314 static BOOL
315 GeneralDlg_OnApply(HWND hwndDlg, PGENERAL_DIALOG pGeneral)
316 {
317     BOOL bDoubleClick = !(IsDlgButtonChecked(hwndDlg, IDC_FOLDER_OPTIONS_SINGLECLICK) == BST_CHECKED);
318     BOOL bUseCommonTasks = (IsDlgButtonChecked(hwndDlg, IDC_FOLDER_OPTIONS_COMMONTASKS) == BST_CHECKED);
319     BOOL bUnderline = (IsDlgButtonChecked(hwndDlg, IDC_FOLDER_OPTIONS_ULPOINT) == BST_CHECKED);
320     BOOL bNewWindowMode = !(IsDlgButtonChecked(hwndDlg, IDC_FOLDER_OPTIONS_SAMEWINDOW) == BST_CHECKED);
321 
322     IntSetUnderlineState(bUnderline);
323     BOOL updateCabinets = IntSetNewWindowMode(bNewWindowMode) == S_OK;
324     IntSetShellStateSettings(bDoubleClick, bUseCommonTasks);
325     if (updateCabinets)
326         PostCabinetMessage(CWM_STATECHANGE, 0, 0);
327     return TRUE;
328 }
329 
330 INT_PTR CALLBACK
331 FolderOptionsGeneralDlg(
332     HWND hwndDlg,
333     UINT uMsg,
334     WPARAM wParam,
335     LPARAM lParam)
336 {
337     static GENERAL_DIALOG general;
338 
339     switch (uMsg)
340     {
341         case WM_INITDIALOG:
342             general.hTaskIcon = NULL;
343             general.hFolderIcon = NULL;
344             general.hClickIcon = NULL;
345             return GeneralDlg_OnInitDialog(hwndDlg, &general);
346 
347         case WM_COMMAND:
348             switch (LOWORD(wParam))
349             {
350                 case IDC_FOLDER_OPTIONS_COMMONTASKS:
351                 case IDC_FOLDER_OPTIONS_CLASSICFOLDERS:
352                 case IDC_FOLDER_OPTIONS_SAMEWINDOW:
353                 case IDC_FOLDER_OPTIONS_OWNWINDOW:
354                 case IDC_FOLDER_OPTIONS_SINGLECLICK:
355                 case IDC_FOLDER_OPTIONS_DOUBLECLICK:
356                 case IDC_FOLDER_OPTIONS_ULBROWSER:
357                 case IDC_FOLDER_OPTIONS_ULPOINT:
358                     if (HIWORD(wParam) == BN_CLICKED)
359                     {
360                         GeneralDlg_UpdateIcons(hwndDlg, LOWORD(wParam), &general);
361 
362                         // Enable the 'Apply' button
363                         PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
364                     }
365                     break;
366                 case IDC_FOLDER_OPTIONS_RESTORE:
367                     if (HIWORD(wParam) == BN_CLICKED)
368                     {
369                         GeneralDlg_OnRestoreDefaults(hwndDlg, &general);
370 
371                         // Enable the 'Apply' button
372                         PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
373                     }
374                     break;
375             }
376             break;
377 
378         case WM_NOTIFY:
379         {
380             LPNMHDR pnmh = (LPNMHDR)lParam;
381 
382             switch (pnmh->code)
383             {
384                 case PSN_SETACTIVE:
385                     break;
386 
387                 case PSN_APPLY:
388                     return GeneralDlg_OnApply(hwndDlg, &general);
389             }
390             break;
391         }
392 
393         case WM_DESTROY:
394             DestroyIcon(general.hTaskIcon);
395             DestroyIcon(general.hFolderIcon);
396             DestroyIcon(general.hClickIcon);
397             break;
398 
399         default:
400              return FALSE;
401     }
402     return FALSE;
403 }
404