Patchwork [12/48] cocoa frontend changes

login
register
mail settings
Submitter Riku Voipio
Date March 26, 2010, 4:06 p.m.
Message ID <823ddb55e1f7bbe419dd8a48da4bc30b689a4259.1269617186.git.riku.voipio@nokia.com>
Download mbox | patch
Permalink /patch/48687/
State New
Headers show

Comments

Riku Voipio - March 26, 2010, 4:06 p.m.
From: Juha Riihimäki <juha.riihimaki@nokia.com>

remove help menu, fix fullscreen mode mouse handling, add confirmation
dialog to quit menu command, add support for undocumented alt-grab and
ctrl-grab options, add qemu version printout in about panel.
- fix build on os x versions prior to 10.6
- cocoa window handling fixes
- show shutting down status in window caption
- add display close handler support
- add support for multitouch in cocoa frontend
- cocoa keymap changes

Signed-Off-By: Riku Voipio <riku.voipio@nokia.com>
Signed-off-by: Juha Riihimäki <juha.riihimaki@nokia.com>
---
 cocoa.m |  313 +++++++++++++++++++++++++++++++++++++++++++-------------------
 1 files changed, 217 insertions(+), 96 deletions(-)
Andreas Färber - March 27, 2010, 1:28 p.m.
Hello,

Am 26.03.2010 um 17:06 schrieb Riku Voipio:

> From: Juha Riihimäki <juha.riihimaki@nokia.com>
> 
> remove help menu, fix fullscreen mode mouse handling, add confirmation
> dialog to quit menu command, add support for undocumented alt-grab and
> ctrl-grab options, add qemu version printout in about panel.
> - fix build on os x versions prior to 10.6
> - cocoa window handling fixes
> - show shutting down status in window caption
> - add display close handler support
> - add support for multitouch in cocoa frontend
> - cocoa keymap changes

I would appreciate if you could untangle these for review by splitting this patch up.
Last time I built on 10.5/ppc there were no build issues in Cocoa, for instance.

Further comment inline.

> 
> Signed-Off-By: Riku Voipio <riku.voipio@nokia.com>
> Signed-off-by: Juha Riihimäki <juha.riihimaki@nokia.com>
> ---
> cocoa.m |  313 +++++++++++++++++++++++++++++++++++++++++++-------------------
> 1 files changed, 217 insertions(+), 96 deletions(-)
> 
> diff --git a/cocoa.m b/cocoa.m
> index 56c789a..524617f 100644
> --- a/cocoa.m
> +++ b/cocoa.m
> @@ -47,10 +47,25 @@
> #define cgrect(nsrect) (*(CGRect *)&(nsrect))
> #define COCOA_MOUSE_EVENT \

Since this macro is growing large, could you consider turning it into a static inline function please?

Regards,
Andreas

