* 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 { namespace Emulator {
static const string Name = "bsnes"; 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 Author = "byuu";
static const string License = "GPLv3"; static const string License = "GPLv3";
static const string Website = "https://byuu.org"; 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(natural, "Hacks/CPU/Overclock", hacks.cpu.overclock);
bind(boolean, "Hacks/PPU/Fast", hacks.ppu.fast); 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/Deinterlace", hacks.ppu.deinterlace);
bind(boolean, "Hacks/PPU/NoSpriteLimit", hacks.ppu.noSpriteLimit);
bind(natural, "Hacks/PPU/Mode7/Scale", hacks.ppu.mode7.scale); 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/Perspective", hacks.ppu.mode7.perspective);
bind(boolean, "Hacks/PPU/Mode7/Supersample", hacks.ppu.mode7.supersample); bind(boolean, "Hacks/PPU/Mode7/Supersample", hacks.ppu.mode7.supersample);

View File

@ -30,8 +30,8 @@ struct Configuration {
} cpu; } cpu;
struct PPU { struct PPU {
bool fast = true; bool fast = true;
bool noSpriteLimit = true;
bool deinterlace = true; bool deinterlace = true;
bool noSpriteLimit = false;
struct Mode7 { struct Mode7 {
uint scale = 1; uint scale = 1;
bool perspective = true; 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/CPU/Overclock", settings.emulator.hack.cpu.overclock);
emulator->configure("Hacks/PPU/Fast", settings.emulator.hack.ppu.fast); 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/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/Scale", settings.emulator.hack.ppu.mode7.scale);
emulator->configure("Hacks/PPU/Mode7/Perspective", settings.emulator.hack.ppu.mode7.perspective); emulator->configure("Hacks/PPU/Mode7/Perspective", settings.emulator.hack.ppu.mode7.perspective);
emulator->configure("Hacks/PPU/Mode7/Supersample", settings.emulator.hack.ppu.mode7.supersample); 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 { auto Program::focused() -> bool {
//exclusive mode creates its own top-level window: presentation window will not have focus //full-screen mode creates its own top-level window: presentation window will not have focus
if(video.exclusive() || presentation.focused()) { if(video.fullScreen() || presentation.focused()) {
mute &= ~Mute::Unfocused; mute &= ~Mute::Unfocused;
return true; return true;
} else { } else {

View File

@ -8,13 +8,13 @@ auto DriverSettings::create() -> void {
videoDriverUpdate.setText(videoDriverOption.selected().text() != video.driver() ? "Change" : "Reload"); videoDriverUpdate.setText(videoDriverOption.selected().text() != video.driver() ? "Change" : "Reload");
}); });
videoDriverUpdate.setText("Change").onActivate([&] { videoDriverChange(); }); 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." "Sets which monitor video is sent to in fullscreen mode."
); );
videoMonitorOption.onChange([&] { videoMonitorChange(); }); videoMonitorOption.onChange([&] { videoMonitorChange(); });
videoFormatLabel.setText("Format:"); videoFormatLabel.setText("Format:");
videoFormatOption.onChange([&] { videoFormatChange(); }); videoFormatOption.onChange([&] { videoFormatChange(); });
videoExclusiveToggle.setText("Exclusive").setToolTip( videoExclusiveToggle.setText("Exclusive mode").setToolTip(
"Causes fullscreen mode to take over all monitors.\n" "Causes fullscreen mode to take over all monitors.\n"
"This allows adaptive sync to work better and reduces input latency.\n" "This allows adaptive sync to work better and reduces input latency.\n"
"However, multi-monitor users should turn this option off.\n" "However, multi-monitor users should turn this option off.\n"
@ -47,13 +47,12 @@ auto DriverSettings::create() -> void {
videoSpacer.setColor({192, 192, 192}); videoSpacer.setColor({192, 192, 192});
audioLabel.setText("Audio").setFont(Font().setBold()); audioLabel.setText("Audio").setFont(Font().setBold());
audioLayout.setSize({2, 2});
audioDriverLabel.setText("Driver:"); audioDriverLabel.setText("Driver:");
audioDriverOption.onChange([&] { audioDriverOption.onChange([&] {
audioDriverUpdate.setText(audioDriverOption.selected().text() != audio.driver() ? "Change" : "Reload"); audioDriverUpdate.setText(audioDriverOption.selected().text() != audio.driver() ? "Change" : "Reload");
}); });
audioDriverUpdate.setText("Change").onActivate([&] { audioDriverChange(); }); audioDriverUpdate.setText("Change").onActivate([&] { audioDriverChange(); });
audioDeviceLabel.setText("Device:"); audioDeviceLabel.setText("Output device:");
audioDeviceOption.onChange([&] { audioDeviceChange(); }); audioDeviceOption.onChange([&] { audioDeviceChange(); });
audioFrequencyLabel.setText("Frequency:"); audioFrequencyLabel.setText("Frequency:");
audioFrequencyOption.onChange([&] { audioFrequencyChange(); }); audioFrequencyOption.onChange([&] { audioFrequencyChange(); });
@ -92,7 +91,6 @@ auto DriverSettings::create() -> void {
audioSpacer.setColor({192, 192, 192}); audioSpacer.setColor({192, 192, 192});
inputLabel.setText("Input").setFont(Font().setBold()); inputLabel.setText("Input").setFont(Font().setBold());
inputLayout.setSize({2, 1});
inputDriverLabel.setText("Driver:"); inputDriverLabel.setText("Driver:");
inputDriverOption.onChange([&] { inputDriverOption.onChange([&] {
inputDriverUpdate.setText(inputDriverOption.selected().text() != input.driver() ? "Change" : "Reload"); inputDriverUpdate.setText(inputDriverOption.selected().text() != input.driver() ? "Change" : "Reload");
@ -167,7 +165,7 @@ auto DriverSettings::videoFormatChanged() -> void {
item.setText(format); item.setText(format);
if(format == video.format()) item.setSelected(); if(format == video.format()) item.setSelected();
} }
//videoFormatOption.setEnabled(video.hasFormat()); videoFormatOption.setEnabled(videoFormatOption.itemCount() > 1);
setGeometry(geometry()); setGeometry(geometry());
videoFormatChange(); videoFormatChange();
} }

View File

@ -35,13 +35,13 @@ auto EmulatorSettings::create() -> void {
mode7Layout.setEnabled(true); mode7Layout.setEnabled(true);
} }
}).doToggle(); }).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([&] { deinterlace.setText("Deinterlace").setChecked(settings.emulator.hack.ppu.deinterlace).onToggle([&] {
settings.emulator.hack.ppu.deinterlace = deinterlace.checked(); settings.emulator.hack.ppu.deinterlace = deinterlace.checked();
emulator->configure("Hacks/PPU/Deinterlace", settings.emulator.hack.ppu.deinterlace); 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()); mode7Label.setText("HD Mode 7 (fast PPU only)").setFont(Font().setBold());
mode7ScaleLabel.setText("Scale:"); mode7ScaleLabel.setText("Scale:");
mode7Scale.append(ComboButtonItem().setText( "240p").setProperty("multiplier", 1)); 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(boolean, "Emulator/AutoLoadStateOnLoad", emulator.autoLoadStateOnLoad);
bind(natural, "Emulator/Hack/CPU/Overclock", emulator.hack.cpu.overclock); 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/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/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(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/Perspective", emulator.hack.ppu.mode7.perspective);
bind(boolean, "Emulator/Hack/PPU/Mode7/Supersample", emulator.hack.ppu.mode7.supersample); bind(boolean, "Emulator/Hack/PPU/Mode7/Supersample", emulator.hack.ppu.mode7.supersample);

View File

@ -100,8 +100,8 @@ struct Settings : Markup::Node {
} cpu; } cpu;
struct PPU { struct PPU {
bool fast = true; bool fast = true;
bool noSpriteLimit = true;
bool deinterlace = true; bool deinterlace = true;
bool noSpriteLimit = false;
struct Mode7 { struct Mode7 {
uint scale = 1; uint scale = 1;
bool perspective = true; bool perspective = true;
@ -334,8 +334,8 @@ public:
Label ppuLabel{this, Size{~0, 0}, 2}; Label ppuLabel{this, Size{~0, 0}, 2};
HorizontalLayout ppuLayout{this, Size{~0, 0}}; HorizontalLayout ppuLayout{this, Size{~0, 0}};
CheckLabel fastPPU{&ppuLayout, Size{0, 0}}; CheckLabel fastPPU{&ppuLayout, Size{0, 0}};
CheckLabel noSpriteLimit{&ppuLayout, Size{0, 0}};
CheckLabel deinterlace{&ppuLayout, Size{0, 0}}; CheckLabel deinterlace{&ppuLayout, Size{0, 0}};
CheckLabel noSpriteLimit{&ppuLayout, Size{0, 0}};
Label mode7Label{this, Size{~0, 0}, 2}; Label mode7Label{this, Size{~0, 0}, 2};
HorizontalLayout mode7Layout{this, Size{~0, 0}}; HorizontalLayout mode7Layout{this, Size{~0, 0}};
Label mode7ScaleLabel{&mode7Layout, Size{0, 0}}; Label mode7ScaleLabel{&mode7Layout, Size{0, 0}};
@ -392,14 +392,14 @@ public:
CheckLabel videoFlushToggle{&videoToggleLayout, Size{0, 0}}; CheckLabel videoFlushToggle{&videoToggleLayout, Size{0, 0}};
Canvas videoSpacer{this, Size{~0, 1}}; Canvas videoSpacer{this, Size{~0, 1}};
Label audioLabel{this, Size{~0, 0}, 2}; Label audioLabel{this, Size{~0, 0}, 2};
TableLayout audioLayout{this, Size{~0, 0}}; VerticalLayout audioLayout{this, Size{~0, 0}};
Label audioDriverLabel{&audioLayout, Size{0, 0}};
HorizontalLayout audioDriverLayout{&audioLayout, Size{~0, 0}}; HorizontalLayout audioDriverLayout{&audioLayout, Size{~0, 0}};
Label audioDriverLabel{&audioDriverLayout, Size{0, 0}};
ComboButton audioDriverOption{&audioDriverLayout, Size{0, 0}}; ComboButton audioDriverOption{&audioDriverLayout, Size{0, 0}};
Button audioDriverUpdate{&audioDriverLayout, Size{0, 0}}; Button audioDriverUpdate{&audioDriverLayout, Size{0, 0}};
Label audioDriverActive{&audioDriverLayout, Size{0, 0}}; Label audioDriverActive{&audioDriverLayout, Size{0, 0}};
Label audioDeviceLabel{&audioLayout, Size{0, 0}};
HorizontalLayout audioPropertyLayout{&audioLayout, Size{~0, 0}}; HorizontalLayout audioPropertyLayout{&audioLayout, Size{~0, 0}};
Label audioDeviceLabel{&audioPropertyLayout, Size{0, 0}};
ComboButton audioDeviceOption{&audioPropertyLayout, Size{0, 0}}; ComboButton audioDeviceOption{&audioPropertyLayout, Size{0, 0}};
Label audioFrequencyLabel{&audioPropertyLayout, Size{0, 0}}; Label audioFrequencyLabel{&audioPropertyLayout, Size{0, 0}};
ComboButton audioFrequencyOption{&audioPropertyLayout, Size{0, 0}}; ComboButton audioFrequencyOption{&audioPropertyLayout, Size{0, 0}};
@ -411,9 +411,9 @@ public:
CheckLabel audioDynamicToggle{&audioToggleLayout, Size{0, 0}}; CheckLabel audioDynamicToggle{&audioToggleLayout, Size{0, 0}};
Canvas audioSpacer{this, Size{~0, 1}}; Canvas audioSpacer{this, Size{~0, 1}};
Label inputLabel{this, Size{~0, 0}, 2}; Label inputLabel{this, Size{~0, 0}, 2};
TableLayout inputLayout{this, Size{~0, 0}}; VerticalLayout inputLayout{this, Size{~0, 0}};
Label inputDriverLabel{&inputLayout, Size{0, 0}};
HorizontalLayout inputDriverLayout{&inputLayout, Size{~0, 0}}; HorizontalLayout inputDriverLayout{&inputLayout, Size{~0, 0}};
Label inputDriverLabel{&inputDriverLayout, Size{0, 0}};
ComboButton inputDriverOption{&inputDriverLayout, Size{0, 0}}; ComboButton inputDriverOption{&inputDriverLayout, Size{0, 0}};
Button inputDriverUpdate{&inputDriverLayout, Size{0, 0}}; Button inputDriverUpdate{&inputDriverLayout, Size{0, 0}};
Label inputDriverActive{&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; -(id) initWith:(VideoCGL*)video pixelFormat:(NSOpenGLPixelFormat*)pixelFormat;
-(void) reshape; -(void) reshape;
-(BOOL) acceptsFirstResponder;
@end
@interface RubyWindowCGL : NSWindow <NSWindowDelegate> {
@public
VideoCGL* video;
}
-(id) initWith:(VideoCGL*)video;
-(BOOL) canBecomeKeyWindow;
-(BOOL) canBecomeMainWindow;
@end @end
struct VideoCGL : VideoDriver, OpenGL { struct VideoCGL : VideoDriver, OpenGL {
@ -23,11 +33,16 @@ struct VideoCGL : VideoDriver, OpenGL {
auto driver() -> string override { return "OpenGL 3.2"; } auto driver() -> string override { return "OpenGL 3.2"; }
auto ready() -> bool override { return _ready; } auto ready() -> bool override { return _ready; }
auto hasFullScreen() -> bool override { return true; }
auto hasContext() -> bool override { return true; } auto hasContext() -> bool override { return true; }
auto hasBlocking() -> bool override { return true; } auto hasBlocking() -> bool override { return true; }
auto hasFlush() -> bool override { return true; } auto hasFlush() -> bool override { return true; }
auto hasShader() -> bool override { return true; } auto hasShader() -> bool override { return true; }
auto setFullScreen(bool fullScreen) -> bool override {
return initialize();
}
auto setContext(uintptr context) -> bool override { auto setContext(uintptr context) -> bool override {
return initialize(); return initialize();
} }
@ -100,9 +115,16 @@ struct VideoCGL : VideoDriver, OpenGL {
private: private:
auto initialize() -> bool { auto initialize() -> bool {
terminate(); terminate();
if(!self.context) return false; if(!self.fullScreen && !self.context) return false;
@autoreleasepool { @autoreleasepool {
if(self.fullScreen) {
window = [[RubyWindowCGL alloc] initWith:this];
[window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
[window toggleFullScreen:nil];
//[NSApp setPresentationOptions:NSApplicationPresentationFullScreen];
}
NSOpenGLPixelFormatAttribute attributeList[] = { NSOpenGLPixelFormatAttribute attributeList[] = {
NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core, NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core,
NSOpenGLPFAColorSize, 24, NSOpenGLPFAColorSize, 24,
@ -111,7 +133,7 @@ private:
0 0
}; };
auto context = (NSView*)self.context; auto context = self.fullScreen ? [window contentView] : (NSView*)self.context;
auto size = [context frame].size; auto size = [context frame].size;
auto format = [[[NSOpenGLPixelFormat alloc] initWithAttributes:attributeList] autorelease]; auto format = [[[NSOpenGLPixelFormat alloc] initWithAttributes:attributeList] autorelease];
auto openGLContext = [[[NSOpenGLContext alloc] initWithFormat:format shareContext:nil] autorelease]; auto openGLContext = [[[NSOpenGLContext alloc] initWithFormat:format shareContext:nil] autorelease];
@ -123,7 +145,7 @@ private:
[view setWantsBestResolutionOpenGLSurface:YES]; [view setWantsBestResolutionOpenGLSurface:YES];
[context addSubview:view]; [context addSubview:view];
[openGLContext setView:view]; [openGLContext setView:view];
[[view window] makeFirstResponder:view];
[view lockFocus]; [view lockFocus];
OpenGL::initialize(self.shader); OpenGL::initialize(self.shader);
@ -142,15 +164,26 @@ private:
_ready = false; _ready = false;
OpenGL::terminate(); OpenGL::terminate();
if(!view) return;
@autoreleasepool { @autoreleasepool {
[view removeFromSuperview]; if(view) {
[view release]; [view removeFromSuperview];
view = nil; [view release];
view = nil;
}
if(window) {
//[NSApp setPresentationOptions:NSApplicationPresentationDefault];
[window toggleFullScreen:nil];
[window setCollectionBehavior:NSWindowCollectionBehaviorDefault];
[window close];
[window release];
window = nil;
}
} }
} }
RubyVideoCGL* view = nullptr; RubyVideoCGL* view = nullptr;
RubyWindowCGL* window = nullptr;
bool _ready = false; bool _ready = false;
}; };
@ -168,4 +201,39 @@ private:
video->output(0, 0); 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 @end

View File

@ -327,14 +327,14 @@ auto Video::hasMonitors() -> vector<Monitor> {
auto displayID = [screenID unsignedIntValue]; auto displayID = [screenID unsignedIntValue];
auto displayPort = CGDisplayIOServicePort(displayID); auto displayPort = CGDisplayIOServicePort(displayID);
auto dictionary = IODisplayCreateInfoDictionary(displayPort, 0); 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); auto languageKeys = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
CFDictionaryApplyFunction((CFDictionaryRef)names, MonitorKeyArrayCallback, (void*)languageKeys); CFDictionaryApplyFunction(names, MonitorKeyArrayCallback, (void*)languageKeys);
auto orderLanguageKeys = CFBundleCopyPreferredLocalizationsFromArray(languageKeys); auto orderLanguageKeys = CFBundleCopyPreferredLocalizationsFromArray(languageKeys);
CFRelease(languageKeys); CFRelease(languageKeys);
if(orderLanguageKeys && CFArrayGetCount(orderLanguageKeys)) { if(orderLanguageKeys && CFArrayGetCount(orderLanguageKeys)) {
auto languageKey = CFArrayGetValueAtIndex(orderLanguageKeys, 0); 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]}; monitor.name = {1 + monitors.size(), ": ", [(__bridge NSString*)localName UTF8String]};
CFRelease(localName); CFRelease(localName);
} }