XDG followup work #94
* Apply save order for save states and batteries. The order for save state/battery: 1. StateDir / BatteryDir; 2. The path of the current loaded game; 3. XDG Base Dir fallback. * Use XDG Base Dir fallback to save screenshots and recordings. * Apply search order for all dirs except recording (not implemented yet) of SDL port. The order for battery/save state/screenshot is: 1. StateDir/BatteryDir/ScreenshotDir; 2. The path of the current loaded game; 3. XDG Base Dir (or equivalent) fallback. * Refactor code. * Fix freeing and setting pointer to NULL of SDL port.
This commit is contained in:
parent
2142a46dd5
commit
a1f0c34ace
180
src/sdl/SDL.cpp
180
src/sdl/SDL.cpp
|
@ -64,14 +64,22 @@
|
||||||
#include "inputSDL.h"
|
#include "inputSDL.h"
|
||||||
#include "text.h"
|
#include "text.h"
|
||||||
|
|
||||||
|
// from: https://stackoverflow.com/questions/7608714/why-is-my-pointer-not-null-after-free
|
||||||
|
#define freeSafe(ptr) free(ptr); ptr = NULL;
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#define GETCWD getcwd
|
#define GETCWD getcwd
|
||||||
#else // _WIN32
|
#else // _WIN32
|
||||||
#include <direct.h>
|
#include <direct.h>
|
||||||
|
#include <io.h>
|
||||||
#define GETCWD _getcwd
|
#define GETCWD _getcwd
|
||||||
#define snprintf sprintf
|
#define snprintf sprintf
|
||||||
#define stat _stat
|
#define stat _stat
|
||||||
|
#define access _access
|
||||||
|
#ifndef W_OK
|
||||||
|
#define W_OK 2
|
||||||
|
#endif
|
||||||
#define mkdir(X,Y) (_mkdir(X))
|
#define mkdir(X,Y) (_mkdir(X))
|
||||||
// from: https://www.linuxquestions.org/questions/programming-9/porting-to-win32-429334/
|
// from: https://www.linuxquestions.org/questions/programming-9/porting-to-win32-429334/
|
||||||
#ifndef S_ISDIR
|
#ifndef S_ISDIR
|
||||||
|
@ -208,7 +216,8 @@ int sdlMirroringEnable = 1;
|
||||||
void systemConsoleMessage(const char*);
|
void systemConsoleMessage(const char*);
|
||||||
|
|
||||||
char* home;
|
char* home;
|
||||||
char homeDataDir[2048];
|
char homeConfigDir[1024];
|
||||||
|
char homeDataDir[1024];
|
||||||
|
|
||||||
char screenMessageBuffer[21];
|
char screenMessageBuffer[21];
|
||||||
uint32_t screenMessageTime = 0;
|
uint32_t screenMessageTime = 0;
|
||||||
|
@ -253,7 +262,7 @@ void StartLirc(void)
|
||||||
fprintf(stdout, "Success\n");
|
fprintf(stdout, "Success\n");
|
||||||
//read the config file
|
//read the config file
|
||||||
char LIRCConfigLoc[2048];
|
char LIRCConfigLoc[2048];
|
||||||
sprintf(LIRCConfigLoc, "%s/%s", homeDataDir, "lircrc");
|
sprintf(LIRCConfigLoc, "%s%c%s", homeConfigDir, FILE_SEP, "lircrc");
|
||||||
fprintf(stdout, "LIRC Config file:");
|
fprintf(stdout, "LIRC Config file:");
|
||||||
if (lirc_readconfig(LIRCConfigLoc, &LIRCConfigInfo, NULL) == 0) {
|
if (lirc_readconfig(LIRCConfigLoc, &LIRCConfigInfo, NULL) == 0) {
|
||||||
//check vbam dir for lircrc
|
//check vbam dir for lircrc
|
||||||
|
@ -291,59 +300,47 @@ void StopLirc(void)
|
||||||
|
|
||||||
bool sdlCheckDirectory(const char* dir)
|
bool sdlCheckDirectory(const char* dir)
|
||||||
{
|
{
|
||||||
bool res = false;
|
|
||||||
|
|
||||||
if (!dir || !dir[0]) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct stat buf;
|
struct stat buf;
|
||||||
|
|
||||||
int len = strlen(dir);
|
if (!dir || !dir[0])
|
||||||
|
return false;
|
||||||
|
|
||||||
char* p = (char*)dir + len - 1;
|
if (stat(dir, &buf) == 0)
|
||||||
|
{
|
||||||
while (p != dir && (*p == '/' || *p == '\\')) {
|
if (!(buf.st_mode & S_IFDIR))
|
||||||
*p = 0;
|
{
|
||||||
p--;
|
fprintf(stderr, "Error: %s is not a directory\n", dir);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
if (stat(dir, &buf) == 0) {
|
{
|
||||||
if (!(buf.st_mode & S_IFDIR)) {
|
fprintf(stderr, "Error: %s does not exist\n", dir);
|
||||||
fprintf(stderr, "Error: %s is not a directory\n", dir);
|
return false;
|
||||||
}
|
|
||||||
res = true;
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "Error: %s does not exist\n", dir);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char* sdlGetFilename(char* name)
|
char* sdlGetFilename(char* name)
|
||||||
{
|
{
|
||||||
static char filebuffer[2048];
|
char path[1024] = ""; // avoid warning about uninitialised value
|
||||||
|
char *filename = strrchr(name, FILE_SEP);
|
||||||
int len = strlen(name);
|
if (filename)
|
||||||
|
strncpy(path, filename + 1, strlen(filename));
|
||||||
char* p = name + len - 1;
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
if (*p == '/' || *p == '\\') {
|
|
||||||
p++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
len--;
|
|
||||||
p--;
|
|
||||||
if (len == 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (len == 0)
|
|
||||||
strcpy(filebuffer, name);
|
|
||||||
else
|
else
|
||||||
strcpy(filebuffer, p);
|
sprintf(path, "%s", name);
|
||||||
return filebuffer;
|
return strdup(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
char* sdlGetFilePath(char* name)
|
||||||
|
{
|
||||||
|
char path[1024] = ""; // avoid warning about uninitialised value
|
||||||
|
char *filename = strrchr(name, FILE_SEP);
|
||||||
|
if (filename)
|
||||||
|
strncpy(path, name, strlen(name) - strlen(filename));
|
||||||
|
else
|
||||||
|
sprintf(path, "%c%c", '.', FILE_SEP);
|
||||||
|
return strdup(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
FILE* sdlFindFile(const char* name)
|
FILE* sdlFindFile(const char* name)
|
||||||
|
@ -661,15 +658,18 @@ static int sdlCalculateShift(uint32_t mask)
|
||||||
static char* sdlStateName(int num)
|
static char* sdlStateName(int num)
|
||||||
{
|
{
|
||||||
static char stateName[2048];
|
static char stateName[2048];
|
||||||
|
char *gameDir = sdlGetFilePath(filename);
|
||||||
|
char *gameFile = sdlGetFilename(filename);
|
||||||
|
|
||||||
if (saveDir)
|
if (saveDir)
|
||||||
sprintf(stateName, "%s/%s%d.sgm", saveDir, sdlGetFilename(filename),
|
sprintf(stateName, "%s%c%s%d.sgm", saveDir, FILE_SEP, gameFile, num + 1);
|
||||||
num + 1);
|
else if (access(gameDir, W_OK) == 0)
|
||||||
else if (homeDir)
|
sprintf(stateName, "%s%c%s%d.sgm", gameDir, FILE_SEP, gameFile, num + 1);
|
||||||
sprintf(stateName, "%s/%s%d.sgm", homeDataDir, sdlGetFilename(filename), num + 1);
|
|
||||||
else
|
else
|
||||||
sprintf(stateName, "%s%d.sgm", filename, num + 1);
|
sprintf(stateName, "%s%c%s%d.sgm", homeDataDir, FILE_SEP, gameFile, num + 1);
|
||||||
|
|
||||||
|
freeSafe(gameDir);
|
||||||
|
freeSafe(gameFile);
|
||||||
return stateName;
|
return stateName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -760,37 +760,46 @@ void sdlWriteBackupStateExchange(int from, int to, int backup)
|
||||||
|
|
||||||
void sdlWriteBattery()
|
void sdlWriteBattery()
|
||||||
{
|
{
|
||||||
char buffer[1048];
|
char buffer[2048];
|
||||||
|
char *gameDir = sdlGetFilePath(filename);
|
||||||
|
char *gameFile = sdlGetFilename(filename);
|
||||||
|
|
||||||
if (batteryDir)
|
if (batteryDir)
|
||||||
sprintf(buffer, "%s/%s.sav", batteryDir, sdlGetFilename(filename));
|
sprintf(buffer, "%s%c%s.sav", batteryDir, FILE_SEP, gameFile);
|
||||||
else if (homeDir)
|
else if (access(gameDir, W_OK) == 0)
|
||||||
sprintf(buffer, "%s/%s.sav", homeDataDir, sdlGetFilename(filename));
|
sprintf(buffer, "%s%c%s.sav", gameDir, FILE_SEP, gameFile);
|
||||||
else
|
else
|
||||||
sprintf(buffer, "%s.sav", filename);
|
sprintf(buffer, "%s%c%s.sav", homeDataDir, FILE_SEP, gameFile);
|
||||||
|
|
||||||
emulator.emuWriteBattery(buffer);
|
bool result = emulator.emuWriteBattery(buffer);
|
||||||
|
|
||||||
systemScreenMessage("Wrote battery");
|
if (result)
|
||||||
|
systemMessage(0, "Wrote battery '%s'", buffer);
|
||||||
|
|
||||||
|
freeSafe(gameFile);
|
||||||
|
freeSafe(gameDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sdlReadBattery()
|
void sdlReadBattery()
|
||||||
{
|
{
|
||||||
char buffer[1048];
|
char buffer[2048];
|
||||||
|
char *gameDir = sdlGetFilePath(filename);
|
||||||
|
char *gameFile = sdlGetFilename(filename);
|
||||||
|
|
||||||
if (batteryDir)
|
if (batteryDir)
|
||||||
sprintf(buffer, "%s/%s.sav", batteryDir, sdlGetFilename(filename));
|
sprintf(buffer, "%s%c%s.sav", batteryDir, FILE_SEP, gameFile);
|
||||||
else if (homeDir)
|
else if (access(gameDir, W_OK) == 0)
|
||||||
sprintf(buffer, "%s/%s.sav", homeDataDir, sdlGetFilename(filename));
|
sprintf(buffer, "%s%c%s.sav", gameDir, FILE_SEP, gameFile);
|
||||||
else
|
else
|
||||||
sprintf(buffer, "%s.sav", filename);
|
sprintf(buffer, "%s%c%s.sav", homeDataDir, FILE_SEP, gameFile);
|
||||||
|
|
||||||
bool res = false;
|
bool result = emulator.emuReadBattery(buffer);
|
||||||
|
|
||||||
res = emulator.emuReadBattery(buffer);
|
if (result)
|
||||||
|
systemMessage(0, "Loaded battery '%s'", buffer);
|
||||||
|
|
||||||
if (res)
|
freeSafe(gameFile);
|
||||||
systemScreenMessage("Loaded battery");
|
freeSafe(gameDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sdlReadDesktopVideoMode()
|
void sdlReadDesktopVideoMode()
|
||||||
|
@ -1644,6 +1653,14 @@ void handleRewinds()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetHomeConfigDir()
|
||||||
|
{
|
||||||
|
sprintf(homeConfigDir, "%s%s", get_xdg_user_config_home().c_str(), DOT_DIR);
|
||||||
|
struct stat s;
|
||||||
|
if (stat(homeDataDir, &s) == -1 || !S_ISDIR(s.st_mode))
|
||||||
|
mkdir(homeDataDir, 0755);
|
||||||
|
}
|
||||||
|
|
||||||
void SetHomeDataDir()
|
void SetHomeDataDir()
|
||||||
{
|
{
|
||||||
sprintf(homeDataDir, "%s%s", get_xdg_user_data_home().c_str(), DOT_DIR);
|
sprintf(homeDataDir, "%s%s", get_xdg_user_data_home().c_str(), DOT_DIR);
|
||||||
|
@ -1658,6 +1675,7 @@ int main(int argc, char** argv)
|
||||||
|
|
||||||
home = argv[0];
|
home = argv[0];
|
||||||
SetHome(home);
|
SetHome(home);
|
||||||
|
SetHomeConfigDir();
|
||||||
SetHomeDataDir();
|
SetHomeDataDir();
|
||||||
|
|
||||||
frameSkip = 2;
|
frameSkip = 2;
|
||||||
|
@ -2224,27 +2242,35 @@ void system10Frames(int rate)
|
||||||
void systemScreenCapture(int a)
|
void systemScreenCapture(int a)
|
||||||
{
|
{
|
||||||
char buffer[2048];
|
char buffer[2048];
|
||||||
|
bool result = false;
|
||||||
|
char *gameDir = sdlGetFilePath(filename);
|
||||||
|
char *gameFile = sdlGetFilename(filename);
|
||||||
|
|
||||||
if (captureFormat) {
|
if (captureFormat) {
|
||||||
if (screenShotDir)
|
if (screenShotDir)
|
||||||
sprintf(buffer, "%s/%s%02d.bmp", screenShotDir, sdlGetFilename(filename), a);
|
sprintf(buffer, "%s%c%s%02d.bmp", screenShotDir, FILE_SEP, gameFile, a);
|
||||||
else if (homeDir)
|
else if (access(gameDir, W_OK) == 0)
|
||||||
sprintf(buffer, "%s/%s%02d.bmp", homeDataDir, sdlGetFilename(filename), a);
|
sprintf(buffer, "%s%c%s%02d.bmp", gameDir, FILE_SEP, gameFile, a);
|
||||||
else
|
else
|
||||||
sprintf(buffer, "%s%02d.bmp", filename, a);
|
sprintf(buffer, "%s%c%s%02d.bmp", homeDataDir, FILE_SEP, gameFile, a);
|
||||||
|
|
||||||
emulator.emuWriteBMP(buffer);
|
result = emulator.emuWriteBMP(buffer);
|
||||||
} else {
|
} else {
|
||||||
if (screenShotDir)
|
if (screenShotDir)
|
||||||
sprintf(buffer, "%s/%s%02d.png", screenShotDir, sdlGetFilename(filename), a);
|
sprintf(buffer, "%s%c%s%02d.png", screenShotDir, FILE_SEP, gameFile, a);
|
||||||
else if (homeDir)
|
else if (access(gameDir, W_OK) == 0)
|
||||||
sprintf(buffer, "%s/%s%02d.png", homeDataDir, sdlGetFilename(filename), a);
|
sprintf(buffer, "%s%c%s%02d.png", gameDir, FILE_SEP, gameFile, a);
|
||||||
else
|
else
|
||||||
sprintf(buffer, "%s%02d.png", filename, a);
|
sprintf(buffer, "%s%c%s%02d.png", homeDataDir, FILE_SEP, gameFile, a);
|
||||||
emulator.emuWritePNG(buffer);
|
|
||||||
|
result = emulator.emuWritePNG(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
systemScreenMessage("Screen capture");
|
if (result)
|
||||||
|
systemScreenMessage("Screen capture");
|
||||||
|
|
||||||
|
freeSafe(gameFile);
|
||||||
|
freeSafe(gameDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
void systemSaveOldest()
|
void systemSaveOldest()
|
||||||
|
|
|
@ -461,6 +461,10 @@ void GameArea::recompute_dirs()
|
||||||
batdir = wxGetApp().GetAbsolutePath(gopts.battery_dir);
|
batdir = wxGetApp().GetAbsolutePath(gopts.battery_dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!wxIsWritable(batdir)) {
|
||||||
|
batdir = wxGetApp().GetDataDir();
|
||||||
|
}
|
||||||
|
|
||||||
statedir = gopts.state_dir;
|
statedir = gopts.state_dir;
|
||||||
|
|
||||||
if (!statedir.size()) {
|
if (!statedir.size()) {
|
||||||
|
@ -469,11 +473,9 @@ void GameArea::recompute_dirs()
|
||||||
statedir = wxGetApp().GetAbsolutePath(gopts.state_dir);
|
statedir = wxGetApp().GetAbsolutePath(gopts.state_dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!wxIsWritable(batdir))
|
if (!wxIsWritable(statedir)) {
|
||||||
batdir = wxGetApp().GetConfigurationPath();
|
statedir = wxGetApp().GetDataDir();
|
||||||
|
}
|
||||||
if (!wxIsWritable(statedir))
|
|
||||||
statedir = wxGetApp().GetConfigurationPath();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameArea::UnloadGame(bool destruct)
|
void GameArea::UnloadGame(bool destruct)
|
||||||
|
|
|
@ -636,6 +636,16 @@ bool wxvbamApp::OnCmdLineParsed(wxCmdLineParser& cl)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wxString wxvbamApp::GetConfigDir()
|
||||||
|
{
|
||||||
|
return GetAbsolutePath(get_xdg_user_config_home() + DOT_DIR);
|
||||||
|
}
|
||||||
|
|
||||||
|
wxString wxvbamApp::GetDataDir()
|
||||||
|
{
|
||||||
|
return GetAbsolutePath(get_xdg_user_data_home() + DOT_DIR);
|
||||||
|
}
|
||||||
|
|
||||||
wxvbamApp::~wxvbamApp() {
|
wxvbamApp::~wxvbamApp() {
|
||||||
if (home != NULL)
|
if (home != NULL)
|
||||||
{
|
{
|
||||||
|
@ -774,7 +784,10 @@ wxString MainFrame::GetGamePath(wxString path)
|
||||||
game_path = wxFileName::GetCwd();
|
game_path = wxFileName::GetCwd();
|
||||||
|
|
||||||
if (!wxIsWritable(game_path))
|
if (!wxIsWritable(game_path))
|
||||||
game_path = wxGetApp().GetConfigurationPath();
|
{
|
||||||
|
game_path = wxGetApp().GetAbsolutePath(get_xdg_user_data_home() + DOT_DIR);
|
||||||
|
wxFileName::Mkdir(game_path, 0777, wxPATH_MKDIR_FULL);
|
||||||
|
}
|
||||||
|
|
||||||
return game_path;
|
return game_path;
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,6 +88,8 @@ public:
|
||||||
virtual bool UsingWayland() { return using_wayland; }
|
virtual bool UsingWayland() { return using_wayland; }
|
||||||
virtual void OnInitCmdLine(wxCmdLineParser&);
|
virtual void OnInitCmdLine(wxCmdLineParser&);
|
||||||
virtual bool OnCmdLineParsed(wxCmdLineParser&);
|
virtual bool OnCmdLineParsed(wxCmdLineParser&);
|
||||||
|
virtual wxString GetConfigDir();
|
||||||
|
virtual wxString GetDataDir();
|
||||||
wxString GetConfigurationPath();
|
wxString GetConfigurationPath();
|
||||||
const wxString GetPluginsDir();
|
const wxString GetPluginsDir();
|
||||||
wxString GetAbsolutePath(wxString path);
|
wxString GetAbsolutePath(wxString path);
|
||||||
|
|
Loading…
Reference in New Issue