>         if (isTabletEnabled) { \
> -            kbd_mouse_event((int)(p.x * 0x7FFF / (screen.width - 1)), (int)((screen.height - p.y) * 0x7FFF / (screen.height - 1)), 0, buttons); \
> +            if (isFullscreen) { \
> +                NSSize fs = [[NSScreen mainScreen] frame].size; \
> +                kbd_mouse_event((int)(p.x * 0x7FFF / (fs.width - 1)), \
> +                                (int)((fs.height - p.y) * 0x7FFF / (fs.height - 1)), \
> +                                0, buttons); \
> +            } else { \
> +                kbd_mouse_event((int)(p.x * 0x7FFF / (screen.width - 1)), \
> +                                (int)((screen.height - p.y) * 0x7FFF / (screen.height - 1)), \
> +                                0, buttons); \
> +            } \
>         } else if (isMouseGrabed) { \
>             kbd_mouse_event((int)[event deltaX], (int)[event deltaY], 0, buttons); \
>         } else { \
> +            if (isFullscreen) { \
> +                NSSize fs = [[NSScreen mainScreen] frame].size; \
> +                kbd_mouse_event((int)(p.x * 0x7FFF / (fs.width - 1)), \
> +                                (int)((fs.height - p.y) * 0x7FFF / (fs.height - 1)), \
> +                                0, buttons); \
> +            } \
>             [NSApp sendEvent:event]; \
>         }
> 
> @@ -65,6 +80,7 @@ int qemu_main(int argc, char **argv); // main defined in qemu/vl.c
> NSWindow *normalWindow;
> id cocoaView;
> static DisplayChangeListener *dcl;
> +static int last_vm_running;
> 
> int gArgc;
> char **gArgv;
> @@ -83,7 +99,7 @@ int keymap[] =
>     45, //  7       0x07    0x2d            X       QZ_x
>     46, //  8       0x08    0x2e            C       QZ_c
>     47, //  9       0x09    0x2f            V       QZ_v
> -    0,  //  10      0x0A    Undefined
> +    0,  //  10      0x0A    Undefined       (paragraph)
>     48, //  11      0x0B    0x30            B       QZ_b
>     16, //  12      0x0C    0x10            Q       QZ_q
>     17, //  13      0x0D    0x11            W       QZ_w
> @@ -127,8 +143,8 @@ int keymap[] =
>     14, //  51      0x33    0x0e            BKSP    QZ_BACKSPACE
>     0,  //  52      0x34    Undefined
>     1,  //  53      0x35    0x01            ESC     QZ_ESCAPE
> -    0,  //  54      0x36                            QZ_RMETA
> -    0,  //  55      0x37                            QZ_LMETA
> +    220,//  54      0xdc            e0,5c   R GUI   QZ_RMETA
> +    219,//  55      0xdb            e0,5b   L GUI   QZ_LMETA
>     42, //  56      0x38    0x2a            L SHFT  QZ_LSHIFT
>     58, //  57      0x39    0x3a            CAPS    QZ_CAPSLOCK
>     56, //  58      0x3A    0x38            L ALT   QZ_LALT
> @@ -136,9 +152,9 @@ int keymap[] =
>     54, //  60      0x3C    0x36            R SHFT  QZ_RSHIFT
>     184,//  61      0x3D    0xb8    E0,38   R ALT   QZ_RALT
>     157,//  62      0x3E    0x9d    E0,1D   R CTRL  QZ_RCTRL
> -    0,  //  63      0x3F    Undefined
> -    0,  //  64      0x40    Undefined
> -    0,  //  65      0x41    Undefined
> +    0,  //  63      0x3F    Undefined       (fn)
> +    0,  //  64      0x40    Undefined       (f17)
> +    83, //  65      0x53    0x53            KP .
>     0,  //  66      0x42    Undefined
>     55, //  67      0x43    0x37            KP *    QZ_KP_MULTIPLY
>     0,  //  68      0x44    Undefined
> @@ -152,9 +168,9 @@ int keymap[] =
>     152,//  76      0x4C    0x9c    E0,1C   KP EN   QZ_KP_ENTER
>     0,  //  77      0x4D    undefined
>     74, //  78      0x4E    0x4a            KP -    QZ_KP_MINUS
> -    0,  //  79      0x4F    Undefined
> -    0,  //  80      0x50    Undefined
> -    0,  //  81      0x51                            QZ_KP_EQUALS
> +    0,  //  79      0x4F    Undefined       (f18)
> +    0,  //  80      0x50    Undefined       (f19)
> +    0,  //  81      0x51                    (kp =)  QZ_KP_EQUALS
>     82, //  82      0x52    0x52            KP 0    QZ_KP0
>     79, //  83      0x53    0x4f            KP 1    QZ_KP1
>     80, //  84      0x54    0x50            KP 2    QZ_KP2
> @@ -178,15 +194,15 @@ int keymap[] =
>     0,  //  102     0x66    Undefined
>     87, //  103     0x67    0x57            F11     QZ_F11
>     0,  //  104     0x68    Undefined
> -    183,//  105     0x69    0xb7                    QZ_PRINT
> +    183,//  105     0x69    0xb7            (f13)   QZ_PRINT
>     0,  //  106     0x6A    Undefined
> -    70, //  107     0x6B    0x46            SCROLL  QZ_SCROLLOCK
> +    70, //  107     0x6B    0x46            SCROLL(f14)  QZ_SCROLLOCK
>     0,  //  108     0x6C    Undefined
>     68, //  109     0x6D    0x44            F10     QZ_F10
>     0,  //  110     0x6E    Undefined
>     88, //  111     0x6F    0x58            F12     QZ_F12
>     0,  //  112     0x70    Undefined
> -    110,//  113     0x71    0x0                     QZ_PAUSE
> +    110,//  113     0x71    0x0             (f15)   QZ_PAUSE
>     210,//  114     0x72    0xd2    E0,52   INSERT  QZ_INSERT
>     199,//  115     0x73    0xc7    E0,47   HOME    QZ_HOME
>     201,//  116     0x74    0xc9    E0,49   PG UP   QZ_PAGEUP
> @@ -204,12 +220,9 @@ int keymap[] =
> 
> /* Aditional 104 Key XP-Keyboard Scancodes from http://www.computer-engineering.org/ps2keyboard/scancodes1.html */
> /*
> -    219 //          0xdb            e0,5b   L GUI
> -    220 //          0xdc            e0,5c   R GUI
>     221 //          0xdd            e0,5d   APPS
>         //              E0,2A,E0,37         PRNT SCRN
>         //              E1,1D,45,E1,9D,C5   PAUSE
> -    83  //          0x53    0x53            KP .
> // ACPI Scan Codes
>     222 //          0xde            E0, 5E  Power
>     223 //          0xdf            E0, 5F  Sleep
> @@ -259,23 +272,29 @@ static int cocoa_keycode_to_qemu(int keycode)
>     NSWindow *fullScreenWindow;
>     float cx,cy,cw,ch,cdx,cdy;
>     CGDataProviderRef dataProviderRef;
> +    void *dataRawPtr;
> +    int mouseX, mouseY;
>     int modifiers_state[256];
>     BOOL isMouseGrabed;
>     BOOL isFullscreen;
>     BOOL isAbsoluteEnabled;
>     BOOL isTabletEnabled;
> +    BOOL isShuttingDownGuest;
> }
> - (void) resizeContentToWidth:(int)w height:(int)h displayState:(DisplayState *)ds;
> - (void) grabMouse;
> - (void) ungrabMouse;
> - (void) toggleFullScreen:(id)sender;
> -- (void) handleEvent:(NSEvent *)event;
> +- (void) qemuHandleEvent:(NSEvent *)event;
> - (void) setAbsoluteEnabled:(BOOL)tIsAbsoluteEnabled;
> +- (void) setShuttingDownGuest;
> - (BOOL) isMouseGrabed;
> - (BOOL) isAbsoluteEnabled;
> - (float) cdx;
> - (float) cdy;
> - (QEMUScreen) gscreen;
> +- (void) updateCaption;
> +- (void) checkAndDisplayAltCursor;
> @end
> 
> @implementation QemuCocoaView
> @@ -310,6 +329,34 @@ static int cocoa_keycode_to_qemu(int keycode)
>     return YES;
> }
> 
> +- (void) checkAndDisplayAltCursor
> +{
> +    if (multitouch_enabled && !isMouseGrabed && !cursor_hide &&
> +        dataRawPtr && modifiers_state[56]) {
> +        unsigned char *p = (unsigned char *)dataRawPtr;
> +        int altX = screen.width - mouseX;
> +        int altY = mouseY;
> +        int x, y;
> +        int bytesperpixel = screen.bitsPerPixel / 8;
> +        p += (altY * screen.width) * bytesperpixel;
> +        for (y = 0; y < 8; y++) {
> +            if (y + altY > 0 && y + altY < screen.height) {
> +                unsigned char *q = p + altX * bytesperpixel;
> +                for (x = 0; x < 8; x++) {
> +                    if (x + altX > 0 && x + altX < screen.width) {
> +                        int i;
> +                        for (i = 0; i < bytesperpixel; i++) {
> +                            q[i] ^= 0xff;
> +                        }
> +                    }
> +                    q += bytesperpixel;
> +                }
> +            }
> +            p += screen.width * bytesperpixel;
> +        }
> +    }
> +}
> +
> - (void) drawRect:(NSRect) rect
> {
>     COCOA_DEBUG("QemuCocoaView: drawRect\n");
> @@ -321,6 +368,7 @@ static int cocoa_keycode_to_qemu(int keycode)
> 
>     // draw screen bitmap directly to Core Graphics context
>     if (dataProviderRef) {
> +        [self checkAndDisplayAltCursor];
>         CGImageRef imageRef = CGImageCreate(
>             screen.width, //width
>             screen.height, //height
> @@ -360,10 +408,10 @@ static int cocoa_keycode_to_qemu(int keycode)
> 
>             [self getRectsBeingDrawn:&rectList count:&rectCount];
>             for (i = 0; i < rectCount; i++) {
> -                clipRect.origin.x = rectList[i].origin.x / cdx;
> -                clipRect.origin.y = (float)screen.height - (rectList[i].origin.y + rectList[i].size.height) / cdy;
> -                clipRect.size.width = rectList[i].size.width / cdx;
> -                clipRect.size.height = rectList[i].size.height / cdy;
> +                clipRect.origin.x = floorf(rectList[i].origin.x / cdx);
> +                clipRect.origin.y = floorf((float)screen.height - (rectList[i].origin.y + rectList[i].size.height) / cdy);
> +                clipRect.size.width = ceilf(rectList[i].size.width / cdx);
> +                clipRect.size.height = ceilf(rectList[i].size.height / cdy);
>                 clipImageRef = CGImageCreateWithImageInRect(
>                     imageRef,
>                     clipRect
> @@ -410,6 +458,7 @@ static int cocoa_keycode_to_qemu(int keycode)
> 	screen.bitsPerPixel = ds_get_bits_per_pixel(ds);
> 	screen.bitsPerComponent = ds_get_bytes_per_pixel(ds) * 2;
> 
> +    dataRawPtr = is_graphic_console() ? ds_get_data(ds) : 0;
>     dataProviderRef = CGDataProviderCreateWithData(NULL, ds_get_data(ds), w * 4 * h, NULL);
> 
>     // update windows
> @@ -417,10 +466,9 @@ static int cocoa_keycode_to_qemu(int keycode)
>         [[fullScreenWindow contentView] setFrame:[[NSScreen mainScreen] frame]];
>         [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];
>     } else {
> -        if (qemu_name)
> -            [normalWindow setTitle:[NSString stringWithFormat:@"QEMU %s", qemu_name]];
>         [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:NO];
>     }
> +    [self updateCaption];
>     screen.width = w;
>     screen.height = h;
> 	[normalWindow center];
> @@ -434,7 +482,7 @@ static int cocoa_keycode_to_qemu(int keycode)
> 
>     if (isFullscreen) { // switch from fullscreen to desktop
>         isFullscreen = FALSE;
> -        [self ungrabMouse];
> +        if (isMouseGrabed) [self ungrabMouse];
>         [self setContentDimensions];
> // test if host supports "exitFullScreenModeWithOptions" at compile time
> #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
> @@ -444,29 +492,33 @@ static int cocoa_keycode_to_qemu(int keycode)
> #endif
>             [fullScreenWindow close];
>             [normalWindow setContentView: self];
> -            [normalWindow makeKeyAndOrderFront: self];
>             [NSMenu setMenuBarVisible:YES];
> #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
>         }
> #endif
> +        [normalWindow makeKeyAndOrderFront:self];
>     } else { // switch from desktop to fullscreen
>         isFullscreen = TRUE;
> -        [self grabMouse];
> +        if (cursor_allow_grab) [self grabMouse];
>         [self setContentDimensions];
> +        [normalWindow orderOut:self];
> // test if host supports "enterFullScreenMode:withOptions" at compile time
> #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
>         if ([NSView respondsToSelector:@selector(enterFullScreenMode:withOptions:)]) { // test if "enterFullScreenMode:withOptions" is supported on host at runtime
> -            [self enterFullScreenMode:[NSScreen mainScreen] withOptions:[NSDictionary dictionaryWithObjectsAndKeys:
> -                [NSNumber numberWithBool:NO], NSFullScreenModeAllScreens,
> -                [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:NO], kCGDisplayModeIsStretched, nil], NSFullScreenModeSetting,
> -                 nil]];
> +            [self enterFullScreenMode:[NSScreen mainScreen]
> +                          withOptions:[NSDictionary dictionaryWithObjectsAndKeys:
> +                                       [NSNumber numberWithBool:NO], NSFullScreenModeAllScreens,
> +                                       [NSDictionary dictionaryWithObjectsAndKeys:
> +                                        [NSNumber numberWithBool:NO], kCGDisplayModeIsStretched,
> +                                        nil], NSFullScreenModeSetting,
> +                                       nil]];
>         } else {
> #endif
>             [NSMenu setMenuBarVisible:NO];
>             fullScreenWindow = [[NSWindow alloc] initWithContentRect:[[NSScreen mainScreen] frame]
> -                styleMask:NSBorderlessWindowMask
> -                backing:NSBackingStoreBuffered
> -                defer:NO];
> +                                                           styleMask:NSBorderlessWindowMask
> +                                                             backing:NSBackingStoreBuffered
> +                                                               defer:NO];
>             [fullScreenWindow setHasShadow:NO];
>             [fullScreenWindow setContentView:self];
>             [fullScreenWindow makeKeyAndOrderFront:self];
> @@ -476,7 +528,7 @@ static int cocoa_keycode_to_qemu(int keycode)
>     }
> }
> 
> -- (void) handleEvent:(NSEvent *)event
> +- (void) qemuHandleEvent:(NSEvent *)event
> {
>     COCOA_DEBUG("QemuCocoaView: handleEvent\n");
> 
> @@ -505,8 +557,13 @@ static int cocoa_keycode_to_qemu(int keycode)
>             }
> 
>             // release Mouse grab when pressing ctrl+alt
> -            if (!isFullscreen && ([event modifierFlags] & NSControlKeyMask) && ([event modifierFlags] & NSAlternateKeyMask)) {
> -                [self ungrabMouse];
> +            if (!isFullscreen) {
> +                if ((ctrl_grab && [event keyCode] == 0x3e)
> +                    || ((([event modifierFlags] & NSControlKeyMask) &&
> +                         ([event modifierFlags] & NSAlternateKeyMask))
> +                        && (!alt_grab || ([event modifierFlags] & NSShiftKeyMask)))) {
> +                    [self ungrabMouse];
> +                }
>             }
>             break;
>         case NSKeyDown:
> @@ -581,15 +638,17 @@ static int cocoa_keycode_to_qemu(int keycode)
>             }
>             break;
>         case NSMouseMoved:
> +            mouseX = p.x;
> +            mouseY = p.y;
>             if (isAbsoluteEnabled) {
>                 if (p.x < 0 || p.x > screen.width || p.y < 0 || p.y > screen.height || ![[self window] isKeyWindow]) {
>                     if (isTabletEnabled) { // if we leave the window, deactivate the tablet
> -                        [NSCursor unhide];
> +                        if (cursor_hide) [NSCursor unhide];
>                         isTabletEnabled = FALSE;
>                     }
>                 } else {
>                     if (!isTabletEnabled) { // if we enter the window, activate the tablet
> -                        [NSCursor hide];
> +                        if (cursor_hide) [NSCursor hide];
>                         isTabletEnabled = TRUE;
>                     }
>                 }
> @@ -602,6 +661,9 @@ static int cocoa_keycode_to_qemu(int keycode)
>             } else {
>                 buttons |= MOUSE_EVENT_LBUTTON;
>             }
> +            if ([event modifierFlags] & NSAlternateKeyMask) {
> +                buttons |= MOUSE_EVENT_MBUTTON << 1;
> +            }
>             COCOA_MOUSE_EVENT
>             break;
>         case NSRightMouseDown:
> @@ -613,11 +675,16 @@ static int cocoa_keycode_to_qemu(int keycode)
>             COCOA_MOUSE_EVENT
>             break;
>         case NSLeftMouseDragged:
> +            mouseX = p.x;
> +            mouseY = p.y;
>             if ([event modifierFlags] & NSCommandKeyMask) {
>                 buttons |= MOUSE_EVENT_RBUTTON;
>             } else {
>                 buttons |= MOUSE_EVENT_LBUTTON;
>             }
> +            if ([event modifierFlags] & NSAlternateKeyMask) {
> +                buttons |= MOUSE_EVENT_MBUTTON << 1;
> +            }
>             COCOA_MOUSE_EVENT
>             break;
>         case NSRightMouseDragged:
> @@ -633,7 +700,7 @@ static int cocoa_keycode_to_qemu(int keycode)
>                     COCOA_MOUSE_EVENT
>             } else if (!isMouseGrabed) {
>                 if (p.x > -1 && p.x < screen.width && p.y > -1 && p.y < screen.height) {
> -                    [self grabMouse];
> +                    if (cursor_allow_grab) [self grabMouse];
>                 } else {
>                     [NSApp sendEvent:event];
>                 }
> @@ -654,6 +721,25 @@ static int cocoa_keycode_to_qemu(int keycode)
>                 [NSApp sendEvent:event];
>             }
>             break;
> +        case NSAppKitDefined:
> +            switch ([event subtype]) {
> +                case NSApplicationActivatedEventType:
> +                    if (dcl) {
> +                        dcl->gui_timer_interval = 0;
> +                        dcl->idle = 0;
> +                    }
> +                    break;
> +                case NSApplicationDeactivatedEventType:
> +                    if (dcl) {
> +                        dcl->gui_timer_interval = 500;
> +                        dcl->idle = 1;
> +                    }
> +                    break;
> +                default:
> +                    break;
> +            }
> +            [NSApp sendEvent:event];
> +            break;
>         default:
>             [NSApp sendEvent:event];
>     }
> @@ -662,34 +748,48 @@ static int cocoa_keycode_to_qemu(int keycode)
> - (void) grabMouse
> {
>     COCOA_DEBUG("QemuCocoaView: grabMouse\n");
> -
> -    if (!isFullscreen) {
> -        if (qemu_name)
> -            [normalWindow setTitle:[NSString stringWithFormat:@"QEMU %s - (Press ctrl + alt to release Mouse)", qemu_name]];
> -        else
> -            [normalWindow setTitle:@"QEMU - (Press ctrl + alt to release Mouse)"];
> -    }
> -    [NSCursor hide];
> +    if (cursor_hide) [NSCursor hide];
>     CGAssociateMouseAndMouseCursorPosition(FALSE);
>     isMouseGrabed = TRUE; // while isMouseGrabed = TRUE, QemuCocoaApp sends all events to [cocoaView handleEvent:]
> +    [self updateCaption];
> }
> 
> - (void) ungrabMouse
> {
>     COCOA_DEBUG("QemuCocoaView: ungrabMouse\n");
> 
> -    if (!isFullscreen) {
> -        if (qemu_name)
> -            [normalWindow setTitle:[NSString stringWithFormat:@"QEMU %s", qemu_name]];
> -        else
> -            [normalWindow setTitle:@"QEMU"];
> -    }
> -    [NSCursor unhide];
> +    if (cursor_hide) [NSCursor unhide];
>     CGAssociateMouseAndMouseCursorPosition(TRUE);
>     isMouseGrabed = FALSE;
> +    [self updateCaption];
> +}
> +
> +- (void) updateCaption
> +{
> +    NSMutableString *caption = [NSMutableString stringWithCapacity:10];
> +    [caption appendFormat:@"QEMU"];
> +    if (isShuttingDownGuest) {
> +        [caption appendString:@" [Shutting down]"];
> +    }
> +    if (qemu_name) {
> +        [caption appendFormat:@" (%s)", qemu_name];
> +    }
> +    if (!vm_running) {
> +        [caption appendString:@" [Stopped]"];
> +    } else if (isMouseGrabed) {
> +        if (ctrl_grab) {
> +            [caption appendString:@" - Press Right-Ctrl to release mouse"];
> +        } else if (alt_grab) {
> +            [caption appendString:@" - Press Ctrl-Alt-Shift to release mouse"];
> +        } else {
> +            [caption appendString:@" - Press Ctrl-Alt to release mouse"];
> +        }
> +    }
> +    [normalWindow setTitle:caption];
> }
> 
> - (void) setAbsoluteEnabled:(BOOL)tIsAbsoluteEnabled {isAbsoluteEnabled = tIsAbsoluteEnabled;}
> +- (void) setShuttingDownGuest { isShuttingDownGuest = YES; [self updateCaption]; }
> - (BOOL) isMouseGrabed {return isMouseGrabed;}
> - (BOOL) isAbsoluteEnabled {return isAbsoluteEnabled;}
> - (float) cdx {return cdx;}
> @@ -704,14 +804,16 @@ static int cocoa_keycode_to_qemu(int keycode)
>     QemuCocoaAppController
>  ------------------------------------------------------
> */
> +#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6)
> +@interface QemuCocoaAppController : NSObject <NSWindowDelegate>
> +#else
> @interface QemuCocoaAppController : NSObject
> +#endif
> {
> }
> - (void)startEmulationWithArgc:(int)argc argv:(char**)argv;
> - (void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo;
> - (void)toggleFullScreen:(id)sender;
> -- (void)showQEMUDoc:(id)sender;
> -- (void)showQEMUTec:(id)sender;
> @end
> 
> @implementation QemuCocoaAppController
> @@ -743,7 +845,8 @@ static int cocoa_keycode_to_qemu(int keycode)
>         [normalWindow useOptimizedDrawing:YES];
>         [normalWindow makeKeyAndOrderFront:self];
> 		[normalWindow center];
> -
> +        [normalWindow setDelegate:self];
> +        [cocoaView updateCaption];
>     }
>     return self;
> }
> @@ -781,7 +884,6 @@ static int cocoa_keycode_to_qemu(int keycode)
>     COCOA_DEBUG("QemuCocoaAppController: applicationWillTerminate\n");
> 
>     qemu_system_shutdown_request();
> -    exit(0);
> }
> 
> - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication
> @@ -819,6 +921,7 @@ static int cocoa_keycode_to_qemu(int keycode)
>         [self startEmulationWithArgc:3 argv:(char**)argv];
>     }
> }
> +
> - (void)toggleFullScreen:(id)sender
> {
>     COCOA_DEBUG("QemuCocoaAppController: toggleFullScreen\n");
> @@ -826,41 +929,57 @@ static int cocoa_keycode_to_qemu(int keycode)
>     [cocoaView toggleFullScreen:sender];
> }
> 
> -- (void)showQEMUDoc:(id)sender
> +- (BOOL)windowShouldClose:(id)sender
> {
> -    COCOA_DEBUG("QemuCocoaAppController: showQEMUDoc\n");
> -
> -    [[NSWorkspace sharedWorkspace] openFile:[NSString stringWithFormat:@"%@/../doc/qemu/qemu-doc.html",
> -        [[NSBundle mainBundle] resourcePath]] withApplication:@"Help Viewer"];
> +    if (!no_quit) {
> +        if (qemu_run_display_close_handler()) {
> +            return YES;
> +        }
> +        [cocoaView setShuttingDownGuest];
> +    }
> +    return NO;
> }
> 
> -- (void)showQEMUTec:(id)sender
> +- (void)confirmQuit:(id)sender
> {
> -    COCOA_DEBUG("QemuCocoaAppController: showQEMUTec\n");
> +    NSAlert *alert = [NSAlert alertWithMessageText:@"Are you sure you want to quit QEMU?"
> +                                     defaultButton:@"No"
> +                                   alternateButton:@"Yes"
> +                                       otherButton:@"Shutdown"
> +                         informativeTextWithFormat:@"If you quit QEMU without shutting down the emulated machine properly you risk losing data and possibly corrupting the virtual machine contents."];
> +    [alert setAlertStyle:NSCriticalAlertStyle];
> +    switch ([alert runModal]) {
> +        case NSAlertDefaultReturn:
> +            /* do nothing */
> +            break;
> +        case NSAlertAlternateReturn:
> +            [NSApp terminate:sender];
> +            break;
> +        case NSAlertOtherReturn:
> +            if (qemu_run_display_close_handler()) {
> +                qemu_system_shutdown_request();
> +            } else {
> +                [cocoaView setShuttingDownGuest];
> +            }
> +            break;
> +        default:
> +            break;
> +    }
> +}
> 
> -    [[NSWorkspace sharedWorkspace] openFile:[NSString stringWithFormat:@"%@/../doc/qemu/qemu-tech.html",
> -        [[NSBundle mainBundle] resourcePath]] withApplication:@"Help Viewer"];
> +- (void)aboutQEMU:(id)sender
> +{
> +    [NSApp orderFrontStandardAboutPanelWithOptions:[NSDictionary dictionaryWithObjectsAndKeys:
> +                                                    @ QEMU_VERSION QEMU_PKGVERSION, @"ApplicationVersion",
> +                                                    nil]];
> }
> @end
> 
> 
> -
> -// Dock Connection
> -typedef struct CPSProcessSerNum
> +int main (int argc, const char * argv[])
> {
> -        UInt32                lo;
> -        UInt32                hi;
> -} CPSProcessSerNum;
> -
> -extern OSErr    CPSGetCurrentProcess( CPSProcessSerNum *psn);
> -extern OSErr    CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5);
> -extern OSErr    CPSSetFrontProcess( CPSProcessSerNum *psn);
> -
> -int main (int argc, const char * argv[]) {
> -
>     gArgc = argc;
>     gArgv = (char **)argv;
> -    CPSProcessSerNum PSN;
>     int i;
> 
>     /* In case we don't need to display a window, let's not do that */
> @@ -875,10 +994,11 @@ int main (int argc, const char * argv[]) {
>     NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
>     [NSApplication sharedApplication];
> 
> -    if (!CPSGetCurrentProcess(&PSN))
> -        if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103))
> -            if (!CPSSetFrontProcess(&PSN))
> -                [NSApplication sharedApplication];
> +    ProcessSerialNumber PSN;
> +    if (!GetCurrentProcess(&PSN) &&
> +        !TransformProcessType(&PSN, kProcessTransformToForegroundApplication) &&
> +        !SetFrontProcess(&PSN))
> +        [NSApplication sharedApplication];
> 
>     // Add menus
>     NSMenu      *menu;
> @@ -888,14 +1008,14 @@ int main (int argc, const char * argv[]) {
> 
>     // Application menu
>     menu = [[NSMenu alloc] initWithTitle:@""];
> -    [menu addItemWithTitle:@"About QEMU" action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""]; // About QEMU
> +    [menu addItemWithTitle:@"About QEMU" action:@selector(aboutQEMU:) keyEquivalent:@""]; // About QEMU
>     [menu addItem:[NSMenuItem separatorItem]]; //Separator
>     [menu addItemWithTitle:@"Hide QEMU" action:@selector(hide:) keyEquivalent:@"h"]; //Hide QEMU
>     menuItem = (NSMenuItem *)[menu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"]; // Hide Others
>     [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)];
>     [menu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""]; // Show All
>     [menu addItem:[NSMenuItem separatorItem]]; //Separator
> -    [menu addItemWithTitle:@"Quit QEMU" action:@selector(terminate:) keyEquivalent:@"q"];
> +    [menu addItemWithTitle:@"Quit QEMU" action:@selector(confirmQuit:) keyEquivalent:@"q"];
>     menuItem = [[NSMenuItem alloc] initWithTitle:@"Apple" action:nil keyEquivalent:@""];
>     [menuItem setSubmenu:menu];
>     [[NSApp mainMenu] addItem:menuItem];
> @@ -916,14 +1036,6 @@ int main (int argc, const char * argv[]) {
>     [[NSApp mainMenu] addItem:menuItem];
>     [NSApp setWindowsMenu:menu];
> 
> -    // Help menu
> -    menu = [[NSMenu alloc] initWithTitle:@"Help"];
> -    [menu addItem: [[[NSMenuItem alloc] initWithTitle:@"QEMU Documentation" action:@selector(showQEMUDoc:) keyEquivalent:@"?"] autorelease]]; // QEMU Help
> -    [menu addItem: [[[NSMenuItem alloc] initWithTitle:@"QEMU Technology" action:@selector(showQEMUTec:) keyEquivalent:@""] autorelease]]; // QEMU Help
> -    menuItem = [[[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""] autorelease];
> -    [menuItem setSubmenu:menu];
> -    [[NSApp mainMenu] addItem:menuItem];
> -
>     // Create an Application controller
>     QemuCocoaAppController *appController = [[QemuCocoaAppController alloc] init];
>     [NSApp setDelegate:appController];
> @@ -968,6 +1080,11 @@ static void cocoa_refresh(DisplayState *ds)
> {
>     COCOA_DEBUG("qemu_cocoa: cocoa_refresh\n");
> 
> +    if (last_vm_running != vm_running) {
> +        last_vm_running = vm_running;
> +        [cocoaView updateCaption];
> +    }
> +    
>     if (kbd_mouse_is_absolute()) {
>         if (![cocoaView isAbsoluteEnabled]) {
>             if ([cocoaView isMouseGrabed]) {
> @@ -984,7 +1101,7 @@ static void cocoa_refresh(DisplayState *ds)
>         event = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:distantPast
>                         inMode: NSDefaultRunLoopMode dequeue:YES];
>         if (event != nil) {
> -            [cocoaView handleEvent:event];
> +            [cocoaView qemuHandleEvent:event];
>         }
>     } while(event != nil);
>     vga_hw_update();
> @@ -1012,3 +1129,7 @@ void cocoa_display_init(DisplayState *ds, int full_screen)
>     // register cleanup function
>     atexit(cocoa_cleanup);
> }
> +
> +#ifdef CONFIG_GLHW
> +#include "hw/gl/opengl_host_cocoa.m"
> +#endif
> -- 
> 1.6.5
> 
> 
>

Patch

diff --git a/cocoa.m b/cocoa.m
index 56c789a..524617f 100644
--- a/cocoa.m
+++ b/cocoa.m
@@ -47,10 +47,25 @@ 
 #define cgrect(nsrect) (*(CGRect *)&(nsrect))
 #define COCOA_MOUSE_EVENT \
         if (isTabletEnabled) { \
-            kbd_mouse_event((int)(p.x * 0x7FFF / (screen.width - 1)), (int)((screen.height - p.y) * 0x7FFF / (screen.height - 1)), 0, buttons); \
+            if (isFullscreen) { \
+                NSSize fs = [[NSScreen mainScreen] frame].size; \
+                kbd_mouse_event((int)(p.x * 0x7FFF / (fs.width - 1)), \
+                                (int)((fs.height - p.y) * 0x7FFF / (fs.height - 1)), \
+                                0, buttons); \
+            } else { \
+                kbd_mouse_event((int)(p.x * 0x7FFF / (screen.width - 1)), \
+                                (int)((screen.height - p.y) * 0x7FFF / (screen.height - 1)), \
+                                0, buttons); \
+            } \
         } else if (isMouseGrabed) { \
             kbd_mouse_event((int)[event deltaX], (int)[event deltaY], 0, buttons); \
         } else { \
+            if (isFullscreen) { \
+                NSSize fs = [[NSScreen mainScreen] frame].size; \
+                kbd_mouse_event((int)(p.x * 0x7FFF / (fs.width - 1)), \
+                                (int)((fs.height - p.y) * 0x7FFF / (fs.height - 1)), \
+                                0, buttons); \
+            } \
             [NSApp sendEvent:event]; \
         }
 
@@ -65,6 +80,7 @@  int qemu_main(int argc, char **argv); // main defined in qemu/vl.c
 NSWindow *normalWindow;
 id cocoaView;
 static DisplayChangeListener *dcl;
+static int last_vm_running;
 
 int gArgc;
 char **gArgv;
@@ -83,7 +99,7 @@  int keymap[] =
     45, //  7       0x07    0x2d            X       QZ_x
     46, //  8       0x08    0x2e            C       QZ_c
     47, //  9       0x09    0x2f            V       QZ_v
-    0,  //  10      0x0A    Undefined
+    0,  //  10      0x0A    Undefined       (paragraph)
     48, //  11      0x0B    0x30            B       QZ_b
     16, //  12      0x0C    0x10            Q       QZ_q
     17, //  13      0x0D    0x11            W       QZ_w
@@ -127,8 +143,8 @@  int keymap[] =
     14, //  51      0x33    0x0e            BKSP    QZ_BACKSPACE
     0,  //  52      0x34    Undefined
     1,  //  53      0x35    0x01            ESC     QZ_ESCAPE
-    0,  //  54      0x36                            QZ_RMETA
-    0,  //  55      0x37                            QZ_LMETA
+    220,//  54      0xdc            e0,5c   R GUI   QZ_RMETA
+    219,//  55      0xdb            e0,5b   L GUI   QZ_LMETA
     42, //  56      0x38    0x2a            L SHFT  QZ_LSHIFT
     58, //  57      0x39    0x3a            CAPS    QZ_CAPSLOCK
     56, //  58      0x3A    0x38            L ALT   QZ_LALT
@@ -136,9 +152,9 @@  int keymap[] =
     54, //  60      0x3C    0x36            R SHFT  QZ_RSHIFT
     184,//  61      0x3D    0xb8    E0,38   R ALT   QZ_RALT
     157,//  62      0x3E    0x9d    E0,1D   R CTRL  QZ_RCTRL
-    0,  //  63      0x3F    Undefined
-    0,  //  64      0x40    Undefined
-    0,  //  65      0x41    Undefined
+    0,  //  63      0x3F    Undefined       (fn)
+    0,  //  64      0x40    Undefined       (f17)
+    83, //  65      0x53    0x53            KP .
     0,  //  66      0x42    Undefined
     55, //  67      0x43    0x37            KP *    QZ_KP_MULTIPLY
     0,  //  68      0x44    Undefined
@@ -152,9 +168,9 @@  int keymap[] =
     152,//  76      0x4C    0x9c    E0,1C   KP EN   QZ_KP_ENTER
     0,  //  77      0x4D    undefined
     74, //  78      0x4E    0x4a            KP -    QZ_KP_MINUS
-    0,  //  79      0x4F    Undefined
-    0,  //  80      0x50    Undefined
-    0,  //  81      0x51                            QZ_KP_EQUALS
+    0,  //  79      0x4F    Undefined       (f18)
+    0,  //  80      0x50    Undefined       (f19)
+    0,  //  81      0x51                    (kp =)  QZ_KP_EQUALS
     82, //  82      0x52    0x52            KP 0    QZ_KP0
     79, //  83      0x53    0x4f            KP 1    QZ_KP1
     80, //  84      0x54    0x50            KP 2    QZ_KP2
@@ -178,15 +194,15 @@  int keymap[] =
     0,  //  102     0x66    Undefined
     87, //  103     0x67    0x57            F11     QZ_F11
     0,  //  104     0x68    Undefined
-    183,//  105     0x69    0xb7                    QZ_PRINT
+    183,//  105     0x69    0xb7            (f13)   QZ_PRINT
     0,  //  106     0x6A    Undefined
-    70, //  107     0x6B    0x46            SCROLL  QZ_SCROLLOCK
+    70, //  107     0x6B    0x46            SCROLL(f14)  QZ_SCROLLOCK
     0,  //  108     0x6C    Undefined
     68, //  109     0x6D    0x44            F10     QZ_F10
     0,  //  110     0x6E    Undefined
     88, //  111     0x6F    0x58            F12     QZ_F12
     0,  //  112     0x70    Undefined
-    110,//  113     0x71    0x0                     QZ_PAUSE
+    110,//  113     0x71    0x0             (f15)   QZ_PAUSE
     210,//  114     0x72    0xd2    E0,52   INSERT  QZ_INSERT
     199,//  115     0x73    0xc7    E0,47   HOME    QZ_HOME
     201,//  116     0x74    0xc9    E0,49   PG UP   QZ_PAGEUP
@@ -204,12 +220,9 @@  int keymap[] =
 
 /* Aditional 104 Key XP-Keyboard Scancodes from http://www.computer-engineering.org/ps2keyboard/scancodes1.html */
 /*
-    219 //          0xdb            e0,5b   L GUI
-    220 //          0xdc            e0,5c   R GUI
     221 //          0xdd            e0,5d   APPS
         //              E0,2A,E0,37         PRNT SCRN
         //              E1,1D,45,E1,9D,C5   PAUSE
-    83  //          0x53    0x53            KP .
 // ACPI Scan Codes
     222 //          0xde            E0, 5E  Power
     223 //          0xdf            E0, 5F  Sleep
@@ -259,23 +272,29 @@  static int cocoa_keycode_to_qemu(int keycode)
     NSWindow *fullScreenWindow;
     float cx,cy,cw,ch,cdx,cdy;
     CGDataProviderRef dataProviderRef;
+    void *dataRawPtr;
+    int mouseX, mouseY;
     int modifiers_state[256];
     BOOL isMouseGrabed;
     BOOL isFullscreen;
     BOOL isAbsoluteEnabled;
     BOOL isTabletEnabled;
+    BOOL isShuttingDownGuest;
 }
 - (void) resizeContentToWidth:(int)w height:(int)h displayState:(DisplayState *)ds;
 - (void) grabMouse;
 - (void) ungrabMouse;
 - (void) toggleFullScreen:(id)sender;
-- (void) handleEvent:(NSEvent *)event;
+- (void) qemuHandleEvent:(NSEvent *)event;
 - (void) setAbsoluteEnabled:(BOOL)tIsAbsoluteEnabled;
+- (void) setShuttingDownGuest;
 - (BOOL) isMouseGrabed;
 - (BOOL) isAbsoluteEnabled;
 - (float) cdx;
 - (float) cdy;
 - (QEMUScreen) gscreen;
+- (void) updateCaption;
+- (void) checkAndDisplayAltCursor;
 @end
 
 @implementation QemuCocoaView
@@ -310,6 +329,34 @@  static int cocoa_keycode_to_qemu(int keycode)
     return YES;
 }
 
+- (void) checkAndDisplayAltCursor
+{
+    if (multitouch_enabled && !isMouseGrabed && !cursor_hide &&
+        dataRawPtr && modifiers_state[56]) {
+        unsigned char *p = (unsigned char *)dataRawPtr;
+        int altX = screen.width - mouseX;
+        int altY = mouseY;
+        int x, y;
+        int bytesperpixel = screen.bitsPerPixel / 8;
+        p += (altY * screen.width) * bytesperpixel;
+        for (y = 0; y < 8; y++) {
+            if (y + altY > 0 && y + altY < screen.height) {
+                unsigned char *q = p + altX * bytesperpixel;
+                for (x = 0; x < 8; x++) {
+                    if (x + altX > 0 && x + altX < screen.width) {
+                        int i;
+                        for (i = 0; i < bytesperpixel; i++) {
+                            q[i] ^= 0xff;
+                        }
+                    }
+                    q += bytesperpixel;
+                }
+            }
+            p += screen.width * bytesperpixel;
+        }
+    }
+}
+
 - (void) drawRect:(NSRect) rect
 {
     COCOA_DEBUG("QemuCocoaView: drawRect\n");
@@ -321,6 +368,7 @@  static int cocoa_keycode_to_qemu(int keycode)
 
     // draw screen bitmap directly to Core Graphics context
     if (dataProviderRef) {
+        [self checkAndDisplayAltCursor];
         CGImageRef imageRef = CGImageCreate(
             screen.width, //width
             screen.height, //height
@@ -360,10 +408,10 @@  static int cocoa_keycode_to_qemu(int keycode)
 
             [self getRectsBeingDrawn:&rectList count:&rectCount];
             for (i = 0; i < rectCount; i++) {
-                clipRect.origin.x = rectList[i].origin.x / cdx;
-                clipRect.origin.y = (float)screen.height - (rectList[i].origin.y + rectList[i].size.height) / cdy;
-                clipRect.size.width = rectList[i].size.width / cdx;
-                clipRect.size.height = rectList[i].size.height / cdy;
+                clipRect.origin.x = floorf(rectList[i].origin.x / cdx);
+                clipRect.origin.y = floorf((float)screen.height - (rectList[i].origin.y + rectList[i].size.height) / cdy);
+                clipRect.size.width = ceilf(rectList[i].size.width / cdx);
+                clipRect.size.height = ceilf(rectList[i].size.height / cdy);
                 clipImageRef = CGImageCreateWithImageInRect(
                     imageRef,
                     clipRect
@@ -410,6 +458,7 @@  static int cocoa_keycode_to_qemu(int keycode)
 	screen.bitsPerPixel = ds_get_bits_per_pixel(ds);
 	screen.bitsPerComponent = ds_get_bytes_per_pixel(ds) * 2;
 
+    dataRawPtr = is_graphic_console() ? ds_get_data(ds) : 0;
     dataProviderRef = CGDataProviderCreateWithData(NULL, ds_get_data(ds), w * 4 * h, NULL);
 
     // update windows
@@ -417,10 +466,9 @@  static int cocoa_keycode_to_qemu(int keycode)
         [[fullScreenWindow contentView] setFrame:[[NSScreen mainScreen] frame]];
         [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];
     } else {
-        if (qemu_name)
-            [normalWindow setTitle:[NSString stringWithFormat:@"QEMU %s", qemu_name]];
         [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:NO];
     }
+    [self updateCaption];
     screen.width = w;
     screen.height = h;
 	[normalWindow center];
@@ -434,7 +482,7 @@  static int cocoa_keycode_to_qemu(int keycode)
 
     if (isFullscreen) { // switch from fullscreen to desktop
         isFullscreen = FALSE;
-        [self ungrabMouse];
+        if (isMouseGrabed) [self ungrabMouse];
         [self setContentDimensions];
 // test if host supports "exitFullScreenModeWithOptions" at compile time
 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
@@ -444,29 +492,33 @@  static int cocoa_keycode_to_qemu(int keycode)
 #endif
             [fullScreenWindow close];
             [normalWindow setContentView: self];
-            [normalWindow makeKeyAndOrderFront: self];
             [NSMenu setMenuBarVisible:YES];
 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
         }
 #endif
+        [normalWindow makeKeyAndOrderFront:self];
     } else { // switch from desktop to fullscreen
         isFullscreen = TRUE;
-        [self grabMouse];
+        if (cursor_allow_grab) [self grabMouse];
         [self setContentDimensions];
+        [normalWindow orderOut:self];
 // test if host supports "enterFullScreenMode:withOptions" at compile time
 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
         if ([NSView respondsToSelector:@selector(enterFullScreenMode:withOptions:)]) { // test if "enterFullScreenMode:withOptions" is supported on host at runtime
-            [self enterFullScreenMode:[NSScreen mainScreen] withOptions:[NSDictionary dictionaryWithObjectsAndKeys:
-                [NSNumber numberWithBool:NO], NSFullScreenModeAllScreens,
-                [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:NO], kCGDisplayModeIsStretched, nil], NSFullScreenModeSetting,
-                 nil]];
+            [self enterFullScreenMode:[NSScreen mainScreen]
+                          withOptions:[NSDictionary dictionaryWithObjectsAndKeys:
+                                       [NSNumber numberWithBool:NO], NSFullScreenModeAllScreens,
+                                       [NSDictionary dictionaryWithObjectsAndKeys:
+                                        [NSNumber numberWithBool:NO], kCGDisplayModeIsStretched,
+                                        nil], NSFullScreenModeSetting,
+                                       nil]];
         } else {
 #endif
             [NSMenu setMenuBarVisible:NO];
             fullScreenWindow = [[NSWindow alloc] initWithContentRect:[[NSScreen mainScreen] frame]
-                styleMask:NSBorderlessWindowMask
-                backing:NSBackingStoreBuffered
-                defer:NO];
+                                                           styleMask:NSBorderlessWindowMask
+                                                             backing:NSBackingStoreBuffered
+                                                               defer:NO];
             [fullScreenWindow setHasShadow:NO];
             [fullScreenWindow setContentView:self];
             [fullScreenWindow makeKeyAndOrderFront:self];
@@ -476,7 +528,7 @@  static int cocoa_keycode_to_qemu(int keycode)
     }
 }
 
-- (void) handleEvent:(NSEvent *)event
+- (void) qemuHandleEvent:(NSEvent *)event
 {
     COCOA_DEBUG("QemuCocoaView: handleEvent\n");
 
@@ -505,8 +557,13 @@  static int cocoa_keycode_to_qemu(int keycode)
             }
 
             // release Mouse grab when pressing ctrl+alt
-            if (!isFullscreen && ([event modifierFlags] & NSControlKeyMask) && ([event modifierFlags] & NSAlternateKeyMask)) {
-                [self ungrabMouse];
+            if (!isFullscreen) {
+                if ((ctrl_grab && [event keyCode] == 0x3e)
+                    || ((([event modifierFlags] & NSControlKeyMask) &&
+                         ([event modifierFlags] & NSAlternateKeyMask))
+                        && (!alt_grab || ([event modifierFlags] & NSShiftKeyMask)))) {
+                    [self ungrabMouse];
+                }
             }
             break;
         case NSKeyDown:
@@ -581,15 +638,17 @@  static int cocoa_keycode_to_qemu(int keycode)
             }
             break;
         case NSMouseMoved:
+            mouseX = p.x;
+            mouseY = p.y;
             if (isAbsoluteEnabled) {
                 if (p.x < 0 || p.x > screen.width || p.y < 0 || p.y > screen.height || ![[self window] isKeyWindow]) {
                     if (isTabletEnabled) { // if we leave the window, deactivate the tablet
-                        [NSCursor unhide];
+                        if (cursor_hide) [NSCursor unhide];
                         isTabletEnabled = FALSE;
                     }
                 } else {
                     if (!isTabletEnabled) { // if we enter the window, activate the tablet
-                        [NSCursor hide];
+                        if (cursor_hide) [NSCursor hide];
                         isTabletEnabled = TRUE;
                     }
                 }
@@ -602,6 +661,9 @@  static int cocoa_keycode_to_qemu(int keycode)
             } else {
                 buttons |= MOUSE_EVENT_LBUTTON;
             }
+            if ([event modifierFlags] & NSAlternateKeyMask) {
+                buttons |= MOUSE_EVENT_MBUTTON << 1;
+            }
             COCOA_MOUSE_EVENT
             break;
         case NSRightMouseDown:
@@ -613,11 +675,16 @@  static int cocoa_keycode_to_qemu(int keycode)
             COCOA_MOUSE_EVENT
             break;
         case NSLeftMouseDragged:
+            mouseX = p.x;
+            mouseY = p.y;
             if ([event modifierFlags] & NSCommandKeyMask) {
                 buttons |= MOUSE_EVENT_RBUTTON;
             } else {
                 buttons |= MOUSE_EVENT_LBUTTON;
             }
+            if ([event modifierFlags] & NSAlternateKeyMask) {
+                buttons |= MOUSE_EVENT_MBUTTON << 1;
+            }
             COCOA_MOUSE_EVENT
             break;
         case NSRightMouseDragged:
@@ -633,7 +700,7 @@  static int cocoa_keycode_to_qemu(int keycode)
                     COCOA_MOUSE_EVENT
             } else if (!isMouseGrabed) {
                 if (p.x > -1 && p.x < screen.width && p.y > -1 && p.y < screen.height) {
-                    [self grabMouse];
+                    if (cursor_allow_grab) [self grabMouse];
                 } else {
                     [NSApp sendEvent:event];
                 }
@@ -654,6 +721,25 @@  static int cocoa_keycode_to_qemu(int keycode)
                 [NSApp sendEvent:event];
             }
             break;
+        case NSAppKitDefined:
+            switch ([event subtype]) {
+                case NSApplicationActivatedEventType:
+                    if (dcl) {
+                        dcl->gui_timer_interval = 0;
+                        dcl->idle = 0;
+                    }
+                    break;
+                case NSApplicationDeactivatedEventType:
+                    if (dcl) {
+                        dcl->gui_timer_interval = 500;
+                        dcl->idle = 1;
+                    }
+                    break;
+                default:
+                    break;
+            }
+            [NSApp sendEvent:event];
+            break;
         default:
             [NSApp sendEvent:event];
     }
@@ -662,34 +748,48 @@  static int cocoa_keycode_to_qemu(int keycode)
 - (void) grabMouse
 {
     COCOA_DEBUG("QemuCocoaView: grabMouse\n");
-
-    if (!isFullscreen) {
-        if (qemu_name)
-            [normalWindow setTitle:[NSString stringWithFormat:@"QEMU %s - (Press ctrl + alt to release Mouse)", qemu_name]];
-        else
-            [normalWindow setTitle:@"QEMU - (Press ctrl + alt to release Mouse)"];
-    }
-    [NSCursor hide];
+    if (cursor_hide) [NSCursor hide];
     CGAssociateMouseAndMouseCursorPosition(FALSE);
     isMouseGrabed = TRUE; // while isMouseGrabed = TRUE, QemuCocoaApp sends all events to [cocoaView handleEvent:]
+    [self updateCaption];
 }
 
 - (void) ungrabMouse
 {
     COCOA_DEBUG("QemuCocoaView: ungrabMouse\n");
 
-    if (!isFullscreen) {
-        if (qemu_name)
-            [normalWindow setTitle:[NSString stringWithFormat:@"QEMU %s", qemu_name]];
-        else
-            [normalWindow setTitle:@"QEMU"];
-    }
-    [NSCursor unhide];
+    if (cursor_hide) [NSCursor unhide];
     CGAssociateMouseAndMouseCursorPosition(TRUE);
     isMouseGrabed = FALSE;
+    [self updateCaption];
+}
+
+- (void) updateCaption
+{
+    NSMutableString *caption = [NSMutableString stringWithCapacity:10];
+    [caption appendFormat:@"QEMU"];
+    if (isShuttingDownGuest) {
+        [caption appendString:@" [Shutting down]"];
+    }
+    if (qemu_name) {
+        [caption appendFormat:@" (%s)", qemu_name];
+    }
+    if (!vm_running) {
+        [caption appendString:@" [Stopped]"];
+    } else if (isMouseGrabed) {
+        if (ctrl_grab) {
+            [caption appendString:@" - Press Right-Ctrl to release mouse"];
+        } else if (alt_grab) {
+            [caption appendString:@" - Press Ctrl-Alt-Shift to release mouse"];
+        } else {
+            [caption appendString:@" - Press Ctrl-Alt to release mouse"];
+        }
+    }
+    [normalWindow setTitle:caption];
 }
 
 - (void) setAbsoluteEnabled:(BOOL)tIsAbsoluteEnabled {isAbsoluteEnabled = tIsAbsoluteEnabled;}
+- (void) setShuttingDownGuest { isShuttingDownGuest = YES; [self updateCaption]; }
 - (BOOL) isMouseGrabed {return isMouseGrabed;}
 - (BOOL) isAbsoluteEnabled {return isAbsoluteEnabled;}
 - (float) cdx {return cdx;}
@@ -704,14 +804,16 @@  static int cocoa_keycode_to_qemu(int keycode)
     QemuCocoaAppController
  ------------------------------------------------------
 */
+#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6)
+@interface QemuCocoaAppController : NSObject <NSWindowDelegate>
+#else
 @interface QemuCocoaAppController : NSObject
+#endif
 {
 }
 - (void)startEmulationWithArgc:(int)argc argv:(char**)argv;
 - (void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo;
 - (void)toggleFullScreen:(id)sender;
-- (void)showQEMUDoc:(id)sender;
-- (void)showQEMUTec:(id)sender;
 @end
 
 @implementation QemuCocoaAppController
@@ -743,7 +845,8 @@  static int cocoa_keycode_to_qemu(int keycode)
         [normalWindow useOptimizedDrawing:YES];
         [normalWindow makeKeyAndOrderFront:self];
 		[normalWindow center];
-
+        [normalWindow setDelegate:self];
+        [cocoaView updateCaption];
     }
     return self;
 }
@@ -781,7 +884,6 @@  static int cocoa_keycode_to_qemu(int keycode)
     COCOA_DEBUG("QemuCocoaAppController: applicationWillTerminate\n");
 
     qemu_system_shutdown_request();
-    exit(0);
 }
 
 - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication
@@ -819,6 +921,7 @@  static int cocoa_keycode_to_qemu(int keycode)
         [self startEmulationWithArgc:3 argv:(char**)argv];
     }
 }
