Allow drag&drop of state files
This commit is contained in:
parent
c1509b6339
commit
8a84a5897e
@ -44,5 +44,6 @@
|
|||||||
-(void) writeMemory:(uint16_t) addr value:(uint8_t)value;
|
-(void) writeMemory:(uint16_t) addr value:(uint8_t)value;
|
||||||
-(void) performAtomicBlock: (void (^)())block;
|
-(void) performAtomicBlock: (void (^)())block;
|
||||||
-(void) connectLinkCable:(NSMenuItem *)sender;
|
-(void) connectLinkCable:(NSMenuItem *)sender;
|
||||||
|
- (bool)loadStateFile:(const char *)path;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@ -1172,12 +1172,12 @@ static unsigned *multiplication_table_for_frequency(unsigned frequency)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (IBAction)loadState:(id)sender
|
- (bool)loadStateFile:(const char *)path
|
||||||
{
|
{
|
||||||
bool __block success = false;
|
bool __block success = false;
|
||||||
NSString *error =
|
NSString *error =
|
||||||
[self captureOutputForBlock:^{
|
[self captureOutputForBlock:^{
|
||||||
success = GB_load_state(&gb, [[self.fileURL URLByDeletingPathExtension] URLByAppendingPathExtension:[NSString stringWithFormat:@"s%ld", (long)[sender tag] ]].path.UTF8String) == 0;
|
success = GB_load_state(&gb, path) == 0;
|
||||||
}];
|
}];
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
@ -1186,6 +1186,12 @@ static unsigned *multiplication_table_for_frequency(unsigned frequency)
|
|||||||
if (error) {
|
if (error) {
|
||||||
[GBWarningPopover popoverWithContents:error onWindow:self.mainWindow];
|
[GBWarningPopover popoverWithContents:error onWindow:self.mainWindow];
|
||||||
}
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)loadState:(id)sender
|
||||||
|
{
|
||||||
|
[self loadStateFile:[[self.fileURL URLByDeletingPathExtension] URLByAppendingPathExtension:[NSString stringWithFormat:@"s%ld", (long)[sender tag] ]].path.UTF8String];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (IBAction)clearConsole:(id)sender
|
- (IBAction)clearConsole:(id)sender
|
||||||
|
@ -142,6 +142,8 @@ static const uint8_t workboy_vk_to_key[] = {
|
|||||||
|
|
||||||
- (void) _init
|
- (void) _init
|
||||||
{
|
{
|
||||||
|
[self registerForDraggedTypes:[NSArray arrayWithObjects: NSPasteboardTypeFileURL, nil]];
|
||||||
|
|
||||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(ratioKeepingChanged) name:@"GBAspectChanged" object:nil];
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(ratioKeepingChanged) name:@"GBAspectChanged" object:nil];
|
||||||
tracking_area = [ [NSTrackingArea alloc] initWithRect:(NSRect){}
|
tracking_area = [ [NSTrackingArea alloc] initWithRect:(NSRect){}
|
||||||
options:NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways | NSTrackingInVisibleRect
|
options:NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways | NSTrackingInVisibleRect
|
||||||
@ -626,4 +628,29 @@ static const uint8_t workboy_vk_to_key[] = {
|
|||||||
return image_buffers[(current_buffer + 2) % self.numberOfBuffers];
|
return image_buffers[(current_buffer + 2) % self.numberOfBuffers];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
-(NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender
|
||||||
|
{
|
||||||
|
NSPasteboard *pboard = [sender draggingPasteboard];
|
||||||
|
|
||||||
|
if ( [[pboard types] containsObject:NSURLPboardType] ) {
|
||||||
|
NSURL *fileURL = [NSURL URLFromPasteboard:pboard];
|
||||||
|
if (GB_is_stave_state(fileURL.fileSystemRepresentation)) {
|
||||||
|
return NSDragOperationGeneric;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NSDragOperationNone;
|
||||||
|
}
|
||||||
|
|
||||||
|
-(BOOL)performDragOperation:(id<NSDraggingInfo>)sender
|
||||||
|
{
|
||||||
|
NSPasteboard *pboard = [sender draggingPasteboard];
|
||||||
|
|
||||||
|
if ( [[pboard types] containsObject:NSURLPboardType] ) {
|
||||||
|
NSURL *fileURL = [NSURL URLFromPasteboard:pboard];
|
||||||
|
return [_document loadStateFile:fileURL.fileSystemRepresentation];
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -19,12 +19,6 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static inline uint32_t state_magic(void)
|
|
||||||
{
|
|
||||||
if (sizeof(bool) == 1) return 'SAME';
|
|
||||||
return 'S4ME';
|
|
||||||
}
|
|
||||||
|
|
||||||
void GB_attributed_logv(GB_gameboy_t *gb, GB_log_attributes attributes, const char *fmt, va_list args)
|
void GB_attributed_logv(GB_gameboy_t *gb, GB_log_attributes attributes, const char *fmt, va_list args)
|
||||||
{
|
{
|
||||||
char *string = NULL;
|
char *string = NULL;
|
||||||
|
@ -1170,3 +1170,36 @@ int GB_load_state_from_buffer(GB_gameboy_t *gb, const uint8_t *buffer, size_t le
|
|||||||
|
|
||||||
return load_state_internal(gb, &file);
|
return load_state_internal(gb, &file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool GB_is_stave_state(const char *path)
|
||||||
|
{
|
||||||
|
bool ret = false;
|
||||||
|
FILE *f = fopen(path, "rb");
|
||||||
|
if (!f) return false;
|
||||||
|
uint32_t magic = 0;
|
||||||
|
fread(&magic, sizeof(magic), 1, f);
|
||||||
|
if (magic == state_magic()) {
|
||||||
|
ret = true;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Legacy corrupted Windows save state
|
||||||
|
if (magic == 0) {
|
||||||
|
fread(&magic, sizeof(magic), 1, f);
|
||||||
|
if (magic == state_magic()) {
|
||||||
|
ret = true;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fseek(f, -sizeof(magic), SEEK_END);
|
||||||
|
fread(&magic, sizeof(magic), 1, f);
|
||||||
|
if (magic == BE32('BESS')) {
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
exit:
|
||||||
|
fclose(f);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
@ -27,8 +27,14 @@ void GB_save_state_to_buffer(GB_gameboy_t *gb, uint8_t *buffer);
|
|||||||
|
|
||||||
int GB_load_state(GB_gameboy_t *gb, const char *path);
|
int GB_load_state(GB_gameboy_t *gb, const char *path);
|
||||||
int GB_load_state_from_buffer(GB_gameboy_t *gb, const uint8_t *buffer, size_t length);
|
int GB_load_state_from_buffer(GB_gameboy_t *gb, const uint8_t *buffer, size_t length);
|
||||||
|
bool GB_is_stave_state(const char *path);
|
||||||
#ifdef GB_INTERNAL
|
#ifdef GB_INTERNAL
|
||||||
|
static inline uint32_t state_magic(void)
|
||||||
|
{
|
||||||
|
if (sizeof(bool) == 1) return 'SAME';
|
||||||
|
return 'S4ME';
|
||||||
|
}
|
||||||
|
|
||||||
/* For internal in-memory save states (rewind, debugger) that do not need BESS */
|
/* For internal in-memory save states (rewind, debugger) that do not need BESS */
|
||||||
size_t GB_get_save_state_size_no_bess(GB_gameboy_t *gb);
|
size_t GB_get_save_state_size_no_bess(GB_gameboy_t *gb);
|
||||||
void GB_save_state_to_buffer_no_bess(GB_gameboy_t *gb, uint8_t *buffer);
|
void GB_save_state_to_buffer_no_bess(GB_gameboy_t *gb, uint8_t *buffer);
|
||||||
|
13
SDL/gui.c
13
SDL/gui.c
@ -18,6 +18,7 @@ SDL_Texture *texture = NULL;
|
|||||||
SDL_PixelFormat *pixel_format = NULL;
|
SDL_PixelFormat *pixel_format = NULL;
|
||||||
enum pending_command pending_command;
|
enum pending_command pending_command;
|
||||||
unsigned command_parameter;
|
unsigned command_parameter;
|
||||||
|
char *dropped_state_file = NULL;
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
#define MODIFIER_NAME " " CMD_STRING
|
#define MODIFIER_NAME " " CMD_STRING
|
||||||
@ -1300,9 +1301,15 @@ void run_gui(bool is_running)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SDL_DROPFILE: {
|
case SDL_DROPFILE: {
|
||||||
set_filename(event.drop.file, SDL_free);
|
if (GB_is_stave_state(event.drop.file)) {
|
||||||
pending_command = GB_SDL_NEW_FILE_COMMAND;
|
dropped_state_file = event.drop.file;
|
||||||
return;
|
pending_command = GB_SDL_LOAD_STATE_FROM_FILE_COMMAND;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
set_filename(event.drop.file, SDL_free);
|
||||||
|
pending_command = GB_SDL_NEW_FILE_COMMAND;
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case SDL_JOYBUTTONDOWN:
|
case SDL_JOYBUTTONDOWN:
|
||||||
{
|
{
|
||||||
|
@ -39,12 +39,14 @@ enum pending_command {
|
|||||||
GB_SDL_RESET_COMMAND,
|
GB_SDL_RESET_COMMAND,
|
||||||
GB_SDL_NEW_FILE_COMMAND,
|
GB_SDL_NEW_FILE_COMMAND,
|
||||||
GB_SDL_QUIT_COMMAND,
|
GB_SDL_QUIT_COMMAND,
|
||||||
|
GB_SDL_LOAD_STATE_FROM_FILE_COMMAND,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define GB_SDL_DEFAULT_SCALE_MAX 8
|
#define GB_SDL_DEFAULT_SCALE_MAX 8
|
||||||
|
|
||||||
extern enum pending_command pending_command;
|
extern enum pending_command pending_command;
|
||||||
extern unsigned command_parameter;
|
extern unsigned command_parameter;
|
||||||
|
extern char *dropped_state_file;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
JOYPAD_BUTTON_LEFT,
|
JOYPAD_BUTTON_LEFT,
|
||||||
|
17
SDL/main.c
17
SDL/main.c
@ -142,8 +142,14 @@ static void handle_events(GB_gameboy_t *gb)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case SDL_DROPFILE: {
|
case SDL_DROPFILE: {
|
||||||
set_filename(event.drop.file, SDL_free);
|
if (GB_is_stave_state(event.drop.file)) {
|
||||||
pending_command = GB_SDL_NEW_FILE_COMMAND;
|
dropped_state_file = event.drop.file;
|
||||||
|
pending_command = GB_SDL_LOAD_STATE_FROM_FILE_COMMAND;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
set_filename(event.drop.file, SDL_free);
|
||||||
|
pending_command = GB_SDL_NEW_FILE_COMMAND;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -433,6 +439,13 @@ static bool handle_pending_command(void)
|
|||||||
end_capturing_logs(true, false);
|
end_capturing_logs(true, false);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case GB_SDL_LOAD_STATE_FROM_FILE_COMMAND:
|
||||||
|
start_capturing_logs();
|
||||||
|
GB_load_state(&gb, dropped_state_file);
|
||||||
|
end_capturing_logs(true, false);
|
||||||
|
SDL_free(dropped_state_file);
|
||||||
|
return false;
|
||||||
|
|
||||||
case GB_SDL_NO_COMMAND:
|
case GB_SDL_NO_COMMAND:
|
||||||
return false;
|
return false;
|
||||||
|
Loading…
Reference in New Issue
Block a user