ref: 7b1f7d3e01f0fbb3ff08ba1f20ab1c9f9d7db179
parent: d1cfcffa05958114846836fddcd186b156eeac37
author: Simon Tatham <anakin@pobox.com>
date: Sun Dec 24 10:56:47 EST 2006
HTML Help support for Puzzles, with the same kind of automatic fallback behaviour as PuTTY's support. [originally from svn r7009]
--- a/blackbox.c
+++ b/blackbox.c
@@ -1398,7 +1398,7 @@
#endif
const struct game thegame = {
- "Black Box", "games.blackbox",
+ "Black Box", "games.blackbox", "blackbox",
default_params,
game_fetch_preset,
decode_params,
--- a/bridges.c
+++ b/bridges.c
@@ -2629,7 +2629,7 @@
#endif
const struct game thegame = {
- "Bridges", "games.bridges",
+ "Bridges", "games.bridges", "bridges",
default_params,
game_fetch_preset,
decode_params,
--- a/cube.c
+++ b/cube.c
@@ -1700,7 +1700,7 @@
#endif
const struct game thegame = {
- "Cube", "games.cube",
+ "Cube", "games.cube", "cube",
default_params,
game_fetch_preset,
decode_params,
--- a/dominosa.c
+++ b/dominosa.c
@@ -1740,7 +1740,7 @@
#endif
const struct game thegame = {
- "Dominosa", "games.dominosa",
+ "Dominosa", "games.dominosa", "dominosa",
default_params,
game_fetch_preset,
decode_params,
--- a/fifteen.c
+++ b/fifteen.c
@@ -838,7 +838,7 @@
#endif
const struct game thegame = {
- "Fifteen", "games.fifteen",
+ "Fifteen", "games.fifteen", "fifteen",
default_params,
game_fetch_preset,
decode_params,
--- a/flip.c
+++ b/flip.c
@@ -1266,7 +1266,7 @@
#endif
const struct game thegame = {
- "Flip", "games.flip",
+ "Flip", "games.flip", "flip",
default_params,
game_fetch_preset,
decode_params,
--- a/guess.c
+++ b/guess.c
@@ -1324,7 +1324,7 @@
#endif
const struct game thegame = {
- "Guess", "games.guess",
+ "Guess", "games.guess", "guess",
default_params,
game_fetch_preset,
decode_params,
--- a/inertia.c
+++ b/inertia.c
@@ -2152,7 +2152,7 @@
#endif
const struct game thegame = {
- "Inertia", "games.inertia",
+ "Inertia", "games.inertia", "inertia",
default_params,
game_fetch_preset,
decode_params,
--- a/lightup.c
+++ b/lightup.c
@@ -2216,7 +2216,7 @@
#endif
const struct game thegame = {
- "Light Up", "games.lightup",
+ "Light Up", "games.lightup", "lightup",
default_params,
game_fetch_preset,
decode_params,
--- a/loopy.c
+++ b/loopy.c
@@ -3811,7 +3811,7 @@
#endif
const struct game thegame = {
- "Loopy", "games.loopy",
+ "Loopy", "games.loopy", "loopy",
default_params,
game_fetch_preset,
decode_params,
--- a/map.c
+++ b/map.c
@@ -3084,7 +3084,7 @@
#endif
const struct game thegame = {
- "Map", "games.map",
+ "Map", "games.map", "map",
default_params,
game_fetch_preset,
decode_params,
--- a/mines.c
+++ b/mines.c
@@ -3070,7 +3070,7 @@
#endif
const struct game thegame = {
- "Mines", "games.mines",
+ "Mines", "games.mines", "mines",
default_params,
game_fetch_preset,
decode_params,
--- a/net.c
+++ b/net.c
@@ -2824,7 +2824,7 @@
#endif
const struct game thegame = {
- "Net", "games.net",
+ "Net", "games.net", "net",
default_params,
game_fetch_preset,
decode_params,
--- a/netslide.c
+++ b/netslide.c
@@ -1780,7 +1780,7 @@
#endif
const struct game thegame = {
- "Netslide", "games.netslide",
+ "Netslide", "games.netslide", "netslide",
default_params,
game_fetch_preset,
decode_params,
--- a/nullgame.c
+++ b/nullgame.c
@@ -251,7 +251,7 @@
#endif
const struct game thegame = {
- "Null Game", NULL,
+ "Null Game", NULL, NULL,
default_params,
game_fetch_preset,
decode_params,
--- a/pattern.c
+++ b/pattern.c
@@ -1243,7 +1243,7 @@
#endif
const struct game thegame = {
- "Pattern", "games.pattern",
+ "Pattern", "games.pattern", "pattern",
default_params,
game_fetch_preset,
decode_params,
--- a/pegs.c
+++ b/pegs.c
@@ -1186,7 +1186,7 @@
#endif
const struct game thegame = {
- "Pegs", "games.pegs",
+ "Pegs", "games.pegs", "pegs",
default_params,
game_fetch_preset,
decode_params,
--- a/puzzles.h
+++ b/puzzles.h
@@ -364,7 +364,7 @@
*/
struct game {
const char *name;
- const char *winhelp_topic;
+ const char *winhelp_topic, *htmlhelp_topic;
game_params *(*default_params)(void);
int (*fetch_preset)(int i, char **name, game_params **params);
void (*decode_params)(game_params *, char const *string);
--- a/rect.c
+++ b/rect.c
@@ -2836,7 +2836,7 @@
#endif
const struct game thegame = {
- "Rectangles", "games.rectangles",
+ "Rectangles", "games.rectangles", "rectangles",
default_params,
game_fetch_preset,
decode_params,
--- a/samegame.c
+++ b/samegame.c
@@ -1626,7 +1626,7 @@
#endif
const struct game thegame = {
- "Same Game", "games.samegame",
+ "Same Game", "games.samegame", "samegame",
default_params,
game_fetch_preset,
decode_params,
--- a/sixteen.c
+++ b/sixteen.c
@@ -1014,7 +1014,7 @@
#endif
const struct game thegame = {
- "Sixteen", "games.sixteen",
+ "Sixteen", "games.sixteen", "sixteen",
default_params,
game_fetch_preset,
decode_params,
--- a/slant.c
+++ b/slant.c
@@ -2186,7 +2186,7 @@
#endif
const struct game thegame = {
- "Slant", "games.slant",
+ "Slant", "games.slant", "slant",
default_params,
game_fetch_preset,
decode_params,
--- a/solo.c
+++ b/solo.c
@@ -3052,7 +3052,7 @@
#endif
const struct game thegame = {
- "Solo", "games.solo",
+ "Solo", "games.solo", "solo",
default_params,
game_fetch_preset,
decode_params,
--- a/tents.c
+++ b/tents.c
@@ -2053,7 +2053,7 @@
#endif
const struct game thegame = {
- "Tents", "games.tents",
+ "Tents", "games.tents", "tents",
default_params,
game_fetch_preset,
decode_params,
--- a/twiddle.c
+++ b/twiddle.c
@@ -1181,7 +1181,7 @@
#endif
const struct game thegame = {
- "Twiddle", "games.twiddle",
+ "Twiddle", "games.twiddle", "twiddle",
default_params,
game_fetch_preset,
decode_params,
--- a/unfinished/pearl.c
+++ b/unfinished/pearl.c
@@ -1364,7 +1364,7 @@
#endif
const struct game thegame = {
- "Pearl", NULL,
+ "Pearl", NULL, NULL,
default_params,
game_fetch_preset,
decode_params,
--- a/unfinished/sokoban.c
+++ b/unfinished/sokoban.c
@@ -1414,7 +1414,7 @@
#endif
const struct game thegame = {
- "Sokoban", NULL,
+ "Sokoban", NULL, NULL,
default_params,
game_fetch_preset,
decode_params,
--- a/untangle.c
+++ b/untangle.c
@@ -1425,7 +1425,7 @@
#endif
const struct game thegame = {
- "Untangle", "games.untangle",
+ "Untangle", "games.untangle", "untangle",
default_params,
game_fetch_preset,
decode_params,
--- a/windows.c
+++ b/windows.c
@@ -4,6 +4,7 @@
#include <windows.h>
#include <commctrl.h>
+#include <htmlhelp.h>
#include <stdio.h>
#include <assert.h>
@@ -35,7 +36,17 @@
#define HELP_FILE_NAME "puzzles.hlp"
#define HELP_CNT_NAME "puzzles.cnt"
+#define CHM_FILE_NAME "puzzles.chm"
+typedef HWND (CALLBACK *htmlhelp_t)(HWND, LPCSTR, UINT, DWORD);
+static DWORD html_help_cookie;
+static htmlhelp_t htmlhelp;
+static HINSTANCE hh_dll;
+enum { NONE, HLP, CHM } help_type;
+char *help_path;
+const char *help_topic;
+int help_has_contents;
+
#ifdef DEBUGGING
static FILE *debug_fp = NULL;
static HANDLE debug_hdl = INVALID_HANDLE_VALUE;
@@ -119,8 +130,7 @@
HFONT cfgfont;
HBRUSH oldbr;
HPEN oldpen;
- char *help_path;
- int help_has_contents;
+ int help_running;
enum { DRAWING, PRINTING, NOTHING } drawstatus;
DOCINFO di;
int printcount, printw, printh, printsolns, printcurr, printcolour;
@@ -981,34 +991,153 @@
}
/*
- * See if we can find a help file.
+ * Set up Help and see if we can find a help file.
*/
-static void find_help_file(frontend *fe)
+static void init_help(void)
{
char b[2048], *p, *q, *r;
FILE *fp;
- if (!fe->help_path) {
- GetModuleFileName(NULL, b, sizeof(b) - 1);
- r = b;
- p = strrchr(b, '\\');
- if (p && p >= r) r = p+1;
- q = strrchr(b, ':');
- if (q && q >= r) r = q+1;
- strcpy(r, HELP_FILE_NAME);
- if ( (fp = fopen(b, "r")) != NULL) {
- fe->help_path = dupstr(b);
- fclose(fp);
- } else
- fe->help_path = NULL;
- strcpy(r, HELP_CNT_NAME);
- if ( (fp = fopen(b, "r")) != NULL) {
- fe->help_has_contents = TRUE;
- fclose(fp);
- } else
- fe->help_has_contents = FALSE;
+
+ /*
+ * Find the executable file path, so we can look alongside
+ * it for help files. Trim the filename off the end.
+ */
+ GetModuleFileName(NULL, b, sizeof(b) - 1);
+ r = b;
+ p = strrchr(b, '\\');
+ if (p && p >= r) r = p+1;
+ q = strrchr(b, ':');
+ if (q && q >= r) r = q+1;
+
+ /*
+ * Try HTML Help first.
+ */
+ strcpy(r, CHM_FILE_NAME);
+ if ( (fp = fopen(b, "r")) != NULL) {
+ fclose(fp);
+
+ /*
+ * We have a .CHM. See if we can use it.
+ */
+ hh_dll = LoadLibrary("hhctrl.ocx");
+ if (hh_dll) {
+ htmlhelp = (htmlhelp_t)GetProcAddress(hh_dll, "HtmlHelpA");
+ if (!htmlhelp)
+ FreeLibrary(hh_dll);
+ }
+ if (htmlhelp) {
+ htmlhelp(NULL, NULL, HH_INITIALIZE, (DWORD)&html_help_cookie);
+ help_path = dupstr(b);
+ help_type = CHM;
+ help_topic = thegame.htmlhelp_topic;
+ return;
+ }
}
+
+ /*
+ * Now try old-style .HLP.
+ */
+ strcpy(r, HELP_FILE_NAME);
+ if ( (fp = fopen(b, "r")) != NULL) {
+ fclose(fp);
+
+ help_path = dupstr(b);
+ help_type = HLP;
+
+ help_topic = thegame.winhelp_topic;
+
+ /*
+ * See if there's a .CNT file alongside it.
+ */
+ strcpy(r, HELP_CNT_NAME);
+ if ( (fp = fopen(b, "r")) != NULL) {
+ fclose(fp);
+ help_has_contents = TRUE;
+ } else
+ help_has_contents = FALSE;
+
+ return;
+ }
+
+ help_type = NONE; /* didn't find any */
}
+/*
+ * Start Help.
+ */
+static void start_help(frontend *fe, char *topic)
+{
+ char *str = NULL;
+ int cmd;
+
+ switch (help_type) {
+ case HLP:
+ assert(help_path);
+ if (topic) {
+ str = snewn(10+strlen(topic), char);
+ sprintf(str, "JI(`',`%s')", topic);
+ cmd = HELP_COMMAND;
+ } else if (help_has_contents) {
+ cmd = HELP_FINDER;
+ } else {
+ cmd = HELP_CONTENTS;
+ }
+ WinHelp(fe->hwnd, help_path, cmd, (DWORD)str);
+ fe->help_running = TRUE;
+ break;
+ case CHM:
+ assert(help_path);
+ assert(htmlhelp);
+ if (topic) {
+ str = snewn(20 + strlen(topic) + strlen(help_path), char);
+ sprintf(str, "%s::/%s.html>main", help_path, topic);
+ } else {
+ str = dupstr(help_path);
+ }
+ htmlhelp(fe->hwnd, str, HH_DISPLAY_TOPIC, 0);
+ fe->help_running = TRUE;
+ break;
+ case NONE:
+ assert(!"This shouldn't happen");
+ break;
+ }
+
+ sfree(str);
+}
+
+/*
+ * Stop Help on window cleanup.
+ */
+static void stop_help(frontend *fe)
+{
+ if (fe->help_running) {
+ switch (help_type) {
+ case HLP:
+ WinHelp(fe->hwnd, help_path, HELP_QUIT, 0);
+ break;
+ case CHM:
+ assert(htmlhelp);
+ htmlhelp(NULL, NULL, HH_CLOSE_ALL, 0);
+ break;
+ case NONE:
+ assert(!"This shouldn't happen");
+ break;
+ }
+ fe->help_running = FALSE;
+ }
+}
+
+/*
+ * Terminate Help on process exit.
+ */
+static void cleanup_help(void)
+{
+ if (help_type == CHM) {
+ assert(htmlhelp);
+ htmlhelp(NULL, NULL, HH_UNINITIALIZE, html_help_cookie);
+ }
+}
+
static void check_window_size(frontend *fe, int *px, int *py)
{
RECT r;
@@ -1096,14 +1225,13 @@
}
}
- fe->help_path = NULL;
- find_help_file(fe);
-
fe->inst = inst;
fe->timer = 0;
fe->hwnd = NULL;
+ fe->help_running = FALSE;
+
fe->drawstatus = NOTHING;
fe->dr = NULL;
fe->fontstart = 0;
@@ -1235,10 +1363,10 @@
menu = CreateMenu();
AppendMenu(bar, MF_ENABLED|MF_POPUP, (UINT)menu, "Help");
AppendMenu(menu, MF_ENABLED, IDM_ABOUT, "About");
- if (fe->help_path) {
+ if (help_type != NONE) {
AppendMenu(menu, MF_SEPARATOR, 0, 0);
AppendMenu(menu, MF_ENABLED, IDM_HELPC, "Contents");
- if (thegame.winhelp_topic) {
+ if (help_topic) {
char *item;
assert(thegame.name);
item = snewn(9+strlen(thegame.name), char); /*ick*/
@@ -2091,19 +2219,10 @@
break;
case IDM_HELPC:
- assert(fe->help_path);
- WinHelp(hwnd, fe->help_path,
- fe->help_has_contents ? HELP_FINDER : HELP_CONTENTS, 0);
- break;
+ start_help(fe, NULL);
+ break;
case IDM_GAMEHELP:
- assert(fe->help_path);
- assert(thegame.winhelp_topic);
- {
- char *cmd = snewn(10+strlen(thegame.winhelp_topic), char);
- sprintf(cmd, "JI(`',`%s')", thegame.winhelp_topic);
- WinHelp(hwnd, fe->help_path, HELP_COMMAND, (DWORD)cmd);
- sfree(cmd);
- }
+ start_help(fe, help_topic);
break;
default:
{
@@ -2118,6 +2237,7 @@
}
break;
case WM_DESTROY:
+ stop_help(fe);
PostQuitMessage(0);
return 0;
case WM_PAINT:
@@ -2333,6 +2453,8 @@
while (*cmdline && isspace((unsigned char)*cmdline))
cmdline++;
+ init_help();
+
if (!new_window(inst, *cmdline ? cmdline : NULL, &error)) {
char buf[128];
sprintf(buf, "%.100s Error", thegame.name);
@@ -2343,6 +2465,8 @@
while (GetMessage(&msg, NULL, 0, 0)) {
DispatchMessage(&msg);
}
+
+ cleanup_help();
return msg.wParam;
}