diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index 77296e33..7172705c 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -165,7 +165,8 @@ snes9x_gtk_SOURCES += \
../logger.cpp \
../snapshot.cpp \
../screenshot.cpp \
- ../movie.cpp
+ ../movie.cpp \
+ ../statemanager.cpp
# ASMCPU Doesn't exist anymore.
snes9x_gtk_SOURCES += \
diff --git a/gtk/src/gtk_config.cpp b/gtk/src/gtk_config.cpp
index c0f3bde5..5b8e0298 100644
--- a/gtk/src/gtk_config.cpp
+++ b/gtk/src/gtk_config.cpp
@@ -174,6 +174,9 @@ Snes9xConfig::load_defaults (void)
netplay_last_host [0] = '\0';
netplay_last_port = 6096;
modal_dialogs = 1;
+
+ rewindGranularity = 5;
+ rewindBufferSize = 150;
#ifdef USE_OPENGL
sync_to_vblank = 1;
diff --git a/gtk/src/gtk_config.h b/gtk/src/gtk_config.h
index 9e8ec7c0..04363c5c 100644
--- a/gtk/src/gtk_config.h
+++ b/gtk/src/gtk_config.h
@@ -132,6 +132,9 @@ class Snes9xConfig
int pointer_is_visible;
struct timeval pointer_timestamp;
+
+ unsigned int rewindGranularity;
+ unsigned int rewindBufferSize;
#ifdef USE_XRANDR
XRRScreenConfiguration *xrr_config;
diff --git a/gtk/src/gtk_control.cpp b/gtk/src/gtk_control.cpp
index 906a2846..1601cad0 100644
--- a/gtk/src/gtk_control.cpp
+++ b/gtk/src/gtk_control.cpp
@@ -89,6 +89,7 @@ const BindingLink b_links[] =
{ "b_load_movie", "LoadMovie" },
{ "b_seek_to_frame", "GTK_seek_to_frame" },
{ "b_swap_controllers", "GTK_swap_controllers" },
+ { "b_rewind", "GTK_rewind" },
{ NULL, NULL }
};
@@ -193,6 +194,8 @@ S9xHandlePortCommand (s9xcommand_t cmd, int16 data1, int16 data2)
{
if (cmd.port[0] == PORT_QUIT)
quit_binding_down = TRUE;
+ else if (cmd.port[0] == PORT_REWIND)
+ top_level->user_rewind = TRUE;
}
if (data1 == FALSE) /* Release */
@@ -225,6 +228,11 @@ S9xHandlePortCommand (s9xcommand_t cmd, int16 data1, int16 data2)
top_level->unpause_from_user ();
}
+ else if (cmd.port[0] == PORT_REWIND)
+ {
+ top_level->user_rewind = FALSE;
+ }
+
else if (cmd.port[0] == PORT_SEEK_TO_FRAME)
{
top_level->movie_seek_dialog ();
@@ -307,6 +315,11 @@ S9xGetPortCommandT (const char *name)
cmd.port[0] = PORT_SWAP_CONTROLLERS;
}
+ else if (!strcasecmp (name, "GTK_rewind"))
+ {
+ cmd.port[0] = PORT_REWIND;
+ }
+
else
{
cmd = S9xGetCommandT (name);
diff --git a/gtk/src/gtk_control.h b/gtk/src/gtk_control.h
index 3afaa9e3..5ed09ac2 100644
--- a/gtk/src/gtk_control.h
+++ b/gtk/src/gtk_control.h
@@ -26,6 +26,7 @@
#define PORT_SEEK_TO_FRAME 5
#define PORT_QUIT 6
#define PORT_SWAP_CONTROLLERS 7
+#define PORT_REWIND 8
typedef struct BindingLink
{
@@ -37,7 +38,7 @@ typedef struct BindingLink
extern const BindingLink b_links[];
extern const int b_breaks[];
#define NUM_JOYPAD_LINKS 24
-#define NUM_EMU_LINKS 52
+#define NUM_EMU_LINKS 53
typedef struct JoypadBinding
{
diff --git a/gtk/src/gtk_s9x.cpp b/gtk/src/gtk_s9x.cpp
index 03e1c812..01595edf 100644
--- a/gtk/src/gtk_s9x.cpp
+++ b/gtk/src/gtk_s9x.cpp
@@ -9,6 +9,8 @@
#include "gtk_sound.h"
#include "gtk_display.h"
+#include "statemanager.h"
+
#ifdef NETPLAY_SUPPORT
#include "gtk_netplay.h"
#endif
@@ -23,6 +25,7 @@ static gboolean S9xScreenSaverCheckFunc (gpointer data);
Snes9xWindow *top_level;
Snes9xConfig *gui_config;
+StateManager stateMan;
static struct timeval next_frame_time = { 0, 0 };
static struct timeval now;
static int needs_fullscreening = FALSE;
@@ -217,6 +220,12 @@ S9xOpenROM (const char *rom_filename)
}
CPU.Flags = flags;
+
+ if (gui_config->rewindBufferSize)
+ {
+ printf("Setting buffer size to %u\n", gui_config->rewindBufferSize * 1024 * 1024);
+ stateMan.init(gui_config->rewindBufferSize * 1024 * 1024);
+ }
S9xROMLoaded ();
@@ -356,6 +365,12 @@ S9xIdleFunc (gpointer data)
if (!S9xNetplayPush ())
{
#endif
+
+ if(top_level->user_rewind)
+ top_level->user_rewind = stateMan.pop();
+ else if(IPPU.TotalEmulatedFrames % gui_config->rewindGranularity == 0)
+ stateMan.push();
+
S9xMainLoop ();
S9xMixSound ();
diff --git a/gtk/src/gtk_s9xwindow.cpp b/gtk/src/gtk_s9xwindow.cpp
index 7c275932..a6ade21e 100644
--- a/gtk/src/gtk_s9xwindow.cpp
+++ b/gtk/src/gtk_s9xwindow.cpp
@@ -589,6 +589,7 @@ Snes9xWindow::Snes9xWindow (Snes9xConfig *config) :
};
user_pause = 0;
+ user_rewind = 0;
sys_pause = 0;
last_width = -1;
last_height = -1;
diff --git a/gtk/src/gtk_s9xwindow.h b/gtk/src/gtk_s9xwindow.h
index d5350480..350e2abd 100644
--- a/gtk/src/gtk_s9xwindow.h
+++ b/gtk/src/gtk_s9xwindow.h
@@ -69,6 +69,7 @@ class Snes9xWindow : public GtkBuilderWindow
Snes9xConfig *config;
int user_pause, sys_pause;
+ int user_rewind;
int last_width, last_height;
int mouse_region_x, mouse_region_y;
int mouse_region_width, mouse_region_height;
diff --git a/gtk/src/snes9x.ui b/gtk/src/snes9x.ui
index 051c2cd8..509128f4 100644
--- a/gtk/src/snes9x.ui
+++ b/gtk/src/snes9x.ui
@@ -8028,7 +8028,7 @@
False
GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
10
- 6
+ 7
2
10
5
@@ -8224,6 +8224,37 @@
GTK_FILL
+
+
+
+ 6
+ 7
+ GTK_FILL
+
+
+
+
+
+
+ 1
+ 2
+ 6
+ 7
+ GTK_FILL
+
+
4