~vcs-imports/qemu/git

« back to all changes in this revision

Viewing changes to cocoa.m

  • Committer: ths
  • Date: 2007-06-17 15:32:30 UTC
  • Revision ID: git-v1:ffb04fcf089865952592f1f8855c2848d4514a89
Allow relative paths for the interpreter prefix in linux-user emulation.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2984 c046a42c-6fe2-441c-8c8c-71466251a162

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
 
 * QEMU Cocoa CG display driver
3
 
 *
4
 
 * Copyright (c) 2008 Mike Kronenberg
5
 
 *
 
2
 * QEMU Cocoa display driver
 
3
 * 
 
4
 * Copyright (c) 2005 Pierre d'Herbemont
 
5
 *                    many code/inspiration from SDL 1.2 code (LGPL)
 
6
 * 
6
7
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7
8
 * of this software and associated documentation files (the "Software"), to deal
8
9
 * in the Software without restriction, including without limitation the rights
21
22
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
23
 * THE SOFTWARE.
23
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
*/
24
37
 
25
38
#import <Cocoa/Cocoa.h>
26
39
 
27
 
#include "qemu-common.h"
28
 
#include "console.h"
29
 
#include "sysemu.h"
30
 
 
31
 
 
32
 
//#define DEBUG
33
 
 
34
 
#ifdef DEBUG
35
 
#define COCOA_DEBUG(...)  { (void) fprintf (stdout, __VA_ARGS__); }
36
 
#else
37
 
#define COCOA_DEBUG(...)  ((void) 0)
38
 
#endif
39
 
 
40
 
#define cgrect(nsrect) (*(CGRect *)&(nsrect))
41
 
#define COCOA_MOUSE_EVENT \
42
 
        if (isTabletEnabled) { \
43
 
            kbd_mouse_event((int)(p.x * 0x7FFF / (screen.width - 1)), (int)((screen.height - p.y) * 0x7FFF / (screen.height - 1)), 0, buttons); \
44
 
        } else if (isMouseGrabed) { \
45
 
            kbd_mouse_event((int)[event deltaX], (int)[event deltaY], 0, buttons); \
46
 
        } else { \
47
 
            [NSApp sendEvent:event]; \
48
 
        }
49
 
 
50
 
typedef struct {
51
 
    int width;
52
 
    int height;
53
 
    int bitsPerComponent;
54
 
    int bitsPerPixel;
55
 
} QEMUScreen;
56
 
 
57
 
int qemu_main(int argc, char **argv); // main defined in qemu/vl.c
58
 
NSWindow *normalWindow;
59
 
id cocoaView;
60
 
static void *screenBuffer;
 
40
#include "vl.h"
 
41
 
 
42
NSWindow *window = NULL;
 
43
NSQuickDrawView *qd_view = NULL;
 
44
 
61
45
 
62
46
int gArgc;
63
47
char **gArgv;
64
 
 
65
 
// keymap conversion
 
48
DisplayState current_ds;
 
49
 
 
50
int grab = 0;
 
51
int modifiers_state[256];
 
52
 
 
53
/* main defined in qemu/vl.c */
 
54
int qemu_main(int argc, char **argv);
 
55
 
 
56
/* To deal with miniaturization */
 
57
@interface QemuWindow : NSWindow
 
58
{ }
 
59
@end
 
60
 
 
61
 
 
62
/*
 
63
 ------------------------------------------------------
 
64
    Qemu Video Driver
 
65
 ------------------------------------------------------
 
66
*/
 
67
 
 
68
/*
 
69
 ------------------------------------------------------
 
70
    cocoa_update
 
71
 ------------------------------------------------------
 
72
*/
 
73
static void cocoa_update(DisplayState *ds, int x, int y, int w, int h)
 
74
{
 
75
    //printf("updating x=%d y=%d w=%d h=%d\n", x, y, w, h);
 
76
 
 
77
    /* Use QDFlushPortBuffer() to flush content to display */
 
78
    RgnHandle dirty = NewRgn ();
 
79
    RgnHandle temp  = NewRgn ();
 
80
 
 
81
    SetEmptyRgn (dirty);
 
82
 
 
83
    /* Build the region of dirty rectangles */
 
84
    MacSetRectRgn (temp, x, y,
 
85
                        x + w, y + h);
 
86
    MacUnionRgn (dirty, temp, dirty);
 
87
                
 
88
    /* Flush the dirty region */
 
89
    QDFlushPortBuffer ( [ qd_view  qdPort ], dirty );
 
90
    DisposeRgn (dirty);
 
91
    DisposeRgn (temp);
 
92
}
 
93
 
 
94
/*
 
95
 ------------------------------------------------------
 
96
    cocoa_resize
 
97
 ------------------------------------------------------
 
98
*/
 
99
static void cocoa_resize(DisplayState *ds, int w, int h)
 
100
{
 
101
    const int device_bpp = 32;
 
102
    static void *screen_pixels;
 
103
    static int  screen_pitch;
 
104
    NSRect contentRect;
 
105
    
 
106
    //printf("resizing to %d %d\n", w, h);
 
107
    
 
108
    contentRect = NSMakeRect (0, 0, w, h);
 
109
    if(window)
 
110
    {
 
111
        [window close];
 
112
        [window release];
 
113
    }
 
114
    window = [ [ QemuWindow alloc ] initWithContentRect:contentRect
 
115
                                  styleMask:NSTitledWindowMask|NSMiniaturizableWindowMask|NSClosableWindowMask
 
116
                                  backing:NSBackingStoreBuffered defer:NO];
 
117
    if(!window)
 
118
    {
 
119
        fprintf(stderr, "(cocoa) can't create window\n");
 
120
        exit(1);
 
121
    }
 
122
    
 
123
    if(qd_view)
 
124
        [qd_view release];
 
125
    
 
126
    qd_view = [ [ NSQuickDrawView alloc ] initWithFrame:contentRect ];
 
127
    
 
128
    if(!qd_view)
 
129
    {
 
130
         fprintf(stderr, "(cocoa) can't create qd_view\n");
 
131
        exit(1);
 
132
    }
 
133
    
 
134
    [ window setAcceptsMouseMovedEvents:YES ];
 
135
    [ window setTitle:@"Qemu" ];
 
136
    [ window setReleasedWhenClosed:NO ];
 
137
    
 
138
    /* Set screen to black */
 
139
    [ window setBackgroundColor: [NSColor blackColor] ];
 
140
    
 
141
    /* set window position */
 
142
    [ window center ];
 
143
    
 
144
    [ qd_view setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable ];
 
145
    [ [ window contentView ] addSubview:qd_view ];
 
146
    [ qd_view release ];
 
147
    [ window makeKeyAndOrderFront:nil ];
 
148
    
 
149
    /* Careful here, the window seems to have to be onscreen to do that */
 
150
    LockPortBits ( [ qd_view qdPort ] );
 
151
    screen_pixels = GetPixBaseAddr ( GetPortPixMap ( [ qd_view qdPort ] ) );
 
152
    screen_pitch  = GetPixRowBytes ( GetPortPixMap ( [ qd_view qdPort ] ) );
 
153
    UnlockPortBits ( [ qd_view qdPort ] );
 
154
    { 
 
155
            int vOffset = [ window frame ].size.height - 
 
156
                [ qd_view frame ].size.height - [ qd_view frame ].origin.y;
 
157
            
 
158
            int hOffset = [ qd_view frame ].origin.x;
 
159
                    
 
160
            screen_pixels += (vOffset * screen_pitch) + hOffset * (device_bpp/8);
 
161
    }
 
162
    ds->data = screen_pixels;
 
163
    ds->linesize = screen_pitch;
 
164
    ds->depth = device_bpp;
 
165
    ds->width = w;
 
166
    ds->height = h;
 
167
#ifdef __LITTLE_ENDIAN__
 
168
    ds->bgr = 1;
 
169
#else
 
170
    ds->bgr = 0;
 
171
#endif
 
172
 
 
173
    current_ds = *ds;
 
174
}
 
175
 
 
176
/*
 
177
 ------------------------------------------------------
 
178
    keymap conversion
 
179
 ------------------------------------------------------
 
180
*/
 
181
 
