21
22
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26
Todo : x miniaturize window
28
- save window position
29
- handle keyboard event
34
x simple graphical prompt to demo
35
- better graphical prompt
25
38
#import <Cocoa/Cocoa.h>
27
#include "qemu-common.h"
35
#define COCOA_DEBUG(...) { (void) fprintf (stdout, __VA_ARGS__); }
37
#define COCOA_DEBUG(...) ((void) 0)
40
#define cgrect(nsrect) (*(CGRect *)&(nsrect))
41
#define COCOA_MOUSE_EVENT \
42
if (isTabletEnabled) { \
43
kbd_mouse_event((int)(p.x * 0x7FFF / (screen.width - 1)), (int)((screen.height - p.y) * 0x7FFF / (screen.height - 1)), 0, buttons); \
44
} else if (isMouseGrabed) { \
45
kbd_mouse_event((int)[event deltaX], (int)[event deltaY], 0, buttons); \
47
[NSApp sendEvent:event]; \
57
int qemu_main(int argc, char **argv); // main defined in qemu/vl.c
58
NSWindow *normalWindow;
60
static void *screenBuffer;
42
NSWindow *window = NULL;
43
NSQuickDrawView *qd_view = NULL;
48
DisplayState current_ds;
51
int modifiers_state[256];
53
/* main defined in qemu/vl.c */
54
int qemu_main(int argc, char **argv);
56
/* To deal with miniaturization */
57
@interface QemuWindow : NSWindow
63
------------------------------------------------------
65
------------------------------------------------------
69
------------------------------------------------------
71
------------------------------------------------------
73
static void cocoa_update(DisplayState *ds, int x, int y, int w, int h)
75
//printf("updating x=%d y=%d w=%d h=%d\n", x, y, w, h);
77
/* Use QDFlushPortBuffer() to flush content to display */
78
RgnHandle dirty = NewRgn ();
79
RgnHandle temp = NewRgn ();
83
/* Build the region of dirty rectangles */
84
MacSetRectRgn (temp, x, y,
86
MacUnionRgn (dirty, temp, dirty);
88
/* Flush the dirty region */
89
QDFlushPortBuffer ( [ qd_view qdPort ], dirty );
95
------------------------------------------------------
97
------------------------------------------------------
99
static void cocoa_resize(DisplayState *ds, int w, int h)
101
const int device_bpp = 32;
102
static void *screen_pixels;
103
static int screen_pitch;
106
//printf("resizing to %d %d\n", w, h);
108
contentRect = NSMakeRect (0, 0, w, h);
114
window = [ [ QemuWindow alloc ] initWithContentRect:contentRect
115
styleMask:NSTitledWindowMask|NSMiniaturizableWindowMask|NSClosableWindowMask
116
backing:NSBackingStoreBuffered defer:NO];
119
fprintf(stderr, "(cocoa) can't create window\n");
126
qd_view = [ [ NSQuickDrawView alloc ] initWithFrame:contentRect ];
130
fprintf(stderr, "(cocoa) can't create qd_view\n");
134
[ window setAcceptsMouseMovedEvents:YES ];
135
[ window setTitle:@"Qemu" ];
136
[ window setReleasedWhenClosed:NO ];
138
/* Set screen to black */
139
[ window setBackgroundColor: [NSColor blackColor] ];
141
/* set window position */
144
[ qd_view setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable ];
145
[ [ window contentView ] addSubview:qd_view ];
147
[ window makeKeyAndOrderFront:nil ];
149
/* Careful here, the window seems to have to be onscreen to do that */
150
LockPortBits ( [ qd_view qdPort ] );
151
screen_pixels = GetPixBaseAddr ( GetPortPixMap ( [ qd_view qdPort ] ) );
152
screen_pitch = GetPixRowBytes ( GetPortPixMap ( [ qd_view qdPort ] ) );
153
UnlockPortBits ( [ qd_view qdPort ] );
155
int vOffset = [ window frame ].size.height -
156
[ qd_view frame ].size.height - [ qd_view frame ].origin.y;
158
int hOffset = [ qd_view frame ].origin.x;
160
screen_pixels += (vOffset * screen_pitch) + hOffset * (device_bpp/8);
162
ds->data = screen_pixels;
163
ds->linesize = screen_pitch;
164
ds->depth = device_bpp;
167
#ifdef __LITTLE_ENDIAN__
177
------------------------------------------------------
179
------------------------------------------------------
68
184
// SdlI macI macH SdlH 104xtH 104xtC sdl
239
355
return keymap[keycode];
245
359
------------------------------------------------------
247
361
------------------------------------------------------
249
@interface QemuCocoaView : NSView
252
NSWindow *fullScreenWindow;
253
float cx,cy,cw,ch,cdx,cdy;
254
CGDataProviderRef dataProviderRef;
255
int modifiers_state[256];
258
BOOL isAbsoluteEnabled;
259
BOOL isTabletEnabled;
261
- (void) resizeContentToWidth:(int)w height:(int)h displayState:(DisplayState *)ds;
263
- (void) ungrabMouse;
264
- (void) toggleFullScreen:(id)sender;
265
- (void) handleEvent:(NSEvent *)event;
266
- (void) setAbsoluteEnabled:(BOOL)tIsAbsoluteEnabled;
267
- (BOOL) isMouseGrabed;
268
- (BOOL) isAbsoluteEnabled;
271
- (QEMUScreen) gscreen;
274
@implementation QemuCocoaView
275
- (id)initWithFrame:(NSRect)frameRect
277
COCOA_DEBUG("QemuCocoaView: initWithFrame\n");
279
self = [super initWithFrame:frameRect];
282
screen.bitsPerComponent = 8;
283
screen.bitsPerPixel = 32;
284
screen.width = frameRect.size.width;
285
screen.height = frameRect.size.height;
293
COCOA_DEBUG("QemuCocoaView: dealloc\n");
299
CGDataProviderRelease(dataProviderRef);
304
- (void) drawRect:(NSRect) rect
306
COCOA_DEBUG("QemuCocoaView: drawRect\n");
308
if ((int)screenBuffer == -1)
311
// get CoreGraphic context
312
CGContextRef viewContextRef = [[NSGraphicsContext currentContext] graphicsPort];
313
CGContextSetInterpolationQuality (viewContextRef, kCGInterpolationNone);
314
CGContextSetShouldAntialias (viewContextRef, NO);
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,
328
CGColorSpaceCreateDeviceRGB(), //colorspace for OS X < 10.4 (actually ppc)
329
kCGImageAlphaNoneSkipFirst, //bitmapInfo
331
dataProviderRef, //provider
334
kCGRenderingIntentDefault //intent
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
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)
344
// selective drawing code (draws only dirty rectangles) (OS X >= 10.4)
345
const NSRect *rectList;
348
CGImageRef clipImageRef;
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(
361
CGContextDrawImage (viewContextRef, cgrect(rectList[i]), clipImageRef);
362
CGImageRelease (clipImageRef);
366
CGImageRelease (imageRef);
370
- (void) setContentDimensions
372
COCOA_DEBUG("QemuCocoaView: setContentDimensions\n");
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;
391
- (void) resizeContentToWidth:(int)w height:(int)h displayState:(DisplayState *)ds
393
COCOA_DEBUG("QemuCocoaView: resizeContent\n");
395
// update screenBuffer
397
CGDataProviderRelease(dataProviderRef);
400
screenBuffer = malloc( w * 4 * h );
402
ds->data = screenBuffer;
403
ds->linesize = (w * 4);
407
#ifdef __LITTLE_ENDIAN__
413
dataProviderRef = CGDataProviderCreateWithData(NULL, screenBuffer, w * 4 * h, NULL);
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];
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];
426
[self setContentDimensions];
427
[self setFrame:NSMakeRect(cx, cy, cw, ch)];
430
- (void) toggleFullScreen:(id)sender
432
COCOA_DEBUG("QemuCocoaView: toggleFullScreen\n");
434
if (isFullscreen) { // switch from fullscreen to desktop
435
isFullscreen = FALSE;
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];
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)
451
} else { // switch from desktop to fullscreen
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,
464
[NSMenu setMenuBarVisible:NO];
465
fullScreenWindow = [[NSWindow alloc] initWithContentRect:[[NSScreen mainScreen] frame]
466
styleMask:NSBorderlessWindowMask
467
backing:NSBackingStoreBuffered
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)
478
- (void) handleEvent:(NSEvent *)event
480
COCOA_DEBUG("QemuCocoaView: handleEvent\n");
484
NSPoint p = [event locationInWindow];
486
switch ([event type]) {
488
keycode = cocoa_keycode_to_qemu([event 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()) {
495
kbd_put_keycode(0xe0);
496
if (modifiers_state[keycode] == 0) { // keydown
497
kbd_put_keycode(keycode & 0x7f);
498
modifiers_state[keycode] = 1;
500
kbd_put_keycode(keycode | 0x80);
501
modifiers_state[keycode] = 0;
506
// release Mouse grab when pressing ctrl+alt
507
if (!isFullscreen && ([event modifierFlags] & NSControlKeyMask) && ([event modifierFlags] & NSAlternateKeyMask)) {
513
// forward command Key Combos
514
if ([event modifierFlags] & NSCommandKeyMask) {
515
[NSApp sendEvent:event];
520
keycode = cocoa_keycode_to_qemu([event keyCode]);
522
// handle control + alt Key Combos (ctrl+alt is reserved for QEMU)
523
if (([event modifierFlags] & NSControlKeyMask) && ([event modifierFlags] & NSAlternateKeyMask)) {
526
// enable graphic console
527
case 0x02 ... 0x0a: // '1' to '9' keys
528
console_select(keycode - 0x02);
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
538
// handlekeys for Monitor
541
switch([event keyCode]) {
543
keysym = QEMU_KEY_HOME;
546
keysym = QEMU_KEY_DELETE;
549
keysym = QEMU_KEY_END;
552
keysym = QEMU_KEY_LEFT;
555
keysym = QEMU_KEY_RIGHT;
558
keysym = QEMU_KEY_DOWN;
561
keysym = QEMU_KEY_UP;
565
NSString *ks = [event characters];
567
keysym = [ks characterAtIndex:0];
571
kbd_put_keysym(keysym);
575
keycode = cocoa_keycode_to_qemu([event keyCode]);
576
if (is_graphic_console()) {
578
kbd_put_keycode(0xe0);
579
kbd_put_keycode(keycode | 0x80); //add 128 to signal release of key
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
587
isTabletEnabled = FALSE;
590
if (!isTabletEnabled) { // if we enter the window, activate the tablet
363
static void cocoa_refresh(DisplayState *ds)
365
//printf("cocoa_refresh \n");
368
NSAutoreleasePool *pool;
370
pool = [ [ NSAutoreleasePool alloc ] init ];
371
distantPast = [ NSDate distantPast ];
376
event = [ NSApp nextEventMatchingMask:NSAnyEventMask untilDate:distantPast
377
inMode: NSDefaultRunLoopMode dequeue:YES ];
379
switch ([event type]) {
382
int keycode = cocoa_keycode_to_qemu([event keyCode]);
386
if (keycode == 58 || keycode == 69) {
387
/* emulate caps lock and num lock keydown and keyup */
388
kbd_put_keycode(keycode);
389
kbd_put_keycode(keycode | 0x80);
390
} else if (is_graphic_console()) {
392
kbd_put_keycode(0xe0);
393
if (modifiers_state[keycode] == 0) {
395
kbd_put_keycode(keycode & 0x7f);
396
modifiers_state[keycode] = 1;
399
kbd_put_keycode(keycode | 0x80);
400
modifiers_state[keycode] = 0;
405
/* release Mouse grab when pressing ctrl+alt */
406
if (([event modifierFlags] & NSControlKeyMask) && ([event modifierFlags] & NSAlternateKeyMask))
408
[window setTitle: @"QEMU"];
410
CGAssociateMouseAndMouseCursorPosition ( TRUE );
418
int keycode = cocoa_keycode_to_qemu([event keyCode]);
420
/* handle command Key Combos */
421
if ([event modifierFlags] & NSCommandKeyMask) {
422
switch ([event keyCode]) {
425
/* switch to windowed View */
431
/* handle control + alt Key Combos */
432
if (([event modifierFlags] & NSControlKeyMask) && ([event modifierFlags] & NSAlternateKeyMask)) {
435
case 0x02 ... 0x0a: /* '1' to '9' keys */
436
console_select(keycode - 0x02);
440
/* handle standard key events */
441
if (is_graphic_console()) {
442
if (keycode & 0x80) //check bit for e0 in front
443
kbd_put_keycode(0xe0);
444
kbd_put_keycode(keycode & 0x7f); //remove e0 bit in front
445
/* handle monitor key events */
449
switch([event keyCode]) {
451
keysym = QEMU_KEY_HOME;
454
keysym = QEMU_KEY_DELETE;
457
keysym = QEMU_KEY_END;
460
keysym = QEMU_KEY_LEFT;
463
keysym = QEMU_KEY_RIGHT;
466
keysym = QEMU_KEY_DOWN;
469
keysym = QEMU_KEY_UP;
473
NSString *ks = [event characters];
476
keysym = [ks characterAtIndex:0];
480
kbd_put_keysym(keysym);
488
int keycode = cocoa_keycode_to_qemu([event keyCode]);
489
if (is_graphic_console()) {
491
kbd_put_keycode(0xe0);
492
kbd_put_keycode(keycode | 0x80); //add 128 to signal release of key
499
int dx = [event deltaX];
500
int dy = [event deltaY];
501
int dz = [event deltaZ];
503
kbd_mouse_event(dx, dy, dz, buttons);
507
case NSLeftMouseDown:
511
/* leftclick+command simulates rightclick */
512
if ([event modifierFlags] & NSCommandKeyMask) {
513
buttons |= MOUSE_EVENT_RBUTTON;
515
buttons |= MOUSE_EVENT_LBUTTON;
517
kbd_mouse_event(0, 0, 0, buttons);
519
[NSApp sendEvent: event];
523
case NSLeftMouseDragged:
525
int dx = [event deltaX];
526
int dy = [event deltaY];
527
int dz = [event deltaZ];
529
if ([[NSApp currentEvent] modifierFlags] & NSCommandKeyMask) { //leftclick+command simulates rightclick
530
buttons |= MOUSE_EVENT_RBUTTON;
532
buttons |= MOUSE_EVENT_LBUTTON;
534
kbd_mouse_event(dx, dy, dz, buttons);
540
kbd_mouse_event(0, 0, 0, 0);
542
[window setTitle: @"QEMU (Press ctrl + alt to release Mouse)"];
592
isTabletEnabled = TRUE;
598
case NSLeftMouseDown:
599
if ([event modifierFlags] & NSCommandKeyMask) {
600
buttons |= MOUSE_EVENT_RBUTTON;
602
buttons |= MOUSE_EVENT_LBUTTON;
606
case NSRightMouseDown:
607
buttons |= MOUSE_EVENT_RBUTTON;
610
case NSOtherMouseDown:
611
buttons |= MOUSE_EVENT_MBUTTON;
614
case NSLeftMouseDragged:
615
if ([event modifierFlags] & NSCommandKeyMask) {
616
buttons |= MOUSE_EVENT_RBUTTON;
618
buttons |= MOUSE_EVENT_LBUTTON;
622
case NSRightMouseDragged:
623
buttons |= MOUSE_EVENT_RBUTTON;
626
case NSOtherMouseDragged:
627
buttons |= MOUSE_EVENT_MBUTTON;
631
if (isTabletEnabled) {
633
} else if (!isMouseGrabed) {
634
if (p.x > -1 && p.x < screen.width && p.y > -1 && p.y < screen.height) {
637
[NSApp sendEvent:event];
650
if (isTabletEnabled || isMouseGrabed) {
651
kbd_mouse_event(0, 0, -[event deltaY], 0);
653
[NSApp sendEvent:event];
657
[NSApp sendEvent:event];
663
COCOA_DEBUG("QemuCocoaView: grabMouse\n");
667
[normalWindow setTitle:[NSString stringWithFormat:@"QEMU %s - (Press ctrl + alt to release Mouse)", qemu_name]];
669
[normalWindow setTitle:@"QEMU - (Press ctrl + alt to release Mouse)"];
672
CGAssociateMouseAndMouseCursorPosition(FALSE);
673
isMouseGrabed = TRUE; // while isMouseGrabed = TRUE, QemuCocoaApp sends all events to [cocoaView handleEvent:]
678
COCOA_DEBUG("QemuCocoaView: ungrabMouse\n");
682
[normalWindow setTitle:[NSString stringWithFormat:@"QEMU %s", qemu_name]];
684
[normalWindow setTitle:@"QEMU"];
687
CGAssociateMouseAndMouseCursorPosition(TRUE);
688
isMouseGrabed = FALSE;
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;}
544
CGAssociateMouseAndMouseCursorPosition ( FALSE );
546
//[NSApp sendEvent: event];
550
case NSRightMouseDown:
554
buttons |= MOUSE_EVENT_RBUTTON;
555
kbd_mouse_event(0, 0, 0, buttons);
557
[NSApp sendEvent: event];
561
case NSRightMouseDragged:
563
int dx = [event deltaX];
564
int dy = [event deltaY];
565
int dz = [event deltaZ];
567
buttons |= MOUSE_EVENT_RBUTTON;
568
kbd_mouse_event(dx, dy, dz, buttons);
574
kbd_mouse_event(0, 0, 0, 0);
576
[NSApp sendEvent: event];
580
case NSOtherMouseDragged:
582
int dx = [event deltaX];
583
int dy = [event deltaY];
584
int dz = [event deltaZ];
586
buttons |= MOUSE_EVENT_MBUTTON;
587
kbd_mouse_event(dx, dy, dz, buttons);
591
case NSOtherMouseDown:
594
buttons |= MOUSE_EVENT_MBUTTON;
595
kbd_mouse_event(0, 0, 0, buttons);
597
[NSApp sendEvent:event];
603
kbd_mouse_event(0, 0, 0, 0);
605
[NSApp sendEvent: event];
611
int dz = [event deltaY];
612
kbd_mouse_event(0, 0, -dz, 0);
616
default: [NSApp sendEvent:event];
619
} while(event != nil);
623
------------------------------------------------------
625
------------------------------------------------------
628
static void cocoa_cleanup(void)
634
------------------------------------------------------
636
------------------------------------------------------
639
void cocoa_display_init(DisplayState *ds, int full_screen)
641
ds->dpy_update = cocoa_update;
642
ds->dpy_resize = cocoa_resize;
643
ds->dpy_refresh = cocoa_refresh;
645
cocoa_resize(ds, 640, 400);
647
atexit(cocoa_cleanup);
651
------------------------------------------------------
653
------------------------------------------------------
658
------------------------------------------------------
660
Some trick from SDL to use miniwindow
661
------------------------------------------------------
663
static void QZ_SetPortAlphaOpaque ()
665
/* Assume 32 bit if( bpp == 32 )*/
668
uint32_t *pixels = (uint32_t*) current_ds.data;
669
uint32_t rowPixels = current_ds.linesize / 4;
672
for (i = 0; i < current_ds.height; i++)
673
for (j = 0; j < current_ds.width; j++) {
675
pixels[ (i * rowPixels) + j ] |= 0xFF000000;
680
@implementation QemuWindow
681
- (void)miniaturize:(id)sender
684
/* make the alpha channel opaque so anim won't have holes in it */
685
QZ_SetPortAlphaOpaque ();
687
[ super miniaturize:sender ];
693
This method fires just before the window deminaturizes from the Dock.
695
We'll save the current visible surface, let the window manager redraw any
696
UI elements, and restore the SDL surface. This way, no expose event
697
is required, and the deminiaturize works perfectly.
700
/* make sure pixels are fully opaque */
701
QZ_SetPortAlphaOpaque ();
703
/* save current visible SDL surface */
704
[ self cacheImageInRect:[ qd_view frame ] ];
706
/* let the window manager redraw controls, border, etc */
709
/* restore visible SDL surface */
710
[ self restoreCachedImage ];
702
717
------------------------------------------------------
703
QemuCocoaAppController
718
QemuCocoaGUIController
719
NSApp's delegate - indeed main object
704
720
------------------------------------------------------
706
@interface QemuCocoaAppController : NSObject
723
@interface QemuCocoaGUIController : NSObject
726
- (void)applicationDidFinishLaunching: (NSNotification *) note;
727
- (void)applicationWillTerminate:(NSNotification *)aNotification;
729
- (void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo;
709
731
- (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;
716
@implementation QemuCocoaAppController
719
COCOA_DEBUG("QemuCocoaAppController: init\n");
724
// create a view and add it to the window
725
cocoaView = [[QemuCocoaView alloc] initWithFrame:NSMakeRect(0.0, 0.0, 640.0, 480.0)];
727
fprintf(stderr, "(cocoa) can't create a view\n");
732
normalWindow = [[NSWindow alloc] initWithContentRect:[cocoaView frame]
733
styleMask:NSTitledWindowMask|NSMiniaturizableWindowMask|NSClosableWindowMask
734
backing:NSBackingStoreBuffered defer:NO];
736
fprintf(stderr, "(cocoa) can't create window\n");
739
[normalWindow setAcceptsMouseMovedEvents:YES];
740
[normalWindow setTitle:[NSString stringWithFormat:@"QEMU"]];
741
[normalWindow setContentView:cocoaView];
742
[normalWindow makeKeyAndOrderFront:self];
750
COCOA_DEBUG("QemuCocoaAppController: dealloc\n");
734
@implementation QemuCocoaGUIController
735
/* Called when the internal event loop has just started running */
757
736
- (void)applicationDidFinishLaunching: (NSNotification *) note
759
COCOA_DEBUG("QemuCocoaAppController: applicationDidFinishLaunching\n");
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) {
739
/* Display an open dialog box if no argument were passed or
740
if qemu was launched from the finder ( the Finder passes "-psn" ) */
742
if( gArgc <= 1 || strncmp (gArgv[1], "-psn", 4) == 0)
764
744
NSOpenPanel *op = [[NSOpenPanel alloc] init];
746
cocoa_resize(¤t_ds, 640, 400);
765
748
[op setPrompt:@"Boot image"];
766
750
[op setMessage:@"Select the disk image you want to boot.\n\nHit the \"Cancel\" button to quit"];
767
752
[op beginSheetForDirectory:nil file:nil types:[NSArray arrayWithObjects:@"img",@"iso",@"dmg",@"qcow",@"cow",@"cloop",@"vmdk",nil]
768
modalForWindow:normalWindow modalDelegate:self
753
modalForWindow:window modalDelegate:self
769
754
didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:) contextInfo:NULL];
771
// or Launch Qemu, with the global args
772
[self startEmulationWithArgc:gArgc argv:(char **)gArgv];
758
/* or Launch Qemu, with the global args */
759
[self startEmulationWithArgc:gArgc argv:gArgv];
776
763
- (void)applicationWillTerminate:(NSNotification *)aNotification
778
COCOA_DEBUG("QemuCocoaAppController: applicationWillTerminate\n");
765
printf("Application will terminate\n");
780
766
qemu_system_shutdown_request();
767
/* In order to avoid a crash */
784
- (void)startEmulationWithArgc:(int)argc argv:(char**)argv
786
COCOA_DEBUG("QemuCocoaAppController: startEmulationWithArgc\n");
789
status = qemu_main(argc, argv);
793
771
- (void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
795
COCOA_DEBUG("QemuCocoaAppController: openPanelDidEnd\n");
797
if(returnCode == NSCancelButton) {
773
if(returnCode == NSCancelButton)
799
} else if(returnCode == NSOKButton) {
778
if(returnCode == NSOKButton)
800
780
char *bin = "qemu";
801
char *img = (char*)[ [ sheet filename ] cStringUsingEncoding:NSASCIIStringEncoding];
781
char *img = (char*)[ [ sheet filename ] cString];
803
783
char **argv = (char**)malloc( sizeof(char*)*3 );
805
785
asprintf(&argv[0], "%s", bin);
806
786
asprintf(&argv[1], "-hda");
807
787
asprintf(&argv[2], "%s", img);
809
789
printf("Using argc %d argv %s -hda %s\n", 3, bin, img);
811
791
[self startEmulationWithArgc:3 argv:(char**)argv];
814
- (void)toggleFullScreen:(id)sender
816
COCOA_DEBUG("QemuCocoaAppController: toggleFullScreen\n");
818
[cocoaView toggleFullScreen:sender];
821
- (void)showQEMUDoc:(id)sender
823
COCOA_DEBUG("QemuCocoaAppController: showQEMUDoc\n");
825
[[NSWorkspace sharedWorkspace] openFile:[NSString stringWithFormat:@"%@/../doc/qemu/qemu-doc.html",
826
[[NSBundle mainBundle] resourcePath]] withApplication:@"Help Viewer"];
829
- (void)showQEMUTec:(id)sender
831
COCOA_DEBUG("QemuCocoaAppController: showQEMUTec\n");
833
[[NSWorkspace sharedWorkspace] openFile:[NSString stringWithFormat:@"%@/../doc/qemu/qemu-tech.html",
834
[[NSBundle mainBundle] resourcePath]] withApplication:@"Help Viewer"];
795
- (void)startEmulationWithArgc:(int)argc argv:(char**)argv
799
printf("starting qemu...\n");
800
status = qemu_main (argc, argv);
806
------------------------------------------------------
808
------------------------------------------------------
811
/* Dock Connection */
841
812
typedef struct CPSProcessSerNum
848
819
extern OSErr CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5);
849
820
extern OSErr CPSSetFrontProcess( CPSProcessSerNum *psn);
851
int main (int argc, const char * argv[]) {
854
gArgv = (char **)argv;
823
static void setApplicationMenu(void)
825
/* warning: this code is very odd */
827
NSMenuItem *menuItem;
832
appleMenu = [[NSMenu alloc] initWithTitle:@""];
835
title = [@"About " stringByAppendingString:appName];
836
[appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""];
838
[appleMenu addItem:[NSMenuItem separatorItem]];
840
title = [@"Hide " stringByAppendingString:appName];
841
[appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"];
843
menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"];
844
[menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)];
846
[appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""];
848
[appleMenu addItem:[NSMenuItem separatorItem]];
850
title = [@"Quit " stringByAppendingString:appName];
851
[appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"];
854
/* Put menu into the menubar */
855
menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""];
856
[menuItem setSubmenu:appleMenu];
857
[[NSApp mainMenu] addItem:menuItem];
859
/* Tell the application object that this is now the application menu */
860
[NSApp setAppleMenu:appleMenu];
862
/* Finally give up our references to the objects */
867
/* Create a window menu */
868
static void setupWindowMenu(void)
871
NSMenuItem *windowMenuItem;
872
NSMenuItem *menuItem;
874
windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
876
/* "Minimize" item */
877
menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"];
878
[windowMenu addItem:menuItem];
881
/* Put menu into the menubar */
882
windowMenuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""];
883
[windowMenuItem setSubmenu:windowMenu];
884
[[NSApp mainMenu] addItem:windowMenuItem];
886
/* Tell the application object that this is now the window menu */
887
[NSApp setWindowsMenu:windowMenu];
889
/* Finally give up our references to the objects */
890
[windowMenu release];
891
[windowMenuItem release];
894
static void CustomApplicationMain(void)
896
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
897
QemuCocoaGUIController *gui_controller;
855
898
CPSProcessSerNum PSN;
857
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
858
900
[NSApplication sharedApplication];
860
902
if (!CPSGetCurrentProcess(&PSN))
861
903
if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103))
862
904
if (!CPSSetFrontProcess(&PSN))
863
905
[NSApplication sharedApplication];
867
NSMenuItem *menuItem;
907
/* Set up the menubar */
869
908
[NSApp setMainMenu:[[NSMenu alloc] init]];
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+)
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];
891
[[NSApp mainMenu] addItem:menuItem];
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];
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];
909
// Create an Application controller
910
QemuCocoaAppController *appController = [[QemuCocoaAppController alloc] init];
911
[NSApp setDelegate:appController];
913
// Start the main event loop
909
setApplicationMenu();
912
/* Create SDLMain and make it the app delegate */
913
gui_controller = [[QemuCocoaGUIController alloc] init];
914
[NSApp setDelegate:gui_controller];
916
/* Start the main event loop */
916
[appController release];
919
[gui_controller release];
923
/* Real main of qemu-cocoa */
924
int main(int argc, char **argv)
929
CustomApplicationMain();
925
static void cocoa_update(DisplayState *ds, int x, int y, int w, int h)
927
COCOA_DEBUG("qemu_cocoa: cocoa_update\n");
930
if ([cocoaView cdx] == 1.0) {
931
rect = NSMakeRect(x, [cocoaView gscreen].height - y - h, w, h);
935
([cocoaView gscreen].height - y - h) * [cocoaView cdy],
937
h * [cocoaView cdy]);
939
[cocoaView displayRect:rect];
942
static void cocoa_resize(DisplayState *ds, int w, int h)
944
COCOA_DEBUG("qemu_cocoa: cocoa_resize\n");
946
[cocoaView resizeContentToWidth:w height:h displayState:ds];
949
static void cocoa_refresh(DisplayState *ds)
951
COCOA_DEBUG("qemu_cocoa: cocoa_refresh\n");
953
if (kbd_mouse_is_absolute()) {
954
if (![cocoaView isAbsoluteEnabled]) {
955
if ([cocoaView isMouseGrabed]) {
956
[cocoaView ungrabMouse];
959
[cocoaView setAbsoluteEnabled:YES];
964
distantPast = [NSDate distantPast];
966
event = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:distantPast
967
inMode: NSDefaultRunLoopMode dequeue:YES];
969
[cocoaView handleEvent:event];
971
} while(event != nil);
975
static void cocoa_cleanup(void)
977
COCOA_DEBUG("qemu_cocoa: cocoa_cleanup\n");
981
void cocoa_display_init(DisplayState *ds, int full_screen)
983
COCOA_DEBUG("qemu_cocoa: cocoa_display_init\n");
985
// register vga outpu callbacks
986
ds->dpy_update = cocoa_update;
987
ds->dpy_resize = cocoa_resize;
988
ds->dpy_refresh = cocoa_refresh;
990
// give window a initial Size
991
cocoa_resize(ds, 640, 400);
993
// register cleanup function
994
atexit(cocoa_cleanup);