4 * Core Cocoa-based user interface
6 * Copyright (c) 2005 Nathan Keynes.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
19 #include <AppKit/AppKit.h>
24 #include "dreamcast.h"
27 #include "cocoaui/cocoaui.h"
29 void cocoa_gui_update( void );
30 void cocoa_gui_start( void );
31 void cocoa_gui_stop( void );
32 void cocoa_gui_run_later( void );
33 uint32_t cocoa_gui_run_slice( uint32_t nanosecs );
35 struct dreamcast_module cocoa_gui_module = { "gui", NULL,
43 * Count of running nanoseconds - used to cut back on the GUI runtime
45 static uint32_t cocoa_gui_nanos = 0;
46 static uint32_t cocoa_gui_ticks = 0;
47 static struct timeval cocoa_gui_lasttv;
48 static BOOL cocoa_gui_autorun = NO;
50 @interface NSApplication (PrivateAdditions)
51 - (void) setAppleMenu:(NSMenu *)aMenu;
54 static void cocoa_gui_create_menu(void)
56 NSMenu *appleMenu, *services;
62 appleMenu = [[NSMenu alloc] initWithTitle:@""];
65 title = [@"About " stringByAppendingString:appName];
66 [appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""];
67 [appleMenu addItem:[NSMenuItem separatorItem]];
70 services = [[[NSMenu alloc] init] autorelease];
71 [appleMenu addItemWithTitle:@"Services" action:nil keyEquivalent:@""];
72 [appleMenu setSubmenu: services forItem: [appleMenu itemWithTitle: @"Services"]];
75 title = [@"Hide " stringByAppendingString:appName];
76 [appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"];
79 menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others"
80 action:@selector(hideOtherApplications:)
82 [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)];
85 [appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""];
86 [appleMenu addItem:[NSMenuItem separatorItem]];
89 title = [@"Quit " stringByAppendingString:appName];
90 [appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"];
92 /* Put menu into the menubar */
93 menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""];
94 [menuItem setSubmenu: appleMenu];
95 NSMenu *menu = [NSMenu new];
96 [menu addItem: menuItem];
98 NSMenu *fileMenu = [[NSMenu alloc] initWithTitle: NS_("File")];
99 [fileMenu addItemWithTitle: NS_("Load Binary") action: @selector(load_binary_action:) keyEquivalent: @"b"];
100 [fileMenu addItemWithTitle: NS_("GD-Rom") action: @selector(mount_action:) keyEquivalent: @"g"];
101 [fileMenu addItem: [NSMenuItem separatorItem]];
102 [[fileMenu addItemWithTitle: NS_("Reset") action: @selector(reset_action:) keyEquivalent: @"r"]
103 setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)];
104 [fileMenu addItemWithTitle: NS_("Pause") action: @selector(pause_action:) keyEquivalent: @"p"];
105 [fileMenu addItemWithTitle: NS_("Resume") action: @selector(run_action:) keyEquivalent: @"r"];
106 [fileMenu addItem: [NSMenuItem separatorItem]];
107 [fileMenu addItemWithTitle: NS_("Load State") action: @selector(load_action:) keyEquivalent: @"o"];
108 [fileMenu addItemWithTitle: NS_("Save State") action: @selector(save_action:) keyEquivalent: @"s"];
110 menuItem = [[NSMenuItem alloc] initWithTitle:NS_("File") action: nil keyEquivalent: @""];
111 [menuItem setSubmenu: fileMenu];
112 [menu addItem: menuItem];
114 /* Tell the application object that this is now the application menu */
115 [NSApp setMainMenu: menu];
116 [NSApp setAppleMenu: appleMenu];
117 [NSApp setServicesMenu: services];
119 /* Finally give up our references to the objects */
125 @interface LxdreamDelegate : NSObject
128 @implementation LxdreamDelegate
129 - (void)windowWillClose: (NSNotification *)notice
131 dreamcast_shutdown();
134 - (void)windowDidBecomeMain: (NSNotification *)notice
136 if( cocoa_gui_autorun ) {
137 cocoa_gui_autorun = NO;
138 cocoa_gui_run_later();
141 - (void) load_action: (id)sender
143 NSOpenPanel *panel = [NSOpenPanel openPanel];
144 NSArray *fileTypes = [NSArray arrayWithObject: @"dst"];
145 int result = [panel runModalForDirectory: NSHomeDirectory() file: nil types: fileTypes];
146 if( result == NSOKButton && [[panel filenames] count] > 0 ) {
147 NSString *filename = [[panel filenames] objectAtIndex: 0];
148 dreamcast_load_state( [filename UTF8String] );
151 - (void) save_action: (id)sender
153 NSSavePanel *panel = [NSSavePanel savePanel];
154 [panel setRequiredFileType: @"dst"];
155 int result = [panel runModalForDirectory: NSHomeDirectory() file:@""];
156 if( result == NSOKButton ) {
157 NSString *filename = [panel filename];
158 dreamcast_save_state( [filename UTF8String] );
161 - (void) load_binary_action: (id)sender
163 NSOpenPanel *panel = [NSOpenPanel openPanel];
164 int result = [panel runModalForDirectory: NSHomeDirectory() file: nil types: nil];
165 if( result == NSOKButton && [[panel filenames] count] > 0 ) {
166 NSString *filename = [[panel filenames] objectAtIndex: 0];
167 file_load_magic( [filename UTF8String] );
170 - (void) mount_action: (id)sender
172 NSOpenPanel *panel = [NSOpenPanel openPanel];
173 int result = [panel runModalForDirectory: NSHomeDirectory() file: nil types: nil];
174 if( result == NSOKButton && [[panel filenames] count] > 0 ) {
175 NSString *filename = [[panel filenames] objectAtIndex: 0];
176 gdrom_mount_image( [filename UTF8String] );
179 - (void) pause_action: (id)sender
184 - (void) reset_action: (id)sender
188 - (void) run_action: (id)sender
190 cocoa_gui_run_later();
192 - (void) run_immediate
199 gboolean gui_parse_cmdline( int *argc, char **argv[] )
204 gboolean gui_init( gboolean withDebug )
206 dreamcast_register_module( &cocoa_gui_module );
208 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
209 [NSApplication sharedApplication];
210 LxdreamDelegate *delegate = [[LxdreamDelegate alloc] init];
211 [NSApp setDelegate: delegate];
212 cocoa_gui_create_menu();
213 NSWindow *window = cocoa_gui_create_main_window();
214 [window makeKeyAndOrderFront: nil];
215 [NSApp activateIgnoringOtherApps: YES];
219 void gui_main_loop( gboolean run )
222 cocoa_gui_autorun = YES;
229 void gui_update_state(void)
234 gboolean gui_error_dialog( const char *msg, ... )
239 void gui_update_io_activity( io_activity_type io, gboolean active )
245 uint32_t cocoa_gui_run_slice( uint32_t nanosecs )
248 NSAutoreleasePool *pool;
250 cocoa_gui_nanos += nanosecs;
251 if( cocoa_gui_nanos > GUI_TICK_PERIOD ) { /* 10 ms */
252 cocoa_gui_nanos -= GUI_TICK_PERIOD;
254 uint32_t current_period = cocoa_gui_ticks * GUI_TICK_PERIOD;
256 // Run the event loop
257 pool = [NSAutoreleasePool new];
258 while( (event = [NSApp nextEventMatchingMask: NSAnyEventMask untilDate: nil
259 inMode: NSDefaultRunLoopMode dequeue: YES]) != nil ) {
260 [NSApp sendEvent: event];
265 gettimeofday(&tv,NULL);
266 uint32_t ns = ((tv.tv_sec - cocoa_gui_lasttv.tv_sec) * 1000000000) +
267 (tv.tv_usec - cocoa_gui_lasttv.tv_usec)*1000;
268 if( (ns * 1.05) < current_period ) {
269 // We've gotten ahead - sleep for a little bit
272 tv.tv_nsec = current_period - ns;
276 /* Update the display every 10 ticks (ie 10 times a second) and
277 * save the current tv value */
278 if( cocoa_gui_ticks > 10 ) {
280 cocoa_gui_ticks -= 10;
282 double speed = (float)( (double)current_period * 100.0 / ns );
283 cocoa_gui_lasttv.tv_sec = tv.tv_sec;
284 cocoa_gui_lasttv.tv_usec = tv.tv_usec;
285 snprintf( buf, 32, _("Running (%2.4f%%)"), speed );
286 [((LxdreamMainWindow *)[NSApp mainWindow]) setStatusText: buf];
293 void cocoa_gui_update( void )
298 void cocoa_gui_start( void )
300 LxdreamMainWindow *win = (LxdreamMainWindow *)[NSApp mainWindow];
301 [win setRunning: YES];
303 gettimeofday(&cocoa_gui_lasttv,NULL);
306 void cocoa_gui_stop( void )
308 LxdreamMainWindow *win = (LxdreamMainWindow *)[NSApp mainWindow];
309 [win setRunning: NO];
313 * Queue a dreamcast_run() to execute after the currently event(s)
315 void cocoa_gui_run_later( void )
317 [[NSRunLoop currentRunLoop] performSelector: @selector(run_immediate)
318 target: [NSApp delegate] argument: nil order: 1
319 modes: [NSArray arrayWithObject: NSDefaultRunLoopMode] ];
.