Commit c304f7e23db91e7add1e72d8e11b839937ac39a0

Authored by ths
1 parent f220f4e3

Core Graphics support (cocoa.m rewrite), by Mike Kronenberg.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3929 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 1 changed file with 650 additions and 589 deletions
1 1 /*
2   - * QEMU Cocoa display driver
  2 + * QEMU Cocoa CG display driver
3 3 *
4   - * Copyright (c) 2005 Pierre d'Herbemont
5   - * many code/inspiration from SDL 1.2 code (LGPL)
  4 + * Copyright (c) 2008 Mike Kronenberg
6 5 *
7 6 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 7 * of this software and associated documentation files (the "Software"), to deal
... ... @@ -22,18 +21,6 @@
22 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 22 * THE SOFTWARE.
24 23 */
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 24  
38 25 #import <Cocoa/Cocoa.h>
39 26  
... ... @@ -41,146 +28,41 @@
41 28 #include "console.h"
42 29 #include "sysemu.h"
43 30  
44   -NSWindow *window = NULL;
45   -NSQuickDrawView *qd_view = NULL;
46   -
47   -
48   -int gArgc;
49   -char **gArgv;
50   -DisplayState current_ds;
51   -
52   -int grab = 0;
53   -int modifiers_state[256];
54   -
55   -/* main defined in qemu/vl.c */
56   -int qemu_main(int argc, char **argv);
57   -
58   -/* To deal with miniaturization */
59   -@interface QemuWindow : NSWindow
60   -{ }
61   -@end
62   -
63   -
64   -/*
65   - ------------------------------------------------------
66   - Qemu Video Driver
67   - ------------------------------------------------------
68   -*/
69   -
70   -/*
71   - ------------------------------------------------------
72   - cocoa_update
73   - ------------------------------------------------------
74   -*/
75   -static void cocoa_update(DisplayState *ds, int x, int y, int w, int h)
76   -{
77   - //printf("updating x=%d y=%d w=%d h=%d\n", x, y, w, h);
78   -
79   - /* Use QDFlushPortBuffer() to flush content to display */
80   - RgnHandle dirty = NewRgn ();
81   - RgnHandle temp = NewRgn ();
82   -
83   - SetEmptyRgn (dirty);
84   -
85   - /* Build the region of dirty rectangles */
86   - MacSetRectRgn (temp, x, y,
87   - x + w, y + h);
88   - MacUnionRgn (dirty, temp, dirty);
89   -
90   - /* Flush the dirty region */
91   - QDFlushPortBuffer ( [ qd_view qdPort ], dirty );
92   - DisposeRgn (dirty);
93   - DisposeRgn (temp);
94   -}
95   -
96   -/*
97   - ------------------------------------------------------
98   - cocoa_resize
99   - ------------------------------------------------------
100   -*/
101   -static void cocoa_resize(DisplayState *ds, int w, int h)
102   -{
103   - const int device_bpp = 32;
104   - static void *screen_pixels;
105   - static int screen_pitch;
106   - NSRect contentRect;
107   -
108   - //printf("resizing to %d %d\n", w, h);
109   -
110   - contentRect = NSMakeRect (0, 0, w, h);
111   - if(window)
112   - {
113   - [window close];
114   - [window release];
115   - }
116   - window = [ [ QemuWindow alloc ] initWithContentRect:contentRect
117   - styleMask:NSTitledWindowMask|NSMiniaturizableWindowMask|NSClosableWindowMask
118   - backing:NSBackingStoreBuffered defer:NO];
119   - if(!window)
120   - {
121   - fprintf(stderr, "(cocoa) can't create window\n");
122   - exit(1);
123   - }
124   -
125   - if(qd_view)
126   - [qd_view release];
127   -
128   - qd_view = [ [ NSQuickDrawView alloc ] initWithFrame:contentRect ];
129   -
130   - if(!qd_view)
131   - {
132   - fprintf(stderr, "(cocoa) can't create qd_view\n");
133   - exit(1);
134   - }
135   -
136   - [ window setAcceptsMouseMovedEvents:YES ];
137   - [ window setTitle:@"Qemu" ];
138   - [ window setReleasedWhenClosed:NO ];
139   -
140   - /* Set screen to black */
141   - [ window setBackgroundColor: [NSColor blackColor] ];
142   -
143   - /* set window position */
144   - [ window center ];
145   -
146   - [ qd_view setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable ];
147   - [ [ window contentView ] addSubview:qd_view ];
148   - [ qd_view release ];
149   - [ window makeKeyAndOrderFront:nil ];
150   -
151   - /* Careful here, the window seems to have to be onscreen to do that */
152   - LockPortBits ( [ qd_view qdPort ] );
153   - screen_pixels = GetPixBaseAddr ( GetPortPixMap ( [ qd_view qdPort ] ) );
154   - screen_pitch = GetPixRowBytes ( GetPortPixMap ( [ qd_view qdPort ] ) );
155   - UnlockPortBits ( [ qd_view qdPort ] );
156   - {
157   - int vOffset = [ window frame ].size.height -
158   - [ qd_view frame ].size.height - [ qd_view frame ].origin.y;
159 31  
160   - int hOffset = [ qd_view frame ].origin.x;
  32 +//#define DEBUG
161 33  
162   - screen_pixels += (vOffset * screen_pitch) + hOffset * (device_bpp/8);
163   - }
164   - ds->data = screen_pixels;
165   - ds->linesize = screen_pitch;
166   - ds->depth = device_bpp;
167   - ds->width = w;
168   - ds->height = h;
169   -#ifdef __LITTLE_ENDIAN__
170   - ds->bgr = 1;
  34 +#ifdef DEBUG
  35 +#define COCOA_DEBUG(...) { (void) fprintf (stdout, __VA_ARGS__); }
171 36 #else
172   - ds->bgr = 0;
  37 +#define COCOA_DEBUG(...) ((void) 0)
173 38 #endif
174 39  
175   - current_ds = *ds;
176   -}
  40 +#define cgrect(nsrect) (*(CGRect *)&(nsrect))
  41 +#define COCOA_MOUSE_EVENT \
  42 + if (isTabletEnabled) { \
  43 + kbd_mouse_event((int)(p.x * 0x7FFF / screen.width), (int)((screen.height - p.y) * 0x7FFF / screen.height), 0, buttons); \
  44 + } else if (isMouseGrabed) { \
  45 + kbd_mouse_event((int)[event deltaX], (int)[event deltaY], 0, buttons); \
  46 + } else { \
  47 + [NSApp sendEvent:event]; \
  48 + }
177 49  
178   -/*
179   - ------------------------------------------------------
180   - keymap conversion
181   - ------------------------------------------------------
182   -*/
  50 +typedef struct {
  51 + int width;
  52 + int height;
  53 + int bitsPerComponent;
  54 + int bitsPerPixel;
  55 +} QEMUScreen;
  56 +
  57 +int qemu_main(int argc, char **argv); // main defined in qemu/vl.c
  58 +NSWindow *normalWindow;
  59 +id cocoaView;
  60 +static void *screenBuffer;
  61 +
  62 +int gArgc;
  63 +char **gArgv;
183 64  
  65 +// keymap conversion
