mirror of
git://git.tartarus.org/simon/puzzles.git
synced 2025-04-20 23:51:29 -07:00
Support user preferences on Windows.
This is done using basically the same methods as on Unix, and just translating the system calls in save_prefs to a different API.
This commit is contained in:
152
windows.c
152
windows.c
@ -7,6 +7,7 @@
|
||||
#ifndef NO_HTMLHELP
|
||||
#include <htmlhelp.h>
|
||||
#endif /* NO_HTMLHELP */
|
||||
#include <io.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
@ -35,6 +36,7 @@
|
||||
#define IDM_LOAD 0x00F0
|
||||
#define IDM_PRINT 0x0100
|
||||
#define IDM_PRESETS 0x0110
|
||||
#define IDM_PREFS 0x0120
|
||||
#define IDM_GAMES 0x0300
|
||||
|
||||
#define IDM_KEYEMUL 0x0400
|
||||
@ -119,6 +121,8 @@ void debug_printf(const char *fmt, ...)
|
||||
(WS_MAXIMIZEBOX | WS_OVERLAPPED))
|
||||
|
||||
static void new_game_size(frontend *fe, float scale);
|
||||
static void load_prefs(midend *me);
|
||||
static char *save_prefs(midend *me);
|
||||
|
||||
struct font {
|
||||
HFONT font;
|
||||
@ -935,6 +939,7 @@ void print(frontend *fe)
|
||||
game_params *params;
|
||||
|
||||
nme = midend_new(NULL, fe->game, NULL, NULL);
|
||||
load_prefs(nme);
|
||||
|
||||
/*
|
||||
* Set the non-interactive mid-end to have the same
|
||||
@ -1442,6 +1447,7 @@ static midend *midend_for_new_game(frontend *fe, const game *cgame,
|
||||
if (!arg) {
|
||||
if (me) midend_free(me);
|
||||
me = midend_new(fe, cgame, &win_drawing, fe);
|
||||
load_prefs(me);
|
||||
midend_new_game(me);
|
||||
} else {
|
||||
FILE *fp;
|
||||
@ -1482,6 +1488,7 @@ static midend *midend_for_new_game(frontend *fe, const game *cgame,
|
||||
if (!err_load) {
|
||||
if (me) midend_free(me);
|
||||
me = midend_new(fe, loadgame, &win_drawing, fe);
|
||||
load_prefs(me);
|
||||
err_load = midend_deserialise(me, savefile_read, fp);
|
||||
}
|
||||
} else {
|
||||
@ -1494,6 +1501,7 @@ static midend *midend_for_new_game(frontend *fe, const game *cgame,
|
||||
*/
|
||||
if (me) midend_free(me);
|
||||
me = midend_new(fe, cgame, &win_drawing, fe);
|
||||
load_prefs(me);
|
||||
err_param = midend_game_id(me, arg);
|
||||
if (!err_param) {
|
||||
midend_new_game(me);
|
||||
@ -1719,6 +1727,8 @@ static int fe_set_midend(frontend *fe, midend *me)
|
||||
AppendMenu(menu, MF_ENABLED, IDM_SOLVE, TEXT("Sol&ve"));
|
||||
}
|
||||
AppendMenu(menu, MF_SEPARATOR, 0, 0);
|
||||
AppendMenu(menu, MF_ENABLED, IDM_PREFS, TEXT("Pre&ferences"));
|
||||
AppendMenu(menu, MF_SEPARATOR, 0, 0);
|
||||
AppendMenu(menu, MF_ENABLED, IDM_QUIT, TEXT("E&xit"));
|
||||
menu = CreateMenu();
|
||||
AppendMenu(bar, MF_ENABLED|MF_POPUP, (UINT_PTR)menu, TEXT("&Help"));
|
||||
@ -2488,6 +2498,138 @@ static void update_type_menu_tick(frontend *fe)
|
||||
DrawMenuBar(fe->hwnd);
|
||||
}
|
||||
|
||||
static char *prefs_dir(void)
|
||||
{
|
||||
const char *var;
|
||||
if ((var = getenv("APPDATA")) != NULL) {
|
||||
size_t size = strlen(var) + 80;
|
||||
char *dir = snewn(size, char);
|
||||
sprintf(dir, "%s\\Simon Tatham's Portable Puzzle Collection", var);
|
||||
return dir;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char *prefs_path_general(const game *game, const char *suffix)
|
||||
{
|
||||
char *dir, *path;
|
||||
|
||||
dir = prefs_dir();
|
||||
if (!dir)
|
||||
return NULL;
|
||||
|
||||
path = make_prefs_path(dir, "\\", game, suffix);
|
||||
|
||||
sfree(dir);
|
||||
return path;
|
||||
}
|
||||
|
||||
static char *prefs_path(const game *game)
|
||||
{
|
||||
return prefs_path_general(game, ".conf");
|
||||
}
|
||||
|
||||
static char *prefs_tmp_path(const game *game)
|
||||
{
|
||||
return prefs_path_general(game, ".tmp");
|
||||
}
|
||||
|
||||
static void load_prefs(midend *me)
|
||||
{
|
||||
const game *game = midend_which_game(me);
|
||||
char *path = prefs_path(game);
|
||||
if (!path)
|
||||
return;
|
||||
FILE *fp = fopen(path, "r");
|
||||
if (!fp)
|
||||
return;
|
||||
const char *err = midend_load_prefs(me, savefile_read, fp);
|
||||
fclose(fp);
|
||||
if (err)
|
||||
fprintf(stderr, "Unable to load preferences file %s:\n%s\n",
|
||||
path, err);
|
||||
sfree(path);
|
||||
}
|
||||
|
||||
static char *save_prefs(midend *me)
|
||||
{
|
||||
const game *game = midend_which_game(me);
|
||||
char *dir_path = prefs_dir();
|
||||
char *file_path = prefs_path(game);
|
||||
char *tmp_path = prefs_tmp_path(game);
|
||||
HANDLE fh;
|
||||
FILE *fp;
|
||||
bool cleanup_dir = false, cleanup_tmpfile = false;
|
||||
char *err = NULL;
|
||||
|
||||
if (!dir_path || !file_path || !tmp_path) {
|
||||
sprintf(err = snewn(256, char),
|
||||
"Unable to save preferences:\n"
|
||||
"Could not determine pathname for configuration files");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!CreateDirectory(dir_path, NULL)) {
|
||||
/* Ignore errors while trying to make the directory. It may
|
||||
* well already exist, and even if we got some error code
|
||||
* other than EEXIST, it's still worth at least _trying_ to
|
||||
* make the file inside it, and see if that goes wrong. */
|
||||
} else {
|
||||
cleanup_dir = true;
|
||||
}
|
||||
|
||||
fh = CreateFile(tmp_path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (fh == INVALID_HANDLE_VALUE) {
|
||||
char *os_err = geterrstr();
|
||||
sprintf(err = snewn(256 + strlen(tmp_path) + strlen(os_err), char),
|
||||
"Unable to save preferences:\n"
|
||||
"Unable to create file '%s':\n%s", tmp_path, os_err);
|
||||
sfree(os_err);
|
||||
goto out;
|
||||
} else {
|
||||
cleanup_tmpfile = true;
|
||||
}
|
||||
|
||||
fp = _fdopen(_open_osfhandle((intptr_t)fh, 0), "w");
|
||||
SetLastError(0);
|
||||
midend_save_prefs(me, savefile_write, fp);
|
||||
fclose(fp);
|
||||
if (GetLastError()) {
|
||||
char *os_err = geterrstr();
|
||||
sprintf(err = snewn(80 + strlen(tmp_path) + strlen(os_err), char),
|
||||
"Unable to write file '%s':\n%s", tmp_path, os_err);
|
||||
sfree(os_err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (MoveFileEx(tmp_path, file_path, MOVEFILE_REPLACE_EXISTING) < 0) {
|
||||
char *os_err = geterrstr();
|
||||
sprintf(err = snewn(256 + strlen(tmp_path) + strlen(file_path) +
|
||||
strlen(os_err), char),
|
||||
"Unable to save preferences:\n"
|
||||
"Unable to rename '%s' to '%s':\n%s", tmp_path, file_path,
|
||||
os_err);
|
||||
sfree(os_err);
|
||||
goto out;
|
||||
} else {
|
||||
cleanup_dir = false;
|
||||
cleanup_tmpfile = false;
|
||||
}
|
||||
|
||||
out:
|
||||
if (cleanup_tmpfile) {
|
||||
if (!DeleteFile(tmp_path)) { /* can't do anything about this */ }
|
||||
}
|
||||
if (cleanup_dir) {
|
||||
if (!RemoveDirectory(dir_path)) { /* can't do anything about this */ }
|
||||
}
|
||||
sfree(dir_path);
|
||||
sfree(file_path);
|
||||
sfree(tmp_path);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void update_copy_menu_greying(frontend *fe)
|
||||
{
|
||||
UINT enable = (midend_can_format_as_text_now(fe->me) ?
|
||||
@ -2582,6 +2724,16 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
|
||||
if (get_config(fe, CFG_PRINT))
|
||||
print(fe);
|
||||
break;
|
||||
case IDM_PREFS:
|
||||
if (get_config(fe, CFG_PREFS)) {
|
||||
char *prefs_err = save_prefs(fe->me);
|
||||
if (prefs_err) {
|
||||
MessageBox(fe->hwnd, prefs_err, "Error saving preferences",
|
||||
MB_ICONERROR | MB_OK);
|
||||
sfree(prefs_err);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case IDM_ABOUT:
|
||||
about(fe);
|
||||
break;
|
||||
|
Reference in New Issue
Block a user