+
 - (void)toggleFullScreen:(id)sender
 {
     COCOA_DEBUG("QemuCocoaAppController: toggleFullScreen\n");
@@ -826,41 +929,57 @@  static int cocoa_keycode_to_qemu(int keycode)
     [cocoaView toggleFullScreen:sender];
 }
 
-- (void)showQEMUDoc:(id)sender
+- (BOOL)windowShouldClose:(id)sender
 {
-    COCOA_DEBUG("QemuCocoaAppController: showQEMUDoc\n");
-
-    [[NSWorkspace sharedWorkspace] openFile:[NSString stringWithFormat:@"%@/../doc/qemu/qemu-doc.html",
-        [[NSBundle mainBundle] resourcePath]] withApplication:@"Help Viewer"];
+    if (!no_quit) {
+        if (qemu_run_display_close_handler()) {
+            return YES;
+        }
+        [cocoaView setShuttingDownGuest];
+    }
+    return NO;
 }
 
-- (void)showQEMUTec:(id)sender
+- (void)confirmQuit:(id)sender
 {
-    COCOA_DEBUG("QemuCocoaAppController: showQEMUTec\n");
+    NSAlert *alert = [NSAlert alertWithMessageText:@"Are you sure you want to quit QEMU?"
+                                     defaultButton:@"No"
+                                   alternateButton:@"Yes"
+                                       otherButton:@"Shutdown"
+                         informativeTextWithFormat:@"If you quit QEMU without shutting down the emulated machine properly you risk losing data and possibly corrupting the virtual machine contents."];
+    [alert setAlertStyle:NSCriticalAlertStyle];
+    switch ([alert runModal]) {
+        case NSAlertDefaultReturn:
+            /* do nothing */
+            break;
+        case NSAlertAlternateReturn:
+            [NSApp terminate:sender];
+            break;
+        case NSAlertOtherReturn:
+            if (qemu_run_display_close_handler()) {
+                qemu_system_shutdown_request();
+            } else {
+                [cocoaView setShuttingDownGuest];
+            }
+            break;
+        default:
+            break;
+    }
+}
 
