qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [patch] cocoa.m - Core Graphics support
@ 2008-01-21 16:18 Mike Kronenberg
  2008-01-30 18:59 ` Alexander Graf
  0 siblings, 1 reply; 15+ messages in thread
From: Mike Kronenberg @ 2008-01-21 16:18 UTC (permalink / raw)
  To: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 39223 bytes --]

This is a complete rewrite of cocoa.m to support Core Graphics.

As mentioned in earlier threads, the QuickDraw API is depreciated  
starting with OS X 10.4.
Now with OS X 10.5 it won't even compile QuickDraw code on x86_64.


This implementation of cocoa.m has the following features:

[new] partial drawing of the window as needed, implemented with CG.
[new] fullscreen support
[new] tablet support
[new] View menu and item to enter Fullscreen (cmd-f)
[new] Help menu and items to show qemu-doc.html (cmd-?) and qemu- 
tec.html in the OS X "Help Viewer"
[new] -name is shown in Title-bar of window
[fix] Application menu creation for 10.4+ (API is private as of 10.4)
[fix] Mouse-clicks on the guests window widgets are no longer  
intercepted
[fix] apple keyboard shortcuts forwarded (minimize (cmd-m), hide QEMU  
(cmd-h), quit QEMU (cmd-q))

It should compile on ppc/intel starting form 10.3 (10.2 with the known  
workarounds).

Please test and comment

Mike

File as .gz
http://www.kberg.ch/qemu/091patches/cocoa.m.gz




/*
  * QEMU Cocoa CG display driver
  *
  * Copyright (c) 2008 Mike Kronenberg
  *
  * Permission is hereby granted, free of charge, to any person  
obtaining a copy
  * of this software and associated documentation files (the  
"Software"), to deal
  * in the Software without restriction, including without limitation  
the rights
  * to use, copy, modify, merge, publish, distribute, sublicense, and/ 
or sell
  * copies of the Software, and to permit persons to whom the Software  
is
  * furnished to do so, subject to the following conditions:
  *
  * The above copyright notice and this permission notice shall be  
included in
  * all copies or substantial portions of the Software.
  *
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,  
EXPRESS OR
  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF  
MERCHANTABILITY,
  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT  
SHALL
  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES  
OR OTHER
  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,  
ARISING FROM,
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER  
DEALINGS IN
  * THE SOFTWARE.
  */

#import <Cocoa/Cocoa.h>

#include "qemu-common.h"
#include "console.h"
#include "sysemu.h"


//#define DEBUG

#ifdef DEBUG
#define COCOA_DEBUG(...)  { (void) fprintf (stdout, __VA_ARGS__); }
#else
#define COCOA_DEBUG(...)  ((void) 0)
#endif

#define cgrect(nsrect) (*(CGRect *)&(nsrect))
#define COCOA_MOUSE_EVENT \
         if (isTabletEnabled) { \
             kbd_mouse_event((int)(p.x * 0x7FFF / screen.width), (int) 
((screen.height - p.y) * 0x7FFF / screen.height), 0, buttons); \
         } else if (isMouseGrabed) { \
             kbd_mouse_event((int)[event deltaX], (int)[event deltaY],  
0, buttons); \
         } else { \
             [NSApp sendEvent:event]; \
         }

typedef struct {
     int width;
     int height;
     int bitsPerComponent;
     int bitsPerPixel;
} QEMUScreen;

int qemu_main(int argc, char **argv); // main defined in qemu/vl.c
NSWindow *normalWindow;
id cocoaView;
static void *screenBuffer;

int gArgc;
char **gArgv;

// keymap conversion
int keymap[] =
{
//  SdlI    macI    macH    SdlH    104xtH  104xtC  sdl
     30, //  0       0x00    0x1e            A       QZ_a
     31, //  1       0x01    0x1f            S       QZ_s
     32, //  2       0x02    0x20            D       QZ_d
     33, //  3       0x03    0x21            F       QZ_f
     35, //  4       0x04    0x23            H       QZ_h
     34, //  5       0x05    0x22            G       QZ_g
     44, //  6       0x06    0x2c            Z       QZ_z
     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
     48, //  11      0x0B    0x30            B       QZ_b
     16, //  12      0x0C    0x10            Q       QZ_q
     17, //  13      0x0D    0x11            W       QZ_w
     18, //  14      0x0E    0x12            E       QZ_e
     19, //  15      0x0F    0x13            R       QZ_r
     21, //  16      0x10    0x15            Y       QZ_y
     20, //  17      0x11    0x14            T       QZ_t
     2,  //  18      0x12    0x02            1       QZ_1
     3,  //  19      0x13    0x03            2       QZ_2
     4,  //  20      0x14    0x04            3       QZ_3
     5,  //  21      0x15    0x05            4       QZ_4
     7,  //  22      0x16    0x07            6       QZ_6
     6,  //  23      0x17    0x06            5       QZ_5
     13, //  24      0x18    0x0d            =       QZ_EQUALS
     10, //  25      0x19    0x0a            9       QZ_9
     8,  //  26      0x1A    0x08            7       QZ_7
     12, //  27      0x1B    0x0c            -       QZ_MINUS
     9,  //  28      0x1C    0x09            8       QZ_8
     11, //  29      0x1D    0x0b            0       QZ_0
     27, //  30      0x1E    0x1b            ]       QZ_RIGHTBRACKET
     24, //  31      0x1F    0x18            O       QZ_o
     22, //  32      0x20    0x16            U       QZ_u
     26, //  33      0x21    0x1a            [       QZ_LEFTBRACKET
     23, //  34      0x22    0x17            I       QZ_i
     25, //  35      0x23    0x19            P       QZ_p
     28, //  36      0x24    0x1c            ENTER   QZ_RETURN
     38, //  37      0x25    0x26            L       QZ_l
     36, //  38      0x26    0x24            J       QZ_j
     40, //  39      0x27    0x28            '       QZ_QUOTE
     37, //  40      0x28    0x25            K       QZ_k
     39, //  41      0x29    0x27            ;       QZ_SEMICOLON
     43, //  42      0x2A    0x2b            \       QZ_BACKSLASH
     51, //  43      0x2B    0x33            ,       QZ_COMMA
     53, //  44      0x2C    0x35            /       QZ_SLASH
     49, //  45      0x2D    0x31            N       QZ_n
     50, //  46      0x2E    0x32            M       QZ_m
     52, //  47      0x2F    0x34            .       QZ_PERIOD
     15, //  48      0x30    0x0f            TAB     QZ_TAB
     57, //  49      0x31    0x39            SPACE   QZ_SPACE
     41, //  50      0x32    0x29            `       QZ_BACKQUOTE
     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
     42, //  56      0x38    0x2a            L SHFT  QZ_LSHIFT
     58, //  57      0x39    0x3a            CAPS    QZ_CAPSLOCK
     56, //  58      0x3A    0x38            L ALT   QZ_LALT
     29, //  59      0x3B    0x1d            L CTRL  QZ_LCTRL
     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,  //  66      0x42    Undefined
     55, //  67      0x43    0x37            KP *    QZ_KP_MULTIPLY
     0,  //  68      0x44    Undefined
     78, //  69      0x45    0x4e            KP +    QZ_KP_PLUS
     0,  //  70      0x46    Undefined
     69, //  71      0x47    0x45            NUM     QZ_NUMLOCK
     0,  //  72      0x48    Undefined
     0,  //  73      0x49    Undefined
     0,  //  74      0x4A    Undefined
     181,//  75      0x4B    0xb5    E0,35   KP /    QZ_KP_DIVIDE
     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
     82, //  82      0x52    0x52            KP 0    QZ_KP0
     79, //  83      0x53    0x4f            KP 1    QZ_KP1
     80, //  84      0x54    0x50            KP 2    QZ_KP2
     81, //  85      0x55    0x51            KP 3    QZ_KP3
     75, //  86      0x56    0x4b            KP 4    QZ_KP4
     76, //  87      0x57    0x4c            KP 5    QZ_KP5
     77, //  88      0x58    0x4d            KP 6    QZ_KP6
     71, //  89      0x59    0x47            KP 7    QZ_KP7
     0,  //  90      0x5A    Undefined
     72, //  91      0x5B    0x48            KP 8    QZ_KP8
     73, //  92      0x5C    0x49            KP 9    QZ_KP9
     0,  //  93      0x5D    Undefined
     0,  //  94      0x5E    Undefined
     0,  //  95      0x5F    Undefined
     63, //  96      0x60    0x3f            F5      QZ_F5
     64, //  97      0x61    0x40            F6      QZ_F6
     65, //  98      0x62    0x41            F7      QZ_F7
     61, //  99      0x63    0x3d            F3      QZ_F3
     66, //  100     0x64    0x42            F8      QZ_F8
     67, //  101     0x65    0x43            F9      QZ_F9
     0,  //  102     0x66    Undefined
     87, //  103     0x67    0x57            F11     QZ_F11
     0,  //  104     0x68    Undefined
     183,//  105     0x69    0xb7                    QZ_PRINT
     0,  //  106     0x6A    Undefined
     70, //  107     0x6B    0x46            SCROLL  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
     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
     211,//  117     0x75    0xd3    E0,53   DELETE  QZ_DELETE
     62, //  118     0x76    0x3e            F4      QZ_F4
     207,//  119     0x77    0xcf    E0,4f   END     QZ_END
     60, //  120     0x78    0x3c            F2      QZ_F2
     209,//  121     0x79    0xd1    E0,51   PG DN   QZ_PAGEDOWN
     59, //  122     0x7A    0x3b            F1      QZ_F1
     203,//  123     0x7B    0xcb    e0,4B   L ARROW QZ_LEFT
     205,//  124     0x7C    0xcd    e0,4D   R ARROW QZ_RIGHT
     208,//  125     0x7D    0xd0    E0,50   D ARROW QZ_DOWN
     200,//  126     0x7E    0xc8    E0,48   U ARROW QZ_UP
/* completed according to http://www.libsdl.org/cgi/cvsweb.cgi/SDL12/src/video/quartz/SDL_QuartzKeys.h?rev=1.6&content-type=text/x-cvsweb-markup 
  */

/* 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
     227 //          0xe3            E0, 63  Wake
// Windows Multimedia Scan Codes
     153 //          0x99            E0, 19  Next Track
     144 //          0x90            E0, 10  Previous Track
     164 //          0xa4            E0, 24  Stop
     162 //          0xa2            E0, 22  Play/Pause
     160 //          0xa0            E0, 20  Mute
     176 //          0xb0            E0, 30  Volume Up
     174 //          0xae            E0, 2E  Volume Down
     237 //          0xed            E0, 6D  Media Select
     236 //          0xec            E0, 6C  E-Mail
     161 //          0xa1            E0, 21  Calculator
     235 //          0xeb            E0, 6B  My Computer
     229 //          0xe5            E0, 65  WWW Search
     178 //          0xb2            E0, 32  WWW Home
     234 //          0xea            E0, 6A  WWW Back
     233 //          0xe9            E0, 69  WWW Forward
     232 //          0xe8            E0, 68  WWW Stop
     231 //          0xe7            E0, 67  WWW Refresh
     230 //          0xe6            E0, 66  WWW Favorites
*/
};

int cocoa_keycode_to_qemu(int keycode)
{
     if((sizeof(keymap)/sizeof(int)) <= keycode)
     {
         printf("(cocoa) warning unknow keycode 0x%x\n", keycode);
         return 0;
     }
     return keymap[keycode];
}



/*
  ------------------------------------------------------
     QemuCocoaView
  ------------------------------------------------------
*/
@interface QemuCocoaView : NSView
{
     QEMUScreen screen;
     NSWindow *fullScreenWindow;
     float cx,cy,cw,ch,cdx,cdy;
     CGDataProviderRef dataProviderRef;
     int modifiers_state[256];
     BOOL isMouseGrabed;
     BOOL isFullscreen;
     BOOL isAbsoluteEnabled;
     BOOL isTabletEnabled;
}
- (void) resizeContentToWidth:(int)w height:(int)h displayState: 
(DisplayState *)ds;
- (void) grabMouse;
- (void) ungrabMouse;
- (void) toggleFullScreen:(id)sender;
- (void) handleEvent:(NSEvent *)event;
- (void) setAbsoluteEnabled:(BOOL)tIsAbsoluteEnabled;
- (BOOL) isMouseGrabed;
- (BOOL) isAbsoluteEnabled;
- (float) cdx;
- (float) cdy;
- (QEMUScreen) gscreen;
@end

@implementation QemuCocoaView
- (id)initWithFrame:(NSRect)frameRect
{
     COCOA_DEBUG("QemuCocoaView: initWithFrame\n");

     self = [super initWithFrame:frameRect];
     if (self) {

         screen.bitsPerComponent = 8;
         screen.bitsPerPixel = 32;
         screen.width = frameRect.size.width;
         screen.height = frameRect.size.height;

     }
     return self;
}

- (void) dealloc
{
     COCOA_DEBUG("QemuCocoaView: dealloc\n");

     if (screenBuffer)
         free(screenBuffer);

     if (dataProviderRef)
         CGDataProviderRelease(dataProviderRef);

     [super dealloc];
}

- (void) drawRect:(NSRect) rect
{
     COCOA_DEBUG("QemuCocoaView: drawRect\n");

     if ((int)screenBuffer == -1)
         return;

     // get CoreGraphic context
     CGContextRef viewContextRef = [[NSGraphicsContext currentContext]  
graphicsPort];
     CGContextSetInterpolationQuality (viewContextRef,  
kCGInterpolationNone);
     CGContextSetShouldAntialias (viewContextRef, NO);

     // draw screen bitmap directly to Core Graphics context
     if (dataProviderRef) {
         CGImageRef imageRef = CGImageCreate(
             screen.width, //width
             screen.height, //height
             screen.bitsPerComponent, //bitsPerComponent
             screen.bitsPerPixel, //bitsPerPixel
             (screen.width * 4), //bytesPerRow
#if __LITTLE_ENDIAN__
             CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB), // 
colorspace for OS X >= 10.4
             kCGImageAlphaNoneSkipLast,
#else
             CGColorSpaceCreateDeviceRGB(), //colorspace for OS X <  
10.4 (actually ppc)
             kCGImageAlphaNoneSkipFirst, //bitmapInfo
#endif
             dataProviderRef, //provider
             NULL, //decode
             0, //interpolate
             kCGRenderingIntentDefault //intent
         );
// test if host support "CGImageCreateWithImageInRect" at compiletime
#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
         if (CGImageCreateWithImageInRect == NULL) { // test if  
"CGImageCreateWithImageInRect" is supported on host at runtime
#endif
             // compatibility drawing code (draws everything) (OS X <  
10.4)
             CGContextDrawImage (viewContextRef, CGRectMake(0, 0,  
[self bounds].size.width, [self bounds].size.height), imageRef);
#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
         } else {
             // selective drawing code (draws only dirty rectangles)  
(OS X >= 10.4)
             const NSRect *rectList;
             int rectCount;
             int i;
             CGImageRef clipImageRef;
             CGRect clipRect;

             [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;
                 clipImageRef = CGImageCreateWithImageInRect(
                     imageRef,
                     clipRect
                 );
                 CGContextDrawImage (viewContextRef,  
cgrect(rectList[i]), clipImageRef);
                 CGImageRelease (clipImageRef);
             }
         }
#endif
         CGImageRelease (imageRef);
     }
}

- (void) setContentDimensions
{
     COCOA_DEBUG("QemuCocoaView: setContentDimensions\n");

     if (isFullscreen) {
         cdx = [[NSScreen mainScreen] frame].size.width /  
(float)screen.width;
         cdy = [[NSScreen mainScreen] frame].size.height /  
(float)screen.height;
         cw = screen.width * cdx;
         ch = screen.height * cdy;
         cx = ([[NSScreen mainScreen] frame].size.width - cw) / 2.0;
         cy = ([[NSScreen mainScreen] frame].size.height - ch) / 2.0;
     } else {
         cx = 0;
         cy = 0;
         cw = screen.width;
         ch = screen.height;
         cdx = 1.0;
         cdy = 1.0;
     }
}

- (void) resizeContentToWidth:(int)w height:(int)h displayState: 
(DisplayState *)ds
{
     COCOA_DEBUG("QemuCocoaView: resizeContent\n");

     // update screenBuffer
     if (dataProviderRef)
         CGDataProviderRelease(dataProviderRef);
     if (screenBuffer)
         free(screenBuffer);
     screenBuffer = malloc( w * 4 * h );

     ds->data = screenBuffer;
     ds->linesize =  (w * 4);
     ds->depth = 32;
     ds->width = w;
     ds->height = h;
#ifdef __LITTLE_ENDIAN__
     ds->bgr = 1;
#else
     ds->bgr = 0;
#endif

     dataProviderRef = CGDataProviderCreateWithData(NULL,  
screenBuffer, w * 4 * h, NULL);

     // update windows
     if (isFullscreen) {
         [[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:YES];
     }
     screen.width = w;
     screen.height = h;
     [self setContentDimensions];
     [self setFrame:NSMakeRect(cx, cy, cw, ch)];
}

- (void) toggleFullScreen:(id)sender
{
     COCOA_DEBUG("QemuCocoaView: toggleFullScreen\n");

     if (isFullscreen) { // switch from fullscreen to desktop
         isFullscreen = FALSE;
         [self ungrabMouse];
         [self setContentDimensions];
// test if host support "enterFullScreenMode:withOptions" at compiletime
#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
         if ([NSView  
respondsToSelector:@selector(exitFullScreenModeWithOptions:)]) { //  
test if "exitFullScreenModeWithOptions" is supported on host at runtime
             [self exitFullScreenModeWithOptions:nil];
         } else {
#endif
             [fullScreenWindow close];
             [normalWindow setContentView: self];
             [normalWindow makeKeyAndOrderFront: self];
             [NSMenu setMenuBarVisible:YES];
#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
         }
#endif
     } else { // switch from desktop to fullscreen
         isFullscreen = TRUE;
         [self grabMouse];
         [self setContentDimensions];
// test if host support "enterFullScreenMode:withOptions" at compiletime
#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
         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]];
         } else {
#endif
             [NSMenu setMenuBarVisible:NO];
             fullScreenWindow = [[NSWindow alloc] initWithContentRect: 
[[NSScreen mainScreen] frame]
                 styleMask:NSBorderlessWindowMask
                 backing:NSBackingStoreBuffered
                 defer:NO];
             [fullScreenWindow setHasShadow:NO];
             [fullScreenWindow setContentView:self];
             [fullScreenWindow makeKeyAndOrderFront:self];
#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
         }
#endif
     }
}

- (void) handleEvent:(NSEvent *)event
{
     COCOA_DEBUG("QemuCocoaView: handleEvent\n");

     int buttons = 0;
     int keycode;
     NSPoint p = [event locationInWindow];

     switch ([event type]) {
         case NSFlagsChanged:
             keycode = cocoa_keycode_to_qemu([event keyCode]);
             if (keycode) {
                 if (keycode == 58 || keycode == 69) { // emulate caps  
lock and num lock keydown and keyup
                     kbd_put_keycode(keycode);
                     kbd_put_keycode(keycode | 0x80);
                 } else if (is_graphic_console()) {
                     if (keycode & 0x80)
                         kbd_put_keycode(0xe0);
                     if (modifiers_state[keycode] == 0) { // keydown
                         kbd_put_keycode(keycode & 0x7f);
                         modifiers_state[keycode] = 1;
                     } else { // keyup
                         kbd_put_keycode(keycode | 0x80);
                         modifiers_state[keycode] = 0;
                     }
                 }
             }

             // release Mouse grab when pressing ctrl+alt
             if (!isFullscreen && ([event modifierFlags] &  
NSControlKeyMask) && ([event modifierFlags] & NSAlternateKeyMask)) {
                 [self ungrabMouse];
             }
             break;
         case NSKeyDown:

             // forward command Key Combos
             if ([event modifierFlags] & NSCommandKeyMask) {
                 [NSApp sendEvent:event];
                 return;
             }

             // default
             keycode = cocoa_keycode_to_qemu([event keyCode]);

             // handle control + alt Key Combos (ctrl+alt is reserved  
for QEMU)
             if (([event modifierFlags] & NSControlKeyMask) && ([event  
modifierFlags] & NSAlternateKeyMask)) {
                 switch (keycode) {

                     // enable graphic console
                     case 0x02 ... 0x0a: // '1' to '9' keys
                         console_select(keycode - 0x02);
                         break;
                 }

             // handle keys for graphic console
             } else if (is_graphic_console()) {
                 if (keycode & 0x80) //check bit for e0 in front
                     kbd_put_keycode(0xe0);
                 kbd_put_keycode(keycode & 0x7f); //remove e0 bit in  
front

             // handlekeys for Monitor
             } else {
                 int keysym = 0;
                 switch([event keyCode]) {
                 case 115:
                     keysym = QEMU_KEY_HOME;
                     break;
                 case 117:
                     keysym = QEMU_KEY_DELETE;
                     break;
                 case 119:
                     keysym = QEMU_KEY_END;
                     break;
                 case 123:
                     keysym = QEMU_KEY_LEFT;
                     break;
                 case 124:
                     keysym = QEMU_KEY_RIGHT;
                     break;
                 case 125:
                     keysym = QEMU_KEY_DOWN;
                     break;
                 case 126:
                     keysym = QEMU_KEY_UP;
                     break;
                 default:
                     {
                         NSString *ks = [event characters];
                         if ([ks length] > 0)
                             keysym = [ks characterAtIndex:0];
                     }
                 }
                 if (keysym)
                     kbd_put_keysym(keysym);
             }
             break;
         case NSKeyUp:
             keycode = cocoa_keycode_to_qemu([event keyCode]);
             if (is_graphic_console()) {
                 if (keycode & 0x80)
                     kbd_put_keycode(0xe0);
                 kbd_put_keycode(keycode | 0x80); //add 128 to signal  
release of key
             }
             break;
         case NSMouseMoved:
             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];
                         isTabletEnabled = FALSE;
                     }
                 } else {
                     if (!isTabletEnabled) { // if we enter the  
window, activate the tablet
                         [NSCursor hide];
                         isTabletEnabled = TRUE;
                     }
                 }
             }
             COCOA_MOUSE_EVENT
             break;
         case NSLeftMouseDown:
             if ([event modifierFlags] & NSCommandKeyMask) {
                 buttons |= MOUSE_EVENT_RBUTTON;
             } else {
                 buttons |= MOUSE_EVENT_LBUTTON;
             }
             COCOA_MOUSE_EVENT
             break;
         case NSRightMouseDown:
             buttons |= MOUSE_EVENT_RBUTTON;
             COCOA_MOUSE_EVENT
             break;
         case NSOtherMouseDown:
             buttons |= MOUSE_EVENT_MBUTTON;
             COCOA_MOUSE_EVENT
             break;
         case NSLeftMouseDragged:
             if ([event modifierFlags] & NSCommandKeyMask) {
                 buttons |= MOUSE_EVENT_RBUTTON;
             } else {
                 buttons |= MOUSE_EVENT_LBUTTON;
             }
             COCOA_MOUSE_EVENT
             break;
         case NSRightMouseDragged:
             buttons |= MOUSE_EVENT_RBUTTON;
             COCOA_MOUSE_EVENT
             break;
         case NSOtherMouseDragged:
             buttons |= MOUSE_EVENT_MBUTTON;
             COCOA_MOUSE_EVENT
             break;
         case NSLeftMouseUp:
             if (isTabletEnabled) {
                     COCOA_MOUSE_EVENT
             } else if (!isMouseGrabed) {
                 if (p.x > -1 && p.x < screen.width && p.y > -1 && p.y  
< screen.height) {
                     [self grabMouse];
                 } else {
                     [NSApp sendEvent:event];
                 }
             } else {
                 COCOA_MOUSE_EVENT
             }
             break;
         case NSRightMouseUp:
             COCOA_MOUSE_EVENT
             break;
         case NSOtherMouseUp:
             COCOA_MOUSE_EVENT
             break;
         case NSScrollWheel:
             if (isTabletEnabled || isMouseGrabed) {
                 kbd_mouse_event(0, 0, -[event deltaY], 0);
             } else {
                 [NSApp sendEvent:event];
             }
             break;
         default:
             [NSApp sendEvent:event];
     }
}

- (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];
     CGAssociateMouseAndMouseCursorPosition(FALSE);
     isMouseGrabed = TRUE; // while isMouseGrabed = TRUE, QemuCocoaApp  
sends all events to [cocoaView handleEvent:]
}

- (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];
     CGAssociateMouseAndMouseCursorPosition(TRUE);
     isMouseGrabed = FALSE;
}

- (void) setAbsoluteEnabled:(BOOL)tIsAbsoluteEnabled  
{isAbsoluteEnabled = tIsAbsoluteEnabled;}
- (BOOL) isMouseGrabed {return isMouseGrabed;}
- (BOOL) isAbsoluteEnabled {return isAbsoluteEnabled;}
- (float) cdx {return cdx;}
- (float) cdy {return cdy;}
- (QEMUScreen) gscreen {return screen;}
@end



/*
  ------------------------------------------------------
     QemuCocoaAppController
  ------------------------------------------------------
*/
@interface QemuCocoaAppController : NSObject
{
}
- (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
- (id) init
{
     COCOA_DEBUG("QemuCocoaAppController: init\n");

     self = [super init];
     if (self) {

         // create a view and add it to the window
         cocoaView = [[QemuCocoaView alloc]  
initWithFrame:NSMakeRect(0.0, 0.0, 640.0, 480.0)];
         if(!cocoaView) {
             fprintf(stderr, "(cocoa) can't create a view\n");
             exit(1);
         }

         // create a window
         normalWindow = [[NSWindow alloc] initWithContentRect: 
[cocoaView frame]
             styleMask:NSTitledWindowMask|NSMiniaturizableWindowMask| 
NSClosableWindowMask
             backing:NSBackingStoreBuffered defer:NO];
         if(!normalWindow) {
             fprintf(stderr, "(cocoa) can't create window\n");
             exit(1);
         }
         [normalWindow setAcceptsMouseMovedEvents:YES];
         [normalWindow setTitle:[NSString stringWithFormat:@"QEMU"]];
         [normalWindow setContentView:cocoaView];
         [normalWindow makeKeyAndOrderFront:self];

     }
     return self;
}

- (void) dealloc
{
     COCOA_DEBUG("QemuCocoaAppController: dealloc\n");

     if (cocoaView)
         [cocoaView release];
     [super dealloc];
}

- (void)applicationDidFinishLaunching: (NSNotification *) note
{
     COCOA_DEBUG("QemuCocoaAppController: applicationDidFinishLaunching 
\n");

     // Display an open dialog box if no argument were passed or
     // if qemu was launched from the finder ( the Finder passes "- 
psn" )
     if( gArgc <= 1 || strncmp ((char *)gArgv[1], "-psn", 4) == 0) {
         NSOpenPanel *op = [[NSOpenPanel alloc] init];
         [op setPrompt:@"Boot image"];
         [op setMessage:@"Select the disk image you want to boot.\n 
\nHit the \"Cancel\" button to quit"];
         [op beginSheetForDirectory:nil file:nil types:[NSArray  
arrayWithObjects 
:@"img",@"iso",@"dmg",@"qcow",@"cow",@"cloop",@"vmdk",nil]
               modalForWindow:normalWindow modalDelegate:self
                
didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:)  
contextInfo:NULL];
     } else {
         // or Launch Qemu, with the global args
         [self startEmulationWithArgc:gArgc argv:(char **)gArgv];
     }
}

- (void)applicationWillTerminate:(NSNotification *)aNotification
{
     COCOA_DEBUG("QemuCocoaAppController: applicationWillTerminate\n");

     qemu_system_shutdown_request();
     exit(0);
}

- (void)startEmulationWithArgc:(int)argc argv:(char**)argv
{
     COCOA_DEBUG("QemuCocoaAppController: startEmulationWithArgc\n");

     int status;
     status = qemu_main(argc, argv);
     exit(status);
}

- (void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode: 
(int)returnCode contextInfo:(void *)contextInfo
{
     COCOA_DEBUG("QemuCocoaAppController: openPanelDidEnd\n");

     if(returnCode == NSCancelButton) {
         exit(0);
     } else if(returnCode == NSOKButton) {
         char *bin = "qemu";
         char *img = (char*)[ [ sheet filename ]  
cStringUsingEncoding:NSASCIIStringEncoding];

         char **argv = (char**)malloc( sizeof(char*)*3 );

         asprintf(&argv[0], "%s", bin);
         asprintf(&argv[1], "-hda");
         asprintf(&argv[2], "%s", img);

         printf("Using argc %d argv %s -hda %s\n", 3, bin, img);

         [self startEmulationWithArgc:3 argv:(char**)argv];
     }
}
- (void)toggleFullScreen:(id)sender
{
     COCOA_DEBUG("QemuCocoaAppController: toggleFullScreen\n");

     [cocoaView toggleFullScreen:sender];
}

- (void)showQEMUDoc:(id)sender
{
     COCOA_DEBUG("QemuCocoaAppController: showQEMUDoc\n");

     [[NSWorkspace sharedWorkspace] openFile:[NSString  
stringWithFormat:@"%@/../doc/qemu/qemu-doc.html",
         [[NSBundle mainBundle] resourcePath]] withApplication:@"Help  
Viewer"];
}

- (void)showQEMUTec:(id)sender
{
     COCOA_DEBUG("QemuCocoaAppController: showQEMUTec\n");

     [[NSWorkspace sharedWorkspace] openFile:[NSString  
stringWithFormat:@"%@/../doc/qemu/qemu-tech.html",
         [[NSBundle mainBundle] resourcePath]] withApplication:@"Help  
Viewer"];
}
@end



// Dock Connection
typedef struct CPSProcessSerNum
{
         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;

     NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
     [NSApplication sharedApplication];

     if (!CPSGetCurrentProcess(&PSN))
         if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103))
             if (!CPSSetFrontProcess(&PSN))
                 [NSApplication sharedApplication];

     // Add menus
     NSMenu      *menu;
     NSMenuItem  *menuItem;

     [NSApp setMainMenu:[[NSMenu alloc] init]];

     // Application menu
     menu = [[NSMenu alloc] initWithTitle:@""];
     [menu addItemWithTitle:@"About QEMU"  
action:@selector(orderFrontStandardAboutPanel:) 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"];
     menuItem = [[NSMenuItem alloc] initWithTitle:@"Apple" action:nil  
keyEquivalent:@""];
     [menuItem setSubmenu:menu];
     [[NSApp mainMenu] addItem:menuItem];
     [NSApp performSelector:@selector(setAppleMenu:)  
withObject:menu]; // Workaround (this method is private since 10.4+)

     // View menu
     menu = [[NSMenu alloc] initWithTitle:@"View"];
     [menu addItem: [[[NSMenuItem alloc] initWithTitle:@"Enter  
Fullscreen" action:@selector(toggleFullScreen:) keyEquivalent:@"f"]  
autorelease]]; // Fullscreen
     menuItem = [[[NSMenuItem alloc] initWithTitle:@"View" action:nil  
keyEquivalent:@""] autorelease];
     [menuItem setSubmenu:menu];
     [[NSApp mainMenu] addItem:menuItem];

     // Window menu
     menu = [[NSMenu alloc] initWithTitle:@"Window"];
     [menu addItem: [[[NSMenuItem alloc] initWithTitle:@"Minimize"  
action:@selector(performMiniaturize:) keyEquivalent:@"m"]  
autorelease]]; // Miniaturize
     menuItem = [[[NSMenuItem alloc] initWithTitle:@"Window"  
action:nil keyEquivalent:@""] autorelease];
     [menuItem setSubmenu:menu];
     [[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];

     // Start the main event loop
     [NSApp run];

     [appController release];
     [pool release];

     return 0;
}



#pragma mark qemu
static void cocoa_update(DisplayState *ds, int x, int y, int w, int h)
{
     COCOA_DEBUG("qemu_cocoa: cocoa_update\n");

     NSRect rect;
     if ([cocoaView cdx] == 1.0) {
         rect = NSMakeRect(x, [cocoaView gscreen].height - y - h, w, h);
     } else {
         rect = NSMakeRect(
             x * [cocoaView cdx],
             ([cocoaView gscreen].height - y - h) * [cocoaView cdy],
             w * [cocoaView cdx],
             h * [cocoaView cdy]);
     }
     [cocoaView displayRect:rect];
}

static void cocoa_resize(DisplayState *ds, int w, int h)
{
     COCOA_DEBUG("qemu_cocoa: cocoa_resize\n");

     [cocoaView resizeContentToWidth:w height:h displayState:ds];
}

static void cocoa_refresh(DisplayState *ds)
{
     COCOA_DEBUG("qemu_cocoa: cocoa_refresh\n");

     if (kbd_mouse_is_absolute()) {
         if (![cocoaView isAbsoluteEnabled]) {
             if ([cocoaView isMouseGrabed]) {
                 [cocoaView ungrabMouse];
             }
         }
         [cocoaView setAbsoluteEnabled:YES];
     }

     NSDate *distantPast;
     NSEvent *event;
     distantPast = [NSDate distantPast];
     do {
         event = [NSApp nextEventMatchingMask:NSAnyEventMask  
untilDate:distantPast
                         inMode: NSDefaultRunLoopMode dequeue:YES];
         if (event != nil) {
             [cocoaView handleEvent:event];
         }
     } while(event != nil);
     vga_hw_update();
}

static void cocoa_cleanup(void)
{
     COCOA_DEBUG("qemu_cocoa: cocoa_cleanup\n");

}

void cocoa_display_init(DisplayState *ds, int full_screen)
{
     COCOA_DEBUG("qemu_cocoa: cocoa_display_init\n");

     // register vga outpu callbacks
     ds->dpy_update = cocoa_update;
     ds->dpy_resize = cocoa_resize;
     ds->dpy_refresh = cocoa_refresh;

     // give window a initial Size
     cocoa_resize(ds, 640, 400);

     // register cleanup function
     atexit(cocoa_cleanup);
}



[-- Attachment #2: smime.p7s --]
[-- Type: application/pkcs7-signature, Size: 2111 bytes --]

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [Qemu-devel] [patch] cocoa.m - Core Graphics support
  2008-01-21 16:18 [Qemu-devel] [patch] cocoa.m - Core Graphics support Mike Kronenberg
@ 2008-01-30 18:59 ` Alexander Graf
  2008-01-30 19:05   ` Alexander Graf
                     ` (2 more replies)
  0 siblings, 3 replies; 15+ messages in thread
From: Alexander Graf @ 2008-01-30 18:59 UTC (permalink / raw)
  To: qemu-devel


On Jan 21, 2008, at 5:18 PM, Mike Kronenberg wrote:

> This is a complete rewrite of cocoa.m to support Core Graphics.
>
> As mentioned in earlier threads, the QuickDraw API is depreciated  
> starting with OS X 10.4.
> Now with OS X 10.5 it won't even compile QuickDraw code on x86_64.
>
>
> This implementation of cocoa.m has the following features:
>
> [new] partial drawing of the window as needed, implemented with CG.
> [new] fullscreen support
> [new] tablet support
> [new] View menu and item to enter Fullscreen (cmd-f)
> [new] Help menu and items to show qemu-doc.html (cmd-?) and qemu- 
> tec.html in the OS X "Help Viewer"
> [new] -name is shown in Title-bar of window
> [fix] Application menu creation for 10.4+ (API is private as of 10.4)
> [fix] Mouse-clicks on the guests window widgets are no longer  
> intercepted
> [fix] apple keyboard shortcuts forwarded (minimize (cmd-m), hide  
> QEMU (cmd-h), quit QEMU (cmd-q))
>
> It should compile on ppc/intel starting form 10.3 (10.2 with the  
> known workarounds).
>
> Please test and comment

I'm sorry that I didn't find the time to test this implementation  
before.

It's damn slow.

I ran it using my x86_64 on 10.5.1, targetting x86_64-softmmu and  
booting a linux kernel. I could literally see every like getting  
repainted (which btw did not happen with my quick hacky version I sent  
to the list some time ago).

I think the major problem is that too much is being done during  
drawRect. If I understand the code correctly, you create CGImage  
objects on every repaint, which is prone to be slow.

Why not simply reuse the framebuffer qemu provides anyway and leave  
everything else to CG?

Alex

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [Qemu-devel] [patch] cocoa.m - Core Graphics support
  2008-01-30 18:59 ` Alexander Graf
@ 2008-01-30 19:05   ` Alexander Graf
  2008-01-30 20:30   ` Mike Kronenberg
  2008-01-30 20:44   ` Mike Kronenberg
  2 siblings, 0 replies; 15+ messages in thread
From: Alexander Graf @ 2008-01-30 19:05 UTC (permalink / raw)
  To: qemu-devel


On Jan 30, 2008, at 7:59 PM, Alexander Graf wrote:

>
> On Jan 21, 2008, at 5:18 PM, Mike Kronenberg wrote:
>
>> This is a complete rewrite of cocoa.m to support Core Graphics.
>>
>> As mentioned in earlier threads, the QuickDraw API is depreciated  
>> starting with OS X 10.4.
>> Now with OS X 10.5 it won't even compile QuickDraw code on x86_64.
>>
>>
>> This implementation of cocoa.m has the following features:
>>
>> [new] partial drawing of the window as needed, implemented with CG.
>> [new] fullscreen support
>> [new] tablet support
>> [new] View menu and item to enter Fullscreen (cmd-f)
>> [new] Help menu and items to show qemu-doc.html (cmd-?) and qemu- 
>> tec.html in the OS X "Help Viewer"
>> [new] -name is shown in Title-bar of window
>> [fix] Application menu creation for 10.4+ (API is private as of 10.4)
>> [fix] Mouse-clicks on the guests window widgets are no longer  
>> intercepted
>> [fix] apple keyboard shortcuts forwarded (minimize (cmd-m), hide  
>> QEMU (cmd-h), quit QEMU (cmd-q))
>>
>> It should compile on ppc/intel starting form 10.3 (10.2 with the  
>> known workarounds).
>>
>> Please test and comment
>
> I'm sorry that I didn't find the time to test this implementation  
> before.
>
> It's damn slow.
>
> I ran it using my x86_64 on 10.5.1, targetting x86_64-softmmu and  
> booting a linux kernel. I could literally see every like getting  
> repainted (which btw did not happen with my quick hacky version I  
> sent to the list some time ago).
>
> I think the major problem is that too much is being done during  
> drawRect. If I understand the code correctly, you create CGImage  
> objects on every repaint, which is prone to be slow.
>
> Why not simply reuse the framebuffer qemu provides anyway and leave  
> everything else to CG?

I just reread my mail again and realized that I didn't say anything  
positive. Sorry about that.

It's great to see someone working on Mac OS X support and thanks a lot  
for writing a compatible implementation of cocoa.m that works with  
every Mac OS X version out there.

Alex

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [Qemu-devel] [patch] cocoa.m - Core Graphics support
  2008-01-30 18:59 ` Alexander Graf
  2008-01-30 19:05   ` Alexander Graf
@ 2008-01-30 20:30   ` Mike Kronenberg
  2008-01-30 20:39     ` Johannes Schindelin
                       ` (3 more replies)
  2008-01-30 20:44   ` Mike Kronenberg
  2 siblings, 4 replies; 15+ messages in thread
From: Mike Kronenberg @ 2008-01-30 20:30 UTC (permalink / raw)
  To: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 2918 bytes --]


On 30.01.2008, at 19:59, Alexander Graf wrote:

>
> On Jan 21, 2008, at 5:18 PM, Mike Kronenberg wrote:
>
>> This is a complete rewrite of cocoa.m to support Core Graphics.
>>
>> As mentioned in earlier threads, the QuickDraw API is depreciated  
>> starting with OS X 10.4.
>> Now with OS X 10.5 it won't even compile QuickDraw code on x86_64.
>>
>>
>> This implementation of cocoa.m has the following features:
>>
>> [new] partial drawing of the window as needed, implemented with CG.
>> [new] fullscreen support
>> [new] tablet support
>> [new] View menu and item to enter Fullscreen (cmd-f)
>> [new] Help menu and items to show qemu-doc.html (cmd-?) and qemu- 
>> tec.html in the OS X "Help Viewer"
>> [new] -name is shown in Title-bar of window
>> [fix] Application menu creation for 10.4+ (API is private as of 10.4)
>> [fix] Mouse-clicks on the guests window widgets are no longer  
>> intercepted
>> [fix] apple keyboard shortcuts forwarded (minimize (cmd-m), hide  
>> QEMU (cmd-h), quit QEMU (cmd-q))
>>
>> It should compile on ppc/intel starting form 10.3 (10.2 with the  
>> known workarounds).
>>
>> Please test and comment
>
> I'm sorry that I didn't find the time to test this implementation  
> before.
>
> It's damn slow.
>
> I ran it using my x86_64 on 10.5.1, targetting x86_64-softmmu and  
> booting a linux kernel. I could literally see every like getting  
> repainted (which btw did not happen with my quick hacky version I  
> sent to the list some time ago).
>
> I think the major problem is that too much is being done during  
> drawRect. If I understand the code correctly, you create CGImage  
> objects on every repaint, which is prone to be slow.
>
> Why not simply reuse the framebuffer qemu provides anyway and leave  
> everything else to CG?
>
> Alex
>
>


Hi Alex,

yes, as stated earlyer, it is slower than Quickdraw, especially if the  
whole screen is redrawn. Overal emulation speed for GUI apps is  
faster, dough, as only small portions of the screen are redrawn.

Unfortunateley, there is no "official" direct access to the  
framebuffer anymore, since apple depreciated QuickDraw. [1]
This way, there is no sharing/direct mapping of the cg framebuffer and  
qemu screenbuffer anymore.
Every time, a section needs display, that part of the qemu  
screenbuffer is mapped to a cg image and then copied on top of the CG  
stack.
CG is fully OpenGL based, so basically, if it needs to refresh an  
area, it has to load the area as texture, hence the copy.

Offtoppic about updated regions in Windows:
While testing with Quartzdebug, I realized, that qemu is updating  
always the whole screenwidth even if only the mouse is moved... is  
this a qemu problem, or is this the default windows behaviour?

Mike

[1] http://developer.apple.com/documentation/Carbon/Conceptual/QuickDrawToQuartz2D/tq_image_data/chapter_6_section_2.html#/ 
/apple_ref/doc/uid/TP40001098-CH227-BBCFFDBB

[-- Attachment #2: smime.p7s --]
[-- Type: application/pkcs7-signature, Size: 2111 bytes --]

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [Qemu-devel] [patch] cocoa.m - Core Graphics support
  2008-01-30 20:30   ` Mike Kronenberg
@ 2008-01-30 20:39     ` Johannes Schindelin
  2008-01-30 21:18       ` andrzej zaborowski
  2008-01-30 21:00     ` Pierre d'Herbemont
                       ` (2 subsequent siblings)
  3 siblings, 1 reply; 15+ messages in thread
From: Johannes Schindelin @ 2008-01-30 20:39 UTC (permalink / raw)
  To: Mike Kronenberg; +Cc: qemu-devel

Hi,

On Wed, 30 Jan 2008, Mike Kronenberg wrote:

> Offtoppic about updated regions in Windows: While testing with 
> Quartzdebug, I realized, that qemu is updating always the whole 
> screenwidth even if only the mouse is moved... is this a qemu problem, 
> or is this the default windows behaviour?

As far as I remember, this is a QEmu "problem".  It only marks lines as 
dirty, not pixels.

Ciao,
Dscho

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [Qemu-devel] [patch] cocoa.m - Core Graphics support
  2008-01-30 18:59 ` Alexander Graf
  2008-01-30 19:05   ` Alexander Graf
  2008-01-30 20:30   ` Mike Kronenberg
@ 2008-01-30 20:44   ` Mike Kronenberg
  2 siblings, 0 replies; 15+ messages in thread
From: Mike Kronenberg @ 2008-01-30 20:44 UTC (permalink / raw)
  To: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 747 bytes --]

>
> I ran it using my x86_64 on 10.5.1, targetting x86_64-softmmu and  
> booting a linux kernel. I could literally see every like getting  
> repainted (which btw did not happen with my quick hacky version I  
> sent to the list some time ago).

You did not notice the effect with Your implementation, because the  
the whole screen is redrawn every time.
With this implementation, only the parts requested by qemu are updated.

If You take a dosprompt, every line that moves up, triggers a redraw  
(only for the specific line) - this is why you notice the redraw.
You can test this easily with the Quartz debugger.

But never the less, overall speed is much faster with partial redraw,  
than if You redraw the whole screen every time.

Mike



[-- Attachment #2: smime.p7s --]
[-- Type: application/pkcs7-signature, Size: 2111 bytes --]

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [Qemu-devel] [patch] cocoa.m - Core Graphics support
  2008-01-30 20:30   ` Mike Kronenberg
  2008-01-30 20:39     ` Johannes Schindelin
@ 2008-01-30 21:00     ` Pierre d'Herbemont
  2008-01-30 21:54     ` Anthony Liguori
  2008-01-31  8:29     ` Alexander Graf
  3 siblings, 0 replies; 15+ messages in thread
From: Pierre d'Herbemont @ 2008-01-30 21:00 UTC (permalink / raw)
  To: qemu-devel


On Jan 30, 2008, at 9:30 PM, Mike Kronenberg wrote:

> Unfortunateley, there is no "official" direct access to the  
> framebuffer anymore, since apple depreciated QuickDraw. [1]

Well, you can using OpenGL and Apple's Extension have a nearly direct  
VRAM access, the idea is to use

glEnable( GL_UNPACK_CLIENT_STORAGE_APPLE );
glPixelStorei( GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE );

and

glTexParameteri( VLCGL_TARGET, GL_TEXTURE_STORAGE_HINT_APPLE,  
GL_STORAGE_SHARED_APPLE );

On the texture on which you want to draw. See:

http://developer.apple.com/documentation/GraphicsImaging/Conceptual/OpenGL-MacProgGuide/opengl_texturedata/chapter_10_section_2.html

Pierre.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [Qemu-devel] [patch] cocoa.m - Core Graphics support
  2008-01-30 20:39     ` Johannes Schindelin
@ 2008-01-30 21:18       ` andrzej zaborowski
  2008-01-31  9:15         ` Jamie Lokier
  0 siblings, 1 reply; 15+ messages in thread
From: andrzej zaborowski @ 2008-01-30 21:18 UTC (permalink / raw)
  To: qemu-devel

On 30/01/2008, Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:
> Hi,
>
> On Wed, 30 Jan 2008, Mike Kronenberg wrote:
>
> > Offtoppic about updated regions in Windows: While testing with
> > Quartzdebug, I realized, that qemu is updating always the whole
> > screenwidth even if only the mouse is moved... is this a qemu problem,
> > or is this the default windows behaviour?
>
> As far as I remember, this is a QEmu "problem".  It only marks lines as
> dirty, not pixels.

In addition lines are not marked dirty because they have a dirty pixel
in them but because they have a pixel in a dirty page. That means more
lines are updated than those containing dirty pixels.

Cheers

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [Qemu-devel] [patch] cocoa.m - Core Graphics support
  2008-01-30 20:30   ` Mike Kronenberg
  2008-01-30 20:39     ` Johannes Schindelin
  2008-01-30 21:00     ` Pierre d'Herbemont
@ 2008-01-30 21:54     ` Anthony Liguori
  2008-01-31  9:46       ` Jamie Lokier
  2008-01-31  8:29     ` Alexander Graf
  3 siblings, 1 reply; 15+ messages in thread
From: Anthony Liguori @ 2008-01-30 21:54 UTC (permalink / raw)
  To: qemu-devel

Mike Kronenberg wrote:
> While testing with Quartzdebug, I realized, that qemu is updating 
> always the whole screenwidth even if only the mouse is moved... is 
> this a qemu problem, or is this the default windows behaviour?

VGA framebuffer operations come in as memory operations.  They're 
tracked by watching what memory gets dirtied.  This can only operate at 
a page-granularity so this results in scan-line granularity updates.  
The VNC front-end goes to great lengths to keep a shadowed framebuffer 
and reduce these updates to a smaller update region.  You could possibly 
look at refactoring that code.  However...

I would be amazed if screen updates on OS X are so slow that it would 
make a difference if updates are in scanline granularities.  The copying 
latency is nothing compared to the other latencies in QEMU.  A modern 
processor can move memory at an extremely high speed.

At a refresh rate of 30 times per second, this is only ~4MB of data for 
mouse movements.  A typical processor can easily handle many GB of data 
per second.

Regards,

Anthony Liguori

> Mike
>
> [1] 
> http://developer.apple.com/documentation/Carbon/Conceptual/QuickDrawToQuartz2D/tq_image_data/chapter_6_section_2.html#//apple_ref/doc/uid/TP40001098-CH227-BBCFFDBB

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [Qemu-devel] [patch] cocoa.m - Core Graphics support
  2008-01-30 20:30   ` Mike Kronenberg
                       ` (2 preceding siblings ...)
  2008-01-30 21:54     ` Anthony Liguori
@ 2008-01-31  8:29     ` Alexander Graf
  3 siblings, 0 replies; 15+ messages in thread
From: Alexander Graf @ 2008-01-31  8:29 UTC (permalink / raw)
  To: qemu-devel


On Jan 30, 2008, at 9:30 PM, Mike Kronenberg wrote:

>
> On 30.01.2008, at 19:59, Alexander Graf wrote:
>
>>
>> On Jan 21, 2008, at 5:18 PM, Mike Kronenberg wrote:
>>
>>> This is a complete rewrite of cocoa.m to support Core Graphics.
>>>
>>> As mentioned in earlier threads, the QuickDraw API is depreciated  
>>> starting with OS X 10.4.
>>> Now with OS X 10.5 it won't even compile QuickDraw code on x86_64.
>>>
>>>
>>> This implementation of cocoa.m has the following features:
>>>
>>> [new] partial drawing of the window as needed, implemented with CG.
>>> [new] fullscreen support
>>> [new] tablet support
>>> [new] View menu and item to enter Fullscreen (cmd-f)
>>> [new] Help menu and items to show qemu-doc.html (cmd-?) and qemu- 
>>> tec.html in the OS X "Help Viewer"
>>> [new] -name is shown in Title-bar of window
>>> [fix] Application menu creation for 10.4+ (API is private as of  
>>> 10.4)
>>> [fix] Mouse-clicks on the guests window widgets are no longer  
>>> intercepted
>>> [fix] apple keyboard shortcuts forwarded (minimize (cmd-m), hide  
>>> QEMU (cmd-h), quit QEMU (cmd-q))
>>>
>>> It should compile on ppc/intel starting form 10.3 (10.2 with the  
>>> known workarounds).
>>>
>>> Please test and comment
>>
>> I'm sorry that I didn't find the time to test this implementation  
>> before.
>>
>> It's damn slow.
>>
>> I ran it using my x86_64 on 10.5.1, targetting x86_64-softmmu and  
>> booting a linux kernel. I could literally see every like getting  
>> repainted (which btw did not happen with my quick hacky version I  
>> sent to the list some time ago).
>>
>> I think the major problem is that too much is being done during  
>> drawRect. If I understand the code correctly, you create CGImage  
>> objects on every repaint, which is prone to be slow.
>>
>> Why not simply reuse the framebuffer qemu provides anyway and leave  
>> everything else to CG?
>>
>> Alex
>>
>>
>
>
> Hi Alex,
>
> yes, as stated earlyer, it is slower than Quickdraw, especially if  
> the whole screen is redrawn. Overal emulation speed for GUI apps is  
> faster, dough, as only small portions of the screen are redrawn.

That's good to hear. I tend to use Linux in command line mode in qemu  
quite often though, so for me the most important thing is full screen  
update, which apparently became slower. Merely running an SDL targeted  
qemu (did this on x86_64 linux) vs a cocoa one shows that something  
feels wrong on cocoa. Maybe there is no other way around this, but I  
still don't like seeing the screen scroll line for line ;-).

Unfortunately I don't have the time right now to investigate this in  
detail and I am really not into graphics programming usually. So for  
the time being it is still _way_ better than a solution that doesn't  
even compile.

The one thing I want to stress here is that maybe it might be worth  
looking into alternatives. If I find the time to do it, I will do so.  
I somehow like the idea of having a GL based video output.

Alex

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [Qemu-devel] [patch] cocoa.m - Core Graphics support
  2008-01-30 21:18       ` andrzej zaborowski
@ 2008-01-31  9:15         ` Jamie Lokier
  0 siblings, 0 replies; 15+ messages in thread
From: Jamie Lokier @ 2008-01-31  9:15 UTC (permalink / raw)
  To: qemu-devel

andrzej zaborowski wrote:
> > > Offtoppic about updated regions in Windows: While testing with
> > > Quartzdebug, I realized, that qemu is updating always the whole
> > > screenwidth even if only the mouse is moved... is this a qemu problem,
> > > or is this the default windows behaviour?
> >
> > As far as I remember, this is a QEmu "problem".  It only marks lines as
> > dirty, not pixels.
> 
> In addition lines are not marked dirty because they have a dirty pixel
> in them but because they have a pixel in a dirty page. That means more
> lines are updated than those containing dirty pixels.

However, if there's an emulated "hardware mouse cursor", just moving
the mouse could be optimised to those pixels only.

-- Jamie

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [Qemu-devel] [patch] cocoa.m - Core Graphics support
  2008-01-30 21:54     ` Anthony Liguori
@ 2008-01-31  9:46       ` Jamie Lokier
  2008-01-31 11:38         ` Julian Seward
  2008-01-31 22:40         ` Anthony Liguori
  0 siblings, 2 replies; 15+ messages in thread
From: Jamie Lokier @ 2008-01-31  9:46 UTC (permalink / raw)
  To: qemu-devel

Anthony Liguori wrote:
> VGA framebuffer operations come in as memory operations.  They're 
> tracked by watching what memory gets dirtied.  This can only operate at 
> a page-granularity so this results in scan-line granularity updates.  
> The VNC front-end goes to great lengths to keep a shadowed framebuffer 
> and reduce these updates to a smaller update region.  You could possibly 
> look at refactoring that code.  However...

That update region code should probably be moved to something generic
and made into a generic display option.

Reducing update region is logically orthogonal, and could work with
any update method (e.g. local X11, remote X11, local X11-OpenGL,
remote X11-OpenGL, SDL etc.).  With some of those, for some people
(especially some but not all remote setups) it might be worth it.

> I would be amazed if screen updates on OS X are so slow that it would 
> make a difference if updates are in scanline granularities.  The copying 
> latency is nothing compared to the other latencies in QEMU.  A modern 
> processor can move memory at an extremely high speed.
> 
> At a refresh rate of 30 times per second, this is only ~4MB of data for 
> mouse movements.  A typical processor can easily handle many GB of data 
> per second.

That's 16MB/frame on an Apple Cinema display at 32bpp, which is
0.5GB/sec.  Not too much, but not free either :-)

-- Jamie

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [Qemu-devel] [patch] cocoa.m - Core Graphics support
  2008-01-31  9:46       ` Jamie Lokier
@ 2008-01-31 11:38         ` Julian Seward
  2008-01-31 22:40         ` Anthony Liguori
  1 sibling, 0 replies; 15+ messages in thread
From: Julian Seward @ 2008-01-31 11:38 UTC (permalink / raw)
  To: qemu-devel

On Thursday 31 January 2008 10:46, Jamie Lokier wrote:
> Anthony Liguori wrote:
> > VGA framebuffer operations come in as memory operations.  They're
> > tracked by watching what memory gets dirtied.  This can only operate at
> > a page-granularity so this results in scan-line granularity updates.
> > The VNC front-end goes to great lengths to keep a shadowed framebuffer
> > and reduce these updates to a smaller update region.  You could possibly
> > look at refactoring that code.  However...
>
> That update region code should probably be moved to something generic
> and made into a generic display option.
>
> Reducing update region is logically orthogonal, and could work with
> any update method (e.g. local X11, remote X11, local X11-OpenGL,
> remote X11-OpenGL, SDL etc.).  With some of those, for some people
> (especially some but not all remote setups) it might be worth it.

For exactly these reasons I developed a shadow framebuffer patch
which ...

> makes QEMU's graphics emulation much more usable over remote
> X connections, by reducing the amount of data sent to the X server.
> This is particularly noticeable for small display updates, most
> importantly mouse cursor movements, which become faster and so 
> generally make the guest's GUI more pleasant to use.

See
http://lists.gnu.org/archive/html/qemu-devel/2007-03/msg00141.html
for the patch and short associated thread.  It never got included,
though.

J

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [Qemu-devel] [patch] cocoa.m - Core Graphics support
  2008-01-31  9:46       ` Jamie Lokier
  2008-01-31 11:38         ` Julian Seward
@ 2008-01-31 22:40         ` Anthony Liguori
  2008-01-31 23:03           ` Jamie Lokier
  1 sibling, 1 reply; 15+ messages in thread
From: Anthony Liguori @ 2008-01-31 22:40 UTC (permalink / raw)
  To: qemu-devel

Jamie Lokier wrote:
> Anthony Liguori wrote:
>   
>> VGA framebuffer operations come in as memory operations.  They're 
>> tracked by watching what memory gets dirtied.  This can only operate at 
>> a page-granularity so this results in scan-line granularity updates.  
>> The VNC front-end goes to great lengths to keep a shadowed framebuffer 
>> and reduce these updates to a smaller update region.  You could possibly 
>> look at refactoring that code.  However...
>>     
>
> That update region code should probably be moved to something generic
> and made into a generic display option.
>
> Reducing update region is logically orthogonal, and could work with
> any update method (e.g. local X11, remote X11, local X11-OpenGL,
> remote X11-OpenGL, SDL etc.).  With some of those, for some people
> (especially some but not all remote setups) it might be worth it.
>
>   
>> I would be amazed if screen updates on OS X are so slow that it would 
>> make a difference if updates are in scanline granularities.  The copying 
>> latency is nothing compared to the other latencies in QEMU.  A modern 
>> processor can move memory at an extremely high speed.
>>
>> At a refresh rate of 30 times per second, this is only ~4MB of data for 
>> mouse movements.  A typical processor can easily handle many GB of data 
>> per second.
>>     
>
> That's 16MB/frame on an Apple Cinema display at 32bpp, which is
> 0.5GB/sec.  Not too much, but not free either :-)
>   

But your guest isn't displaying to the entire screen...  I was assuming 
a 32-pixel height, 1024 pixel wide region.

Regards,

Anthony Liguori

> -- Jamie
>
>
>   

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [Qemu-devel] [patch] cocoa.m - Core Graphics support
  2008-01-31 22:40         ` Anthony Liguori
@ 2008-01-31 23:03           ` Jamie Lokier
  0 siblings, 0 replies; 15+ messages in thread
From: Jamie Lokier @ 2008-01-31 23:03 UTC (permalink / raw)
  To: qemu-devel

Anthony Liguori wrote:
> >That's 16MB/frame on an Apple Cinema display at 32bpp, which is
> >0.5GB/sec.  Not too much, but not free either :-)
> >  
> 
> But your guest isn't displaying to the entire screen...  I was assuming 
> a 32-pixel height, 1024 pixel wide region.

I don't know about you; I quite like running Qemu in full screen mode
on my biggest screen when I want to do some work in another OS.  (I
don't have a Cinema display, though, it was just to make the point).

But this is not an important thing, let's leave it.

-- Jamie

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2008-02-01  0:34 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-01-21 16:18 [Qemu-devel] [patch] cocoa.m - Core Graphics support Mike Kronenberg
2008-01-30 18:59 ` Alexander Graf
2008-01-30 19:05   ` Alexander Graf
2008-01-30 20:30   ` Mike Kronenberg
2008-01-30 20:39     ` Johannes Schindelin
2008-01-30 21:18       ` andrzej zaborowski
2008-01-31  9:15         ` Jamie Lokier
2008-01-30 21:00     ` Pierre d'Herbemont
2008-01-30 21:54     ` Anthony Liguori
2008-01-31  9:46       ` Jamie Lokier
2008-01-31 11:38         ` Julian Seward
2008-01-31 22:40         ` Anthony Liguori
2008-01-31 23:03           ` Jamie Lokier
2008-01-31  8:29     ` Alexander Graf
2008-01-30 20:44   ` Mike Kronenberg

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).