Reactos
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
24WINE_DEFAULT_DEBUG_CHANNEL (fprop);
25
26static const LPCWSTR s_pszExplorerKey = REGSTR_PATH_EXPLORER;
27
28enum { UNDERLINE_ON, UNDERLINE_OFF, UNDERLINE_HOVER, UNDERLINE_IE };
29
30/////////////////////////////////////////////////////////////////////////////
31// Shell settings
32
33EXTERN_C void
34SHELL32_GetDefaultShellState(LPSHELLSTATE pss)
35{
36 ZeroMemory(pss, sizeof(*pss));
37 pss->fShowAllObjects = TRUE;
38 pss->fShowExtensions = TRUE;
39 pss->fShowCompColor = TRUE;
40 pss->fDoubleClickInWebView = TRUE;
41 pss->fShowAttribCol = TRUE; // ROS defaults to Details view with this column on
42 pss->fShowInfoTip = TRUE;
43 pss->fShowSuperHidden = FALSE;
44 pss->lParamSort = SHFSF_COL_NAME;
45 pss->iSortDirection = 1;
46 pss->version = REGSHELLSTATE_VERSION;
47 pss->fSepProcess = FALSE;
48 pss->fStartPanelOn = FALSE; // Note: This should be changed to TRUE when the modern start menu is implemented
49}
50
51EXTERN_C LSTATUS
52SHELL32_WriteRegShellState(PREGSHELLSTATE prss)
53{
54 prss->dwSize = REGSHELLSTATE_SIZE;
55 prss->ss.version = REGSHELLSTATE_VERSION;
56 return SHSetValueW(HKEY_CURRENT_USER, s_pszExplorerKey, L"ShellState",
57 REG_BINARY, prss, prss->dwSize);
58}
59
60// bDoubleClick is TRUE if "Double-click to open an item (single-click to select)".
61// bDoubleClick is FALSE if "Single-click to open an item (point to select)".
62//////////////////////////////////////////////////////////////////////////////
63// API Monitor:
64// SHLWAPI.dll RegOpenKeyExW ( 0x000000c8, NULL, 0, MAXIMUM_ALLOWED, 0x00def234 ) ERROR_SUCCESS
65// SHLWAPI.dll RegSetValueExW ( 0x000003e8, "ShellState", 0, REG_BINARY, 0x000c2050, 36 ) ERROR_SUCCESS
66// SHLWAPI.dll RegCloseKey ( 0x000003e8 ) ERROR_SUCCESS
67// Explorer.EXE SHSettingsChanged ( 0, "ShellState" ) (WM_SETTINGCHANGE handling)
68static BOOL
69IntSetShellStateSettings(BOOL bDoubleClick, BOOL bUseCommonTasks)
70{
71 SHELLSTATE shellstate;
72 shellstate.fDoubleClickInWebView = !!bDoubleClick;
73 shellstate.fWebView = !!bUseCommonTasks;
74 SHGetSetSettings(&shellstate, SSF_DOUBLECLICKINWEBVIEW | SSF_WEBVIEW, TRUE);
75 return TRUE;
76}
77
78EXTERN_C BOOL
79SHELL32_ReadRegShellState(PREGSHELLSTATE prss)
80{
81 DWORD dwSize = sizeof(REGSHELLSTATE);
82 LSTATUS err = SHGetValueW(HKEY_CURRENT_USER, s_pszExplorerKey,
83 L"ShellState", NULL, prss, &dwSize);
84 return err == ERROR_SUCCESS && prss->dwSize >= REGSHELLSTATE_SIZE;
85}
86
87// bUnderlineHover is TRUE if "Underline icon titles only when I point at them".
88// bUnderlineHover is FALSE if "Underline icon titles consistent with my browser".
89//////////////////////////////////////////////////////////////////////////////
90// API Monitor:
91// SHELL32.dll SHRegGetUSValueW ( "Software\Microsoft\Windows\CurrentVersion\Explorer", "IconUnderline", NULL, 0x00d2f324, 0x00d2f328, FALSE, 0x00d2f32c, 4 ) ERROR_SUCCESS
92// SHELL32.dll IsDlgButtonChecked ( 0x0005009e, 30104 ) BST_CHECKED
93// SHELL32.dll SHRegSetUSValueW ( "Software\Microsoft\Windows\CurrentVersion\Explorer", "IconUnderline", 0, 0x00d2f314, 4, 6 ) ERROR_SUCCESS
94// Explorer.EXE SHSettingsChanged ( 0, "Software\Microsoft\Windows\CurrentVersion\Explorer\IconUnderline" ) (WM_SETTINGCHANGE handling)
95static BOOL IntSetUnderlineState(BOOL bUnderlineHover)
96{
97 LSTATUS Status;
98 DWORD dwValue = bUnderlineHover ? UNDERLINE_HOVER : UNDERLINE_IE;
99 Status = SHRegSetUSValue(s_pszExplorerKey, L"IconUnderline", REG_NONE,
100 &dwValue, sizeof(dwValue), SHREGSET_FORCE_HKCU | SHREGSET_HKLM);
101 if (Status != ERROR_SUCCESS)
102 return FALSE;
103
104 SHSendMessageBroadcastW(WM_SETTINGCHANGE, 0, (LPARAM)(REGSTR_PATH_EXPLORER L"\\IconUnderline"));
105 return TRUE;
106}
107
108static UINT IntGetRawIconUnderlineValue()
109{
110 DWORD dwValue, dwDefault = UNDERLINE_ON;
111 DWORD dwSize = sizeof(dwValue);
112 SHRegGetUSValue(s_pszExplorerKey, L"IconUnderline", NULL, &dwValue, &dwSize, FALSE, &dwDefault, sizeof(dwDefault));
113 return dwValue;
114}
115
116static UINT SHELL_GetIconUnderlineMode()
117{
118 UINT mode = IntGetRawIconUnderlineValue();
119 if (mode < UNDERLINE_IE)
120 return mode;
121
122 WCHAR buf[sizeof("hoverX")];
123 *buf = UNICODE_NULL;
124 DWORD cb = sizeof(buf);
125 SHRegGetUSValueW(L"Software\\Microsoft\\Internet Explorer\\Main",
126 L"Anchor Underline", NULL, buf, &cb, FALSE, buf, cb);
127 if (!lstrcmpiW(buf, L"no"))
128 return UNDERLINE_OFF;
129 if (!lstrcmpiW(buf, L"hover"))
130 return UNDERLINE_HOVER;
131 return UNDERLINE_ON;
132}
133
134UINT SHELL_GetIconUnderlineFlags()
135{
136 UINT mode = SHELL_GetIconUnderlineMode();
137 if (mode == UNDERLINE_HOVER)
138 return LVS_EX_UNDERLINEHOT;
139 if (mode == UNDERLINE_ON)
140 return LVS_EX_UNDERLINEHOT | LVS_EX_UNDERLINECOLD;
141 return 0;
142}
143
144// bNewWindowMode is TRUE if "Open each folder in its own window".
145// bNewWindowMode is FALSE if "Open each folder in the same window".
146//////////////////////////////////////////////////////////////////////////////
147// API Monitor:
148// 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
149// SHELL32.dll RegSetValueExW ( 0x00000854, "Settings", 0, REG_BINARY, 0x0210f170, 12 ) ERROR_SUCCESS 0.0001472
150// SHELL32.dll RegSetValueExW ( 0x00000854, "FullPath", 0, REG_DWORD, 0x00d2f2ac, 4 ) ERROR_SUCCESS 0.0000168
151// SHELL32.dll RegCloseKey ( 0x00000854 ) ERROR_SUCCESS 0.0000000
152static HRESULT IntSetNewWindowMode(BOOL bNewWindowMode)
153{
154 CABINETSTATE cs;
155 if (!ReadCabinetState(&cs, sizeof(cs)))
156 return E_FAIL;
157
158 BOOL changed = !!cs.fNewWindowMode != !!bNewWindowMode;
159 cs.fNewWindowMode = !!bNewWindowMode;
160 return WriteCabinetState(&cs) ? (changed ? S_OK : S_FALSE) : E_FAIL;
161}
162
163static BOOL IntGetNewWindowMode(VOID)
164{
165 CABINETSTATE cs;
166 if (!ReadCabinetState(&cs, sizeof(cs)))
167 return FALSE;
168
169 return !!cs.fNewWindowMode;
170}
171
172/////////////////////////////////////////////////////////////////////////////
173// GeneralDlg
174
175typedef struct GENERAL_DIALOG
176{
177 HICON hTaskIcon;
178 HICON hFolderIcon;
179 HICON hClickIcon;
180} GENERAL_DIALOG, *PGENERAL_DIALOG;
181
182static VOID
183GeneralDlg_UpdateIcons(HWND hDlg, UINT nCtrlID, PGENERAL_DIALOG pGeneral)
184{
185 HICON hTaskIcon = NULL, hFolderIcon = NULL, hClickIcon = NULL;
186 LPTSTR lpTaskIconName = NULL, lpFolderIconName = NULL, lpClickIconName = NULL;
187
188 // Show task setting icon.
189 if (IsDlgButtonChecked(hDlg, IDC_FOLDER_OPTIONS_COMMONTASKS) == BST_CHECKED)
190 lpTaskIconName = MAKEINTRESOURCE(IDI_SHELL_SHOW_COMMON_TASKS);
191 else if (IsDlgButtonChecked(hDlg, IDC_FOLDER_OPTIONS_CLASSICFOLDERS) == BST_CHECKED)
192 lpTaskIconName = MAKEINTRESOURCE(IDI_SHELL_CLASSIC_FOLDERS);
193
194 if (lpTaskIconName)
195 {
196 hTaskIcon = (HICON)LoadImage(shell32_hInstance, lpTaskIconName,
197 IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR);
198 if (hTaskIcon)
199 {
200 HWND hwndTaskIcon = GetDlgItem(hDlg, IDC_FOLDER_OPTIONS_TASKICON);
201 SendMessage(hwndTaskIcon, STM_SETIMAGE, IMAGE_ICON, (LPARAM)hTaskIcon);
202 }
203 }
204
205 // Show Folder setting icons
206 if (IsDlgButtonChecked(hDlg, IDC_FOLDER_OPTIONS_SAMEWINDOW) == BST_CHECKED)
207 lpFolderIconName = MAKEINTRESOURCE(IDI_SHELL_OPEN_IN_SOME_WINDOW);
208 else if (IsDlgButtonChecked(hDlg, IDC_FOLDER_OPTIONS_OWNWINDOW) == BST_CHECKED)
209 lpFolderIconName = MAKEINTRESOURCE(IDI_SHELL_OPEN_IN_NEW_WINDOW);
210
211 if (lpFolderIconName)
212 {
213 hFolderIcon = (HICON)LoadImage(shell32_hInstance, lpFolderIconName,
214 IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR);
215 if (hFolderIcon)
216 {
217 HWND hwndFolderIcon = GetDlgItem(hDlg, IDC_FOLDER_OPTIONS_FOLDERICON);
218 SendMessage(hwndFolderIcon, STM_SETIMAGE, IMAGE_ICON, (LPARAM)hFolderIcon);
219 }
220 }
221
222 // Show click setting icon
223 if (IsDlgButtonChecked(hDlg, IDC_FOLDER_OPTIONS_SINGLECLICK) == BST_CHECKED)
224 lpClickIconName = MAKEINTRESOURCE(IDI_SHELL_SINGLE_CLICK_TO_OPEN);
225 else if (IsDlgButtonChecked(hDlg, IDC_FOLDER_OPTIONS_DOUBLECLICK) == BST_CHECKED)
226 lpClickIconName = MAKEINTRESOURCE(IDI_SHELL_DOUBLE_CLICK_TO_OPEN);
227
228 if (lpClickIconName)
229 {
230 hClickIcon = (HICON)LoadImage(shell32_hInstance, lpClickIconName,
231 IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR);
232 if (hClickIcon)
233 {
234 HWND hwndClickIcon = GetDlgItem(hDlg, IDC_FOLDER_OPTIONS_CLICKICON);
235 SendMessage(hwndClickIcon, STM_SETIMAGE, IMAGE_ICON, (LPARAM)hClickIcon);
236 }
237 }
238
239 // Replace icons
240 if (hTaskIcon)
241 {
242 DestroyIcon(pGeneral->hTaskIcon);
243 pGeneral->hTaskIcon = hTaskIcon;
244 }
245 if (hFolderIcon)
246 {
247 DestroyIcon(pGeneral->hFolderIcon);
248 pGeneral->hFolderIcon = hFolderIcon;
249 }
250 if (hClickIcon)
251 {
252 DestroyIcon(pGeneral->hClickIcon);
253 pGeneral->hClickIcon = hClickIcon;
254 }
255
256 if (nCtrlID == IDC_FOLDER_OPTIONS_SINGLECLICK)
257 {
258 EnableWindow(GetDlgItem(hDlg, IDC_FOLDER_OPTIONS_ULBROWSER), TRUE);
259 EnableWindow(GetDlgItem(hDlg, IDC_FOLDER_OPTIONS_ULPOINT), TRUE);
260 }
261
262 if (nCtrlID == IDC_FOLDER_OPTIONS_DOUBLECLICK)
263 {
264 EnableWindow(GetDlgItem(hDlg, IDC_FOLDER_OPTIONS_ULBROWSER), FALSE);
265 EnableWindow(GetDlgItem(hDlg, IDC_FOLDER_OPTIONS_ULPOINT), FALSE);
266 }
267}
268
269static void
270GeneralDlg_StoreToUI(HWND hwndDlg, BOOL bDoubleClick, BOOL bUseCommonTasks,
271 BOOL bUnderlineHover, BOOL bNewWindowMode, PGENERAL_DIALOG pGeneral)
272{
273 if (SHRestricted(REST_CLASSICSHELL))
274 {
275 EnableWindow(GetDlgItem(hwndDlg, IDC_FOLDER_OPTIONS_SINGLECLICK), FALSE);
276 bDoubleClick = TRUE;
277 bUseCommonTasks = FALSE;
278 }
279
280 EnableWindow(GetDlgItem(hwndDlg, IDC_FOLDER_OPTIONS_COMMONTASKS), bUseCommonTasks); // TODO: ROS DefView does not support WebView nor the tasks pane
281
282 if (bUseCommonTasks)
283 CheckRadioButton(hwndDlg, IDC_FOLDER_OPTIONS_COMMONTASKS, IDC_FOLDER_OPTIONS_CLASSICFOLDERS, IDC_FOLDER_OPTIONS_COMMONTASKS);
284 else
285 CheckRadioButton(hwndDlg, IDC_FOLDER_OPTIONS_COMMONTASKS, IDC_FOLDER_OPTIONS_CLASSICFOLDERS, IDC_FOLDER_OPTIONS_CLASSICFOLDERS);
286
287 if (bDoubleClick)
288 CheckRadioButton(hwndDlg, IDC_FOLDER_OPTIONS_SINGLECLICK, IDC_FOLDER_OPTIONS_DOUBLECLICK, IDC_FOLDER_OPTIONS_DOUBLECLICK);
289 else
290 CheckRadioButton(hwndDlg, IDC_FOLDER_OPTIONS_SINGLECLICK, IDC_FOLDER_OPTIONS_DOUBLECLICK, IDC_FOLDER_OPTIONS_SINGLECLICK);
291
292 if (bNewWindowMode)
293 CheckRadioButton(hwndDlg, IDC_FOLDER_OPTIONS_SAMEWINDOW, IDC_FOLDER_OPTIONS_OWNWINDOW, IDC_FOLDER_OPTIONS_OWNWINDOW);
294 else
295 CheckRadioButton(hwndDlg, IDC_FOLDER_OPTIONS_SAMEWINDOW, IDC_FOLDER_OPTIONS_OWNWINDOW, IDC_FOLDER_OPTIONS_SAMEWINDOW);
296
297 EnableWindow(GetDlgItem(hwndDlg, IDC_FOLDER_OPTIONS_ULBROWSER), !bDoubleClick);
298 EnableWindow(GetDlgItem(hwndDlg, IDC_FOLDER_OPTIONS_ULPOINT), !bDoubleClick);
299 if (bUnderlineHover)
300 CheckRadioButton(hwndDlg, IDC_FOLDER_OPTIONS_ULBROWSER, IDC_FOLDER_OPTIONS_ULPOINT, IDC_FOLDER_OPTIONS_ULPOINT);
301 else
302 CheckRadioButton(hwndDlg, IDC_FOLDER_OPTIONS_ULBROWSER, IDC_FOLDER_OPTIONS_ULPOINT, IDC_FOLDER_OPTIONS_ULBROWSER);
303}
304
305static BOOL
306GeneralDlg_OnInitDialog(HWND hwndDlg, PGENERAL_DIALOG pGeneral)
307{
308 SHELLSTATE ss;
309 SHGetSetSettings(&ss, SSF_DOUBLECLICKINWEBVIEW | SSF_WEBVIEW, FALSE);
310 BOOL bDoubleClick = !!ss.fDoubleClickInWebView;
311 BOOL bUseCommonTasks = !!ss.fWebView;
312 BOOL bUnderlineHover = IntGetRawIconUnderlineValue() == UNDERLINE_HOVER;
313 BOOL bNewWindowMode = IntGetNewWindowMode();
314
315 GeneralDlg_StoreToUI(hwndDlg, bDoubleClick, bUseCommonTasks, bUnderlineHover, bNewWindowMode, pGeneral);
316 GeneralDlg_UpdateIcons(hwndDlg, 0, pGeneral);
317
318 return TRUE;
319}
320
321static void
322GeneralDlg_OnRestoreDefaults(HWND hwndDlg, PGENERAL_DIALOG pGeneral)
323{
324 // default values
325 BOOL bDoubleClick = TRUE;
326 BOOL bUseCommonTasks = TRUE;
327 BOOL bUnderlineHover = FALSE;
328 BOOL bNewWindowMode = (_WIN32_WINNT < _WIN32_WINNT_WIN2K);
329
330 GeneralDlg_StoreToUI(hwndDlg, bDoubleClick, bUseCommonTasks, bUnderlineHover, bNewWindowMode, pGeneral);
331 GeneralDlg_UpdateIcons(hwndDlg, 0, pGeneral);
332}
333
334static BOOL
335GeneralDlg_OnApply(HWND hwndDlg, PGENERAL_DIALOG pGeneral)
336{
337 BOOL bDoubleClick = !(IsDlgButtonChecked(hwndDlg, IDC_FOLDER_OPTIONS_SINGLECLICK) == BST_CHECKED);
338 BOOL bUseCommonTasks = (IsDlgButtonChecked(hwndDlg, IDC_FOLDER_OPTIONS_COMMONTASKS) == BST_CHECKED);
339 BOOL bUnderlineHover = (IsDlgButtonChecked(hwndDlg, IDC_FOLDER_OPTIONS_ULPOINT) == BST_CHECKED);
340 BOOL bNewWindowMode = !(IsDlgButtonChecked(hwndDlg, IDC_FOLDER_OPTIONS_SAMEWINDOW) == BST_CHECKED);
341
342 IntSetUnderlineState(bUnderlineHover);
343 BOOL updateCabinets = IntSetNewWindowMode(bNewWindowMode) == S_OK;
344 IntSetShellStateSettings(bDoubleClick, bUseCommonTasks);
345 if (updateCabinets)
346 PostCabinetMessage(CWM_STATECHANGE, 0, 0);
347 return TRUE;
348}
349
350INT_PTR CALLBACK
351FolderOptionsGeneralDlg(
352 HWND hwndDlg,
353 UINT uMsg,
354 WPARAM wParam,
355 LPARAM lParam)
356{
357 static GENERAL_DIALOG general;
358
359 switch (uMsg)
360 {
361 case WM_INITDIALOG:
362 general.hTaskIcon = NULL;
363 general.hFolderIcon = NULL;
364 general.hClickIcon = NULL;
365 return GeneralDlg_OnInitDialog(hwndDlg, &general);
366
367 case WM_COMMAND:
368 switch (LOWORD(wParam))
369 {
370 case IDC_FOLDER_OPTIONS_COMMONTASKS:
371 case IDC_FOLDER_OPTIONS_CLASSICFOLDERS:
372 case IDC_FOLDER_OPTIONS_SAMEWINDOW:
373 case IDC_FOLDER_OPTIONS_OWNWINDOW:
374 case IDC_FOLDER_OPTIONS_SINGLECLICK:
375 case IDC_FOLDER_OPTIONS_DOUBLECLICK:
376 case IDC_FOLDER_OPTIONS_ULBROWSER:
377 case IDC_FOLDER_OPTIONS_ULPOINT:
378 if (HIWORD(wParam) == BN_CLICKED)
379 {
380 GeneralDlg_UpdateIcons(hwndDlg, LOWORD(wParam), &general);
381
382 // Enable the 'Apply' button
383 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
384 }
385 break;
386 case IDC_FOLDER_OPTIONS_RESTORE:
387 if (HIWORD(wParam) == BN_CLICKED)
388 {
389 GeneralDlg_OnRestoreDefaults(hwndDlg, &general);
390
391 // Enable the 'Apply' button
392 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
393 }
394 break;
395 }
396 break;
397
398 case WM_NOTIFY:
399 {
400 LPNMHDR pnmh = (LPNMHDR)lParam;
401
402 switch (pnmh->code)
403 {
404 case PSN_SETACTIVE:
405 break;
406
407 case PSN_APPLY:
408 return GeneralDlg_OnApply(hwndDlg, &general);
409 }
410 break;
411 }
412
413 case WM_DESTROY:
414 DestroyIcon(general.hTaskIcon);
415 DestroyIcon(general.hFolderIcon);
416 DestroyIcon(general.hClickIcon);
417 break;
418
419 default:
420 return FALSE;
421 }
422 return FALSE;
423}