Skip to content
This repository has been archived by the owner on Jul 10, 2023. It is now read-only.

Commit

Permalink
Merge pull request #1874 from reicast/einsteinx2/macos-console-window
Browse files Browse the repository at this point in the history
macOS console window with regex filtering
  • Loading branch information
skmp authored Apr 2, 2020
2 parents 657bdd4 + 183ce7a commit 046d94d
Show file tree
Hide file tree
Showing 11 changed files with 447 additions and 109 deletions.
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,9 @@ elseif(${HOST_OS} EQUAL ${OS_DARWIN})
${d_osx}/main.m
${d_osx}/input.mm
${d_osx}/AppDelegate.mm
${d_osx}/ConsoleViewController.m
${d_osx}/EmuGLView.m
${d_osx}/MainMenu.m
)

list(APPEND osd_SRCS ${objc_SRCS}
Expand Down
16 changes: 9 additions & 7 deletions libswirl/hw/sh4/modules/scif.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,16 @@ int SerialReadData(u8* buffer, size_t nbytes) {
}

void SerialWriteData(u8 data) {
if (settings.debug.SerialConsole) {
putc(data, stdout);
}
if (settings.debug.SerialConsole) {
putc(data, stdout);
}
#if FEAT_HAS_SERIAL_TTY
if (pty_master != -1) {
while(write(pty_master, &data, 1) != 1 && errno != EAGAIN)
printf("SERIAL: PTY write failed, %s\n", strerror(errno));
}
if (pty_master != -1) {
while(write(pty_master, &data, 1) != 1 && errno != EAGAIN) {
// Some error other than "resource temporarily unavailable" aka "buffer is full" aka "nothing is consuming it" occurred during write
printf("SERIAL: PTY write failed, %s\n", strerror(errno));
}
}
#endif
}

Expand Down
11 changes: 10 additions & 1 deletion reicast/apple/emulator-osx/emulator-osx/AppDelegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,21 @@

#import <AppKit/AppKit.h>
#import "EmuGLView.h"
#import "ConsoleViewController.h"

@interface AppDelegate : NSObject <NSWindowDelegate, EmuGLViewDelegate>

@property (strong) NSWindow *window;
// Main UI display window
@property (strong) NSWindow *mainWindow;
@property (strong) EmuGLView *glView;

// Console window
@property (strong) NSWindow *consoleWindow;
@property (strong) ConsoleViewController *consoleViewController;

+ (AppDelegate *)sharedInstance;

- (void)showConsoleWindow:(NSMenuItem *)menuItem;
- (void)hideConsoleWindow:(NSMenuItem *)menuItem;

@end
131 changes: 120 additions & 11 deletions reicast/apple/emulator-osx/emulator-osx/AppDelegate.mm
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "license/bsd"

#import "AppDelegate.h"
#import "MainMenu.h"
#import "libswirl.h"
#import "gui/gui_renderer.h"

Expand All @@ -23,9 +24,17 @@
static CGSize _glViewSize;
static void gl_resize();

@interface AppDelegate()
@property (strong) NSTextStorage *consoleTextStorage;
@end

@implementation AppDelegate {
NSThread *_uiThread;
BOOL _removePTYSymlink;

// Console redirection
dispatch_source_t _stdoutSource;
dispatch_source_t _stderrSource;
}

#pragma mark - Delegate Methods -
Expand Down Expand Up @@ -55,31 +64,131 @@ - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sende
// TODO: BEN This works while in BIOS or game, but doesn't correctly update the DPI for ImGUI
- (void)windowDidChangeBackingProperties:(NSNotification *)notification {
// Handle DPI changes dragging between monitors
_backingScaleFactor = _window.screen.backingScaleFactor;
_backingScaleFactor = _mainWindow.screen.backingScaleFactor;
[self setupScreenDPI];
gl_resize();
}

- (void)windowWillClose:(NSNotification *)notification {
if (notification.object == _mainWindow) {
// Make sure to close the console window if we're closing Reicast
[_consoleWindow close];
} else if (notification.object == _consoleWindow) {
_consoleWindow = nil;
_consoleViewController = nil;

// Change menu item
NSMenuItem *menuItem = [MainMenu toggleConsoleMenuItem];
menuItem.title = @"Show Console";
menuItem.action = @selector(showConsoleWindow:);
}
}

- (void)emuGLViewIsResizing:(EmuGLView *)emuGLView {
// Smoother rendering while resizing the window
_glViewSize = emuGLView.frame.size;
gl_resize();
}

#pragma mark - Action Methods -

- (void)showConsoleWindow:(NSMenuItem *)menuItem {
if (!_consoleWindow) {
// Create the ConsoleViewController
_consoleViewController = [[ConsoleViewController alloc] initWithTextStorage:_consoleTextStorage];

// Create the Window
NSWindowStyleMask styleMask = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable;
_consoleWindow = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 640, 480) styleMask:styleMask backing:NSBackingStoreBuffered defer:NO];
_consoleWindow.delegate = self;
_consoleWindow.contentViewController = _consoleViewController;
_consoleWindow.releasedWhenClosed = NO;
_consoleWindow.title = @"Console Output";
[_consoleWindow makeKeyAndOrderFront:_consoleWindow];
[_consoleWindow setFrameOrigin:NSMakePoint(NSMaxX(_mainWindow.frame) + 50, NSMinY(_mainWindow.frame))];
[_mainWindow makeKeyAndOrderFront:_mainWindow];

// Change menu item
menuItem.title = @"Hide Console";
menuItem.action = @selector(hideConsoleWindow:);
}
}

- (void)hideConsoleWindow:(NSMenuItem *)menuItem {
if (_consoleWindow) {
[_consoleWindow close];
}
}

