root / cocoa.m @ 71be0fc3
History | View | Annotate | Download (17 kB)
1 |
/* |
---|---|
2 |
* QEMU Cocoa display driver |
3 |
* |
4 |
* Copyright (c) 2005 Pierre d'Herbemont |
5 |
* many code/inspiration from SDL 1.2 code (LGPL) |
6 |
* |
7 |
* Permission is hereby granted, free of charge, to any person obtaining a copy |
8 |
* of this software and associated documentation files (the "Software"), to deal |
9 |
* in the Software without restriction, including without limitation the rights |
10 |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
11 |
* copies of the Software, and to permit persons to whom the Software is |
12 |
* furnished to do so, subject to the following conditions: |
13 |
* |
14 |
* The above copyright notice and this permission notice shall be included in |
15 |
* all copies or substantial portions of the Software. |
16 |
* |
17 |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
18 |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
19 |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
20 |
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
21 |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
22 |
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
23 |
* THE SOFTWARE. |
24 |
*/ |
25 |
/* |
26 |
Todo : x miniaturize window |
27 |
x center the window |
28 |
- save window position |
29 |
- handle keyboard event |
30 |
- handle mouse event |
31 |
- non 32 bpp support |
32 |
- full screen |
33 |
- mouse focus |
34 |
x simple graphical prompt to demo |
35 |
- better graphical prompt |
36 |
*/ |
37 |
|
38 |
#import <Cocoa/Cocoa.h> |
39 |
|
40 |
#include "vl.h" |
41 |
|
42 |
NSWindow *window = NULL; |
43 |
NSQuickDrawView *qd_view = NULL; |
44 |
|
45 |
|
46 |
int gArgc; |
47 |
char **gArgv; |
48 |
DisplayState current_ds; |
49 |
|
50 |
/* main defined in qemu/vl.c */ |
51 |
int qemu_main(int argc, char **argv); |
52 |
|
53 |
/* To deal with miniaturization */ |
54 |
@interface QemuWindow : NSWindow |
55 |
{ } |
56 |
@end |
57 |
|
58 |
|
59 |
/* |
60 |
------------------------------------------------------ |
61 |
Qemu Video Driver |
62 |
------------------------------------------------------ |
63 |
*/ |
64 |
|
65 |
/* |
66 |
------------------------------------------------------ |
67 |
cocoa_update |
68 |
------------------------------------------------------ |
69 |
*/ |
70 |
static void cocoa_update(DisplayState *ds, int x, int y, int w, int h) |
71 |
{ |
72 |
//printf("updating x=%d y=%d w=%d h=%d\n", x, y, w, h); |
73 |
|
74 |
/* Use QDFlushPortBuffer() to flush content to display */ |
75 |
RgnHandle dirty = NewRgn (); |
76 |
RgnHandle temp = NewRgn (); |
77 |
|
78 |
SetEmptyRgn (dirty); |
79 |
|
80 |
/* Build the region of dirty rectangles */ |
81 |
MacSetRectRgn (temp, x, y, |
82 |
x + w, y + h); |
83 |
MacUnionRgn (dirty, temp, dirty); |
84 |
|
85 |
/* Flush the dirty region */ |
86 |
QDFlushPortBuffer ( [ qd_view qdPort ], dirty ); |
87 |
DisposeRgn (dirty); |
88 |
DisposeRgn (temp); |
89 |
} |
90 |
|
91 |
/* |
92 |
------------------------------------------------------ |
93 |
cocoa_resize |
94 |
------------------------------------------------------ |
95 |
*/ |
96 |
static void cocoa_resize(DisplayState *ds, int w, int h) |
97 |
{ |
98 |
const int device_bpp = 32; |
99 |
static void *screen_pixels; |
100 |
static int screen_pitch; |
101 |
NSRect contentRect; |
102 |
|
103 |
//printf("resizing to %d %d\n", w, h); |
104 |
|
105 |
contentRect = NSMakeRect (0, 0, w, h); |
106 |
if(window) |
107 |
{ |
108 |
[window close]; |
109 |
[window release]; |
110 |
} |
111 |
window = [ [ QemuWindow alloc ] initWithContentRect:contentRect |
112 |
styleMask:NSTitledWindowMask|NSMiniaturizableWindowMask|NSClosableWindowMask |
113 |
backing:NSBackingStoreBuffered defer:NO]; |
114 |
if(!window) |
115 |
{ |
116 |
fprintf(stderr, "(cocoa) can't create window\n"); |
117 |
exit(1); |
118 |
} |
119 |
|
120 |
if(qd_view) |
121 |
[qd_view release]; |
122 |
|
123 |
qd_view = [ [ NSQuickDrawView alloc ] initWithFrame:contentRect ]; |
124 |
|
125 |
if(!qd_view) |
126 |
{ |
127 |
fprintf(stderr, "(cocoa) can't create qd_view\n"); |
128 |
exit(1); |
129 |
} |
130 |
|
131 |
[ window setAcceptsMouseMovedEvents:YES ]; |
132 |
[ window setTitle:@"Qemu" ]; |
133 |
[ window setReleasedWhenClosed:NO ]; |
134 |
|
135 |
/* Set screen to black */ |
136 |
[ window setBackgroundColor: [NSColor blackColor] ]; |
137 |
|
138 |
/* set window position */ |
139 |
[ window center ]; |
140 |
|
141 |
[ qd_view setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable ]; |
142 |
[ [ window contentView ] addSubview:qd_view ]; |
143 |
[ qd_view release ]; |
144 |
[ window makeKeyAndOrderFront:nil ]; |
145 |
|
146 |
/* Careful here, the window seems to have to be onscreen to do that */ |
147 |
LockPortBits ( [ qd_view qdPort ] ); |
148 |
screen_pixels = GetPixBaseAddr ( GetPortPixMap ( [ qd_view qdPort ] ) ); |
149 |
screen_pitch = GetPixRowBytes ( GetPortPixMap ( [ qd_view qdPort ] ) ); |
150 |
UnlockPortBits ( [ qd_view qdPort ] ); |
151 |
{ |
152 |
int vOffset = [ window frame ].size.height - |
153 |
[ qd_view frame ].size.height - [ qd_view frame ].origin.y; |
154 |
|
155 |
int hOffset = [ qd_view frame ].origin.x; |
156 |
|
157 |
screen_pixels += (vOffset * screen_pitch) + hOffset * (device_bpp/8); |
158 |
} |
159 |
ds->data = screen_pixels; |
160 |
ds->linesize = screen_pitch; |
161 |
ds->depth = device_bpp; |
162 |
ds->width = w; |
163 |
ds->height = h; |
164 |
|
165 |
current_ds = *ds; |
166 |
} |
167 |
|
168 |
/* |
169 |
------------------------------------------------------ |
170 |
keymap conversion |
171 |
------------------------------------------------------ |
172 |
*/ |
173 |
|
174 |
static int keymap[] = |
175 |
{ |
176 |
30, //'a' 0x0 |
177 |
31, //'s' |
178 |
32, //'d' |
179 |
33, //'f' |
180 |
35, //'h' |
181 |
34, //'g' |
182 |
44, //'z' |
183 |
45, //'x' |
184 |
46, //'c' |
185 |
47, //'v' |
186 |
0, // 0 0x0a |
187 |
48, //'b' |
188 |
16, //'q' |
189 |
17, //'w' |
190 |
18, //'e' |
191 |
19, //'r' |
192 |
21, //'y' 0x10 |
193 |
20, //'t' |
194 |
2, //'1' |
195 |
3, //'2' |
196 |
4, //'3' |
197 |
5, //'4' |
198 |
7, //'6' |
199 |
6, //'5' |
200 |
0, //'=' |
201 |
10, //'9' |
202 |
8, //'7' 0x1A |
203 |
0, //'-' |
204 |
9, //'8' |
205 |
11, //'0' |
206 |
27, //']' |
207 |
24, //'o' |
208 |
22, //'u' 0x20 |
209 |
26, //'[' |
210 |
23, //'i' |
211 |
25, //'p' |
212 |
28, //'\n' |
213 |
38, //'l' |
214 |
36, //'j' |
215 |
40, //'"' |
216 |
37, //'k' |
217 |
39, //';' |
218 |
15, //'\t' 0x30 |
219 |
0, //' ' |
220 |
0, //'`' |
221 |
14, //'<backspace>' |
222 |
0, //'' 0x34 |
223 |
0, //'<esc>' |
224 |
0, //'<esc>' |
225 |
/* Not completed to finish see http://www.libsdl.org/cgi/cvsweb.cgi/SDL12/src/video/quartz/SDL_QuartzKeys.h?rev=1.6&content-type=text/x-cvsweb-markup */ |
226 |
}; |
227 |
|
228 |
static int cocoa_keycode_to_qemu(int keycode) |
229 |
{ |
230 |
if(sizeof(keymap) <= keycode) |
231 |
{ |
232 |
printf("(cocoa) warning unknow keycode 0x%x\n", keycode); |
233 |
return 0; |
234 |
} |
235 |
return keymap[keycode]; |
236 |
} |
237 |
|
238 |
/* |
239 |
------------------------------------------------------ |
240 |
cocoa_refresh |
241 |
------------------------------------------------------ |
242 |
*/ |
243 |
static void cocoa_refresh(DisplayState *ds) |
244 |
{ |
245 |
//printf("cocoa_refresh \n"); |
246 |
NSDate *distantPast; |
247 |
NSEvent *event; |
248 |
NSAutoreleasePool *pool; |
249 |
int grab = 1; |
250 |
|
251 |
pool = [ [ NSAutoreleasePool alloc ] init ]; |
252 |
distantPast = [ NSDate distantPast ]; |
253 |
|
254 |
if (is_active_console(vga_console)) |
255 |
vga_update_display(); |
256 |
do { |
257 |
event = [ NSApp nextEventMatchingMask:NSAnyEventMask untilDate:distantPast |
258 |
inMode: NSDefaultRunLoopMode dequeue:YES ]; |
259 |
if (event != nil) { |
260 |
switch ([event type]) { |
261 |
case NSKeyDown: |
262 |
if(grab) |
263 |
{ |
264 |
int keycode = cocoa_keycode_to_qemu([event keyCode]); |
265 |
|
266 |
if (keycode & 0x80) |
267 |
kbd_put_keycode(0xe0); |
268 |
kbd_put_keycode(keycode & 0x7f); |
269 |
} |
270 |
break; |
271 |
case NSKeyUp: |
272 |
if(grab) |
273 |
{ |
274 |
int keycode = cocoa_keycode_to_qemu([event keyCode]); |
275 |
|
276 |
if (keycode & 0x80) |
277 |
kbd_put_keycode(0xe0); |
278 |
kbd_put_keycode(keycode | 0x80); |
279 |
} |
280 |
break; |
281 |
case NSScrollWheel: |
282 |
|
283 |
case NSLeftMouseDown: |
284 |
case NSLeftMouseUp: |
285 |
|
286 |
case NSOtherMouseDown: |
287 |
case NSRightMouseDown: |
288 |
|
289 |
case NSOtherMouseUp: |
290 |
case NSRightMouseUp: |
291 |
|
292 |
case NSMouseMoved: |
293 |
case NSOtherMouseDragged: |
294 |
case NSRightMouseDragged: |
295 |
case NSLeftMouseDragged: |
296 |
|
297 |
default: [NSApp sendEvent:event]; |
298 |
} |
299 |
} |
300 |
} while(event != nil); |
301 |
} |
302 |
|
303 |
/* |
304 |
------------------------------------------------------ |
305 |
cocoa_cleanup |
306 |
------------------------------------------------------ |
307 |
*/ |
308 |
|
309 |
static void cocoa_cleanup(void) |
310 |
{ |
311 |
|
312 |
} |
313 |
|
314 |
/* |
315 |
------------------------------------------------------ |
316 |
cocoa_display_init |
317 |
------------------------------------------------------ |
318 |
*/ |
319 |
|
320 |
void cocoa_display_init(DisplayState *ds, int full_screen) |
321 |
{ |
322 |
ds->dpy_update = cocoa_update; |
323 |
ds->dpy_resize = cocoa_resize; |
324 |
ds->dpy_refresh = cocoa_refresh; |
325 |
|
326 |
cocoa_resize(ds, 640, 400); |
327 |
|
328 |
atexit(cocoa_cleanup); |
329 |
} |
330 |
|
331 |
/* |
332 |
------------------------------------------------------ |
333 |
Interface with Cocoa |
334 |
------------------------------------------------------ |
335 |
*/ |
336 |
|
337 |
|
338 |
/* |
339 |
------------------------------------------------------ |
340 |
QemuWindow |
341 |
Some trick from SDL to use miniwindow |
342 |
------------------------------------------------------ |
343 |
*/ |
344 |
static void QZ_SetPortAlphaOpaque () |
345 |
{ |
346 |
/* Assume 32 bit if( bpp == 32 )*/ |
347 |
if ( 1 ) { |
348 |
|
349 |
uint32_t *pixels = (uint32_t*) current_ds.data; |
350 |
uint32_t rowPixels = current_ds.linesize / 4; |
351 |
uint32_t i, j; |
352 |
|
353 |
for (i = 0; i < current_ds.height; i++) |
354 |
for (j = 0; j < current_ds.width; j++) { |
355 |
|
356 |
pixels[ (i * rowPixels) + j ] |= 0xFF000000; |
357 |
} |
358 |
} |
359 |
} |
360 |
|
361 |
@implementation QemuWindow |
362 |
- (void)miniaturize:(id)sender |
363 |
{ |
364 |
|
365 |
/* make the alpha channel opaque so anim won't have holes in it */ |
366 |
QZ_SetPortAlphaOpaque (); |
367 |
|
368 |
[ super miniaturize:sender ]; |
369 |
|
370 |
} |
371 |
- (void)display |
372 |
{ |
373 |
/* |
374 |
This method fires just before the window deminaturizes from the Dock. |
375 |
|
376 |
We'll save the current visible surface, let the window manager redraw any |
377 |
UI elements, and restore the SDL surface. This way, no expose event |
378 |
is required, and the deminiaturize works perfectly. |
379 |
*/ |
380 |
|
381 |
/* make sure pixels are fully opaque */ |
382 |
QZ_SetPortAlphaOpaque (); |
383 |
|
384 |
/* save current visible SDL surface */ |
385 |
[ self cacheImageInRect:[ qd_view frame ] ]; |
386 |
|
387 |
/* let the window manager redraw controls, border, etc */ |
388 |
[ super display ]; |
389 |
|
390 |
/* restore visible SDL surface */ |
391 |
[ self restoreCachedImage ]; |
392 |
} |
393 |
|
394 |
@end |
395 |
|
396 |
|
397 |
/* |
398 |
------------------------------------------------------ |
399 |
QemuCocoaGUIController |
400 |
NSApp's delegate - indeed main object |
401 |
------------------------------------------------------ |
402 |
*/ |
403 |
|
404 |
@interface QemuCocoaGUIController : NSObject |
405 |
{ |
406 |
} |
407 |
- (void)applicationDidFinishLaunching: (NSNotification *) note; |
408 |
- (void)applicationWillTerminate:(NSNotification *)aNotification; |
409 |
|
410 |
- (void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo; |
411 |
|
412 |
- (void)startEmulationWithArgc:(int)argc argv:(char**)argv; |
413 |
@end |
414 |
|
415 |
@implementation QemuCocoaGUIController |
416 |
/* Called when the internal event loop has just started running */ |
417 |
- (void)applicationDidFinishLaunching: (NSNotification *) note |
418 |
{ |
419 |
|
420 |
/* Display an open dialog box if no argument were passed or |
421 |
if qemu was launched from the finder ( the Finder passes "-psn" ) */ |
422 |
|
423 |
if( gArgc <= 1 || strncmp (gArgv[1], "-psn", 4) == 0) |
424 |
{ |
425 |
NSOpenPanel *op = [[NSOpenPanel alloc] init]; |
426 |
|
427 |
cocoa_resize(¤t_ds, 640, 400); |
428 |
|
429 |
[op setPrompt:@"Boot image"]; |
430 |
|
431 |
[op setMessage:@"Select the disk image you want to boot.\n\nHit the \"Cancel\" button to quit"]; |
432 |
|
433 |
[op beginSheetForDirectory:nil file:nil types:[NSArray arrayWithObjects:@"img",@"iso",@"dmg",@"qcow",@"cow",@"cloop",@"vmdk",nil] |
434 |
modalForWindow:window modalDelegate:self |
435 |
didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:) contextInfo:NULL]; |
436 |
} |
437 |
else |
438 |
{ |
439 |
/* or Launch Qemu, with the global args */ |
440 |
[self startEmulationWithArgc:gArgc argv:gArgv]; |
441 |
} |
442 |
} |
443 |
|
444 |
- (void)applicationWillTerminate:(NSNotification *)aNotification |
445 |
{ |
446 |
printf("Application will terminate\n"); |
447 |
qemu_system_shutdown_request(); |
448 |
/* In order to avoid a crash */ |
449 |
exit(0); |
450 |
} |
451 |
|
452 |
- (void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo |
453 |
{ |
454 |
if(returnCode == NSCancelButton) |
455 |
{ |
456 |
exit(0); |
457 |
} |
458 |
|
459 |
if(returnCode == NSOKButton) |
460 |
{ |
461 |
char *bin = "qemu"; |
462 |
char *img = (char*)[ [ sheet filename ] cString]; |
463 |
|
464 |
char **argv = (char**)malloc( sizeof(char*)*3 ); |
465 |
|
466 |
asprintf(&argv[0], "%s", bin); |
467 |
asprintf(&argv[1], "-hda"); |
468 |
asprintf(&argv[2], "%s", img); |
469 |
|
470 |
printf("Using argc %d argv %s -hda %s\n", 3, bin, img); |
471 |
|
472 |
[self startEmulationWithArgc:3 argv:(char**)argv]; |
473 |
} |
474 |
} |
475 |
|
476 |
- (void)startEmulationWithArgc:(int)argc argv:(char**)argv |
477 |
{ |
478 |
int status; |
479 |
/* Launch Qemu */ |
480 |
printf("starting qemu...\n"); |
481 |
status = qemu_main (argc, argv); |
482 |
exit(status); |
483 |
} |
484 |
@end |
485 |
|
486 |
/* |
487 |
------------------------------------------------------ |
488 |
Application Creation |
489 |
------------------------------------------------------ |
490 |
*/ |
491 |
|
492 |
/* Dock Connection */ |
493 |
typedef struct CPSProcessSerNum |
494 |
{ |
495 |
UInt32 lo; |
496 |
UInt32 hi; |
497 |
} CPSProcessSerNum; |
498 |
|
499 |
extern OSErr CPSGetCurrentProcess( CPSProcessSerNum *psn); |
500 |
extern OSErr CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5); |
501 |
extern OSErr CPSSetFrontProcess( CPSProcessSerNum *psn); |
502 |
|
503 |
/* Menu Creation */ |
504 |
static void setApplicationMenu(void) |
505 |
{ |
506 |
/* warning: this code is very odd */ |
507 |
NSMenu *appleMenu; |
508 |
NSMenuItem *menuItem; |
509 |
NSString *title; |
510 |
NSString *appName; |
511 |
|
512 |
appName = @"Qemu"; |
513 |
appleMenu = [[NSMenu alloc] initWithTitle:@""]; |
514 |
|
515 |
/* Add menu items */ |
516 |
title = [@"About " stringByAppendingString:appName]; |
517 |
[appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""]; |
518 |
|
519 |
[appleMenu addItem:[NSMenuItem separatorItem]]; |
520 |
|
521 |
title = [@"Hide " stringByAppendingString:appName]; |
522 |
[appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"]; |
523 |
|
524 |
menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"]; |
525 |
[menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)]; |
526 |
|
527 |
[appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""]; |
528 |
|
529 |
[appleMenu addItem:[NSMenuItem separatorItem]]; |
530 |
|
531 |
title = [@"Quit " stringByAppendingString:appName]; |
532 |
[appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"]; |
533 |
|
534 |
|
535 |
/* Put menu into the menubar */ |
536 |
menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""]; |
537 |
[menuItem setSubmenu:appleMenu]; |
538 |
[[NSApp mainMenu] addItem:menuItem]; |
539 |
|
540 |
/* Tell the application object that this is now the application menu */ |
541 |
[NSApp setAppleMenu:appleMenu]; |
542 |
|
543 |
/* Finally give up our references to the objects */ |
544 |
[appleMenu release]; |
545 |
[menuItem release]; |
546 |
} |
547 |
|
548 |
/* Create a window menu */ |
549 |
static void setupWindowMenu(void) |
550 |
{ |
551 |
NSMenu *windowMenu; |
552 |
NSMenuItem *windowMenuItem; |
553 |
NSMenuItem *menuItem; |
554 |
|
555 |
windowMenu = [[NSMenu alloc] initWithTitle:@"Window"]; |
556 |
|
557 |
/* "Minimize" item */ |
558 |
menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"]; |
559 |
[windowMenu addItem:menuItem]; |
560 |
[menuItem release]; |
561 |
|
562 |
/* Put menu into the menubar */ |
563 |
windowMenuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""]; |
564 |
[windowMenuItem setSubmenu:windowMenu]; |
565 |
[[NSApp mainMenu] addItem:windowMenuItem]; |
566 |
|
567 |
/* Tell the application object that this is now the window menu */ |
568 |
[NSApp setWindowsMenu:windowMenu]; |
569 |
|
570 |
/* Finally give up our references to the objects */ |
571 |
[windowMenu release]; |
572 |
[windowMenuItem release]; |
573 |
|
574 |
} |
575 |
|
576 |
static void CustomApplicationMain (argc, argv) |
577 |
{ |
578 |
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; |
579 |
QemuCocoaGUIController *gui_controller; |
580 |
CPSProcessSerNum PSN; |
581 |
|
582 |
[NSApplication sharedApplication]; |
583 |
|
584 |
if (!CPSGetCurrentProcess(&PSN)) |
585 |
if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103)) |
586 |
if (!CPSSetFrontProcess(&PSN)) |
587 |
[NSApplication sharedApplication]; |
588 |
|
589 |
/* Set up the menubar */ |
590 |
[NSApp setMainMenu:[[NSMenu alloc] init]]; |
591 |
setApplicationMenu(); |
592 |
setupWindowMenu(); |
593 |
|
594 |
/* Create SDLMain and make it the app delegate */ |
595 |
gui_controller = [[QemuCocoaGUIController alloc] init]; |
596 |
[NSApp setDelegate:gui_controller]; |
597 |
|
598 |
/* Start the main event loop */ |
599 |
[NSApp run]; |
600 |
|
601 |
[gui_controller release]; |
602 |
[pool release]; |
603 |
} |
604 |
|
605 |
/* Real main of qemu-cocoa */ |
606 |
int main(int argc, char **argv) |
607 |
{ |
608 |
gArgc = argc; |
609 |
gArgv = argv; |
610 |
|
611 |
CustomApplicationMain (argc, argv); |
612 |
|
613 |
return 0; |
614 |
} |