184 66 int keymap[] =
185 67 {
186 68 // SdlI macI macH SdlH 104xtH 104xtC sdl
... ... @@ -289,7 +171,7 @@ int keymap[] =
289 171 0, // 102 0x66 Undefined
290 172 87, // 103 0x67 0x57 F11 QZ_F11
291 173 0, // 104 0x68 Undefined
292   - 183,// 105 0x69 0xb7 QZ_PRINT
  174 + 183,// 105 0x69 0xb7 QZ_PRINT
293 175 0, // 106 0x6A Undefined
294 176 70, // 107 0x6B 0x46 SCROLL QZ_SCROLLOCK
295 177 0, // 108 0x6C Undefined
... ... @@ -357,430 +239,566 @@ int cocoa_keycode_to_qemu(int keycode)
357 239 return keymap[keycode];
358 240 }
359 241  
  242 +
  243 +
360 244 /*
361 245 ------------------------------------------------------
362   - cocoa_refresh
  246 + QemuCocoaView
363 247 ------------------------------------------------------
364 248 */
365   -static void cocoa_refresh(DisplayState *ds)
  249 +@interface QemuCocoaView : NSView
366 250 {
367   - //printf("cocoa_refresh \n");
368   - NSDate *distantPast;
369   - NSEvent *event;
370   - NSAutoreleasePool *pool;
371   -
372   - pool = [ [ NSAutoreleasePool alloc ] init ];
373   - distantPast = [ NSDate distantPast ];
374   -
375   - vga_hw_update();
376   -
377   - do {
378   - event = [ NSApp nextEventMatchingMask:NSAnyEventMask untilDate:distantPast
379   - inMode: NSDefaultRunLoopMode dequeue:YES ];
380   - if (event != nil) {
381   - switch ([event type]) {
382   - case NSFlagsChanged:
383   - {
384   - int keycode = cocoa_keycode_to_qemu([event keyCode]);
385   -
386   - if (keycode)
387   - {
388   - if (keycode == 58 || keycode == 69) {
389   - /* emulate caps lock and num lock keydown and keyup */
390   - kbd_put_keycode(keycode);
391   - kbd_put_keycode(keycode | 0x80);
392   - } else if (is_graphic_console()) {
393   - if (keycode & 0x80)
394   - kbd_put_keycode(0xe0);
395   - if (modifiers_state[keycode] == 0) {
396   - /* keydown */
397   - kbd_put_keycode(keycode & 0x7f);
398   - modifiers_state[keycode] = 1;
399   - } else {
400   - /* keyup */
401   - kbd_put_keycode(keycode | 0x80);
402   - modifiers_state[keycode] = 0;
403   - }
404   - }
405   - }
406   -
407   - /* release Mouse grab when pressing ctrl+alt */
408   - if (([event modifierFlags] & NSControlKeyMask) && ([event modifierFlags] & NSAlternateKeyMask))
409   - {
410   - [window setTitle: @"QEMU"];
411   - [NSCursor unhide];
412   - CGAssociateMouseAndMouseCursorPosition ( TRUE );
413   - grab = 0;
414   - }
415   - }
416   - break;
417   -
418   - case NSKeyDown:
419   - {
420   - int keycode = cocoa_keycode_to_qemu([event keyCode]);
421   -
422   - /* handle command Key Combos */
423   - if ([event modifierFlags] & NSCommandKeyMask) {
424   - switch ([event keyCode]) {
425   - /* quit */
426   - case 12: /* q key */
427   - /* switch to windowed View */
428   - exit(0);
429   - return;
430   - }
431   - }
432   -
433   - /* handle control + alt Key Combos */
434   - if (([event modifierFlags] & NSControlKeyMask) && ([event modifierFlags] & NSAlternateKeyMask)) {
435   - switch (keycode) {
436   - /* toggle Monitor */
437   - case 0x02 ... 0x0a: /* '1' to '9' keys */
438   - console_select(keycode - 0x02);
439   - break;
440   - }
441   - } else {
442   - /* handle standard key events */
443   - if (is_graphic_console()) {
444   - if (keycode & 0x80) //check bit for e0 in front
445   - kbd_put_keycode(0xe0);
446   - kbd_put_keycode(keycode & 0x7f); //remove e0 bit in front
447   - /* handle monitor key events */
448   - } else {
449   - int keysym = 0;
450   -
451   - switch([event keyCode]) {
452   - case 115:
453   - keysym = QEMU_KEY_HOME;
454   - break;
455   - case 117:
456   - keysym = QEMU_KEY_DELETE;
457   - break;
458   - case 119:
459   - keysym = QEMU_KEY_END;
460   - break;
461   - case 123:
462   - keysym = QEMU_KEY_LEFT;
463   - break;
464   - case 124:
465   - keysym = QEMU_KEY_RIGHT;
466   - break;
467   - case 125:
468   - keysym = QEMU_KEY_DOWN;
469   - break;
470   - case 126:
471   - keysym = QEMU_KEY_UP;
472   - break;
473   - default:
474   - {
475   - NSString *ks = [event characters];
476   -
477   - if ([ks length] > 0)
478   - keysym = [ks characterAtIndex:0];
479   - }
480   - }
481   - if (keysym)
482   - kbd_put_keysym(keysym);
483   - }
484   - }
485   - }
486   - break;
487   -
488   - case NSKeyUp:
489   - {
490   - int keycode = cocoa_keycode_to_qemu([event keyCode]);
491   - if (is_graphic_console()) {
492   - if (keycode & 0x80)
493   - kbd_put_keycode(0xe0);
494   - kbd_put_keycode(keycode | 0x80); //add 128 to signal release of key
495   - }
496   - }
497   - break;
498   -
499   - case NSMouseMoved:
500   - if (grab) {
501   - int dx = [event deltaX];
502   - int dy = [event deltaY];
503   - int dz = [event deltaZ];
504   - int buttons = 0;
505   - kbd_mouse_event(dx, dy, dz, buttons);
506   - }
507   - break;
508   -
509   - case NSLeftMouseDown:
510   - if (grab) {
511   - int buttons = 0;
512   -
513   - /* leftclick+command simulates rightclick */
514   - if ([event modifierFlags] & NSCommandKeyMask) {
515   - buttons |= MOUSE_EVENT_RBUTTON;
516   - } else {
517   - buttons |= MOUSE_EVENT_LBUTTON;
518   - }
519   - kbd_mouse_event(0, 0, 0, buttons);
520   - } else {
521   - [NSApp sendEvent: event];
522   - }
523   - break;
524   -
525   - case NSLeftMouseDragged:
526   - if (grab) {
527   - int dx = [event deltaX];
528   - int dy = [event deltaY];
529   - int dz = [event deltaZ];
530   - int buttons = 0;
531   - if ([[NSApp currentEvent] modifierFlags] & NSCommandKeyMask) { //leftclick+command simulates rightclick
532   - buttons |= MOUSE_EVENT_RBUTTON;
533   - } else {
534   - buttons |= MOUSE_EVENT_LBUTTON;
535   - }
536   - kbd_mouse_event(dx, dy, dz, buttons);
537   - }
538   - break;
539   -
540   - case NSLeftMouseUp:
541   - if (grab) {
542   - kbd_mouse_event(0, 0, 0, 0);
543   - } else {
544   - [window setTitle: @"QEMU (Press ctrl + alt to release Mouse)"];
545   - [NSCursor hide];
546   - CGAssociateMouseAndMouseCursorPosition ( FALSE );
547   - grab = 1;
548   - //[NSApp sendEvent: event];
549   - }
550   - break;
  251 + QEMUScreen screen;
  252 + NSWindow *fullScreenWindow;
  253 + float cx,cy,cw,ch,cdx,cdy;
  254 + CGDataProviderRef dataProviderRef;
  255 + int modifiers_state[256];
  256 + BOOL isMouseGrabed;
  257 + BOOL isFullscreen;
  258 + BOOL isAbsoluteEnabled;
  259 + BOOL isTabletEnabled;
  260 +}
  261 +- (void) resizeContentToWidth:(int)w height:(int)h displayState:(DisplayState *)ds;
  262 +- (void) grabMouse;
  263 +- (void) ungrabMouse;
  264 +- (void) toggleFullScreen:(id)sender;
  265 +- (void) handleEvent:(NSEvent *)event;
  266 +- (void) setAbsoluteEnabled:(BOOL)tIsAbsoluteEnabled;
  267 +- (BOOL) isMouseGrabed;
  268 +- (BOOL) isAbsoluteEnabled;
  269 +- (float) cdx;
  270 +- (float) cdy;
  271 +- (QEMUScreen) gscreen;
  272 +@end
551 273  
552   - case NSRightMouseDown:
553   - if (grab) {
554   - int buttons = 0;
  274 +@implementation QemuCocoaView
  275 +- (id)initWithFrame:(NSRect)frameRect
  276 +{
  277 + COCOA_DEBUG("QemuCocoaView: initWithFrame\n");
555 278  
556   - buttons |= MOUSE_EVENT_RBUTTON;
557   - kbd_mouse_event(0, 0, 0, buttons);
558   - } else {
559   - [NSApp sendEvent: event];
560   - }
561   - break;
  279 + self = [super initWithFrame:frameRect];
  280 + if (self) {
562 281  
563   - case NSRightMouseDragged:
564   - if (grab) {
565   - int dx = [event deltaX];
566   - int dy = [event deltaY];
567   - int dz = [event deltaZ];
568   - int buttons = 0;
569   - buttons |= MOUSE_EVENT_RBUTTON;
570   - kbd_mouse_event(dx, dy, dz, buttons);
571   - }
572   - break;
  282 + screen.bitsPerComponent = 8;
  283 + screen.bitsPerPixel = 32;
  284 + screen.width = frameRect.size.width;
  285 + screen.height = frameRect.size.height;
573 286  
574   - case NSRightMouseUp:
575   - if (grab) {
576   - kbd_mouse_event(0, 0, 0, 0);
577   - } else {
578   - [NSApp sendEvent: event];
579   - }
580   - break;
  287 + }
  288 + return self;
  289 +}
581 290  
582   - case NSOtherMouseDragged:
583   - if (grab) {
584   - int dx = [event deltaX];
585   - int dy = [event deltaY];
586   - int dz = [event deltaZ];
587   - int buttons = 0;
588   - buttons |= MOUSE_EVENT_MBUTTON;
589   - kbd_mouse_event(dx, dy, dz, buttons);
590   - }
591   - break;
  291 +- (void) dealloc
  292 +{
  293 + COCOA_DEBUG("QemuCocoaView: dealloc\n");
592 294  
593   - case NSOtherMouseDown:
594   - if (grab) {
595   - int buttons = 0;
596   - buttons |= MOUSE_EVENT_MBUTTON;
597   - kbd_mouse_event(0, 0, 0, buttons);
598   - } else {
599   - [NSApp sendEvent:event];
600   - }
601   - break;
  295 + if (screenBuffer)
  296 + free(screenBuffer);
602 297  
603   - case NSOtherMouseUp:
604   - if (grab) {
605   - kbd_mouse_event(0, 0, 0, 0);
606   - } else {
607   - [NSApp sendEvent: event];
608   - }
609   - break;
  298 + if (dataProviderRef)
  299 + CGDataProviderRelease(dataProviderRef);
610 300  
611   - case NSScrollWheel:
612   - if (grab) {
613   - int dz = [event deltaY];
614   - kbd_mouse_event(0, 0, -dz, 0);
615   - }
616   - break;
  301 + [super dealloc];
  302 +}
617 303  
618   - default: [NSApp sendEvent:event];
  304 +- (void) drawRect:(NSRect) rect
  305 +{
  306 + COCOA_DEBUG("QemuCocoaView: drawRect\n");
  307 +
  308 + if ((int)screenBuffer == -1)
  309 + return;
  310 +
  311 + // get CoreGraphic context
  312 + CGContextRef viewContextRef = [[NSGraphicsContext currentContext] graphicsPort];
  313 + CGContextSetInterpolationQuality (viewContextRef, kCGInterpolationNone);
  314 + CGContextSetShouldAntialias (viewContextRef, NO);
  315 +
  316 + // draw screen bitmap directly to Core Graphics context
  317 + if (dataProviderRef) {
  318 + CGImageRef imageRef = CGImageCreate(
  319 + screen.width, //width
  320 + screen.height, //height
  321 + screen.bitsPerComponent, //bitsPerComponent
  322 + screen.bitsPerPixel, //bitsPerPixel
  323 + (screen.width * 4), //bytesPerRow
  324 +#if __LITTLE_ENDIAN__
  325 + CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB), //colorspace for OS X >= 10.4
  326 + kCGImageAlphaNoneSkipLast,
  327 +#else
  328 + CGColorSpaceCreateDeviceRGB(), //colorspace for OS X < 10.4 (actually ppc)
  329 + kCGImageAlphaNoneSkipFirst, //bitmapInfo
  330 +#endif
  331 + dataProviderRef, //provider
  332 + NULL, //decode
  333 + 0, //interpolate
  334 + kCGRenderingIntentDefault //intent
  335 + );
  336 +// test if host support "CGImageCreateWithImageInRect" at compiletime
  337 +#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
  338 + if (CGImageCreateWithImageInRect == NULL) { // test if "CGImageCreateWithImageInRect" is supported on host at runtime
  339 +#endif
  340 + // compatibility drawing code (draws everything) (OS X < 10.4)
  341 + CGContextDrawImage (viewContextRef, CGRectMake(0, 0, [self bounds].size.width, [self bounds].size.height), imageRef);
  342 +#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
  343 + } else {
  344 + // selective drawing code (draws only dirty rectangles) (OS X >= 10.4)
  345 + const NSRect *rectList;
  346 + int rectCount;
  347 + int i;
  348 + CGImageRef clipImageRef;
  349 + CGRect clipRect;
  350 +
  351 + [self getRectsBeingDrawn:&rectList count:&rectCount];
  352 + for (i = 0; i < rectCount; i++) {
  353 + clipRect.origin.x = rectList[i].origin.x / cdx;
  354 + clipRect.origin.y = (float)screen.height - (rectList[i].origin.y + rectList[i].size.height) / cdy;
  355 + clipRect.size.width = rectList[i].size.width / cdx;
  356 + clipRect.size.height = rectList[i].size.height / cdy;
  357 + clipImageRef = CGImageCreateWithImageInRect(
  358 + imageRef,
  359 + clipRect
  360 + );
  361 + CGContextDrawImage (viewContextRef, cgrect(rectList[i]), clipImageRef);
  362 + CGImageRelease (clipImageRef);
619 363 }
620 364 }
621   - } while(event != nil);
  365 +#endif
  366 + CGImageRelease (imageRef);
  367 + }
622 368 }
623 369  
624   -/*
625   - ------------------------------------------------------
626   - cocoa_cleanup
627   - ------------------------------------------------------
628   -*/
629   -
630   -static void cocoa_cleanup(void)
  370 +- (void) setContentDimensions
631 371 {
632   -
  372 + COCOA_DEBUG("QemuCocoaView: setContentDimensions\n");
  373 +
  374 + if (isFullscreen) {
  375 + cdx = [[NSScreen mainScreen] frame].size.width / (float)screen.width;
  376 + cdy = [[NSScreen mainScreen] frame].size.height / (float)screen.height;
  377 + cw = screen.width * cdx;
  378 + ch = screen.height * cdy;
  379 + cx = ([[NSScreen mainScreen] frame].size.width - cw) / 2.0;
  380 + cy = ([[NSScreen mainScreen] frame].size.height - ch) / 2.0;
  381 + } else {
  382 + cx = 0;
  383 + cy = 0;
  384 + cw = screen.width;
  385 + ch = screen.height;
  386 + cdx = 1.0;
  387 + cdy = 1.0;
  388 + }
633 389 }
634 390  
635   -/*
636   - ------------------------------------------------------
637   - cocoa_display_init
638   - ------------------------------------------------------
639   -*/
640   -
641   -void cocoa_display_init(DisplayState *ds, int full_screen)
  391 +- (void) resizeContentToWidth:(int)w height:(int)h displayState:(DisplayState *)ds
642 392 {
643   - ds->dpy_update = cocoa_update;
644   - ds->dpy_resize = cocoa_resize;
645   - ds->dpy_refresh = cocoa_refresh;
  393 + COCOA_DEBUG("QemuCocoaView: resizeContent\n");
  394 +
  395 + // update screenBuffer
  396 + if (dataProviderRef)
  397 + CGDataProviderRelease(dataProviderRef);
  398 + if (screenBuffer)
  399 + free(screenBuffer);
  400 + screenBuffer = malloc( w * 4 * h );
  401 +
  402 + ds->data = screenBuffer;
  403 + ds->linesize = (w * 4);
  404 + ds->depth = 32;
  405 + ds->width = w;
  406 + ds->height = h;
  407 +#ifdef __LITTLE_ENDIAN__
  408 + ds->bgr = 1;
  409 +#else
  410 + ds->bgr = 0;
  411 +#endif
646 412  
647   - cocoa_resize(ds, 640, 400);
  413 + dataProviderRef = CGDataProviderCreateWithData(NULL, screenBuffer, w * 4 * h, NULL);
648 414  
649   - atexit(cocoa_cleanup);
  415 + // update windows
  416 + if (isFullscreen) {
  417 + [[fullScreenWindow contentView] setFrame:[[NSScreen mainScreen] frame]];
  418 + [normalWindow setFrame:NSMakeRect([normalWindow frame].origin.x, [normalWindow frame].origin.y - h + screen.height, w, h + [normalWindow frame].size.height - screen.height) display:NO animate:NO];
  419 + } else {
  420 + if (qemu_name)
  421 + [normalWindow setTitle:[NSString stringWithFormat:@"QEMU %s", qemu_name]];
  422 + [normalWindow setFrame:NSMakeRect([normalWindow frame].origin.x, [normalWindow frame].origin.y - h + screen.height, w, h + [normalWindow frame].size.height - screen.height) display:YES animate:YES];
  423 + }
  424 + screen.width = w;
  425 + screen.height = h;
  426 + [self setContentDimensions];
  427 + [self setFrame:NSMakeRect(cx, cy, cw, ch)];
650 428 }
651 429  
652   -/*
653   - ------------------------------------------------------
654   - Interface with Cocoa
655   - ------------------------------------------------------
656   -*/
657   -
  430 +- (void) toggleFullScreen:(id)sender
  431 +{
  432 + COCOA_DEBUG("QemuCocoaView: toggleFullScreen\n");
  433 +
  434 + if (isFullscreen) { // switch from fullscreen to desktop
  435 + isFullscreen = FALSE;
  436 + [self ungrabMouse];
  437 + [self setContentDimensions];
  438 +// test if host support "enterFullScreenMode:withOptions" at compiletime
  439 +#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
  440 + if ([NSView respondsToSelector:@selector(exitFullScreenModeWithOptions:)]) { // test if "exitFullScreenModeWithOptions" is supported on host at runtime
  441 + [self exitFullScreenModeWithOptions:nil];
  442 + } else {
  443 +#endif
  444 + [fullScreenWindow close];
  445 + [normalWindow setContentView: self];
  446 + [normalWindow makeKeyAndOrderFront: self];
  447 + [NSMenu setMenuBarVisible:YES];
  448 +#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
  449 + }
  450 +#endif
  451 + } else { // switch from desktop to fullscreen
  452 + isFullscreen = TRUE;
  453 + [self grabMouse];
  454 + [self setContentDimensions];
  455 +// test if host support "enterFullScreenMode:withOptions" at compiletime
  456 +#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
  457 + if ([NSView respondsToSelector:@selector(enterFullScreenMode:withOptions:)]) { // test if "enterFullScreenMode:withOptions" is supported on host at runtime
  458 + [self enterFullScreenMode:[NSScreen mainScreen] withOptions:[NSDictionary dictionaryWithObjectsAndKeys:
  459 + [NSNumber numberWithBool:NO], NSFullScreenModeAllScreens,
  460 + [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:NO], kCGDisplayModeIsStretched, nil], NSFullScreenModeSetting,
  461 + nil]];
  462 + } else {
  463 +#endif
  464 + [NSMenu setMenuBarVisible:NO];
  465 + fullScreenWindow = [[NSWindow alloc] initWithContentRect:[[NSScreen mainScreen] frame]
  466 + styleMask:NSBorderlessWindowMask
  467 + backing:NSBackingStoreBuffered
  468 + defer:NO];
  469 + [fullScreenWindow setHasShadow:NO];
  470 + [fullScreenWindow setContentView:self];
  471 + [fullScreenWindow makeKeyAndOrderFront:self];
  472 +#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
  473 + }
  474 +#endif
  475 + }
  476 +}
