]> Git Repo - qemu.git/blame - cocoa.m
Avoid accessing guest memory directly in usermode emulation.
[qemu.git] / cocoa.m
CommitLineData
5b0753e0
FB
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*/
da4dbf74 37
5b0753e0
FB
38#import <Cocoa/Cocoa.h>
39
da4dbf74
FB
40#include "vl.h"
41
5b0753e0
FB
42NSWindow *window = NULL;
43NSQuickDrawView *qd_view = NULL;
44
45
46int gArgc;
47char **gArgv;
48DisplayState current_ds;
49
87f48e6a
FB
50int grab = 0;
51int modifiers_state[256];
52
5b0753e0
FB
53/* main defined in qemu/vl.c */
54int 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*/
73static 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*/
99static 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
168 current_ds = *ds;
169}
170
171/*
172 ------------------------------------------------------
173 keymap conversion
174 ------------------------------------------------------
175*/
176
87f48e6a 177int keymap[] =
5b0753e0 178{
87f48e6a
FB
179// SdlI macI macH SdlH 104xtH 104xtC sdl
180 30, // 0 0x00 0x1e A QZ_a
181 31, // 1 0x01 0x1f S QZ_s
182 32, // 2 0x02 0x20 D QZ_d
183 33, // 3 0x03 0x21 F QZ_f
184 35, // 4 0x04 0x23 H QZ_h
185 34, // 5 0x05 0x22 G QZ_g
186 44, // 6 0x06 0x2c Z QZ_z
187 45, // 7 0x07 0x2d X QZ_x
188 46, // 8 0x08 0x2e C QZ_c
189 47, // 9 0x09 0x2f V QZ_v
190 0, // 10 0x0A Undefined
191 48, // 11 0x0B 0x30 B QZ_b
192 16, // 12 0x0C 0x10 Q QZ_q
193 17, // 13 0x0D 0x11 W QZ_w
194 18, // 14 0x0E 0x12 E QZ_e
195 19, // 15 0x0F 0x13 R QZ_r
196 21, // 16 0x10 0x15 Y QZ_y
197 20, // 17 0x11 0x14 T QZ_t
198 2, // 18 0x12 0x02 1 QZ_1
199 3, // 19 0x13 0x03 2 QZ_2
200 4, // 20 0x14 0x04 3 QZ_3
201 5, // 21 0x15 0x05 4 QZ_4
202 7, // 22 0x16 0x07 6 QZ_6
203 6, // 23 0x17 0x06 5 QZ_5
204 13, // 24 0x18 0x0d = QZ_EQUALS
205 10, // 25 0x19 0x0a 9 QZ_9
206 8, // 26 0x1A 0x08 7 QZ_7
207 12, // 27 0x1B 0x0c - QZ_MINUS
208 9, // 28 0x1C 0x09 8 QZ_8
209 11, // 29 0x1D 0x0b 0 QZ_0
210 27, // 30 0x1E 0x1b ] QZ_RIGHTBRACKET
211 24, // 31 0x1F 0x18 O QZ_o
212 22, // 32 0x20 0x16 U QZ_u
213 26, // 33 0x21 0x1a [ QZ_LEFTBRACKET
214 23, // 34 0x22 0x17 I QZ_i
215 25, // 35 0x23 0x19 P QZ_p
216 28, // 36 0x24 0x1c ENTER QZ_RETURN
217 38, // 37 0x25 0x26 L QZ_l
218 36, // 38 0x26 0x24 J QZ_j
219 40, // 39 0x27 0x28 ' QZ_QUOTE
220 37, // 40 0x28 0x25 K QZ_k
221 39, // 41 0x29 0x27 ; QZ_SEMICOLON
222 43, // 42 0x2A 0x2b \ QZ_BACKSLASH
223 51, // 43 0x2B 0x33 , QZ_COMMA
224 53, // 44 0x2C 0x35 / QZ_SLASH
225 49, // 45 0x2D 0x31 N QZ_n
226 50, // 46 0x2E 0x32 M QZ_m
227 52, // 47 0x2F 0x34 . QZ_PERIOD
228 15, // 48 0x30 0x0f TAB QZ_TAB
229 57, // 49 0x31 0x39 SPACE QZ_SPACE
230 41, // 50 0x32 0x29 ` QZ_BACKQUOTE
231 14, // 51 0x33 0x0e BKSP QZ_BACKSPACE
232 0, // 52 0x34 Undefined
233 1, // 53 0x35 0x01 ESC QZ_ESCAPE
234 0, // 54 0x36 QZ_RMETA
235 0, // 55 0x37 QZ_LMETA
236 42, // 56 0x38 0x2a L SHFT QZ_LSHIFT
237 58, // 57 0x39 0x3a CAPS QZ_CAPSLOCK
238 56, // 58 0x3A 0x38 L ALT QZ_LALT
239 29, // 59 0x3B 0x1d L CTRL QZ_LCTRL
240 54, // 60 0x3C 0x36 R SHFT QZ_RSHIFT
241 184,// 61 0x3D 0xb8 E0,38 R ALT QZ_RALT
242 157,// 62 0x3E 0x9d E0,1D R CTRL QZ_RCTRL
243 0, // 63 0x3F Undefined
244 0, // 64 0x40 Undefined
245 0, // 65 0x41 Undefined
246 0, // 66 0x42 Undefined
247 55, // 67 0x43 0x37 KP * QZ_KP_MULTIPLY
248 0, // 68 0x44 Undefined
249 78, // 69 0x45 0x4e KP + QZ_KP_PLUS
250 0, // 70 0x46 Undefined
251 69, // 71 0x47 0x45 NUM QZ_NUMLOCK
252 0, // 72 0x48 Undefined
253 0, // 73 0x49 Undefined
254 0, // 74 0x4A Undefined
255 181,// 75 0x4B 0xb5 E0,35 KP / QZ_KP_DIVIDE
256 152,// 76 0x4C 0x9c E0,1C KP EN QZ_KP_ENTER
257 0, // 77 0x4D undefined
258 74, // 78 0x4E 0x4a KP - QZ_KP_MINUS
259 0, // 79 0x4F Undefined
260 0, // 80 0x50 Undefined
261 0, // 81 0x51 QZ_KP_EQUALS
262 82, // 82 0x52 0x52 KP 0 QZ_KP0
263 79, // 83 0x53 0x4f KP 1 QZ_KP1
264 80, // 84 0x54 0x50 KP 2 QZ_KP2
265 81, // 85 0x55 0x51 KP 3 QZ_KP3
266 75, // 86 0x56 0x4b KP 4 QZ_KP4
267 76, // 87 0x57 0x4c KP 5 QZ_KP5
268 77, // 88 0x58 0x4d KP 6 QZ_KP6
269 71, // 89 0x59 0x47 KP 7 QZ_KP7
270 0, // 90 0x5A Undefined
271 72, // 91 0x5B 0x48 KP 8 QZ_KP8
272 73, // 92 0x5C 0x49 KP 9 QZ_KP9
273 0, // 93 0x5D Undefined
274 0, // 94 0x5E Undefined
275 0, // 95 0x5F Undefined
276 63, // 96 0x60 0x3f F5 QZ_F5
277 64, // 97 0x61 0x40 F6 QZ_F6
278 65, // 98 0x62 0x41 F7 QZ_F7
279 61, // 99 0x63 0x3d F3 QZ_F3
280 66, // 100 0x64 0x42 F8 QZ_F8
281 67, // 101 0x65 0x43 F9 QZ_F9
282 0, // 102 0x66 Undefined
283 87, // 103 0x67 0x57 F11 QZ_F11
284 0, // 104 0x68 Undefined
285 183,// 105 0x69 0xb7 QZ_PRINT
286 0, // 106 0x6A Undefined
287 70, // 107 0x6B 0x46 SCROLL QZ_SCROLLOCK
288 0, // 108 0x6C Undefined
289 68, // 109 0x6D 0x44 F10 QZ_F10
290 0, // 110 0x6E Undefined
291 88, // 111 0x6F 0x58 F12 QZ_F12
292 0, // 112 0x70 Undefined
293 110,// 113 0x71 0x0 QZ_PAUSE
294 210,// 114 0x72 0xd2 E0,52 INSERT QZ_INSERT
295 199,// 115 0x73 0xc7 E0,47 HOME QZ_HOME
296 201,// 116 0x74 0xc9 E0,49 PG UP QZ_PAGEUP
297 211,// 117 0x75 0xd3 E0,53 DELETE QZ_DELETE
298 62, // 118 0x76 0x3e F4 QZ_F4
299 207,// 119 0x77 0xcf E0,4f END QZ_END
300 60, // 120 0x78 0x3c F2 QZ_F2
301 209,// 121 0x79 0xd1 E0,51 PG DN QZ_PAGEDOWN
302 59, // 122 0x7A 0x3b F1 QZ_F1
303 203,// 123 0x7B 0xcb e0,4B L ARROW QZ_LEFT
304 205,// 124 0x7C 0xcd e0,4D R ARROW QZ_RIGHT
305 208,// 125 0x7D 0xd0 E0,50 D ARROW QZ_DOWN
306 200,// 126 0x7E 0xc8 E0,48 U ARROW QZ_UP
307/* 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 */
308
309/* Aditional 104 Key XP-Keyboard Scancodes from http://www.computer-engineering.org/ps2keyboard/scancodes1.html */
310/*
311 219 // 0xdb e0,5b L GUI
312 220 // 0xdc e0,5c R GUI
313 221 // 0xdd e0,5d APPS
314 // E0,2A,E0,37 PRNT SCRN
315 // E1,1D,45,E1,9D,C5 PAUSE
316 83 // 0x53 0x53 KP .
317// ACPI Scan Codes
318 222 // 0xde E0, 5E Power
319 223 // 0xdf E0, 5F Sleep
320 227 // 0xe3 E0, 63 Wake
321// Windows Multimedia Scan Codes
322 153 // 0x99 E0, 19 Next Track
323 144 // 0x90 E0, 10 Previous Track
324 164 // 0xa4 E0, 24 Stop
325 162 // 0xa2 E0, 22 Play/Pause
326 160 // 0xa0 E0, 20 Mute
327 176 // 0xb0 E0, 30 Volume Up
328 174 // 0xae E0, 2E Volume Down
329 237 // 0xed E0, 6D Media Select
330 236 // 0xec E0, 6C E-Mail
331 161 // 0xa1 E0, 21 Calculator
332 235 // 0xeb E0, 6B My Computer
333 229 // 0xe5 E0, 65 WWW Search
334 178 // 0xb2 E0, 32 WWW Home
335 234 // 0xea E0, 6A WWW Back
336 233 // 0xe9 E0, 69 WWW Forward
337 232 // 0xe8 E0, 68 WWW Stop
338 231 // 0xe7 E0, 67 WWW Refresh
339 230 // 0xe6 E0, 66 WWW Favorites
340*/
5b0753e0
FB
341};
342
87f48e6a 343int cocoa_keycode_to_qemu(int keycode)
5b0753e0 344{
87f48e6a 345 if((sizeof(keymap)/sizeof(int)) <= keycode)
5b0753e0
FB
346 {
347 printf("(cocoa) warning unknow keycode 0x%x\n", keycode);
348 return 0;
349 }
350 return keymap[keycode];
351}
352
353/*
354 ------------------------------------------------------
355 cocoa_refresh
356 ------------------------------------------------------
357*/
358static void cocoa_refresh(DisplayState *ds)
359{
360 //printf("cocoa_refresh \n");
361 NSDate *distantPast;
362 NSEvent *event;
363 NSAutoreleasePool *pool;
5b0753e0
FB
364
365 pool = [ [ NSAutoreleasePool alloc ] init ];
366 distantPast = [ NSDate distantPast ];
367
368 if (is_active_console(vga_console))
369 vga_update_display();
370 do {
371 event = [ NSApp nextEventMatchingMask:NSAnyEventMask untilDate:distantPast
372 inMode: NSDefaultRunLoopMode dequeue:YES ];
373 if (event != nil) {
374 switch ([event type]) {
87f48e6a 375 case NSFlagsChanged:
5b0753e0
FB
376 {
377 int keycode = cocoa_keycode_to_qemu([event keyCode]);
7c206a75
FB
378
379 if (keycode)
87f48e6a 380 {
7c206a75
FB
381 if (keycode == 58 || keycode == 69) {
382 /* emulate caps lock and num lock keydown and keyup */
383 kbd_put_keycode(keycode);
384 kbd_put_keycode(keycode | 0x80);
385 } else if (is_active_console(vga_console)) {
386 if (keycode & 0x80)
387 kbd_put_keycode(0xe0);
388 if (modifiers_state[keycode] == 0) {
389 /* keydown */
390 kbd_put_keycode(keycode & 0x7f);
391 modifiers_state[keycode] = 1;
392 } else {
393 /* keyup */
394 kbd_put_keycode(keycode | 0x80);
395 modifiers_state[keycode] = 0;
396 }
397 }
87f48e6a 398 }
7c206a75 399
87f48e6a
FB
400 /* release Mouse grab when pressing ctrl+alt */
401 if (([event modifierFlags] & NSControlKeyMask) && ([event modifierFlags] & NSAlternateKeyMask))
7c206a75 402 {
87f48e6a
FB
403 [window setTitle: @"QEMU"];
404 [NSCursor unhide];
405 CGAssociateMouseAndMouseCursorPosition ( TRUE );
406 grab = 0;
7c206a75 407 }
5b0753e0
FB
408 }
409 break;
7c206a75 410
87f48e6a
FB
411 case NSKeyDown:
412 {
413 int keycode = cocoa_keycode_to_qemu([event keyCode]);
414
415 /* handle command Key Combos */
416 if ([event modifierFlags] & NSCommandKeyMask) {
417 switch ([event keyCode]) {
418 /* quit */
419 case 12: /* q key */
420 /* switch to windowed View */
421 exit(0);
422 return;
423 }
424 }
425
426 /* handle control + alt Key Combos */
427 if (([event modifierFlags] & NSControlKeyMask) && ([event modifierFlags] & NSAlternateKeyMask)) {
428 switch (keycode) {
429 /* toggle Monitor */
430 case 0x02 ... 0x0a: /* '1' to '9' keys */
431 console_select(keycode - 0x02);
432 if (is_active_console(vga_console)) {
433 /* tell the vga console to redisplay itself */
434 vga_invalidate_display();
435 break;
436 }
437 }
438 } else {
439 /* handle standard key events */
440 if (is_active_console(vga_console)) {
441 if (keycode & 0x80) //check bit for e0 in front
442 kbd_put_keycode(0xe0);
443 kbd_put_keycode(keycode & 0x7f); //remove e0 bit in front
444 /* handle monitor key events */
445 } else {
446 switch([event keyCode]) {
447 case 123:
448 kbd_put_keysym(QEMU_KEY_LEFT);
449 break;
450 case 124:
451 kbd_put_keysym(QEMU_KEY_RIGHT);
452 break;
453 case 125:
454 kbd_put_keysym(QEMU_KEY_DOWN);
455 break;
456 case 126:
457 kbd_put_keysym(QEMU_KEY_UP);
458 break;
459 default:
460 kbd_put_keysym([[event characters] characterAtIndex:0]);
461 break;
462 }
463 }
464 }
465 }
466 break;
467
5b0753e0 468 case NSKeyUp:
5b0753e0 469 {
87f48e6a
FB
470 int keycode = cocoa_keycode_to_qemu([event keyCode]);
471 if (is_active_console(vga_console)) {
472 if (keycode & 0x80)
473 kbd_put_keycode(0xe0);
474 kbd_put_keycode(keycode | 0x80); //add 128 to signal release of key
475 }
5b0753e0
FB
476 }
477 break;
87f48e6a
FB
478
479 case NSMouseMoved:
480 if (grab) {
481 int dx = [event deltaX];
482 int dy = [event deltaY];
483 int dz = [event deltaZ];
484 int buttons = 0;
485 kbd_mouse_event(dx, dy, dz, buttons);
486 }
487 break;
488
5b0753e0 489 case NSLeftMouseDown:
87f48e6a
FB
490 if (grab) {
491 int buttons = 0;
492
493 /* leftclick+command simulates rightclick */
494 if ([event modifierFlags] & NSCommandKeyMask) {
495 buttons |= MOUSE_EVENT_RBUTTON;
496 } else {
497 buttons |= MOUSE_EVENT_LBUTTON;
498 }
499 kbd_mouse_event(0, 0, 0, buttons);
500 } else {
501 [NSApp sendEvent: event];
502 }
503 break;
504
505 case NSLeftMouseDragged:
506 if (grab) {
507 int dx = [event deltaX];
508 int dy = [event deltaY];
509 int dz = [event deltaZ];
510 int buttons = 0;
511 if ([[NSApp currentEvent] modifierFlags] & NSCommandKeyMask) { //leftclick+command simulates rightclick
512 buttons |= MOUSE_EVENT_RBUTTON;
513 } else {
514 buttons |= MOUSE_EVENT_LBUTTON;
515 }
516 kbd_mouse_event(dx, dy, dz, buttons);
517 }
518 break;
519
5b0753e0 520 case NSLeftMouseUp:
87f48e6a
FB
521 if (grab) {
522 kbd_mouse_event(0, 0, 0, 0);
523 } else {
524 [window setTitle: @"QEMU (Press ctrl + alt to release Mouse)"];
525 [NSCursor hide];
526 CGAssociateMouseAndMouseCursorPosition ( FALSE );
527 grab = 1;
528 //[NSApp sendEvent: event];
529 }
530 break;
531
5b0753e0 532 case NSRightMouseDown:
87f48e6a
FB
533 if (grab) {
534 int buttons = 0;
535
536 buttons |= MOUSE_EVENT_RBUTTON;
537 kbd_mouse_event(0, 0, 0, buttons);
538 } else {
539 [NSApp sendEvent: event];
540 }
541 break;
542
543 case NSRightMouseDragged:
544 if (grab) {
545 int dx = [event deltaX];
546 int dy = [event deltaY];
547 int dz = [event deltaZ];
548 int buttons = 0;
549 buttons |= MOUSE_EVENT_RBUTTON;
550 kbd_mouse_event(dx, dy, dz, buttons);
551 }
552 break;
553
5b0753e0 554 case NSRightMouseUp:
87f48e6a
FB
555 if (grab) {
556 kbd_mouse_event(0, 0, 0, 0);
557 } else {
558 [NSApp sendEvent: event];
559 }
560 break;
561
5b0753e0 562 case NSOtherMouseDragged:
87f48e6a
FB
563 if (grab) {
564 int dx = [event deltaX];
565 int dy = [event deltaY];
566 int dz = [event deltaZ];
567 int buttons = 0;
568 buttons |= MOUSE_EVENT_MBUTTON;
569 kbd_mouse_event(dx, dy, dz, buttons);
570 }
571 break;
572
573 case NSOtherMouseDown:
574 if (grab) {
575 int buttons = 0;
576 buttons |= MOUSE_EVENT_MBUTTON;
577 kbd_mouse_event(0, 0, 0, buttons);
578 } else {
579 [NSApp sendEvent:event];
580 }
581 break;
582
583 case NSOtherMouseUp:
584 if (grab) {
585 kbd_mouse_event(0, 0, 0, 0);
586 } else {
587 [NSApp sendEvent: event];
588 }
589 break;
590
591 case NSScrollWheel:
592 if (grab) {
593 int dz = [event deltaY];
594 kbd_mouse_event(0, 0, -dz, 0);
595 }
596 break;
5b0753e0
FB
597
598 default: [NSApp sendEvent:event];
599 }
600 }
601 } while(event != nil);
602}
603
604/*
605 ------------------------------------------------------
606 cocoa_cleanup
607 ------------------------------------------------------
608*/
609
610static void cocoa_cleanup(void)
611{
612
613}
614
615/*
616 ------------------------------------------------------
617 cocoa_display_init
618 ------------------------------------------------------
619*/
620
621void cocoa_display_init(DisplayState *ds, int full_screen)
622{
623 ds->dpy_update = cocoa_update;
624 ds->dpy_resize = cocoa_resize;
625 ds->dpy_refresh = cocoa_refresh;
626
627 cocoa_resize(ds, 640, 400);
628
629 atexit(cocoa_cleanup);
630}
631
632/*
633 ------------------------------------------------------
634 Interface with Cocoa
635 ------------------------------------------------------
636*/
637
638
639/*
640 ------------------------------------------------------
641 QemuWindow
642 Some trick from SDL to use miniwindow
643 ------------------------------------------------------
644*/
645static void QZ_SetPortAlphaOpaque ()
646{
647 /* Assume 32 bit if( bpp == 32 )*/
648 if ( 1 ) {
649
650 uint32_t *pixels = (uint32_t*) current_ds.data;
651 uint32_t rowPixels = current_ds.linesize / 4;
652 uint32_t i, j;
653
654 for (i = 0; i < current_ds.height; i++)
655 for (j = 0; j < current_ds.width; j++) {
656
657 pixels[ (i * rowPixels) + j ] |= 0xFF000000;
658 }
659 }
660}
661
662@implementation QemuWindow
663- (void)miniaturize:(id)sender
664{
665
666 /* make the alpha channel opaque so anim won't have holes in it */
667 QZ_SetPortAlphaOpaque ();
668
669 [ super miniaturize:sender ];
670
671}
672- (void)display
673{
674 /*
675 This method fires just before the window deminaturizes from the Dock.
676
677 We'll save the current visible surface, let the window manager redraw any
678 UI elements, and restore the SDL surface. This way, no expose event
679 is required, and the deminiaturize works perfectly.
680 */
681
682 /* make sure pixels are fully opaque */
683 QZ_SetPortAlphaOpaque ();
684
685 /* save current visible SDL surface */
686 [ self cacheImageInRect:[ qd_view frame ] ];
687
688 /* let the window manager redraw controls, border, etc */
689 [ super display ];
690
691 /* restore visible SDL surface */
692 [ self restoreCachedImage ];
693}
694
695@end
696
697
698/*
699 ------------------------------------------------------
700 QemuCocoaGUIController
701 NSApp's delegate - indeed main object
702 ------------------------------------------------------
703*/
704
705@interface QemuCocoaGUIController : NSObject
706{
707}
708- (void)applicationDidFinishLaunching: (NSNotification *) note;
709- (void)applicationWillTerminate:(NSNotification *)aNotification;
710
711- (void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo;
712
713- (void)startEmulationWithArgc:(int)argc argv:(char**)argv;
714@end
715
716@implementation QemuCocoaGUIController
717/* Called when the internal event loop has just started running */
718- (void)applicationDidFinishLaunching: (NSNotification *) note
719{
5a246934
FB
720
721 /* Display an open dialog box if no argument were passed or
722 if qemu was launched from the finder ( the Finder passes "-psn" ) */
723
724 if( gArgc <= 1 || strncmp (gArgv[1], "-psn", 4) == 0)
5b0753e0
FB
725 {
726 NSOpenPanel *op = [[NSOpenPanel alloc] init];
727
728 cocoa_resize(&current_ds, 640, 400);
729
730 [op setPrompt:@"Boot image"];
731
732 [op setMessage:@"Select the disk image you want to boot.\n\nHit the \"Cancel\" button to quit"];
733
7a674b13 734 [op beginSheetForDirectory:nil file:nil types:[NSArray arrayWithObjects:@"img",@"iso",@"dmg",@"qcow",@"cow",@"cloop",@"vmdk",nil]
5b0753e0
FB
735 modalForWindow:window modalDelegate:self
736 didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:) contextInfo:NULL];
737 }
5a246934
FB
738 else
739 {
740 /* or Launch Qemu, with the global args */
741 [self startEmulationWithArgc:gArgc argv:gArgv];
742 }
5b0753e0
FB
743}
744
745- (void)applicationWillTerminate:(NSNotification *)aNotification
746{
747 printf("Application will terminate\n");
748 qemu_system_shutdown_request();
749 /* In order to avoid a crash */
750 exit(0);
751}
752
753- (void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
754{
755 if(returnCode == NSCancelButton)
756 {
757 exit(0);
758 }
759
760 if(returnCode == NSOKButton)
761 {
762 char *bin = "qemu";
763 char *img = (char*)[ [ sheet filename ] cString];
764
765 char **argv = (char**)malloc( sizeof(char*)*3 );
766
767 asprintf(&argv[0], "%s", bin);
768 asprintf(&argv[1], "-hda");
769 asprintf(&argv[2], "%s", img);
770
771 printf("Using argc %d argv %s -hda %s\n", 3, bin, img);
772
773 [self startEmulationWithArgc:3 argv:(char**)argv];
774 }
775}
776
777- (void)startEmulationWithArgc:(int)argc argv:(char**)argv
778{
779 int status;
780 /* Launch Qemu */
781 printf("starting qemu...\n");
782 status = qemu_main (argc, argv);
783 exit(status);
784}
785@end
786
787/*
788 ------------------------------------------------------
789 Application Creation
790 ------------------------------------------------------
791*/
792
793/* Dock Connection */
794typedef struct CPSProcessSerNum
795{
796 UInt32 lo;
797 UInt32 hi;
798} CPSProcessSerNum;
799
800extern OSErr CPSGetCurrentProcess( CPSProcessSerNum *psn);
801extern OSErr CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5);
802extern OSErr CPSSetFrontProcess( CPSProcessSerNum *psn);
803
804/* Menu Creation */
805static void setApplicationMenu(void)
806{
807 /* warning: this code is very odd */
808 NSMenu *appleMenu;
809 NSMenuItem *menuItem;
810 NSString *title;
811 NSString *appName;
812
813 appName = @"Qemu";
814 appleMenu = [[NSMenu alloc] initWithTitle:@""];
815
816 /* Add menu items */
817 title = [@"About " stringByAppendingString:appName];
818 [appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""];
819
820 [appleMenu addItem:[NSMenuItem separatorItem]];
821
822 title = [@"Hide " stringByAppendingString:appName];
823 [appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"];
824
825 menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"];
826 [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)];
827
828 [appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""];
829
830 [appleMenu addItem:[NSMenuItem separatorItem]];
831
832 title = [@"Quit " stringByAppendingString:appName];
833 [appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"];
834
835
836 /* Put menu into the menubar */
837 menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""];
838 [menuItem setSubmenu:appleMenu];
839 [[NSApp mainMenu] addItem:menuItem];
840
841 /* Tell the application object that this is now the application menu */
842 [NSApp setAppleMenu:appleMenu];
843
844 /* Finally give up our references to the objects */
845 [appleMenu release];
846 [menuItem release];
847}
848
849/* Create a window menu */
850static void setupWindowMenu(void)
851{
852 NSMenu *windowMenu;
853 NSMenuItem *windowMenuItem;
854 NSMenuItem *menuItem;
855
856 windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
857
858 /* "Minimize" item */
859 menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"];
860 [windowMenu addItem:menuItem];
861 [menuItem release];
862
863 /* Put menu into the menubar */
864 windowMenuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""];
865 [windowMenuItem setSubmenu:windowMenu];
866 [[NSApp mainMenu] addItem:windowMenuItem];
867
868 /* Tell the application object that this is now the window menu */
869 [NSApp setWindowsMenu:windowMenu];
870
871 /* Finally give up our references to the objects */
872 [windowMenu release];
873 [windowMenuItem release];
874
875}
876
877static void CustomApplicationMain (argc, argv)
878{
879 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
880 QemuCocoaGUIController *gui_controller;
881 CPSProcessSerNum PSN;
882
883 [NSApplication sharedApplication];
884
885 if (!CPSGetCurrentProcess(&PSN))
886 if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103))
887 if (!CPSSetFrontProcess(&PSN))
888 [NSApplication sharedApplication];
889
890 /* Set up the menubar */
891 [NSApp setMainMenu:[[NSMenu alloc] init]];
892 setApplicationMenu();
893 setupWindowMenu();
894
895 /* Create SDLMain and make it the app delegate */
896 gui_controller = [[QemuCocoaGUIController alloc] init];
897 [NSApp setDelegate:gui_controller];
898
899 /* Start the main event loop */
900 [NSApp run];
901
902 [gui_controller release];
903 [pool release];
904}
905
906/* Real main of qemu-cocoa */
907int main(int argc, char **argv)
908{
909 gArgc = argc;
910 gArgv = argv;
911
912 CustomApplicationMain (argc, argv);
913
914 return 0;
915}
This page took 0.15539 seconds and 4 git commands to generate.