Introduce a versioning mechanism, and an `About' box in all front

ends. Versioning will be done solely by Subversion revision number,
since development on these puzzles is very incremental and gradual
and there don't tend to be obvious points to place numbered
releases.

[originally from svn r5781]
This commit is contained in:
Simon Tatham
2005-05-15 10:31:11 +00:00
parent 68d27f0526
commit c05b4697a8
7 changed files with 395 additions and 15 deletions

40
Recipe
View File

@ -14,7 +14,7 @@
!makefile osx Makefile.osx !makefile osx Makefile.osx
WINDOWS = windows user32.lib gdi32.lib comctl32.lib WINDOWS = windows user32.lib gdi32.lib comctl32.lib
COMMON = midend misc malloc random COMMON = midend misc malloc random version
NET = net tree234 NET = net tree234
NETSLIDE = netslide tree234 NETSLIDE = netslide tree234
@ -84,3 +84,41 @@ Puzzles.dmg: Puzzles
# be built on a regular basis. # be built on a regular basis.
nullgame : [X] gtk COMMON nullgame nullgame : [X] gtk COMMON nullgame
nullgame : [G] WINDOWS COMMON nullgame nullgame : [G] WINDOWS COMMON nullgame
# Version management.
!begin vc
version.obj: *.c *.h
cl $(VER) $(CFLAGS) /c version.c
!end
!specialobj vc version
!begin cygwin
version.o: FORCE
FORCE:
$(CC) $(COMPAT) $(XFLAGS) $(CFLAGS) $(VER) -c version.c
!end
!specialobj cygwin version
# For Unix, we also need the gross MD5 hack that causes automatic
# version number selection in release source archives.
!begin gtk
version.o: FORCE;
FORCE:
if test -z "$(VER)" && md5sum -c manifest; then \
$(CC) $(COMPAT) $(XFLAGS) $(CFLAGS) `cat version.def` -c version.c; \
else \
$(CC) $(COMPAT) $(XFLAGS) $(CFLAGS) $(VER) -c version.c; \
fi
!end
!specialobj gtk version
# For OS X, this is made more fiddly by the fact that we don't have
# md5sum readily available. We do, however, have `md5 -r' which
# generates _nearly_ the same output, but it has no check function.
!begin osx
version.o: FORCE;
FORCE:
if test -z "$(VER)" && test -f manifest && (md5 -r `awk '{print $$2}' manifest` | diff -w manifest -); then \
$(CC) $(COMPAT) $(XFLAGS) $(CFLAGS) `cat version.def` -c version.c; \
else \
$(CC) $(COMPAT) $(XFLAGS) $(CFLAGS) $(VER) -c version.c; \
fi
!end
!specialobj osx version

37
gtk.c
View File