66
182
int keymap[] =
67
183
{
68
184
//  SdlI    macI    macH    SdlH    104xtH  104xtC  sdl
171
287
    0,  //  102     0x66    Undefined
172
288
    87, //  103     0x67    0x57            F11     QZ_F11
173
289
    0,  //  104     0x68    Undefined
174
 
    183,//  105     0x69    0xb7                    QZ_PRINT
 
290
    183,//  105     0x69    0xb7            QZ_PRINT
175
291
    0,  //  106     0x6A    Undefined
176
292
    70, //  107     0x6B    0x46            SCROLL  QZ_SCROLLOCK
177
293
    0,  //  108     0x6C    Undefined
194
310
    208,//  125     0x7D    0xd0    E0,50   D ARROW QZ_DOWN
195
311
    200,//  126     0x7E    0xc8    E0,48   U ARROW QZ_UP
196
312
/* 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 */
197
 
 
 
313
  
198
314
/* Aditional 104 Key XP-Keyboard Scancodes from http://www.computer-engineering.org/ps2keyboard/scancodes1.html */
199
315
/*
200
 
    219 //          0xdb            e0,5b   L GUI
201
 
    220 //          0xdc            e0,5c   R GUI
202
 
    221 //          0xdd            e0,5d   APPS
203
 
        //              E0,2A,E0,37         PRNT SCRN
204
 
        //              E1,1D,45,E1,9D,C5   PAUSE
205
 
    83  //          0x53    0x53            KP .
206
 
// ACPI Scan Codes
207
 
    222 //          0xde            E0, 5E  Power
208
 
    223 //          0xdf            E0, 5F  Sleep
209
 
    227 //          0xe3            E0, 63  Wake
210
 
// Windows Multimedia Scan Codes
211
 
    153 //          0x99            E0, 19  Next Track
212
 
    144 //          0x90            E0, 10  Previous Track
213
 
    164 //          0xa4            E0, 24  Stop
214
 
    162 //          0xa2            E0, 22  Play/Pause
215
 
    160 //          0xa0            E0, 20  Mute
216
 
    176 //          0xb0            E0, 30  Volume Up
217
 
    174 //          0xae            E0, 2E  Volume Down
218
 
    237 //          0xed            E0, 6D  Media Select
219
 
    236 //          0xec            E0, 6C  E-Mail
220
 
    161 //          0xa1            E0, 21  Calculator
221
 
    235 //          0xeb            E0, 6B  My Computer
222
 
    229 //          0xe5            E0, 65  WWW Search
223
 
    178 //          0xb2            E0, 32  WWW Home
224
 
    234 //          0xea            E0, 6A  WWW Back
225
 
    233 //          0xe9            E0, 69  WWW Forward
226
 
    232 //          0xe8            E0, 68  WWW Stop
227
 
    231 //          0xe7            E0, 67  WWW Refresh
228
 
    230 //          0xe6            E0, 66  WWW Favorites
 
316
    219 //          0xdb            e0,5b   L GUI   
 
317
    220 //          0xdc            e0,5c   R GUI   
 
318
    221 //          0xdd            e0,5d   APPS    
 
319
        //              E0,2A,E0,37         PRNT SCRN   
 
320
        //              E1,1D,45,E1,9D,C5   PAUSE   
 
321
    83  //          0x53    0x53            KP .    
 
322
// ACPI Scan Codes                              
 
323
    222 //          0xde            E0, 5E  Power   
 
324
    223 //          0xdf            E0, 5F  Sleep   
 
325
    227 //          0xe3            E0, 63  Wake    
 
326
// Windows Multimedia Scan Codes                                
 
327
    153 //          0x99            E0, 19  Next Track  
 
328
    144 //          0x90            E0, 10  Previous Track  
 
329
    164 //          0xa4            E0, 24  Stop    
 
330
    162 //          0xa2            E0, 22  Play/Pause  
 
331
    160 //          0xa0            E0, 20  Mute    
 
332
    176 //          0xb0            E0, 30  Volume Up   
 
333
    174 //          0xae            E0, 2E  Volume Down 
 
334
    237 //          0xed            E0, 6D  Media Select    
 
335
    236 //          0xec            E0, 6C  E-Mail  
 
336
    161 //          0xa1            E0, 21  Calculator  
 
337
    235 //          0xeb            E0, 6B  My Computer 
 
338
    229 //          0xe5            E0, 65  WWW Search  
 
339
    178 //          0xb2            E0, 32  WWW Home    
 
340
    234 //          0xea            E0, 6A  WWW Back    
 
341
    233 //          0xe9            E0, 69  WWW Forward 
 
342
    232 //          0xe8            E0, 68  WWW Stop    
 
343
    231 //          0xe7            E0, 67  WWW Refresh 
 
344
    230 //          0xe6            E0, 66  WWW Favorites   
229
345
*/
230
346
};
231
347
 
239
355
    return keymap[keycode];
240
356
}
241
357
 
242
 
 
243
 
 
244
358
/*
245
359
 ------------------------------------------------------
246
 
    QemuCocoaView
 
360
    cocoa_refresh
247
361
 ------------------------------------------------------
248
362
*/
249
 
@interface QemuCocoaView : NSView
250
 
{
251
 
    QEMUScreen screen;
252
 
    NSWindow *fullScreenWindow;
253
 
    float cx,cy,cw,ch,cdx,cdy;
254
 
    CGDataProviderRef dataProviderRef;
255
 
    int modifiers_state[256];
256
 
    BOOL isMouseGrabed;
257
 
    BOOL isFullscreen;
258
 
    BOOL isAbsoluteEnabled;
259
 
    BOOL isTabletEnabled;
260
 
}
261
 
- (void) resizeContentToWidth:(int)w height:(int)h displayState:(DisplayState *)ds;
262
 
- (void) grabMouse;
263
 
- (void) ungrabMouse;
264
 
- (void) toggleFullScreen:(id)sender;
265
 
- (void) handleEvent:(NSEvent *)event;
266
 
- (void) setAbsoluteEnabled:(BOOL)tIsAbsoluteEnabled;
267
 
- (BOOL) isMouseGrabed;
268
 
- (BOOL) isAbsoluteEnabled;
269
 
- (float) cdx;
270
 
- (float) cdy;
271
 
- (QEMUScreen) gscreen;
272
 
@end
273
 
 
274
 
@implementation QemuCocoaView
275
 
- (id)initWithFrame:(NSRect)frameRect
276
 
{
277
 
    COCOA_DEBUG("QemuCocoaView: initWithFrame\n");
278
 
 
279
 
    self = [super initWithFrame:frameRect];
280
 
    if (self) {
281
 
 
282
 
        screen.bitsPerComponent = 8;
283
 
        screen.bitsPerPixel = 32;
284
 
        screen.width = frameRect.size.width;
285
 
        screen.height = frameRect.size.height;
286
 
 
287
 
    }
288
 
    return self;
289
 
}
290
 
 
291
 
- (void) dealloc
292
 
{
293
 
    COCOA_DEBUG("QemuCocoaView: dealloc\n");
294
 
 
295
 
    if (screenBuffer)
296
 
        free(screenBuffer);
297
 
 
298
 
    if (dataProviderRef)
299
 
        CGDataProviderRelease(dataProviderRef);
300
 
 
301
 
    [super dealloc];
302
 
}
303
 
 
304
 
- (void) drawRect:(NSRect) rect
305
 
