Refactor Cnf* functions.

On Windows, freeze.{cpp,h} was factored into w32main.cpp.
The old implementation was too redundant and leaked registry
key handles.

On all platforms, Cnf* functions now use std::string.
This simplifies code everywhere, but will be particularly useful
when the Windows port switches to the *W WinAPI functions.
pull/4/head
whitequark 2015-12-26 23:54:26 +08:00
parent c84a3b6de3
commit 3ffbac38c6
10 changed files with 217 additions and 405 deletions

View File

@ -116,11 +116,7 @@ set(generated_SOURCES
# platform dependencies # platform dependencies
if(WIN32) if(WIN32)
set(platform_HEADERS
win32/freeze.h)
set(platform_SOURCES set(platform_SOURCES
win32/freeze.cpp
win32/w32main.cpp win32/w32main.cpp
win32/resource.rc) win32/resource.rc)
@ -300,7 +296,6 @@ add_executable(solvespace WIN32 MACOSX_BUNDLE
${libslvs_HEADERS} ${libslvs_HEADERS}
${libslvs_SOURCES} ${libslvs_SOURCES}
${util_SOURCES} ${util_SOURCES}
${platform_HEADERS}
${platform_SOURCES} ${platform_SOURCES}
${platform_BUNDLED_RESOURCES} ${platform_BUNDLED_RESOURCES}
${generated_SOURCES} ${generated_SOURCES}

View File

@ -30,42 +30,43 @@ char SolveSpace::RecentFile[MAX_RECENT][MAX_PATH];
/* Settings */ /* Settings */
namespace SolveSpace { namespace SolveSpace {
void CnfFreezeInt(uint32_t val, const char *key) { void CnfFreezeInt(uint32_t val, const std::string &key) {
[[NSUserDefaults standardUserDefaults] [[NSUserDefaults standardUserDefaults]
setInteger:val forKey:[NSString stringWithUTF8String:key]]; setInteger:val forKey:[NSString stringWithUTF8String:key.c_str()]];
} }
uint32_t CnfThawInt(uint32_t val, const char *key) { uint32_t CnfThawInt(uint32_t val, const std::string &key) {
NSString *nsKey = [NSString stringWithUTF8String:key]; NSString *nsKey = [NSString stringWithUTF8String:key.c_str()];
if([[NSUserDefaults standardUserDefaults] objectForKey:nsKey]) if([[NSUserDefaults standardUserDefaults] objectForKey:nsKey])
return [[NSUserDefaults standardUserDefaults] integerForKey:nsKey]; return [[NSUserDefaults standardUserDefaults] integerForKey:nsKey];
return val; return val;
} }
void CnfFreezeFloat(float val, const char *key) { void CnfFreezeFloat(float val, const std::string &key) {
[[NSUserDefaults standardUserDefaults] [[NSUserDefaults standardUserDefaults]
setFloat:val forKey:[NSString stringWithUTF8String:key]]; setFloat:val forKey:[NSString stringWithUTF8String:key.c_str()]];
} }
float CnfThawFloat(float val, const char *key) { float CnfThawFloat(float val, const std::string &key) {
NSString *nsKey = [NSString stringWithUTF8String:key]; NSString *nsKey = [NSString stringWithUTF8String:key.c_str()];
if([[NSUserDefaults standardUserDefaults] objectForKey:nsKey]) if([[NSUserDefaults standardUserDefaults] objectForKey:nsKey])
return [[NSUserDefaults standardUserDefaults] floatForKey:nsKey]; return [[NSUserDefaults standardUserDefaults] floatForKey:nsKey];
return val; return val;
} }
void CnfFreezeString(const char *val, const char *key) { void CnfFreezeString(const std::string &val, const std::string &key) {
[[NSUserDefaults standardUserDefaults] [[NSUserDefaults standardUserDefaults]
setObject:[NSString stringWithUTF8String:val] setObject:[NSString stringWithUTF8String:val.c_str()]
forKey:[NSString stringWithUTF8String:key]]; forKey:[NSString stringWithUTF8String:key.c_str()]];
} }
void CnfThawString(char *val, int valsz, const char *key) { std::string CnfThawString(const std::string &val, const std::string &key) {
NSString *nsKey = [NSString stringWithUTF8String:key]; NSString *nsKey = [NSString stringWithUTF8String:key.c_str()];
if([[NSUserDefaults standardUserDefaults] objectForKey:nsKey]) { if([[NSUserDefaults standardUserDefaults] objectForKey:nsKey]) {
NSString *nsVal = [[NSUserDefaults standardUserDefaults] stringForKey:nsKey]; NSString *nsNewVal = [[NSUserDefaults standardUserDefaults] stringForKey:nsKey];
snprintf(val, valsz, "%s", [nsVal UTF8String]); return [nsNewVal UTF8String];
} }
return val;
} }
}; };

View File

@ -79,59 +79,47 @@ char RecentFile[MAX_RECENT][MAX_PATH];
a schema globally. */ a schema globally. */
static json_object *settings = NULL; static json_object *settings = NULL;
static int CnfPrepare(char *path, int pathsz) { static std::string CnfPrepare() {
// Refer to http://standards.freedesktop.org/basedir-spec/latest/ // Refer to http://standards.freedesktop.org/basedir-spec/latest/
const char *xdg_home, *home; std::string dir;
xdg_home = getenv("XDG_CONFIG_HOME"); if(getenv("XDG_CONFIG_HOME")) {
home = getenv("HOME"); dir = std::string(getenv("XDG_CONFIG_HOME")) + "/solvespace";
} else if(getenv("HOME")) {
char dir[MAX_PATH]; dir = std::string(getenv("HOME")) + "/.config/solvespace";
int dirlen; } else {
if(xdg_home) dbp("neither XDG_CONFIG_HOME nor HOME are set");
dirlen = snprintf(dir, sizeof(dir), "%s/solvespace", xdg_home); return "";
else if(home)
dirlen = snprintf(dir, sizeof(dir), "%s/.config/solvespace", home);
else {
dbp("neither XDG_CONFIG_HOME nor HOME is set");
return 1;
} }
if(dirlen >= sizeof(dir))
oops();
struct stat st; struct stat st;
if(stat(dir, &st)) { if(stat(dir.c_str(), &st)) {
if(errno == ENOENT) { if(errno == ENOENT) {
if(mkdir(dir, 0777)) { if(mkdir(dir.c_str(), 0777)) {
dbp("cannot mkdir %s: %s", dir, strerror(errno)); dbp("cannot mkdir %s: %s", dir.c_str(), strerror(errno));
return 1; return "";
} }
} else { } else {
dbp("cannot stat %s: %s", dir, strerror(errno)); dbp("cannot stat %s: %s", dir.c_str(), strerror(errno));
return 1; return "";
} }
} else if(!S_ISDIR(st.st_mode)) { } else if(!S_ISDIR(st.st_mode)) {
dbp("%s is not a directory", dir); dbp("%s is not a directory", dir.c_str());
return 1; return "";
} }
int pathlen = snprintf(path, pathsz, "%s/settings.json", dir); return dir + "/settings.json";
if(pathlen >= pathsz)
oops();
return 0;
} }
static void CnfLoad() { static void CnfLoad() {
char path[MAX_PATH]; std::string path = CnfPrepare();
if(CnfPrepare(path, sizeof(path))) if(path.empty())
return; return;
if(settings) if(settings)
json_object_put(settings); // deallocate json_object_put(settings); // deallocate
settings = json_object_from_file(path); settings = json_object_from_file(path.c_str());
if(!settings) { if(!settings) {
if(errno != ENOENT) if(errno != ENOENT)
dbp("cannot load settings: %s", strerror(errno)); dbp("cannot load settings: %s", strerror(errno));
@ -141,84 +129,74 @@ static void CnfLoad() {
} }
static void CnfSave() { static void CnfSave() {
char path[MAX_PATH]; std::string path = CnfPrepare();
if(CnfPrepare(path, sizeof(path))) if(path.empty())
return; return;
if(json_object_to_file_ext(path, settings, JSON_C_TO_STRING_PRETTY)) /* json-c <0.12 has the first argument non-const here */
if(json_object_to_file_ext((char*) path.c_str(), settings, JSON_C_TO_STRING_PRETTY))
dbp("cannot save settings: %s", strerror(errno)); dbp("cannot save settings: %s", strerror(errno));
} }
void CnfFreezeInt(uint32_t val, const char *key) { void CnfFreezeInt(uint32_t val, const std::string &key) {
struct json_object *jval = json_object_new_int(val); struct json_object *jval = json_object_new_int(val);
json_object_object_add(settings, key, jval); json_object_object_add(settings, key.c_str(), jval);
CnfSave(); CnfSave();
} }
uint32_t CnfThawInt(uint32_t val, const char *key) { uint32_t CnfThawInt(uint32_t val, const std::string &key) {
struct json_object *jval; struct json_object *jval;
if(json_object_object_get_ex(settings, key, &jval)) if(json_object_object_get_ex(settings, key.c_str(), &jval))
return json_object_get_int(jval); return json_object_get_int(jval);
else return val; else return val;
} }
void CnfFreezeFloat(float val, const char *key) { void CnfFreezeFloat(float val, const std::string &key) {
struct json_object *jval = json_object_new_double(val); struct json_object *jval = json_object_new_double(val);
json_object_object_add(settings, key, jval); json_object_object_add(settings, key.c_str(), jval);
CnfSave(); CnfSave();
} }
float CnfThawFloat(float val, const char *key) { float CnfThawFloat(float val, const std::string &key) {
struct json_object *jval; struct json_object *jval;
if(json_object_object_get_ex(settings, key, &jval)) if(json_object_object_get_ex(settings, key.c_str(), &jval))
return json_object_get_double(jval); return json_object_get_double(jval);
else return val; else return val;
} }
void CnfFreezeString(const char *val, const char *key) { void CnfFreezeString(const std::string &val, const std::string &key) {
struct json_object *jval = json_object_new_string(val); struct json_object *jval = json_object_new_string(val.c_str());
json_object_object_add(settings, key, jval); json_object_object_add(settings, key.c_str(), jval);
CnfSave(); CnfSave();
} }
void CnfThawString(char *val, int valsz, const char *key) { std::string CnfThawString(const std::string &val, const std::string &key) {
struct json_object *jval; struct json_object *jval;
if(json_object_object_get_ex(settings, key, &jval)) if(json_object_object_get_ex(settings, key.c_str(), &jval))
snprintf(val, valsz, "%s", json_object_get_string(jval)); return json_object_get_string(jval);
return val;
} }
static void CnfFreezeWindowPos(Gtk::Window *win, const char *key) { static void CnfFreezeWindowPos(Gtk::Window *win, const std::string &key) {
int x, y, w, h; int x, y, w, h;
win->get_position(x, y); win->get_position(x, y);
win->get_size(w, h); win->get_size(w, h);
char buf[100]; CnfFreezeInt(x, key + "_left");
snprintf(buf, sizeof(buf), "%s_left", key); CnfFreezeInt(y, key + "_top");
CnfFreezeInt(x, buf); CnfFreezeInt(w, key + "_width");
snprintf(buf, sizeof(buf), "%s_top", key); CnfFreezeInt(h, key + "_height");
CnfFreezeInt(y, buf);
snprintf(buf, sizeof(buf), "%s_width", key);
CnfFreezeInt(w, buf);
snprintf(buf, sizeof(buf), "%s_height", key);
CnfFreezeInt(h, buf);
CnfSave();
} }
static void CnfThawWindowPos(Gtk::Window *win, const char *key) { static void CnfThawWindowPos(Gtk::Window *win, const std::string &key) {
int x, y, w, h; int x, y, w, h;
win->get_position(x, y); win->get_position(x, y);
win->get_size(w, h); win->get_size(w, h);
char buf[100]; x = CnfThawInt(x, key + "_left");
snprintf(buf, sizeof(buf), "%s_left", key); y = CnfThawInt(y, key + "_top");
x = CnfThawInt(x, buf); w = CnfThawInt(w, key + "_width");
snprintf(buf, sizeof(buf), "%s_top", key); h = CnfThawInt(h, key + "_height");
y = CnfThawInt(y, buf);
snprintf(buf, sizeof(buf), "%s_width", key);
w = CnfThawInt(w, buf);
snprintf(buf, sizeof(buf), "%s_height", key);
h = CnfThawInt(h, buf);
win->move(x, y); win->move(x, y);
win->resize(w, h); win->resize(w, h);
@ -1105,10 +1083,7 @@ bool GetOpenFile(char *file, const char *active, const char *patterns) {
chooser.set_filename(file); chooser.set_filename(file);
chooser.add_button("_Cancel", Gtk::RESPONSE_CANCEL); chooser.add_button("_Cancel", Gtk::RESPONSE_CANCEL);
chooser.add_button("_Open", Gtk::RESPONSE_OK); chooser.add_button("_Open", Gtk::RESPONSE_OK);
chooser.set_current_folder(CnfThawString("", "FileChooserPath"));
char current_folder[MAX_PATH];
CnfThawString(current_folder, sizeof(current_folder), "FileChooserPath");
chooser.set_current_folder(current_folder);
FiltersFromPattern(active, patterns, chooser); FiltersFromPattern(active, patterns, chooser);
@ -1168,9 +1143,7 @@ bool GetSaveFile(char *file, const char *active, const char *patterns) {
FiltersFromPattern(active, patterns, chooser); FiltersFromPattern(active, patterns, chooser);
char current_folder[MAX_PATH]; chooser.set_current_folder(CnfThawString("", "FileChooserPath"));
CnfThawString(current_folder, sizeof(current_folder), "FileChooserPath");
chooser.set_current_folder(current_folder);
chooser.set_current_name(std::string("untitled.") + active); chooser.set_current_name(std::string("untitled.") + active);
/* Gtk's dialog doesn't change the extension when you change the filter, /* Gtk's dialog doesn't change the extension when you change the filter,
@ -1179,7 +1152,7 @@ bool GetSaveFile(char *file, const char *active, const char *patterns) {
connect(sigc::bind(sigc::ptr_fun(&ChooserFilterChanged), &chooser)); connect(sigc::bind(sigc::ptr_fun(&ChooserFilterChanged), &chooser));
if(chooser.run() == Gtk::RESPONSE_OK) { if(chooser.run() == Gtk::RESPONSE_OK) {
CnfFreezeString(chooser.get_current_folder().c_str(), "FileChooserPath"); CnfFreezeString(chooser.get_current_folder(), "FileChooserPath");
strcpy(file, chooser.get_filename().c_str()); strcpy(file, chooser.get_filename().c_str());
return true; return true;
} else { } else {

View File

@ -17,12 +17,12 @@ void Group::GenerateEquations(IdList<Equation,hEquation> *l) {
// Nothing to do for now. // Nothing to do for now.
} }
void SolveSpace::CnfFreezeInt(uint32_t v, const char *name) void SolveSpace::CnfFreezeInt(uint32_t v, const std::string &name)
{ {
abort(); abort();
} }
uint32_t SolveSpace::CnfThawInt(uint32_t v, const char *name) uint32_t SolveSpace::CnfThawInt(uint32_t v, const std::string &name)
{ {
abort(); abort();
return 0; return 0;

View File

@ -5,7 +5,6 @@
// Copyright 2008-2013 Jonathan Westhues. // Copyright 2008-2013 Jonathan Westhues.
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#include "solvespace.h" #include "solvespace.h"
#include <string>
SolveSpaceUI SolveSpace::SS = {}; SolveSpaceUI SolveSpace::SS = {};
Sketch SolveSpace::SK = {}; Sketch SolveSpace::SK = {};
@ -87,8 +86,8 @@ void SolveSpaceUI::Init() {
for(i = 0; i < MAX_RECENT; i++) { for(i = 0; i < MAX_RECENT; i++) {
char name[100]; char name[100];
sprintf(name, "RecentFile_%d", i); sprintf(name, "RecentFile_%d", i);
strcpy(RecentFile[i], ""); strncpy(RecentFile[i], CnfThawString("", name).c_str(), MAX_PATH);
CnfThawString(RecentFile[i], MAX_PATH, name);
} }
RefreshRecentMenus(); RefreshRecentMenus();
// Autosave timer // Autosave timer
@ -486,9 +485,9 @@ void SolveSpaceUI::MenuFile(int id) {
case GraphicsWindow::MNU_EXPORT_VIEW: { case GraphicsWindow::MNU_EXPORT_VIEW: {
char exportFile[MAX_PATH] = "", exportExt[10] = VEC_EXT; char exportFile[MAX_PATH] = "", exportExt[10] = VEC_EXT;
CnfThawString(exportExt, sizeof(exportExt), "2DExportFormat"); strncpy(exportFile, CnfThawString("", "2DExportFormat").c_str(), MAX_PATH);
if(!GetSaveFile(exportFile, exportExt, VEC_PATTERN)) break; if(!GetSaveFile(exportFile, exportExt, VEC_PATTERN)) break;
CnfFreezeString(Extname(exportFile).c_str(), "2DExportFormat"); CnfFreezeString(Extname(exportFile), "2DExportFormat");
// If the user is exporting something where it would be // If the user is exporting something where it would be
// inappropriate to include the constraints, then warn. // inappropriate to include the constraints, then warn.

View File

@ -17,6 +17,7 @@
#include <math.h> #include <math.h>
#include <limits.h> #include <limits.h>
#include <algorithm> #include <algorithm>
#include <string>
#ifdef HAVE_STDINT_H #ifdef HAVE_STDINT_H
# include <stdint.h> # include <stdint.h>
#endif #endif
@ -246,12 +247,12 @@ void SetAutosaveTimerFor(int minutes);
void ScheduleLater(); void ScheduleLater();
void ExitNow(void); void ExitNow(void);
void CnfFreezeString(const char *str, const char *name); void CnfFreezeInt(uint32_t val, const std::string &name);
void CnfFreezeInt(uint32_t v, const char *name); void CnfFreezeFloat(float val, const std::string &name);
void CnfFreezeFloat(float v, const char *name); void CnfFreezeString(const std::string &val, const std::string &name);
void CnfThawString(char *str, int maxLen, const char *name); std::string CnfThawString(const std::string &val, const std::string &name);
uint32_t CnfThawInt(uint32_t v, const char *name); uint32_t CnfThawInt(uint32_t val, const std::string &name);
float CnfThawFloat(float v, const char *name); float CnfThawFloat(float val, const std::string &name);
void *AllocTemporary(size_t n); void *AllocTemporary(size_t n);
void FreeTemporary(void *p); void FreeTemporary(void *p);
@ -340,10 +341,10 @@ bool StringAllPrintable(const char *str);
bool StringEndsIn(const char *str, const char *ending); bool StringEndsIn(const char *str, const char *ending);
void Message(const char *str, ...); void Message(const char *str, ...);
void Error(const char *str, ...); void Error(const char *str, ...);
void CnfFreezeBool(bool v, const char *name); void CnfFreezeBool(bool v, const std::string &name);
void CnfFreezeColor(RgbaColor v, const char *name); void CnfFreezeColor(RgbaColor v, const std::string &name);
bool CnfThawBool(bool v, const char *name); bool CnfThawBool(bool v, const std::string &name);
RgbaColor CnfThawColor(RgbaColor v, const char *name); RgbaColor CnfThawColor(RgbaColor v, const std::string &name);
class System { class System {
public: public:

View File

@ -207,16 +207,16 @@ void SolveSpace::Message(const char *str, ...)
va_end(f); va_end(f);
} }
void SolveSpace::CnfFreezeBool(bool v, const char *name) void SolveSpace::CnfFreezeBool(bool v, const std::string &name)
{ CnfFreezeInt(v ? 1 : 0, name); } { CnfFreezeInt(v ? 1 : 0, name); }
void SolveSpace::CnfFreezeColor(RgbaColor v, const char *name) void SolveSpace::CnfFreezeColor(RgbaColor v, const std::string &name)
{ CnfFreezeInt(v.ToPackedInt(), name); } { CnfFreezeInt(v.ToPackedInt(), name); }
bool SolveSpace::CnfThawBool(bool v, const char *name) bool SolveSpace::CnfThawBool(bool v, const std::string &name)
{ return CnfThawInt(v ? 1 : 0, name) != 0; } { return CnfThawInt(v ? 1 : 0, name) != 0; }
RgbaColor SolveSpace::CnfThawColor(RgbaColor v, const char *name) RgbaColor SolveSpace::CnfThawColor(RgbaColor v, const std::string &name)
{ return RgbaColor::FromPackedInt(CnfThawInt(v.ToPackedInt(), name)); } { return RgbaColor::FromPackedInt(CnfThawInt(v.ToPackedInt(), name)); }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------

View File

@ -1,219 +0,0 @@
/*
* A library for storing parameters in the registry.
*
* Jonathan Westhues, 2002
*/
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#define FREEZE_SUBKEY ----
#include "freeze.h"
/*
* store a window's position in the registry, or fail silently if the registry calls don't work
*/
void FreezeWindowPosF(HWND hwnd, const char *subKey, const char *name)
{
RECT r;
GetWindowRect(hwnd, &r);
HKEY software;
if(RegOpenKeyEx(HKEY_CURRENT_USER, "Software", 0, KEY_ALL_ACCESS, &software) != ERROR_SUCCESS)
return;
char *keyName = (char *)malloc(strlen(name) + 30);
if(!keyName)
return;
HKEY sub;
if(RegCreateKeyEx(software, subKey, 0, (LPTSTR)"", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &sub, NULL) != ERROR_SUCCESS)
return;
sprintf(keyName, "%s_left", name);
if(RegSetValueEx(sub, keyName, 0, REG_DWORD, (BYTE *)&(r.left), sizeof(DWORD)) != ERROR_SUCCESS)
return;
sprintf(keyName, "%s_right", name);
if(RegSetValueEx(sub, keyName, 0, REG_DWORD, (BYTE *)&(r.right), sizeof(DWORD)) != ERROR_SUCCESS)
return;
sprintf(keyName, "%s_top", name);
if(RegSetValueEx(sub, keyName, 0, REG_DWORD, (BYTE *)&(r.top), sizeof(DWORD)) != ERROR_SUCCESS)
return;
sprintf(keyName, "%s_bottom", name);
if(RegSetValueEx(sub, keyName, 0, REG_DWORD, (BYTE *)&(r.bottom), sizeof(DWORD)) != ERROR_SUCCESS)
return;
sprintf(keyName, "%s_maximized", name);
DWORD v = IsZoomed(hwnd);
if(RegSetValueEx(sub, keyName, 0, REG_DWORD, (BYTE *)&(v), sizeof(DWORD)) != ERROR_SUCCESS)
return;
free(keyName);
}
static void Clamp(LONG *v, LONG min, LONG max)
{
if(*v < min) *v = min;
if(*v > max) *v = max;
}
/*
* retrieve a window's position from the registry, or do nothing if there is no info saved
*/
void ThawWindowPosF(HWND hwnd, const char *subKey, const char *name)
{
HKEY software;
if(RegOpenKeyEx(HKEY_CURRENT_USER, "Software", 0, KEY_ALL_ACCESS, &software) != ERROR_SUCCESS)
return;
HKEY sub;
if(RegOpenKeyEx(software, subKey, 0, KEY_ALL_ACCESS, &sub) != ERROR_SUCCESS)
return;
char *keyName = (char *)malloc(strlen(name) + 30);
if(!keyName)
return;
DWORD l;
RECT r;
sprintf(keyName, "%s_left", name);
l = sizeof(DWORD);
if(RegQueryValueEx(sub, keyName, NULL, NULL, (BYTE *)&(r.left), &l) != ERROR_SUCCESS)
return;
sprintf(keyName, "%s_right", name);
l = sizeof(DWORD);
if(RegQueryValueEx(sub, keyName, NULL, NULL, (BYTE *)&(r.right), &l) != ERROR_SUCCESS)
return;
sprintf(keyName, "%s_top", name);
l = sizeof(DWORD);
if(RegQueryValueEx(sub, keyName, NULL, NULL, (BYTE *)&(r.top), &l) != ERROR_SUCCESS)
return;
sprintf(keyName, "%s_bottom", name);
l = sizeof(DWORD);
if(RegQueryValueEx(sub, keyName, NULL, NULL, (BYTE *)&(r.bottom), &l) != ERROR_SUCCESS)
return;
sprintf(keyName, "%s_maximized", name);
DWORD v;
l = sizeof(DWORD);
if(RegQueryValueEx(sub, keyName, NULL, NULL, (BYTE *)&v, &l) != ERROR_SUCCESS)
return;
if(v)
ShowWindow(hwnd, SW_MAXIMIZE);
HMONITOR hMonitor;
MONITORINFO mi;
RECT dr;
hMonitor = MonitorFromRect(&r, MONITOR_DEFAULTTONEAREST);
mi.cbSize = sizeof(mi);
GetMonitorInfo(hMonitor, &mi);
dr = mi.rcMonitor;
// If it somehow ended up off-screen, then put it back.
Clamp(&(r.left), dr.left, dr.right);
Clamp(&(r.right), dr.left, dr.right);
Clamp(&(r.top), dr.top, dr.bottom);
Clamp(&(r.bottom), dr.top, dr.bottom);
if(r.right - r.left < 100) {
r.left -= 300; r.right += 300;
}
if(r.bottom - r.top < 100) {
r.top -= 300; r.bottom += 300;
}
Clamp(&(r.left), dr.left, dr.right);
Clamp(&(r.right), dr.left, dr.right);
Clamp(&(r.top), dr.top, dr.bottom);
Clamp(&(r.bottom), dr.top, dr.bottom);
MoveWindow(hwnd, r.left, r.top, r.right - r.left, r.bottom - r.top, TRUE);
free(keyName);
}
/*
* store a DWORD setting in the registry
*/
void FreezeDWORDF(DWORD val, const char *subKey, const char *name)
{
HKEY software;
if(RegOpenKeyEx(HKEY_CURRENT_USER, "Software", 0, KEY_ALL_ACCESS, &software) != ERROR_SUCCESS)
return;
HKEY sub;
if(RegCreateKeyEx(software, subKey, 0, (LPTSTR)"", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &sub, NULL) != ERROR_SUCCESS)
return;
if(RegSetValueEx(sub, name, 0, REG_DWORD, (BYTE *)&val, sizeof(DWORD)) != ERROR_SUCCESS)
return;
}
/*
* retrieve a DWORD setting, or return the default if that setting is unavailable
*/
DWORD ThawDWORDF(DWORD val, const char *subKey, const char *name)
{
HKEY software;
if(RegOpenKeyEx(HKEY_CURRENT_USER, "Software", 0, KEY_ALL_ACCESS, &software) != ERROR_SUCCESS)
return val;
HKEY sub;
if(RegOpenKeyEx(software, subKey, 0, KEY_ALL_ACCESS, &sub) != ERROR_SUCCESS)
return val;
DWORD l = sizeof(DWORD);
DWORD v;
if(RegQueryValueEx(sub, name, NULL, NULL, (BYTE *)&v, &l) != ERROR_SUCCESS)
return val;
return v;
}
/*
* store a string setting in the registry
*/
void FreezeStringF(const char *val, const char *subKey, const char *name)
{
HKEY software;
if(RegOpenKeyEx(HKEY_CURRENT_USER, "Software", 0, KEY_ALL_ACCESS, &software) != ERROR_SUCCESS)
return;
HKEY sub;
if(RegCreateKeyEx(software, subKey, 0, (LPTSTR)"", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &sub, NULL) != ERROR_SUCCESS)
return;
if(RegSetValueEx(sub, name, 0, REG_SZ, (const BYTE *)val, (DWORD)strlen(val)+1) != ERROR_SUCCESS)
return;
}
/*
* retrieve a string setting, or return the default if that setting is unavailable
*/
void ThawStringF(char *val, int max, const char *subKey, const char *name)
{
HKEY software;
if(RegOpenKeyEx(HKEY_CURRENT_USER, "Software", 0, KEY_ALL_ACCESS, &software) != ERROR_SUCCESS)
return;
HKEY sub;
if(RegOpenKeyEx(software, subKey, 0, KEY_ALL_ACCESS, &sub) != ERROR_SUCCESS)
return;
DWORD l = max;
if(RegQueryValueEx(sub, name, NULL, NULL, (BYTE *)val, &l) != ERROR_SUCCESS)
return;
if(l >= (DWORD)max) return;
val[l] = '\0';
return;
}

View File

@ -1,33 +0,0 @@
/*
* A library for storing parameters in the registry.
*
* Jonathan Westhues, 2002
*/
#ifndef __FREEZE_H
#define __FREEZE_H
#ifndef FREEZE_SUBKEY
#error must define FREEZE_SUBKEY to a string uniquely identifying the app
#endif
#define FreezeWindowPos(hwnd) FreezeWindowPosF(hwnd, FREEZE_SUBKEY, #hwnd)
void FreezeWindowPosF(HWND hWnd, const char *subKey, const char *name);
#define ThawWindowPos(hwnd) ThawWindowPosF(hwnd, FREEZE_SUBKEY, #hwnd)
void ThawWindowPosF(HWND hWnd, const char *subKey, const char *name);
#define FreezeDWORD(val) FreezeDWORDF(val, FREEZE_SUBKEY, #val)
void FreezeDWORDF(DWORD val, const char *subKey, const char *name);
#define ThawDWORD(val) val = ThawDWORDF(val, FREEZE_SUBKEY, #val)
DWORD ThawDWORDF(DWORD val, const char *subKey, const char *name);
#define FreezeString(val) FreezeStringF(val, FREEZE_SUBKEY, #val)
void FreezeStringF(const char *val, const char *subKey, const char *name);
#define ThawString(val, max) ThawStringF(val, max, FREEZE_SUBKEY, #val)
void ThawStringF(char *val, int max, const char *subKey, const char *name);
#endif

View File

@ -21,9 +21,6 @@
# undef uint32_t // thanks but no thanks # undef uint32_t // thanks but no thanks
#endif #endif
#define FREEZE_SUBKEY "SolveSpace"
#include "freeze.h"
// For the edit controls // For the edit controls
#define EDIT_WIDTH 220 #define EDIT_WIDTH 220
#define EDIT_HEIGHT 21 #define EDIT_HEIGHT 21
@ -286,35 +283,133 @@ void SolveSpace::ExitNow(void) {
// Helpers so that we can read/write registry keys from the platform- // Helpers so that we can read/write registry keys from the platform-
// independent code. // independent code.
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void SolveSpace::CnfFreezeString(const char *str, const char *name) inline int CLAMP(int v, int a, int b) {
{ FreezeStringF(str, FREEZE_SUBKEY, name); } // Clamp it to the range [a, b]
if(v <= a) return a;
void SolveSpace::CnfFreezeInt(uint32_t v, const char *name) if(v >= b) return b;
{ FreezeDWORDF((DWORD)v, FREEZE_SUBKEY, name); } return v;
union floatDWORD {
float f;
DWORD d;
};
void SolveSpace::CnfFreezeFloat(float v, const char *name) {
if(sizeof(float) != sizeof(DWORD)) oops();
floatDWORD u;
u.f = v;
FreezeDWORDF(u.d, FREEZE_SUBKEY, name);
} }
void SolveSpace::CnfThawString(char *str, int maxLen, const char *name) static HKEY GetRegistryKey()
{ ThawStringF(str, maxLen, FREEZE_SUBKEY, name); } {
HKEY Software;
if(RegOpenKeyEx(HKEY_CURRENT_USER, "Software", 0, KEY_ALL_ACCESS, &Software) != ERROR_SUCCESS)
return NULL;
uint32_t SolveSpace::CnfThawInt(uint32_t v, const char *name) HKEY SolveSpace;
{ return (uint32_t)ThawDWORDF((DWORD)v, FREEZE_SUBKEY, name); } if(RegCreateKeyEx(Software, "SolveSpace", 0, NULL, 0,
KEY_ALL_ACCESS, NULL, &SolveSpace, NULL) != ERROR_SUCCESS)
return NULL;
float SolveSpace::CnfThawFloat(float v, const char *name) { RegCloseKey(Software);
floatDWORD u;
u.f = v; return SolveSpace;
u.d = ThawDWORDF(u.d, FREEZE_SUBKEY, name); }
return u.f;
void SolveSpace::CnfFreezeInt(uint32_t val, const std::string &name)
{
HKEY SolveSpace = GetRegistryKey();
RegSetValueEx(SolveSpace, &name[0], 0,
REG_DWORD, (const BYTE*) &val, sizeof(DWORD));
RegCloseKey(SolveSpace);
}
void SolveSpace::CnfFreezeFloat(float val, const std::string &name)
{
static_assert(sizeof(float) == sizeof(DWORD),
"sizes of float and DWORD must match");
HKEY SolveSpace = GetRegistryKey();
RegSetValueEx(SolveSpace, &name[0], 0,
REG_DWORD, (const BYTE*) &val, sizeof(DWORD));
RegCloseKey(SolveSpace);
}
void SolveSpace::CnfFreezeString(const std::string &str, const std::string &name)
{
HKEY SolveSpace = GetRegistryKey();
RegSetValueEx(SolveSpace, &name[0], 0,
REG_SZ, (const BYTE*) &str[0], str.length() + 1);
RegCloseKey(SolveSpace);
}
static void FreezeWindowPos(HWND hwnd, const std::string &name)
{
RECT r;
GetWindowRect(hwnd, &r);
CnfFreezeInt(r.left, name + "_left");
CnfFreezeInt(r.right, name + "_right");
CnfFreezeInt(r.top, name + "_top");
CnfFreezeInt(r.bottom, name + "_bottom");
CnfFreezeInt(IsZoomed(hwnd), name + "_maximized");
}
uint32_t SolveSpace::CnfThawInt(uint32_t val, const std::string &name)
{
HKEY SolveSpace = GetRegistryKey();
DWORD type, newval, len = sizeof(DWORD);
LONG result = RegQueryValueEx(SolveSpace, &name[0], NULL, &type, (BYTE*) &newval, &len);
RegCloseKey(SolveSpace);
if(result == ERROR_SUCCESS && type == REG_DWORD)
return newval;
else
return val;
}
float SolveSpace::CnfThawFloat(float val, const std::string &name)
{
HKEY SolveSpace = GetRegistryKey();
DWORD type, len = sizeof(DWORD);
float newval;
LONG result = RegQueryValueEx(SolveSpace, &name[0], NULL, &type, (BYTE*) &newval, &len);
RegCloseKey(SolveSpace);
if(result == ERROR_SUCCESS && type == REG_DWORD)
return newval;
else
return val;
}
std::string SolveSpace::CnfThawString(const std::string &val, const std::string &name)
{
HKEY SolveSpace = GetRegistryKey();
DWORD type, len;
if(RegQueryValueEx(SolveSpace, &name[0], NULL,
&type, NULL, &len) != ERROR_SUCCESS || type != REG_SZ) {
RegCloseKey(SolveSpace);
return val;
}
std::string newval(len, '\0');
if(RegQueryValueEx(SolveSpace, &name[0], NULL,
NULL, (BYTE*) &newval[0], &len) != ERROR_SUCCESS) {
RegCloseKey(SolveSpace);
return val;
}
RegCloseKey(SolveSpace);
return newval;
}
static void ThawWindowPos(HWND hwnd, const std::string &name)
{
RECT r;
GetWindowRect(hwnd, &r);
r.left = CnfThawInt(r.left, name + "_left");
r.right = CnfThawInt(r.right, name + "_right");
r.top = CnfThawInt(r.top, name + "_top");
r.bottom = CnfThawInt(r.bottom, name + "_bottom");
HMONITOR hMonitor = MonitorFromRect(&r, MONITOR_DEFAULTTONEAREST);;
MONITORINFO mi;
mi.cbSize = sizeof(mi);
GetMonitorInfo(hMonitor, &mi);
// If it somehow ended up off-screen, then put it back.
RECT dr = mi.rcMonitor;
r.left = CLAMP(r.left, dr.left, dr.right);
r.right = CLAMP(r.right, dr.left, dr.right);
r.top = CLAMP(r.top, dr.top, dr.bottom);
r.bottom = CLAMP(r.bottom, dr.top, dr.bottom);
MoveWindow(hwnd, r.left, r.top, r.right - r.left, r.bottom - r.top, TRUE);
if(CnfThawInt(FALSE, name + "_maximized"))
ShowWindow(hwnd, SW_MAXIMIZE);
} }
void SolveSpace::SetCurrentFilename(const char *filename) { void SolveSpace::SetCurrentFilename(const char *filename) {
@ -1216,8 +1311,8 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
// the graphics // the graphics
CreateMainWindows(); CreateMainWindows();
ThawWindowPos(TextWnd); ThawWindowPos(TextWnd, "TextWnd");
ThawWindowPos(GraphicsWnd); ThawWindowPos(GraphicsWnd, "GraphicsWnd");
ShowWindow(TextWnd, SW_SHOWNOACTIVATE); ShowWindow(TextWnd, SW_SHOWNOACTIVATE);
ShowWindow(GraphicsWnd, SW_SHOW); ShowWindow(GraphicsWnd, SW_SHOW);
@ -1301,8 +1396,8 @@ done:
#endif #endif
// Write everything back to the registry // Write everything back to the registry
FreezeWindowPos(TextWnd); FreezeWindowPos(TextWnd, "TextWnd");
FreezeWindowPos(GraphicsWnd); FreezeWindowPos(GraphicsWnd, "GraphicsWnd");
// Free the memory we've used; anything that remains is a leak. // Free the memory we've used; anything that remains is a leak.
SK.Clear(); SK.Clear();