Search
lxdream.org :: lxdream/src/cocoaui/cocoaui.c :: diff
lxdream 0.9.1
released Jun 29
Download Now
filename src/cocoaui/cocoaui.c
changeset 681:1755a126b109
next685:fa1589b42be7
author nkeynes
date Sun Jun 01 00:47:45 2008 +0000 (15 years ago)
permissions -rw-r--r--
last change First cut of the Cocoa GUI implementation
file annotate diff log raw
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/src/cocoaui/cocoaui.c Sun Jun 01 00:47:45 2008 +0000
1.3 @@ -0,0 +1,320 @@
1.4 +/**
1.5 + * $Id$
1.6 + *
1.7 + * Core Cocoa-based user interface
1.8 + *
1.9 + * Copyright (c) 2005 Nathan Keynes.
1.10 + *
1.11 + * This program is free software; you can redistribute it and/or modify
1.12 + * it under the terms of the GNU General Public License as published by
1.13 + * the Free Software Foundation; either version 2 of the License, or
1.14 + * (at your option) any later version.
1.15 + *
1.16 + * This program is distributed in the hope that it will be useful,
1.17 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.18 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.19 + * GNU General Public License for more details.
1.20 + */
1.21 +
1.22 +#include <AppKit/AppKit.h>
1.23 +#include <stdio.h>
1.24 +#include <stdlib.h>
1.25 +#include <sys/time.h>
1.26 +#include "lxdream.h"
1.27 +#include "dreamcast.h"
1.28 +#include "dream.h"
1.29 +#include "gui.h"
1.30 +#include "cocoaui/cocoaui.h"
1.31 +
1.32 +void cocoa_gui_update( void );
1.33 +void cocoa_gui_start( void );
1.34 +void cocoa_gui_stop( void );
1.35 +void cocoa_gui_run_later( void );
1.36 +uint32_t cocoa_gui_run_slice( uint32_t nanosecs );
1.37 +
1.38 +struct dreamcast_module cocoa_gui_module = { "gui", NULL,
1.39 + cocoa_gui_update,
1.40 + cocoa_gui_start,
1.41 + cocoa_gui_run_slice,
1.42 + cocoa_gui_stop,
1.43 + NULL, NULL };
1.44 +
1.45 +/**
1.46 + * Count of running nanoseconds - used to cut back on the GUI runtime
1.47 + */
1.48 +static uint32_t cocoa_gui_nanos = 0;
1.49 +static uint32_t cocoa_gui_ticks = 0;
1.50 +static struct timeval cocoa_gui_lasttv;
1.51 +static BOOL cocoa_gui_autorun = NO;
1.52 +
1.53 +@interface NSApplication (PrivateAdditions)
1.54 +- (void) setAppleMenu:(NSMenu *)aMenu;
1.55 +@end
1.56 +
1.57 +static void cocoa_gui_create_menu(void)
1.58 +{
1.59 + NSMenu *appleMenu, *services;
1.60 + NSMenuItem *menuItem;
1.61 + NSString *title;
1.62 + NSString *appName;
1.63 +
1.64 + appName = @"Lxdream";
1.65 + appleMenu = [[NSMenu alloc] initWithTitle:@""];
1.66 +
1.67 + /* Add menu items */
1.68 + title = [@"About " stringByAppendingString:appName];
1.69 + [appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""];
1.70 + [appleMenu addItem:[NSMenuItem separatorItem]];
1.71 +
1.72 + // Services Menu
1.73 + services = [[[NSMenu alloc] init] autorelease];
1.74 + [appleMenu addItemWithTitle:@"Services" action:nil keyEquivalent:@""];
1.75 + [appleMenu setSubmenu: services forItem: [appleMenu itemWithTitle: @"Services"]];
1.76 +
1.77 + // Hide AppName
1.78 + title = [@"Hide " stringByAppendingString:appName];
1.79 + [appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"];
1.80 +
1.81 + // Hide Others
1.82 + menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others"
1.83 + action:@selector(hideOtherApplications:)
1.84 + keyEquivalent:@"h"];
1.85 + [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)];
1.86 +
1.87 + // Show All
1.88 + [appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""];
1.89 + [appleMenu addItem:[NSMenuItem separatorItem]];
1.90 +
1.91 + // Quit AppName
1.92 + title = [@"Quit " stringByAppendingString:appName];
1.93 + [appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"];
1.94 +
1.95 + /* Put menu into the menubar */
1.96 + menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""];
1.97 + [menuItem setSubmenu: appleMenu];
1.98 + NSMenu *menu = [NSMenu new];
1.99 + [menu addItem: menuItem];
1.100 +
1.101 + NSMenu *fileMenu = [[NSMenu alloc] initWithTitle: NS_("File")];
1.102 + [fileMenu addItemWithTitle: NS_("Load Binary") action: @selector(load_binary_action:) keyEquivalent: @"b"];
1.103 + [fileMenu addItemWithTitle: NS_("GD-Rom") action: @selector(mount_action:) keyEquivalent: @"g"];
1.104 + [fileMenu addItem: [NSMenuItem separatorItem]];
1.105 + [[fileMenu addItemWithTitle: NS_("Reset") action: @selector(reset_action:) keyEquivalent: @"r"]
1.106 + setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)];
1.107 + [fileMenu addItemWithTitle: NS_("Pause") action: @selector(pause_action:) keyEquivalent: @"p"];
1.108 + [fileMenu addItemWithTitle: NS_("Resume") action: @selector(run_action:) keyEquivalent: @"r"];
1.109 + [fileMenu addItem: [NSMenuItem separatorItem]];
1.110 + [fileMenu addItemWithTitle: NS_("Load State") action: @selector(load_action:) keyEquivalent: @"o"];
1.111 + [fileMenu addItemWithTitle: NS_("Save State") action: @selector(save_action:) keyEquivalent: @"s"];
1.112 +
1.113 + menuItem = [[NSMenuItem alloc] initWithTitle:NS_("File") action: nil keyEquivalent: @""];
1.114 + [menuItem setSubmenu: fileMenu];
1.115 + [menu addItem: menuItem];
1.116 +
1.117 + /* Tell the application object that this is now the application menu */
1.118 + [NSApp setMainMenu: menu];
1.119 + [NSApp setAppleMenu: appleMenu];
1.120 + [NSApp setServicesMenu: services];
1.121 +
1.122 + /* Finally give up our references to the objects */
1.123 + [appleMenu release];
1.124 + [menuItem release];
1.125 + [menu release];
1.126 +}
1.127 +
1.128 +@interface LxdreamDelegate : NSObject
1.129 +@end
1.130 +
1.131 +@implementation LxdreamDelegate
1.132 +- (void)windowWillClose: (NSNotification *)notice
1.133 +{
1.134 + dreamcast_shutdown();
1.135 + exit(0);
1.136 +}
1.137 +- (void)windowDidBecomeMain: (NSNotification *)notice
1.138 +{
1.139 + if( cocoa_gui_autorun ) {
1.140 + cocoa_gui_autorun = NO;
1.141 + cocoa_gui_run_later();
1.142 + }
1.143 +}
1.144 +- (void) load_action: (id)sender
1.145 +{
1.146 + NSOpenPanel *panel = [NSOpenPanel openPanel];
1.147 + NSArray *fileTypes = [NSArray arrayWithObject: @"dst"];
1.148 + int result = [panel runModalForDirectory: NSHomeDirectory() file: nil types: fileTypes];
1.149 + if( result == NSOKButton && [[panel filenames] count] > 0 ) {
1.150 + NSString *filename = [[panel filenames] objectAtIndex: 0];
1.151 + dreamcast_load_state( [filename UTF8String] );
1.152 + }
1.153 +}
1.154 +- (void) save_action: (id)sender
1.155 +{
1.156 + NSSavePanel *panel = [NSSavePanel savePanel];
1.157 + [panel setRequiredFileType: @"dst"];
1.158 + int result = [panel runModalForDirectory: NSHomeDirectory() file:@""];
1.159 + if( result == NSOKButton ) {
1.160 + NSString *filename = [panel filename];
1.161 + dreamcast_save_state( [filename UTF8String] );
1.162 + }
1.163 +}
1.164 +- (void) load_binary_action: (id)sender
1.165 +{
1.166 + NSOpenPanel *panel = [NSOpenPanel openPanel];
1.167 + int result = [panel runModalForDirectory: NSHomeDirectory() file: nil types: nil];
1.168 + if( result == NSOKButton && [[panel filenames] count] > 0 ) {
1.169 + NSString *filename = [[panel filenames] objectAtIndex: 0];
1.170 + file_load_magic( [filename UTF8String] );
1.171 + }
1.172 +}
1.173 +- (void) mount_action: (id)sender
1.174 +{
1.175 + NSOpenPanel *panel = [NSOpenPanel openPanel];
1.176 + int result = [panel runModalForDirectory: NSHomeDirectory() file: nil types: nil];
1.177 + if( result == NSOKButton && [[panel filenames] count] > 0 ) {
1.178 + NSString *filename = [[panel filenames] objectAtIndex: 0];
1.179 + gdrom_mount_image( [filename UTF8String] );
1.180 + }
1.181 +}
1.182 +- (void) pause_action: (id)sender
1.183 +{
1.184 + dreamcast_stop();
1.185 +}
1.186 +
1.187 +- (void) reset_action: (id)sender
1.188 +{
1.189 + dreamcast_reset();
1.190 +}
1.191 +- (void) run_action: (id)sender
1.192 +{
1.193 + cocoa_gui_run_later();
1.194 +}
1.195 +- (void) run_immediate
1.196 +{
1.197 + dreamcast_run();
1.198 +}
1.199 +@end
1.200 +
1.201 +
1.202 +gboolean gui_parse_cmdline( int *argc, char **argv[] )
1.203 +{
1.204 + /* do nothing */
1.205 +}
1.206 +
1.207 +gboolean gui_init( gboolean withDebug )
1.208 +{
1.209 + dreamcast_register_module( &cocoa_gui_module );
1.210 +
1.211 + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1.212 + [NSApplication sharedApplication];
1.213 + LxdreamDelegate *delegate = [[LxdreamDelegate alloc] init];
1.214 + [NSApp setDelegate: delegate];
1.215 + cocoa_gui_create_menu();
1.216 + NSWindow *window = cocoa_gui_create_main_window();
1.217 + [window makeKeyAndOrderFront: nil];
1.218 + [NSApp activateIgnoringOtherApps: YES];
1.219 + [pool release];
1.220 +}
1.221 +
1.222 +void gui_main_loop( gboolean run )
1.223 +{
1.224 + if( run ) {
1.225 + cocoa_gui_autorun = YES;
1.226 + /*
1.227 + */
1.228 + }
1.229 + [NSApp run];
1.230 +}
1.231 +
1.232 +void gui_update_state(void)
1.233 +{
1.234 + cocoa_gui_update();
1.235 +}
1.236 +
1.237 +gboolean gui_error_dialog( const char *msg, ... )
1.238 +{
1.239 +
1.240 +}
1.241 +
1.242 +void gui_update_io_activity( io_activity_type io, gboolean active )
1.243 +{
1.244 +
1.245 +}
1.246 +
1.247 +
1.248 +uint32_t cocoa_gui_run_slice( uint32_t nanosecs )
1.249 +{
1.250 + NSEvent *event;
1.251 + NSAutoreleasePool *pool;
1.252 +
1.253 + cocoa_gui_nanos += nanosecs;
1.254 + if( cocoa_gui_nanos > GUI_TICK_PERIOD ) { /* 10 ms */
1.255 + cocoa_gui_nanos -= GUI_TICK_PERIOD;
1.256 + cocoa_gui_ticks ++;
1.257 + uint32_t current_period = cocoa_gui_ticks * GUI_TICK_PERIOD;
1.258 +
1.259 + // Run the event loop
1.260 + pool = [NSAutoreleasePool new];
1.261 + while( (event = [NSApp nextEventMatchingMask: NSAnyEventMask untilDate: nil
1.262 + inMode: NSDefaultRunLoopMode dequeue: YES]) != nil ) {
1.263 + [NSApp sendEvent: event];
1.264 + }
1.265 + [pool release];
1.266 +
1.267 + struct timeval tv;
1.268 + gettimeofday(&tv,NULL);
1.269 + uint32_t ns = ((tv.tv_sec - cocoa_gui_lasttv.tv_sec) * 1000000000) +
1.270 + (tv.tv_usec - cocoa_gui_lasttv.tv_usec)*1000;
1.271 + if( (ns * 1.05) < current_period ) {
1.272 + // We've gotten ahead - sleep for a little bit
1.273 + struct timespec tv;
1.274 + tv.tv_sec = 0;
1.275 + tv.tv_nsec = current_period - ns;
1.276 + nanosleep(&tv, &tv);
1.277 + }
1.278 +
1.279 + /* Update the display every 10 ticks (ie 10 times a second) and
1.280 + * save the current tv value */
1.281 + if( cocoa_gui_ticks > 10 ) {
1.282 + gchar buf[32];
1.283 + cocoa_gui_ticks -= 10;
1.284 +
1.285 + double speed = (float)( (double)current_period * 100.0 / ns );
1.286 + cocoa_gui_lasttv.tv_sec = tv.tv_sec;
1.287 + cocoa_gui_lasttv.tv_usec = tv.tv_usec;
1.288 + snprintf( buf, 32, _("Running (%2.4f%%)"), speed );
1.289 + [((LxdreamMainWindow *)[NSApp mainWindow]) setStatusText: buf];
1.290 +
1.291 + }
1.292 + }
1.293 + return nanosecs;
1.294 +}
1.295 +
1.296 +void cocoa_gui_update( void )
1.297 +{
1.298 +
1.299 +}
1.300 +
1.301 +void cocoa_gui_start( void )
1.302 +{
1.303 + LxdreamMainWindow *win = (LxdreamMainWindow *)[NSApp mainWindow];
1.304 + [win setRunning: YES];
1.305 + cocoa_gui_nanos = 0;
1.306 + gettimeofday(&cocoa_gui_lasttv,NULL);
1.307 +}
1.308 +
1.309 +void cocoa_gui_stop( void )
1.310 +{
1.311 + LxdreamMainWindow *win = (LxdreamMainWindow *)[NSApp mainWindow];
1.312 + [win setRunning: NO];
1.313 +}
1.314 +
1.315 +/**
1.316 + * Queue a dreamcast_run() to execute after the currently event(s)
1.317 + */
1.318 +void cocoa_gui_run_later( void )
1.319 +{
1.320 + [[NSRunLoop currentRunLoop] performSelector: @selector(run_immediate)
1.321 + target: [NSApp delegate] argument: nil order: 1
1.322 + modes: [NSArray arrayWithObject: NSDefaultRunLoopMode] ];
1.323 +}
1.324 \ No newline at end of file
.