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 * Permission is hereby granted, free of charge, to any person obtaining a copy 6 * 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 7 * of this software and associated documentation files (the "Software"), to deal
@@ -22,18 +21,6 @@ @@ -22,18 +21,6 @@
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE. 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 #import <Cocoa/Cocoa.h> 25 #import <Cocoa/Cocoa.h>
39 26
@@ -41,146 +28,41 @@ @@ -41,146 +28,41 @@
41 #include "console.h" 28 #include "console.h"
42 #include "sysemu.h" 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 #else 36 #else
172 - ds->bgr = 0; 37 +#define COCOA_DEBUG(...) ((void) 0)
173 #endif 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 int keymap[] = 66 int keymap[] =
185 { 67 {
186 // SdlI macI macH SdlH 104xtH 104xtC sdl 68 // SdlI macI macH SdlH 104xtH 104xtC sdl
@@ -289,7 +171,7 @@ int keymap[] = @@ -289,7 +171,7 @@ int keymap[] =
289 0, // 102 0x66 Undefined 171 0, // 102 0x66 Undefined
290 87, // 103 0x67 0x57 F11 QZ_F11 172 87, // 103 0x67 0x57 F11 QZ_F11
291 0, // 104 0x68 Undefined 173 0, // 104 0x68 Undefined
292 - 183,// 105 0x69 0xb7 QZ_PRINT 174 + 183,// 105 0x69 0xb7 QZ_PRINT
293 0, // 106 0x6A Undefined 175 0, // 106 0x6A Undefined
294 70, // 107 0x6B 0x46 SCROLL QZ_SCROLLOCK 176 70, // 107 0x6B 0x46 SCROLL QZ_SCROLLOCK
295 0, // 108 0x6C Undefined 177 0, // 108 0x6C Undefined
@@ -357,430 +239,566 @@ int cocoa_keycode_to_qemu(int keycode) @@ -357,430 +239,566 @@ int cocoa_keycode_to_qemu(int keycode)
357 return keymap[keycode]; 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 @end 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 - (void)startEmulationWithArgc:(int)argc argv:(char**)argv; 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 @end 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 [op beginSheetForDirectory:nil file:nil types:[NSArray arrayWithObjects:@"img",@"iso",@"dmg",@"qcow",@"cow",@"cloop",@"vmdk",nil] 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 didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:) contextInfo:NULL]; 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 - (void)applicationWillTerminate:(NSNotification *)aNotification 776 - (void)applicationWillTerminate:(NSNotification *)aNotification
766 { 777 {
767 - printf("Application will terminate\n"); 778 + COCOA_DEBUG("QemuCocoaAppController: applicationWillTerminate\n");
  779 +
768 qemu_system_shutdown_request(); 780 qemu_system_shutdown_request();
769 - /* In order to avoid a crash */  
770 exit(0); 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 - (void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo 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 char *bin = "qemu"; 800 char *bin = "qemu";
783 - char *img = (char*)[ [ sheet filename ] cString]; 801 + char *img = (char*)[ [ sheet filename ] cStringUsingEncoding:NSASCIIStringEncoding];
784 802
785 char **argv = (char**)malloc( sizeof(char*)*3 ); 803 char **argv = (char**)malloc( sizeof(char*)*3 );
786 804
@@ -793,24 +811,33 @@ static void QZ_SetPortAlphaOpaque () @@ -793,24 +811,33 @@ static void QZ_SetPortAlphaOpaque ()
793 [self startEmulationWithArgc:3 argv:(char**)argv]; 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 @end 836 @end
806 837
807 -/*  
808 - ------------------------------------------------------  
809 - Application Creation  
810 - ------------------------------------------------------  
811 -*/  
812 838
813 -/* Dock Connection */ 839 +
  840 +// Dock Connection
814 typedef struct CPSProcessSerNum 841 typedef struct CPSProcessSerNum
815 { 842 {
816 UInt32 lo; 843 UInt32 lo;
@@ -821,114 +848,148 @@ extern OSErr CPSGetCurrentProcess( CPSProcessSerNum *psn); @@ -821,114 +848,148 @@ extern OSErr CPSGetCurrentProcess( CPSProcessSerNum *psn);
821 extern OSErr CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5); 848 extern OSErr CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5);
822 extern OSErr CPSSetFrontProcess( CPSProcessSerNum *psn); 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 [[NSApp mainMenu] addItem:menuItem]; 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 }