root / cocoa.m @ 8f40c388
History | View | Annotate | Download (33.7 kB)
1 |
/* |
---|---|
2 |
* QEMU Cocoa display driver |
3 |
* |
4 |
* Copyright (c) 2005 Pierre d'Herbemont |
5 |
* many code/inspiration from SDL 1.2 code (LGPL) |
6 |
* |
7 |
* Permission is hereby granted, free of charge, to any person obtaining a copy |
8 |
* of this software and associated documentation files (the "Software"), to deal |
9 |
* in the Software without restriction, including without limitation the rights |
10 |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
11 |
* copies of the Software, and to permit persons to whom the Software is |
12 |
* furnished to do so, subject to the following conditions: |
13 |
* |
14 |
* The above copyright notice and this permission notice shall be included in |
15 |
* all copies or substantial portions of the Software. |
16 |
* |
17 |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
18 |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
19 |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
20 |
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
21 |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
22 |
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
23 |
* THE SOFTWARE. |
24 |
*/ |
25 |
/* |
26 |
Todo : x miniaturize window |
27 |
x center the window |
28 |
- save window position |
29 |
- handle keyboard event |
30 |
- handle mouse event |
31 |
- non 32 bpp support |
32 |
- full screen |
33 |
- mouse focus |
34 |
x simple graphical prompt to demo |
35 |
- better graphical prompt |
36 |
*/ |
37 |
|
38 |
#import <Cocoa/Cocoa.h> |
39 |
|
40 |
#include "vl.h" |
41 |
|
42 |
NSWindow *window = NULL; |
43 |
NSQuickDrawView *qd_view = NULL; |
44 |
|
45 |
|
46 |
int gArgc; |
47 |
char **gArgv; |
48 |
DisplayState current_ds; |
49 |
|
50 |
int grab = 0; |
51 |
int modifiers_state[256]; |
52 |
|
53 |
/* main defined in qemu/vl.c */ |
54 |
int 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 |
*/ |
73 |
static 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 |
*/ |
99 |
static 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 |
|
177 |
int keymap[] = |
178 |
{ |
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 |
*/ |
341 |
}; |
342 |
|
343 |
int cocoa_keycode_to_qemu(int keycode) |
344 |
{ |
345 |
if((sizeof(keymap)/sizeof(int)) <= keycode) |
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 |
*/ |
358 |
static void cocoa_refresh(DisplayState *ds) |
359 |
{ |
360 |
//printf("cocoa_refresh \n"); |
361 |
NSDate *distantPast; |
362 |
NSEvent *event; |
363 |
NSAutoreleasePool *pool; |
364 |
|
365 |
pool = [ [ NSAutoreleasePool alloc ] init ]; |
366 |
distantPast = [ NSDate distantPast ]; |
367 |
|
368 |
vga_hw_update(); |
369 |
|
370 |
do { |
371 |
event = [ NSApp nextEventMatchingMask:NSAnyEventMask untilDate:distantPast |
372 |
inMode: NSDefaultRunLoopMode dequeue:YES ]; |
373 |
if (event != nil) { |
374 |
switch ([event type]) { |
375 |
case NSFlagsChanged: |
376 |
{ |
377 |
int keycode = cocoa_keycode_to_qemu([event keyCode]); |
378 |
|
379 |
if (keycode) |
380 |
{ |
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_graphic_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 |
} |
398 |
} |
399 |
|
400 |
/* release Mouse grab when pressing ctrl+alt */ |
401 |
if (([event modifierFlags] & NSControlKeyMask) && ([event modifierFlags] & NSAlternateKeyMask)) |
402 |
{ |
403 |
[window setTitle: @"QEMU"]; |
404 |
[NSCursor unhide]; |
405 |
CGAssociateMouseAndMouseCursorPosition ( TRUE ); |
406 |
grab = 0; |
407 |
} |
408 |
} |
409 |
break; |
410 |
|
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 |
break; |
433 |
} |
434 |
} else { |
435 |
/* handle standard key events */ |
436 |
if (is_graphic_console()) { |
437 |
if (keycode & 0x80) //check bit for e0 in front |
438 |
kbd_put_keycode(0xe0); |
439 |
kbd_put_keycode(keycode & 0x7f); //remove e0 bit in front |
440 |
/* handle monitor key events */ |
441 |
} else { |
442 |
int keysym = 0; |
443 |
|
444 |
switch([event keyCode]) { |
445 |
case 115: |
446 |
keysym = QEMU_KEY_HOME; |
447 |
break; |
448 |
case 117: |
449 |
keysym = QEMU_KEY_DELETE; |
450 |
break; |
451 |
case 119: |
452 |
keysym = QEMU_KEY_END; |
453 |
break; |
454 |
case 123: |
455 |
keysym = QEMU_KEY_LEFT; |
456 |
break; |
457 |
case 124: |
458 |
keysym = QEMU_KEY_RIGHT; |
459 |
break; |
460 |
case 125: |
461 |
keysym = QEMU_KEY_DOWN; |
462 |
break; |
463 |
case 126: |
464 |
keysym = QEMU_KEY_UP; |
465 |
break; |
466 |
default: |
467 |
{ |
468 |
NSString *ks = [event characters]; |
469 |
|
470 |
if ([ks length] > 0) |
471 |
keysym = [ks characterAtIndex:0]; |
472 |
} |
473 |
} |
474 |
if (keysym) |
475 |
kbd_put_keysym(keysym); |
476 |
} |
477 |
} |
478 |
} |
479 |
break; |
480 |
|
481 |
case NSKeyUp: |
482 |
{ |
483 |
int keycode = cocoa_keycode_to_qemu([event keyCode]); |
484 |
if (is_graphic_console()) { |
485 |
if (keycode & 0x80) |
486 |
kbd_put_keycode(0xe0); |
487 |
kbd_put_keycode(keycode | 0x80); //add 128 to signal release of key |
488 |
} |
489 |
} |
490 |
break; |
491 |
|
492 |
case NSMouseMoved: |
493 |
if (grab) { |
494 |
int dx = [event deltaX]; |
495 |
int dy = [event deltaY]; |
496 |
int dz = [event deltaZ]; |
497 |
int buttons = 0; |
498 |
kbd_mouse_event(dx, dy, dz, buttons); |
499 |
} |
500 |
break; |
501 |
|
502 |
case NSLeftMouseDown: |
503 |
if (grab) { |
504 |
int buttons = 0; |
505 |
|
506 |
/* leftclick+command simulates rightclick */ |
507 |
if ([event modifierFlags] & NSCommandKeyMask) { |
508 |
buttons |= MOUSE_EVENT_RBUTTON; |
509 |
} else { |
510 |
buttons |= MOUSE_EVENT_LBUTTON; |
511 |
} |
512 |
kbd_mouse_event(0, 0, 0, buttons); |
513 |
} else { |
514 |
[NSApp sendEvent: event]; |
515 |
} |
516 |
break; |
517 |
|
518 |
case NSLeftMouseDragged: |
519 |
if (grab) { |
520 |
int dx = [event deltaX]; |
521 |
int dy = [event deltaY]; |
522 |
int dz = [event deltaZ]; |
523 |
int buttons = 0; |
524 |
if ([[NSApp currentEvent] modifierFlags] & NSCommandKeyMask) { //leftclick+command simulates rightclick |
525 |
buttons |= MOUSE_EVENT_RBUTTON; |
526 |
} else { |
527 |
buttons |= MOUSE_EVENT_LBUTTON; |
528 |
} |
529 |
kbd_mouse_event(dx, dy, dz, buttons); |
530 |
} |
531 |
break; |
532 |
|
533 |
case NSLeftMouseUp: |
534 |
if (grab) { |
535 |
kbd_mouse_event(0, 0, 0, 0); |
536 |
} else { |
537 |
[window setTitle: @"QEMU (Press ctrl + alt to release Mouse)"]; |
538 |
[NSCursor hide]; |
539 |
CGAssociateMouseAndMouseCursorPosition ( FALSE ); |
540 |
grab = 1; |
541 |
//[NSApp sendEvent: event]; |
542 |
} |
543 |
break; |
544 |
|
545 |
case NSRightMouseDown: |
546 |
if (grab) { |
547 |
int buttons = 0; |
548 |
|
549 |
buttons |= MOUSE_EVENT_RBUTTON; |
550 |
kbd_mouse_event(0, 0, 0, buttons); |
551 |
} else { |
552 |
[NSApp sendEvent: event]; |
553 |
} |
554 |
break; |
555 |
|
556 |
case NSRightMouseDragged: |
557 |
if (grab) { |
558 |
int dx = [event deltaX]; |
559 |
int dy = [event deltaY]; |
560 |
int dz = [event deltaZ]; |
561 |
int buttons = 0; |
562 |
buttons |= MOUSE_EVENT_RBUTTON; |
563 |
kbd_mouse_event(dx, dy, dz, buttons); |
564 |
} |
565 |
break; |
566 |
|
567 |
case NSRightMouseUp: |
568 |
if (grab) { |
569 |
kbd_mouse_event(0, 0, 0, 0); |
570 |
} else { |
571 |
[NSApp sendEvent: event]; |
572 |
} |
573 |
break; |
574 |
|
575 |
case NSOtherMouseDragged: |
576 |
if (grab) { |
577 |
int dx = [event deltaX]; |
578 |
int dy = [event deltaY]; |
579 |
int dz = [event deltaZ]; |
580 |
int buttons = 0; |
581 |
buttons |= MOUSE_EVENT_MBUTTON; |
582 |
kbd_mouse_event(dx, dy, dz, buttons); |
583 |
} |
584 |
break; |
585 |
|
586 |
case NSOtherMouseDown: |
587 |
if (grab) { |
588 |
int buttons = 0; |
589 |
buttons |= MOUSE_EVENT_MBUTTON; |
590 |
kbd_mouse_event(0, 0, 0, buttons); |
591 |
} else { |
592 |
[NSApp sendEvent:event]; |
593 |
} |
594 |
break; |
595 |
|
596 |
case NSOtherMouseUp: |
597 |
if (grab) { |
598 |
kbd_mouse_event(0, 0, 0, 0); |
599 |
} else { |
600 |
[NSApp sendEvent: event]; |
601 |
} |
602 |
break; |
603 |
|
604 |
case NSScrollWheel: |
605 |
if (grab) { |
606 |
int dz = [event deltaY]; |
607 |
kbd_mouse_event(0, 0, -dz, 0); |
608 |
} |
609 |
break; |
610 |
|
611 |
default: [NSApp sendEvent:event]; |
612 |
} |
613 |
} |
614 |
} while(event != nil); |
615 |
} |
616 |
|
617 |
/* |
618 |
------------------------------------------------------ |
619 |
cocoa_cleanup |
620 |
------------------------------------------------------ |
621 |
*/ |
622 |
|
623 |
static void cocoa_cleanup(void) |
624 |
{ |
625 |
|
626 |
} |
627 |
|
628 |
/* |
629 |
------------------------------------------------------ |
630 |
cocoa_display_init |
631 |
------------------------------------------------------ |
632 |
*/ |
633 |
|
634 |
void cocoa_display_init(DisplayState *ds, int full_screen) |
635 |
{ |
636 |
ds->dpy_update = cocoa_update; |
637 |
ds->dpy_resize = cocoa_resize; |
638 |
ds->dpy_refresh = cocoa_refresh; |
639 |
|
640 |
cocoa_resize(ds, 640, 400); |
641 |
|
642 |
atexit(cocoa_cleanup); |
643 |
} |
644 |
|
645 |
/* |
646 |
------------------------------------------------------ |
647 |
Interface with Cocoa |
648 |
------------------------------------------------------ |
649 |
*/ |
650 |
|
651 |
|
652 |
/* |
653 |
------------------------------------------------------ |
654 |
QemuWindow |
655 |
Some trick from SDL to use miniwindow |
656 |
------------------------------------------------------ |
657 |
*/ |
658 |
static void QZ_SetPortAlphaOpaque () |
659 |
{ |
660 |
/* Assume 32 bit if( bpp == 32 )*/ |
661 |
if ( 1 ) { |
662 |
|
663 |
uint32_t *pixels = (uint32_t*) current_ds.data; |
664 |
uint32_t rowPixels = current_ds.linesize / 4; |
665 |
uint32_t i, j; |
666 |
|
667 |
for (i = 0; i < current_ds.height; i++) |
668 |
for (j = 0; j < current_ds.width; j++) { |
669 |
|
670 |
pixels[ (i * rowPixels) + j ] |= 0xFF000000; |
671 |
} |
672 |
} |
673 |
} |
674 |
|
675 |
@implementation QemuWindow |
676 |
- (void)miniaturize:(id)sender |
677 |
{ |
678 |
|
679 |
/* make the alpha channel opaque so anim won't have holes in it */ |
680 |
QZ_SetPortAlphaOpaque (); |
681 |
|
682 |
[ super miniaturize:sender ]; |
683 |
|
684 |
} |
685 |
- (void)display |
686 |
{ |
687 |
/* |
688 |
This method fires just before the window deminaturizes from the Dock. |
689 |
|
690 |
We'll save the current visible surface, let the window manager redraw any |
691 |
UI elements, and restore the SDL surface. This way, no expose event |
692 |
is required, and the deminiaturize works perfectly. |
693 |
*/ |
694 |
|
695 |
/* make sure pixels are fully opaque */ |
696 |
QZ_SetPortAlphaOpaque (); |
697 |
|
698 |
/* save current visible SDL surface */ |
699 |
[ self cacheImageInRect:[ qd_view frame ] ]; |
700 |
|
701 |
/* let the window manager redraw controls, border, etc */ |
702 |
[ super display ]; |
703 |
|
704 |
/* restore visible SDL surface */ |
705 |
[ self restoreCachedImage ]; |
706 |
} |
707 |
|
708 |
@end |
709 |
|
710 |
|
711 |
/* |
712 |
------------------------------------------------------ |
713 |
QemuCocoaGUIController |
714 |
NSApp's delegate - indeed main object |
715 |
------------------------------------------------------ |
716 |
*/ |
717 |
|
718 |
@interface QemuCocoaGUIController : NSObject |
719 |
{ |
720 |
} |
721 |
- (void)applicationDidFinishLaunching: (NSNotification *) note; |
722 |
- (void)applicationWillTerminate:(NSNotification *)aNotification; |
723 |
|
724 |
- (void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo; |
725 |
|
726 |
- (void)startEmulationWithArgc:(int)argc argv:(char**)argv; |
727 |
@end |
728 |
|
729 |
@implementation QemuCocoaGUIController |
730 |
/* Called when the internal event loop has just started running */ |
731 |
- (void)applicationDidFinishLaunching: (NSNotification *) note |
732 |
{ |
733 |
|
734 |
/* Display an open dialog box if no argument were passed or |
735 |
if qemu was launched from the finder ( the Finder passes "-psn" ) */ |
736 |
|
737 |
if( gArgc <= 1 || strncmp (gArgv[1], "-psn", 4) == 0) |
738 |
{ |
739 |
NSOpenPanel *op = [[NSOpenPanel alloc] init]; |
740 |
|
741 |
cocoa_resize(¤t_ds, 640, 400); |
742 |
|
743 |
[op setPrompt:@"Boot image"]; |
744 |
|
745 |
[op setMessage:@"Select the disk image you want to boot.\n\nHit the \"Cancel\" button to quit"]; |
746 |
|
747 |
[op beginSheetForDirectory:nil file:nil types:[NSArray arrayWithObjects:@"img",@"iso",@"dmg",@"qcow",@"cow",@"cloop",@"vmdk",nil] |
748 |
modalForWindow:window modalDelegate:self |
749 |
didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:) contextInfo:NULL]; |
750 |
} |
751 |
else |
752 |
{ |
753 |
/* or Launch Qemu, with the global args */ |
754 |
[self startEmulationWithArgc:gArgc argv:gArgv]; |
755 |
} |
756 |
} |
757 |
|
758 |
- (void)applicationWillTerminate:(NSNotification *)aNotification |
759 |
{ |
760 |
printf("Application will terminate\n"); |
761 |
qemu_system_shutdown_request(); |
762 |
/* In order to avoid a crash */ |
763 |
exit(0); |
764 |
} |
765 |
|
766 |
- (void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo |
767 |
{ |
768 |
if(returnCode == NSCancelButton) |
769 |
{ |
770 |
exit(0); |
771 |
} |
772 |
|
773 |
if(returnCode == NSOKButton) |
774 |
{ |
775 |
char *bin = "qemu"; |
776 |
char *img = (char*)[ [ sheet filename ] cString]; |
777 |
|
778 |
char **argv = (char**)malloc( sizeof(char*)*3 ); |
779 |
|
780 |
asprintf(&argv[0], "%s", bin); |
781 |
asprintf(&argv[1], "-hda"); |
782 |
asprintf(&argv[2], "%s", img); |
783 |
|
784 |
printf("Using argc %d argv %s -hda %s\n", 3, bin, img); |
785 |
|
786 |
[self startEmulationWithArgc:3 argv:(char**)argv]; |
787 |
} |
788 |
} |
789 |
|
790 |
- (void)startEmulationWithArgc:(int)argc argv:(char**)argv |
791 |
{ |
792 |
int status; |
793 |
/* Launch Qemu */ |
794 |
printf("starting qemu...\n"); |
795 |
status = qemu_main (argc, argv); |
796 |
exit(status); |
797 |
} |
798 |
@end |
799 |
|
800 |
/* |
801 |
------------------------------------------------------ |
802 |
Application Creation |
803 |
------------------------------------------------------ |
804 |
*/ |
805 |
|
806 |
/* Dock Connection */ |
807 |
typedef struct CPSProcessSerNum |
808 |
{ |
809 |
UInt32 lo; |
810 |
UInt32 hi; |
811 |
} CPSProcessSerNum; |
812 |
|
813 |
extern OSErr CPSGetCurrentProcess( CPSProcessSerNum *psn); |
814 |
extern OSErr CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5); |
815 |
extern OSErr CPSSetFrontProcess( CPSProcessSerNum *psn); |
816 |
|
817 |
/* Menu Creation */ |
818 |
static void setApplicationMenu(void) |
819 |
{ |
820 |
/* warning: this code is very odd */ |
821 |
NSMenu *appleMenu; |
822 |
NSMenuItem *menuItem; |
823 |
NSString *title; |
824 |
NSString *appName; |
825 |
|
826 |
appName = @"Qemu"; |
827 |
appleMenu = [[NSMenu alloc] initWithTitle:@""]; |
828 |
|
829 |
/* Add menu items */ |
830 |
title = [@"About " stringByAppendingString:appName]; |
831 |
[appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""]; |
832 |
|
833 |
[appleMenu addItem:[NSMenuItem separatorItem]]; |
834 |
|
835 |
title = [@"Hide " stringByAppendingString:appName]; |
836 |
[appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"]; |
837 |
|
838 |
menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"]; |
839 |
[menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)]; |
840 |
|
841 |
[appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""]; |
842 |
|
843 |
[appleMenu addItem:[NSMenuItem separatorItem]]; |
844 |
|
845 |
title = [@"Quit " stringByAppendingString:appName]; |
846 |
[appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"]; |
847 |
|
848 |
|
849 |
/* Put menu into the menubar */ |
850 |
menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""]; |
851 |
[menuItem setSubmenu:appleMenu]; |
852 |
[[NSApp mainMenu] addItem:menuItem]; |
853 |
|
854 |
/* Tell the application object that this is now the application menu */ |
855 |
[NSApp setAppleMenu:appleMenu]; |
856 |
|
857 |
/* Finally give up our references to the objects */ |
858 |
[appleMenu release]; |
859 |
[menuItem release]; |
860 |
} |
861 |
|
862 |
/* Create a window menu */ |
863 |
static void setupWindowMenu(void) |
864 |
{ |
865 |
NSMenu *windowMenu; |
866 |
NSMenuItem *windowMenuItem; |
867 |
NSMenuItem *menuItem; |
868 |
|
869 |
windowMenu = [[NSMenu alloc] initWithTitle:@"Window"]; |
870 |
|
871 |
/* "Minimize" item */ |
872 |
menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"]; |
873 |
[windowMenu addItem:menuItem]; |
874 |
[menuItem release]; |
875 |
|
876 |
/* Put menu into the menubar */ |
877 |
windowMenuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""]; |
878 |
[windowMenuItem setSubmenu:windowMenu]; |
879 |
[[NSApp mainMenu] addItem:windowMenuItem]; |
880 |
|
881 |
/* Tell the application object that this is now the window menu */ |
882 |
[NSApp setWindowsMenu:windowMenu]; |
883 |
|
884 |
/* Finally give up our references to the objects */ |
885 |
[windowMenu release]; |
886 |
[windowMenuItem release]; |
887 |
} |
888 |
|
889 |
static void CustomApplicationMain(void) |
890 |
{ |
891 |
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; |
892 |
QemuCocoaGUIController *gui_controller; |
893 |
CPSProcessSerNum PSN; |
894 |
|
895 |
[NSApplication sharedApplication]; |
896 |
|
897 |
if (!CPSGetCurrentProcess(&PSN)) |
898 |
if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103)) |
899 |
if (!CPSSetFrontProcess(&PSN)) |
900 |
[NSApplication sharedApplication]; |
901 |
|
902 |
/* Set up the menubar */ |
903 |
[NSApp setMainMenu:[[NSMenu alloc] init]]; |
904 |
setApplicationMenu(); |
905 |
setupWindowMenu(); |
906 |
|
907 |
/* Create SDLMain and make it the app delegate */ |
908 |
gui_controller = [[QemuCocoaGUIController alloc] init]; |
909 |
[NSApp setDelegate:gui_controller]; |
910 |
|
911 |
/* Start the main event loop */ |
912 |
[NSApp run]; |
913 |
|
914 |
[gui_controller release]; |
915 |
[pool release]; |
916 |
} |
917 |
|
918 |
/* Real main of qemu-cocoa */ |
919 |
int main(int argc, char **argv) |
920 |
{ |
921 |
gArgc = argc; |
922 |
gArgv = argv; |
923 |
|
924 |
CustomApplicationMain(); |
925 |
|
926 |
return 0; |
927 |
} |