(linenum→info "unix/slp.c:2238")

qemu/0.9.1/cocoa.m

    1: /*
    2:  * QEMU Cocoa display driver
    3:  *
    4:  * Copyright (c) 2005 Pierre d'Herbemont
    5:  *                    many code/inspiration from SDL 1.2 code (LGPL)
    6:  *
    7:  * Permission is hereby granted, free of charge, to any person obtaining a copy
    8:  * of this software and associated documentation files (the "Software"), to deal
    9:  * in the Software without restriction, including without limitation the rights
   10:  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   11:  * copies of the Software, and to permit persons to whom the Software is
   12:  * furnished to do so, subject to the following conditions:
   13:  *
   14:  * The above copyright notice and this permission notice shall be included in
   15:  * all copies or substantial portions of the Software.
   16:  *
   17:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   18:  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   19:  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   20:  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   21:  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   22:  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
   23:  * THE SOFTWARE.
   24:  */
   25: /*
   26:     Todo :    x  miniaturize window
   27:               x  center the window
   28:               -  save window position
   29:               -  handle keyboard event
   30:               -  handle mouse event
   31:               -  non 32 bpp support
   32:               -  full screen
   33:               -  mouse focus
   34:               x  simple graphical prompt to demo
   35:               -  better graphical prompt
   36: */
   37: 
   38: #import <Cocoa/Cocoa.h>
   39: 
   40: #include "qemu-common.h"
   41: #include "console.h"
   42: #include "sysemu.h"
   43: 
   44: NSWindow *window = NULL;
   45: NSQuickDrawView *qd_view = NULL;
   46: 
   47: 
   48: int gArgc;
   49: char **gArgv;
   50: DisplayState current_ds;
   51: 
   52: int grab = 0;
   53: int modifiers_state[256];
   54: 
   55: /* main defined in qemu/vl.c */
   56: int qemu_main(int argc, char **argv);
   57: 
   58: /* To deal with miniaturization */
   59: @interface QemuWindow : NSWindow
   60: { }
   61: @end
   62: 
   63: 
   64: /*
   65:  ------------------------------------------------------
   66:     Qemu Video Driver
   67:  ------------------------------------------------------
   68: */
   69: 
   70: /*
   71:  ------------------------------------------------------
   72:     cocoa_update
   73:  ------------------------------------------------------
   74: */
   75: static void cocoa_update(DisplayState *ds, int x, int y, int w, int h)
   76: {
   77:     //printf("updating x=%d y=%d w=%d h=%d\n", x, y, w, h);
   78: 
   79:     /* Use QDFlushPortBuffer() to flush content to display */
   80:     RgnHandle dirty = NewRgn ();
   81:     RgnHandle temp  = NewRgn ();
   82: 
   83:     SetEmptyRgn (dirty);
   84: 
   85:     /* Build the region of dirty rectangles */
   86:     MacSetRectRgn (temp, x, y,
   87:                         x + w, y + h);
   88:     MacUnionRgn (dirty, temp, dirty);
   89: 
   90:     /* Flush the dirty region */
   91:     QDFlushPortBuffer ( [ qd_view  qdPort ], dirty );
   92:     DisposeRgn (dirty);
   93:     DisposeRgn (temp);
   94: }
   95: 
   96: /*
   97:  ------------------------------------------------------
   98:     cocoa_resize
   99:  ------------------------------------------------------
  100: */
  101: static void cocoa_resize(DisplayState *ds, int w, int h)
  102: {
  103:     const int device_bpp = 32;
  104:     static void *screen_pixels;
  105:     static int  screen_pitch;
  106:     NSRect contentRect;
  107: 
  108:     //printf("resizing to %d %d\n", w, h);
  109: 
  110:     contentRect = NSMakeRect (0, 0, w, h);
  111:     if(window)
  112:     {
  113:         [window close];
  114:         [window release];
  115:     }
  116:     window = [ [ QemuWindow alloc ] initWithContentRect:contentRect
  117:                                   styleMask:NSTitledWindowMask|NSMiniaturizableWindowMask|NSClosableWindowMask
  118:                                   backing:NSBackingStoreBuffered defer:NO];
  119:     if(!window)
  120:     {
  121:         fprintf(stderr, "(cocoa) can't create window\n");
  122:         exit(1);
  123:     }
  124: 
  125:     if(qd_view)
  126:         [qd_view release];
  127: 
  128:     qd_view = [ [ NSQuickDrawView alloc ] initWithFrame:contentRect ];
  129: 
  130:     if(!qd_view)
  131:     {
  132:          fprintf(stderr, "(cocoa) can't create qd_view\n");
  133:         exit(1);
  134:     }
  135: 
  136:     [ window setAcceptsMouseMovedEvents:YES ];
  137:     [ window setTitle:@"Qemu" ];
  138:     [ window setReleasedWhenClosed:NO ];
  139: 
  140:     /* Set screen to black */
  141:     [ window setBackgroundColor: [NSColor blackColor] ];
  142: 
  143:     /* set window position */
  144:     [ window center ];
  145: 
  146:     [ qd_view setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable ];
  147:     [ [ window contentView ] addSubview:qd_view ];
  148:     [ qd_view release ];
  149:     [ window makeKeyAndOrderFront:nil ];
  150: 
  151:     /* Careful here, the window seems to have to be onscreen to do that */
  152:     LockPortBits ( [ qd_view qdPort ] );
  153:     screen_pixels = GetPixBaseAddr ( GetPortPixMap ( [ qd_view qdPort ] ) );
  154:     screen_pitch  = GetPixRowBytes ( GetPortPixMap ( [ qd_view qdPort ] ) );
  155:     UnlockPortBits ( [ qd_view qdPort ] );
  156:     {
  157:             int vOffset = [ window frame ].size.height -
  158:                 [ qd_view frame ].size.height - [ qd_view frame ].origin.y;
  159: 
  160:             int hOffset = [ qd_view frame ].origin.x;
  161: 
  162:             screen_pixels += (vOffset * screen_pitch) + hOffset * (device_bpp/8);
  163:     }
  164:     ds->data = screen_pixels;
  165:     ds->linesize = screen_pitch;
  166:     ds->depth = device_bpp;
  167:     ds->width = w;
  168:     ds->height = h;
  169: #ifdef __LITTLE_ENDIAN__
  170:     ds->bgr = 1;
  171: #else
  172:     ds->bgr = 0;
  173: #endif
  174: 
  175:     current_ds = *ds;
  176: }
  177: 
  178: /*
  179:  ------------------------------------------------------
  180:     keymap conversion
  181:  ------------------------------------------------------
  182: */
  183: 
  184: int keymap[] =
  185: {
  186: //  SdlI    macI    macH    SdlH    104xtH  104xtC  sdl
  187:     30, //  0       0x00    0x1e            A       QZ_a
  188:     31, //  1       0x01    0x1f            S       QZ_s
  189:     32, //  2       0x02    0x20            D       QZ_d
  190:     33, //  3       0x03    0x21            F       QZ_f
  191:     35, //  4       0x04    0x23            H       QZ_h
  192:     34, //  5       0x05    0x22            G       QZ_g
  193:     44, //  6       0x06    0x2c            Z       QZ_z
  194:     45, //  7       0x07    0x2d            X       QZ_x
  195:     46, //  8       0x08    0x2e            C       QZ_c
  196:     47, //  9       0x09    0x2f            V       QZ_v
  197:     0,  //  10      0x0A    Undefined
  198:     48, //  11      0x0B    0x30            B       QZ_b
  199:     16, //  12      0x0C    0x10            Q       QZ_q
  200:     17, //  13      0x0D    0x11            W       QZ_w
  201:     18, //  14      0x0E    0x12            E       QZ_e
  202:     19, //  15      0x0F    0x13            R       QZ_r
  203:     21, //  16      0x10    0x15            Y       QZ_y
  204:     20, //  17      0x11    0x14            T       QZ_t
  205:     2,  //  18      0x12    0x02            1       QZ_1
  206:     3,  //  19      0x13    0x03            2       QZ_2
  207:     4,  //  20      0x14    0x04            3       QZ_3
  208:     5,  //  21      0x15    0x05            4       QZ_4
  209:     7,  //  22      0x16    0x07            6       QZ_6
  210:     6,  //  23      0x17    0x06            5       QZ_5
  211:     13, //  24      0x18    0x0d            =       QZ_EQUALS
  212:     10, //  25      0x19    0x0a            9       QZ_9
  213:     8,  //  26      0x1A    0x08            7       QZ_7
  214:     12, //  27      0x1B    0x0c            -       QZ_MINUS
  215:     9,  //  28      0x1C    0x09            8       QZ_8
  216:     11, //  29      0x1D    0x0b            0       QZ_0
  217:     27, //  30      0x1E    0x1b            ]       QZ_RIGHTBRACKET
  218:     24, //  31      0x1F    0x18            O       QZ_o
  219:     22, //  32      0x20    0x16            U       QZ_u
  220:     26, //  33      0x21    0x1a            [       QZ_LEFTBRACKET
  221:     23, //  34      0x22    0x17            I       QZ_i
  222:     25, //  35      0x23    0x19            P       QZ_p
  223:     28, //  36      0x24    0x1c            ENTER   QZ_RETURN
  224:     38, //  37      0x25    0x26            L       QZ_l
  225:     36, //  38      0x26    0x24            J       QZ_j
  226:     40, //  39      0x27    0x28            '       QZ_QUOTE
  227:     37, //  40      0x28    0x25            K       QZ_k
  228:     39, //  41      0x29    0x27            ;       QZ_SEMICOLON
  229:     43, //  42      0x2A    0x2b            \       QZ_BACKSLASH
  230:     51, //  43      0x2B    0x33            ,       QZ_COMMA
  231:     53, //  44      0x2C    0x35            /       QZ_SLASH
  232:     49, //  45      0x2D    0x31            N       QZ_n
  233:     50, //  46      0x2E    0x32            M       QZ_m
  234:     52, //  47      0x2F    0x34            .       QZ_PERIOD
  235:     15, //  48      0x30    0x0f            TAB     QZ_TAB
  236:     57, //  49      0x31    0x39            SPACE   QZ_SPACE
  237:     41, //  50      0x32    0x29            `       QZ_BACKQUOTE
  238:     14, //  51      0x33    0x0e            BKSP    QZ_BACKSPACE
  239:     0,  //  52      0x34    Undefined
  240:     1,  //  53      0x35    0x01            ESC     QZ_ESCAPE
  241:     0,  //  54      0x36                            QZ_RMETA
  242:     0,  //  55      0x37                            QZ_LMETA
  243:     42, //  56      0x38    0x2a            L SHFT  QZ_LSHIFT
  244:     58, //  57      0x39    0x3a            CAPS    QZ_CAPSLOCK
  245:     56, //  58      0x3A    0x38            L ALT   QZ_LALT
  246:     29, //  59      0x3B    0x1d            L CTRL  QZ_LCTRL
  247:     54, //  60      0x3C    0x36            R SHFT  QZ_RSHIFT
  248:     184,//  61      0x3D    0xb8    E0,38   R ALT   QZ_RALT
  249:     157,//  62      0x3E    0x9d    E0,1D   R CTRL  QZ_RCTRL
  250:     0,  //  63      0x3F    Undefined
  251:     0,  //  64      0x40    Undefined
  252:     0,  //  65      0x41    Undefined
  253:     0,  //  66      0x42    Undefined
  254:     55, //  67      0x43    0x37            KP *    QZ_KP_MULTIPLY
  255:     0,  //  68      0x44    Undefined
  256:     78, //  69      0x45    0x4e            KP +    QZ_KP_PLUS
  257:     0,  //  70      0x46    Undefined
  258:     69, //  71      0x47    0x45            NUM     QZ_NUMLOCK
  259:     0,  //  72      0x48    Undefined
  260:     0,  //  73      0x49    Undefined
  261:     0,  //  74      0x4A    Undefined
  262:     181,//  75      0x4B    0xb5    E0,35   KP /    QZ_KP_DIVIDE
  263:     152,//  76      0x4C    0x9c    E0,1C   KP EN   QZ_KP_ENTER
  264:     0,  //  77      0x4D    undefined
  265:     74, //  78      0x4E    0x4a            KP -    QZ_KP_MINUS
  266:     0,  //  79      0x4F    Undefined
  267:     0,  //  80      0x50    Undefined
  268:     0,  //  81      0x51                            QZ_KP_EQUALS
  269:     82, //  82      0x52    0x52            KP 0    QZ_KP0
  270:     79, //  83      0x53    0x4f            KP 1    QZ_KP1
  271:     80, //  84      0x54    0x50            KP 2    QZ_KP2
  272:     81, //  85      0x55    0x51            KP 3    QZ_KP3
  273:     75, //  86      0x56    0x4b            KP 4    QZ_KP4
  274:     76, //  87      0x57    0x4c            KP 5    QZ_KP5
  275:     77, //  88      0x58    0x4d            KP 6    QZ_KP6
  276:     71, //  89      0x59    0x47            KP 7    QZ_KP7
  277:     0,  //  90      0x5A    Undefined
  278:     72, //  91      0x5B    0x48            KP 8    QZ_KP8
  279:     73, //  92      0x5C    0x49            KP 9    QZ_KP9
  280:     0,  //  93      0x5D    Undefined
  281:     0,  //  94      0x5E    Undefined
  282:     0,  //  95      0x5F    Undefined
  283:     63, //  96      0x60    0x3f            F5      QZ_F5
  284:     64, //  97      0x61    0x40            F6      QZ_F6
  285:     65, //  98      0x62    0x41            F7      QZ_F7
  286:     61, //  99      0x63    0x3d            F3      QZ_F3
  287:     66, //  100     0x64    0x42            F8      QZ_F8
  288:     67, //  101     0x65    0x43            F9      QZ_F9
  289:     0,  //  102     0x66    Undefined
  290:     87, //  103     0x67    0x57            F11     QZ_F11
  291:     0,  //  104     0x68    Undefined
  292:     183,//  105     0x69    0xb7            QZ_PRINT
  293:     0,  //  106     0x6A    Undefined
  294:     70, //  107     0x6B    0x46            SCROLL  QZ_SCROLLOCK
  295:     0,  //  108     0x6C    Undefined
  296:     68, //  109     0x6D    0x44            F10     QZ_F10
  297:     0,  //  110     0x6E    Undefined
  298:     88, //  111     0x6F    0x58            F12     QZ_F12
  299:     0,  //  112     0x70    Undefined
  300:     110,//  113     0x71    0x0                     QZ_PAUSE
  301:     210,//  114     0x72    0xd2    E0,52   INSERT  QZ_INSERT
  302:     199,//  115     0x73    0xc7    E0,47   HOME    QZ_HOME
  303:     201,//  116     0x74    0xc9    E0,49   PG UP   QZ_PAGEUP
  304:     211,//  117     0x75    0xd3    E0,53   DELETE  QZ_DELETE
  305:     62, //  118     0x76    0x3e            F4      QZ_F4
  306:     207,//  119     0x77    0xcf    E0,4f   END     QZ_END
  307:     60, //  120     0x78    0x3c            F2      QZ_F2
  308:     209,//  121     0x79    0xd1    E0,51   PG DN   QZ_PAGEDOWN
  309:     59, //  122     0x7A    0x3b            F1      QZ_F1
  310:     203,//  123     0x7B    0xcb    e0,4B   L ARROW QZ_LEFT
  311:     205,//  124     0x7C    0xcd    e0,4D   R ARROW QZ_RIGHT
  312:     208,//  125     0x7D    0xd0    E0,50   D ARROW QZ_DOWN
  313:     200,//  126     0x7E    0xc8    E0,48   U ARROW QZ_UP
  314: /* 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 */
  315: 
  316: /* Aditional 104 Key XP-Keyboard Scancodes from http://www.computer-engineering.org/ps2keyboard/scancodes1.html */
  317: /*
  318:     219 //          0xdb            e0,5b   L GUI
  319:     220 //          0xdc            e0,5c   R GUI
  320:     221 //          0xdd            e0,5d   APPS
  321:         //              E0,2A,E0,37         PRNT SCRN
  322:         //              E1,1D,45,E1,9D,C5   PAUSE
  323:     83  //          0x53    0x53            KP .
  324: // ACPI Scan Codes
  325:     222 //          0xde            E0, 5E  Power
  326:     223 //          0xdf            E0, 5F  Sleep
  327:     227 //          0xe3            E0, 63  Wake
  328: // Windows Multimedia Scan Codes
  329:     153 //          0x99            E0, 19  Next Track
  330:     144 //          0x90            E0, 10  Previous Track
  331:     164 //          0xa4            E0, 24  Stop
  332:     162 //          0xa2            E0, 22  Play/Pause
  333:     160 //          0xa0            E0, 20  Mute
  334:     176 //          0xb0            E0, 30  Volume Up
  335:     174 //          0xae            E0, 2E  Volume Down
  336:     237 //          0xed            E0, 6D  Media Select
  337:     236 //          0xec            E0, 6C  E-Mail
  338:     161 //          0xa1            E0, 21  Calculator
  339:     235 //          0xeb            E0, 6B  My Computer
  340:     229 //          0xe5            E0, 65  WWW Search
  341:     178 //          0xb2            E0, 32  WWW Home
  342:     234 //          0xea            E0, 6A  WWW Back
  343:     233 //          0xe9            E0, 69  WWW Forward
  344:     232 //          0xe8            E0, 68  WWW Stop
  345:     231 //          0xe7            E0, 67  WWW Refresh
  346:     230 //          0xe6            E0, 66  WWW Favorites
  347: */
  348: };
  349: 
  350: int cocoa_keycode_to_qemu(int keycode)
  351: {
  352:     if((sizeof(keymap)/sizeof(int)) <= keycode)
  353:     {
  354:         printf("(cocoa) warning unknow keycode 0x%x\n", keycode);
  355:         return 0;
  356:     }
  357:     return keymap[keycode];
  358: }
  359: 
  360: /*
  361:  ------------------------------------------------------
  362:     cocoa_refresh
  363:  ------------------------------------------------------
  364: */
  365: static void cocoa_refresh(DisplayState *ds)
  366: {
  367:     //printf("cocoa_refresh \n");
  368:     NSDate *distantPast;
  369:     NSEvent *event;
  370:     NSAutoreleasePool *pool;
  371: 
  372:     pool = [ [ NSAutoreleasePool alloc ] init ];
  373:     distantPast = [ NSDate distantPast ];
  374: 
  375:     vga_hw_update();
  376: 
  377:     do {
  378:         event = [ NSApp nextEventMatchingMask:NSAnyEventMask untilDate:distantPast
  379:                         inMode: NSDefaultRunLoopMode dequeue:YES ];
  380:         if (event != nil) {
  381:             switch ([event type]) {
  382:                 case NSFlagsChanged:
  383:                     {
  384:                         int keycode = cocoa_keycode_to_qemu([event keyCode]);
  385: 
  386:                         if (keycode)
  387:                         {
  388:                             if (keycode == 58 || keycode == 69) {
  389:                                 /* emulate caps lock and num lock keydown and keyup */
  390:                                 kbd_put_keycode(keycode);
  391:                                 kbd_put_keycode(keycode | 0x80);
  392:                             } else if (is_graphic_console()) {
  393:                                 if (keycode & 0x80)
  394:                                     kbd_put_keycode(0xe0);
  395:                                 if (modifiers_state[keycode] == 0) {
  396:                                     /* keydown */
  397:                                     kbd_put_keycode(keycode & 0x7f);
  398:                                     modifiers_state[keycode] = 1;
  399:                                 } else {
  400:                                     /* keyup */
  401:                                     kbd_put_keycode(keycode | 0x80);
  402:                                     modifiers_state[keycode] = 0;
  403:                                 }
  404:                             }
  405:                         }
  406: 
  407:                         /* release Mouse grab when pressing ctrl+alt */
  408:                         if (([event modifierFlags] & NSControlKeyMask) && ([event modifierFlags] & NSAlternateKeyMask))
  409:                         {
  410:                             [window setTitle: @"QEMU"];
  411:                             [NSCursor unhide];
  412:                             CGAssociateMouseAndMouseCursorPosition ( TRUE );
  413:                             grab = 0;
  414:                         }
  415:                     }
  416:                     break;
  417: 
  418:                 case NSKeyDown:
  419:                     {
  420:                         int keycode = cocoa_keycode_to_qemu([event keyCode]);
  421: 
  422:                         /* handle command Key Combos */
  423:                         if ([event modifierFlags] & NSCommandKeyMask) {
  424:                             switch ([event keyCode]) {
  425:                                 /* quit */
  426:                                 case 12: /* q key */
  427:                                     /* switch to windowed View */
  428:                                     exit(0);
  429:                                     return;
  430:                             }
  431:                         }
  432: 
  433:                         /* handle control + alt Key Combos */
  434:                         if (([event modifierFlags] & NSControlKeyMask) && ([event modifierFlags] & NSAlternateKeyMask)) {
  435:                             switch (keycode) {
  436:                                 /* toggle Monitor */
  437:                                 case 0x02 ... 0x0a: /* '1' to '9' keys */
  438:                                     console_select(keycode - 0x02);
  439:                                     break;
  440:                             }
  441:                         } else {
  442:                             /* handle standard key events */
  443:                             if (is_graphic_console()) {
  444:                                 if (keycode & 0x80) //check bit for e0 in front
  445:                                     kbd_put_keycode(0xe0);
  446:                                 kbd_put_keycode(keycode & 0x7f); //remove e0 bit in front
  447:                             /* handle monitor key events */
  448:                             } else {
  449:                                 int keysym = 0;
  450: 
  451:                                 switch([event keyCode]) {
  452:                                 case 115:
  453:                                     keysym = QEMU_KEY_HOME;
  454:                                     break;
  455:                                 case 117:
  456:                                     keysym = QEMU_KEY_DELETE;
  457:                                     break;
  458:                                 case 119:
  459:                                     keysym = QEMU_KEY_END;
  460:                                     break;
  461:                                 case 123:
  462:                                     keysym = QEMU_KEY_LEFT;
  463:                                     break;
  464:                                 case 124:
  465:                                     keysym = QEMU_KEY_RIGHT;
  466:                                     break;
  467:                                 case 125:
  468:                                     keysym = QEMU_KEY_DOWN;
  469:                                     break;
  470:                                 case 126:
  471:                                     keysym = QEMU_KEY_UP;
  472:                                     break;
  473:                                 default:
  474:                                     {
  475:                                         NSString *ks = [event characters];
  476: 
  477:                                         if ([ks length] > 0)
  478:                                             keysym = [ks characterAtIndex:0];
  479:                                     }
  480:                                 }
  481:                                 if (keysym)
  482:                                     kbd_put_keysym(keysym);
  483:                             }
  484:                         }
  485:                     }
  486:                     break;
  487: 
  488:                 case NSKeyUp:
  489:                     {
  490:                         int keycode = cocoa_keycode_to_qemu([event keyCode]);
  491:                         if (is_graphic_console()) {
  492:                             if (keycode & 0x80)
  493:                                 kbd_put_keycode(0xe0);
  494:                             kbd_put_keycode(keycode | 0x80); //add 128 to signal release of key
  495:                         }
  496:                     }
  497:                     break;
  498: 
  499:                 case NSMouseMoved:
  500:                     if (grab) {
  501:                         int dx = [event deltaX];
  502:                         int dy = [event deltaY];
  503:                         int dz = [event deltaZ];
  504:                         int buttons = 0;
  505:                         kbd_mouse_event(dx, dy, dz, buttons);
  506:                     }
  507:                     break;
  508: 
  509:                 case NSLeftMouseDown:
  510:                     if (grab) {
  511:                         int buttons = 0;
  512: 
  513:                         /* leftclick+command simulates rightclick */
  514:                         if ([event modifierFlags] & NSCommandKeyMask) {
  515:                             buttons |= MOUSE_EVENT_RBUTTON;
  516:                         } else {
  517:                             buttons |= MOUSE_EVENT_LBUTTON;
  518:                         }
  519:                         kbd_mouse_event(0, 0, 0, buttons);
  520:                     } else {
  521:                         [NSApp sendEvent: event];
  522:                     }
  523:                     break;
  524: 
  525:                 case NSLeftMouseDragged:
  526:                     if (grab) {
  527:                         int dx = [event deltaX];
  528:                         int dy = [event deltaY];
  529:                         int dz = [event deltaZ];
  530:                         int buttons = 0;
  531:                         if ([[NSApp currentEvent] modifierFlags] & NSCommandKeyMask) { //leftclick+command simulates rightclick
  532:                             buttons |= MOUSE_EVENT_RBUTTON;
  533:                         } else {
  534:                             buttons |= MOUSE_EVENT_LBUTTON;
  535:                         }
  536:                         kbd_mouse_event(dx, dy, dz, buttons);
  537:                     }
  538:                     break;
  539: 
  540:                 case NSLeftMouseUp:
  541:                     if (grab) {
  542:                         kbd_mouse_event(0, 0, 0, 0);
  543:                     } else {
  544:                         [window setTitle: @"QEMU (Press ctrl + alt to release Mouse)"];
  545:                         [NSCursor hide];
  546:                         CGAssociateMouseAndMouseCursorPosition ( FALSE );
  547:                         grab = 1;
  548:                         //[NSApp sendEvent: event];
  549:                     }
  550:                     break;
  551: 
  552:                 case NSRightMouseDown:
  553:                     if (grab) {
  554:                         int buttons = 0;
  555: 
  556:                         buttons |= MOUSE_EVENT_RBUTTON;
  557:                         kbd_mouse_event(0, 0, 0, buttons);
  558:                     } else {
  559:                         [NSApp sendEvent: event];
  560:                     }
  561:                     break;
  562: 
  563:                 case NSRightMouseDragged:
  564:                     if (grab) {
  565:                         int dx = [event deltaX];
  566:                         int dy = [event deltaY];
  567:                         int dz = [event deltaZ];
  568:                         int buttons = 0;
  569:                         buttons |= MOUSE_EVENT_RBUTTON;
  570:                         kbd_mouse_event(dx, dy, dz, buttons);
  571:                     }
  572:                     break;
  573: 
  574:                 case NSRightMouseUp:
  575:                     if (grab) {
  576:                         kbd_mouse_event(0, 0, 0, 0);
  577:                     } else {
  578:                         [NSApp sendEvent: event];
  579:                     }
  580:                     break;
  581: 
  582:                 case NSOtherMouseDragged:
  583:                     if (grab) {
  584:                         int dx = [event deltaX];
  585:                         int dy = [event deltaY];
  586:                         int dz = [event deltaZ];
  587:                         int buttons = 0;
  588:                         buttons |= MOUSE_EVENT_MBUTTON;
  589:                         kbd_mouse_event(dx, dy, dz, buttons);
  590:                     }
  591:                     break;
  592: 
  593:                 case NSOtherMouseDown:
  594:                     if (grab) {
  595:                         int buttons = 0;
  596:                         buttons |= MOUSE_EVENT_MBUTTON;
  597:                         kbd_mouse_event(0, 0, 0, buttons);
  598:                     } else {
  599:                         [NSApp sendEvent:event];
  600:                     }
  601:                     break;
  602: 
  603:                 case NSOtherMouseUp:
  604:                     if (grab) {
  605:                         kbd_mouse_event(0, 0, 0, 0);
  606:                     } else {
  607:                         [NSApp sendEvent: event];
  608:                     }
  609:                     break;
  610: 
  611:                 case NSScrollWheel:
  612:                     if (grab) {
  613:                         int dz = [event deltaY];
  614:                         kbd_mouse_event(0, 0, -dz, 0);
  615:                     }
  616:                     break;
  617: 
  618:                 default: [NSApp sendEvent:event];
  619:             }
  620:         }
  621:     } while(event != nil);
  622: }
  623: 
  624: /*
  625:  ------------------------------------------------------
  626:     cocoa_cleanup
  627:  ------------------------------------------------------
  628: */
  629: 
  630: static void cocoa_cleanup(void)
  631: {
  632: 
  633: }
  634: 
  635: /*
  636:  ------------------------------------------------------
  637:     cocoa_display_init
  638:  ------------------------------------------------------
  639: */
  640: 
  641: void cocoa_display_init(DisplayState *ds, int full_screen)
  642: {
  643:     ds->dpy_update = cocoa_update;
  644:     ds->dpy_resize = cocoa_resize;
  645:     ds->dpy_refresh = cocoa_refresh;
  646: 
  647:     cocoa_resize(ds, 640, 400);
  648: 
  649:     atexit(cocoa_cleanup);
  650: }
  651: 
  652: /*
  653:  ------------------------------------------------------
  654:     Interface with Cocoa
  655:  ------------------------------------------------------
  656: */
  657: 
  658: 
  659: /*
  660:  ------------------------------------------------------
  661:     QemuWindow
  662:     Some trick from SDL to use miniwindow
  663:  ------------------------------------------------------
  664: */
  665: static void QZ_SetPortAlphaOpaque ()
  666: {
  667:     /* Assume 32 bit if( bpp == 32 )*/
  668:     if ( 1 ) {
  669: 
  670:         uint32_t    *pixels = (uint32_t*) current_ds.data;
  671:         uint32_t    rowPixels = current_ds.linesize / 4;
  672:         uint32_t    i, j;
  673: 
  674:         for (i = 0; i < current_ds.height; i++)
  675:             for (j = 0; j < current_ds.width; j++) {
  676: 
  677:                 pixels[ (i * rowPixels) + j ] |= 0xFF000000;
  678:             }
  679:     }
  680: }
  681: 
  682: @implementation QemuWindow
  683: - (void)miniaturize:(id)sender
  684: {
  685: 
  686:     /* make the alpha channel opaque so anim won't have holes in it */
  687:     QZ_SetPortAlphaOpaque ();
  688: 
  689:     [ super miniaturize:sender ];
  690: 
  691: }
  692: - (void)display
  693: {
  694:     /*
  695:         This method fires just before the window deminaturizes from the Dock.
  696: 
  697:         We'll save the current visible surface, let the window manager redraw any
  698:         UI elements, and restore the SDL surface. This way, no expose event
  699:         is required, and the deminiaturize works perfectly.
  700:     */
  701: 
  702:     /* make sure pixels are fully opaque */
  703:     QZ_SetPortAlphaOpaque ();
  704: 
  705:     /* save current visible SDL surface */
  706:     [ self cacheImageInRect:[ qd_view frame ] ];
  707: 
  708:     /* let the window manager redraw controls, border, etc */
  709:     [ super display ];
  710: 
  711:     /* restore visible SDL surface */
  712:     [ self restoreCachedImage ];
  713: }
  714: 
  715: @end
  716: 
  717: 
  718: /*
  719:  ------------------------------------------------------
  720:     QemuCocoaGUIController
  721:     NSApp's delegate - indeed main object
  722:  ------------------------------------------------------
  723: */
  724: 
  725: @interface QemuCocoaGUIController : NSObject
  726: {
  727: }
  728: - (void)applicationDidFinishLaunching: (NSNotification *) note;
  729: - (void)applicationWillTerminate:(NSNotification *)aNotification;
  730: 
  731: - (void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo;
  732: 
  733: - (void)startEmulationWithArgc:(int)argc argv:(char**)argv;
  734: @end
  735: 
  736: @implementation QemuCocoaGUIController
  737: /* Called when the internal event loop has just started running */
  738: - (void)applicationDidFinishLaunching: (NSNotification *) note
  739: {
  740: 
  741:     /* Display an open dialog box if no argument were passed or
  742:        if qemu was launched from the finder ( the Finder passes "-psn" ) */
  743: 
  744:     if( gArgc <= 1 || strncmp (gArgv[1], "-psn", 4) == 0)
  745:     {
  746:         NSOpenPanel *op = [[NSOpenPanel alloc] init];
  747: 
  748:         cocoa_resize(&current_ds, 640, 400);
  749: 
  750:         [op setPrompt:@"Boot image"];
  751: 
  752:         [op setMessage:@"Select the disk image you want to boot.\n\nHit the \"Cancel\" button to quit"];
  753: 
  754:         [op beginSheetForDirectory:nil file:nil types:[NSArray arrayWithObjects:@"img",@"iso",@"dmg",@"qcow",@"cow",@"cloop",@"vmdk",nil]
  755:               modalForWindow:window modalDelegate:self
  756:               didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:) contextInfo:NULL];
  757:     }
  758:     else
  759:     {
  760:         /* or Launch Qemu, with the global args */
  761:         [self startEmulationWithArgc:gArgc argv:gArgv];
  762:     }
  763: }
  764: 
  765: - (void)applicationWillTerminate:(NSNotification *)aNotification
  766: {
  767:     printf("Application will terminate\n");
  768:     qemu_system_shutdown_request();
  769:     /* In order to avoid a crash */
  770:     exit(0);
  771: }
  772: 
  773: - (void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
  774: {
  775:     if(returnCode == NSCancelButton)
  776:     {
  777:         exit(0);
  778:     }
  779: 
  780:     if(returnCode == NSOKButton)
  781:     {
  782:         char *bin = "qemu";
  783:         char *img = (char*)[ [ sheet filename ] cString];
  784: 
  785:         char **argv = (char**)malloc( sizeof(char*)*3 );
  786: 
  787:         asprintf(&argv[0], "%s", bin);
  788:         asprintf(&argv[1], "-hda");
  789:         asprintf(&argv[2], "%s", img);
  790: 
  791:         printf("Using argc %d argv %s -hda %s\n", 3, bin, img);
  792: 
  793:         [self startEmulationWithArgc:3 argv:(char**)argv];
  794:     }
  795: }
  796: 
  797: - (void)startEmulationWithArgc:(int)argc argv:(char**)argv
  798: {
  799:     int status;
  800:     /* Launch Qemu */
  801:     printf("starting qemu...\n");
  802:     status = qemu_main (argc, argv);
  803:     exit(status);
  804: }
  805: @end
  806: 
  807: /*
  808:  ------------------------------------------------------
  809:     Application Creation
  810:  ------------------------------------------------------
  811: */
  812: 
  813: /* Dock Connection */