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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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 static HANDLE initEvent; 30 31 /* Dialog handle 32 */ 33 static HWND dialog; 34 35 /* Progress data for the text* functions and for scaling. 36 */ 37 static unsigned int progressMax, progressCurr; 38 static double progressScale; 39 40 /* Progress group counter for the gui* functions. 41 */ 42 static int progressGroup; 43 44 static WNDPROC DefEditProc; 45 46 static int 47 MBdefault (int uType) 48 { 49 static const int matrix[][4] = {{IDOK, 0, 0, 0}, 50 {IDOK, IDCANCEL, 0, 0}, 51 {IDABORT, IDRETRY, IDIGNORE, 0}, 52 {IDYES, IDNO, IDCANCEL, 0}, 53 {IDYES, IDNO, 0, 0}, 54 {IDRETRY, IDCANCEL, 0, 0}}; 55 int type = uType & MB_TYPEMASK; 56 int def = (uType & MB_DEFMASK) / MB_DEFBUTTON2; 57 58 return matrix[type][def]; 59 } 60 61 /* report (R_STATUS, fmt, ...) */ 62 static int 63 textStatus (va_list ap) 64 { 65 char *str = vstrmake (NULL, ap); 66 67 fputs (str, stderr); 68 fputc ('\n', stderr); 69 free (str); 70 return 0; 71 } 72 73 static int 74 guiStatus (va_list ap) 75 { 76 size_t len; 77 char *str = vstrmake (&len, ap); 78 79 if (len > 128) str[129] = 0; 80 SetDlgItemText (dialog, IDC_SB, str); 81 free (str); 82 return 0; 83 } 84 85 /* report (R_PROGRESS, barnum, steps) */ 86 static int 87 textProgress (va_list ap) 88 { 89 progressGroup = va_arg (ap, int); 90 progressMax = va_arg (ap, int); 91 progressCurr = 0; 92 return 0; 93 } 94 95 static int 96 guiProgress (va_list ap) 97 { 98 unsigned int max; 99 HWND pb; 100 101 progressGroup = va_arg (ap, int); 102 progressMax = max = va_arg (ap, int); 103 progressCurr = 0; 104 if (max > 0xffff) { 105 progressScale = (double)0xffff / max; 106 max = 0xffff; 107 } 108 else progressScale = 1; 109 pb = GetDlgItem (dialog, IDC_PB0 + progressGroup * 2); 110 SendMessage (pb, PBM_SETRANGE, 0, MAKELPARAM (0, max)); 111 SendMessage (pb, PBM_SETSTEP, (WPARAM)1, 0); 112 return 0; 113 } 114 115 /* report (R_STEP, fmt, ...) */ 116 static int 117 textStep (va_list ap) 118 { 119 char *str = vstrmake (NULL, ap); 120 121 progressCurr++; 122 fputs (str, stderr); 123 fprintf (stderr, " (%d of %d)\n", progressCurr, progressMax); 124 free (str); 125 return 0; 126 } 127 128 static int 129 guiStep (va_list ap) 130 { 131 const int pgID = IDC_ST0 + progressGroup * 2; 132 char *str = vstrmake (NULL, ap); 133 134 progressCurr++; 135 SetDlgItemText (dialog, pgID, str); 136 SendDlgItemMessage (dialog, pgID+1, PBM_SETPOS, 137 (WPARAM)(progressScale * progressCurr), 0); 138 free (str); 139 return 0; 140 } 141 142 /* report (R_DELTA, inc, fmt, ...) */ 143 static int 144 textDelta (va_list ap) 145 { 146 const int inc = va_arg (ap, int); 147 char *str = vstrmake (NULL, ap); 148 149 progressCurr += inc; 150 fputs (str, stderr); 151 fprintf (stderr, " (%d of %d)\n", progressCurr, progressMax); 152 free (str); 153 return 0; 154 } 155 156 static int 157 guiDelta (va_list ap) 158 { 159 const int inc = va_arg (ap, int); 160 const int pgID = IDC_ST0 + progressGroup * 2; 161 char *str = vstrmake (NULL, ap); 162 163 progressCurr += inc; 164 SetDlgItemText (dialog, pgID, str); 165 SendDlgItemMessage (dialog, pgID+1, PBM_SETPOS, 166 (WPARAM)(progressScale * progressCurr), 0); 167 free (str); 168 return 0; 169 } 170 171 /* report (R_TAG) */ 172 static int 173 textTag (va_list ap) 174 { 175 fputs ("Tag: ", stderr); 176 fputs (tag, stderr); 177 fputc ('\n', stderr); 178 return 0; 179 } 180 181 static int 182 guiTag (va_list ap) 183 { 184 SetDlgItemText (dialog, IDC_TAG, tag); 185 return 0; 186 } 187 188 /* report (R_DIR, fmt, ...) */ 189 static int 190 textDir (va_list ap) 191 { 192 char *str = vstrmake (NULL, ap); 193 194 fputs ("Temporary directory: ", stderr); 195 fputs (str, stderr); 196 fputc ('\n', stderr); 197 free (str); 198 return 0; 199 } 200 201 static int 202 guiDir (va_list ap) 203 { 204 char *str = vstrmake (NULL, ap); 205 206 SetDlgItemText (dialog, IDC_DIR, str); 207 free (str); 208 return 0; 209 } 210 211 /* report (R_OUT, fmt, ...) */ 212 static int 213 textOut (va_list ap) 214 { 215 char *str = vstrmake (NULL, ap); 216 217 fputs ("Log file: ", stderr); 218 fputs (str, stderr); 219 fputc ('\n', stderr); 220 free (str); 221 return 0; 222 } 223 224 static int 225 guiOut (va_list ap) 226 { 227 char *str = vstrmake (NULL, ap); 228 229 SetDlgItemText (dialog, IDC_OUT, str); 230 free (str); 231 return 0; 232 } 233 234 /* report (R_WARNING, fmt, ...) */ 235 static int 236 textWarning (va_list ap) 237 { 238 fputs ("Warning: ", stderr); 239 textStatus (ap); 240 return 0; 241 } 242 243 static int 244 guiWarning (va_list ap) 245 { 246 char *str = vstrmake (NULL, ap); 247 248 MessageBox (dialog, str, "Warning", MB_ICONWARNING | MB_OK); 249 free (str); 250 return 0; 251 } 252 253 /* report (R_ERROR, fmt, ...) */ 254 static int 255 textError (va_list ap) 256 { 257 fputs ("Error: ", stderr); 258 textStatus (ap); 259 return 0; 260 } 261 262 static int 263 guiError (va_list ap) 264 { 265 char *str = vstrmake (NULL, ap); 266 267 MessageBox (dialog, str, "Error", MB_ICONERROR | MB_OK); 268 free (str); 269 return 0; 270 } 271 272 /* report (R_FATAL, fmt, ...) */ 273 static int 274 textFatal (va_list ap) 275 { 276 textError (ap); 277 exit (1); 278 } 279 280 static int 281 guiFatal (va_list ap) 282 { 283 guiError (ap); 284 exit (1); 285 } 286 287 /* report (R_ASK, type, fmt, ...) */ 288 static int 289 textAsk (va_list ap) 290 { 291 int uType = va_arg (ap, int); 292 int ret = MBdefault (uType); 293 char *str = vstrmake (NULL, ap); 294 295 fprintf (stderr, "Question of type %d: %s\n" 296 "Returning default: %d\n", uType, str, ret); 297 free (str); 298 return ret; 299 } 300 301 static int 302 guiAsk (va_list ap) 303 { 304 int uType = va_arg (ap, int); 305 char *str = vstrmake (NULL, ap); 306 int ret = MessageBox (dialog, str, "Question", 307 MB_ICONQUESTION | uType); 308 309 free (str); 310 return ret; 311 } 312 313 static BOOL CALLBACK 314 EditTagProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 315 { 316 switch (msg) { 317 case WM_CHAR: 318 if (wParam == 8) break; /* backspace is OK */ 319 if (GetWindowTextLengthA (hwnd) == MAXTAGLEN || 320 !goodtagchar (wParam)) return TRUE; 321 break; 322 } 323 return CallWindowProcA (DefEditProc, hwnd, msg, wParam, lParam); 324 } 325 326 static INT_PTR CALLBACK 327 AskTagProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 328 { 329 int len; 330 331 switch (msg) { 332 case WM_INITDIALOG: 333 DefEditProc = (WNDPROC)SetWindowLongPtr 334 (GetDlgItem (hwnd, IDC_TAG), GWLP_WNDPROC, (LONG_PTR)EditTagProc); 335 return TRUE; 336 case WM_COMMAND: 337 switch (LOWORD (wParam)) { 338 case IDOK: 339 len = GetWindowTextLengthA (GetDlgItem (hwnd, IDC_TAG)); 340 tag = xmalloc (len+1); 341 GetDlgItemTextA (hwnd, IDC_TAG, tag, len+1); 342 EndDialog (hwnd, IDOK); 343 return TRUE; 344 case IDABORT: 345 EndDialog (hwnd, IDABORT); 346 return TRUE; 347 } 348 } 349 return FALSE; 350 } 351 352 int 353 guiAskTag (void) 354 { 355 return DialogBox (GetModuleHandle (NULL), 356 MAKEINTRESOURCE (IDD_TAG), 357 dialog, AskTagProc); 358 } 359 360 /* Quiet functions */ 361 static int 362 qNoOp (va_list ap) 363 { 364 return 0; 365 } 366 367 static int 368 qFatal (va_list ap) 369 { 370 exit (1); 371 } 372 373 static int 374 qAsk (va_list ap) 375 { 376 return MBdefault (va_arg (ap, int)); 377 } 378 379 static INT_PTR CALLBACK 380 AboutProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 381 { 382 switch (msg) { 383 case WM_COMMAND: 384 switch (LOWORD (wParam)) { 385 case IDCANCEL: 386 EndDialog (hwnd, IDCANCEL); 387 return TRUE; 388 } 389 } 390 return FALSE; 391 } 392 393 static INT_PTR CALLBACK 394 DlgProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 395 { 396 switch (msg) { 397 case WM_INITDIALOG: 398 SendMessage (hwnd, WM_SETICON, ICON_SMALL, 399 (LPARAM)LoadIcon (GetModuleHandle (NULL), 400 MAKEINTRESOURCE (IDI_WINE))); 401 SendMessage (hwnd, WM_SETICON, ICON_BIG, 402 (LPARAM)LoadIcon (GetModuleHandle (NULL), 403 MAKEINTRESOURCE (IDI_WINE))); 404 dialog = hwnd; 405 if (!SetEvent (initEvent)) { 406 report (R_STATUS, "Can't signal main thread: %d", 407 GetLastError ()); 408 EndDialog (hwnd, 2); 409 } 410 return TRUE; 411 case WM_CLOSE: 412 EndDialog (hwnd, 3); 413 return TRUE; 414 case WM_COMMAND: 415 switch (LOWORD (wParam)) { 416 case IDHELP: 417 DialogBox (GetModuleHandle (NULL), 418 MAKEINTRESOURCE (IDD_ABOUT), hwnd, AboutProc); 419 return TRUE; 420 case IDABORT: 421 report (R_WARNING, "Not implemented"); 422 return TRUE; 423 } 424 } 425 return FALSE; 426 } 427 428 static DWORD WINAPI 429 DlgThreadProc (LPVOID param) 430 { 431 int ret; 432 433 InitCommonControls (); 434 ret = DialogBox (GetModuleHandle (NULL), 435 MAKEINTRESOURCE (IDD_STATUS), 436 NULL, DlgProc); 437 switch (ret) { 438 case 0: 439 report (R_WARNING, "Invalid parent handle"); 440 break; 441 case 1: 442 report (R_WARNING, "DialogBox failed: %d", 443 GetLastError ()); 444 break; 445 case 3: 446 exit (0); 447 default: 448 report (R_STATUS, "Dialog exited: %d", ret); 449 } 450 return 0; 451 } 452 453 int 454 report (enum report_type t, ...) 455 { 456 typedef int r_fun_t (va_list); 457 458 va_list ap; 459 int ret = 0; 460 static r_fun_t * const text_funcs[] = 461 {textStatus, textProgress, textStep, textDelta, 462 textTag, textDir, textOut, 463 textWarning, textError, textFatal, textAsk}; 464 static r_fun_t * const GUI_funcs[] = 465 {guiStatus, guiProgress, guiStep, guiDelta, 466 guiTag, guiDir, guiOut, 467 guiWarning, guiError, guiFatal, guiAsk}; 468 static r_fun_t * const quiet_funcs[] = 469 {qNoOp, qNoOp, qNoOp, qNoOp, 470 qNoOp, qNoOp, qNoOp, 471 qNoOp, qNoOp, qFatal, qAsk}; 472 static r_fun_t * const * funcs = NULL; 473 474 switch (t) { 475 case R_TEXTMODE: 476 funcs = text_funcs; 477 return 0; 478 case R_QUIET: 479 funcs = quiet_funcs; 480 return 0; 481 default: 482 break; 483 } 484 485 if (!funcs) { 486 HANDLE DlgThread; 487 DWORD DlgThreadID; 488 489 funcs = text_funcs; 490 initEvent = CreateEvent (NULL, FALSE, FALSE, NULL); 491 if (!initEvent) 492 report (R_STATUS, "Can't create event object: %d", 493 GetLastError ()); 494 else { 495 DlgThread = CreateThread (NULL, 0, DlgThreadProc, 496 NULL, 0, &DlgThreadID); 497 if (!DlgThread) 498 report (R_STATUS, "Can't create GUI thread: %d", 499 GetLastError ()); 500 else { 501 DWORD ret = WaitForSingleObject (initEvent, INFINITE); 502 switch (ret) { 503 case WAIT_OBJECT_0: 504 funcs = GUI_funcs; 505 break; 506 case WAIT_TIMEOUT: 507 report (R_STATUS, "GUI creation timed out"); 508 break; 509 case WAIT_FAILED: 510 report (R_STATUS, "Wait for GUI failed: %d", 511 GetLastError ()); 512 break; 513 default: 514 report (R_STATUS, "Wait returned %d", 515 ret); 516 break; 517 } 518 } 519 } 520 } 521 522 va_start (ap, t); 523 if (t < sizeof text_funcs / sizeof text_funcs[0] && 524 t < sizeof GUI_funcs / sizeof GUI_funcs[0]) ret = funcs[t](ap); 525 else report (R_WARNING, "unimplemented report type: %d", t); 526 va_end (ap); 527 return ret; 528 } 529