shithub: puzzles

Download patch

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;
 }