89a310825a3e36db4d20e4a3157920246c272475
[reactos.git] / reactos / apps / utils / winetest / gui.c
1 /*
2 * GUI support
3 *
4 * Copyright 2004 Ferenc Wagner
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 #include <windows.h>
22 #include <commctrl.h>
23
24 #include "resource.h"
25 #include "winetest.h"
26
27 /* Event object to signal successful window creation to main thread.
28 */
29 HANDLE initEvent;
30
31 /* Dialog handle
32 */
33 HWND dialog;
34
35 /* Progress data for the text* functions and for scaling.
36 */
37 unsigned int progressMax, progressCurr;
38 double progressScale;
39
40 /* Progress group counter for the gui* functions.
41 */
42 int progressGroup;
43
44 char *
45 renderString (va_list ap)
46 {
47 const char *fmt = va_arg (ap, char*);
48 static char buffer[128];
49
50 vsnprintf (buffer, sizeof buffer, fmt, ap);
51 return buffer;
52 }
53
54 int
55 MBdefault (int uType)
56 {
57 static const int matrix[][4] = {{IDOK, 0, 0, 0},
58 {IDOK, IDCANCEL, 0, 0},
59 {IDABORT, IDRETRY, IDIGNORE, 0},
60 {IDYES, IDNO, IDCANCEL, 0},
61 {IDYES, IDNO, 0, 0},
62 {IDRETRY, IDCANCEL, 0, 0}};
63 int type = uType & MB_TYPEMASK;
64 int def = (uType & MB_DEFMASK) / MB_DEFBUTTON2;
65
66 return matrix[type][def];
67 }
68
69 /* report (R_STATUS, fmt, ...) */
70 int
71 textStatus (va_list ap)
72 {
73 char *str = vstrmake (NULL, ap);
74
75 fputs (str, stderr);
76 fputc ('\n', stderr);
77 free (str);
78 return 0;
79 }
80
81 int
82 guiStatus (va_list ap)
83 {
84 size_t len;
85 char *str = vstrmake (&len, ap);
86
87 if (len > 128) str[129] = 0;
88 SetDlgItemText (dialog, IDC_SB, str);
89 free (str);
90 return 0;
91 }
92
93 /* report (R_PROGRESS, barnum, steps) */
94 int
95 textProgress (va_list ap)
96 {
97 progressGroup = va_arg (ap, int);
98 progressMax = va_arg (ap, int);
99 progressCurr = 0;
100 return 0;
101 }
102
103 int
104 guiProgress (va_list ap)
105 {
106 unsigned int max;
107 HWND pb;
108
109 progressGroup = va_arg (ap, int);
110 progressMax = max = va_arg (ap, int);
111 progressCurr = 0;
112 if (max > 0xffff) {
113 progressScale = (double)0xffff / max;
114 max = 0xffff;
115 }
116 else progressScale = 1;
117 pb = GetDlgItem (dialog, IDC_PB0 + progressGroup * 2);
118 SendMessage (pb, PBM_SETRANGE, 0, MAKELPARAM (0, max));
119 SendMessage (pb, PBM_SETSTEP, (WPARAM)1, 0);
120 return 0;
121 }
122
123 /* report (R_STEP, fmt, ...) */
124 int
125 textStep (va_list ap)
126 {
127 char *str = vstrmake (NULL, ap);
128
129 progressCurr++;
130 fputs (str, stderr);
131 fprintf (stderr, " (%d of %d)\n", progressCurr, progressMax);
132 free (str);
133 return 0;
134 }
135
136 int
137 guiStep (va_list ap)
138 {
139 const int pgID = IDC_ST0 + progressGroup * 2;
140 char *str = vstrmake (NULL, ap);
141
142 progressCurr++;
143 SetDlgItemText (dialog, pgID, str);
144 SendDlgItemMessage (dialog, pgID+1, PBM_SETPOS,
145 (WPARAM)(progressScale * progressCurr), 0);
146 free (str);
147 return 0;
148 }
149
150 /* report (R_DELTA, inc, fmt, ...) */
151 int
152 textDelta (va_list ap)
153 {
154 const int inc = va_arg (ap, int);
155 char *str = vstrmake (NULL, ap);
156
157 progressCurr += inc;
158 fputs (str, stderr);
159 fprintf (stderr, " (%d of %d)\n", progressCurr, progressMax);
160 free (str);
161 return 0;
162 }
163
164 int
165 guiDelta (va_list ap)
166 {
167 const int inc = va_arg (ap, int);
168 const int pgID = IDC_ST0 + progressGroup * 2;
169 char *str = vstrmake (NULL, ap);
170
171 progressCurr += inc;
172 SetDlgItemText (dialog, pgID, str);
173 SendDlgItemMessage (dialog, pgID+1, PBM_SETPOS,
174 (WPARAM)(progressScale * progressCurr), 0);
175 free (str);
176 return 0;
177 }
178
179 /* report (R_DIR, fmt, ...) */
180 int
181 textDir (va_list ap)
182 {
183 char *str = vstrmake (NULL, ap);
184
185 fputs ("Temporary directory: ", stderr);
186 fputs (str, stderr);
187 fputc ('\n', stderr);
188 free (str);
189 return 0;
190 }
191
192 int
193 guiDir (va_list ap)
194 {
195 char *str = vstrmake (NULL, ap);
196
197 SetDlgItemText (dialog, IDC_DIR, str);
198 free (str);
199 return 0;
200 }
201
202 /* report (R_OUT, fmt, ...) */
203 int
204 textOut (va_list ap)
205 {
206 char *str = vstrmake (NULL, ap);
207
208 fputs ("Log file: ", stderr);
209 fputs (str, stderr);
210 fputc ('\n', stderr);
211 free (str);
212 return 0;
213 }
214
215 int
216 guiOut (va_list ap)
217 {
218 char *str = vstrmake (NULL, ap);
219
220 SetDlgItemText (dialog, IDC_OUT, str);
221 free (str);
222 return 0;
223 }
224
225 /* report (R_WARNING, fmt, ...) */
226 int
227 textWarning (va_list ap)
228 {
229 fputs ("Warning: ", stderr);
230 textStatus (ap);
231 return 0;
232 }
233
234 int
235 guiWarning (va_list ap)
236 {
237 char *str = vstrmake (NULL, ap);
238
239 MessageBox (dialog, str, "Warning", MB_ICONWARNING | MB_OK);
240 free (str);
241 return 0;
242 }
243
244 /* report (R_ERROR, fmt, ...) */
245 int
246 textError (va_list ap)
247 {
248 fputs ("Error: ", stderr);
249 textStatus (ap);
250 return 0;
251 }
252
253 int
254 guiError (va_list ap)
255 {
256 char *str = vstrmake (NULL, ap);
257
258 MessageBox (dialog, str, "Error", MB_ICONERROR | MB_OK);
259 free (str);
260 return 0;
261 }
262
263 /* report (R_FATAL, fmt, ...) */
264 int
265 textFatal (va_list ap)
266 {
267 textError (ap);
268 exit (1);
269 }
270
271 int
272 guiFatal (va_list ap)
273 {
274 guiError (ap);
275 exit (1);
276 }
277
278 /* report (R_ASK, type, fmt, ...) */
279 int
280 textAsk (va_list ap)
281 {
282 int uType = va_arg (ap, int);
283 int ret = MBdefault (uType);
284 char *str = vstrmake (NULL, ap);
285
286 fprintf (stderr, "Question of type %d: %s\n"
287 "Returning default: %d\n", uType, str, ret);
288 free (str);
289 return ret;
290 }
291
292 int
293 guiAsk (va_list ap)
294 {
295 int uType = va_arg (ap, int);
296 char *str = vstrmake (NULL, ap);
297 int ret = MessageBox (dialog, str, "Question",
298 MB_ICONQUESTION | uType);
299
300 free (str);
301 return ret;
302 }
303
304 /* Quiet functions */
305 int
306 qNoOp (va_list ap)
307 {
308 return 0;
309 }
310
311 int
312 qFatal (va_list ap)
313 {
314 exit (1);
315 }
316
317 int
318 qAsk (va_list ap)
319 {
320 return MBdefault (va_arg (ap, int));
321 }
322
323 BOOL CALLBACK
324 AboutProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
325 {
326 switch (msg) {
327 case WM_COMMAND:
328 switch (LOWORD (wParam)) {
329 case IDCANCEL:
330 EndDialog (hwnd, IDCANCEL);
331 return TRUE;
332 }
333 }
334 return FALSE;
335 }
336
337 BOOL CALLBACK
338 DlgProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
339 {
340 switch (msg) {
341 case WM_INITDIALOG:
342 SendMessage (hwnd, WM_SETICON, ICON_SMALL,
343 (LPARAM)LoadIcon (GetModuleHandle (NULL),
344 MAKEINTRESOURCE (IDI_WINE)));
345 SendMessage (hwnd, WM_SETICON, ICON_BIG,
346 (LPARAM)LoadIcon (GetModuleHandle (NULL),
347 MAKEINTRESOURCE (IDI_WINE)));
348 dialog = hwnd;
349 if (!SetEvent (initEvent)) {
350 report (R_STATUS, "Can't signal main thread: %d",
351 GetLastError ());
352 EndDialog (hwnd, 2);
353 }
354 return TRUE;
355 case WM_CLOSE:
356 EndDialog (hwnd, 3);
357 return TRUE;
358 case WM_COMMAND:
359 switch (LOWORD (wParam)) {
360 case IDHELP:
361 DialogBox (GetModuleHandle (NULL),
362 MAKEINTRESOURCE (IDD_ABOUT), hwnd, AboutProc);
363 return TRUE;
364 case IDABORT:
365 report (R_WARNING, "Not implemented");
366 return TRUE;
367 }
368 }
369 return FALSE;
370 }
371
372 DWORD WINAPI
373 DlgThreadProc ()
374 {
375 int ret;
376
377 InitCommonControls ();
378 ret = DialogBox (GetModuleHandle (NULL),
379 MAKEINTRESOURCE (IDD_STATUS),
380 NULL, DlgProc);
381 switch (ret) {
382 case 0:
383 report (R_WARNING, "Invalid parent handle");
384 break;
385 case 1:
386 report (R_WARNING, "DialogBox failed: %d",
387 GetLastError ());
388 break;
389 case 3:
390 exit (0);
391 default:
392 report (R_STATUS, "Dialog exited: %d", ret);
393 }
394 return 0;
395 }
396
397 int
398 report (enum report_type t, ...)
399 {
400 typedef int r_fun_t (va_list);
401
402 va_list ap;
403 int ret = 0;
404 static r_fun_t * const text_funcs[] =
405 {textStatus, textProgress, textStep, textDelta,
406 textDir, textOut,
407 textWarning, textError, textFatal, textAsk};
408 static r_fun_t * const GUI_funcs[] =
409 {guiStatus, guiProgress, guiStep, guiDelta,
410 guiDir, guiOut,
411 guiWarning, guiError, guiFatal, guiAsk};
412 static r_fun_t * const quiet_funcs[] =
413 {qNoOp, qNoOp, qNoOp, qNoOp,
414 qNoOp, qNoOp,
415 qNoOp, qNoOp, qFatal, qAsk};
416 static r_fun_t * const * funcs = NULL;
417
418 switch (t) {
419 case R_TEXTMODE:
420 funcs = text_funcs;
421 return 0;
422 case R_QUIET:
423 funcs = quiet_funcs;
424 return 0;
425 default:
426 break;
427 }
428
429 if (!funcs) {
430 HANDLE DlgThread;
431 DWORD DlgThreadID;
432
433 funcs = text_funcs;
434 initEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
435 if (!initEvent)
436 report (R_STATUS, "Can't create event object: %d",
437 GetLastError ());
438 else {
439 DlgThread = CreateThread (NULL, 0, DlgThreadProc,
440 NULL, 0, &DlgThreadID);
441 if (!DlgThread)
442 report (R_STATUS, "Can't create GUI thread: %d",
443 GetLastError ());
444 else {
445 DWORD ret = WaitForSingleObject (initEvent, INFINITE);
446 switch (ret) {
447 case WAIT_OBJECT_0:
448 funcs = GUI_funcs;
449 break;
450 case WAIT_TIMEOUT:
451 report (R_STATUS, "GUI creation timed out");
452 break;
453 case WAIT_FAILED:
454 report (R_STATUS, "Wait for GUI failed: %d",
455 GetLastError ());
456 break;
457 default:
458 report (R_STATUS, "Wait returned %d",
459 ret);
460 break;
461 }
462 }
463 }
464 }
465
466 va_start (ap, t);
467 if (t < sizeof text_funcs / sizeof text_funcs[0] &&
468 t < sizeof GUI_funcs / sizeof GUI_funcs[0] &&
469 t >= 0) ret = funcs[t](ap);
470 else report (R_WARNING, "unimplemented report type: %d", t);
471 va_end (ap);
472 return ret;
473 }