{
306
 
    COCOA_DEBUG("QemuCocoaView: drawRect\n");
307
 
 
308
 
    if ((int)screenBuffer == -1)
309
 
        return;
310
 
 
311
 
    // get CoreGraphic context
312
 
    CGContextRef viewContextRef = [[NSGraphicsContext currentContext] graphicsPort];
313
 
    CGContextSetInterpolationQuality (viewContextRef, kCGInterpolationNone);
314
 
    CGContextSetShouldAntialias (viewContextRef, NO);
315
 
 
316
 
    // draw screen bitmap directly to Core Graphics context
317
 
    if (dataProviderRef) {
318
 
        CGImageRef imageRef = CGImageCreate(
319
 
            screen.width, //width
320
 
            screen.height, //height
321
 
            screen.bitsPerComponent, //bitsPerComponent
322
 
            screen.bitsPerPixel, //bitsPerPixel
323
 
            (screen.width * 4), //bytesPerRow
324
 
#if __LITTLE_ENDIAN__
325
 
            CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB), //colorspace for OS X >= 10.4
326
 
            kCGImageAlphaNoneSkipLast,
327
 
#else
328
 
            CGColorSpaceCreateDeviceRGB(), //colorspace for OS X < 10.4 (actually ppc)
329
 
            kCGImageAlphaNoneSkipFirst, //bitmapInfo
330
 
#endif
331
 
            dataProviderRef, //provider
332
 
            NULL, //decode
333
 
            0, //interpolate
334
 
            kCGRenderingIntentDefault //intent
335
 
        );
336
 
// test if host support "CGImageCreateWithImageInRect" at compiletime
337
 
#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
338
 
        if (CGImageCreateWithImageInRect == NULL) { // test if "CGImageCreateWithImageInRect" is supported on host at runtime
339
 
#endif
340
 
            // compatibility drawing code (draws everything) (OS X < 10.4)
341
 
            CGContextDrawImage (viewContextRef, CGRectMake(0, 0, [self bounds].size.width, [self bounds].size.height), imageRef);
342
 
#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
343
 
        } else {
344
 
            // selective drawing code (draws only dirty rectangles) (OS X >= 10.4)
345
 
            const NSRect *rectList;
346
 
            int rectCount;
347
 
            int i;
348
 
            CGImageRef clipImageRef;
349
 
            CGRect clipRect;
350
 
 
351
 
            [self getRectsBeingDrawn:&rectList count:&rectCount];
352
 
            for (i = 0; i < rectCount; i++) {
353
 
                clipRect.origin.x = rectList[i].origin.x / cdx;
354
 
                clipRect.origin.y = (float)screen.height - (rectList[i].origin.y + rectList[i].size.height) / cdy;
355
 
                clipRect.size.width = rectList[i].size.width / cdx;
356
 
                clipRect.size.height = rectList[i].size.height / cdy;
357
 
                clipImageRef = CGImageCreateWithImageInRect(
358
 
                    imageRef,
359
 
                    clipRect
360
 
                );
361
 
                CGContextDrawImage (viewContextRef, cgrect(rectList[i]), clipImageRef);
362
 
                CGImageRelease (clipImageRef);
363
 
            }
364
 
        }
365
 
#endif
366
 
        CGImageRelease (imageRef);
367
 
    }
368
 
}
369
 
 
370
 
- (void) setContentDimensions
371
 
{
372
 
    COCOA_DEBUG("QemuCocoaView: setContentDimensions\n");
373
 
 
374
 
    if (isFullscreen) {
375
 
        cdx = [[NSScreen mainScreen] frame].size.width / (float)screen.width;
376
 
        cdy = [[NSScreen mainScreen] frame].size.height / (float)screen.height;
377
 
        cw = screen.width * cdx;
378
 
        ch = screen.height * cdy;
379
 
        cx = ([[NSScreen mainScreen] frame].size.width - cw) / 2.0;
380
 
        cy = ([[NSScreen mainScreen] frame].size.height - ch) / 2.0;
381
 
    } else {
382
 
        cx = 0;
383
 
        cy = 0;
384
 
        cw = screen.width;
385
 
        ch = screen.height;
386
 
        cdx = 1.0;
387
 
        cdy = 1.0;
388
 
    }
389
 
}
390
 
 
391
 
- (void) resizeContentToWidth:(int)w height:(int)h displayState:(DisplayState *)ds
392
 
{
393
 
    COCOA_DEBUG("QemuCocoaView: resizeContent\n");
394
 
 
395
 
    // update screenBuffer
396
 
    if (dataProviderRef)
397
 
        CGDataProviderRelease(dataProviderRef);
398
 
    if (screenBuffer)
399
 
        free(screenBuffer);
400
 
    screenBuffer = malloc( w * 4 * h );
401
 
 
402
 
    ds->data = screenBuffer;
403
 
    ds->linesize =  (w * 4);
404
 
    ds->depth = 32;
405
 
    ds->width = w;
406
 
    ds->height = h;
407
 
#ifdef __LITTLE_ENDIAN__
408
 
    ds->bgr = 1;
409
 
#else
410
 
    ds->bgr = 0;
411
 
#endif
412
 
 
413
 
    dataProviderRef = CGDataProviderCreateWithData(NULL, screenBuffer, w * 4 * h, NULL);
414
 
 
415
 
    // update windows
416
 
    if (isFullscreen) {
417
 
        [[fullScreenWindow contentView] setFrame:[[NSScreen mainScreen] frame]];
418
 
        [normalWindow setFrame:NSMakeRect([normalWindow frame].origin.x, [normalWindow frame].origin.y - h + screen.height, w, h + [normalWindow frame].size.height - screen.height) display:NO animate:NO];
419
 
    } else {
420
 
        if (qemu_name)
421
 
            [normalWindow setTitle:[NSString stringWithFormat:@"QEMU %s", qemu_name]];
422
 
        [normalWindow setFrame:NSMakeRect([normalWindow frame].origin.x, [normalWindow frame].origin.y - h + screen.height, w, h + [normalWindow frame].size.height - screen.height) display:YES animate:YES];
423
 
    }
424
 
    screen.width = w;
425
 
    screen.height = h;
426
 
    [self setContentDimensions];
427
 
    [self setFrame:NSMakeRect(cx, cy, cw, ch)];
428
 
}
429
 
 
430
 
- (void) toggleFullScreen:(id)sender
431
 
{
432
 
    COCOA_DEBUG("QemuCocoaView: toggleFullScreen\n");
433
 
 
434
 
    if (isFullscreen) { // switch from fullscreen to desktop
435
 
        isFullscreen = FALSE;
436
 
        [self ungrabMouse];
437
 
        [self setContentDimensions];
438
 
// test if host support "enterFullScreenMode:withOptions" at compiletime
439
 
#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
440
 
        if ([NSView respondsToSelector:@selector(exitFullScreenModeWithOptions:)]) { // test if "exitFullScreenModeWithOptions" is supported on host at runtime
441
 
            [self exitFullScreenModeWithOptions:nil];
442
 
        } else {
443
 
#endif
444
 
            [fullScreenWindow close];
445
 
            [normalWindow setContentView: self];
446
 
            [normalWindow makeKeyAndOrderFront: self];
447
 
            [NSMenu setMenuBarVisible:YES];
448
 
#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
449
 
        }
450
 
#endif
451
 
    } else { // switch from desktop to fullscreen
452
 
        isFullscreen = TRUE;
453
 
        [self grabMouse];
454
 
        [self setContentDimensions];
455
 
// test if host support "enterFullScreenMode:withOptions" at compiletime
456
 
#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
457
 
        if ([NSView respondsToSelector:@selector(enterFullScreenMode:withOptions:)]) { // test if "enterFullScreenMode:withOptions" is supported on host at runtime
458
 
            [self enterFullScreenMode:[NSScreen mainScreen] withOptions:[NSDictionary dictionaryWithObjectsAndKeys:
459
 
                [NSNumber numberWithBool:NO], NSFullScreenModeAllScreens,
460
 
                [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:NO], kCGDisplayModeIsStretched, nil], NSFullScreenModeSetting,
461
 
                 nil]];
462
 
        } else {
463
 
#endif
464
 
            [NSMenu setMenuBarVisible:NO];
465
 
            fullScreenWindow = [[NSWindow alloc] initWithContentRect:[[NSScreen mainScreen] frame]
466
 
                styleMask:NSBorderlessWindowMask
467
 
                backing:NSBackingStoreBuffered
468
 
                defer:NO];
469
 
            [fullScreenWindow setHasShadow:NO];
470
 
            [fullScreenWindow setContentView:self];
471
 
            [fullScreenWindow makeKeyAndOrderFront:self];
472
 
#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
473
 
        }
474
 
#endif
475
 
    }
476
 
}
477
 
 
478
 
- (void) handleEvent:(NSEvent *)event
479
 