-    [[NSWorkspace sharedWorkspace] openFile:[NSString stringWithFormat:@"%@/../doc/qemu/qemu-tech.html",
-        [[NSBundle mainBundle] resourcePath]] withApplication:@"Help Viewer"];
+- (void)aboutQEMU:(id)sender
+{
+    [NSApp orderFrontStandardAboutPanelWithOptions:[NSDictionary dictionaryWithObjectsAndKeys:
+                                                    @ QEMU_VERSION QEMU_PKGVERSION, @"ApplicationVersion",
+                                                    nil]];
 }
 @end
 
 
-
-// Dock Connection
-typedef struct CPSProcessSerNum
+int main (int argc, const char * argv[])
 {
-        UInt32                lo;
-        UInt32                hi;
-} CPSProcessSerNum;
-
-extern OSErr    CPSGetCurrentProcess( CPSProcessSerNum *psn);
-extern OSErr    CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5);
-extern OSErr    CPSSetFrontProcess( CPSProcessSerNum *psn);
-
-int main (int argc, const char * argv[]) {
-
     gArgc = argc;
     gArgv = (char **)argv;
-    CPSProcessSerNum PSN;
     int i;
 
     /* In case we don't need to display a window, let's not do that */
@@ -875,10 +994,11 @@  int main (int argc, const char * argv[]) {
     NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
     [NSApplication sharedApplication];
 
-    if (!CPSGetCurrentProcess(&PSN))
-        if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103))
-            if (!CPSSetFrontProcess(&PSN))
-                [NSApplication sharedApplication];
+    ProcessSerialNumber PSN;
+    if (!GetCurrentProcess(&PSN) &&
+        !TransformProcessType(&PSN, kProcessTransformToForegroundApplication) &&
+        !SetFrontProcess(&PSN))
+        [NSApplication sharedApplication];
 
     // Add menus
     NSMenu      *menu;
