query: Add a stub implementation for LocateCatalogs.
[wine] / programs / winecfg / appdefaults.c
1 /*
2  * WineCfg app settings tabsheet
3  *
4  * Copyright 2004 Robert van Herk
5  * Copyright 2004 Chris Morgan
6  * Copyright 2004 Mike Hearn
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  *
22  */
23
24 #define WIN32_LEAN_AND_MEAN
25 #define NONAMELESSUNION
26 #include <windows.h>
27 #include <commdlg.h>
28 #include <wine/debug.h>
29 #include <stdio.h>
30 #include <assert.h>
31 #include "winecfg.h"
32 #include "resource.h"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(winecfg);
35
36 static const struct
37 {
38     const char *szVersion;
39     const char *szDescription;
40     DWORD       dwMajorVersion;
41     DWORD       dwMinorVersion;
42     DWORD       dwBuildNumber;
43     DWORD       dwPlatformId;
44     const char *szCSDVersion;
45     WORD        wServicePackMajor;
46     WORD        wServicePackMinor;
47     const char *szProductType;
48 } win_versions[] =
49 {
50     { "win2003", "Windows 2003",   5,  2, 0xECE, VER_PLATFORM_WIN32_NT, "Service Pack 1", 1, 0, "ServerNT"},
51     { "winxp",   "Windows XP",     5,  1, 0xA28, VER_PLATFORM_WIN32_NT, "Service Pack 2", 2, 0, "WinNT"},
52     { "win2k",   "Windows 2000",   5,  0, 0x893, VER_PLATFORM_WIN32_NT, "Service Pack 4", 4, 0, "WinNT"},
53     { "winme",   "Windows ME",     4, 90, 0xBB8, VER_PLATFORM_WIN32_WINDOWS, " ", 0, 0, ""},
54     { "win98",   "Windows 98",     4, 10, 0x8AE, VER_PLATFORM_WIN32_WINDOWS, " A ", 0, 0, ""},
55     { "win95",   "Windows 95",     4,  0, 0x3B6, VER_PLATFORM_WIN32_WINDOWS, "", 0, 0, ""},
56     { "nt40",    "Windows NT 4.0", 4,  0, 0x565, VER_PLATFORM_WIN32_NT, "Service Pack 6a", 6, 0, "WinNT"},
57     { "nt351",   "Windows NT 3.5", 3, 51, 0x421, VER_PLATFORM_WIN32_NT, "Service Pack 2", 0, 0, "WinNT"},
58     { "win31",   "Windows 3.1",    2, 10,     0, VER_PLATFORM_WIN32s, "Win32s 1.3", 0, 0, ""},
59     { "win30",   "Windows 3.0",    3,  0,     0, VER_PLATFORM_WIN32s, "Win32s 1.3", 0, 0, ""},
60     { "win20",   "Windows 2.0",    2,  0,     0, VER_PLATFORM_WIN32s, "Win32s 1.3", 0, 0, ""}
61 };
62
63 #define NB_VERSIONS (sizeof(win_versions)/sizeof(win_versions[0]))
64
65 static void update_comboboxes(HWND dialog)
66 {
67     int i;
68
69     char *winver;
70   
71     /* retrieve the registry values */
72     winver = get_reg_key(config_key, keypath(""), "Version", "");
73
74     if (*winver == '\0')
75     {
76         HeapFree(GetProcessHeap(), 0, winver);
77
78         if (current_app) /* no explicit setting */
79         {
80             WINE_TRACE("setting winver combobox to default\n");
81             SendDlgItemMessage (dialog, IDC_WINVER, CB_SETCURSEL, 0, 0);
82             return;
83         }
84         winver = strdupA("win2k");
85     }
86     WINE_TRACE("winver is %s\n", winver);
87
88     /* normalize the version strings */
89     for (i = 0; i < NB_VERSIONS; i++)
90     {
91         if (!strcasecmp (win_versions[i].szVersion, winver))
92         {
93             SendDlgItemMessage (dialog, IDC_WINVER, CB_SETCURSEL,
94                                 (WPARAM) i + (current_app?1:0), 0);
95             WINE_TRACE("match with %s\n", win_versions[i].szVersion);
96             break;
97         }
98     }
99
100     HeapFree(GetProcessHeap(), 0, winver);
101 }
102
103 static void
104 init_comboboxes (HWND dialog)
105 {
106     int i;
107
108     SendDlgItemMessage(dialog, IDC_WINVER, CB_RESETCONTENT, 0, 0);
109
110     /* add the default entries (automatic) which correspond to no setting  */
111     if (current_app)
112         SendDlgItemMessage(dialog, IDC_WINVER, CB_ADDSTRING, 0, (LPARAM) "Use global settings");
113
114     for (i = 0; i < NB_VERSIONS; i++)
115     {
116       SendDlgItemMessage (dialog, IDC_WINVER, CB_ADDSTRING,
117                           0, (LPARAM) win_versions[i].szDescription);
118     }
119 }
120
121 static void add_listview_item(HWND listview, const char *text, void *association)
122 {
123   LVITEM item;
124
125   ZeroMemory(&item, sizeof(LVITEM));
126
127   item.mask = LVIF_TEXT | LVIF_PARAM;
128   item.pszText = (char*) text;
129   item.cchTextMax = strlen(text);
130   item.lParam = (LPARAM) association;
131   item.iItem = ListView_GetItemCount(listview);
132
133   SendMessage(listview, LVM_INSERTITEM, 0, (LPARAM) &item);
134 }
135
136 /* Called when the application is initialized (cannot reinit!)  */
137 static void init_appsheet(HWND dialog)
138 {
139   HWND listview;
140   HKEY key;
141   int i;
142   DWORD size;
143   char appname[1024];
144
145   WINE_TRACE("()\n");
146
147   listview = GetDlgItem(dialog, IDC_APP_LISTVIEW);
148
149   /* we use the lparam field of the item so we can alter the presentation later and not change code
150    * for instance, to use the tile view or to display the EXEs embedded 'display name' */
151   add_listview_item(listview, "Default Settings", NULL);
152
153   /* because this list is only populated once, it's safe to bypass the settings list here  */
154   if (RegOpenKey(config_key, "AppDefaults", &key) == ERROR_SUCCESS)
155   {
156       i = 0;
157       size = sizeof(appname);
158       while (RegEnumKeyEx(key, i, appname, &size, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
159       {
160           add_listview_item(listview, appname, strdupA(appname));
161
162           i++;
163           size = sizeof(appname);
164       }
165
166       RegCloseKey(key);
167   }
168
169   init_comboboxes(dialog);
170   
171   /* Select the default settings listview item  */
172   {
173       LVITEM item;
174       
175       ZeroMemory(&item, sizeof(item));
176       
177       item.mask = LVIF_STATE;
178       item.iItem = 0;
179       item.state = LVIS_SELECTED | LVIS_FOCUSED;
180       item.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
181
182       SendMessage(listview, LVM_SETITEM, 0, (LPARAM) &item);
183   }
184   
185 }
186
187 /* there has to be an easier way than this  */
188 static int get_listview_selection(HWND listview)
189 {
190   int count = ListView_GetItemCount(listview);
191   int i;
192   
193   for (i = 0; i < count; i++)
194   {
195     if (ListView_GetItemState(listview, i, LVIS_SELECTED)) return i;
196   }
197
198   return -1;
199 }
200
201
202 /* called when the user selects a different application */
203 static void on_selection_change(HWND dialog, HWND listview)
204 {
205   LVITEM item;
206   char *oldapp = current_app;
207
208   WINE_TRACE("()\n");
209
210   item.iItem = get_listview_selection(listview);
211   item.mask = LVIF_PARAM;
212
213   WINE_TRACE("item.iItem=%d\n", item.iItem);
214   
215   if (item.iItem == -1) return;
216   
217   SendMessage(listview, LVM_GETITEM, 0, (LPARAM) &item);
218
219   current_app = (char *) item.lParam;
220
221   if (current_app)
222   {
223       WINE_TRACE("current_app is now %s\n", current_app);
224       enable(IDC_APP_REMOVEAPP);
225   }
226   else
227   {
228       WINE_TRACE("current_app=NULL, editing global settings\n");
229       /* focus will never be on the button in this callback so it's safe  */
230       disable(IDC_APP_REMOVEAPP);
231   }
232
233   /* reset the combo boxes if we changed from/to global/app-specific  */
234
235   if ((oldapp && !current_app) || (!oldapp && current_app))
236       init_comboboxes(dialog);
237   
238   update_comboboxes(dialog);
239
240   set_window_title(dialog);
241 }
242
243 static BOOL list_contains_file(HWND listview, char *filename)
244 {
245   LVFINDINFO find_info = { LVFI_STRING, filename, 0, {0, 0}, 0 };
246   int index;
247
248   index = ListView_FindItem(listview, -1, &find_info);
249
250   return (index != -1);
251 }
252
253 static void on_add_app_click(HWND dialog)
254 {
255   char filetitle[MAX_PATH];
256   char file[MAX_PATH];
257
258   OPENFILENAME ofn = { sizeof(OPENFILENAME),
259                        0, /*hInst*/0, "Wine Programs (*.exe,*.exe.so)\0*.exe;*.exe.so\0", NULL, 0, 0, NULL,
260                        0, NULL, 0, "c:\\", "Select a Windows executable file",
261                        OFN_SHOWHELP | OFN_HIDEREADONLY, 0, 0, NULL, 0, NULL };
262
263   ofn.lpstrFileTitle = filetitle;
264   ofn.lpstrFileTitle[0] = '\0';
265   ofn.nMaxFileTitle = sizeof(filetitle);
266   ofn.lpstrFile = file;
267   ofn.lpstrFile[0] = '\0';
268   ofn.nMaxFile = sizeof(file);
269
270   if (GetOpenFileName(&ofn))
271   {
272       HWND listview = GetDlgItem(dialog, IDC_APP_LISTVIEW);
273       int count = ListView_GetItemCount(listview);
274       char* new_app;
275       
276       new_app = strdupA(filetitle);
277
278       if (list_contains_file(listview, new_app))
279           return;
280       
281       WINE_TRACE("adding %s\n", new_app);
282       
283       add_listview_item(listview, new_app, new_app);
284
285       ListView_SetItemState(listview, count, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
286
287       SetFocus(listview);
288   }
289   else WINE_TRACE("user cancelled\n");
290 }
291
292 static void on_remove_app_click(HWND dialog)
293 {
294     HWND listview = GetDlgItem(dialog, IDC_APP_LISTVIEW);
295     int selection = get_listview_selection(listview);
296     char *section = keypath(""); /* AppDefaults\\whatever.exe\\ */
297
298     WINE_TRACE("selection=%d, section=%s\n", selection, section);
299     
300     assert( selection != 0 ); /* user cannot click this button when "default settings" is selected  */
301
302     section[strlen(section)] = '\0'; /* remove last backslash  */
303     set_reg_key(config_key, section, NULL, NULL); /* delete the section  */
304     SendMessage(listview, LVM_DELETEITEM, selection, 0);
305     ListView_SetItemState(listview, selection - 1, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
306
307     SetFocus(listview);
308     
309     SendMessage(GetParent(dialog), PSM_CHANGED, (WPARAM) dialog, 0);        
310 }
311
312 static void on_winver_change(HWND dialog)
313 {
314     int selection = SendDlgItemMessage(dialog, IDC_WINVER, CB_GETCURSEL, 0, 0);
315
316     if (!selection && current_app)
317     {
318         WINE_TRACE("default selected so removing current setting\n");
319         set_reg_key(config_key, keypath(""), "Version", NULL);
320     }
321     else
322     {
323         if (current_app) selection--;
324         WINE_TRACE("setting Version key to value '%s'\n", win_versions[selection].szVersion);
325         set_reg_key(config_key, keypath(""), "Version", win_versions[selection].szVersion);
326     }
327     /* global version only */
328     if (!current_app)
329     {
330         static const char szKey9x[] = "Software\\Microsoft\\Windows\\CurrentVersion";
331         static const char szKeyNT[] = "Software\\Microsoft\\Windows NT\\CurrentVersion";
332         static const char szKeyProdNT[] = "System\\CurrentControlSet\\Control\\ProductOptions";
333         static const char szKeyWindNT[] = "System\\CurrentControlSet\\Control\\Windows";
334         static const char szKeyEnvNT[]  = "System\\CurrentControlSet\\Control\\Session Manager\\Environment";
335         char Buffer[40];
336
337         switch (win_versions[selection].dwPlatformId)
338         {
339         case VER_PLATFORM_WIN32_WINDOWS:
340             snprintf(Buffer, sizeof(Buffer), "%ld.%ld.%ld", win_versions[selection].dwMajorVersion,
341                      win_versions[selection].dwMinorVersion, win_versions[selection].dwBuildNumber);
342             set_reg_key(HKEY_LOCAL_MACHINE, szKey9x, "VersionNumber", Buffer);
343             set_reg_key(HKEY_LOCAL_MACHINE, szKey9x, "SubVersionNumber", win_versions[selection].szCSDVersion);
344
345             set_reg_key(HKEY_LOCAL_MACHINE, szKeyNT, "CSDVersion", NULL);
346             set_reg_key(HKEY_LOCAL_MACHINE, szKeyNT, "CurrentVersion", NULL);
347             set_reg_key(HKEY_LOCAL_MACHINE, szKeyNT, "CurrentBuildNumber", NULL);
348             set_reg_key(HKEY_LOCAL_MACHINE, szKeyProdNT, "ProductType", NULL);
349             set_reg_key(HKEY_LOCAL_MACHINE, szKeyWindNT, "CSDVersion", NULL);
350             set_reg_key(HKEY_LOCAL_MACHINE, szKeyEnvNT, "OS", NULL);
351             break;
352
353         case VER_PLATFORM_WIN32_NT:
354             snprintf(Buffer, sizeof(Buffer), "%ld.%ld", win_versions[selection].dwMajorVersion,
355                      win_versions[selection].dwMinorVersion);
356             set_reg_key(HKEY_LOCAL_MACHINE, szKeyNT, "CurrentVersion", Buffer);
357             set_reg_key(HKEY_LOCAL_MACHINE, szKeyNT, "CSDVersion", win_versions[selection].szCSDVersion);
358             snprintf(Buffer, sizeof(Buffer), "%ld", win_versions[selection].dwBuildNumber);
359             set_reg_key(HKEY_LOCAL_MACHINE, szKeyNT, "CurrentBuildNumber", Buffer);
360             set_reg_key(HKEY_LOCAL_MACHINE, szKeyProdNT, "ProductType", win_versions[selection].szProductType);
361             set_reg_key_dword(HKEY_LOCAL_MACHINE, szKeyWindNT, "CSDVersion",
362                               MAKEWORD( win_versions[selection].wServicePackMinor,
363                                         win_versions[selection].wServicePackMajor ));
364             set_reg_key(HKEY_LOCAL_MACHINE, szKeyEnvNT, "OS", "Windows_NT");
365
366             set_reg_key(HKEY_LOCAL_MACHINE, szKey9x, "VersionNumber", NULL);
367             set_reg_key(HKEY_LOCAL_MACHINE, szKey9x, "SubVersionNumber", NULL);
368             break;
369
370         case VER_PLATFORM_WIN32s:
371             set_reg_key(HKEY_LOCAL_MACHINE, szKeyNT, "CSDVersion", NULL);
372             set_reg_key(HKEY_LOCAL_MACHINE, szKeyNT, "CurrentVersion", NULL);
373             set_reg_key(HKEY_LOCAL_MACHINE, szKeyNT, "CurrentBuildNumber", NULL);
374             set_reg_key(HKEY_LOCAL_MACHINE, szKeyProdNT, "ProductType", NULL);
375             set_reg_key(HKEY_LOCAL_MACHINE, szKeyWindNT, "CSDVersion", NULL);
376             set_reg_key(HKEY_LOCAL_MACHINE, szKeyEnvNT, "OS", NULL);
377             set_reg_key(HKEY_LOCAL_MACHINE, szKey9x, "VersionNumber", NULL);
378             set_reg_key(HKEY_LOCAL_MACHINE, szKey9x, "SubVersionNumber", NULL);
379             break;
380         }
381     }
382
383     /* enable the apply button  */
384     SendMessage(GetParent(dialog), PSM_CHANGED, (WPARAM) dialog, 0);
385 }
386
387 INT_PTR CALLBACK
388 AppDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
389 {
390   switch (uMsg)
391   {
392     case WM_INITDIALOG:
393         init_appsheet(hDlg);
394         break;
395
396     case WM_SHOWWINDOW:
397         set_window_title(hDlg);
398         break;
399
400     case WM_NOTIFY:
401       switch (((LPNMHDR)lParam)->code)
402       {
403         case LVN_ITEMCHANGED:
404             on_selection_change(hDlg, GetDlgItem(hDlg, IDC_APP_LISTVIEW));
405             break;
406         case PSN_APPLY:
407             apply();
408             SetWindowLongPtr(hDlg, DWLP_MSGRESULT, PSNRET_NOERROR);
409             break;
410       }
411       
412       break;
413     
414     case WM_COMMAND:
415       switch(HIWORD(wParam))
416       {
417         case CBN_SELCHANGE:
418           switch(LOWORD(wParam))
419           {
420             case IDC_WINVER:
421               on_winver_change(hDlg);
422               break;
423           }
424         case BN_CLICKED:
425           switch(LOWORD(wParam))
426           {
427             case IDC_APP_ADDAPP:
428               on_add_app_click(hDlg);
429               break;
430             case IDC_APP_REMOVEAPP:
431               on_remove_app_click(hDlg);
432               break;
433           }
434           break;
435       }
436
437       break;
438   }
439   
440   return 0;
441 }