Turn a GDI object into a system object via an explicit Wine extension
[wine/wine64.git] / programs / winetest / gui.c
blob97e365d4d5e789956851aca23b81f712dbaed703
1 /*
2 * GUI support
4 * Copyright 2004 Ferenc Wagner
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.
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.
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
21 #include <windows.h>
22 #include <commctrl.h>
24 #include "resource.h"
25 #include "winetest.h"
27 /* Event object to signal successful window creation to main thread.
29 HANDLE initEvent;
31 /* Dialog handle
33 HWND dialog;
35 /* Progress data for the text* functions and for scaling.
37 unsigned int progressMax, progressCurr;
38 double progressScale;
40 /* Progress group counter for the gui* functions.
42 int progressGroup;
44 WNDPROC DefEditProc;
46 char *
47 renderString (va_list ap)
49 const char *fmt = va_arg (ap, char*);
50 static char buffer[128];
52 vsnprintf (buffer, sizeof buffer, fmt, ap);
53 return buffer;
56 int
57 MBdefault (int uType)
59 static const int matrix[][4] = {{IDOK, 0, 0, 0},
60 {IDOK, IDCANCEL, 0, 0},
61 {IDABORT, IDRETRY, IDIGNORE, 0},
62 {IDYES, IDNO, IDCANCEL, 0},
63 {IDYES, IDNO, 0, 0},
64 {IDRETRY, IDCANCEL, 0, 0}};
65 int type = uType & MB_TYPEMASK;
66 int def = (uType & MB_DEFMASK) / MB_DEFBUTTON2;
68 return matrix[type][def];
71 /* report (R_STATUS, fmt, ...) */
72 int
73 textStatus (va_list ap)
75 char *str = vstrmake (NULL, ap);
77 fputs (str, stderr);
78 fputc ('\n', stderr);
79 free (str);
80 return 0;
83 int
84 guiStatus (va_list ap)
86 size_t len;
87 char *str = vstrmake (&len, ap);
89 if (len > 128) str[129] = 0;
90 SetDlgItemText (dialog, IDC_SB, str);
91 free (str);
92 return 0;
95 /* report (R_PROGRESS, barnum, steps) */
96 int
97 textProgress (va_list ap)
99 progressGroup = va_arg (ap, int);
100 progressMax = va_arg (ap, int);
101 progressCurr = 0;
102 return 0;
106 guiProgress (va_list ap)
108 unsigned int max;
109 HWND pb;
111 progressGroup = va_arg (ap, int);
112 progressMax = max = va_arg (ap, int);
113 progressCurr = 0;
114 if (max > 0xffff) {
115 progressScale = (double)0xffff / max;
116 max = 0xffff;
118 else progressScale = 1;
119 pb = GetDlgItem (dialog, IDC_PB0 + progressGroup * 2);
120 SendMessage (pb, PBM_SETRANGE, 0, MAKELPARAM (0, max));
121 SendMessage (pb, PBM_SETSTEP, (WPARAM)1, 0);
122 return 0;
125 /* report (R_STEP, fmt, ...) */
127 textStep (va_list ap)
129 char *str = vstrmake (NULL, ap);
131 progressCurr++;
132 fputs (str, stderr);
133 fprintf (stderr, " (%d of %d)\n", progressCurr, progressMax);
134 free (str);
135 return 0;
139 guiStep (va_list ap)
141 const int pgID = IDC_ST0 + progressGroup * 2;
142 char *str = vstrmake (NULL, ap);
144 progressCurr++;
145 SetDlgItemText (dialog, pgID, str);
146 SendDlgItemMessage (dialog, pgID+1, PBM_SETPOS,
147 (WPARAM)(progressScale * progressCurr), 0);
148 free (str);
149 return 0;
152 /* report (R_DELTA, inc, fmt, ...) */
154 textDelta (va_list ap)
156 const int inc = va_arg (ap, int);
157 char *str = vstrmake (NULL, ap);
159 progressCurr += inc;
160 fputs (str, stderr);
161 fprintf (stderr, " (%d of %d)\n", progressCurr, progressMax);
162 free (str);
163 return 0;
167 guiDelta (va_list ap)
169 const int inc = va_arg (ap, int);
170 const int pgID = IDC_ST0 + progressGroup * 2;
171 char *str = vstrmake (NULL, ap);
173 progressCurr += inc;
174 SetDlgItemText (dialog, pgID, str);
175 SendDlgItemMessage (dialog, pgID+1, PBM_SETPOS,
176 (WPARAM)(progressScale * progressCurr), 0);
177 free (str);
178 return 0;
181 /* report (R_TAG) */
183 textTag (va_list ap)
185 fputs ("Tag: ", stderr);
186 fputs (tag, stderr);
187 fputc ('\n', stderr);
188 return 0;
192 guiTag (va_list ap)
194 SetDlgItemText (dialog, IDC_TAG, tag);
195 return 0;
198 /* report (R_DIR, fmt, ...) */
200 textDir (va_list ap)
202 char *str = vstrmake (NULL, ap);
204 fputs ("Temporary directory: ", stderr);
205 fputs (str, stderr);
206 fputc ('\n', stderr);
207 free (str);
208 return 0;
212 guiDir (va_list ap)
214 char *str = vstrmake (NULL, ap);
216 SetDlgItemText (dialog, IDC_DIR, str);
217 free (str);
218 return 0;
221 /* report (R_OUT, fmt, ...) */
223 textOut (va_list ap)
225 char *str = vstrmake (NULL, ap);
227 fputs ("Log file: ", stderr);
228 fputs (str, stderr);
229 fputc ('\n', stderr);
230 free (str);
231 return 0;
235 guiOut (va_list ap)
237 char *str = vstrmake (NULL, ap);
239 SetDlgItemText (dialog, IDC_OUT, str);
240 free (str);
241 return 0;
244 /* report (R_WARNING, fmt, ...) */
246 textWarning (va_list ap)
248 fputs ("Warning: ", stderr);
249 textStatus (ap);
250 return 0;
254 guiWarning (va_list ap)
256 char *str = vstrmake (NULL, ap);
258 MessageBox (dialog, str, "Warning", MB_ICONWARNING | MB_OK);
259 free (str);
260 return 0;
263 /* report (R_ERROR, fmt, ...) */
265 textError (va_list ap)
267 fputs ("Error: ", stderr);
268 textStatus (ap);
269 return 0;
273 guiError (va_list ap)
275 char *str = vstrmake (NULL, ap);
277 MessageBox (dialog, str, "Error", MB_ICONERROR | MB_OK);
278 free (str);
279 return 0;
282 /* report (R_FATAL, fmt, ...) */
284 textFatal (va_list ap)
286 textError (ap);
287 exit (1);
291 guiFatal (va_list ap)
293 guiError (ap);
294 exit (1);
297 /* report (R_ASK, type, fmt, ...) */
299 textAsk (va_list ap)
301 int uType = va_arg (ap, int);
302 int ret = MBdefault (uType);
303 char *str = vstrmake (NULL, ap);
305 fprintf (stderr, "Question of type %d: %s\n"
306 "Returning default: %d\n", uType, str, ret);
307 free (str);
308 return ret;
312 guiAsk (va_list ap)
314 int uType = va_arg (ap, int);
315 char *str = vstrmake (NULL, ap);
316 int ret = MessageBox (dialog, str, "Question",
317 MB_ICONQUESTION | uType);
319 free (str);
320 return ret;
323 BOOL CALLBACK
324 EditTagProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
326 switch (msg) {
327 case WM_CHAR:
328 if (wParam == 8) break; /* backspace is OK */
329 if (GetWindowTextLengthA (hwnd) == MAXTAGLEN ||
330 !goodtagchar (wParam)) return TRUE;
331 break;
333 return CallWindowProcA (DefEditProc, hwnd, msg, wParam, lParam);
336 BOOL CALLBACK
337 AskTagProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
339 int len;
341 switch (msg) {
342 case WM_INITDIALOG:
343 DefEditProc = (WNDPROC)SetWindowLongPtr
344 (GetDlgItem (hwnd, IDC_TAG), GWLP_WNDPROC, (LONG_PTR)EditTagProc);
345 return TRUE;
346 case WM_COMMAND:
347 switch (LOWORD (wParam)) {
348 case IDOK:
349 len = GetWindowTextLengthA (GetDlgItem (hwnd, IDC_TAG));
350 tag = xmalloc (len+1);
351 GetDlgItemTextA (hwnd, IDC_TAG, tag, len+1);
352 EndDialog (hwnd, IDOK);
353 return TRUE;
354 case IDABORT:
355 EndDialog (hwnd, IDABORT);
356 return TRUE;
359 return FALSE;
363 guiAskTag (void)
365 return DialogBox (GetModuleHandle (NULL),
366 MAKEINTRESOURCE (IDD_TAG),
367 dialog, AskTagProc);
370 /* Quiet functions */
372 qNoOp (va_list ap)
374 return 0;
378 qFatal (va_list ap)
380 exit (1);
384 qAsk (va_list ap)
386 return MBdefault (va_arg (ap, int));
389 BOOL CALLBACK
390 AboutProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
392 switch (msg) {
393 case WM_COMMAND:
394 switch (LOWORD (wParam)) {
395 case IDCANCEL:
396 EndDialog (hwnd, IDCANCEL);
397 return TRUE;
400 return FALSE;
403 BOOL CALLBACK
404 DlgProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
406 switch (msg) {
407 case WM_INITDIALOG:
408 SendMessage (hwnd, WM_SETICON, ICON_SMALL,
409 (LPARAM)LoadIcon (GetModuleHandle (NULL),
410 MAKEINTRESOURCE (IDI_WINE)));
411 SendMessage (hwnd, WM_SETICON, ICON_BIG,
412 (LPARAM)LoadIcon (GetModuleHandle (NULL),
413 MAKEINTRESOURCE (IDI_WINE)));
414 dialog = hwnd;
415 if (!SetEvent (initEvent)) {
416 report (R_STATUS, "Can't signal main thread: %d",
417 GetLastError ());
418 EndDialog (hwnd, 2);
420 return TRUE;
421 case WM_CLOSE:
422 EndDialog (hwnd, 3);
423 return TRUE;
424 case WM_COMMAND:
425 switch (LOWORD (wParam)) {
426 case IDHELP:
427 DialogBox (GetModuleHandle (NULL),
428 MAKEINTRESOURCE (IDD_ABOUT), hwnd, AboutProc);
429 return TRUE;
430 case IDABORT:
431 report (R_WARNING, "Not implemented");
432 return TRUE;
435 return FALSE;
438 DWORD WINAPI
439 DlgThreadProc ()
441 int ret;
443 InitCommonControls ();
444 ret = DialogBox (GetModuleHandle (NULL),
445 MAKEINTRESOURCE (IDD_STATUS),
446 NULL, DlgProc);
447 switch (ret) {
448 case 0:
449 report (R_WARNING, "Invalid parent handle");
450 break;
451 case 1:
452 report (R_WARNING, "DialogBox failed: %d",
453 GetLastError ());
454 break;
455 case 3:
456 exit (0);
457 default:
458 report (R_STATUS, "Dialog exited: %d", ret);
460 return 0;
464 report (enum report_type t, ...)
466 typedef int r_fun_t (va_list);
468 va_list ap;
469 int ret = 0;
470 static r_fun_t * const text_funcs[] =
471 {textStatus, textProgress, textStep, textDelta,
472 textTag, textDir, textOut,
473 textWarning, textError, textFatal, textAsk};
474 static r_fun_t * const GUI_funcs[] =
475 {guiStatus, guiProgress, guiStep, guiDelta,
476 guiTag, guiDir, guiOut,
477 guiWarning, guiError, guiFatal, guiAsk};
478 static r_fun_t * const quiet_funcs[] =
479 {qNoOp, qNoOp, qNoOp, qNoOp,
480 qNoOp, qNoOp, qNoOp,
481 qNoOp, qNoOp, qFatal, qAsk};
482 static r_fun_t * const * funcs = NULL;
484 switch (t) {
485 case R_TEXTMODE:
486 funcs = text_funcs;
487 return 0;
488 case R_QUIET:
489 funcs = quiet_funcs;
490 return 0;
491 default:
492 break;
495 if (!funcs) {
496 HANDLE DlgThread;
497 DWORD DlgThreadID;
499 funcs = text_funcs;
500 initEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
501 if (!initEvent)
502 report (R_STATUS, "Can't create event object: %d",
503 GetLastError ());
504 else {
505 DlgThread = CreateThread (NULL, 0, DlgThreadProc,
506 NULL, 0, &DlgThreadID);
507 if (!DlgThread)
508 report (R_STATUS, "Can't create GUI thread: %d",
509 GetLastError ());
510 else {
511 DWORD ret = WaitForSingleObject (initEvent, INFINITE);
512 switch (ret) {
513 case WAIT_OBJECT_0:
514 funcs = GUI_funcs;
515 break;
516 case WAIT_TIMEOUT:
517 report (R_STATUS, "GUI creation timed out");
518 break;
519 case WAIT_FAILED:
520 report (R_STATUS, "Wait for GUI failed: %d",
521 GetLastError ());
522 break;
523 default:
524 report (R_STATUS, "Wait returned %d",
525 ret);
526 break;
532 va_start (ap, t);
533 if (t < sizeof text_funcs / sizeof text_funcs[0] &&
534 t < sizeof GUI_funcs / sizeof GUI_funcs[0]) ret = funcs[t](ap);
535 else report (R_WARNING, "unimplemented report type: %d", t);
536 va_end (ap);
537 return ret;