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