winecfg: Restrict dpi slider to sane values.
[wine] / programs / winecfg / x11drvdlg.c
1 /*
2  * Graphics configuration code
3  *
4  * Copyright 2003 Mark Westcott
5  * Copyright 2003-2004 Mike Hearn
6  * Copyright 2005 Raphael Junqueira
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
26 #include <stdarg.h>
27 #include <stdlib.h>
28 #include <stdio.h>
29
30 #include <windows.h>
31 #include <wine/debug.h>
32
33 #include "resource.h"
34 #include "winecfg.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(winecfg);
37
38 #define RES_MAXLEN 5 /* max number of digits in a screen dimension. 5 digits should be plenty */
39 #define MINDPI 96
40 #define MAXDPI 144      /* making this too high surprises and hurts users */
41 #define DEFDPI 96
42
43 #define IDT_DPIEDIT 0x1234
44
45 static const WCHAR logpixels_reg[] = {'S','y','s','t','e','m','\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\','H','a','r','d','w','a','r','e',' ','P','r','o','f','i','l','e','s','\\','C','u','r','r','e','n','t','\\','S','o','f','t','w','a','r','e','\\','F','o','n','t','s',0};
46 static const WCHAR logpixels[] = {'L','o','g','P','i','x','e','l','s',0};
47
48 static struct SHADERMODE
49 {
50   UINT displayStrID;
51   const char* settingStr;
52 } const D3D_VS_Modes[] = {
53   {IDS_SHADER_MODE_HARDWARE,  "hardware"},
54   {IDS_SHADER_MODE_NONE,      "none"},
55   {0, 0}
56 };
57
58
59 int updating_ui;
60
61 static void update_gui_for_desktop_mode(HWND dialog) {
62     int desktopenabled = FALSE;
63
64     WINE_TRACE("\n");
65     updating_ui = TRUE;
66
67     if (current_app)
68     {
69         disable(IDC_ENABLE_DESKTOP);
70         disable(IDC_DESKTOP_WIDTH);
71         disable(IDC_DESKTOP_HEIGHT);
72         disable(IDC_DESKTOP_SIZE);
73         disable(IDC_DESKTOP_BY);
74         return;
75     }
76     enable(IDC_ENABLE_DESKTOP);
77
78     /* do we have desktop mode enabled? */
79     if (reg_key_exists(config_key, keypath("X11 Driver"), "Desktop"))
80     {
81         char* buf, *bufindex;
82         CheckDlgButton(dialog, IDC_ENABLE_DESKTOP, BST_CHECKED);
83
84         buf = get_reg_key(config_key, keypath("X11 Driver"), "Desktop", "800x600");
85         /* note: this test must match the one in x11drv */
86         if( buf[0] != 'n' &&  buf[0] != 'N' &&  buf[0] != 'F' &&  buf[0] != 'f'
87                 &&  buf[0] != '0') {
88             desktopenabled = TRUE;
89             enable(IDC_DESKTOP_WIDTH);
90             enable(IDC_DESKTOP_HEIGHT);
91             enable(IDC_DESKTOP_SIZE);
92             enable(IDC_DESKTOP_BY);
93
94             bufindex = strchr(buf, 'x');
95             if (bufindex) {
96                 *bufindex = 0;
97                 ++bufindex;
98                 SetWindowText(GetDlgItem(dialog, IDC_DESKTOP_WIDTH), buf);
99                 SetWindowText(GetDlgItem(dialog, IDC_DESKTOP_HEIGHT), bufindex);
100             } else {
101                 WINE_TRACE("Desktop registry entry is malformed\n");
102                 SetWindowText(GetDlgItem(dialog, IDC_DESKTOP_WIDTH), "800");
103                 SetWindowText(GetDlgItem(dialog, IDC_DESKTOP_HEIGHT), "600");
104             }
105         }
106         HeapFree(GetProcessHeap(), 0, buf);
107     }
108     if (!desktopenabled)
109     {
110         CheckDlgButton(dialog, IDC_ENABLE_DESKTOP, BST_UNCHECKED);
111         
112         disable(IDC_DESKTOP_WIDTH);
113         disable(IDC_DESKTOP_HEIGHT);
114         disable(IDC_DESKTOP_SIZE);
115         disable(IDC_DESKTOP_BY);
116
117         SetWindowText(GetDlgItem(dialog, IDC_DESKTOP_WIDTH), "");
118         SetWindowText(GetDlgItem(dialog, IDC_DESKTOP_HEIGHT), "");
119     }
120
121     updating_ui = FALSE;
122 }
123
124 static void init_dialog(HWND dialog)
125 {
126     unsigned int it;
127     char* buf;
128
129     update_gui_for_desktop_mode(dialog);
130
131     updating_ui = TRUE;
132     
133     SendDlgItemMessage(dialog, IDC_DESKTOP_WIDTH, EM_LIMITTEXT, RES_MAXLEN, 0);
134     SendDlgItemMessage(dialog, IDC_DESKTOP_HEIGHT, EM_LIMITTEXT, RES_MAXLEN, 0);
135
136     buf = get_reg_key(config_key, keypath("X11 Driver"), "DXGrab", "N");
137     if (IS_OPTION_TRUE(*buf))
138         CheckDlgButton(dialog, IDC_DX_MOUSE_GRAB, BST_CHECKED);
139     else
140         CheckDlgButton(dialog, IDC_DX_MOUSE_GRAB, BST_UNCHECKED);
141     HeapFree(GetProcessHeap(), 0, buf);
142
143     buf = get_reg_key(config_key, keypath("X11 Driver"), "Managed", "Y");
144     if (IS_OPTION_TRUE(*buf))
145         CheckDlgButton(dialog, IDC_ENABLE_MANAGED, BST_CHECKED);
146     else
147         CheckDlgButton(dialog, IDC_ENABLE_MANAGED, BST_UNCHECKED);
148     HeapFree(GetProcessHeap(), 0, buf);
149
150     buf = get_reg_key(config_key, keypath("X11 Driver"), "Decorated", "Y");
151     if (IS_OPTION_TRUE(*buf))
152         CheckDlgButton(dialog, IDC_ENABLE_DECORATED, BST_CHECKED);
153     else
154         CheckDlgButton(dialog, IDC_ENABLE_DECORATED, BST_UNCHECKED);
155     HeapFree(GetProcessHeap(), 0, buf);
156
157
158     SendDlgItemMessage(dialog, IDC_D3D_VSHADER_MODE, CB_RESETCONTENT, 0, 0);
159     for (it = 0; 0 != D3D_VS_Modes[it].displayStrID; ++it) {
160       SendDlgItemMessageW (dialog, IDC_D3D_VSHADER_MODE, CB_ADDSTRING, 0,
161           (LPARAM)load_string (D3D_VS_Modes[it].displayStrID));
162     }  
163     buf = get_reg_key(config_key, keypath("Direct3D"), "VertexShaderMode", "hardware"); 
164     for (it = 0; NULL != D3D_VS_Modes[it].settingStr; ++it) {
165       if (strcmp(buf, D3D_VS_Modes[it].settingStr) == 0) {
166         SendDlgItemMessage(dialog, IDC_D3D_VSHADER_MODE, CB_SETCURSEL, it, 0);
167         break ;
168       }
169     }
170     if (NULL == D3D_VS_Modes[it].settingStr) {
171       WINE_ERR("Invalid Direct3D VertexShader Mode read from registry (%s)\n", buf);
172     }
173     HeapFree(GetProcessHeap(), 0, buf);
174
175     buf = get_reg_key(config_key, keypath("Direct3D"), "PixelShaderMode", "enabled");
176     if (!strcmp(buf, "enabled"))
177       CheckDlgButton(dialog, IDC_D3D_PSHADER_MODE, BST_CHECKED);
178     else
179       CheckDlgButton(dialog, IDC_D3D_PSHADER_MODE, BST_UNCHECKED);
180     HeapFree(GetProcessHeap(), 0, buf);
181
182     updating_ui = FALSE;
183 }
184
185 static void set_from_desktop_edits(HWND dialog) {
186     char *width, *height, *new;
187
188     if (updating_ui) return;
189     
190     WINE_TRACE("\n");
191
192     width = get_text(dialog, IDC_DESKTOP_WIDTH);
193     height = get_text(dialog, IDC_DESKTOP_HEIGHT);
194
195     if (width == NULL || strcmp(width, "") == 0) {
196         HeapFree(GetProcessHeap(), 0, width);
197         width = strdupA("800");
198     }
199     
200     if (height == NULL || strcmp(height, "") == 0) {
201         HeapFree(GetProcessHeap(), 0, height);
202         height = strdupA("600");
203     }
204
205     new = HeapAlloc(GetProcessHeap(), 0, strlen(width) + strlen(height) + 2 /* x + terminator */);
206     sprintf(new, "%sx%s", width, height);
207     set_reg_key(config_key, keypath("X11 Driver"), "Desktop", new);
208     
209     HeapFree(GetProcessHeap(), 0, width);
210     HeapFree(GetProcessHeap(), 0, height);
211     HeapFree(GetProcessHeap(), 0, new);
212 }
213
214 static void on_enable_desktop_clicked(HWND dialog) {
215     WINE_TRACE("\n");
216     
217     if (IsDlgButtonChecked(dialog, IDC_ENABLE_DESKTOP) == BST_CHECKED) {
218         set_from_desktop_edits(dialog);
219     } else {
220         set_reg_key(config_key, keypath("X11 Driver"), "Desktop", NULL);
221     }
222     
223     update_gui_for_desktop_mode(dialog);
224 }
225
226 static void on_enable_managed_clicked(HWND dialog) {
227     WINE_TRACE("\n");
228     
229     if (IsDlgButtonChecked(dialog, IDC_ENABLE_MANAGED) == BST_CHECKED) {
230         set_reg_key(config_key, keypath("X11 Driver"), "Managed", "Y");
231     } else {
232         set_reg_key(config_key, keypath("X11 Driver"), "Managed", "N");
233     }
234 }
235
236 static void on_enable_decorated_clicked(HWND dialog) {
237     WINE_TRACE("\n");
238
239     if (IsDlgButtonChecked(dialog, IDC_ENABLE_DECORATED) == BST_CHECKED) {
240         set_reg_key(config_key, keypath("X11 Driver"), "Decorated", "Y");
241     } else {
242         set_reg_key(config_key, keypath("X11 Driver"), "Decorated", "N");
243     }
244 }
245
246 static void on_dx_mouse_grab_clicked(HWND dialog) {
247     if (IsDlgButtonChecked(dialog, IDC_DX_MOUSE_GRAB) == BST_CHECKED) 
248         set_reg_key(config_key, keypath("X11 Driver"), "DXGrab", "Y");
249     else
250         set_reg_key(config_key, keypath("X11 Driver"), "DXGrab", "N");
251 }
252
253 static void on_d3d_vshader_mode_changed(HWND dialog) {
254   int selected_mode = SendDlgItemMessage(dialog, IDC_D3D_VSHADER_MODE, CB_GETCURSEL, 0, 0);  
255   set_reg_key(config_key, keypath("Direct3D"), "VertexShaderMode",
256       D3D_VS_Modes[selected_mode].settingStr); 
257 }
258
259 static void on_d3d_pshader_mode_clicked(HWND dialog) {
260     if (IsDlgButtonChecked(dialog, IDC_D3D_PSHADER_MODE) == BST_CHECKED)
261         set_reg_key(config_key, keypath("Direct3D"), "PixelShaderMode", "enabled");
262     else
263         set_reg_key(config_key, keypath("Direct3D"), "PixelShaderMode", "disabled");
264 }
265 static INT read_logpixels_reg(void)
266 {
267     DWORD dwLogPixels;
268     WCHAR *buf = get_reg_keyW(HKEY_LOCAL_MACHINE, logpixels_reg, logpixels, NULL);
269     dwLogPixels = buf ? *buf : DEFDPI;
270     HeapFree(GetProcessHeap(), 0, buf);
271     return dwLogPixels;
272 }
273
274 static void init_dpi_editbox(HWND hDlg)
275 {
276     DWORD dwLogpixels;
277     char szLogpixels[MAXBUFLEN];
278
279     updating_ui = TRUE;
280
281     dwLogpixels = read_logpixels_reg();
282     WINE_TRACE("%u\n", dwLogpixels);
283
284     sprintf(szLogpixels, "%u", dwLogpixels);
285     SetDlgItemText(hDlg, IDC_RES_DPIEDIT, szLogpixels);
286
287     updating_ui = FALSE;
288 }
289
290 static void init_trackbar(HWND hDlg)
291 {
292     HWND hTrackBar = GetDlgItem(hDlg, IDC_RES_TRACKBAR);
293     DWORD dwLogpixels;
294
295     updating_ui = TRUE;
296
297     dwLogpixels = read_logpixels_reg();
298
299     SendMessageW(hTrackBar, TBM_SETRANGE, TRUE, MAKELONG(MINDPI, MAXDPI));
300     SendMessageW(hTrackBar, TBM_SETPOS, TRUE, dwLogpixels);
301
302     updating_ui = FALSE;
303 }
304
305 static void update_dpi_trackbar_from_edit(HWND hDlg, BOOL fix)
306 {
307     DWORD dpi;
308
309     updating_ui = TRUE;
310
311     dpi = GetDlgItemInt(hDlg, IDC_RES_DPIEDIT, NULL, FALSE);
312
313     if (fix)
314     {
315         DWORD fixed_dpi = dpi;
316
317         if (dpi < MINDPI) fixed_dpi = MINDPI;
318         if (dpi > MAXDPI) fixed_dpi = MAXDPI;
319
320         if (fixed_dpi != dpi)
321         {
322             char buf[16];
323
324             dpi = fixed_dpi;
325             sprintf(buf, "%u", dpi);
326             SetDlgItemText(hDlg, IDC_RES_DPIEDIT, buf);
327         }
328     }
329
330     if (dpi >= MINDPI && dpi <= MAXDPI)
331     {
332         SendDlgItemMessage(hDlg, IDC_RES_TRACKBAR, TBM_SETPOS, TRUE, dpi);
333         set_reg_key_dwordW(HKEY_LOCAL_MACHINE, logpixels_reg, logpixels, dpi);
334     }
335
336     updating_ui = FALSE;
337 }
338
339 INT_PTR CALLBACK
340 GraphDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
341 {
342     switch (uMsg) {
343         case WM_INITDIALOG:
344             init_dpi_editbox(hDlg);
345             init_trackbar(hDlg);
346             break;
347
348         case WM_SHOWWINDOW:
349             set_window_title(hDlg);
350             break;
351
352         case WM_TIMER:
353             if (wParam == IDT_DPIEDIT)
354             {
355                 KillTimer(hDlg, IDT_DPIEDIT);
356                 update_dpi_trackbar_from_edit(hDlg, TRUE);
357             }
358             break;
359             
360         case WM_COMMAND:
361             switch(HIWORD(wParam)) {
362                 case EN_CHANGE: {
363                     if (updating_ui) break;
364                     SendMessage(GetParent(hDlg), PSM_CHANGED, 0, 0);
365                     if ( ((LOWORD(wParam) == IDC_DESKTOP_WIDTH) || (LOWORD(wParam) == IDC_DESKTOP_HEIGHT)) && !updating_ui )
366                         set_from_desktop_edits(hDlg);
367                     else if (LOWORD(wParam) == IDC_RES_DPIEDIT)
368                     {
369                         update_dpi_trackbar_from_edit(hDlg, FALSE);
370                         SetTimer(hDlg, IDT_DPIEDIT, 1500, NULL);
371                     }
372                     break;
373                 }
374                 case BN_CLICKED: {
375                     if (updating_ui) break;
376                     SendMessage(GetParent(hDlg), PSM_CHANGED, 0, 0);
377                     switch(LOWORD(wParam)) {
378                         case IDC_ENABLE_DESKTOP: on_enable_desktop_clicked(hDlg); break;
379                         case IDC_ENABLE_MANAGED: on_enable_managed_clicked(hDlg); break;
380                         case IDC_ENABLE_DECORATED: on_enable_decorated_clicked(hDlg); break;
381                         case IDC_DX_MOUSE_GRAB:  on_dx_mouse_grab_clicked(hDlg); break;
382                         case IDC_D3D_PSHADER_MODE: on_d3d_pshader_mode_clicked(hDlg); break;
383                     }
384                     break;
385                 }
386                 case CBN_SELCHANGE: {
387                     SendMessage(GetParent(hDlg), PSM_CHANGED, 0, 0);
388                     switch (LOWORD(wParam)) {
389                     case IDC_D3D_VSHADER_MODE: on_d3d_vshader_mode_changed(hDlg); break;
390                     }
391                     break;
392                 }
393                     
394                 default:
395                     break;
396             }
397             break;
398         
399         
400         case WM_NOTIFY:
401             switch (((LPNMHDR)lParam)->code) {
402                 case PSN_KILLACTIVE: {
403                     SetWindowLongPtr(hDlg, DWLP_MSGRESULT, FALSE);
404                     break;
405                 }
406                 case PSN_APPLY: {
407                     apply();
408                     SetWindowLongPtr(hDlg, DWLP_MSGRESULT, PSNRET_NOERROR);
409                     break;
410                 }
411                 case PSN_SETACTIVE: {
412                     init_dialog (hDlg);
413                     break;
414                 }
415             }
416             break;
417
418         case WM_HSCROLL:
419             switch (wParam) {
420                 default: {
421                     char buf[MAXBUFLEN];
422                     int i = SendMessageW(GetDlgItem(hDlg, IDC_RES_TRACKBAR), TBM_GETPOS, 0, 0);
423                     buf[0] = 0;
424                     sprintf(buf, "%d", i);
425                     SendMessage(GetDlgItem(hDlg, IDC_RES_DPIEDIT), WM_SETTEXT, 0, (LPARAM) buf);
426                     set_reg_key_dwordW(HKEY_LOCAL_MACHINE, logpixels_reg, logpixels, i);
427                     break;
428                 }
429             }
430             break;
431
432         default:
433             break;
434     }
435     return FALSE;
436 }