Commit 5b0753e0d8dfca5a33edcd3cc1306bb5d0594005
1 parent
157777ef
initial Cocoa support (Pierre d'Herbemont)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1313 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
4 changed files
with
634 additions
and
2 deletions
Makefile.target
... | ... | @@ -346,6 +346,10 @@ endif |
346 | 346 | ifdef CONFIG_SDL |
347 | 347 | VL_OBJS+=sdl.o |
348 | 348 | endif |
349 | +ifdef CONFIG_COCOA | |
350 | +VL_OBJS+=cocoa.o | |
351 | +COCOA_LIBS=-F/System/Library/Frameworks -framework Cocoa | |
352 | +endif | |
349 | 353 | ifdef CONFIG_SLIRP |
350 | 354 | DEFINES+=-I$(SRC_PATH)/slirp |
351 | 355 | SLIRP_OBJS=cksum.o if.o ip_icmp.o ip_input.o ip_output.o \ |
... | ... | @@ -373,7 +377,10 @@ VL_LDFLAGS+=-p |
373 | 377 | endif |
374 | 378 | |
375 | 379 | $(QEMU_SYSTEM): $(VL_OBJS) libqemu.a |
376 | - $(CC) $(VL_LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) $(VL_LIBS) | |
380 | + $(CC) $(VL_LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) $(COCOA_LIBS) $(VL_LIBS) | |
381 | + | |
382 | +cocoa.o: cocoa.m | |
383 | + $(CC) $(CFLAGS) $(DEFINES) -c -o $@ $< | |
377 | 384 | |
378 | 385 | sdl.o: sdl.c keymaps.c sdl_keysym.h |
379 | 386 | $(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $< | ... | ... |
cocoa.m
0 → 100644
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 | +#include "vl.h" | |
38 | +#import <Cocoa/Cocoa.h> | |
39 | + | |
40 | +NSWindow *window = NULL; | |
41 | +NSQuickDrawView *qd_view = NULL; | |
42 | + | |
43 | + | |
44 | +int gArgc; | |
45 | +char **gArgv; | |
46 | +DisplayState current_ds; | |
47 | + | |
48 | +/* main defined in qemu/vl.c */ | |
49 | +int qemu_main(int argc, char **argv); | |
50 | + | |
51 | +/* To deal with miniaturization */ | |
52 | +@interface QemuWindow : NSWindow | |
53 | +{ } | |
54 | +@end | |
55 | + | |
56 | + | |
57 | +/* | |
58 | + ------------------------------------------------------ | |
59 | + Qemu Video Driver | |
60 | + ------------------------------------------------------ | |
61 | +*/ | |
62 | + | |
63 | +/* | |
64 | + ------------------------------------------------------ | |
65 | + cocoa_update | |
66 | + ------------------------------------------------------ | |
67 | +*/ | |
68 | +static void cocoa_update(DisplayState *ds, int x, int y, int w, int h) | |
69 | +{ | |
70 | + //printf("updating x=%d y=%d w=%d h=%d\n", x, y, w, h); | |
71 | + | |
72 | + /* Use QDFlushPortBuffer() to flush content to display */ | |
73 | + RgnHandle dirty = NewRgn (); | |
74 | + RgnHandle temp = NewRgn (); | |
75 | + | |
76 | + SetEmptyRgn (dirty); | |
77 | + | |
78 | + /* Build the region of dirty rectangles */ | |
79 | + MacSetRectRgn (temp, x, y, | |
80 | + x + w, y + h); | |
81 | + MacUnionRgn (dirty, temp, dirty); | |
82 | + | |
83 | + /* Flush the dirty region */ | |
84 | + QDFlushPortBuffer ( [ qd_view qdPort ], dirty ); | |
85 | + DisposeRgn (dirty); | |
86 | + DisposeRgn (temp); | |
87 | +} | |
88 | + | |
89 | +/* | |
90 | + ------------------------------------------------------ | |
91 | + cocoa_resize | |
92 | + ------------------------------------------------------ | |
93 | +*/ | |
94 | +static void cocoa_resize(DisplayState *ds, int w, int h) | |
95 | +{ | |
96 | + const int device_bpp = 32; | |
97 | + static void *screen_pixels; | |
98 | + static int screen_pitch; | |
99 | + NSRect contentRect; | |
100 | + | |
101 | + //printf("resizing to %d %d\n", w, h); | |
102 | + | |
103 | + contentRect = NSMakeRect (0, 0, w, h); | |
104 | + if(window) | |
105 | + { | |
106 | + [window close]; | |
107 | + [window release]; | |
108 | + } | |
109 | + window = [ [ QemuWindow alloc ] initWithContentRect:contentRect | |
110 | + styleMask:NSTitledWindowMask|NSMiniaturizableWindowMask|NSClosableWindowMask | |
111 | + backing:NSBackingStoreBuffered defer:NO]; | |
112 | + if(!window) | |
113 | + { | |
114 | + fprintf(stderr, "(cocoa) can't create window\n"); | |
115 | + exit(1); | |
116 | + } | |
117 | + | |
118 | + if(qd_view) | |
119 | + [qd_view release]; | |
120 | + | |
121 | + qd_view = [ [ NSQuickDrawView alloc ] initWithFrame:contentRect ]; | |
122 | + | |
123 | + if(!qd_view) | |
124 | + { | |
125 | + fprintf(stderr, "(cocoa) can't create qd_view\n"); | |
126 | + exit(1); | |
127 | + } | |
128 | + | |
129 | + [ window setAcceptsMouseMovedEvents:YES ]; | |
130 | + [ window setTitle:@"Qemu" ]; | |
131 | + [ window setReleasedWhenClosed:NO ]; | |
132 | + | |
133 | + /* Set screen to black */ | |
134 | + [ window setBackgroundColor: [NSColor blackColor] ]; | |
135 | + | |
136 | + /* set window position */ | |
137 | + [ window center ]; | |
138 | + | |
139 | + [ qd_view setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable ]; | |
140 | + [ [ window contentView ] addSubview:qd_view ]; | |
141 | + [ qd_view release ]; | |
142 | + [ window makeKeyAndOrderFront:nil ]; | |
143 | + | |
144 | + /* Careful here, the window seems to have to be onscreen to do that */ | |
145 | + LockPortBits ( [ qd_view qdPort ] ); | |
146 | + screen_pixels = GetPixBaseAddr ( GetPortPixMap ( [ qd_view qdPort ] ) ); | |
147 | + screen_pitch = GetPixRowBytes ( GetPortPixMap ( [ qd_view qdPort ] ) ); | |
148 | + UnlockPortBits ( [ qd_view qdPort ] ); | |
149 | + { | |
150 | + int vOffset = [ window frame ].size.height - | |
151 | + [ qd_view frame ].size.height - [ qd_view frame ].origin.y; | |
152 | + | |
153 | + int hOffset = [ qd_view frame ].origin.x; | |
154 | + | |
155 | + screen_pixels += (vOffset * screen_pitch) + hOffset * (device_bpp/8); | |
156 | + } | |
157 | + ds->data = screen_pixels; | |
158 | + ds->linesize = screen_pitch; | |
159 | + ds->depth = device_bpp; | |
160 | + ds->width = w; | |
161 | + ds->height = h; | |
162 | + | |
163 | + current_ds = *ds; | |
164 | +} | |
165 | + | |
166 | +/* | |
167 | + ------------------------------------------------------ | |
168 | + keymap conversion | |
169 | + ------------------------------------------------------ | |
170 | +*/ | |
171 | + | |
172 | +static int keymap[] = | |
173 | +{ | |
174 | + 30, //'a' 0x0 | |
175 | + 31, //'s' | |
176 | + 32, //'d' | |
177 | + 33, //'f' | |
178 | + 35, //'h' | |
179 | + 34, //'g' | |
180 | + 44, //'z' | |
181 | + 45, //'x' | |
182 | + 46, //'c' | |
183 | + 47, //'v' | |
184 | + 0, // 0 0x0a | |
185 | + 48, //'b' | |
186 | + 16, //'q' | |
187 | + 17, //'w' | |
188 | + 18, //'e' | |
189 | + 19, //'r' | |
190 | + 21, //'y' 0x10 | |
191 | + 20, //'t' | |
192 | + 2, //'1' | |
193 | + 3, //'2' | |
194 | + 4, //'3' | |
195 | + 5, //'4' | |
196 | + 7, //'6' | |
197 | + 6, //'5' | |
198 | + 0, //'=' | |
199 | + 10, //'9' | |
200 | + 8, //'7' 0x1A | |
201 | + 0, //'-' | |
202 | + 9, //'8' | |
203 | + 11, //'0' | |
204 | + 27, //']' | |
205 | + 24, //'o' | |
206 | + 22, //'u' 0x20 | |
207 | + 26, //'[' | |
208 | + 23, //'i' | |
209 | + 25, //'p' | |
210 | + 28, //'\n' | |
211 | + 38, //'l' | |
212 | + 36, //'j' | |
213 | + 40, //'"' | |
214 | + 37, //'k' | |
215 | + 39, //';' | |
216 | + 15, //'\t' 0x30 | |
217 | + 0, //' ' | |
218 | + 0, //'`' | |
219 | + 14, //'<backspace>' | |
220 | + 0, //'' 0x34 | |
221 | + 0, //'<esc>' | |
222 | + 0, //'<esc>' | |
223 | + /* 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 */ | |
224 | +}; | |
225 | + | |
226 | +static int cocoa_keycode_to_qemu(int keycode) | |
227 | +{ | |
228 | + if(sizeof(keymap) <= keycode) | |
229 | + { | |
230 | + printf("(cocoa) warning unknow keycode 0x%x\n", keycode); | |
231 | + return 0; | |
232 | + } | |
233 | + return keymap[keycode]; | |
234 | +} | |
235 | + | |
236 | +/* | |
237 | + ------------------------------------------------------ | |
238 | + cocoa_refresh | |
239 | + ------------------------------------------------------ | |
240 | +*/ | |
241 | +static void cocoa_refresh(DisplayState *ds) | |
242 | +{ | |
243 | + //printf("cocoa_refresh \n"); | |
244 | + NSDate *distantPast; | |
245 | + NSEvent *event; | |
246 | + NSAutoreleasePool *pool; | |
247 | + int grab = 1; | |
248 | + | |
249 | + pool = [ [ NSAutoreleasePool alloc ] init ]; | |
250 | + distantPast = [ NSDate distantPast ]; | |
251 | + | |
252 | + if (is_active_console(vga_console)) | |
253 | + vga_update_display(); | |
254 | + do { | |
255 | + event = [ NSApp nextEventMatchingMask:NSAnyEventMask untilDate:distantPast | |
256 | + inMode: NSDefaultRunLoopMode dequeue:YES ]; | |
257 | + if (event != nil) { | |
258 | + switch ([event type]) { | |
259 | + case NSKeyDown: | |
260 | + if(grab) | |
261 | + { | |
262 | + int keycode = cocoa_keycode_to_qemu([event keyCode]); | |
263 | + | |
264 | + if (keycode & 0x80) | |
265 | + kbd_put_keycode(0xe0); | |
266 | + kbd_put_keycode(keycode & 0x7f); | |
267 | + } | |
268 | + break; | |
269 | + case NSKeyUp: | |
270 | + if(grab) | |
271 | + { | |
272 | + int keycode = cocoa_keycode_to_qemu([event keyCode]); | |
273 | + | |
274 | + if (keycode & 0x80) | |
275 | + kbd_put_keycode(0xe0); | |
276 | + kbd_put_keycode(keycode | 0x80); | |
277 | + } | |
278 | + break; | |
279 | + case NSScrollWheel: | |
280 | + | |
281 | + case NSLeftMouseDown: | |
282 | + case NSLeftMouseUp: | |
283 | + | |
284 | + case NSOtherMouseDown: | |
285 | + case NSRightMouseDown: | |
286 | + | |
287 | + case NSOtherMouseUp: | |
288 | + case NSRightMouseUp: | |
289 | + | |
290 | + case NSMouseMoved: | |
291 | + case NSOtherMouseDragged: | |
292 | + case NSRightMouseDragged: | |
293 | + case NSLeftMouseDragged: | |
294 | + | |
295 | + default: [NSApp sendEvent:event]; | |
296 | + } | |
297 | + } | |
298 | + } while(event != nil); | |
299 | +} | |
300 | + | |
301 | +/* | |
302 | + ------------------------------------------------------ | |
303 | + cocoa_cleanup | |
304 | + ------------------------------------------------------ | |
305 | +*/ | |
306 | + | |
307 | +static void cocoa_cleanup(void) | |
308 | +{ | |
309 | + | |
310 | +} | |
311 | + | |
312 | +/* | |
313 | + ------------------------------------------------------ | |
314 | + cocoa_display_init | |
315 | + ------------------------------------------------------ | |
316 | +*/ | |
317 | + | |
318 | +void cocoa_display_init(DisplayState *ds, int full_screen) | |
319 | +{ | |
320 | + ds->dpy_update = cocoa_update; | |
321 | + ds->dpy_resize = cocoa_resize; | |
322 | + ds->dpy_refresh = cocoa_refresh; | |
323 | + | |
324 | + cocoa_resize(ds, 640, 400); | |
325 | + | |
326 | + atexit(cocoa_cleanup); | |
327 | +} | |
328 | + | |
329 | +/* | |
330 | + ------------------------------------------------------ | |
331 | + Interface with Cocoa | |
332 | + ------------------------------------------------------ | |
333 | +*/ | |
334 | + | |
335 | + | |
336 | +/* | |
337 | + ------------------------------------------------------ | |
338 | + QemuWindow | |
339 | + Some trick from SDL to use miniwindow | |
340 | + ------------------------------------------------------ | |
341 | +*/ | |
342 | +static void QZ_SetPortAlphaOpaque () | |
343 | +{ | |
344 | + /* Assume 32 bit if( bpp == 32 )*/ | |
345 | + if ( 1 ) { | |
346 | + | |
347 | + uint32_t *pixels = (uint32_t*) current_ds.data; | |
348 | + uint32_t rowPixels = current_ds.linesize / 4; | |
349 | + uint32_t i, j; | |
350 | + | |
351 | + for (i = 0; i < current_ds.height; i++) | |
352 | + for (j = 0; j < current_ds.width; j++) { | |
353 | + | |
354 | + pixels[ (i * rowPixels) + j ] |= 0xFF000000; | |
355 | + } | |
356 | + } | |
357 | +} | |
358 | + | |
359 | +@implementation QemuWindow | |
360 | +- (void)miniaturize:(id)sender | |
361 | +{ | |
362 | + | |
363 | + /* make the alpha channel opaque so anim won't have holes in it */ | |
364 | + QZ_SetPortAlphaOpaque (); | |
365 | + | |
366 | + [ super miniaturize:sender ]; | |
367 | + | |
368 | +} | |
369 | +- (void)display | |
370 | +{ | |
371 | + /* | |
372 | + This method fires just before the window deminaturizes from the Dock. | |
373 | + | |
374 | + We'll save the current visible surface, let the window manager redraw any | |
375 | + UI elements, and restore the SDL surface. This way, no expose event | |
376 | + is required, and the deminiaturize works perfectly. | |
377 | + */ | |
378 | + | |
379 | + /* make sure pixels are fully opaque */ | |
380 | + QZ_SetPortAlphaOpaque (); | |
381 | + | |
382 | + /* save current visible SDL surface */ | |
383 | + [ self cacheImageInRect:[ qd_view frame ] ]; | |
384 | + | |
385 | + /* let the window manager redraw controls, border, etc */ | |
386 | + [ super display ]; | |
387 | + | |
388 | + /* restore visible SDL surface */ | |
389 | + [ self restoreCachedImage ]; | |
390 | +} | |
391 | + | |
392 | +@end | |
393 | + | |
394 | + | |
395 | +/* | |
396 | + ------------------------------------------------------ | |
397 | + QemuCocoaGUIController | |
398 | + NSApp's delegate - indeed main object | |
399 | + ------------------------------------------------------ | |
400 | +*/ | |
401 | + | |
402 | +@interface QemuCocoaGUIController : NSObject | |
403 | +{ | |
404 | +} | |
405 | +- (void)applicationDidFinishLaunching: (NSNotification *) note; | |
406 | +- (void)applicationWillTerminate:(NSNotification *)aNotification; | |
407 | + | |
408 | +- (void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo; | |
409 | + | |
410 | +- (void)startEmulationWithArgc:(int)argc argv:(char**)argv; | |
411 | +@end | |
412 | + | |
413 | +@implementation QemuCocoaGUIController | |
414 | +/* Called when the internal event loop has just started running */ | |
415 | +- (void)applicationDidFinishLaunching: (NSNotification *) note | |
416 | +{ | |
417 | + | |
418 | + /* Do whatever we want here : set up a pc list... */ | |
419 | + { | |
420 | + NSOpenPanel *op = [[NSOpenPanel alloc] init]; | |
421 | + | |
422 | + cocoa_resize(¤t_ds, 640, 400); | |
423 | + | |
424 | + [op setPrompt:@"Boot image"]; | |
425 | + | |
426 | + [op setMessage:@"Select the disk image you want to boot.\n\nHit the \"Cancel\" button to quit"]; | |
427 | + | |
428 | + [op beginSheetForDirectory:nil file:nil types:[NSArray arrayWithObjects:@"img",@"iso",nil] | |
429 | + modalForWindow:window modalDelegate:self | |
430 | + didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:) contextInfo:NULL]; | |
431 | + } | |
432 | + | |
433 | + /* or Launch Qemu, with the global args */ | |
434 | + //[self startEmulationWithArgc:gArgc argv:gArgv]; | |
435 | +} | |
436 | + | |
437 | +- (void)applicationWillTerminate:(NSNotification *)aNotification | |
438 | +{ | |
439 | + printf("Application will terminate\n"); | |
440 | + qemu_system_shutdown_request(); | |
441 | + /* In order to avoid a crash */ | |
442 | + exit(0); | |
443 | +} | |
444 | + | |
445 | +- (void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo | |
446 | +{ | |
447 | + if(returnCode == NSCancelButton) | |
448 | + { | |
449 | + exit(0); | |
450 | + } | |
451 | + | |
452 | + if(returnCode == NSOKButton) | |
453 | + { | |
454 | + char *bin = "qemu"; | |
455 | + char *img = (char*)[ [ sheet filename ] cString]; | |
456 | + | |
457 | + char **argv = (char**)malloc( sizeof(char*)*3 ); | |
458 | + | |
459 | + asprintf(&argv[0], "%s", bin); | |
460 | + asprintf(&argv[1], "-hda"); | |
461 | + asprintf(&argv[2], "%s", img); | |
462 | + | |
463 | + printf("Using argc %d argv %s -hda %s\n", 3, bin, img); | |
464 | + | |
465 | + [self startEmulationWithArgc:3 argv:(char**)argv]; | |
466 | + } | |
467 | +} | |
468 | + | |
469 | +- (void)startEmulationWithArgc:(int)argc argv:(char**)argv | |
470 | +{ | |
471 | + int status; | |
472 | + /* Launch Qemu */ | |
473 | + printf("starting qemu...\n"); | |
474 | + status = qemu_main (argc, argv); | |
475 | + exit(status); | |
476 | +} | |
477 | +@end | |
478 | + | |
479 | +/* | |
480 | + ------------------------------------------------------ | |
481 | + Application Creation | |
482 | + ------------------------------------------------------ | |
483 | +*/ | |
484 | + | |
485 | +/* Dock Connection */ | |
486 | +typedef struct CPSProcessSerNum | |
487 | +{ | |
488 | + UInt32 lo; | |
489 | + UInt32 hi; | |
490 | +} CPSProcessSerNum; | |
491 | + | |
492 | +extern OSErr CPSGetCurrentProcess( CPSProcessSerNum *psn); | |
493 | +extern OSErr CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5); | |
494 | +extern OSErr CPSSetFrontProcess( CPSProcessSerNum *psn); | |
495 | + | |
496 | +/* Menu Creation */ | |
497 | +static void setApplicationMenu(void) | |
498 | +{ | |
499 | + /* warning: this code is very odd */ | |
500 | + NSMenu *appleMenu; | |
501 | + NSMenuItem *menuItem; | |
502 | + NSString *title; | |
503 | + NSString *appName; | |
504 | + | |
505 | + appName = @"Qemu"; | |
506 | + appleMenu = [[NSMenu alloc] initWithTitle:@""]; | |
507 | + | |
508 | + /* Add menu items */ | |
509 | + title = [@"About " stringByAppendingString:appName]; | |
510 | + [appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""]; | |
511 | + | |
512 | + [appleMenu addItem:[NSMenuItem separatorItem]]; | |
513 | + | |
514 | + title = [@"Hide " stringByAppendingString:appName]; | |
515 | + [appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"]; | |
516 | + | |
517 | + menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"]; | |
518 | + [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)]; | |
519 | + | |
520 | + [appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""]; | |
521 | + | |
522 | + [appleMenu addItem:[NSMenuItem separatorItem]]; | |
523 | + | |
524 | + title = [@"Quit " stringByAppendingString:appName]; | |
525 | + [appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"]; | |
526 | + | |
527 | + | |
528 | + /* Put menu into the menubar */ | |
529 | + menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""]; | |
530 | + [menuItem setSubmenu:appleMenu]; | |
531 | + [[NSApp mainMenu] addItem:menuItem]; | |
532 | + | |
533 | + /* Tell the application object that this is now the application menu */ | |
534 | + [NSApp setAppleMenu:appleMenu]; | |
535 | + | |
536 | + /* Finally give up our references to the objects */ | |
537 | + [appleMenu release]; | |
538 | + [menuItem release]; | |
539 | +} | |
540 | + | |
541 | +/* Create a window menu */ | |
542 | +static void setupWindowMenu(void) | |
543 | +{ | |
544 | + NSMenu *windowMenu; | |
545 | + NSMenuItem *windowMenuItem; | |
546 | + NSMenuItem *menuItem; | |
547 | + | |
548 | + windowMenu = [[NSMenu alloc] initWithTitle:@"Window"]; | |
549 | + | |
550 | + /* "Minimize" item */ | |
551 | + menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"]; | |
552 | + [windowMenu addItem:menuItem]; | |
553 | + [menuItem release]; | |
554 | + | |
555 | + /* Put menu into the menubar */ | |
556 | + windowMenuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""]; | |
557 | + [windowMenuItem setSubmenu:windowMenu]; | |
558 | + [[NSApp mainMenu] addItem:windowMenuItem]; | |
559 | + | |
560 | + /* Tell the application object that this is now the window menu */ | |
561 | + [NSApp setWindowsMenu:windowMenu]; | |
562 | + | |
563 | + /* Finally give up our references to the objects */ | |
564 | + [windowMenu release]; | |
565 | + [windowMenuItem release]; | |
566 | + | |
567 | +} | |
568 | + | |
569 | +static void CustomApplicationMain (argc, argv) | |
570 | +{ | |
571 | + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; | |
572 | + QemuCocoaGUIController *gui_controller; | |
573 | + CPSProcessSerNum PSN; | |
574 | + | |
575 | + [NSApplication sharedApplication]; | |
576 | + | |
577 | + if (!CPSGetCurrentProcess(&PSN)) | |
578 | + if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103)) | |
579 | + if (!CPSSetFrontProcess(&PSN)) | |
580 | + [NSApplication sharedApplication]; | |
581 | + | |
582 | + /* Set up the menubar */ | |
583 | + [NSApp setMainMenu:[[NSMenu alloc] init]]; | |
584 | + setApplicationMenu(); | |
585 | + setupWindowMenu(); | |
586 | + | |
587 | + /* Create SDLMain and make it the app delegate */ | |
588 | + gui_controller = [[QemuCocoaGUIController alloc] init]; | |
589 | + [NSApp setDelegate:gui_controller]; | |
590 | + | |
591 | + /* Start the main event loop */ | |
592 | + [NSApp run]; | |
593 | + | |
594 | + [gui_controller release]; | |
595 | + [pool release]; | |
596 | +} | |
597 | + | |
598 | +/* Real main of qemu-cocoa */ | |
599 | +int main(int argc, char **argv) | |
600 | +{ | |
601 | + gArgc = argc; | |
602 | + gArgv = argv; | |
603 | + | |
604 | + CustomApplicationMain (argc, argv); | |
605 | + | |
606 | + return 0; | |
607 | +} | ... | ... |
configure
... | ... | @@ -83,6 +83,7 @@ fmod_inc="" |
83 | 83 | linux="no" |
84 | 84 | kqemu="no" |
85 | 85 | kernel_path="" |
86 | +cocoa="no" | |
86 | 87 | |
87 | 88 | # OS specific |
88 | 89 | targetos=`uname -s` |
... | ... | @@ -178,6 +179,8 @@ for opt do |
178 | 179 | ;; |
179 | 180 | --kernel-path=*) kernel_path=${opt#--kernel-path=} |
180 | 181 | ;; |
182 | + --enable-cocoa) cocoa="yes" ; sdl="no" | |
183 | + ;; | |
181 | 184 | esac |
182 | 185 | done |
183 | 186 | |
... | ... | @@ -403,6 +406,9 @@ echo "host big endian $bigendian" |
403 | 406 | echo "target list $target_list" |
404 | 407 | echo "gprof enabled $gprof" |
405 | 408 | echo "static build $static" |
409 | +if test "$darwin" = "yes" ; then | |
410 | + echo "Cocoa support $cocoa" | |
411 | +fi | |
406 | 412 | echo "SDL support $sdl" |
407 | 413 | echo "SDL static link $sdl_static" |
408 | 414 | echo "mingw32 support $mingw32" |
... | ... | @@ -676,6 +682,11 @@ if test "$target_user_only" = "no"; then |
676 | 682 | fi |
677 | 683 | fi |
678 | 684 | |
685 | +if test "$cocoa" = "yes" ; then | |
686 | + echo "#define CONFIG_COCOA 1" >> $config_h | |
687 | + echo "CONFIG_COCOA=yes" >> $config_mak | |
688 | +fi | |
689 | + | |
679 | 690 | done # for target in $targets |
680 | 691 | |
681 | 692 | # build tree in object directory if source path is different from current one | ... | ... |
vl.c
... | ... | @@ -72,6 +72,11 @@ |
72 | 72 | #endif |
73 | 73 | #endif /* CONFIG_SDL */ |
74 | 74 | |
75 | +#ifdef CONFIG_COCOA | |
76 | +#undef main | |
77 | +#define main qemu_main | |
78 | +#endif /* CONFIG_COCOA */ | |
79 | + | |
75 | 80 | #include "disas.h" |
76 | 81 | |
77 | 82 | #include "exec-all.h" |
... | ... | @@ -3554,8 +3559,10 @@ int main(int argc, char **argv) |
3554 | 3559 | if (nographic) { |
3555 | 3560 | dumb_display_init(ds); |
3556 | 3561 | } else { |
3557 | -#ifdef CONFIG_SDL | |
3562 | +#if defined(CONFIG_SDL) | |
3558 | 3563 | sdl_display_init(ds, full_screen); |
3564 | +#elif defined(CONFIG_COCOA) | |
3565 | + cocoa_display_init(ds, full_screen); | |
3559 | 3566 | #else |
3560 | 3567 | dumb_display_init(ds); |
3561 | 3568 | #endif | ... | ... |