{
480
 
    COCOA_DEBUG("QemuCocoaView: handleEvent\n");
481
 
 
482
 
    int buttons = 0;
483
 
    int keycode;
484
 
    NSPoint p = [event locationInWindow];
485
 
 
486
 
    switch ([event type]) {
487
 
        case NSFlagsChanged:
488
 
            keycode = cocoa_keycode_to_qemu([event keyCode]);
489
 
            if (keycode) {
490
 
                if (keycode == 58 || keycode == 69) { // emulate caps lock and num lock keydown and keyup
491
 
                    kbd_put_keycode(keycode);
492
 
                    kbd_put_keycode(keycode | 0x80);
493
 
                } else if (is_graphic_console()) {
494
 
                    if (keycode & 0x80)
495
 
                        kbd_put_keycode(0xe0);
496
 
                    if (modifiers_state[keycode] == 0) { // keydown
497
 
                        kbd_put_keycode(keycode & 0x7f);
498
 
                        modifiers_state[keycode] = 1;
499
 
                    } else { // keyup
500
 
                        kbd_put_keycode(keycode | 0x80);
501
 
                        modifiers_state[keycode] = 0;
502
 
                    }
503
 
                }
504
 
            }
505
 
 
506
 
            // release Mouse grab when pressing ctrl+alt
507
 
            if (!isFullscreen && ([event modifierFlags] & NSControlKeyMask) && ([event modifierFlags] & NSAlternateKeyMask)) {
508
 
                [self ungrabMouse];
509
 
            }
510
 
            break;
511
 
        case NSKeyDown:
512
 
 
513
 
            // forward command Key Combos
514
 
            if ([event modifierFlags] & NSCommandKeyMask) {
515
 
                [NSApp sendEvent:event];
516
 
                return;
517
 
            }
518
 
 
519
 
            // default
520
 
            keycode = cocoa_keycode_to_qemu([event keyCode]);
521
 
 
522
 
            // handle control + alt Key Combos (ctrl+alt is reserved for QEMU)
523
 
            if (([event modifierFlags] & NSControlKeyMask) && ([event modifierFlags] & NSAlternateKeyMask)) {
524
 
                switch (keycode) {
525
 
 
526
 
                    // enable graphic console
527
 
                    case 0x02 ... 0x0a: // '1' to '9' keys
528
 
                        console_select(keycode - 0x02);
529
 
                        break;
530
 
                }
531
 
 
532
 
            // handle keys for graphic console
533
 
            } else if (is_graphic_console()) {
534
 
                if (keycode & 0x80) //check bit for e0 in front
535
 
                    kbd_put_keycode(0xe0);
536
 
                kbd_put_keycode(keycode & 0x7f); //remove e0 bit in front
537
 
 
538
 
            // handlekeys for Monitor
539
 
            } else {
540
 
                int keysym = 0;
541
 
                switch([event keyCode]) {
542
 
                case 115:
543
 
                    keysym = QEMU_KEY_HOME;
544
 
                    break;
545
 
                case 117:
546
 
                    keysym = QEMU_KEY_DELETE;
547
 
                    break;
548
 
                case 119:
549
 
                    keysym = QEMU_KEY_END;
550
 
                    break;
551
 
                case 123:
552
 
                    keysym = QEMU_KEY_LEFT;
553
 
                    break;
554
 
                case 124:
555
 
                    keysym = QEMU_KEY_RIGHT;
556
 
                    break;
557
 
                case 125:
558
 
                    keysym = QEMU_KEY_DOWN;
559
 
                    break;
560
 
                case 126:
561
 
                    keysym = QEMU_KEY_UP;
562
 
                    break;
563
 
                default:
564
 
                    {
565
 
                        NSString *ks = [event characters];
566
 
                        if ([ks length] > 0)
567
 
                            keysym = [ks characterAtIndex:0];
568
 
                    }
569
 
                }
570
 
                if (keysym)
571
 
                    kbd_put_keysym(keysym);
572
 
            }
573
 
            break;
574
 
        case NSKeyUp:
575
 
            keycode = cocoa_keycode_to_qemu([event keyCode]);
576
 
            if (is_graphic_console()) {
577
 
                if (keycode & 0x80)
578
 
                    kbd_put_keycode(0xe0);
579
 
                kbd_put_keycode(keycode | 0x80); //add 128 to signal release of key
580
 
            }
581
 
            break;
582
 
        case NSMouseMoved:
583
 
            if (isAbsoluteEnabled) {
584
 
                if (p.x < 0 || p.x > screen.width || p.y < 0 || p.y > screen.height || ![[self window] isKeyWindow]) {
585
 
                    if (isTabletEnabled) { // if we leave the window, deactivate the tablet
586
 
                        [NSCursor unhide];
587
 
                        isTabletEnabled = FALSE;
588
 
                    }
589
 
                } else {
590
 
                    if (!isTabletEnabled) { // if we enter the window, activate the tablet
 
363
static void cocoa_refresh(DisplayState *ds)
 
364
{
 
365
    //printf("cocoa_refresh \n");
 
366
    NSDate *distantPast;
 
367
    NSEvent *event;
 
368
    NSAutoreleasePool *pool;
 
369
    
 
370
    pool = [ [ NSAutoreleasePool alloc ] init ];
 
371
    distantPast = [ NSDate distantPast ];
 
372
    
 
373
    vga_hw_update();
 
374
 
 
375
    do {
 
376
        event = [ NSApp nextEventMatchingMask:NSAnyEventMask untilDate:distantPast
 
377
                        inMode: NSDefaultRunLoopMode dequeue:YES ];
 
378
        if (event != nil) {
 
379
            switch ([event type]) {
 
380
                case NSFlagsChanged:
 
381
                    {
 
382
                        int keycode = cocoa_keycode_to_qemu([event keyCode]);
 
383
 
 
384
                        if (keycode)
 
385
                        {
 
386
                            if (keycode == 58 || keycode == 69) {
 
387
                                /* emulate caps lock and num lock keydown and keyup */
 
388
                                kbd_put_keycode(keycode);
 
389
                                kbd_put_keycode(keycode | 0x80);
 
390
                            } else if (is_graphic_console()) {
 
391
                                if (keycode & 0x80)
 
392
                                    kbd_put_keycode(0xe0);
 
393
                                if (modifiers_state[keycode] == 0) {
 
394
                                    /* keydown */
 
395
                                    kbd_put_keycode(keycode & 0x7f);
 
396
                                    modifiers_state[keycode] = 1;
 
397
                                } else {
 
398
                                    /* keyup */
 
399
                                    kbd_put_keycode(keycode | 0x80);
 
400
                                    modifiers_state[keycode] = 0;
 
401
                                }
 
402
                            }
 
403
                        }
 
404
 
 
405
                        /* release Mouse grab when pressing ctrl+alt */
 
406
                        if (([event modifierFlags] & NSControlKeyMask) && ([event modifierFlags] & NSAlternateKeyMask))
 
407
                        {
 
408
                            [window setTitle: @"QEMU"];
 
409
                            [NSCursor unhide];
 
410
                            CGAssociateMouseAndMouseCursorPosition ( TRUE );
 
411
                            grab = 0;
 
412
                        }
 
413
                    }
 
414
                    break;
 
415
 
 
416
                case NSKeyDown:
 
417
                    {
 
418
                        int keycode = cocoa_keycode_to_qemu([event keyCode]);               
 
419
                        
 
420
                        /* handle command Key Combos */
 
421
                        if ([event modifierFlags] & NSCommandKeyMask) {
 
422
                            switch ([event keyCode]) {
 
423
                                /* quit */
 
424
                                case 12: /* q key */
 
425
                                    /* switch to windowed View */
 
426
                                    exit(0);
 
427
                                    return;
 
428
                            }
 
429
                        }
 
430
                        
 
431
                        /* handle control + alt Key Combos */
 
432
                        if (([event modifierFlags] & NSControlKeyMask) && ([event modifierFlags] & NSAlternateKeyMask)) {
 
433
                            switch (keycode) {
 
434
                                /* toggle Monitor */
 
435
                                case 0x02 ... 0x0a: /* '1' to '9' keys */
 
436
                                    console_select(keycode - 0x02);
 
437
                                    break;
 
438
                            }
 
439
                        } else {
 
440
                            /* handle standard key events */
 
441
                            if (is_graphic_console()) {
 
442
                                if (keycode & 0x80) //check bit for e0 in front
 
443
                                    kbd_put_keycode(0xe0);
 
444
                                kbd_put_keycode(keycode & 0x7f); //remove e0 bit in front
 
445
                            /* handle monitor key events */
 
446
                            } else {
 
447
                                int keysym = 0;
 
448
 
 
449
                                switch([event keyCode]) {
 
450
                                case 115:
 
451
                                    keysym = QEMU_KEY_HOME;
 
452
                                    break;
 
453
                                case 117:
 
454
                                    keysym = QEMU_KEY_DELETE;
 
455
                                    break;
 
456
                                case 119:
 
457
                                    keysym = QEMU_KEY_END;
 
458
                                    break;
 
459
                                case 123:
 
460
                                    keysym = QEMU_KEY_LEFT;
 
461
                                    break;
 
462
                                case 124:
 
463
                                    keysym = QEMU_KEY_RIGHT;
 
464
                                    break;
 
465
                                case 125:
 
466
                                    keysym = QEMU_KEY_DOWN;
 
467
                                    break;
 
468
                                case 126:
 
469
                                    keysym = QEMU_KEY_UP;
 
470
                                    break;
 
471
                                default:
 
472
                                    {
 
473
                                        NSString *ks = [event characters];
 
474
 
 
475
                                        if ([ks length] > 0)
 
476
                                            keysym = [ks characterAtIndex:0];
 
477
                                    }
 
478
                                }
 
479
                                if (keysym)
 
480
                                    kbd_put_keysym(keysym);
 
481
                            }
 
482
                        }
 
483
                    }
 
484
                    break;
 
485
                    
 
486
                case NSKeyUp:
 
487
                    {
 
488
                        int keycode = cocoa_keycode_to_qemu([event keyCode]);   
 
489
                        if (is_graphic_console()) {
 
490
                            if (keycode & 0x80)
 
491
                                kbd_put_keycode(0xe0);
 
492
                            kbd_put_keycode(keycode | 0x80); //add 128 to signal release of key
 
493
                        }
 
494
                    }
 
495
                    break;
 
496
                    
 
497
                case NSMouseMoved:
 
498
                    if (grab) {
 
499
                        int dx = [event deltaX];
 
500
                        int dy = [event deltaY];
 
501
                        int dz = [event deltaZ];
 
502
                        int buttons = 0;
 
503
                        kbd_mouse_event(dx, dy, dz, buttons);
 
504
                    }
 
505
                    break;
 
506
                        
 
507
                case NSLeftMouseDown:
 
508
                    if (grab) {
 
509
                        int buttons = 0;
 
510
                        
 
511
                        /* leftclick+command simulates rightclick */
 
512
                        if ([event modifierFlags] & NSCommandKeyMask) {
 
513
                            buttons |= MOUSE_EVENT_RBUTTON;
 
514
                        } else {
 
515
                            buttons |= MOUSE_EVENT_LBUTTON;
 
516
                        }
 
517
                        kbd_mouse_event(0, 0, 0, buttons);
 
518
                    } else {
 
519
                        [NSApp sendEvent: event];
 
520
                    }
 
521
                    break;
 
522
                        
 
523
                case NSLeftMouseDragged:
 
524
                    if (grab) {
 
525
                        int dx = [event deltaX];
 
526
                        int dy = [event deltaY];
 
527
                        int dz = [event deltaZ];
 
528
                        int buttons = 0;
 
529
                        if ([[NSApp currentEvent] modifierFlags] & NSCommandKeyMask) { //leftclick+command simulates rightclick
 
530
                            buttons |= MOUSE_EVENT_RBUTTON;
 
531
                        } else {
 
532
                            buttons |= MOUSE_EVENT_LBUTTON;
 
533
                        }
 
534
                        kbd_mouse_event(dx, dy, dz, buttons);
 
535
                    }
 
536
                    break;
 
537
                        
 
538
                case NSLeftMouseUp:
 
539
                    if (grab) {
 
540
                        kbd_mouse_event(0, 0, 0, 0);
 
541
                    } else {
 
542
                        [window setTitle: @"QEMU (Press ctrl + alt to release Mouse)"];
591
543
                        [NSCursor hide];
592
 
                        isTabletEnabled = TRUE;
593
 
                    }
594
 
                }
595
 
            }
596
 
            COCOA_MOUSE_EVENT
597
 
            break;
598
 
        case NSLeftMouseDown:
599
 
            if ([event modifierFlags] & NSCommandKeyMask) {
600
 
                buttons |= MOUSE_EVENT_RBUTTON;
601
 
            } else {
602
 
                buttons |= MOUSE_EVENT_LBUTTON;
603
 
            }
604
 
            COCOA_MOUSE_EVENT
605
 
            break;
606
 
        case NSRightMouseDown:
607
 
            buttons |= MOUSE_EVENT_RBUTTON;
608
 
            COCOA_MOUSE_EVENT
609
 
            break;
610
 
        case NSOtherMouseDown:
611
 
            buttons |= MOUSE_EVENT_MBUTTON;
612
 
            COCOA_MOUSE_EVENT
613
 
            break;
614
 
        case NSLeftMouseDragged:
615
 
            if ([event modifierFlags] & NSCommandKeyMask) {
616
 
                buttons |= MOUSE_EVENT_RBUTTON;
617
 
            } else {
618
 
                buttons |= MOUSE_EVENT_LBUTTON;
619
 
            }
620
 
            COCOA_MOUSE_EVENT
621
 
            break;
622
 
        case NSRightMouseDragged:
623
 
            buttons |= MOUSE_EVENT_RBUTTON;
624
 
            COCOA_MOUSE_EVENT
625
 
            break;
626
 
        case NSOtherMouseDragged:
627
 
            buttons |= MOUSE_EVENT_MBUTTON;
628
 
            COCOA_MOUSE_EVENT
629
 
            break;
630
 
        case NSLeftMouseUp:
631
 
            if (isTabletEnabled) {
632
 
                    COCOA_MOUSE_EVENT
633
 
            } else if (!isMouseGrabed) {
634
 
                if (p.x > -1 && p.x < screen.width && p.y > -1 && p.y < screen.height) {
635
 
                    [self grabMouse];
636
 
                } else {
637
 
                    [NSApp sendEvent:event];
638
 
                }
639
 
            } else {
640
 
                COCOA_MOUSE_EVENT
641
 
            }
642
 
            break;
643
 
        case NSRightMouseUp:
644
 
            COCOA_MOUSE_EVENT
645
 
            break;
646
 
        case NSOtherMouseUp:
647
 
            COCOA_MOUSE_EVENT
648
 
            break;
649
 
        case NSScrollWheel:
650
 
            if (isTabletEnabled || isMouseGrabed) {
651
 
                kbd_mouse_event(0, 0, -[event deltaY], 0);
652
 
            } else {
653
 
                [NSApp sendEvent:event];
654
 
            }
655
 
            break;
656
 
        default:
657
 
            [NSApp sendEvent:event];
658
 
    }
659
 
}
660
 
 
661
 
- (void) grabMouse
662
 
{
663
 
    COCOA_DEBUG("QemuCocoaView: grabMouse\n");
664
 
 
665
 
    if (!isFullscreen) {
666
 
        if (qemu_name)
667
 
            [normalWindow setTitle:[NSString stringWithFormat:@"QEMU %s - (Press ctrl + alt to release Mouse)", qemu_name]];
668
 
        else
669
 
            [normalWindow setTitle:@"QEMU - (Press ctrl + alt to release Mouse)"];
670
 
    }
671
 
    [NSCursor hide];
672
 
    CGAssociateMouseAndMouseCursorPosition(FALSE);
673
 
    isMouseGrabed = TRUE; // while isMouseGrabed = TRUE, QemuCocoaApp sends all events to [cocoaView handleEvent:]
674
 
}
675
 
 
676
 
- (void) ungrabMouse
677
 
{
678
 
    COCOA_DEBUG("QemuCocoaView: ungrabMouse\n");
679
 
 
680
 
    if (!isFullscreen) {
681
 
        if (qemu_name)
682
 
            [normalWindow setTitle:[NSString stringWithFormat:@"QEMU %s", qemu_name]];
683
 
        else
684
 
            [normalWindow setTitle:@"QEMU"];
685
 
    }
686
 
    [NSCursor unhide];
687
 
    CGAssociateMouseAndMouseCursorPosition(TRUE);
688
 
    isMouseGrabed = FALSE;
689
 
}
690
 
 
691
 
- (void) setAbsoluteEnabled:(BOOL)tIsAbsoluteEnabled {isAbsoluteEnabled = tIsAbsoluteEnabled;}
692
 
- (BOOL) isMouseGrabed {return isMouseGrabed;}
693
 
- (BOOL) isAbsoluteEnabled {return isAbsoluteEnabled;}
694
 
- (float) cdx {return cdx;}
695
 
- (float) cdy {return cdy;}
696
 
- (QEMUScreen) gscreen {return screen;}
 
544
                        CGAssociateMouseAndMouseCursorPosition ( FALSE );
 
545
                        grab = 1;
 
546
                        //[NSApp sendEvent: event];
 
547
                    }
 
548
                    break;
 
549
                        
 
550
                case NSRightMouseDown:
 
551
                    if (grab) {
 
552
                        int buttons = 0;
 
553
                        
 
554
                        buttons |= MOUSE_EVENT_RBUTTON;
 
555
                        kbd_mouse_event(0, 0, 0, buttons);
 
556
                    } else {
 
557
                        [NSApp sendEvent: event];
 
558
                    }
 
559
                    break;
 
560
                    
 
561
                case NSRightMouseDragged:
 
562
                    if (grab) {
 
563
                        int dx = [event deltaX];
 
564
                        int dy = [event deltaY];
 
565
                        int dz = [event deltaZ];
 
566
                        int buttons = 0;
 
567
                        buttons |= MOUSE_EVENT_RBUTTON;
 
568
                        kbd_mouse_event(dx, dy, dz, buttons);
 
569
                    }
 
570
                    break;
 
571
                    
 
572
                case NSRightMouseUp:
 
573
                    if (grab) {
 
574
                        kbd_mouse_event(0, 0, 0, 0);
 
575
                    } else {
 
576
                        [NSApp sendEvent: event];
 
577
                    }
 
578
                    break;
 
579
                        
 
580
                case NSOtherMouseDragged:
 
581
                    if (grab) {
 
582
                        int dx = [event deltaX];
 
583
                        int dy = [event deltaY];
 
584
                        int dz = [event deltaZ];
 
585
                        int buttons = 0;
 
586
                        buttons |= MOUSE_EVENT_MBUTTON;
 
587
                        kbd_mouse_event(dx, dy, dz, buttons);
 
588
                    }
 
589
                    break;
 
590
                    
 
591
                case NSOtherMouseDown:
 
592
                    if (grab) {
 
593
                        int buttons = 0;
 
594
                        buttons |= MOUSE_EVENT_MBUTTON;
 
595
                        kbd_mouse_event(0, 0, 0, buttons);
 
596
                    } else {
 
597
                        [NSApp sendEvent:event];
 
598
                    }
 
599
                    break;
 
600
                        
 
601
                case NSOtherMouseUp:
 
602
                    if (grab) {
 
603
                        kbd_mouse_event(0, 0, 0, 0);
 
604
                    } else {
 
605
                        [NSApp sendEvent: event];
 
606
                    }
 
607
                    break;
 
608
                        
 
609
                case NSScrollWheel:
 
610
                    if (grab) {
 
611
                        int dz = [event deltaY];
 
612
                        kbd_mouse_event(0, 0, -dz, 0);
 
613
                    }
 
614
                    break;
 
615
                
 
616
                default: [NSApp sendEvent:event];
 
617
            }
 
618
        }
 
619
    } while(event != nil);
 
620
}
 