658 477  
659   -/*
660   - ------------------------------------------------------
661   - QemuWindow
662   - Some trick from SDL to use miniwindow
663   - ------------------------------------------------------
664   -*/
665   -static void QZ_SetPortAlphaOpaque ()
  478 +- (void) handleEvent:(NSEvent *)event
666 479 {
667   - /* Assume 32 bit if( bpp == 32 )*/
668   - if ( 1 ) {
  480 + COCOA_DEBUG("QemuCocoaView: handleEvent\n");
  481 +
  482 + int buttons = 0;
  483 + int keycode;
  484 + NSPoint p = [event locationInWindow];
  485 +
  486 + switch ([event type]) {
  487 + case NSFlagsChanged:
  488 + keycode = cocoa_keycode_to_qemu([event keyCode]);
  489 + if (keycode) {
  490 + if (keycode == 58 || keycode == 69) { // emulate caps lock and num lock keydown and keyup
  491 + kbd_put_keycode(keycode);
  492 + kbd_put_keycode(keycode | 0x80);
  493 + } else if (is_graphic_console()) {
  494 + if (keycode & 0x80)
  495 + kbd_put_keycode(0xe0);
  496 + if (modifiers_state[keycode] == 0) { // keydown
  497 + kbd_put_keycode(keycode & 0x7f);
  498 + modifiers_state[keycode] = 1;
  499 + } else { // keyup
  500 + kbd_put_keycode(keycode | 0x80);
  501 + modifiers_state[keycode] = 0;
  502 + }
  503 + }
  504 + }
669 505  
670   - uint32_t *pixels = (uint32_t*) current_ds.data;
671   - uint32_t rowPixels = current_ds.linesize / 4;
672   - uint32_t i, j;
  506 + // release Mouse grab when pressing ctrl+alt
  507 + if (!isFullscreen && ([event modifierFlags] & NSControlKeyMask) && ([event modifierFlags] & NSAlternateKeyMask)) {
  508 + [self ungrabMouse];
  509 + }
  510 + break;
  511 + case NSKeyDown:
673 512  
674   - for (i = 0; i < current_ds.height; i++)
675   - for (j = 0; j < current_ds.width; j++) {
  513 + // forward command Key Combos
  514 + if ([event modifierFlags] & NSCommandKeyMask) {
  515 + [NSApp sendEvent:event];
  516 + return;
  517 + }
676 518  
677   - pixels[ (i * rowPixels) + j ] |= 0xFF000000;
  519 + // default
  520 + keycode = cocoa_keycode_to_qemu([event keyCode]);
  521 +
  522 + // handle control + alt Key Combos (ctrl+alt is reserved for QEMU)
  523 + if (([event modifierFlags] & NSControlKeyMask) && ([event modifierFlags] & NSAlternateKeyMask)) {
  524 + switch (keycode) {
  525 +
  526 + // enable graphic console
  527 + case 0x02 ... 0x0a: // '1' to '9' keys
  528 + console_select(keycode - 0x02);
  529 + break;
  530 + }
  531 +
  532 + // handle keys for graphic console
  533 + } else if (is_graphic_console()) {
  534 + if (keycode & 0x80) //check bit for e0 in front
  535 + kbd_put_keycode(0xe0);
  536 + kbd_put_keycode(keycode & 0x7f); //remove e0 bit in front
  537 +
  538 + // handlekeys for Monitor
  539 + } else {
  540 + int keysym = 0;
  541 + switch([event keyCode]) {
  542 + case 115:
  543 + keysym = QEMU_KEY_HOME;
  544 + break;
  545 + case 117:
  546 + keysym = QEMU_KEY_DELETE;
  547 + break;
  548 + case 119:
  549 + keysym = QEMU_KEY_END;
  550 + break;
  551 + case 123:
  552 + keysym = QEMU_KEY_LEFT;
  553 + break;
  554 + case 124:
  555 + keysym = QEMU_KEY_RIGHT;
  556 + break;
  557 + case 125:
  558 + keysym = QEMU_KEY_DOWN;
  559 + break;
  560 + case 126:
  561 + keysym = QEMU_KEY_UP;
  562 + break;
  563 + default:
  564 + {
  565 + NSString *ks = [event characters];
  566 + if ([ks length] > 0)
  567 + keysym = [ks characterAtIndex:0];
  568 + }
  569 + }
  570 + if (keysym)
  571 + kbd_put_keysym(keysym);
  572 + }
  573 + break;
  574 + case NSKeyUp:
  575 + keycode = cocoa_keycode_to_qemu([event keyCode]);
  576 + if (is_graphic_console()) {
  577 + if (keycode & 0x80)
  578 + kbd_put_keycode(0xe0);
  579 + kbd_put_keycode(keycode | 0x80); //add 128 to signal release of key
  580 + }
  581 + break;
  582 + case NSMouseMoved:
  583 + if (isAbsoluteEnabled) {
  584 + if (p.x < 0 || p.x > screen.width || p.y < 0 || p.y > screen.height || ![[self window] isKeyWindow]) {
  585 + if (isTabletEnabled) { // if we leave the window, deactivate the tablet
  586 + [NSCursor unhide];
  587 + isTabletEnabled = FALSE;
  588 + }
  589 + } else {
  590 + if (!isTabletEnabled) { // if we enter the window, activate the tablet
  591 + [NSCursor hide];
  592 + isTabletEnabled = TRUE;
  593 + }
  594 + }
678 595 }
  596 + COCOA_MOUSE_EVENT
  597 + break;
  598 + case NSLeftMouseDown:
  599 + if ([event modifierFlags] & NSCommandKeyMask) {
  600 + buttons |= MOUSE_EVENT_RBUTTON;
  601 + } else {
  602 + buttons |= MOUSE_EVENT_LBUTTON;
  603 + }
  604 + COCOA_MOUSE_EVENT
  605 + break;
  606 + case NSRightMouseDown:
  607 + buttons |= MOUSE_EVENT_RBUTTON;
  608 + COCOA_MOUSE_EVENT
  609 + break;
  610 + case NSOtherMouseDown:
  611 + buttons |= MOUSE_EVENT_MBUTTON;
  612 + COCOA_MOUSE_EVENT
  613 + break;
  614 + case NSLeftMouseDragged:
  615 + if ([event modifierFlags] & NSCommandKeyMask) {
  616 + buttons |= MOUSE_EVENT_RBUTTON;
  617 + } else {
  618 + buttons |= MOUSE_EVENT_LBUTTON;
  619 + }
  620 + COCOA_MOUSE_EVENT
  621 + break;
  622 + case NSRightMouseDragged:
  623 + buttons |= MOUSE_EVENT_RBUTTON;
  624 + COCOA_MOUSE_EVENT
  625 + break;
  626 + case NSOtherMouseDragged:
  627 + buttons |= MOUSE_EVENT_MBUTTON;
  628 + COCOA_MOUSE_EVENT
  629 + break;
  630 + case NSLeftMouseUp:
  631 + if (isTabletEnabled) {
  632 + COCOA_MOUSE_EVENT
  633 + } else if (!isMouseGrabed) {
  634 + if (p.x > -1 && p.x < screen.width && p.y > -1 && p.y < screen.height) {
  635 + [self grabMouse];
  636 + } else {
  637 + [NSApp sendEvent:event];
  638 + }
  639 + } else {
  640 + COCOA_MOUSE_EVENT
  641 + }
  642 + break;
  643 + case NSRightMouseUp:
  644 + COCOA_MOUSE_EVENT
  645 + break;
  646 + case NSOtherMouseUp:
  647 + COCOA_MOUSE_EVENT
  648 + break;
  649 + case NSScrollWheel:
  650 + if (isTabletEnabled || isMouseGrabed) {
  651 + kbd_mouse_event(0, 0, -[event deltaY], 0);
  652 + } else {
  653 + [NSApp sendEvent:event];
  654 + }
  655 + break;
  656 + default:
  657 + [NSApp sendEvent:event];
679 658 }
680 659 }
681 660  
682   -@implementation QemuWindow
683   -- (void)miniaturize:(id)sender
  661 +- (void) grabMouse
684 662 {
  663 + COCOA_DEBUG("QemuCocoaView: grabMouse\n");
685 664  
686   - /* make the alpha channel opaque so anim won't have holes in it */
687   - QZ_SetPortAlphaOpaque ();
688   -
689   - [ super miniaturize:sender ];
690   -
  665 + if (!isFullscreen) {
  666 + if (qemu_name)
  667 + [normalWindow setTitle:[NSString stringWithFormat:@"QEMU %s - (Press ctrl + alt to release Mouse)", qemu_name]];
  668 + else
  669 + [normalWindow setTitle:@"QEMU - (Press ctrl + alt to release Mouse)"];
  670 + }
  671 + [NSCursor hide];
  672 + CGAssociateMouseAndMouseCursorPosition(FALSE);
  673 + isMouseGrabed = TRUE; // while isMouseGrabed = TRUE, QemuCocoaApp sends all events to [cocoaView handleEvent:]
691 674 }
692   -- (void)display
693   -{
694   - /*
695   - This method fires just before the window deminaturizes from the Dock.
696   -
697   - We'll save the current visible surface, let the window manager redraw any
698   - UI elements, and restore the SDL surface. This way, no expose event
699   - is required, and the deminiaturize works perfectly.
700   - */
701   -
702   - /* make sure pixels are fully opaque */
703   - QZ_SetPortAlphaOpaque ();
704 675  
705   - /* save current visible SDL surface */
706   - [ self cacheImageInRect:[ qd_view frame ] ];
707   -
708   - /* let the window manager redraw controls, border, etc */
709   - [ super display ];
  676 +- (void) ungrabMouse
  677 +{
  678 + COCOA_DEBUG("QemuCocoaView: ungrabMouse\n");
710 679  
711   - /* restore visible SDL surface */
712   - [ self restoreCachedImage ];
  680 + if (!isFullscreen) {
  681 + if (qemu_name)
  682 + [normalWindow setTitle:[NSString stringWithFormat:@"QEMU %s", qemu_name]];
  683 + else
  684 + [normalWindow setTitle:@"QEMU"];
  685 + }
  686 + [NSCursor unhide];
  687 + CGAssociateMouseAndMouseCursorPosition(TRUE);
  688 + isMouseGrabed = FALSE;
713 689 }
714 690  
  691 +- (void) setAbsoluteEnabled:(BOOL)tIsAbsoluteEnabled {isAbsoluteEnabled = tIsAbsoluteEnabled;}
  692 +- (BOOL) isMouseGrabed {return isMouseGrabed;}
  693 +- (BOOL) isAbsoluteEnabled {return isAbsoluteEnabled;}
  694 +- (float) cdx {return cdx;}
  695 +- (float) cdy {return cdy;}
  696 +- (QEMUScreen) gscreen {return screen;}
715 697 @end
716 698  
717 699  
  700 +
718 701 /*
719 702 ------------------------------------------------------
720   - QemuCocoaGUIController
721   - NSApp's delegate - indeed main object
  703 + QemuCocoaAppController
722 704 ------------------------------------------------------
723 705 */
724   -
725   -@interface QemuCocoaGUIController : NSObject
  706 +@interface QemuCocoaAppController : NSObject
726 707 {
727 708 }
728   -- (void)applicationDidFinishLaunching: (NSNotification *) note;
729   -- (void)applicationWillTerminate:(NSNotification *)aNotification;
730   -
731   -- (void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo;
732   -
733 709 - (void)startEmulationWithArgc:(int)argc argv:(char**)argv;
  710 +- (void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo;
  711 +- (void)toggleFullScreen:(id)sender;
  712 +- (void)showQEMUDoc:(id)sender;
  713 +- (void)showQEMUTec:(id)sender;
734 714 @end
735 715  
736   -@implementation QemuCocoaGUIController
737   -/* Called when the internal event loop has just started running */
738   -- (void)applicationDidFinishLaunching: (NSNotification *) note
  716 +@implementation QemuCocoaAppController
  717 +- (id) init
739 718 {
  719 + COCOA_DEBUG("QemuCocoaAppController: init\n");
740 720  
741   - /* Display an open dialog box if no argument were passed or
742   - if qemu was launched from the finder ( the Finder passes "-psn" ) */
  721 + self = [super init];
  722 + if (self) {
743 723  
744   - if( gArgc <= 1 || strncmp (gArgv[1], "-psn", 4) == 0)
745   - {
746   - NSOpenPanel *op = [[NSOpenPanel alloc] init];
  724 + // create a view and add it to the window
  725 + cocoaView = [[QemuCocoaView alloc] initWithFrame:NSMakeRect(0.0, 0.0, 640.0, 480.0)];
  726 + if(!cocoaView) {
  727 + fprintf(stderr, "(cocoa) can't create a view\n");
  728 + exit(1);
  729 + }
747 730  
748   - cocoa_resize(&current_ds, 640, 400);
  731 + // create a window
  732 + normalWindow = [[NSWindow alloc] initWithContentRect:[cocoaView frame]
  733 + styleMask:NSTitledWindowMask|NSMiniaturizableWindowMask|NSClosableWindowMask
  734 + backing:NSBackingStoreBuffered defer:NO];
  735 + if(!normalWindow) {
  736 + fprintf(stderr, "(cocoa) can't create window\n");
  737 + exit(1);
  738 + }
  739 + [normalWindow setAcceptsMouseMovedEvents:YES];
  740 + [normalWindow setTitle:[NSString stringWithFormat:@"QEMU"]];
  741 + [normalWindow setContentView:cocoaView];
  742 + [normalWindow makeKeyAndOrderFront:self];
749 743  
750   - [op setPrompt:@"Boot image"];
  744 + }
  745 + return self;
  746 +}
751 747  
752   - [op setMessage:@"Select the disk image you want to boot.\n\nHit the \"Cancel\" button to quit"];
  748 +- (void) dealloc
  749 +{
  750 + COCOA_DEBUG("QemuCocoaAppController: dealloc\n");
  751 +
  752 + if (cocoaView)
  753 + [cocoaView release];
  754 + [super dealloc];
  755 +}
753 756  
  757 +- (void)applicationDidFinishLaunching: (NSNotification *) note
  758 +{
  759 + COCOA_DEBUG("QemuCocoaAppController: applicationDidFinishLaunching\n");
  760 +
  761 + // Display an open dialog box if no argument were passed or
  762 + // if qemu was launched from the finder ( the Finder passes "-psn" )
  763 + if( gArgc <= 1 || strncmp ((char *)gArgv[1], "-psn", 4) == 0) {
  764 + NSOpenPanel *op = [[NSOpenPanel alloc] init];
  765 + [op setPrompt:@"Boot image"];
  766 + [op setMessage:@"Select the disk image you want to boot.\n\nHit the \"Cancel\" button to quit"];
754 767 [op beginSheetForDirectory:nil file:nil types:[NSArray arrayWithObjects:@"img",@"iso",@"dmg",@"qcow",@"cow",@"cloop",@"vmdk",nil]
755   - modalForWindow:window modalDelegate:self
  768 + modalForWindow:normalWindow modalDelegate:self
756 769 didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:) contextInfo:NULL];
757   - }
758   - else
759   - {
760   - /* or Launch Qemu, with the global args */
761   - [self startEmulationWithArgc:gArgc argv:gArgv];
  770 + } else {
  771 + // or Launch Qemu, with the global args
  772 + [self startEmulationWithArgc:gArgc argv:(char **)gArgv];
762 773 }
763 774 }
764 775  
765 776 - (void)applicationWillTerminate:(NSNotification *)aNotification
766 777 {
767   - printf("Application will terminate\n");
  778 + COCOA_DEBUG("QemuCocoaAppController: applicationWillTerminate\n");
  779 +
768 780 qemu_system_shutdown_request();
769   - /* In order to avoid a crash */
770 781 exit(0);
771 782 }
772 783  
  784 +- (void)startEmulationWithArgc:(int)argc argv:(char**)argv
  785 +{
  786 + COCOA_DEBUG("QemuCocoaAppController: startEmulationWithArgc\n");
  787 +
  788 + int status;
  789 + status = qemu_main(argc, argv);
  790 + exit(status);
  791 +}
  792 +
773 793 - (void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
774 794 {
775   - if(returnCode == NSCancelButton)
776   - {
777   - exit(0);
778   - }
  795 + COCOA_DEBUG("QemuCocoaAppController: openPanelDidEnd\n");
779 796  
780   - if(returnCode == NSOKButton)
781   - {
  797 + if(returnCode == NSCancelButton) {
  798 + exit(0);
  799 + } else if(returnCode == NSOKButton) {
782 800 char *bin = "qemu";
783   - char *img = (char*)[ [ sheet filename ] cString];
  801 + char *img = (char*)[ [ sheet filename ] cStringUsingEncoding:NSASCIIStringEncoding];
784 802  
785 803 char **argv = (char**)malloc( sizeof(char*)*3 );
786 804  
... ... @@ -793,24 +811,33 @@ static void QZ_SetPortAlphaOpaque ()
793 811 [self startEmulationWithArgc:3 argv:(char**)argv];
794 812 }
795 813 }
  814 +- (void)toggleFullScreen:(id)sender
  815 +{
  816 + COCOA_DEBUG("QemuCocoaAppController: toggleFullScreen\n");
  817 +
  818 + [cocoaView toggleFullScreen:sender];
  819 +}
796 820  
797   -- (void)startEmulationWithArgc:(int)argc argv:(char**)argv
  821 +- (void)showQEMUDoc:(id)sender
798 822 {
799   - int status;
800   - /* Launch Qemu */
801   - printf("starting qemu...\n");
802   - status = qemu_main (argc, argv);
803   - exit(status);
  823 + COCOA_DEBUG("QemuCocoaAppController: showQEMUDoc\n");
  824 +
  825 + [[NSWorkspace sharedWorkspace] openFile:[NSString stringWithFormat:@"%@/../doc/qemu/qemu-doc.html",
  826 + [[NSBundle mainBundle] resourcePath]] withApplication:@"Help Viewer"];
  827 +}
  828 +
  829 +- (void)showQEMUTec:(id)sender
  830 +{
  831 + COCOA_DEBUG("QemuCocoaAppController: showQEMUTec\n");
  832 +
  833 + [[NSWorkspace sharedWorkspace] openFile:[NSString stringWithFormat:@"%@/../doc/qemu/qemu-tech.html",
  834 + [[NSBundle mainBundle] resourcePath]] withApplication:@"Help Viewer"];
804 835 }
805 836 @end
806 837  
807   -/*
808   - ------------------------------------------------------
809   - Application Creation
810   - ------------------------------------------------------
811   -*/
812 838  
813   -/* Dock Connection */
  839 +
  840 +// Dock Connection
814 841 typedef struct CPSProcessSerNum
815 842 {
816 843 UInt32 lo;
... ... @@ -821,114 +848,148 @@ extern OSErr CPSGetCurrentProcess( CPSProcessSerNum *psn);
821 848 extern OSErr CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5);
822 849 extern OSErr CPSSetFrontProcess( CPSProcessSerNum *psn);
823 850  
824   -/* Menu Creation */
825   -static void setApplicationMenu(void)
826   -{
827   - /* warning: this code is very odd */
828   - NSMenu *appleMenu;
829   - NSMenuItem *menuItem;
830   - NSString *title;
831   - NSString *appName;
832   -
833   - appName = @"Qemu";
834   - appleMenu = [[NSMenu alloc] initWithTitle:@""];
835   -
836   - /* Add menu items */
837   - title = [@"About " stringByAppendingString:appName];
838   - [appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""];
  851 +int main (int argc, const char * argv[]) {
839 852  
840   - [appleMenu addItem:[NSMenuItem separatorItem]];
841   -
842   - title = [@"Hide " stringByAppendingString:appName];
843   - [appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"];
  853 + gArgc = argc;
  854 + gArgv = (char **)argv;
  855 + CPSProcessSerNum PSN;
844 856  
845   - menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"];
846   - [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)];
  857 + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
  858 + [NSApplication sharedApplication];
847 859  
848   - [appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""];
  860 + if (!CPSGetCurrentProcess(&PSN))
  861 + if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103))
  862 + if (!CPSSetFrontProcess(&PSN))
  863 + [NSApplication sharedApplication];
849 864  
850   - [appleMenu addItem:[NSMenuItem separatorItem]];
  865 + // Add menus
  866 + NSMenu *menu;
  867 + NSMenuItem *menuItem;
851 868  
852   - title = [@"Quit " stringByAppendingString:appName];
853   - [appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"];
  869 + [NSApp setMainMenu:[[NSMenu alloc] init]];
854 870  
  871 + // Application menu
  872 + menu = [[NSMenu alloc] initWithTitle:@""];
  873 + [menu addItemWithTitle:@"About QEMU" action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""]; // About QEMU
  874 + [menu addItem:[NSMenuItem separatorItem]]; //Separator
  875 + [menu addItemWithTitle:@"Hide QEMU" action:@selector(hide:) keyEquivalent:@"h"]; //Hide QEMU
  876 + menuItem = (NSMenuItem *)[menu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"]; // Hide Others
  877 + [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)];
  878 + [menu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""]; // Show All
  879 + [menu addItem:[NSMenuItem separatorItem]]; //Separator
  880 + [menu addItemWithTitle:@"Quit QEMU" action:@selector(terminate:) keyEquivalent:@"q"];
  881 + menuItem = [[NSMenuItem alloc] initWithTitle:@"Apple" action:nil keyEquivalent:@""];
  882 + [menuItem setSubmenu:menu];
  883 + [[NSApp mainMenu] addItem:menuItem];
  884 + [NSApp performSelector:@selector(setAppleMenu:) withObject:menu]; // Workaround (this method is private since 10.4+)
855 885  
856   - /* Put menu into the menubar */
857   - menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""];
858   - [menuItem setSubmenu:appleMenu];
  886 + // View menu
  887 + menu = [[NSMenu alloc] initWithTitle:@"View"];
  888 + [menu addItem: [[[NSMenuItem alloc] initWithTitle:@"Enter Fullscreen" action:@selector(toggleFullScreen:) keyEquivalent:@"f"] autorelease]]; // Fullscreen
  889 + menuItem = [[[NSMenuItem alloc] initWithTitle:@"View" action:nil keyEquivalent:@""] autorelease];
  890 + [menuItem setSubmenu:menu];
859 891 [[NSApp mainMenu] addItem:menuItem];
860 892  
861   - /* Tell the application object that this is now the application menu */
862   - [NSApp setAppleMenu:appleMenu];
  893 + // Window menu
  894 + menu = [[NSMenu alloc] initWithTitle:@"Window"];
  895 + [menu addItem: [[[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"] autorelease]]; // Miniaturize
  896 + menuItem = [[[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""] autorelease];
  897 + [menuItem setSubmenu:menu];
  898 + [[NSApp mainMenu] addItem:menuItem];
  899 + [NSApp setWindowsMenu:menu];
  900 +
  901 + // Help menu
  902 + menu = [[NSMenu alloc] initWithTitle:@"Help"];
  903 + [menu addItem: [[[NSMenuItem alloc] initWithTitle:@"QEMU Documentation" action:@selector(showQEMUDoc:) keyEquivalent:@"?"] autorelease]]; // QEMU Help
  904 + [menu addItem: [[[NSMenuItem alloc] initWithTitle:@"QEMU Technology" action:@selector(showQEMUTec:) keyEquivalent:@""] autorelease]]; // QEMU Help
  905 + menuItem = [[[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""] autorelease];
  906 + [menuItem setSubmenu:menu];
  907 + [[NSApp mainMenu] addItem:menuItem];
863 908  
864   - /* Finally give up our references to the objects */
865   - [appleMenu release];
866   - [menuItem release];
867   -}
  909 + // Create an Application controller
  910 + QemuCocoaAppController *appController = [[QemuCocoaAppController alloc] init];
  911 + [NSApp setDelegate:appController];
868 912  
869   -/* Create a window menu */
870   -static void setupWindowMenu(void)
871   -{
872   - NSMenu *windowMenu;
873   - NSMenuItem *windowMenuItem;
874   - NSMenuItem *menuItem;
  913 + // Start the main event loop
  914 + [NSApp run];
875 915  
876   - windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
  916 + [appController release];
  917 + [pool release];
877 918  
878   - /* "Minimize" item */
879   - menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"];
880   - [windowMenu addItem:menuItem];
881   - [menuItem release];
  919 + return 0;
  920 +}
882 921  
883   - /* Put menu into the menubar */
884   - windowMenuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""];
885   - [windowMenuItem setSubmenu:windowMenu];
886   - [[NSApp mainMenu] addItem:windowMenuItem];
887 922  
888   - /* Tell the application object that this is now the window menu */
889   - [NSApp setWindowsMenu:windowMenu];
890 923  
891   - /* Finally give up our references to the objects */
892   - [windowMenu release];
893   - [windowMenuItem release];
  924 +#pragma mark qemu
  925 +static void cocoa_update(DisplayState *ds, int x, int y, int w, int h)
  926 +{
  927 + COCOA_DEBUG("qemu_cocoa: cocoa_update\n");
  928 +
  929 + NSRect rect;
  930 + if ([cocoaView cdx] == 1.0) {
  931 + rect = NSMakeRect(x, [cocoaView gscreen].height - y - h, w, h);
  932 + } else {
  933 + rect = NSMakeRect(
  934 + x * [cocoaView cdx],
  935 + ([cocoaView gscreen].height - y - h) * [cocoaView cdy],
  936 + w * [cocoaView cdx],
  937 + h * [cocoaView cdy]);
  938 + }
  939 + [cocoaView displayRect:rect];
894 940 }
895 941  
896   -static void CustomApplicationMain(void)
  942 +static void cocoa_resize(DisplayState *ds, int w, int h)
897 943 {
898   - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
899   - QemuCocoaGUIController *gui_controller;
900   - CPSProcessSerNum PSN;
  944 + COCOA_DEBUG("qemu_cocoa: cocoa_resize\n");
901 945  
902   - [NSApplication sharedApplication];
  946 + [cocoaView resizeContentToWidth:w height:h displayState:ds];
  947 +}
903 948  
904   - if (!CPSGetCurrentProcess(&PSN))
905   - if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103))
906   - if (!CPSSetFrontProcess(&PSN))
907   - [NSApplication sharedApplication];
  949 +static void cocoa_refresh(DisplayState *ds)
  950 +{
  951 + COCOA_DEBUG("qemu_cocoa: cocoa_refresh\n");
908 952  
909   - /* Set up the menubar */
910   - [NSApp setMainMenu:[[NSMenu alloc] init]];
911   - setApplicationMenu();
912   - setupWindowMenu();
  953 + if (kbd_mouse_is_absolute()) {
  954 + if (![cocoaView isAbsoluteEnabled]) {
  955 + if ([cocoaView isMouseGrabed]) {
  956 + [cocoaView ungrabMouse];
  957 + }
  958 + }
  959 + [cocoaView setAbsoluteEnabled:YES];
  960 + }
913 961  
914   - /* Create SDLMain and make it the app delegate */
915   - gui_controller = [[QemuCocoaGUIController alloc] init];
916   - [NSApp setDelegate:gui_controller];
  962 + NSDate *distantPast;
  963 + NSEvent *event;
  964 + distantPast = [NSDate distantPast];
  965 + do {
  966 + event = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:distantPast
  967 + inMode: NSDefaultRunLoopMode dequeue:YES];
  968 + if (event != nil) {
  969 + [cocoaView handleEvent:event];
  970 + }
  971 + } while(event != nil);
  972 + vga_hw_update();
  973 +}
917 974  
918   - /* Start the main event loop */
919   - [NSApp run];
  975 +static void cocoa_cleanup(void)
  976 +{
  977 + COCOA_DEBUG("qemu_cocoa: cocoa_cleanup\n");
920 978  
921   - [gui_controller release];
922   - [pool release];
923 979 }
924 980  
925   -/* Real main of qemu-cocoa */
926   -int main(int argc, char **argv)
  981 +void cocoa_display_init(DisplayState *ds, int full_screen)
927 982 {
928   - gArgc = argc;
929   - gArgv = argv;
  983 + COCOA_DEBUG("qemu_cocoa: cocoa_display_init\n");
  984 +
  985 + // register vga outpu callbacks
  986 + ds->dpy_update = cocoa_update;
  987 + ds->dpy_resize = cocoa_resize;
  988 + ds->dpy_refresh = cocoa_refresh;
930 989  
931   - CustomApplicationMain();
  990 + // give window a initial Size
  991 + cocoa_resize(ds, 640, 400);
932 992  
933   - return 0;
  993 + // register cleanup function
  994 + atexit(cocoa_cleanup);
934 995 }
... ...