X-Git-Url: https://git.distorted.org.uk/~mdw/sgt/puzzles/blobdiff_plain/899e7ff54c5c345cac62818d4d13feb1aca790f1..95c76d7c0c76081ab4f389aa1bb7667ee08c99eb:/windows.c diff --git a/windows.c b/windows.c index 2aa8016..0185f01 100644 --- a/windows.c +++ b/windows.c @@ -4,6 +4,9 @@ #include #include +#ifndef NO_HTMLHELP +#include +#endif /* NO_HTMLHELP */ #include #include @@ -35,6 +38,20 @@ #define HELP_FILE_NAME "puzzles.hlp" #define HELP_CNT_NAME "puzzles.cnt" +#ifndef NO_HTMLHELP +#define CHM_FILE_NAME "puzzles.chm" +#endif /* NO_HTMLHELP */ + +#ifndef NO_HTMLHELP +typedef HWND (CALLBACK *htmlhelp_t)(HWND, LPCSTR, UINT, DWORD); +static DWORD html_help_cookie; +static htmlhelp_t htmlhelp; +static HINSTANCE hh_dll; +#endif /* NO_HTMLHELP */ +enum { NONE, HLP, CHM } help_type; +char *help_path; +const char *help_topic; +int help_has_contents; #ifdef DEBUGGING static FILE *debug_fp = NULL; @@ -74,6 +91,11 @@ void debug_printf(char *fmt, ...) } #endif +#define WINFLAGS (WS_OVERLAPPEDWINDOW &~ \ + (WS_THICKFRAME | WS_MAXIMIZEBOX | WS_OVERLAPPED)) + +static void new_game_size(frontend *fe); + struct font { HFONT font; int type; @@ -114,9 +136,7 @@ struct frontend { HFONT cfgfont; HBRUSH oldbr; HPEN oldpen; - char *help_path; - int help_has_contents; - char *laststatus; + int help_running; enum { DRAWING, PRINTING, NOTHING } drawstatus; DOCINFO di; int printcount, printw, printh, printsolns, printcurr, printcolour; @@ -175,16 +195,8 @@ void get_random_seed(void **randseed, int *randseedsize) static void win_status_bar(void *handle, char *text) { frontend *fe = (frontend *)handle; - char *rewritten; - rewritten = midend_rewrite_statusbar(fe->me, text); - if (!fe->laststatus || strcmp(rewritten, fe->laststatus)) { - SetWindowText(fe->statusbar, rewritten); - sfree(fe->laststatus); - fe->laststatus = rewritten; - } else { - sfree(rewritten); - } + SetWindowText(fe->statusbar, text); } static blitter *win_blitter_new(void *handle, int w, int h) @@ -908,7 +920,7 @@ void print(frontend *fe) fe->drawstatus = PRINTING; fe->hdc = pd.hDC; - fe->dr = drawing_init(&win_drawing, fe); + fe->dr = drawing_new(&win_drawing, NULL, fe); document_print(doc, fe->dr); drawing_free(fe->dr); fe->dr = NULL; @@ -985,32 +997,159 @@ void write_clip(HWND hwnd, char *data) } /* - * 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; + +#ifndef NO_HTMLHELP + /* + * 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; + } } +#endif /* NO_HTMLHELP */ + + /* + * 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, const 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: +#ifndef NO_HTMLHELP + 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; +#endif /* NO_HTMLHELP */ + 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: +#ifndef NO_HTMLHELP + assert(htmlhelp); + htmlhelp(NULL, NULL, HH_CLOSE_ALL, 0); + break; +#endif /* NO_HTMLHELP */ + case NONE: + assert(!"This shouldn't happen"); + break; + } + fe->help_running = FALSE; + } +} + +/* + * Terminate Help on process exit. + */ +static void cleanup_help(void) +{ +#ifndef NO_HTMLHELP + if (help_type == CHM) { + assert(htmlhelp); + htmlhelp(NULL, NULL, HH_UNINITIALIZE, html_help_cookie); + } +#endif /* NO_HTMLHELP */ } static void check_window_size(frontend *fe, int *px, int *py) @@ -1042,9 +1181,7 @@ static void check_window_size(frontend *fe, int *px, int *py) r.left = r.top = 0; r.right = x; r.bottom = y + sy; - AdjustWindowRectEx(&r, WS_OVERLAPPEDWINDOW &~ - (WS_THICKFRAME | WS_MAXIMIZEBOX | WS_OVERLAPPED), - TRUE, 0); + AdjustWindowRectEx(&r, WINFLAGS, TRUE, 0); SetWindowPos(fe->hwnd, NULL, 0, 0, r.right - r.left, r.bottom - r.top, SWP_NOMOVE | SWP_NOZORDER); } @@ -1059,12 +1196,35 @@ static void check_window_size(frontend *fe, int *px, int *py) *py = y; } +static void get_max_puzzle_size(frontend *fe, int *x, int *y) +{ + RECT r, sr; + + if (SystemParametersInfo(SPI_GETWORKAREA, 0, &sr, FALSE)) { + *x = sr.right - sr.left; + *y = sr.bottom - sr.top; + r.left = 100; + r.right = 200; + r.top = 100; + r.bottom = 200; + AdjustWindowRectEx(&r, WINFLAGS, TRUE, 0); + *x -= r.right - r.left - 100; + *y -= r.bottom - r.top - 100; + } else { + *x = *y = INT_MAX; + } + + if (fe->statusbar != NULL) { + GetWindowRect(fe->statusbar, &sr); + *y -= sr.bottom - sr.top; + } +} + static frontend *new_window(HINSTANCE inst, char *game_id, char **error) { frontend *fe; int x, y; RECT r; - HDC hdc; fe = snew(frontend); @@ -1079,14 +1239,13 @@ static frontend *new_window(HINSTANCE inst, char *game_id, char **error) } } - 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; @@ -1096,8 +1255,6 @@ static frontend *new_window(HINSTANCE inst, char *game_id, char **error) fe->fonts = NULL; fe->nfonts = fe->fontsize = 0; - fe->laststatus = NULL; - { int i, ncolours; float *colours; @@ -1115,17 +1272,24 @@ static frontend *new_window(HINSTANCE inst, char *game_id, char **error) fe->brushes[i] = CreateSolidBrush(fe->colours[i]); fe->pens[i] = CreatePen(PS_SOLID, 1, fe->colours[i]); } + sfree(colours); } - x = y = INT_MAX; /* find puzzle's preferred size */ + if (midend_wants_statusbar(fe->me)) { + fe->statusbar = CreateWindowEx(0, STATUSCLASSNAME, "ooh", + WS_CHILD | WS_VISIBLE, + 0, 0, 0, 0, /* status bar does these */ + NULL, NULL, inst, NULL); + } else + fe->statusbar = NULL; + + get_max_puzzle_size(fe, &x, &y); midend_size(fe->me, &x, &y, FALSE); r.left = r.top = 0; r.right = x; r.bottom = y; - AdjustWindowRectEx(&r, WS_OVERLAPPEDWINDOW &~ - (WS_THICKFRAME | WS_MAXIMIZEBOX | WS_OVERLAPPED), - TRUE, 0); + AdjustWindowRectEx(&r, WINFLAGS, TRUE, 0); fe->hwnd = CreateWindowEx(0, thegame.name, thegame.name, WS_OVERLAPPEDWINDOW &~ @@ -1136,6 +1300,7 @@ static frontend *new_window(HINSTANCE inst, char *game_id, char **error) if (midend_wants_statusbar(fe->me)) { RECT sr; + DestroyWindow(fe->statusbar); fe->statusbar = CreateWindowEx(0, STATUSCLASSNAME, "ooh", WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, /* status bar does these */ @@ -1212,10 +1377,10 @@ static frontend *new_window(HINSTANCE inst, char *game_id, char **error) 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*/ @@ -1227,12 +1392,10 @@ static frontend *new_window(HINSTANCE inst, char *game_id, char **error) SetMenu(fe->hwnd, bar); } + fe->bitmap = NULL; + new_game_size(fe); /* initialises fe->bitmap */ check_window_size(fe, &x, &y); - hdc = GetDC(fe->hwnd); - fe->bitmap = CreateCompatibleBitmap(hdc, x, y); - ReleaseDC(fe->hwnd, hdc); - SetWindowLong(fe->hwnd, GWL_USERDATA, (LONG)fe); ShowWindow(fe->hwnd, SW_NORMAL); @@ -1847,16 +2010,13 @@ static void new_game_size(frontend *fe) HDC hdc; int x, y; - x = y = INT_MAX; + get_max_puzzle_size(fe, &x, &y); midend_size(fe->me, &x, &y, FALSE); r.left = r.top = 0; r.right = x; r.bottom = y; - AdjustWindowRectEx(&r, WS_OVERLAPPEDWINDOW &~ - (WS_THICKFRAME | WS_MAXIMIZEBOX | - WS_OVERLAPPED), - TRUE, 0); + AdjustWindowRectEx(&r, WINFLAGS, TRUE, 0); if (fe->statusbar != NULL) { GetWindowRect(fe->statusbar, &sr); @@ -1874,7 +2034,7 @@ static void new_game_size(frontend *fe) SetWindowPos(fe->statusbar, NULL, 0, y, x, sr.bottom - sr.top, SWP_NOZORDER); - DeleteObject(fe->bitmap); + if (fe->bitmap) DeleteObject(fe->bitmap); hdc = GetDC(fe->hwnd); fe->bitmap = CreateCompatibleBitmap(hdc, x, y); @@ -2073,19 +2233,10 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, 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: { @@ -2100,6 +2251,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, } break; case WM_DESTROY: + stop_help(fe); PostQuitMessage(0); return 0; case WM_PAINT: @@ -2303,7 +2455,9 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = inst; - wndclass.hIcon = LoadIcon(inst, IDI_APPLICATION); + wndclass.hIcon = LoadIcon(inst, MAKEINTRESOURCE(200)); + if (!wndclass.hIcon) /* in case resource file is absent */ + wndclass.hIcon = LoadIcon(inst, IDI_APPLICATION); wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground = NULL; wndclass.lpszMenuName = NULL; @@ -2315,6 +2469,8 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) 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); @@ -2326,5 +2482,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) DispatchMessage(&msg); } + cleanup_help(); + return msg.wParam; }