mirror of https://github.com/bsnes-emu/bsnes.git
v108.11
* added (primary-monitor only) fullscreen support for macOS * improved settings windows a bit * correct Program::focused() move from Video::exclusive()->fullScreen()
This commit is contained in:
parent
ab25877af4
commit
95831d3675
|
@ -29,7 +29,7 @@ using namespace nall;
|
|||
|
||||
namespace Emulator {
|
||||
static const string Name = "bsnes";
|
||||
static const string Version = "108.10";
|
||||
static const string Version = "108.11";
|
||||
static const string Author = "byuu";
|
||||
static const string License = "GPLv3";
|
||||
static const string Website = "https://byuu.org";
|
||||
|
|
|
@ -18,8 +18,8 @@ auto Configuration::process(Markup::Node document, bool load) -> void {
|
|||
|
||||
bind(natural, "Hacks/CPU/Overclock", hacks.cpu.overclock);
|
||||
bind(boolean, "Hacks/PPU/Fast", hacks.ppu.fast);
|
||||
bind(boolean, "Hacks/PPU/NoSpriteLimit", hacks.ppu.noSpriteLimit);
|
||||
bind(boolean, "Hacks/PPU/Deinterlace", hacks.ppu.deinterlace);
|
||||
bind(boolean, "Hacks/PPU/NoSpriteLimit", hacks.ppu.noSpriteLimit);
|
||||
bind(natural, "Hacks/PPU/Mode7/Scale", hacks.ppu.mode7.scale);
|
||||
bind(boolean, "Hacks/PPU/Mode7/Perspective", hacks.ppu.mode7.perspective);
|
||||
bind(boolean, "Hacks/PPU/Mode7/Supersample", hacks.ppu.mode7.supersample);
|
||||
|
|
|
@ -30,8 +30,8 @@ struct Configuration {
|
|||
} cpu;
|
||||
struct PPU {
|
||||
bool fast = true;
|
||||
bool noSpriteLimit = true;
|
||||
bool deinterlace = true;
|
||||
bool noSpriteLimit = false;
|
||||
struct Mode7 {
|
||||
uint scale = 1;
|
||||
bool perspective = true;
|
||||
|
|
|
@ -3,8 +3,8 @@ auto Program::load() -> void {
|
|||
|
||||
emulator->configure("Hacks/CPU/Overclock", settings.emulator.hack.cpu.overclock);
|
||||
emulator->configure("Hacks/PPU/Fast", settings.emulator.hack.ppu.fast);
|
||||
emulator->configure("Hacks/PPU/NoSpriteLimit", settings.emulator.hack.ppu.noSpriteLimit);
|
||||
emulator->configure("Hacks/PPU/Deinterlace", settings.emulator.hack.ppu.deinterlace);
|
||||
emulator->configure("Hacks/PPU/NoSpriteLimit", settings.emulator.hack.ppu.noSpriteLimit);
|
||||
emulator->configure("Hacks/PPU/Mode7/Scale", settings.emulator.hack.ppu.mode7.scale);
|
||||
emulator->configure("Hacks/PPU/Mode7/Perspective", settings.emulator.hack.ppu.mode7.perspective);
|
||||
emulator->configure("Hacks/PPU/Mode7/Supersample", settings.emulator.hack.ppu.mode7.supersample);
|
||||
|
|
|
@ -74,8 +74,8 @@ auto Program::inactive() -> bool {
|
|||
}
|
||||
|
||||
auto Program::focused() -> bool {
|
||||
//exclusive mode creates its own top-level window: presentation window will not have focus
|
||||
if(video.exclusive() || presentation.focused()) {
|
||||
//full-screen mode creates its own top-level window: presentation window will not have focus
|
||||
if(video.fullScreen() || presentation.focused()) {
|
||||
mute &= ~Mute::Unfocused;
|
||||
return true;
|
||||
} else {
|
||||
|
|
|
@ -8,13 +8,13 @@ auto DriverSettings::create() -> void {
|
|||
videoDriverUpdate.setText(videoDriverOption.selected().text() != video.driver() ? "Change" : "Reload");
|
||||
});
|
||||
videoDriverUpdate.setText("Change").onActivate([&] { videoDriverChange(); });
|
||||
videoMonitorLabel.setText("Fullscreen Monitor:").setToolTip(
|
||||
videoMonitorLabel.setText("Fullscreen monitor:").setToolTip(
|
||||
"Sets which monitor video is sent to in fullscreen mode."
|
||||
);
|
||||
videoMonitorOption.onChange([&] { videoMonitorChange(); });
|
||||
videoFormatLabel.setText("Format:");
|
||||
videoFormatOption.onChange([&] { videoFormatChange(); });
|
||||
videoExclusiveToggle.setText("Exclusive").setToolTip(
|
||||
videoExclusiveToggle.setText("Exclusive mode").setToolTip(
|
||||
"Causes fullscreen mode to take over all monitors.\n"
|
||||
"This allows adaptive sync to work better and reduces input latency.\n"
|
||||
"However, multi-monitor users should turn this option off.\n"
|
||||
|
@ -47,13 +47,12 @@ auto DriverSettings::create() -> void {
|
|||
videoSpacer.setColor({192, 192, 192});
|
||||
|
||||
audioLabel.setText("Audio").setFont(Font().setBold());
|
||||
audioLayout.setSize({2, 2});
|
||||
audioDriverLabel.setText("Driver:");
|
||||
audioDriverOption.onChange([&] {
|
||||
audioDriverUpdate.setText(audioDriverOption.selected().text() != audio.driver() ? "Change" : "Reload");
|
||||
});
|
||||
audioDriverUpdate.setText("Change").onActivate([&] { audioDriverChange(); });
|
||||
audioDeviceLabel.setText("Device:");
|
||||
audioDeviceLabel.setText("Output device:");
|
||||
audioDeviceOption.onChange([&] { audioDeviceChange(); });
|
||||
audioFrequencyLabel.setText("Frequency:");
|
||||
audioFrequencyOption.onChange([&] { audioFrequencyChange(); });
|
||||
|
@ -92,7 +91,6 @@ auto DriverSettings::create() -> void {
|
|||
audioSpacer.setColor({192, 192, 192});
|
||||
|
||||
inputLabel.setText("Input").setFont(Font().setBold());
|
||||
inputLayout.setSize({2, 1});
|
||||
inputDriverLabel.setText("Driver:");
|
||||
inputDriverOption.onChange([&] {
|
||||
inputDriverUpdate.setText(inputDriverOption.selected().text() != input.driver() ? "Change" : "Reload");
|
||||
|
@ -167,7 +165,7 @@ auto DriverSettings::videoFormatChanged() -> void {
|
|||
item.setText(format);
|
||||
if(format == video.format()) item.setSelected();
|
||||
}
|
||||
//videoFormatOption.setEnabled(video.hasFormat());
|
||||
videoFormatOption.setEnabled(videoFormatOption.itemCount() > 1);
|
||||
setGeometry(geometry());
|
||||
videoFormatChange();
|
||||
}
|
||||
|
|
|
@ -35,13 +35,13 @@ auto EmulatorSettings::create() -> void {
|
|||
mode7Layout.setEnabled(true);
|
||||
}
|
||||
}).doToggle();
|
||||
noSpriteLimit.setText("No sprite limit").setChecked(settings.emulator.hack.ppu.noSpriteLimit).onToggle([&] {
|
||||
settings.emulator.hack.ppu.noSpriteLimit = noSpriteLimit.checked();
|
||||
});
|
||||
deinterlace.setText("Deinterlace").setChecked(settings.emulator.hack.ppu.deinterlace).onToggle([&] {
|
||||
settings.emulator.hack.ppu.deinterlace = deinterlace.checked();
|
||||
emulator->configure("Hacks/PPU/Deinterlace", settings.emulator.hack.ppu.deinterlace);
|
||||
});
|
||||
noSpriteLimit.setText("No sprite limit").setChecked(settings.emulator.hack.ppu.noSpriteLimit).onToggle([&] {
|
||||
settings.emulator.hack.ppu.noSpriteLimit = noSpriteLimit.checked();
|
||||
});
|
||||
mode7Label.setText("HD Mode 7 (fast PPU only)").setFont(Font().setBold());
|
||||
mode7ScaleLabel.setText("Scale:");
|
||||
mode7Scale.append(ComboButtonItem().setText( "240p").setProperty("multiplier", 1));
|
||||
|
|
|
@ -114,8 +114,8 @@ auto Settings::process(bool load) -> void {
|
|||
bind(boolean, "Emulator/AutoLoadStateOnLoad", emulator.autoLoadStateOnLoad);
|
||||
bind(natural, "Emulator/Hack/CPU/Overclock", emulator.hack.cpu.overclock);
|
||||
bind(boolean, "Emulator/Hack/PPU/Fast", emulator.hack.ppu.fast);
|
||||
bind(boolean, "Emulator/Hack/PPU/NoSpriteLimit", emulator.hack.ppu.noSpriteLimit);
|
||||
bind(boolean, "Emulator/Hack/PPU/Deinterlace", emulator.hack.ppu.deinterlace);
|
||||
bind(boolean, "Emulator/Hack/PPU/NoSpriteLimit", emulator.hack.ppu.noSpriteLimit);
|
||||
bind(natural, "Emulator/Hack/PPU/Mode7/Scale", emulator.hack.ppu.mode7.scale);
|
||||
bind(boolean, "Emulator/Hack/PPU/Mode7/Perspective", emulator.hack.ppu.mode7.perspective);
|
||||
bind(boolean, "Emulator/Hack/PPU/Mode7/Supersample", emulator.hack.ppu.mode7.supersample);
|
||||
|
|
|
@ -100,8 +100,8 @@ struct Settings : Markup::Node {
|
|||
} cpu;
|
||||
struct PPU {
|
||||
bool fast = true;
|
||||
bool noSpriteLimit = true;
|
||||
bool deinterlace = true;
|
||||
bool noSpriteLimit = false;
|
||||
struct Mode7 {
|
||||
uint scale = 1;
|
||||
bool perspective = true;
|
||||
|
@ -334,8 +334,8 @@ public:
|
|||
Label ppuLabel{this, Size{~0, 0}, 2};
|
||||
HorizontalLayout ppuLayout{this, Size{~0, 0}};
|
||||
CheckLabel fastPPU{&ppuLayout, Size{0, 0}};
|
||||
CheckLabel noSpriteLimit{&ppuLayout, Size{0, 0}};
|
||||
CheckLabel deinterlace{&ppuLayout, Size{0, 0}};
|
||||
CheckLabel noSpriteLimit{&ppuLayout, Size{0, 0}};
|
||||
Label mode7Label{this, Size{~0, 0}, 2};
|
||||
HorizontalLayout mode7Layout{this, Size{~0, 0}};
|
||||
Label mode7ScaleLabel{&mode7Layout, Size{0, 0}};
|
||||
|
@ -392,14 +392,14 @@ public:
|
|||
CheckLabel videoFlushToggle{&videoToggleLayout, Size{0, 0}};
|
||||
Canvas videoSpacer{this, Size{~0, 1}};
|
||||
Label audioLabel{this, Size{~0, 0}, 2};
|
||||
TableLayout audioLayout{this, Size{~0, 0}};
|
||||
Label audioDriverLabel{&audioLayout, Size{0, 0}};
|
||||
VerticalLayout audioLayout{this, Size{~0, 0}};
|
||||
HorizontalLayout audioDriverLayout{&audioLayout, Size{~0, 0}};
|
||||
Label audioDriverLabel{&audioDriverLayout, Size{0, 0}};
|
||||
ComboButton audioDriverOption{&audioDriverLayout, Size{0, 0}};
|
||||
Button audioDriverUpdate{&audioDriverLayout, Size{0, 0}};
|
||||
Label audioDriverActive{&audioDriverLayout, Size{0, 0}};
|
||||
Label audioDeviceLabel{&audioLayout, Size{0, 0}};
|
||||
HorizontalLayout audioPropertyLayout{&audioLayout, Size{~0, 0}};
|
||||
Label audioDeviceLabel{&audioPropertyLayout, Size{0, 0}};
|
||||
ComboButton audioDeviceOption{&audioPropertyLayout, Size{0, 0}};
|
||||
Label audioFrequencyLabel{&audioPropertyLayout, Size{0, 0}};
|
||||
ComboButton audioFrequencyOption{&audioPropertyLayout, Size{0, 0}};
|
||||
|
@ -411,9 +411,9 @@ public:
|
|||
CheckLabel audioDynamicToggle{&audioToggleLayout, Size{0, 0}};
|
||||
Canvas audioSpacer{this, Size{~0, 1}};
|
||||
Label inputLabel{this, Size{~0, 0}, 2};
|
||||
TableLayout inputLayout{this, Size{~0, 0}};
|
||||
Label inputDriverLabel{&inputLayout, Size{0, 0}};
|
||||
VerticalLayout inputLayout{this, Size{~0, 0}};
|
||||
HorizontalLayout inputDriverLayout{&inputLayout, Size{~0, 0}};
|
||||
Label inputDriverLabel{&inputDriverLayout, Size{0, 0}};
|
||||
ComboButton inputDriverOption{&inputDriverLayout, Size{0, 0}};
|
||||
Button inputDriverUpdate{&inputDriverLayout, Size{0, 0}};
|
||||
Label inputDriverActive{&inputDriverLayout, Size{0, 0}};
|
||||
|
|
|
@ -9,6 +9,16 @@ struct VideoCGL;
|
|||
}
|
||||
-(id) initWith:(VideoCGL*)video pixelFormat:(NSOpenGLPixelFormat*)pixelFormat;
|
||||
-(void) reshape;
|
||||
-(BOOL) acceptsFirstResponder;
|
||||
@end
|
||||
|
||||
@interface RubyWindowCGL : NSWindow <NSWindowDelegate> {
|
||||
@public
|
||||
VideoCGL* video;
|
||||
}
|
||||
-(id) initWith:(VideoCGL*)video;
|
||||
-(BOOL) canBecomeKeyWindow;
|
||||
-(BOOL) canBecomeMainWindow;
|
||||
@end
|
||||
|
||||
struct VideoCGL : VideoDriver, OpenGL {
|
||||
|
@ -23,11 +33,16 @@ struct VideoCGL : VideoDriver, OpenGL {
|
|||
auto driver() -> string override { return "OpenGL 3.2"; }
|
||||
auto ready() -> bool override { return _ready; }
|
||||
|
||||
auto hasFullScreen() -> bool override { return true; }
|
||||
auto hasContext() -> bool override { return true; }
|
||||
auto hasBlocking() -> bool override { return true; }
|
||||
auto hasFlush() -> bool override { return true; }
|
||||
auto hasShader() -> bool override { return true; }
|
||||
|
||||
auto setFullScreen(bool fullScreen) -> bool override {
|
||||
return initialize();
|
||||
}
|
||||
|
||||
auto setContext(uintptr context) -> bool override {
|
||||
return initialize();
|
||||
}
|
||||
|
@ -100,9 +115,16 @@ struct VideoCGL : VideoDriver, OpenGL {
|
|||
private:
|
||||
auto initialize() -> bool {
|
||||
terminate();
|
||||
if(!self.context) return false;
|
||||
if(!self.fullScreen && !self.context) return false;
|
||||
|
||||
@autoreleasepool {
|
||||
if(self.fullScreen) {
|
||||
window = [[RubyWindowCGL alloc] initWith:this];
|
||||
[window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
|
||||
[window toggleFullScreen:nil];
|
||||
//[NSApp setPresentationOptions:NSApplicationPresentationFullScreen];
|
||||
}
|
||||
|
||||
NSOpenGLPixelFormatAttribute attributeList[] = {
|
||||
NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core,
|
||||
NSOpenGLPFAColorSize, 24,
|
||||
|
@ -111,7 +133,7 @@ private:
|
|||
0
|
||||
};
|
||||
|
||||
auto context = (NSView*)self.context;
|
||||
auto context = self.fullScreen ? [window contentView] : (NSView*)self.context;
|
||||
auto size = [context frame].size;
|
||||
auto format = [[[NSOpenGLPixelFormat alloc] initWithAttributes:attributeList] autorelease];
|
||||
auto openGLContext = [[[NSOpenGLContext alloc] initWithFormat:format shareContext:nil] autorelease];
|
||||
|
@ -123,7 +145,7 @@ private:
|
|||
[view setWantsBestResolutionOpenGLSurface:YES];
|
||||
[context addSubview:view];
|
||||
[openGLContext setView:view];
|
||||
|
||||
[[view window] makeFirstResponder:view];
|
||||
[view lockFocus];
|
||||
|
||||
OpenGL::initialize(self.shader);
|
||||
|
@ -142,15 +164,26 @@ private:
|
|||
_ready = false;
|
||||
OpenGL::terminate();
|
||||
|
||||
if(!view) return;
|
||||
@autoreleasepool {
|
||||
[view removeFromSuperview];
|
||||
[view release];
|
||||
view = nil;
|
||||
if(view) {
|
||||
[view removeFromSuperview];
|
||||
[view release];
|
||||
view = nil;
|
||||
}
|
||||
|
||||
if(window) {
|
||||
//[NSApp setPresentationOptions:NSApplicationPresentationDefault];
|
||||
[window toggleFullScreen:nil];
|
||||
[window setCollectionBehavior:NSWindowCollectionBehaviorDefault];
|
||||
[window close];
|
||||
[window release];
|
||||
window = nil;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RubyVideoCGL* view = nullptr;
|
||||
RubyWindowCGL* window = nullptr;
|
||||
|
||||
bool _ready = false;
|
||||
};
|
||||
|
@ -168,4 +201,39 @@ private:
|
|||
video->output(0, 0);
|
||||
}
|
||||
|
||||
-(BOOL) acceptsFirstResponder {
|
||||
return YES;
|
||||
}
|
||||
|
||||
-(void) keyDown:(NSEvent*)event {
|
||||
}
|
||||
|
||||
-(void) keyUp:(NSEvent*)event {
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation RubyWindowCGL : NSWindow
|
||||
|
||||
-(id) initWith:(VideoCGL*)videoPointer {
|
||||
auto primaryRect = [[[NSScreen screens] objectAtIndex:0] frame];
|
||||
if(self = [super initWithContentRect:primaryRect styleMask:0 backing:NSBackingStoreBuffered defer:YES]) {
|
||||
video = videoPointer;
|
||||
[self setDelegate:self];
|
||||
[self setReleasedWhenClosed:NO];
|
||||
[self setAcceptsMouseMovedEvents:YES];
|
||||
[self setTitle:@""];
|
||||
[self makeKeyAndOrderFront:nil];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
-(BOOL) canBecomeKeyWindow {
|
||||
return YES;
|
||||
}
|
||||
|
||||
-(BOOL) canBecomeMainWindow {
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -327,14 +327,14 @@ auto Video::hasMonitors() -> vector<Monitor> {
|
|||
auto displayID = [screenID unsignedIntValue];
|
||||
auto displayPort = CGDisplayIOServicePort(displayID);
|
||||
auto dictionary = IODisplayCreateInfoDictionary(displayPort, 0);
|
||||
if(auto names = CFDictionaryGetValue(dictionary, CFSTR(kDisplayProductName))) {
|
||||
if(auto names = (CFDictionaryRef)CFDictionaryGetValue(dictionary, CFSTR(kDisplayProductName))) {
|
||||
auto languageKeys = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
|
||||
CFDictionaryApplyFunction((CFDictionaryRef)names, MonitorKeyArrayCallback, (void*)languageKeys);
|
||||
CFDictionaryApplyFunction(names, MonitorKeyArrayCallback, (void*)languageKeys);
|
||||
auto orderLanguageKeys = CFBundleCopyPreferredLocalizationsFromArray(languageKeys);
|
||||
CFRelease(languageKeys);
|
||||
if(orderLanguageKeys && CFArrayGetCount(orderLanguageKeys)) {
|
||||
auto languageKey = CFArrayGetValueAtIndex(orderLanguageKeys, 0);
|
||||
auto localName = CFDictionaryGetValue((CFDictionaryRef)names, languageKey);
|
||||
auto localName = CFDictionaryGetValue(names, languageKey);
|
||||
monitor.name = {1 + monitors.size(), ": ", [(__bridge NSString*)localName UTF8String]};
|
||||
CFRelease(localName);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue