* 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:
byuu 2019-08-18 03:20:14 +09:00
parent ab25877af4
commit 95831d3675
11 changed files with 99 additions and 33 deletions

View File

@ -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";

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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 {

View File

@ -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();
}

View File

@ -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));

View File

@ -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);

View File

@ -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}};

View File

@ -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

View File

@ -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);
}