@ -525,7 +525,7 @@ static int win_key_press(GtkWidget *widget, GdkEventKey *event, gpointer data)
return FALSE; return FALSE;
} }
void error_box(GtkWidget *parent, char *msg) void message_box(GtkWidget *parent, char *title, char *msg, int centre)
{ {
GtkWidget *window, *hbox, *text, *ok; GtkWidget *window, *hbox, *text, *ok;
@ -538,7 +538,7 @@ void error_box(GtkWidget *parent, char *msg)
hbox, FALSE, FALSE, 20); hbox, FALSE, FALSE, 20);
gtk_widget_show(text); gtk_widget_show(text);
gtk_widget_show(hbox); gtk_widget_show(hbox);
gtk_window_set_title(GTK_WINDOW(window), "Error"); gtk_window_set_title(GTK_WINDOW(window), title);
gtk_label_set_line_wrap(GTK_LABEL(text), TRUE); gtk_label_set_line_wrap(GTK_LABEL(text), TRUE);
ok = gtk_button_new_with_label("OK"); ok = gtk_button_new_with_label("OK");
gtk_box_pack_end(GTK_BOX(GTK_DIALOG(window)->action_area), gtk_box_pack_end(GTK_BOX(GTK_DIALOG(window)->action_area),
@ -559,6 +559,11 @@ void error_box(GtkWidget *parent, char *msg)
gtk_main(); gtk_main();
} }
void error_box(GtkWidget *parent, char *msg)
{
message_box(parent, "Error", msg, FALSE);
}
static void config_ok_button_clicked(GtkButton *button, gpointer data) static void config_ok_button_clicked(GtkButton *button, gpointer data)
{ {
frontend *fe = (frontend *)data; frontend *fe = (frontend *)data;
@ -949,6 +954,21 @@ static void menu_config_event(GtkMenuItem *menuitem, gpointer data)
fe->h = y; fe->h = y;
} }
static void menu_about_event(GtkMenuItem *menuitem, gpointer data)
{
frontend *fe = (frontend *)data;
char titlebuf[256];
char textbuf[1024];
sprintf(titlebuf, "About %.200s", thegame.name);
sprintf(textbuf,
"%.200s\n\n"
"from Simon Tatham's Portable Puzzle Collection\n\n"
"%.500s", thegame.name, ver);
message_box(fe->window, titlebuf, textbuf, TRUE);
}
static GtkWidget *add_menu_item_with_key(frontend *fe, GtkContainer *cont, static GtkWidget *add_menu_item_with_key(frontend *fe, GtkContainer *cont,
char *text, int key) char *text, int key)
{ {
@ -1080,6 +1100,19 @@ static frontend *new_window(char *game_id, char **error)
add_menu_separator(GTK_CONTAINER(menu)); add_menu_separator(GTK_CONTAINER(menu));
add_menu_item_with_key(fe, GTK_CONTAINER(menu), "Exit", 'q'); add_menu_item_with_key(fe, GTK_CONTAINER(menu), "Exit", 'q');
menuitem = gtk_menu_item_new_with_label("Help");
gtk_container_add(GTK_CONTAINER(menubar), menuitem);
gtk_widget_show(menuitem);
menu = gtk_menu_new();
gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), menu);
menuitem = gtk_menu_item_new_with_label("About");
gtk_container_add(GTK_CONTAINER(menu), menuitem);
gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
GTK_SIGNAL_FUNC(menu_about_event), fe);
gtk_widget_show(menuitem);
{ {
int i, ncolours; int i, ncolours;
float *colours; float *colours;

View File

@ -51,6 +51,7 @@ while (<IN>) {
if ($_[0] eq "!name") { $project_name = $_[1]; next; } if ($_[0] eq "!name") { $project_name = $_[1]; next; }
if ($_[0] eq "!srcdir") { push @srcdirs, $_[1]; next; } if ($_[0] eq "!srcdir") { push @srcdirs, $_[1]; next; }
if ($_[0] eq "!makefile" and &mfval($_[1])) { $makefiles{$_[1]}=$_[2]; next;} if ($_[0] eq "!makefile" and &mfval($_[1])) { $makefiles{$_[1]}=$_[2]; next;}
if ($_[0] eq "!specialobj" and &mfval($_[1])) { $specialobj{$_[1]}->{$_[2]} = 1; next;}
if ($_[0] eq "!begin") { if ($_[0] eq "!begin") {
if (&mfval($_[1])) { if (&mfval($_[1])) {
$divert = \$makefile_extra{$_[1]}; $divert = \$makefile_extra{$_[1]};
@ -299,6 +300,7 @@ sub deps {
@ret = (); @ret = ();
$depchar ||= ':'; $depchar ||= ':';
foreach $i (sort keys %depends) { foreach $i (sort keys %depends) {
next if $specialobj{$mftyp}->{$i};
if ($i =~ /^(.*)\.(res|rsrc)/) { if ($i =~ /^(.*)\.(res|rsrc)/) {
next if !defined $rtmpl; next if !defined $rtmpl;
$y = $1; $y = $1;

103
osx.m
View File

@ -232,6 +232,98 @@ NSMenuItem *newitem(NSMenu *parent, char *title, char *key,
parent, title, key, target, action); parent, title, key, target, action);
} }
/* ----------------------------------------------------------------------
* About box.
*/
@class AboutBox;
@interface AboutBox : NSWindow
{
}
- (id)init;
@end
@implementation AboutBox
- (id)init
{
NSRect totalrect;
NSView *views[16];
int nviews = 0;
NSImageView *iv;
NSTextField *tf;
NSFont *font1 = [NSFont systemFontOfSize:0];
NSFont *font2 = [NSFont boldSystemFontOfSize:[font1 pointSize] * 1.1];
const int border = 24;
int i;
double y;
/*
* Construct the controls that go in the About box.
*/
iv = [[NSImageView alloc] initWithFrame:NSMakeRect(0,0,64,64)];
[iv setImage:[NSImage imageNamed:@"NSApplicationIcon"]];
views[nviews++] = iv;
tf = [[NSTextField alloc]
initWithFrame:NSMakeRect(0,0,400,1)];
[tf setEditable:NO];
[tf setSelectable:NO];
[tf setBordered:NO];
[tf setDrawsBackground:NO];
[tf setFont:font2];
[tf setStringValue:@"Simon Tatham's Portable Puzzle Collection"];
[tf sizeToFit];
views[nviews++] = tf;
tf = [[NSTextField alloc]
initWithFrame:NSMakeRect(0,0,400,1)];
[tf setEditable:NO];
[tf setSelectable:NO];
[tf setBordered:NO];
[tf setDrawsBackground:NO];
[tf setFont:font1];
[tf setStringValue:[NSString stringWithCString:ver]];
[tf sizeToFit];
views[nviews++] = tf;
/*
* Lay the controls out.
*/
totalrect = NSMakeRect(0,0,0,0);
for (i = 0; i < nviews; i++) {
NSRect r = [views[i] frame];
if (totalrect.size.width < r.size.width)
totalrect.size.width = r.size.width;
totalrect.size.height += border + r.size.height;
}
totalrect.size.width += 2 * border;
totalrect.size.height += border;
y = totalrect.size.height;
for (i = 0; i < nviews; i++) {
NSRect r = [views[i] frame];
r.origin.x = (totalrect.size.width - r.size.width) / 2;
y -= border + r.size.height;
r.origin.y = y;
[views[i] setFrame:r];
}
self = [super initWithContentRect:totalrect
styleMask:(NSTitledWindowMask | NSMiniaturizableWindowMask |
NSClosableWindowMask)
backing:NSBackingStoreBuffered
defer:YES];
for (i = 0; i < nviews; i++)
[[self contentView] addSubview:views[i]];
[self center]; /* :-) */
return self;
}
@end
/* ---------------------------------------------------------------------- /* ----------------------------------------------------------------------
* The front end presented to midend.c. * The front end presented to midend.c.
* *
@ -1169,6 +1261,7 @@ void status_bar(frontend *fe, char *text)
{ {
} }
- (void)newGameWindow:(id)sender; - (void)newGameWindow:(id)sender;
- (void)about:(id)sender;
@end @end
@implementation AppController @implementation AppController
@ -1182,6 +1275,14 @@ void status_bar(frontend *fe, char *text)
[win makeKeyAndOrderFront:self]; [win makeKeyAndOrderFront:self];
} }
- (void)about:(id)sender
{
id win;
win = [[AboutBox alloc] init];
[win makeKeyAndOrderFront:self];
}
- (NSMenu *)applicationDockMenu:(NSApplication *)sender - (NSMenu *)applicationDockMenu:(NSApplication *)sender
{ {
NSMenu *menu = newmenu("Dock Menu"); NSMenu *menu = newmenu("Dock Menu");
@ -1224,6 +1325,8 @@ int main(int argc, char **argv)
[NSApp setMainMenu: newmenu("Main Menu")]; [NSApp setMainMenu: newmenu("Main Menu")];
menu = newsubmenu([NSApp mainMenu], "Apple Menu"); menu = newsubmenu([NSApp mainMenu], "Apple Menu");
item = newitem(menu, "About Puzzles", "", NULL, @selector(about:));
[menu addItem:[NSMenuItem separatorItem]];
[NSApp setServicesMenu:newsubmenu(menu, "Services")]; [NSApp setServicesMenu:newsubmenu(menu, "Services")];
[menu addItem:[NSMenuItem separatorItem]]; [menu addItem:[NSMenuItem separatorItem]];
item = newitem(menu, "Hide Puzzles", "h", NSApp, @selector(hide:)); item = newitem(menu, "Hide Puzzles", "h", NSApp, @selector(hide:));

View File

@ -161,6 +161,11 @@ char *dupstr(const char *s);
*/ */
void free_cfg(config_item *cfg); void free_cfg(config_item *cfg);
/*
* version.c
*/
extern char ver[];
/* /*
* random.c * random.c
*/ */

16
version.c Normal file
View File

@ -0,0 +1,16 @@
/*
* Puzzles version numbering.
*/
#define STR1(x) #x
#define STR(x) STR1(x)
#if defined REVISION
char ver[] = "Revision: r" STR(REVISION);
#else
char ver[] = "Unidentified build, " __DATE__ " " __TIME__;
#endif

207
windows.c
View File

@ -35,6 +35,7 @@
#define IDM_HELPC 0x00A0 #define IDM_HELPC 0x00A0
#define IDM_GAMEHELP 0x00B0 #define IDM_GAMEHELP 0x00B0
#define IDM_PRESETS 0x0100 #define IDM_PRESETS 0x0100
#define IDM_ABOUT 0x0110
#define HELP_FILE_NAME "puzzles.hlp" #define HELP_FILE_NAME "puzzles.hlp"
#define HELP_CNT_NAME "puzzles.cnt" #define HELP_CNT_NAME "puzzles.cnt"
@ -112,7 +113,7 @@ struct frontend {
int nfonts, fontsize; int nfonts, fontsize;
config_item *cfg; config_item *cfg;
struct cfg_aux *cfgaux; struct cfg_aux *cfgaux;
int cfg_which, cfg_done; int cfg_which, dlg_done;
HFONT cfgfont; HFONT cfgfont;
char *help_path; char *help_path;
int help_has_contents; int help_has_contents;
@ -517,16 +518,18 @@ static frontend *new_window(HINSTANCE inst, char *game_id, char **error)
} }
AppendMenu(menu, MF_SEPARATOR, 0, 0); AppendMenu(menu, MF_SEPARATOR, 0, 0);
AppendMenu(menu, MF_ENABLED, IDM_QUIT, "Exit"); AppendMenu(menu, MF_ENABLED, IDM_QUIT, "Exit");
menu = CreateMenu();
AppendMenu(bar, MF_ENABLED|MF_POPUP, (UINT)menu, "Help");
AppendMenu(menu, MF_ENABLED, IDM_ABOUT, "About");
if (fe->help_path) { if (fe->help_path) {
HMENU hmenu = CreateMenu(); AppendMenu(menu, MF_SEPARATOR, 0, 0);
AppendMenu(bar, MF_ENABLED|MF_POPUP, (UINT)hmenu, "Help"); AppendMenu(menu, MF_ENABLED, IDM_HELPC, "Contents");
AppendMenu(hmenu, MF_ENABLED, IDM_HELPC, "Contents");
if (thegame.winhelp_topic) { if (thegame.winhelp_topic) {
char *item; char *item;
assert(thegame.name); assert(thegame.name);
item = snewn(9+strlen(thegame.name), char); /*ick*/ item = snewn(9+strlen(thegame.name), char); /*ick*/
sprintf(item, "Help on %s", thegame.name); sprintf(item, "Help on %s", thegame.name);
AppendMenu(hmenu, MF_ENABLED, IDM_GAMEHELP, item); AppendMenu(menu, MF_ENABLED, IDM_GAMEHELP, item);
sfree(item); sfree(item);
} }
} }
@ -562,6 +565,30 @@ static frontend *new_window(HINSTANCE inst, char *game_id, char **error)
return fe; return fe;
} }
static int CALLBACK AboutDlgProc(HWND hwnd, UINT msg,
WPARAM wParam, LPARAM lParam)
{
frontend *fe = (frontend *)GetWindowLong(hwnd, GWL_USERDATA);
switch (msg) {
case WM_INITDIALOG:
return 0;
case WM_COMMAND:
if ((HIWORD(wParam) == BN_CLICKED ||
HIWORD(wParam) == BN_DOUBLECLICKED) &&
LOWORD(wParam) == IDOK)
fe->dlg_done = 1;
return 0;
case WM_CLOSE:
fe->dlg_done = 1;
return 0;
}
return 0;
}
static int CALLBACK ConfigDlgProc(HWND hwnd, UINT msg, static int CALLBACK ConfigDlgProc(HWND hwnd, UINT msg,
WPARAM wParam, LPARAM lParam) WPARAM wParam, LPARAM lParam)
{ {
@ -587,10 +614,10 @@ static int CALLBACK ConfigDlgProc(HWND hwnd, UINT msg,
MessageBox(hwnd, err, "Validation error", MessageBox(hwnd, err, "Validation error",
MB_ICONERROR | MB_OK); MB_ICONERROR | MB_OK);
} else { } else {
fe->cfg_done = 2; fe->dlg_done = 2;
} }
} else { } else {
fe->cfg_done = 1; fe->dlg_done = 1;
} }
return 0; return 0;
} }
@ -624,7 +651,7 @@ static int CALLBACK ConfigDlgProc(HWND hwnd, UINT msg,
return 0; return 0;
case WM_CLOSE: case WM_CLOSE:
fe->cfg_done = 1; fe->dlg_done = 1;
return 0; return 0;
} }
@ -633,7 +660,7 @@ static int CALLBACK ConfigDlgProc(HWND hwnd, UINT msg,
HWND mkctrl(frontend *fe, int x1, int x2, int y1, int y2, HWND mkctrl(frontend *fe, int x1, int x2, int y1, int y2,
char *wclass, int wstyle, char *wclass, int wstyle,
int exstyle, char *wtext, int wid) int exstyle, const char *wtext, int wid)
{ {
HWND ret; HWND ret;
ret = CreateWindowEx(exstyle, wclass, wtext, ret = CreateWindowEx(exstyle, wclass, wtext,
@ -643,6 +670,158 @@ HWND mkctrl(frontend *fe, int x1, int x2, int y1, int y2,
return ret; return ret;
} }
static void about(frontend *fe)
{
int i;
WNDCLASS wc;
MSG msg;
TEXTMETRIC tm;
HDC hdc;
HFONT oldfont;
SIZE size;
int gm, id;
int winwidth, winheight, y;
int height, width, maxwid;
const char *strings[16];
int lengths[16];
int nstrings = 0;
char titlebuf[512];
sprintf(titlebuf, "About %.250s", thegame.name);
strings[nstrings++] = thegame.name;
strings[nstrings++] = "from Simon Tatham's Portable Puzzle Collection";
strings[nstrings++] = ver;
wc.style = CS_DBLCLKS | CS_SAVEBITS | CS_BYTEALIGNWINDOW;
wc.lpfnWndProc = DefDlgProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = DLGWINDOWEXTRA + 8;
wc.hInstance = fe->inst;
wc.hIcon = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH) (COLOR_BACKGROUND +1);
wc.lpszMenuName = NULL;
wc.lpszClassName = "GameAboutBox";
RegisterClass(&wc);
hdc = GetDC(fe->hwnd);
SetMapMode(hdc, MM_TEXT);
fe->dlg_done = FALSE;
fe->cfgfont = CreateFont(-MulDiv(8, GetDeviceCaps(hdc, LOGPIXELSY), 72),
0, 0, 0, 0,
FALSE, FALSE, FALSE, DEFAULT_CHARSET,
OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY,
FF_SWISS,
"MS Shell Dlg");
oldfont = SelectObject(hdc, fe->cfgfont);
if (GetTextMetrics(hdc, &tm)) {
height = tm.tmAscent + tm.tmDescent;
width = tm.tmAveCharWidth;
} else {
height = width = 30;
}
/*
* Figure out the layout of the About box by measuring the
* length of each piece of text.
*/
maxwid = 0;
winheight = height/2;
for (i = 0; i < nstrings; i++) {
if (GetTextExtentPoint32(hdc, strings[i], strlen(strings[i]), &size))
lengths[i] = size.cx;
else
lengths[i] = 0; /* *shrug* */
if (maxwid < lengths[i])
maxwid = lengths[i];
winheight += height * 3 / 2 + (height / 2);
}
winheight += height + height * 7 / 4; /* OK button */
winwidth = maxwid + 4*width;
SelectObject(hdc, oldfont);
ReleaseDC(fe->hwnd, hdc);
/*
* Create the dialog, now that we know its size.
*/
{
RECT r, r2;
r.left = r.top = 0;
r.right = winwidth;
r.bottom = winheight;
AdjustWindowRectEx(&r, (WS_OVERLAPPEDWINDOW /*|
DS_MODALFRAME | WS_POPUP | WS_VISIBLE |
WS_CAPTION | WS_SYSMENU*/) &~
(WS_MAXIMIZEBOX | WS_OVERLAPPED),
FALSE, 0);
/*
* Centre the dialog on its parent window.
*/
r.right -= r.left;
r.bottom -= r.top;
GetWindowRect(fe->hwnd, &r2);
r.left = (r2.left + r2.right - r.right) / 2;
r.top = (r2.top + r2.bottom - r.bottom) / 2;
r.right += r.left;
r.bottom += r.top;
fe->cfgbox = CreateWindowEx(0, wc.lpszClassName, titlebuf,
DS_MODALFRAME | WS_POPUP | WS_VISIBLE |
WS_CAPTION | WS_SYSMENU,
r.left, r.top,
r.right-r.left, r.bottom-r.top,
fe->hwnd, NULL, fe->inst, NULL);
}
SendMessage(fe->cfgbox, WM_SETFONT, (WPARAM)fe->cfgfont, FALSE);
SetWindowLong(fe->cfgbox, GWL_USERDATA, (LONG)fe);
SetWindowLong(fe->cfgbox, DWL_DLGPROC, (LONG)AboutDlgProc);
id = 1000;
y = height/2;
for (i = 0; i < nstrings; i++) {
int border = width*2 + (maxwid - lengths[i]) / 2;
mkctrl(fe, border, border+lengths[i], y+height*1/8, y+height*9/8,
"Static", 0, 0, strings[i], id++);
y += height*3/2;
assert(y < winheight);
y += height/2;
}
y += height/2; /* extra space before OK */
mkctrl(fe, width*2, maxwid+width*2, y, y+height*7/4, "BUTTON",
BS_PUSHBUTTON | BS_NOTIFY | WS_TABSTOP | BS_DEFPUSHBUTTON, 0,
"OK", IDOK);
SendMessage(fe->cfgbox, WM_INITDIALOG, 0, 0);
EnableWindow(fe->hwnd, FALSE);
ShowWindow(fe->cfgbox, SW_NORMAL);
while ((gm=GetMessage(&msg, NULL, 0, 0)) > 0) {
if (!IsDialogMessage(fe->cfgbox, &msg))
DispatchMessage(&msg);
if (fe->dlg_done)
break;
}
EnableWindow(fe->hwnd, TRUE);
SetForegroundWindow(fe->hwnd);
DestroyWindow(fe->cfgbox);
DeleteObject(fe->cfgfont);
}
static int get_config(frontend *fe, int which) static int get_config(frontend *fe, int which)
{ {
config_item *i; config_item *i;
@ -674,7 +853,7 @@ static int get_config(frontend *fe, int which)
hdc = GetDC(fe->hwnd); hdc = GetDC(fe->hwnd);
SetMapMode(hdc, MM_TEXT); SetMapMode(hdc, MM_TEXT);
fe->cfg_done = FALSE; fe->dlg_done = FALSE;
fe->cfgfont = CreateFont(-MulDiv(8, GetDeviceCaps(hdc, LOGPIXELSY), 72), fe->cfgfont = CreateFont(-MulDiv(8, GetDeviceCaps(hdc, LOGPIXELSY), 72),
0, 0, 0, 0, 0, 0, 0, 0,
@ -738,6 +917,7 @@ static int get_config(frontend *fe, int which)
col2r = col1l+2*height+maxcheckbox; col2r = col1l+2*height+maxcheckbox;
winwidth = col2r + 2*width; winwidth = col2r + 2*width;
SelectObject(hdc, oldfont);
ReleaseDC(fe->hwnd, hdc); ReleaseDC(fe->hwnd, hdc);
/* /*
@ -869,7 +1049,7 @@ static int get_config(frontend *fe, int which)
while ((gm=GetMessage(&msg, NULL, 0, 0)) > 0) { while ((gm=GetMessage(&msg, NULL, 0, 0)) > 0) {
if (!IsDialogMessage(fe->cfgbox, &msg)) if (!IsDialogMessage(fe->cfgbox, &msg))
DispatchMessage(&msg); DispatchMessage(&msg);
if (fe->cfg_done) if (fe->dlg_done)
break; break;
} }
EnableWindow(fe->hwnd, TRUE); EnableWindow(fe->hwnd, TRUE);
@ -880,7 +1060,7 @@ static int get_config(frontend *fe, int which)
free_cfg(fe->cfg); free_cfg(fe->cfg);
sfree(fe->cfgaux); sfree(fe->cfgaux);
return (fe->cfg_done == 2); return (fe->dlg_done == 2);
} }
static void new_game_type(frontend *fe) static void new_game_type(frontend *fe)
@ -979,6 +1159,9 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
if (get_config(fe, CFG_SEED)) if (get_config(fe, CFG_SEED))
new_game_type(fe); new_game_type(fe);
break; break;
case IDM_ABOUT:
about(fe);
break;
case IDM_HELPC: case IDM_HELPC:
assert(fe->help_path); assert(fe->help_path);
WinHelp(hwnd, fe->help_path, WinHelp(hwnd, fe->help_path,