@@ -888,14 +1008,14 @@  int main (int argc, const char * argv[]) {
 
     // Application menu
     menu = [[NSMenu alloc] initWithTitle:@""];
-    [menu addItemWithTitle:@"About QEMU" action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""]; // About QEMU
+    [menu addItemWithTitle:@"About QEMU" action:@selector(aboutQEMU:) keyEquivalent:@""]; // About QEMU
     [menu addItem:[NSMenuItem separatorItem]]; //Separator
     [menu addItemWithTitle:@"Hide QEMU" action:@selector(hide:) keyEquivalent:@"h"]; //Hide QEMU
     menuItem = (NSMenuItem *)[menu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"]; // Hide Others
     [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)];
     [menu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""]; // Show All
     [menu addItem:[NSMenuItem separatorItem]]; //Separator
-    [menu addItemWithTitle:@"Quit QEMU" action:@selector(terminate:) keyEquivalent:@"q"];
+    [menu addItemWithTitle:@"Quit QEMU" action:@selector(confirmQuit:) keyEquivalent:@"q"];
     menuItem = [[NSMenuItem alloc] initWithTitle:@"Apple" action:nil keyEquivalent:@""];
     [menuItem setSubmenu:menu];
     [[NSApp mainMenu] addItem:menuItem];
@@ -916,14 +1036,6 @@  int main (int argc, const char * argv[]) {
     [[NSApp mainMenu] addItem:menuItem];
     [NSApp setWindowsMenu:menu];
 
-    // Help menu
-    menu = [[NSMenu alloc] initWithTitle:@"Help"];
-    [menu addItem: [[[NSMenuItem alloc] initWithTitle:@"QEMU Documentation" action:@selector(showQEMUDoc:) keyEquivalent:@"?"] autorelease]]; // QEMU Help
-    [menu addItem: [[[NSMenuItem alloc] initWithTitle:@"QEMU Technology" action:@selector(showQEMUTec:) keyEquivalent:@""] autorelease]]; // QEMU Help
-    menuItem = [[[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""] autorelease];
-    [menuItem setSubmenu:menu];
-    [[NSApp mainMenu] addItem:menuItem];
-
     // Create an Application controller
     QemuCocoaAppController *appController = [[QemuCocoaAppController alloc] init];
     [NSApp setDelegate:appController];
@@ -968,6 +1080,11 @@  static void cocoa_refresh(DisplayState *ds)
 {
     COCOA_DEBUG("qemu_cocoa: cocoa_refresh\n");
 
+    if (last_vm_running != vm_running) {
+        last_vm_running = vm_running;
+        [cocoaView updateCaption];
+    }
+    
     if (kbd_mouse_is_absolute()) {
         if (![cocoaView isAbsoluteEnabled]) {
             if ([cocoaView isMouseGrabed]) {
@@ -984,7 +1101,7 @@  static void cocoa_refresh(DisplayState *ds)
         event = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:distantPast
                         inMode: NSDefaultRunLoopMode dequeue:YES];
         if (event != nil) {
-            [cocoaView handleEvent:event];
+            [cocoaView qemuHandleEvent:event];
         }
     } while(event != nil);
     vga_hw_update();
@@ -1012,3 +1129,7 @@  void cocoa_display_init(DisplayState *ds, int full_screen)
     // register cleanup function
     atexit(cocoa_cleanup);
 }
+
+#ifdef CONFIG_GLHW
+#include "hw/gl/opengl_host_cocoa.m"
+#endif