]>
Commit | Line | Data |
---|---|---|
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 |
44 | NSWindow *window = NULL; |
45 | NSQuickDrawView *qd_view = NULL; | |
46 | ||
47 | ||
48 | int gArgc; | |
49 | char **gArgv; | |
50 | DisplayState current_ds; | |
51 | ||
87f48e6a FB |
52 | int grab = 0; |
53 | int modifiers_state[256]; | |
54 | ||
5b0753e0 FB |
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); | |
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 | */ | |
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; | |
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 | 184 | int 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 | 350 | int 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 | */ | |
365 | static 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 | 630 | static void cocoa_cleanup(void) |
5b0753e0 FB |
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; | |
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 | */ | |
665 | static 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(¤t_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 */ | |
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; | |
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 */ | |
870 | static 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 | 896 | static 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 */ | |
926 | int main(int argc, char **argv) | |
927 | { | |
928 | gArgc = argc; | |
929 | gArgv = argv; | |
cae41b10 FB |
930 | |
931 | CustomApplicationMain(); | |
932 | ||
5b0753e0 FB |
933 | return 0; |
934 | } |