621
 
 
622
/*
 
623
 ------------------------------------------------------
 
624
    cocoa_cleanup
 
625
 ------------------------------------------------------
 
626
*/
 
627
 
 
628
static void cocoa_cleanup(void) 
 
629
{
 
630
 
 
631
}
 
632
 
 
633
/*
 
634
 ------------------------------------------------------
 
635
    cocoa_display_init
 
636
 ------------------------------------------------------
 
637
*/
 
638
 
 
639
void cocoa_display_init(DisplayState *ds, int full_screen)
 
640
{
 
641
    ds->dpy_update = cocoa_update;
 
642
    ds->dpy_resize = cocoa_resize;
 
643
    ds->dpy_refresh = cocoa_refresh;
 
644
    
 
645
    cocoa_resize(ds, 640, 400);
 
646
    
 
647
    atexit(cocoa_cleanup);
 
648
}
 
649
 
 
650
/*
 
651
 ------------------------------------------------------
 
652
    Interface with Cocoa
 
653
 ------------------------------------------------------
 
654
*/
 
655
 
 
656
 
 
657
/*
 
658
 ------------------------------------------------------
 
659
    QemuWindow
 
660
    Some trick from SDL to use miniwindow
 
661
 ------------------------------------------------------
 
662
*/
 
663
static void QZ_SetPortAlphaOpaque ()
 