#pragma mark - Setup Methods -

- (void)mainSetup {
[self captureConsoleOutput];
[self setupWindow];
[self setupScreenDPI];
[self setupPaths];
common_linux_setup();
if (reicast_init(0, NULL) != 0) {
[self alertAndTerminateWithMessage:@"Reicast initialization failed"];
}
#if FEAT_HAS_SERIAL_TTY
_removePTYSymlink = common_serial_pty_setup();
#endif
[self setupUIThread];
}

- (void)captureConsoleOutput {
// Create the console text storage
_consoleTextStorage = [[NSTextStorage alloc] init];

// Block to consolidate common code
void (^handleConsoleEvent)(NSPipe*, void*, int) = ^void(NSPipe *pipe, void *buffer, int fdOrig) {
// Read from stderr/out
ssize_t readResult = 0;
do {
errno = 0;
readResult = read(pipe.fileHandleForReading.fileDescriptor, buffer, 4096);
} while (readResult == -1 && errno == EINTR);

if(readResult > 0) {
// There was output, so write it to the console window's text storage
NSString* string = [[NSString alloc] initWithBytesNoCopy:buffer length:readResult encoding:NSUTF8StringEncoding freeWhenDone:NO];
NSDictionary *attributes = [ConsoleViewController defaultTextAttributes];
NSAttributedString* attributedString = [[NSAttributedString alloc] initWithString:string attributes:attributes];
dispatch_sync(dispatch_get_main_queue(),^{
[self.consoleTextStorage appendAttributedString:attributedString];
});

// Write to normal console output as well
write(fdOrig, buffer, readResult);
}
};

// Read buffers
static char stderrBuffer[4096];
static char stdoutBuffer[4096];

// Duplicate original file descriptors to allow writing to the standard console
int stderrOrig = dup(fileno(stderr));
int stdoutOrig = dup(fileno(stdout));

// Create the pipes and divert the standard outputs
NSPipe *stderrPipe = [NSPipe pipe];
NSPipe *stdoutPipe = [NSPipe pipe];
dup2(stderrPipe.fileHandleForWriting.fileDescriptor, fileno(stderr));
dup2(stdoutPipe.fileHandleForWriting.fileDescriptor, fileno(stdout));

// Set up dispatch event handlers to listen for output
_stderrSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, stderrPipe.fileHandleForReading.fileDescriptor, 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0));
_stdoutSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, stdoutPipe.fileHandleForReading.fileDescriptor, 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0));
dispatch_source_set_event_handler(_stderrSource, ^{ handleConsoleEvent(stderrPipe, &stderrBuffer, stderrOrig); });
dispatch_source_set_event_handler(_stdoutSource, ^{ handleConsoleEvent(stdoutPipe, &stdoutBuffer, stdoutOrig); });

// Start listening
dispatch_resume(_stderrSource);
dispatch_resume(_stdoutSource);
}

- (void)setupWindow {
// Create the OpenGL view and context
// TODO: BEN See why background color is red when resizing window tall (it's likely due to default GL framebuffer color)
Expand All @@ -88,21 +197,21 @@ - (void)setupWindow {

// Create the Window
NSWindowStyleMask styleMask = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable;
_window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 640, 480) styleMask:styleMask backing:NSBackingStoreBuffered defer:NO];
_window.delegate = self;
_window.contentView = _glView;
_window.acceptsMouseMovedEvents = YES;
[_window makeKeyAndOrderFront:_window];
[_window center];
_mainWindow = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 640, 480) styleMask:styleMask backing:NSBackingStoreBuffered defer:NO];
_mainWindow.delegate = self;
_mainWindow.contentView = _glView;
_mainWindow.acceptsMouseMovedEvents = YES;
[_mainWindow makeKeyAndOrderFront:_mainWindow];
[_mainWindow center];

// Set initial scale factor and view size
_backingScaleFactor = _window.screen.backingScaleFactor;
_backingScaleFactor = _mainWindow.screen.backingScaleFactor;
_glViewSize = _glView.bounds.size;
}

- (void)setupScreenDPI {
// Calculate screen DPI
NSScreen *screen = _window.screen;
NSScreen *screen = _mainWindow.screen;
NSDictionary *description = [screen deviceDescription];
NSSize displayPixelSize = [[description objectForKey:NSDeviceSize] sizeValue];
// Must multiply by the scale factor to account for retina displays
Expand Down Expand Up @@ -250,7 +359,7 @@ static void gl_resize() {
}

void* libPvr_GetRenderTarget() {
return (__bridge void*)_sharedInstance.window;
return (__bridge void*)_sharedInstance.mainWindow;
}

void* libPvr_GetRenderSurface() {
Expand All @@ -268,7 +377,7 @@ int push_vmu_screen(u8* buffer) {
int darw_printf(const wchar* text,...) {
va_list args;

wchar temp[2048];
static wchar temp[2048];
va_start(args, text);
vsprintf(temp, text, args);
va_end(args);
Expand Down
17 changes: 17 additions & 0 deletions reicast/apple/emulator-osx/emulator-osx/ConsoleViewController.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//
// ConsoleViewController.h
// reicast-osx
//
// Created by Benjamin Baron on 3/31/20.
// Copyright © 2020 reicast. All rights reserved.
//

#import <Cocoa/Cocoa.h>

@interface ConsoleViewController : NSViewController <NSTextStorageDelegate, NSTextFieldDelegate>

+ (NSDictionary *)defaultTextAttributes;

- (instancetype)initWithTextStorage:(NSTextStorage *)textStorage;

@end
Loading

0 comments on commit 046d94d

Please sign in to comment.