]> git.proxmox.com Git - mirror_qemu.git/blame - cocoa.m
linux-user readlinkat() syscall, by Thayne Harbaugh.
[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
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);
3b46e624 87
5b0753e0
FB
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;
3b46e624 105
5b0753e0 106 //printf("resizing to %d %d\n", w, h);
3b46e624 107
5b0753e0
FB
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 }
3b46e624 122
5b0753e0
FB
123 if(qd_view)
124 [qd_view release];
3b46e624 125
5b0753e0 126 qd_view = [ [ NSQuickDrawView alloc ] initWithFrame:contentRect ];
3b46e624 127
5b0753e0
FB
128 if(!qd_view)
129 {
130 fprintf(stderr, "(cocoa) can't create qd_view\n");
131 exit(1);
132 }
3b46e624 133
5b0753e0
FB
134 [ window setAcceptsMouseMovedEvents:YES ];
135 [ window setTitle:@"Qemu" ];
136 [ window setReleasedWhenClosed:NO ];
3b46e624 137
5b0753e0
FB
138 /* Set screen to black */
139 [ window setBackgroundColor: [NSColor blackColor] ];
3b46e624 140
5b0753e0
FB
141 /* set window position */
142 [ window center ];
3b46e624 143
5b0753e0
FB
144 [ qd_view setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable ];
145 [ [ window contentView ] addSubview:qd_view ];
146 [ qd_view release ];
147 [ window makeKeyAndOrderFront:nil ];
3b46e624 148
5b0753e0
FB
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 ] );
5fafdf24
TS
154 {
155 int vOffset = [ window frame ].size.height -
5b0753e0 156 [ qd_view frame ].size.height - [ qd_view frame ].origin.y;
3b46e624 157
5b0753e0 158 int hOffset = [ qd_view frame ].origin.x;
3b46e624 159
5b0753e0
FB
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;
b29169d2
BS
167#ifdef __LITTLE_ENDIAN__
168 ds->bgr = 1;
169#else
170 ds->bgr = 0;
171#endif
172
5b0753e0
FB
173 current_ds = *ds;
174}
175
176/*
177 ------------------------------------------------------
178 keymap conversion
179 ------------------------------------------------------
180*/
181
87f48e6a 182int keymap[] =
5b0753e0 183{
87f48e6a
FB
184// SdlI macI macH SdlH 104xtH 104xtC sdl
185 30, // 0 0x00 0x1e A QZ_a
186 31, // 1 0x01 0x1f S QZ_s
187 32, // 2 0x02 0x20 D QZ_d
188 33, // 3 0x03 0x21 F QZ_f
189 35, // 4 0x04 0x23 H QZ_h
190 34, // 5 0x05 0x22 G QZ_g
191 44, // 6 0x06 0x2c Z QZ_z
192 45, // 7 0x07 0x2d X QZ_x
193 46, // 8 0x08 0x2e C QZ_c
194 47, // 9 0x09 0x2f V QZ_v
195 0, // 10 0x0A Undefined
196 48, // 11 0x0B 0x30 B QZ_b
197 16, // 12 0x0C 0x10 Q QZ_q
198 17, // 13 0x0D 0x11 W QZ_w
199 18, // 14 0x0E 0x12 E QZ_e
200 19, // 15 0x0F 0x13 R QZ_r
201 21, // 16 0x10 0x15 Y QZ_y
202 20, // 17 0x11 0x14 T QZ_t
203 2, // 18 0x12 0x02 1 QZ_1
204 3, // 19 0x13 0x03 2 QZ_2
205 4, // 20 0x14 0x04 3 QZ_3
206 5, // 21 0x15 0x05 4 QZ_4
207 7, // 22 0x16 0x07 6 QZ_6
208 6, // 23 0x17 0x06 5 QZ_5
209 13, // 24 0x18 0x0d = QZ_EQUALS
210 10, // 25 0x19 0x0a 9 QZ_9
211 8, // 26 0x1A 0x08 7 QZ_7
212 12, // 27 0x1B 0x0c - QZ_MINUS
213 9, // 28 0x1C 0x09 8 QZ_8
214 11, // 29 0x1D 0x0b 0 QZ_0
215 27, // 30 0x1E 0x1b ] QZ_RIGHTBRACKET
216 24, // 31 0x1F 0x18 O QZ_o
217 22, // 32 0x20 0x16 U QZ_u
218 26, // 33 0x21 0x1a [ QZ_LEFTBRACKET
219 23, // 34 0x22 0x17 I QZ_i
220 25, // 35 0x23 0x19 P QZ_p
221 28, // 36 0x24 0x1c ENTER QZ_RETURN
222 38, // 37 0x25 0x26 L QZ_l
223 36, // 38 0x26 0x24 J QZ_j
224 40, // 39 0x27 0x28 ' QZ_QUOTE
225 37, // 40 0x28 0x25 K QZ_k
226 39, // 41 0x29 0x27 ; QZ_SEMICOLON
227 43, // 42 0x2A 0x2b \ QZ_BACKSLASH
228 51, // 43 0x2B 0x33 , QZ_COMMA
229 53, // 44 0x2C 0x35 / QZ_SLASH
230 49, // 45 0x2D 0x31 N QZ_n
231 50, // 46 0x2E 0x32 M QZ_m
232 52, // 47 0x2F 0x34 . QZ_PERIOD
233 15, // 48 0x30 0x0f TAB QZ_TAB
234 57, // 49 0x31 0x39 SPACE QZ_SPACE
235 41, // 50 0x32 0x29 ` QZ_BACKQUOTE
236 14, // 51 0x33 0x0e BKSP QZ_BACKSPACE
237 0, // 52 0x34 Undefined
238 1, // 53 0x35 0x01 ESC QZ_ESCAPE
239 0, // 54 0x36 QZ_RMETA
240 0, // 55 0x37 QZ_LMETA
241 42, // 56 0x38 0x2a L SHFT QZ_LSHIFT
242 58, // 57 0x39 0x3a CAPS QZ_CAPSLOCK
243 56, // 58 0x3A 0x38 L ALT QZ_LALT
244 29, // 59 0x3B 0x1d L CTRL QZ_LCTRL
245 54, // 60 0x3C 0x36 R SHFT QZ_RSHIFT
246 184,// 61 0x3D 0xb8 E0,38 R ALT QZ_RALT
247 157,// 62 0x3E 0x9d E0,1D R CTRL QZ_RCTRL
248 0, // 63 0x3F Undefined
249 0, // 64 0x40 Undefined
250 0, // 65 0x41 Undefined
251 0, // 66 0x42 Undefined
252 55, // 67 0x43 0x37 KP * QZ_KP_MULTIPLY
253 0, // 68 0x44 Undefined
254 78, // 69 0x45 0x4e KP + QZ_KP_PLUS
255 0, // 70 0x46 Undefined
256 69, // 71 0x47 0x45 NUM QZ_NUMLOCK
257 0, // 72 0x48 Undefined
258 0, // 73 0x49 Undefined
259 0, // 74 0x4A Undefined
260 181,// 75 0x4B 0xb5 E0,35 KP / QZ_KP_DIVIDE
261 152,// 76 0x4C 0x9c E0,1C KP EN QZ_KP_ENTER
262 0, // 77 0x4D undefined
263 74, // 78 0x4E 0x4a KP - QZ_KP_MINUS
264 0, // 79 0x4F Undefined
265 0, // 80 0x50 Undefined
266 0, // 81 0x51 QZ_KP_EQUALS
267 82, // 82 0x52 0x52 KP 0 QZ_KP0
268 79, // 83 0x53 0x4f KP 1 QZ_KP1
269 80, // 84 0x54 0x50 KP 2 QZ_KP2
270 81, // 85 0x55 0x51 KP 3 QZ_KP3
271 75, // 86 0x56 0x4b KP 4 QZ_KP4
272 76, // 87 0x57 0x4c KP 5 QZ_KP5
273 77, // 88 0x58 0x4d KP 6 QZ_KP6
274 71, // 89 0x59 0x47 KP 7 QZ_KP7
275 0, // 90 0x5A Undefined
276 72, // 91 0x5B 0x48 KP 8 QZ_KP8
277 73, // 92 0x5C 0x49 KP 9 QZ_KP9
278 0, // 93 0x5D Undefined
279 0, // 94 0x5E Undefined
280 0, // 95 0x5F Undefined
281 63, // 96 0x60 0x3f F5 QZ_F5
282 64, // 97 0x61 0x40 F6 QZ_F6
283 65, // 98 0x62 0x41 F7 QZ_F7
284 61, // 99 0x63 0x3d F3 QZ_F3
285 66, // 100 0x64 0x42 F8 QZ_F8
286 67, // 101 0x65 0x43 F9 QZ_F9
287 0, // 102 0x66 Undefined
288 87, // 103 0x67 0x57 F11 QZ_F11
289 0, // 104 0x68 Undefined
290 183,// 105 0x69 0xb7 QZ_PRINT
291 0, // 106 0x6A Undefined
292 70, // 107 0x6B 0x46 SCROLL QZ_SCROLLOCK
293 0, // 108 0x6C Undefined
294 68, // 109 0x6D 0x44 F10 QZ_F10
295 0, // 110 0x6E Undefined
296 88, // 111 0x6F 0x58 F12 QZ_F12
297 0, // 112 0x70 Undefined
298 110,// 113 0x71 0x0 QZ_PAUSE
299 210,// 114 0x72 0xd2 E0,52 INSERT QZ_INSERT
300 199,// 115 0x73 0xc7 E0,47 HOME QZ_HOME
301 201,// 116 0x74 0xc9 E0,49 PG UP QZ_PAGEUP
302 211,// 117 0x75 0xd3 E0,53 DELETE QZ_DELETE
303 62, // 118 0x76 0x3e F4 QZ_F4
304 207,// 119 0x77 0xcf E0,4f END QZ_END
305 60, // 120 0x78 0x3c F2 QZ_F2
306 209,// 121 0x79 0xd1 E0,51 PG DN QZ_PAGEDOWN
307 59, // 122 0x7A 0x3b F1 QZ_F1
308 203,// 123 0x7B 0xcb e0,4B L ARROW QZ_LEFT
309 205,// 124 0x7C 0xcd e0,4D R ARROW QZ_RIGHT
310 208,// 125 0x7D 0xd0 E0,50 D ARROW QZ_DOWN
311 200,// 126 0x7E 0xc8 E0,48 U ARROW QZ_UP
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 */
3b46e624 313
87f48e6a
FB
314/* Aditional 104 Key XP-Keyboard Scancodes from http://www.computer-engineering.org/ps2keyboard/scancodes1.html */
315/*
3b46e624
TS
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
5fafdf24 333 174 // 0xae E0, 2E Volume Down
3b46e624
TS
334 237 // 0xed E0, 6D Media Select
335 236 // 0xec E0, 6C E-Mail
336 161 // 0xa1 E0, 21 Calculator
5fafdf24 337 235 // 0xeb E0, 6B My Computer
3b46e624
TS
338 229 // 0xe5 E0, 65 WWW Search
339 178 // 0xb2 E0, 32 WWW Home
340 234 // 0xea E0, 6A WWW Back
5fafdf24 341 233 // 0xe9 E0, 69 WWW Forward
3b46e624 342 232 // 0xe8 E0, 68 WWW Stop
5fafdf24 343 231 // 0xe7 E0, 67 WWW Refresh
3b46e624 344 230 // 0xe6 E0, 66 WWW Favorites
87f48e6a 345*/
5b0753e0
FB
346};
347
87f48e6a 348int cocoa_keycode_to_qemu(int keycode)
5b0753e0 349{
87f48e6a 350 if((sizeof(keymap)/sizeof(int)) <= keycode)
5b0753e0
FB
351 {
352 printf("(cocoa) warning unknow keycode 0x%x\n", keycode);
353 return 0;
354 }
355 return keymap[keycode];
356}
357
358/*
359 ------------------------------------------------------
360 cocoa_refresh
361 ------------------------------------------------------
362*/
363static void cocoa_refresh(DisplayState *ds)
364{
365 //printf("cocoa_refresh \n");
366 NSDate *distantPast;
367 NSEvent *event;
368 NSAutoreleasePool *pool;
3b46e624 369
5b0753e0
FB
370 pool = [ [ NSAutoreleasePool alloc ] init ];
371 distantPast = [ NSDate distantPast ];
3b46e624 372
95219897
PB
373 vga_hw_update();
374
5b0753e0
FB
375 do {
376 event = [ NSApp nextEventMatchingMask:NSAnyEventMask untilDate:distantPast
377 inMode: NSDefaultRunLoopMode dequeue:YES ];
378 if (event != nil) {
379 switch ([event type]) {
87f48e6a 380 case NSFlagsChanged:
5b0753e0
FB
381 {
382 int keycode = cocoa_keycode_to_qemu([event keyCode]);
7c206a75
FB
383
384 if (keycode)
87f48e6a 385 {
7c206a75
FB
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);
95219897 390 } else if (is_graphic_console()) {
7c206a75
FB
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 }
87f48e6a 403 }
7c206a75 404
87f48e6a
FB
405 /* release Mouse grab when pressing ctrl+alt */
406 if (([event modifierFlags] & NSControlKeyMask) && ([event modifierFlags] & NSAlternateKeyMask))
7c206a75 407 {
87f48e6a
FB
408 [window setTitle: @"QEMU"];
409 [NSCursor unhide];
410 CGAssociateMouseAndMouseCursorPosition ( TRUE );
411 grab = 0;
7c206a75 412 }
5b0753e0
FB
413 }
414 break;
7c206a75 415
87f48e6a
FB
416 case NSKeyDown:
417 {
3b46e624
TS
418 int keycode = cocoa_keycode_to_qemu([event keyCode]);
419
87f48e6a
FB
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 }
3b46e624 430
87f48e6a
FB
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);
87f48e6a 437 break;
87f48e6a
FB
438 }
439 } else {
440 /* handle standard key events */
95219897 441 if (is_graphic_console()) {
87f48e6a
FB
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 {
5cbfcd00
FB
447 int keysym = 0;
448
87f48e6a 449 switch([event keyCode]) {
5cbfcd00
FB
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 }
87f48e6a 478 }
5cbfcd00
FB
479 if (keysym)
480 kbd_put_keysym(keysym);
87f48e6a
FB
481 }
482 }
483 }
484 break;
3b46e624 485
5b0753e0 486 case NSKeyUp:
5b0753e0 487 {
3b46e624 488 int keycode = cocoa_keycode_to_qemu([event keyCode]);
95219897 489 if (is_graphic_console()) {
87f48e6a
FB
490 if (keycode & 0x80)
491 kbd_put_keycode(0xe0);
492 kbd_put_keycode(keycode | 0x80); //add 128 to signal release of key
493 }
5b0753e0
FB
494 }
495 break;
3b46e624 496
87f48e6a
FB
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;
3b46e624 506
5b0753e0 507 case NSLeftMouseDown:
87f48e6a
FB
508 if (grab) {
509 int buttons = 0;
3b46e624 510
87f48e6a
FB
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;
3b46e624 522
87f48e6a
FB
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;
3b46e624 537
5b0753e0 538 case NSLeftMouseUp:
87f48e6a
FB
539 if (grab) {
540 kbd_mouse_event(0, 0, 0, 0);
541 } else {
542 [window setTitle: @"QEMU (Press ctrl + alt to release Mouse)"];
543 [NSCursor hide];
544 CGAssociateMouseAndMouseCursorPosition ( FALSE );
545 grab = 1;
546 //[NSApp sendEvent: event];
547 }
548 break;
3b46e624 549
5b0753e0 550 case NSRightMouseDown:
87f48e6a
FB
551 if (grab) {
552 int buttons = 0;
3b46e624 553
87f48e6a
FB
554 buttons |= MOUSE_EVENT_RBUTTON;
555 kbd_mouse_event(0, 0, 0, buttons);
556 } else {
557 [NSApp sendEvent: event];
558 }
559 break;
3b46e624 560
87f48e6a
FB
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;
3b46e624 571
5b0753e0 572 case NSRightMouseUp:
87f48e6a
FB
573 if (grab) {
574 kbd_mouse_event(0, 0, 0, 0);
575 } else {
576 [NSApp sendEvent: event];
577 }
578 break;
3b46e624 579
5b0753e0 580 case NSOtherMouseDragged:
87f48e6a
FB
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;
3b46e624 590
87f48e6a
FB
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;
3b46e624 600
87f48e6a
FB
601 case NSOtherMouseUp:
602 if (grab) {
603 kbd_mouse_event(0, 0, 0, 0);
604 } else {
605 [NSApp sendEvent: event];
606 }
607 break;
3b46e624 608
87f48e6a
FB
609 case NSScrollWheel:
610 if (grab) {
611 int dz = [event deltaY];
612 kbd_mouse_event(0, 0, -dz, 0);
613 }
614 break;
3b46e624 615
5b0753e0
FB
616 default: [NSApp sendEvent:event];
617 }
618 }
619 } while(event != nil);
620}
621
622/*
623 ------------------------------------------------------
624 cocoa_cleanup
625 ------------------------------------------------------
626*/
627
5fafdf24 628static void cocoa_cleanup(void)
5b0753e0
FB
629{
630
631}
632
633/*
634 ------------------------------------------------------
635 cocoa_display_init
636 ------------------------------------------------------
637*/
638
639void 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;
3b46e624 644
5b0753e0 645 cocoa_resize(ds, 640, 400);
3b46e624 646
5b0753e0
FB
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*/
663static void QZ_SetPortAlphaOpaque ()
3b46e624 664{
5b0753e0
FB
665 /* Assume 32 bit if( bpp == 32 )*/
666 if ( 1 ) {
3b46e624 667
5b0753e0
FB
668 uint32_t *pixels = (uint32_t*) current_ds.data;
669 uint32_t rowPixels = current_ds.linesize / 4;
670 uint32_t i, j;
3b46e624 671
5b0753e0
FB
672 for (i = 0; i < current_ds.height; i++)
673 for (j = 0; j < current_ds.width; j++) {
3b46e624 674
5b0753e0
FB
675 pixels[ (i * rowPixels) + j ] |= 0xFF000000;
676 }
677 }
678}
679
680@implementation QemuWindow
681- (void)miniaturize:(id)sender
682{
3b46e624 683
5b0753e0
FB
684 /* make the alpha channel opaque so anim won't have holes in it */
685 QZ_SetPortAlphaOpaque ();
3b46e624 686
5b0753e0 687 [ super miniaturize:sender ];
3b46e624 688
5b0753e0
FB
689}
690- (void)display
3b46e624 691{
5fafdf24 692 /*
5b0753e0 693 This method fires just before the window deminaturizes from the Dock.
3b46e624 694
5b0753e0 695 We'll save the current visible surface, let the window manager redraw any
5fafdf24 696 UI elements, and restore the SDL surface. This way, no expose event
5b0753e0
FB
697 is required, and the deminiaturize works perfectly.
698 */
3b46e624 699
5b0753e0
FB
700 /* make sure pixels are fully opaque */
701 QZ_SetPortAlphaOpaque ();
3b46e624 702
5b0753e0
FB
703 /* save current visible SDL surface */
704 [ self cacheImageInRect:[ qd_view frame ] ];
3b46e624 705
5b0753e0
FB
706 /* let the window manager redraw controls, border, etc */
707 [ super display ];
3b46e624 708
5b0753e0
FB
709 /* restore visible SDL surface */
710 [ self restoreCachedImage ];
711}
712
713@end
714
715
716/*
717 ------------------------------------------------------
718 QemuCocoaGUIController
719 NSApp's delegate - indeed main object
720 ------------------------------------------------------
721*/
722
723@interface QemuCocoaGUIController : NSObject
724{
725}
726- (void)applicationDidFinishLaunching: (NSNotification *) note;
727- (void)applicationWillTerminate:(NSNotification *)aNotification;
728
729- (void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo;
730
731- (void)startEmulationWithArgc:(int)argc argv:(char**)argv;
732@end
733
734@implementation QemuCocoaGUIController
735/* Called when the internal event loop has just started running */
736- (void)applicationDidFinishLaunching: (NSNotification *) note
737{
5a246934
FB
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)
5b0753e0
FB
743 {
744 NSOpenPanel *op = [[NSOpenPanel alloc] init];
3b46e624 745
5b0753e0 746 cocoa_resize(&current_ds, 640, 400);
3b46e624 747
5b0753e0 748 [op setPrompt:@"Boot image"];
3b46e624 749
5b0753e0 750 [op setMessage:@"Select the disk image you want to boot.\n\nHit the \"Cancel\" button to quit"];
3b46e624 751
7a674b13 752 [op beginSheetForDirectory:nil file:nil types:[NSArray arrayWithObjects:@"img",@"iso",@"dmg",@"qcow",@"cow",@"cloop",@"vmdk",nil]
5b0753e0
FB
753 modalForWindow:window modalDelegate:self
754 didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:) contextInfo:NULL];
755 }
5a246934
FB
756 else
757 {
758 /* or Launch Qemu, with the global args */
759 [self startEmulationWithArgc:gArgc argv:gArgv];
760 }
5b0753e0
FB
761}
762
763- (void)applicationWillTerminate:(NSNotification *)aNotification
764{
765 printf("Application will terminate\n");
766 qemu_system_shutdown_request();
767 /* In order to avoid a crash */
768 exit(0);
769}
770
771- (void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
772{
773 if(returnCode == NSCancelButton)
774 {
775 exit(0);
776 }
3b46e624 777
5b0753e0
FB
778 if(returnCode == NSOKButton)
779 {
780 char *bin = "qemu";
781 char *img = (char*)[ [ sheet filename ] cString];
3b46e624 782
5b0753e0 783 char **argv = (char**)malloc( sizeof(char*)*3 );
3b46e624 784
5b0753e0
FB
785 asprintf(&argv[0], "%s", bin);
786 asprintf(&argv[1], "-hda");
787 asprintf(&argv[2], "%s", img);
3b46e624 788
5b0753e0 789 printf("Using argc %d argv %s -hda %s\n", 3, bin, img);
3b46e624 790
5b0753e0
FB
791 [self startEmulationWithArgc:3 argv:(char**)argv];
792 }
793}
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);
802}
803@end
804
805/*
806 ------------------------------------------------------
807 Application Creation
808 ------------------------------------------------------
809*/
810
811/* Dock Connection */
812typedef struct CPSProcessSerNum
813{
814 UInt32 lo;
815 UInt32 hi;
816} CPSProcessSerNum;
817
818extern OSErr CPSGetCurrentProcess( CPSProcessSerNum *psn);
819extern OSErr CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5);
820extern OSErr CPSSetFrontProcess( CPSProcessSerNum *psn);
821
822/* Menu Creation */
823static void setApplicationMenu(void)
824{
825 /* warning: this code is very odd */
826 NSMenu *appleMenu;
827 NSMenuItem *menuItem;
828 NSString *title;
829 NSString *appName;
3b46e624 830
5b0753e0
FB
831 appName = @"Qemu";
832 appleMenu = [[NSMenu alloc] initWithTitle:@""];
3b46e624 833
5b0753e0
FB
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
3b46e624 853
5b0753e0
FB
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 */
868static void setupWindowMenu(void)
869{
870 NSMenu *windowMenu;
871 NSMenuItem *windowMenuItem;
872 NSMenuItem *menuItem;
873
874 windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
3b46e624 875
5b0753e0
FB
876 /* "Minimize" item */
877 menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"];
878 [windowMenu addItem:menuItem];
879 [menuItem release];
3b46e624 880
5b0753e0
FB
881 /* Put menu into the menubar */
882 windowMenuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""];
883 [windowMenuItem setSubmenu:windowMenu];
884 [[NSApp mainMenu] addItem:windowMenuItem];
3b46e624 885
5b0753e0
FB
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];
5b0753e0
FB
892}
893
cae41b10 894static void CustomApplicationMain(void)
5b0753e0
FB
895{
896 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
897 QemuCocoaGUIController *gui_controller;
898 CPSProcessSerNum PSN;
3b46e624 899
5b0753e0 900 [NSApplication sharedApplication];
3b46e624 901
5b0753e0
FB
902 if (!CPSGetCurrentProcess(&PSN))
903 if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103))
904 if (!CPSSetFrontProcess(&PSN))
905 [NSApplication sharedApplication];
3b46e624 906
5b0753e0
FB
907 /* Set up the menubar */
908 [NSApp setMainMenu:[[NSMenu alloc] init]];
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];
3b46e624 915
5b0753e0
FB
916 /* Start the main event loop */
917 [NSApp run];
3b46e624 918
5b0753e0
FB
919 [gui_controller release];
920 [pool release];
921}
922
923/* Real main of qemu-cocoa */
924int main(int argc, char **argv)
925{
926 gArgc = argc;
927 gArgv = argv;
cae41b10
FB
928
929 CustomApplicationMain();
930
5b0753e0
FB
931 return 0;
932}