664
{    
 
665
    /* Assume 32 bit if( bpp == 32 )*/
 
666
    if ( 1 ) {
 
667
    
 
668
        uint32_t    *pixels = (uint32_t*) current_ds.data;
 
669
        uint32_t    rowPixels = current_ds.linesize / 4;
 
670
        uint32_t    i, j;
 
671
        
 
672
        for (i = 0; i < current_ds.height; i++)
 
673
            for (j = 0; j < current_ds.width; j++) {
 
674
        
 
675
                pixels[ (i * rowPixels) + j ] |= 0xFF000000;
 
676
            }
 
677
    }
 
678
}
 
679
 
 
680
@implementation QemuWindow
 
681
- (void)miniaturize:(id)sender
 
682
{
 
683
        
 
684
    /* make the alpha channel opaque so anim won't have holes in it */
 
685
    QZ_SetPortAlphaOpaque ();
 
686
    
 
687
    [ super miniaturize:sender ];
 
688
    
 
689
}
 
690
- (void)display
 
691
{    
 
692
    /* 
 
693
        This method fires just before the window deminaturizes from the Dock.
 
694
        
 
695
        We'll save the current visible surface, let the window manager redraw any
 
696
        UI elements, and restore the SDL surface. This way, no expose event 
 
697
        is required, and the deminiaturize works perfectly.
 
698
    */
 
699
    
 
700
    /* make sure pixels are fully opaque */
 
701
    QZ_SetPortAlphaOpaque ();
 
702
    
 
703
    /* save current visible SDL surface */
 
704
    [ self cacheImageInRect:[ qd_view frame ] ];
 
705
    
 
706
    /* let the window manager redraw controls, border, etc */
 
707
    [ super display ];
 
708
    
 
709
    /* restore visible SDL surface */
 
710
    [ self restoreCachedImage ];
 
711
}
 
712
 
697
713
@end
698
714
 
699
715
 
700
 
 
701
716
/*
702
717
 ------------------------------------------------------
703
 
    QemuCocoaAppController
 
718
    QemuCocoaGUIController
 
719
    NSApp's delegate - indeed main object
704
720
 ------------------------------------------------------
705
721
*/
706
 
@interface QemuCocoaAppController : NSObject
 
722
 
 
723
@interface QemuCocoaGUIController : NSObject
707
724
{
708
725
}
 
726
- (void)applicationDidFinishLaunching: (NSNotification *) note;
 
727
- (void)applicationWillTerminate:(NSNotification *)aNotification;
 
