]> git.proxmox.com Git - mirror_qemu.git/blame - cocoa.m
fixed register constraint
[mirror_qemu.git] / cocoa.m
CommitLineData
5b0753e0
FB
1/*
2 * QEMU Cocoa display driver
5fafdf24 3 *
5b0753e0
FB
4 * Copyright (c) 2005 Pierre d'Herbemont
5 * many code/inspiration from SDL 1.2 code (LGPL)
5fafdf24 6 *
5b0753e0
FB
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/*
5fafdf24 26 Todo : x miniaturize window
5b0753e0
FB
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
87ecb68b
PB
40#include "qemu-common.h"
41#include "console.h"
42#include "sysemu.h"
da4dbf74 43
5b0753e0
FB
44NSWindow *window = NULL;
45NSQuickDrawView *qd_view = NULL;
46
47
48int gArgc;
49char **gArgv;
50DisplayState current_ds;
51
87f48e6a
FB
52int grab = 0;
53int modifiers_state[256];
54
5b0753e0
FB
55/* main defined in qemu/vl.c */
56int 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*/
75static 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);
3b46e624 89
5b0753e0
FB
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*/
101static 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;
3b46e624 107
5b0753e0 108 //printf("resizing to %d %d\n", w, h);
3b46e624 109
5b0753e0
FB
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 }
3b46e624 124
5b0753e0
FB
125 if(qd_view)
126 [qd_view release];
3b46e624 127
5b0753e0 128 qd_view = [ [ NSQuickDrawView alloc ] initWithFrame:contentRect ];
3b46e624 129
5b0753e0
FB
130 if(!qd_view)
131 {
132 fprintf(stderr, "(cocoa) can't create qd_view\n");
133 exit(1);
134 }
3b46e624 135
5b0753e0
FB
136 [ window setAcceptsMouseMovedEvents:YES ];
137 [ window setTitle:@"Qemu" ];
138 [ window setReleasedWhenClosed:NO ];
3b46e624 139
5b0753e0
FB
140 /* Set screen to black */
141 [ window setBackgroundColor: [NSColor blackColor] ];
3b46e624 142
5b0753e0
FB
143 /* set window position */
144 [ window center ];
3b46e624 145
5b0753e0
FB
146 [ qd_view setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable ];
147 [ [ window contentView ] addSubview:qd_view ];
148 [ qd_view release ];
149 [ window makeKeyAndOrderFront:nil ];
3b46e624 150
5b0753e0
FB
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 ] );
5fafdf24
TS
156 {
157 int vOffset = [ window frame ].size.height -
5b0753e0 158 [ qd_view frame ].size.height - [ qd_view frame ].origin.y;
3b46e624 159
5b0753e0 160 int hOffset = [ qd_view frame ].origin.x;
3b46e624 161
5b0753e0
FB
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;
b29169d2
BS
169#ifdef __LITTLE_ENDIAN__
170 ds->bgr = 1;
171#else
172 ds->bgr = 0;
173#endif
174
5b0753e0
FB
175 current_ds = *ds;
176}
177
178/*
179 ------------------------------------------------------
180 keymap conversion
181 ------------------------------------------------------
182*/
183
87f48e6a 184int keymap[] =
5b0753e0 185{
87f48e6a
FB
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 */
3b46e624 315
87f48e6a
FB
316/* Aditional 104 Key XP-Keyboard Scancodes from http://www.computer-engineering.org/ps2keyboard/scancodes1.html */
317/*
3b46e624
TS
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
5fafdf24 335 174 // 0xae E0, 2E Volume Down
3b46e624
TS
336 237 // 0xed E0, 6D Media Select
337 236 // 0xec E0, 6C E-Mail
338 161 // 0xa1 E0, 21 Calculator
5fafdf24 339 235 // 0xeb E0, 6B My Computer
3b46e624
TS
340 229 // 0xe5 E0, 65 WWW Search
341 178 // 0xb2 E0, 32 WWW Home
342 234 // 0xea E0, 6A WWW Back
5fafdf24 343 233 // 0xe9 E0, 69 WWW Forward
3b46e624 344 232 // 0xe8 E0, 68 WWW Stop
5fafdf24 345 231 // 0xe7 E0, 67 WWW Refresh
3b46e624 346 230 // 0xe6 E0, 66 WWW Favorites
87f48e6a 347*/
5b0753e0
FB
348};
349
87f48e6a 350int cocoa_keycode_to_qemu(int keycode)
5b0753e0 351{
87f48e6a 352 if((sizeof(keymap)/sizeof(int)) <= keycode)
5b0753e0
FB
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*/
365static void cocoa_refresh(DisplayState *ds)
366{
367 //printf("cocoa_refresh \n");
368 NSDate *distantPast;
369 NSEvent *event;
370 NSAutoreleasePool *pool;
3b46e624 371
5b0753e0
FB
372 pool = [ [ NSAutoreleasePool alloc ] init ];
373 distantPast = [ NSDate distantPast ];
3b46e624 374
95219897
PB
375 vga_hw_update();
376
5b0753e0
FB
377 do {
378 event = [ NSApp nextEventMatchingMask:NSAnyEventMask untilDate:distantPast
379 inMode: NSDefaultRunLoopMode dequeue:YES ];
380 if (event != nil) {
381 switch ([event type]) {
87f48e6a 382 case NSFlagsChanged:
5b0753e0
FB
383 {
384 int keycode = cocoa_keycode_to_qemu([event keyCode]);
7c206a75
FB
385
386 if (keycode)
87f48e6a 387 {
7c206a75
FB
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);
95219897 392 } else if (is_graphic_console()) {
7c206a75
FB
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 }
87f48e6a 405 }
7c206a75 406
87f48e6a
FB
407 /* release Mouse grab when pressing ctrl+alt */
408 if (([event modifierFlags] & NSControlKeyMask) && ([event modifierFlags] & NSAlternateKeyMask))
7c206a75 409 {
87f48e6a
FB
410 [window setTitle: @"QEMU"];
411 [NSCursor unhide];
412 CGAssociateMouseAndMouseCursorPosition ( TRUE );
413 grab = 0;
7c206a75 414 }
5b0753e0
FB
415 }
416 break;
7c206a75 417
87f48e6a
FB
418 case NSKeyDown:
419 {
3b46e624
TS
420 int keycode = cocoa_keycode_to_qemu([event keyCode]);
421
87f48e6a
FB
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 }
3b46e624 432
87f48e6a
FB
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);
87f48e6a 439 break;
87f48e6a
FB
440 }
441 } else {
442 /* handle standard key events */
95219897 443 if (is_graphic_console()) {
87f48e6a
FB
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 {
5cbfcd00
FB
449 int keysym = 0;
450
87f48e6a 451 switch([event keyCode]) {
5cbfcd00
FB
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 }
87f48e6a 480 }
5cbfcd00
FB
481 if (keysym)
482 kbd_put_keysym(keysym);
87f48e6a
FB
483 }
484 }
485 }
486 break;
3b46e624 487
5b0753e0 488 case NSKeyUp:
5b0753e0 489 {
3b46e624 490 int keycode = cocoa_keycode_to_qemu([event keyCode]);
95219897 491 if (is_graphic_console()) {
87f48e6a
FB
492 if (keycode & 0x80)
493 kbd_put_keycode(0xe0);
494 kbd_put_keycode(keycode | 0x80); //add 128 to signal release of key
495 }
5b0753e0
FB
496 }
497 break;
3b46e624 498
87f48e6a
FB
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;
3b46e624 508
5b0753e0 509 case NSLeftMouseDown:
87f48e6a
FB
510 if (grab) {
511 int buttons = 0;
3b46e624 512
87f48e6a
FB
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;
3b46e624 524
87f48e6a
FB
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;
3b46e624 539
5b0753e0 540 case NSLeftMouseUp:
87f48e6a
FB
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;
3b46e624 551
5b0753e0 552 case NSRightMouseDown:
87f48e6a
FB
553 if (grab) {
554 int buttons = 0;
3b46e624 555
87f48e6a
FB
556 buttons |= MOUSE_EVENT_RBUTTON;
557 kbd_mouse_event(0, 0, 0, buttons);
558 } else {
559 [NSApp sendEvent: event];
560 }
561 break;
3b46e624 562
87f48e6a
FB
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;
3b46e624 573
5b0753e0 574 case NSRightMouseUp:
87f48e6a
FB
575 if (grab) {
576 kbd_mouse_event(0, 0, 0, 0);
577 } else {
578 [NSApp sendEvent: event];
579 }
580 break;
3b46e624 581
5b0753e0 582 case NSOtherMouseDragged:
87f48e6a
FB
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;
3b46e624 592
87f48e6a
FB
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;
3b46e624 602
87f48e6a
FB
603 case NSOtherMouseUp:
604 if (grab) {
605 kbd_mouse_event(0, 0, 0, 0);
606 } else {
607 [NSApp sendEvent: event];
608 }
609 break;
3b46e624 610
87f48e6a
FB
611 case NSScrollWheel:
612 if (grab) {
613 int dz = [event deltaY];
614 kbd_mouse_event(0, 0, -dz, 0);
615 }
616 break;
3b46e624 617
5b0753e0
FB
618 default: [NSApp sendEvent:event];
619 }
620 }
621 } while(event != nil);
622}
623
624/*
625 ------------------------------------------------------
626 cocoa_cleanup
627 ------------------------------------------------------
628*/
629
5fafdf24 630static void cocoa_cleanup(void)
5b0753e0
FB
631{
632
633}
634
635/*
636 ------------------------------------------------------
637 cocoa_display_init
638 ------------------------------------------------------
639*/
640
641void 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;
3b46e624 646
5b0753e0 647 cocoa_resize(ds, 640, 400);
3b46e624 648
5b0753e0
FB
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*/
665static void QZ_SetPortAlphaOpaque ()
3b46e624 666{
5b0753e0
FB
667 /* Assume 32 bit if( bpp == 32 )*/
668 if ( 1 ) {
3b46e624 669
5b0753e0
FB
670 uint32_t *pixels = (uint32_t*) current_ds.data;
671 uint32_t rowPixels = current_ds.linesize / 4;
672 uint32_t i, j;
3b46e624 673
5b0753e0
FB
674 for (i = 0; i < current_ds.height; i++)
675 for (j = 0; j < current_ds.width; j++) {
3b46e624 676
5b0753e0
FB
677 pixels[ (i * rowPixels) + j ] |= 0xFF000000;
678 }
679 }
680}
681
682@implementation QemuWindow
683- (void)miniaturize:(id)sender
684{
3b46e624 685
5b0753e0
FB
686 /* make the alpha channel opaque so anim won't have holes in it */
687 QZ_SetPortAlphaOpaque ();
3b46e624 688
5b0753e0 689 [ super miniaturize:sender ];
3b46e624 690
5b0753e0
FB
691}
692- (void)display
3b46e624 693{
5fafdf24 694 /*
5b0753e0 695 This method fires just before the window deminaturizes from the Dock.
3b46e624 696
5b0753e0 697 We'll save the current visible surface, let the window manager redraw any
5fafdf24 698 UI elements, and restore the SDL surface. This way, no expose event
5b0753e0
FB
699 is required, and the deminiaturize works perfectly.
700 */
3b46e624 701
5b0753e0
FB
702 /* make sure pixels are fully opaque */
703 QZ_SetPortAlphaOpaque ();
3b46e624 704
5b0753e0
FB
705 /* save current visible SDL surface */
706 [ self cacheImageInRect:[ qd_view frame ] ];
3b46e624 707
5b0753e0
FB
708 /* let the window manager redraw controls, border, etc */
709 [ super display ];
3b46e624 710
5b0753e0
FB
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{
5a246934
FB
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)
5b0753e0
FB
745 {
746 NSOpenPanel *op = [[NSOpenPanel alloc] init];
3b46e624 747
5b0753e0 748 cocoa_resize(&current_ds, 640, 400);
3b46e624 749
5b0753e0 750 [op setPrompt:@"Boot image"];
3b46e624 751
5b0753e0 752 [op setMessage:@"Select the disk image you want to boot.\n\nHit the \"Cancel\" button to quit"];
3b46e624 753
7a674b13 754 [op beginSheetForDirectory:nil file:nil types:[NSArray arrayWithObjects:@"img",@"iso",@"dmg",@"qcow",@"cow",@"cloop",@"vmdk",nil]
5b0753e0
FB
755 modalForWindow:window modalDelegate:self
756 didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:) contextInfo:NULL];
757 }
5a246934
FB
758 else
759 {
760 /* or Launch Qemu, with the global args */
761 [self startEmulationWithArgc:gArgc argv:gArgv];
762 }
5b0753e0
FB
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 }
3b46e624 779
5b0753e0
FB
780 if(returnCode == NSOKButton)
781 {
782 char *bin = "qemu";
783 char *img = (char*)[ [ sheet filename ] cString];
3b46e624 784
5b0753e0 785 char **argv = (char**)malloc( sizeof(char*)*3 );
3b46e624 786
5b0753e0
FB
787 asprintf(&argv[0], "%s", bin);
788 asprintf(&argv[1], "-hda");
789 asprintf(&argv[2], "%s", img);
3b46e624 790
5b0753e0 791 printf("Using argc %d argv %s -hda %s\n", 3, bin, img);
3b46e624 792
5b0753e0
FB
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 */
814typedef struct CPSProcessSerNum
815{
816 UInt32 lo;
817 UInt32 hi;
818} CPSProcessSerNum;
819
820extern OSErr CPSGetCurrentProcess( CPSProcessSerNum *psn);
821extern OSErr CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5);
822extern OSErr CPSSetFrontProcess( CPSProcessSerNum *psn);
823
824/* Menu Creation */
825static void setApplicationMenu(void)
826{
827 /* warning: this code is very odd */
828 NSMenu *appleMenu;
829 NSMenuItem *menuItem;
830 NSString *title;
831 NSString *appName;
3b46e624 832
5b0753e0
FB
833 appName = @"Qemu";
834 appleMenu = [[NSMenu alloc] initWithTitle:@""];
3b46e624 835
5b0753e0
FB
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
3b46e624 855
5b0753e0
FB
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 */
870static void setupWindowMenu(void)
871{
872 NSMenu *windowMenu;
873 NSMenuItem *windowMenuItem;
874 NSMenuItem *menuItem;
875
876 windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
3b46e624 877
5b0753e0
FB
878 /* "Minimize" item */
879 menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"];
880 [windowMenu addItem:menuItem];
881 [menuItem release];
3b46e624 882
5b0753e0
FB
883 /* Put menu into the menubar */
884 windowMenuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""];
885 [windowMenuItem setSubmenu:windowMenu];
886 [[NSApp mainMenu] addItem:windowMenuItem];
3b46e624 887
5b0753e0
FB
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];
5b0753e0
FB
894}
895
cae41b10 896static void CustomApplicationMain(void)
5b0753e0
FB
897{
898 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
899 QemuCocoaGUIController *gui_controller;
900 CPSProcessSerNum PSN;
3b46e624 901
5b0753e0 902 [NSApplication sharedApplication];
3b46e624 903
5b0753e0
FB
904 if (!CPSGetCurrentProcess(&PSN))
905 if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103))
906 if (!CPSSetFrontProcess(&PSN))
907 [NSApplication sharedApplication];
3b46e624 908
5b0753e0
FB
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];
3b46e624 917
5b0753e0
FB
918 /* Start the main event loop */
919 [NSApp run];
3b46e624 920
5b0753e0
FB
921 [gui_controller release];
922 [pool release];
923}
924
925/* Real main of qemu-cocoa */
926int main(int argc, char **argv)
927{
928 gArgc = argc;
929 gArgv = argv;
cae41b10
FB
930
931 CustomApplicationMain();
932
5b0753e0
FB
933 return 0;
934}