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