562 lines
13 KiB
C
562 lines
13 KiB
C
/*
|
|
* GUI support
|
|
*
|
|
* Copyright 2004 Ferenc Wagner
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
*/
|
|
|
|
#include <windows.h>
|
|
#include <commctrl.h>
|
|
|
|
#include "resource.h"
|
|
#include "winetest.h"
|
|
|
|
/* Event object to signal successful window creation to main thread.
|
|
*/
|
|
static HANDLE initEvent;
|
|
|
|
/* Dialog handle
|
|
*/
|
|
static HWND dialog;
|
|
|
|
/* Progress data for the text* functions and for scaling.
|
|
*/
|
|
static unsigned int progressMax, progressCurr;
|
|
static double progressScale;
|
|
|
|
/* Progress group counter for the gui* functions.
|
|
*/
|
|
static int progressGroup;
|
|
|
|
static WNDPROC DefEditProc;
|
|
|
|
static int
|
|
MBdefault (int uType)
|
|
{
|
|
static const int matrix[][4] = {{IDOK, 0, 0, 0},
|
|
{IDOK, IDCANCEL, 0, 0},
|
|
{IDABORT, IDRETRY, IDIGNORE, 0},
|
|
{IDYES, IDNO, IDCANCEL, 0},
|
|
{IDYES, IDNO, 0, 0},
|
|
{IDRETRY, IDCANCEL, 0, 0}};
|
|
int type = uType & MB_TYPEMASK;
|
|
int def = (uType & MB_DEFMASK) / MB_DEFBUTTON2;
|
|
|
|
return matrix[type][def];
|
|
}
|
|
|
|
/* report (R_STATUS, fmt, ...) */
|
|
static int
|
|
textStatus (va_list ap)
|
|
{
|
|
char *str = vstrmake (NULL, ap);
|
|
|
|
fputs (str, stderr);
|
|
fputc ('\n', stderr);
|
|
heap_free (str);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
guiStatus (va_list ap)
|
|
{
|
|
size_t len;
|
|
char *str = vstrmake (&len, ap);
|
|
|
|
if (len > 128) str[129] = 0;
|
|
SetDlgItemText (dialog, IDC_SB, str);
|
|
heap_free (str);
|
|
return 0;
|
|
}
|
|
|
|
/* report (R_PROGRESS, barnum, steps) */
|
|
static int
|
|
textProgress (va_list ap)
|
|
{
|
|
progressGroup = va_arg (ap, int);
|
|
progressMax = va_arg (ap, int);
|
|
progressCurr = 0;
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
guiProgress (va_list ap)
|
|
{
|
|
unsigned int max;
|
|
HWND pb;
|
|
|
|
progressGroup = va_arg (ap, int);
|
|
progressMax = max = va_arg (ap, int);
|
|
progressCurr = 0;
|
|
if (max > 0xffff) {
|
|
progressScale = (double)0xffff / max;
|
|
max = 0xffff;
|
|
}
|
|
else progressScale = 1;
|
|
pb = GetDlgItem (dialog, IDC_PB0 + progressGroup * 2);
|
|
SendMessage (pb, PBM_SETRANGE, 0, MAKELPARAM (0, max));
|
|
SendMessage (pb, PBM_SETSTEP, 1, 0);
|
|
return 0;
|
|
}
|
|
|
|
/* report (R_STEP, fmt, ...) */
|
|
static int
|
|
textStep (va_list ap)
|
|
{
|
|
char *str = vstrmake (NULL, ap);
|
|
|
|
progressCurr++;
|
|
fputs (str, stderr);
|
|
fprintf (stderr, " (%d of %d)\n", progressCurr, progressMax);
|
|
heap_free (str);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
guiStep (va_list ap)
|
|
{
|
|
const int pgID = IDC_ST0 + progressGroup * 2;
|
|
char *str = vstrmake (NULL, ap);
|
|
|
|
progressCurr++;
|
|
SetDlgItemText (dialog, pgID, str);
|
|
SendDlgItemMessage (dialog, pgID+1, PBM_SETPOS,
|
|
progressScale * progressCurr, 0);
|
|
heap_free (str);
|
|
return 0;
|
|
}
|
|
|
|
/* report (R_DELTA, inc, fmt, ...) */
|
|
static int
|
|
textDelta (va_list ap)
|
|
{
|
|
const int inc = va_arg (ap, int);
|
|
char *str = vstrmake (NULL, ap);
|
|
|
|
progressCurr += inc;
|
|
fputs (str, stderr);
|
|
fprintf (stderr, " (%d of %d)\n", progressCurr, progressMax);
|
|
heap_free (str);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
guiDelta (va_list ap)
|
|
{
|
|
const int inc = va_arg (ap, int);
|
|
const int pgID = IDC_ST0 + progressGroup * 2;
|
|
char *str = vstrmake (NULL, ap);
|
|
|
|
progressCurr += inc;
|
|
SetDlgItemText (dialog, pgID, str);
|
|
SendDlgItemMessage (dialog, pgID+1, PBM_SETPOS,
|
|
progressScale * progressCurr, 0);
|
|
heap_free (str);
|
|
return 0;
|
|
}
|
|
|
|
/* report (R_TAG) */
|
|
static int
|
|
textTag (va_list ap)
|
|
{
|
|
fputs ("Tag: ", stderr);
|
|
fputs (tag, stderr);
|
|
fputc ('\n', stderr);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
guiTag (va_list ap)
|
|
{
|
|
SetDlgItemText (dialog, IDC_TAG, tag);
|
|
return 0;
|
|
}
|
|
|
|
/* report (R_DIR, fmt, ...) */
|
|
static int
|
|
textDir (va_list ap)
|
|
{
|
|
char *str = vstrmake (NULL, ap);
|
|
|
|
fputs ("Temporary directory: ", stderr);
|
|
fputs (str, stderr);
|
|
fputc ('\n', stderr);
|
|
heap_free (str);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
guiDir (va_list ap)
|
|
{
|
|
char *str = vstrmake (NULL, ap);
|
|
|
|
SetDlgItemText (dialog, IDC_DIR, str);
|
|
heap_free (str);
|
|
return 0;
|
|
}
|
|
|
|
/* report (R_OUT, fmt, ...) */
|
|
static int
|
|
textOut (va_list ap)
|
|
{
|
|
char *str = vstrmake (NULL, ap);
|
|
|
|
fputs ("Log file: ", stderr);
|
|
fputs (str, stderr);
|
|
fputc ('\n', stderr);
|
|
heap_free (str);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
guiOut (va_list ap)
|
|
{
|
|
char *str = vstrmake (NULL, ap);
|
|
|
|
SetDlgItemText (dialog, IDC_OUT, str);
|
|
heap_free (str);
|
|
return 0;
|
|
}
|
|
|
|
/* report (R_WARNING, fmt, ...) */
|
|
static int
|
|
textWarning (va_list ap)
|
|
{
|
|
fputs ("Warning: ", stderr);
|
|
textStatus (ap);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
guiWarning (va_list ap)
|
|
{
|
|
char *str = vstrmake (NULL, ap);
|
|
|
|
MessageBox (dialog, str, "Warning", MB_ICONWARNING | MB_OK);
|
|
heap_free (str);
|
|
return 0;
|
|
}
|
|
|
|
/* report (R_ERROR, fmt, ...) */
|
|
static int
|
|
textError (va_list ap)
|
|
{
|
|
fputs ("Error: ", stderr);
|
|
textStatus (ap);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
guiError (va_list ap)
|
|
{
|
|
char *str = vstrmake (NULL, ap);
|
|
|
|
MessageBox (dialog, str, "Error", MB_ICONERROR | MB_OK);
|
|
heap_free (str);
|
|
return 0;
|
|
}
|
|
|
|
/* report (R_FATAL, fmt, ...) */
|
|
static int
|
|
textFatal (va_list ap)
|
|
{
|
|
textError (ap);
|
|
exit (1);
|
|
}
|
|
|
|
static int
|
|
guiFatal (va_list ap)
|
|
{
|
|
guiError (ap);
|
|
exit (1);
|
|
}
|
|
|
|
/* report (R_ASK, type, fmt, ...) */
|
|
static int
|
|
textAsk (va_list ap)
|
|
{
|
|
int uType = va_arg (ap, int);
|
|
int ret = MBdefault (uType);
|
|
char *str = vstrmake (NULL, ap);
|
|
|
|
fprintf (stderr, "Question of type %d: %s\n"
|
|
"Returning default: %d\n", uType, str, ret);
|
|
heap_free (str);
|
|
return ret;
|
|
}
|
|
|
|
static int
|
|
guiAsk (va_list ap)
|
|
{
|
|
int uType = va_arg (ap, int);
|
|
char *str = vstrmake (NULL, ap);
|
|
int ret = MessageBox (dialog, str, "Question",
|
|
MB_ICONQUESTION | uType);
|
|
|
|
heap_free (str);
|
|
return ret;
|
|
}
|
|
|
|
static BOOL CALLBACK
|
|
EditTagProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch (msg) {
|
|
case WM_CHAR:
|
|
if (wParam == 8) break; /* backspace is OK */
|
|
if (GetWindowTextLengthA (hwnd) == MAXTAGLEN ||
|
|
!goodtagchar (wParam)) return TRUE;
|
|
break;
|
|
}
|
|
return CallWindowProcA (DefEditProc, hwnd, msg, wParam, lParam);
|
|
}
|
|
|
|
static INT_PTR CALLBACK
|
|
AskTagProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
int len;
|
|
|
|
switch (msg) {
|
|
case WM_INITDIALOG:
|
|
DefEditProc = (WNDPROC)SetWindowLongPtr
|
|
(GetDlgItem (hwnd, IDC_TAG), GWLP_WNDPROC, (LONG_PTR)EditTagProc);
|
|
return TRUE;
|
|
case WM_COMMAND:
|
|
switch (LOWORD (wParam)) {
|
|
case IDOK:
|
|
len = GetWindowTextLengthA (GetDlgItem (hwnd, IDC_TAG));
|
|
if(!len) {
|
|
report (R_WARNING, "You must enter a tag to continue");
|
|
return FALSE;
|
|
}
|
|
tag = heap_alloc (len+1);
|
|
GetDlgItemTextA (hwnd, IDC_TAG, tag, len+1);
|
|
EndDialog (hwnd, IDOK);
|
|
return TRUE;
|
|
case IDABORT:
|
|
EndDialog (hwnd, IDABORT);
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
int
|
|
guiAskTag (void)
|
|
{
|
|
return DialogBox (GetModuleHandle (NULL),
|
|
MAKEINTRESOURCE (IDD_TAG),
|
|
dialog, AskTagProc);
|
|
}
|
|
|
|
static INT_PTR CALLBACK
|
|
AskEmailProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
int len;
|
|
|
|
switch (msg)
|
|
{
|
|
case WM_COMMAND:
|
|
switch (LOWORD (wParam)) {
|
|
case IDOK:
|
|
len = GetWindowTextLengthA (GetDlgItem (hwnd, IDC_EMAIL));
|
|
if(!len) {
|
|
report (R_WARNING, "You must enter an email address to continue");
|
|
return FALSE;
|
|
}
|
|
email = heap_alloc (len+1);
|
|
GetDlgItemTextA (hwnd, IDC_EMAIL, email, len+1);
|
|
EndDialog (hwnd, IDOK);
|
|
return TRUE;
|
|
case IDABORT:
|
|
EndDialog (hwnd, IDABORT);
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
int
|
|
guiAskEmail (void)
|
|
{
|
|
return DialogBox (GetModuleHandle (NULL), MAKEINTRESOURCE (IDD_EMAIL), dialog, AskEmailProc);
|
|
}
|
|
|
|
/* Quiet functions */
|
|
static int
|
|
qNoOp (va_list ap)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
qAsk (va_list ap)
|
|
{
|
|
return MBdefault (va_arg (ap, int));
|
|
}
|
|
|
|
static INT_PTR CALLBACK
|
|
AboutProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch (msg) {
|
|
case WM_COMMAND:
|
|
switch (LOWORD (wParam)) {
|
|
case IDCANCEL:
|
|
EndDialog (hwnd, IDCANCEL);
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
static INT_PTR CALLBACK
|
|
DlgProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch (msg) {
|
|
case WM_INITDIALOG:
|
|
SendMessage (hwnd, WM_SETICON, ICON_SMALL,
|
|
(LPARAM)LoadImage( GetModuleHandle (NULL), MAKEINTRESOURCE (IDI_WINE), IMAGE_ICON,
|
|
GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON),
|
|
LR_SHARED ));
|
|
SendMessage (hwnd, WM_SETICON, ICON_BIG,
|
|
(LPARAM)LoadIcon (GetModuleHandle (NULL),
|
|
MAKEINTRESOURCE (IDI_WINE)));
|
|
dialog = hwnd;
|
|
if (!SetEvent (initEvent)) {
|
|
report (R_STATUS, "Can't signal main thread: %d",
|
|
GetLastError ());
|
|
EndDialog (hwnd, 2);
|
|
}
|
|
return TRUE;
|
|
case WM_CLOSE:
|
|
EndDialog (hwnd, 3);
|
|
return TRUE;
|
|
case WM_COMMAND:
|
|
switch (LOWORD (wParam)) {
|
|
case IDHELP:
|
|
DialogBox (GetModuleHandle (NULL),
|
|
MAKEINTRESOURCE (IDD_ABOUT), hwnd, AboutProc);
|
|
return TRUE;
|
|
case IDABORT:
|
|
report (R_STATUS, "Aborting, please wait...");
|
|
aborting = TRUE;
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
static DWORD WINAPI
|
|
DlgThreadProc (LPVOID param)
|
|
{
|
|
int ret;
|
|
|
|
InitCommonControls ();
|
|
ret = DialogBox (GetModuleHandle (NULL),
|
|
MAKEINTRESOURCE (IDD_STATUS),
|
|
NULL, DlgProc);
|
|
switch (ret) {
|
|
case 0:
|
|
report (R_FATAL, "Cannot display dialog");
|
|
break;
|
|
case 1:
|
|
report (R_WARNING, "DialogBox failed: %d",
|
|
GetLastError ());
|
|
break;
|
|
case 3:
|
|
exit (0);
|
|
default:
|
|
report (R_STATUS, "Dialog exited: %d", ret);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
report (enum report_type t, ...)
|
|
{
|
|
typedef int r_fun_t (va_list);
|
|
|
|
va_list ap;
|
|
int ret = 0;
|
|
static r_fun_t * const text_funcs[] =
|
|
{textStatus, textProgress, textStep, textDelta,
|
|
textTag, textDir, textOut,
|
|
textWarning, textError, textFatal, textAsk};
|
|
static r_fun_t * const GUI_funcs[] =
|
|
{guiStatus, guiProgress, guiStep, guiDelta,
|
|
guiTag, guiDir, guiOut,
|
|
guiWarning, guiError, guiFatal, guiAsk};
|
|
static r_fun_t * const quiet_funcs[] =
|
|
{qNoOp, qNoOp, qNoOp, qNoOp,
|
|
qNoOp, qNoOp, qNoOp,
|
|
qNoOp, textError, textFatal, qAsk};
|
|
static r_fun_t * const * funcs = NULL;
|
|
|
|
switch (t) {
|
|
case R_TEXTMODE:
|
|
funcs = text_funcs;
|
|
return 0;
|
|
case R_QUIET:
|
|
funcs = quiet_funcs;
|
|
return 0;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (!funcs) {
|
|
HANDLE DlgThread;
|
|
DWORD DlgThreadID;
|
|
|
|
funcs = text_funcs;
|
|
initEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
|
|
if (!initEvent)
|
|
report (R_STATUS, "Can't create event object: %d",
|
|
GetLastError ());
|
|
else {
|
|
DlgThread = CreateThread (NULL, 0, DlgThreadProc,
|
|
NULL, 0, &DlgThreadID);
|
|
if (!DlgThread)
|
|
report (R_STATUS, "Can't create GUI thread: %d",
|
|
GetLastError ());
|
|
else {
|
|
DWORD ret = WaitForSingleObject (initEvent, INFINITE);
|
|
switch (ret) {
|
|
case WAIT_OBJECT_0:
|
|
funcs = GUI_funcs;
|
|
break;
|
|
case WAIT_TIMEOUT:
|
|
report (R_STATUS, "GUI creation timed out");
|
|
break;
|
|
case WAIT_FAILED:
|
|
report (R_STATUS, "Wait for GUI failed: %d",
|
|
GetLastError ());
|
|
break;
|
|
default:
|
|
report (R_STATUS, "Wait returned %d",
|
|
ret);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
va_start (ap, t);
|
|
if (t < sizeof text_funcs / sizeof text_funcs[0] &&
|
|
t < sizeof GUI_funcs / sizeof GUI_funcs[0]) ret = funcs[t](ap);
|
|
else report (R_WARNING, "unimplemented report type: %d", t);
|
|
va_end (ap);
|
|
return ret;
|
|
}
|