Added a few more Unicode digits from Unicode version 4.1.
[wine] / programs / winecfg / libraries.c
1 /*
2  * WineCfg libraries tabsheet
3  *
4  * Copyright 2004 Robert van Herk
5  * Copyright 2004 Mike Hearn
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  *
21  */
22
23 #define NONAMELESSUNION
24 #include <windows.h>
25 #include <commdlg.h>
26 #include <wine/debug.h>
27 #include <stdio.h>
28 #include <assert.h>
29 #include "winecfg.h"
30 #include "resource.h"
31
32 WINE_DEFAULT_DEBUG_CHANNEL(winecfg);
33
34 enum dllmode
35 {
36         BUILTIN_NATIVE,
37         NATIVE_BUILTIN,
38         BUILTIN,
39         NATIVE,
40         DISABLE,
41         UNKNOWN /* Special value indicating an erronous DLL override mode */
42 };
43
44 struct dll
45 {
46         char *name;
47         enum dllmode mode;
48 };
49
50 /* Convert a registry string to a dllmode */
51 static enum dllmode string_to_mode(char *in)
52 {
53     int i, j, len;
54     char *out;
55     enum dllmode res;
56
57     len = strlen(in);
58     out = HeapAlloc(GetProcessHeap(), 0, len);
59
60     /* remove the spaces */
61     for (i = j = 0; i <= len; ++i) {
62         if (in[i] != ' ') {
63             out[j++] = in[i];
64         }
65     }
66
67     /* parse the string */
68     res = UNKNOWN;
69     if (strcmp(out, "builtin,native") == 0) res = BUILTIN_NATIVE;
70     if (strcmp(out, "native,builtin") == 0) res = NATIVE_BUILTIN;
71     if (strcmp(out, "builtin") == 0) res = BUILTIN;
72     if (strcmp(out, "native") == 0) res = NATIVE;
73     if (strcmp(out, "") == 0) res = DISABLE;
74
75     HeapFree(GetProcessHeap(), 0, out);
76     return res;
77 }
78
79 /* Convert a dllmode to a registry string. */
80 static const char* mode_to_string(enum dllmode mode)
81 {
82     switch( mode )
83     {
84         case NATIVE: return "native";
85         case BUILTIN: return "builtin";
86         case NATIVE_BUILTIN: return "native,builtin";
87         case BUILTIN_NATIVE: return "builtin,native";
88         case DISABLE: return "";
89         default: assert(FALSE); return "";
90     }
91 }
92
93 /* Convert a dllmode to a pretty string for display. TODO: use translations. */
94 static const char* mode_to_label(enum dllmode mode)
95 {
96     WINE_FIXME("translate me\n");
97     return mode_to_string(mode);
98 }
99
100 /* Convert a control id (IDC_ constant) to a dllmode */
101 static enum dllmode id_to_mode(DWORD id)
102 {
103     switch( id )
104     {
105         case IDC_RAD_BUILTIN: return BUILTIN;
106         case IDC_RAD_NATIVE: return NATIVE;
107         case IDC_RAD_NATIVE_BUILTIN: return NATIVE_BUILTIN;
108         case IDC_RAD_BUILTIN_NATIVE: return BUILTIN_NATIVE;
109         case IDC_RAD_DISABLE: return DISABLE;
110         default: assert( FALSE ); return 0; /* should not be reached  */
111     }
112 }
113
114 /* Convert a dllmode to a control id (IDC_ constant) */
115 static DWORD mode_to_id(enum dllmode mode)
116 {
117     switch( mode )
118     {
119         case BUILTIN: return IDC_RAD_BUILTIN;
120         case NATIVE: return IDC_RAD_NATIVE;
121         case NATIVE_BUILTIN: return IDC_RAD_NATIVE_BUILTIN;
122         case BUILTIN_NATIVE: return IDC_RAD_BUILTIN_NATIVE;
123         case DISABLE: return IDC_RAD_DISABLE;
124         default: assert( FALSE ); return 0; /* should not be reached  */
125     }
126 }
127
128 static void set_controls_from_selection(HWND dialog)
129 {
130     /* FIXME: display/update some information about the selected dll (purpose, recommended loadorder) maybe? */
131 }
132
133 static void clear_settings(HWND dialog)
134 {
135     int count = SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_GETCOUNT, 0, 0);
136     int i;
137
138     WINE_TRACE("count=%d\n", count);
139     
140     for (i = 0; i < count; i++)
141     {
142         struct dll *dll = (struct dll *) SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_GETITEMDATA, 0, 0);
143         
144         SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_DELETESTRING, 0, 0);
145         
146         HeapFree(GetProcessHeap(), 0, dll->name);
147         HeapFree(GetProcessHeap(), 0, dll);
148     }
149 }
150
151 static void load_library_settings(HWND dialog)
152 {
153     char **overrides = enumerate_values(config_key, keypath("DllOverrides"));
154     char **p;
155     int sel, count = 0;
156
157     sel = SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_GETCURSEL, 0, 0);
158
159     WINE_TRACE("sel=%d\n", sel);
160
161     clear_settings(dialog);
162     
163     if (!overrides || *overrides == NULL)
164     {
165         set_controls_from_selection(dialog);
166         disable(IDC_DLLS_EDITDLL);
167         disable(IDC_DLLS_REMOVEDLL);
168         HeapFree(GetProcessHeap(), 0, overrides);
169         return;
170     }
171
172     enable(IDC_DLLS_EDITDLL);
173     enable(IDC_DLLS_REMOVEDLL);
174     
175     for (p = overrides; *p != NULL; p++)
176     {
177         int index;
178         char *str, *value;
179         const char *label;
180         struct dll *dll;
181
182         value = get_reg_key(config_key, keypath("DllOverrides"), *p, NULL);
183
184         label = mode_to_label(string_to_mode(value));
185         
186         str = HeapAlloc(GetProcessHeap(), 0, strlen(*p) + 2 + strlen(label) + 2);
187         strcpy(str, *p);
188         strcat(str, " (");
189         strcat(str, label);
190         strcat(str, ")");
191
192         dll = HeapAlloc(GetProcessHeap(), 0, sizeof(struct dll));
193         dll->name = *p;
194         dll->mode = string_to_mode(value);
195
196         index = SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_ADDSTRING, (WPARAM) -1, (LPARAM) str);
197         SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_SETITEMDATA, index, (LPARAM) dll);
198
199         HeapFree(GetProcessHeap(), 0, str);
200
201         count++;
202     }
203
204     HeapFree(GetProcessHeap(), 0, overrides);
205
206     /* restore the previous selection, if possible  */
207     if (sel >= count - 1) sel = count - 1;
208     else if (sel == -1) sel = 0;
209     
210     SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_SETCURSEL, sel, 0);
211
212     set_controls_from_selection(dialog);
213 }
214
215 /* Called when the application is initialized (cannot reinit!)  */
216 static void init_libsheet(HWND dialog)
217 {
218     /* clear the add dll controls  */
219     SendDlgItemMessage(dialog, IDC_DLLCOMBO, WM_SETTEXT, 1, (LPARAM) "");
220     disable(IDC_DLLS_ADDDLL);
221 }
222
223 static void on_add_combo_change(HWND dialog)
224 {
225     char buffer[1024];
226
227     SendDlgItemMessage(dialog, IDC_DLLCOMBO, WM_GETTEXT, sizeof(buffer), (LPARAM) buffer);
228
229     if (strlen(buffer))
230         enable(IDC_DLLS_ADDDLL)
231     else
232         disable(IDC_DLLS_ADDDLL);
233 }
234
235 static void set_dllmode(HWND dialog, DWORD id)
236 {
237     enum dllmode mode;
238     struct dll *dll;
239     int sel;
240     const char *str;
241
242     mode = id_to_mode(id);
243
244     sel = SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_GETCURSEL, 0, 0);
245     if (sel == -1) return;
246     
247     dll = (struct dll *) SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_GETITEMDATA, sel, 0);
248
249     str = mode_to_string(mode);
250     WINE_TRACE("Setting %s to %s\n", dll->name, str);
251     
252     SendMessage(GetParent(dialog), PSM_CHANGED, 0, 0);
253     set_reg_key(config_key, keypath("DllOverrides"), dll->name, str);
254
255     load_library_settings(dialog);  /* ... and refresh  */
256 }
257
258 static void on_add_click(HWND dialog)
259 {
260     static const char dotDll[] = ".dll";
261     char buffer[1024], *ptr;
262
263     ZeroMemory(buffer, sizeof(buffer));
264
265     SendDlgItemMessage(dialog, IDC_DLLCOMBO, WM_GETTEXT, sizeof(buffer), (LPARAM) buffer);
266     if (lstrlenA(buffer) >= sizeof(dotDll))
267     {
268         ptr = buffer + lstrlenA(buffer) - sizeof(dotDll) + 1;
269         if (!lstrcmpiA(ptr, dotDll))
270         {
271             WINE_TRACE("Stripping dll extension\n");
272             *ptr = '\0';
273         }
274     }
275     SendDlgItemMessage(dialog, IDC_DLLCOMBO, WM_SETTEXT, 0, (LPARAM) "");
276     disable(IDC_DLLS_ADDDLL);
277     
278     WINE_TRACE("Adding %s as native, builtin", buffer);
279     
280     SendMessage(GetParent(dialog), PSM_CHANGED, 0, 0);
281     set_reg_key(config_key, keypath("DllOverrides"), buffer, "native,builtin");
282
283     load_library_settings(dialog);
284
285     SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_SELECTSTRING, (WPARAM) 0, (LPARAM) buffer);
286
287     set_controls_from_selection(dialog);
288 }
289
290 static INT_PTR CALLBACK loadorder_dlgproc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
291 {
292     static WORD sel;
293
294     switch(uMsg) 
295     {
296     case WM_INITDIALOG:
297         CheckRadioButton(hwndDlg, IDC_RAD_BUILTIN, IDC_RAD_DISABLE, lParam);
298         sel = lParam;
299         return TRUE;
300
301     case WM_COMMAND:
302         if(HIWORD(wParam) != BN_CLICKED) break;
303         switch (LOWORD(wParam))
304         {
305         case IDC_RAD_BUILTIN:
306         case IDC_RAD_NATIVE:
307         case IDC_RAD_BUILTIN_NATIVE:
308         case IDC_RAD_NATIVE_BUILTIN:
309         case IDC_RAD_DISABLE:
310             sel = LOWORD(wParam);
311             return TRUE;
312         case IDOK:
313             EndDialog(hwndDlg, sel);
314             return TRUE;
315         case IDCANCEL:
316             EndDialog(hwndDlg, wParam);
317             return TRUE;
318         }
319     }
320     return FALSE;
321 }
322
323 static void on_edit_click(HWND hwnd)
324 {
325     INT_PTR ret; 
326     int index = SendDlgItemMessage(hwnd, IDC_DLLS_LIST, LB_GETCURSEL, 0, 0);
327     struct dll *dll;
328     DWORD id;
329
330     /* if no override is selected the edit button should be disabled... */
331     assert(index != -1);
332
333     dll = (struct dll *) SendDlgItemMessage(hwnd, IDC_DLLS_LIST, LB_GETITEMDATA, index, 0);
334     id = mode_to_id(dll->mode);
335     
336     ret = DialogBoxParam(0, MAKEINTRESOURCE(IDD_LOADORDER), hwnd, loadorder_dlgproc, id);
337     
338     if(ret != IDCANCEL)
339         set_dllmode(hwnd, ret);
340 }
341
342 static void on_remove_click(HWND dialog)
343 {
344     int sel = SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_GETCURSEL, 0, 0);
345     struct dll *dll;
346
347     if (sel == LB_ERR) return;
348     
349     dll = (struct dll *) SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_GETITEMDATA, sel, 0);
350     
351     SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_DELETESTRING, sel, 0);
352
353     SendMessage(GetParent(dialog), PSM_CHANGED, 0, 0);
354     set_reg_key(config_key, keypath("DllOverrides"), dll->name, NULL);
355
356     HeapFree(GetProcessHeap(), 0, dll->name);
357     HeapFree(GetProcessHeap(), 0, dll);
358
359     if (SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_GETCOUNT, 0, 0) > 0)
360         SendDlgItemMessage(dialog, IDC_DLLS_LIST, LB_SETCURSEL, max(sel - 1, 0), 0);
361     else
362     {
363         disable(IDC_DLLS_EDITDLL);
364         disable(IDC_DLLS_REMOVEDLL);
365     }
366
367     set_controls_from_selection(dialog);
368 }
369
370 INT_PTR CALLBACK
371 LibrariesDlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
372 {
373         switch (uMsg)
374         {
375         case WM_INITDIALOG:
376                 init_libsheet(hDlg);
377                 break;
378         case WM_SHOWWINDOW:
379                 set_window_title(hDlg);
380                 break;
381         case WM_NOTIFY:
382                 switch (((LPNMHDR)lParam)->code) {
383                 case PSN_SETACTIVE:
384                     load_library_settings(hDlg);
385                     break;
386                 }
387                 break;
388         case WM_COMMAND:
389                 switch(HIWORD(wParam)) {
390
391                     /* FIXME: when the user hits enter in the DLL combo box we should invoke the add
392                      * add button, rather than the propsheet OK button. But I don't know how to do that!
393                      */
394                     
395                 case CBN_EDITCHANGE:
396                         if(LOWORD(wParam) == IDC_DLLCOMBO)
397                         {
398                             on_add_combo_change(hDlg);
399                             break;
400                         }
401
402                 case BN_CLICKED:
403                         switch(LOWORD(wParam)) {
404                         case IDC_DLLS_ADDDLL:
405                             on_add_click(hDlg);
406                             break;
407                         case IDC_DLLS_EDITDLL:
408                             on_edit_click(hDlg);
409                             break;
410                         case IDC_DLLS_REMOVEDLL:
411                             on_remove_click(hDlg);
412                             break;
413                         }
414                         break;
415                 case LBN_SELCHANGE:
416                         set_controls_from_selection(hDlg);
417                         break;
418                 }
419                 break;
420         }
421
422         return 0;
423 }