]> git.proxmox.com Git - qemu.git/blob - cocoa.m
Break up vl.h.
[qemu.git] / 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 */
814 typedef struct CPSProcessSerNum
815 {
816 UInt32 lo;
817 UInt32 hi;
818 } CPSProcessSerNum;
819
820 extern OSErr CPSGetCurrentProcess( CPSProcessSerNum *psn);
821 extern OSErr CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5);
822 extern OSErr CPSSetFrontProcess( CPSProcessSerNum *psn);
823
824 /* Menu Creation */
825 static void setApplicationMenu(void)
826 {
827 /* warning: this code is very odd */
828 NSMenu *appleMenu;
829 NSMenuItem *menuItem;
830 NSString *title;
831 NSString *appName;
832
833 appName = @"Qemu";
834 appleMenu = [[NSMenu alloc] initWithTitle:@""];
835
836 /* Add menu items */
837 title = [@"About " stringByAppendingString:appName];
838 [appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""];
839
840 [appleMenu addItem:[NSMenuItem separatorItem]];
841
842 title = [@"Hide " stringByAppendingString:appName];
843 [appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"];
844
845 menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"];
846 [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)];
847
848 [appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""];
849
850 [appleMenu addItem:[NSMenuItem separatorItem]];
851
852 title = [@"Quit " stringByAppendingString:appName];
853 [appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"];
854
855
856 /* Put menu into the menubar */
857 menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""];
858 [menuItem setSubmenu:appleMenu];
859 [[NSApp mainMenu] addItem:menuItem];
860
861 /* Tell the application object that this is now the application menu */
862 [NSApp setAppleMenu:appleMenu];
863
864 /* Finally give up our references to the objects */
865 [appleMenu release];
866 [menuItem release];
867 }
868
869 /* Create a window menu */
870 static void setupWindowMenu(void)
871 {
872 NSMenu *windowMenu;
873 NSMenuItem *windowMenuItem;
874 NSMenuItem *menuItem;
875
876 windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
877
878 /* "Minimize" item */
879 menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"];
880 [windowMenu addItem:menuItem];
881 [menuItem release];
882
883 /* Put menu into the menubar */
884 windowMenuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""];
885 [windowMenuItem setSubmenu:windowMenu];
886 [[NSApp mainMenu] addItem:windowMenuItem];
887
888 /* Tell the application object that this is now the window menu */
889 [NSApp setWindowsMenu:windowMenu];
890
891 /* Finally give up our references to the objects */
892 [windowMenu release];
893 [windowMenuItem release];
894 }
895
896 static void CustomApplicationMain(void)
897 {
898 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
899 QemuCocoaGUIController *gui_controller;
900 CPSProcessSerNum PSN;
901
902 [NSApplication sharedApplication];
903
904 if (!CPSGetCurrentProcess(&PSN))
905 if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103))
906 if (!CPSSetFrontProcess(&PSN))
907 [NSApplication sharedApplication];
908
909 /* Set up the menubar */
910 [NSApp setMainMenu:[[NSMenu alloc] init]];
911 setApplicationMenu();
912 setupWindowMenu();
913
914 /* Create SDLMain and make it the app delegate */
915 gui_controller = [[QemuCocoaGUIController alloc] init];
916 [NSApp setDelegate:gui_controller];
917
918 /* Start the main event loop */
919 [NSApp run];
920
921 [gui_controller release];
922 [pool release];
923 }
924
925 /* Real main of qemu-cocoa */
926 int main(int argc, char **argv)
927 {
928 gArgc = argc;
929 gArgv = argv;
930
931 CustomApplicationMain();
932
933 return 0;
934 }