728
 
 
729
- (void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo;
 
730
 
709
731
- (void)startEmulationWithArgc:(int)argc argv:(char**)argv;
710
 
- (void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo;
711
 
- (void)toggleFullScreen:(id)sender;
712
 
- (void)showQEMUDoc:(id)sender;
713
 
- (void)showQEMUTec:(id)sender;
714
732
@end
715
733
 
716
 
@implementation QemuCocoaAppController
717
 
- (id) init
718
 
{
719
 
    COCOA_DEBUG("QemuCocoaAppController: init\n");
720
 
 
721
 
    self = [super init];
722
 
    if (self) {
723
 
 
724
 
        // create a view and add it to the window
725
 
        cocoaView = [[QemuCocoaView alloc] initWithFrame:NSMakeRect(0.0, 0.0, 640.0, 480.0)];
726
 
        if(!cocoaView) {
727
 
            fprintf(stderr, "(cocoa) can't create a view\n");
728
 
            exit(1);
729
 
        }
730
 
 
731
 
        // create a window
732
 
        normalWindow = [[NSWindow alloc] initWithContentRect:[cocoaView frame]
733
 
            styleMask:NSTitledWindowMask|NSMiniaturizableWindowMask|NSClosableWindowMask
734
 
            backing:NSBackingStoreBuffered defer:NO];
735
 
        if(!normalWindow) {
736
 
            fprintf(stderr, "(cocoa) can't create window\n");
737
 
            exit(1);
738
 
        }
739
 
        [normalWindow setAcceptsMouseMovedEvents:YES];
740
 
        [normalWindow setTitle:[NSString stringWithFormat:@"QEMU"]];
741
 
        [normalWindow setContentView:cocoaView];
742
 
        [normalWindow makeKeyAndOrderFront:self];
743
 
 
744
 
    }
745
 
    return self;
746
 
}
747
 
 
748
 
- (void) dealloc
749
 
{
750
 
    COCOA_DEBUG("QemuCocoaAppController: dealloc\n");
751
 
 
752
 
    if (cocoaView)
753
 
        [cocoaView release];
754
 
    [super dealloc];
755
 
}
756
 
 
 
734
@implementation QemuCocoaGUIController
 
735
/* Called when the internal event loop has just started running */
757
736
- (void)applicationDidFinishLaunching: (NSNotification *) note
758
737
{
759
 
    COCOA_DEBUG("QemuCocoaAppController: applicationDidFinishLaunching\n");
760
 
 
761
 
    // Display an open dialog box if no argument were passed or
762
 
    // if qemu was launched from the finder ( the Finder passes "-psn" )
763
 
    if( gArgc <= 1 || strncmp ((char *)gArgv[1], "-psn", 4) == 0) {
 
738
 
 
739
    /* Display an open dialog box if no argument were passed or
 
740
       if qemu was launched from the finder ( the Finder passes "-psn" ) */
 
741
 
 
742
    if( gArgc <= 1 || strncmp (gArgv[1], "-psn", 4) == 0)
 
743
    {
764
744
        NSOpenPanel *op = [[NSOpenPanel alloc] init];
 
745
        
 
746
        cocoa_resize(&current_ds, 640, 400);
 
747
        
765
748
        [op setPrompt:@"Boot image"];
 
749
        
766
750
        [op setMessage:@"Select the disk image you want to boot.\n\nHit the \"Cancel\" button to quit"];
 
751
        
767
752
        [op beginSheetForDirectory:nil file:nil types:[NSArray arrayWithObjects:@"img",@"iso",@"dmg",@"qcow",@"cow",@"cloop",@"vmdk",nil]
768
 
              modalForWindow:normalWindow modalDelegate:self
 
753
              modalForWindow:window modalDelegate:self
769
754
              didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:) contextInfo:NULL];
770
 
    } else {
771
 
        // or Launch Qemu, with the global args
772
 
        [self startEmulationWithArgc:gArgc argv:(char **)gArgv];
 
755
    }
 
756
    else
 
757
    {
 
758
        /* or Launch Qemu, with the global args */
 
759
        [self startEmulationWithArgc:gArgc argv:gArgv];
773
760
    }
774
761
}
775
762
 
776
763
- (void)applicationWillTerminate:(NSNotification *)aNotification
777
764
{
778
 
    COCOA_DEBUG("QemuCocoaAppController: applicationWillTerminate\n");
779
 
 
 
765
    printf("Application will terminate\n");
780
766
    qemu_system_shutdown_request();
 
767
    /* In order to avoid a crash */
781
768
    exit(0);
782
769
}
783
770
 
784
 
- (void)startEmulationWithArgc:(int)argc argv:(char**)argv
785
 
{
786
 
    COCOA_DEBUG("QemuCocoaAppController: startEmulationWithArgc\n");
787
 
 
788
 
    int status;
789
 
    status = qemu_main(argc, argv);
790
 
    exit(status);
791
 
}
792
 
 
793
771
- (void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
794
772
{
795
 
    COCOA_DEBUG("QemuCocoaAppController: openPanelDidEnd\n");
796
 
 
797
 
    if(returnCode == NSCancelButton) {
 
773
    if(returnCode == NSCancelButton)
 
774
    {
798
775
        exit(0);
799
 
    } else if(returnCode == NSOKButton) {
 
776
    }
 
777
    
 
778
    if(returnCode == NSOKButton)
 
779
    {
800
780
        char *bin = "qemu";
801
 
        char *img = (char*)[ [ sheet filename ] cStringUsingEncoding:NSASCIIStringEncoding];
802
 
 
 
781
        char *img = (char*)[ [ sheet filename ] cString];
 
782
        
803
783
        char **argv = (char**)malloc( sizeof(char*)*3 );
804
 
 
 
784
        
805
785
        asprintf(&argv[0], "%s", bin);
806
786
        asprintf(&argv[1], "-hda");
807
787
        asprintf(&argv[2], "%s", img);
808
 
 
 
788
        
809
789
        printf("Using argc %d argv %s -hda %s\n", 3, bin, img);
810
 
 
 
790
        
811
791
        [self startEmulationWithArgc:3 argv:(char**)argv];
812
792
    }
813
793
}
814
 
- (void)toggleFullScreen:(id)sender
815
 
{
816
 
    COCOA_DEBUG("QemuCocoaAppController: toggleFullScreen\n");
817
 
 
818
 
    [cocoaView toggleFullScreen:sender];
819
 
}
820
 
 
821
 
- (void)showQEMUDoc:(id)sender
822
 
{
823
 
    COCOA_DEBUG("QemuCocoaAppController: showQEMUDoc\n");
824
 
 
825
 
    [[NSWorkspace sharedWorkspace] openFile:[NSString stringWithFormat:@"%@/../doc/qemu/qemu-doc.html",
826
 
        [[NSBundle mainBundle] resourcePath]] withApplication:@"Help Viewer"];
827
 
}
828
 
 
829
 
- (void)showQEMUTec:(id)sender
830
 
{
831
 
    COCOA_DEBUG("QemuCocoaAppController: showQEMUTec\n");
832
 
 
833
 
    [[NSWorkspace sharedWorkspace] openFile:[NSString stringWithFormat:@"%@/../doc/qemu/qemu-tech.html",
834
 
        [[NSBundle mainBundle] resourcePath]] withApplication:@"Help Viewer"];
 
794
 
 
795
- (void)startEmulationWithArgc:(int)argc argv:(char**)argv
 
796
{
 
797
    int status;
 
798
    /* Launch Qemu */
 
799
    printf("starting qemu...\n");
 
800
    status = qemu_main (argc, argv);
 
801
    exit(status);
835
802
}
836
803
@end
837
804
 
838
 
 
839
 
 
840
 
// Dock Connection
 
805
/*
 
806
 ------------------------------------------------------
 
807
    Application Creation
 
808
 ------------------------------------------------------
 
809
*/
 
810
 
 
811
/* Dock Connection */
841
812
typedef struct CPSProcessSerNum
842
813
{
843
814
        UInt32                lo;
848
819
extern OSErr    CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5);
849
820
extern OSErr    CPSSetFrontProcess( CPSProcessSerNum *psn);
850
821
 
851
 
int main (int argc, const char * argv[]) {
852
 
 
853
 
    gArgc = argc;
854
 
    gArgv = (char **)argv;
 
822
/* Menu Creation */
 
823
static void setApplicationMenu(void)
 
824
{
 
825
    /* warning: this code is very odd */
 
826
    NSMenu *appleMenu;
 
827
    NSMenuItem *menuItem;
 
828
    NSString *title;
 
829
    NSString *appName;
 
830
    
 
831
    appName = @"Qemu";
 
832
    appleMenu = [[NSMenu alloc] initWithTitle:@""];
 
833
    
 
834
    /* Add menu items */
 
835
    title = [@"About " stringByAppendingString:appName];
 
836
    [appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""];
 
837
 
 
838
    [appleMenu addItem:[NSMenuItem separatorItem]];
 
839
 
 
840
    title = [@"Hide " stringByAppendingString:appName];
 
841
    [appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"];
 
842
 
 
843
    menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"];
 
844
    [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)];
 
845
 
 
846
    [appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""];
 
847
 
 
848
    [appleMenu addItem:[NSMenuItem separatorItem]];
 
849
 
 
850
    title = [@"Quit " stringByAppendingString:appName];
 
851
    [appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"];
 
852
 
 
853
    
 
854
    /* Put menu into the menubar */
 
855
    menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""];
 
856
    [menuItem setSubmenu:appleMenu];
 
857
    [[NSApp mainMenu] addItem:menuItem];
 
858
 
 
859
    /* Tell the application object that this is now the application menu */
 
860
    [NSApp setAppleMenu:appleMenu];
 
861
 
 
862
    /* Finally give up our references to the objects */
 
863
    [appleMenu release];
 
864
    [menuItem release];
 
865
}
 
866
 
 
867
/* Create a window menu */
 
868
static void setupWindowMenu(void)
 
869
{
 
870
    NSMenu      *windowMenu;
 
871
    NSMenuItem  *windowMenuItem;
 
872
    NSMenuItem  *menuItem;
 
873
 
 
874
    windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
 
875
    
 
876
    /* "Minimize" item */
 
877
    menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"];
 
878
    [windowMenu addItem:menuItem];
 
879
    [menuItem release];
 
880
    
 
881
    /* Put menu into the menubar */
 
882
    windowMenuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""];
 
883
    [windowMenuItem setSubmenu:windowMenu];
 
884
    [[NSApp mainMenu] addItem:windowMenuItem];
 
885
    
 
886
    /* Tell the application object that this is now the window menu */
 
887
    [NSApp setWindowsMenu:windowMenu];
 
888
 
 
889
    /* Finally give up our references to the objects */
 
890
    [windowMenu release];
 
891
    [windowMenuItem release];
 
892
}
 
893
 
 
894
static void CustomApplicationMain(void)
 
895
{
 
896
    NSAutoreleasePool   *pool = [[NSAutoreleasePool alloc] init];
 
897
    QemuCocoaGUIController *gui_controller;
855
898
    CPSProcessSerNum PSN;
856
 
 
857
 
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
 
899
    
858
900
    [NSApplication sharedApplication];
859
 
 
 
901
    
860
902
    if (!CPSGetCurrentProcess(&PSN))
861
903
        if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103))
862
904
            if (!CPSSetFrontProcess(&PSN))
863
905
                [NSApplication sharedApplication];
864
 
 
865
 
    // Add menus
866
 
    NSMenu      *menu;
867
 
    NSMenuItem  *menuItem;
868
 
 
 
906
                
 
907
    /* Set up the menubar */
869
908
    [NSApp setMainMenu:[[NSMenu alloc] init]];
870
 
 
871
 
    // Application menu
872
 
    menu = [[NSMenu alloc] initWithTitle:@""];
873
 
    [menu addItemWithTitle:@"About QEMU" action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""]; // About QEMU
874
 
    [menu addItem:[NSMenuItem separatorItem]]; //Separator
875
 
    [menu addItemWithTitle:@"Hide QEMU" action:@selector(hide:) keyEquivalent:@"h"]; //Hide QEMU
876
 
    menuItem = (NSMenuItem *)[menu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"]; // Hide Others
877
 
    [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)];
878
 
    [menu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""]; // Show All
879
 
    [menu addItem:[NSMenuItem separatorItem]]; //Separator
880
 
    [menu addItemWithTitle:@"Quit QEMU" action:@selector(terminate:) keyEquivalent:@"q"];
881
 
    menuItem = [[NSMenuItem alloc] initWithTitle:@"Apple" action:nil keyEquivalent:@""];
882
 
    [menuItem setSubmenu:menu];
883
 
    [[NSApp mainMenu] addItem:menuItem];
884
 
    [NSApp performSelector:@selector(setAppleMenu:) withObject:menu]; // Workaround (this method is private since 10.4+)
885
 
 
886
 
    // View menu
887
 
    menu = [[NSMenu alloc] initWithTitle:@"View"];
888
 
    [menu addItem: [[[NSMenuItem alloc] initWithTitle:@"Enter Fullscreen" action:@selector(toggleFullScreen:) keyEquivalent:@"f"] autorelease]]; // Fullscreen
889
 
    menuItem = [[[NSMenuItem alloc] initWithTitle:@"View" action:nil keyEquivalent:@""] autorelease];
890
 
    [menuItem setSubmenu:menu];
891
 
    [[NSApp mainMenu] addItem:menuItem];
892
 
 
893
 
    // Window menu
894
 
    menu = [[NSMenu alloc] initWithTitle:@"Window"];
895
 
    [menu addItem: [[[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"] autorelease]]; // Miniaturize
896
 
    menuItem = [[[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""] autorelease];
897
 
    [menuItem setSubmenu:menu];
898
 
    [[NSApp mainMenu] addItem:menuItem];
899
 
    [NSApp setWindowsMenu:menu];
900
 
 
901
 
    // Help menu
902
 
    menu = [[NSMenu alloc] initWithTitle:@"Help"];
903
 
    [menu addItem: [[[NSMenuItem alloc] initWithTitle:@"QEMU Documentation" action:@selector(showQEMUDoc:) keyEquivalent:@"?"] autorelease]]; // QEMU Help
904
 
    [menu addItem: [[[NSMenuItem alloc] initWithTitle:@"QEMU Technology" action:@selector(showQEMUTec:) keyEquivalent:@""] autorelease]]; // QEMU Help
905
 
    menuItem = [[[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""] autorelease];
906
 
    [menuItem setSubmenu:menu];
907
 
    [[NSApp mainMenu] addItem:menuItem];
908
 
 
909
 
    // Create an Application controller
910
 
    QemuCocoaAppController *appController = [[QemuCocoaAppController alloc] init];
911
 
    [NSApp setDelegate:appController];
912
 
 
913
 
    // Start the main event loop
 
909
    setApplicationMenu();
 
910
    setupWindowMenu();
 
911
 
 
912
    /* Create SDLMain and make it the app delegate */
 
913
    gui_controller = [[QemuCocoaGUIController alloc] init];
 
914
    [NSApp setDelegate:gui_controller];
 
915
    
 
916
    /* Start the main event loop */
914
917
    [NSApp run];
915
 
 
916
 
    [appController release];
 
918
    
 
919
    [gui_controller release];
917
920
    [pool release];
 
921
}
 
922
 
 
923
/* Real main of qemu-cocoa */
 
924
int main(int argc, char **argv)
 
925
{
 
926
    gArgc = argc;
 
927
    gArgv = argv;
 
928
 
 
929
    CustomApplicationMain();
918
930
 
919
931
    return 0;
920
932
}
921
 
 
922
 
 
923
 
 
924
 
#pragma mark qemu
925
 
static void cocoa_update(DisplayState *ds, int x, int y, int w, int h)
926
 
{
927
 
    COCOA_DEBUG("qemu_cocoa: cocoa_update\n");
928
 
 
929
 
    NSRect rect;
930
 
    if ([cocoaView cdx] == 1.0) {
931
 
        rect = NSMakeRect(x, [cocoaView gscreen].height - y - h, w, h);
932
 
    } else {
933
 
        rect = NSMakeRect(
934
 
            x * [cocoaView cdx],
935
 
            ([cocoaView gscreen].height - y - h) * [cocoaView cdy],
936
 
            w * [cocoaView cdx],
937
 
            h * [cocoaView cdy]);
938
 
    }
939
 
    [cocoaView displayRect:rect];
940
 
}
941
 
 
942
 
static void cocoa_resize(DisplayState *ds, int w, int h)
943
 
{
944
 
    COCOA_DEBUG("qemu_cocoa: cocoa_resize\n");
945
 
 
946
 
    [cocoaView resizeContentToWidth:w height:h displayState:ds];
947
 
}
948
 
 
949
 
static void cocoa_refresh(DisplayState *ds)
950
 
{
951
 
    COCOA_DEBUG("qemu_cocoa: cocoa_refresh\n");
952
 
 
953
 
    if (kbd_mouse_is_absolute()) {
954
 
        if (![cocoaView isAbsoluteEnabled]) {
955
 
            if ([cocoaView isMouseGrabed]) {
956
 
                [cocoaView ungrabMouse];
957
 
            }
958
 
        }
959
 
        [cocoaView setAbsoluteEnabled:YES];
960
 
    }
961
 
 
962
 
    NSDate *distantPast;
963
 
    NSEvent *event;
964
 
    distantPast = [NSDate distantPast];
965
 
    do {
966
 
        event = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:distantPast
967
 
                        inMode: NSDefaultRunLoopMode dequeue:YES];
968
 
        if (event != nil) {
969
 
            [cocoaView handleEvent:event];
970
 
        }
971
 
    } while(event != nil);
972
 
    vga_hw_update();
973
 
}
974
 
 
975
 
static void cocoa_cleanup(void)
976
 
{
977
 
    COCOA_DEBUG("qemu_cocoa: cocoa_cleanup\n");
978
 
 
979
 
}
980
 
 
981
 
void cocoa_display_init(DisplayState *ds, int full_screen)
982
 
{
983
 
    COCOA_DEBUG("qemu_cocoa: cocoa_display_init\n");
984
 
 
985
 
    // register vga outpu callbacks
986
 
    ds->dpy_update = cocoa_update;
987
 
    ds->dpy_resize = cocoa_resize;
988
 
    ds->dpy_refresh = cocoa_refresh;
989
 
 
990
 
    // give window a initial Size
991
 
    cocoa_resize(ds, 640, 400);
992
 
 
993
 
    // register cleanup function
994
 
    atexit(cocoa_cleanup);
995
 
}