|
1 /* |
|
2 * QEMU Cocoa CG display driver |
|
3 * |
|
4 * Copyright (c) 2008 Mike Kronenberg |
|
5 * |
|
6 * Permission is hereby granted, free of charge, to any person obtaining a copy |
|
7 * of this software and associated documentation files (the "Software"), to deal |
|
8 * in the Software without restriction, including without limitation the rights |
|
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
10 * copies of the Software, and to permit persons to whom the Software is |
|
11 * furnished to do so, subject to the following conditions: |
|
12 * |
|
13 * The above copyright notice and this permission notice shall be included in |
|
14 * all copies or substantial portions of the Software. |
|
15 * |
|
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
|
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|
22 * THE SOFTWARE. |
|
23 */ |
|
24 |
|
25 #import <Cocoa/Cocoa.h> |
|
26 |
|
27 #include "qemu-common.h" |
|
28 #include "console.h" |
|
29 #include "sysemu.h" |
|
30 |
|
31 |
|
32 //#define DEBUG |
|
33 |
|
34 #ifdef DEBUG |
|
35 #define COCOA_DEBUG(...) { (void) fprintf (stdout, __VA_ARGS__); } |
|
36 #else |
|
37 #define COCOA_DEBUG(...) ((void) 0) |
|
38 #endif |
|
39 |
|
40 #define cgrect(nsrect) (*(CGRect *)&(nsrect)) |
|
41 #define COCOA_MOUSE_EVENT \ |
|
42 if (isTabletEnabled) { \ |
|
43 kbd_mouse_event((int)(p.x * 0x7FFF / (screen.width - 1)), (int)((screen.height - p.y) * 0x7FFF / (screen.height - 1)), 0, buttons); \ |
|
44 } else if (isMouseGrabed) { \ |
|
45 kbd_mouse_event((int)[event deltaX], (int)[event deltaY], 0, buttons); \ |
|
46 } else { \ |
|
47 [NSApp sendEvent:event]; \ |
|
48 } |
|
49 |
|
50 typedef struct { |
|
51 int width; |
|
52 int height; |
|
53 int bitsPerComponent; |
|
54 int bitsPerPixel; |
|
55 } QEMUScreen; |
|
56 |
|
57 int qemu_main(int argc, char **argv); // main defined in qemu/vl.c |
|
58 NSWindow *normalWindow; |
|
59 id cocoaView; |
|
60 static void *screenBuffer; |
|
61 |
|
62 int gArgc; |
|
63 char **gArgv; |
|
64 |
|
65 // keymap conversion |
|
66 int keymap[] = |
|
67 { |
|
68 // SdlI macI macH SdlH 104xtH 104xtC sdl |
|
69 30, // 0 0x00 0x1e A QZ_a |
|
70 31, // 1 0x01 0x1f S QZ_s |
|
71 32, // 2 0x02 0x20 D QZ_d |
|
72 33, // 3 0x03 0x21 F QZ_f |
|
73 35, // 4 0x04 0x23 H QZ_h |
|
74 34, // 5 0x05 0x22 G QZ_g |
|
75 44, // 6 0x06 0x2c Z QZ_z |
|
76 45, // 7 0x07 0x2d X QZ_x |
|
77 46, // 8 0x08 0x2e C QZ_c |
|
78 47, // 9 0x09 0x2f V QZ_v |
|
79 0, // 10 0x0A Undefined |
|
80 48, // 11 0x0B 0x30 B QZ_b |
|
81 16, // 12 0x0C 0x10 Q QZ_q |
|
82 17, // 13 0x0D 0x11 W QZ_w |
|
83 18, // 14 0x0E 0x12 E QZ_e |
|
84 19, // 15 0x0F 0x13 R QZ_r |
|
85 21, // 16 0x10 0x15 Y QZ_y |
|
86 20, // 17 0x11 0x14 T QZ_t |
|
87 2, // 18 0x12 0x02 1 QZ_1 |
|
88 3, // 19 0x13 0x03 2 QZ_2 |
|
89 4, // 20 0x14 0x04 3 QZ_3 |
|
90 5, // 21 0x15 0x05 4 QZ_4 |
|
91 7, // 22 0x16 0x07 6 QZ_6 |
|
92 6, // 23 0x17 0x06 5 QZ_5 |
|
93 13, // 24 0x18 0x0d = QZ_EQUALS |
|
94 10, // 25 0x19 0x0a 9 QZ_9 |
|
95 8, // 26 0x1A 0x08 7 QZ_7 |
|
96 12, // 27 0x1B 0x0c - QZ_MINUS |
|
97 9, // 28 0x1C 0x09 8 QZ_8 |
|
98 11, // 29 0x1D 0x0b 0 QZ_0 |
|
99 27, // 30 0x1E 0x1b ] QZ_RIGHTBRACKET |
|
100 24, // 31 0x1F 0x18 O QZ_o |
|
101 22, // 32 0x20 0x16 U QZ_u |
|
102 26, // 33 0x21 0x1a [ QZ_LEFTBRACKET |
|
103 23, // 34 0x22 0x17 I QZ_i |
|
104 25, // 35 0x23 0x19 P QZ_p |
|
105 28, // 36 0x24 0x1c ENTER QZ_RETURN |
|
106 38, // 37 0x25 0x26 L QZ_l |
|
107 36, // 38 0x26 0x24 J QZ_j |
|
108 40, // 39 0x27 0x28 ' QZ_QUOTE |
|
109 37, // 40 0x28 0x25 K QZ_k |
|
110 39, // 41 0x29 0x27 ; QZ_SEMICOLON |
|
111 43, // 42 0x2A 0x2b \ QZ_BACKSLASH |
|
112 51, // 43 0x2B 0x33 , QZ_COMMA |
|
113 53, // 44 0x2C 0x35 / QZ_SLASH |
|
114 49, // 45 0x2D 0x31 N QZ_n |
|
115 50, // 46 0x2E 0x32 M QZ_m |
|
116 52, // 47 0x2F 0x34 . QZ_PERIOD |
|
117 15, // 48 0x30 0x0f TAB QZ_TAB |
|
118 57, // 49 0x31 0x39 SPACE QZ_SPACE |
|
119 41, // 50 0x32 0x29 ` QZ_BACKQUOTE |
|
120 14, // 51 0x33 0x0e BKSP QZ_BACKSPACE |
|
121 0, // 52 0x34 Undefined |
|
122 1, // 53 0x35 0x01 ESC QZ_ESCAPE |
|
123 0, // 54 0x36 QZ_RMETA |
|
124 0, // 55 0x37 QZ_LMETA |
|
125 42, // 56 0x38 0x2a L SHFT QZ_LSHIFT |
|
126 58, // 57 0x39 0x3a CAPS QZ_CAPSLOCK |
|
127 56, // 58 0x3A 0x38 L ALT QZ_LALT |
|
128 29, // 59 0x3B 0x1d L CTRL QZ_LCTRL |
|
129 54, // 60 0x3C 0x36 R SHFT QZ_RSHIFT |
|
130 184,// 61 0x3D 0xb8 E0,38 R ALT QZ_RALT |
|
131 157,// 62 0x3E 0x9d E0,1D R CTRL QZ_RCTRL |
|
132 0, // 63 0x3F Undefined |
|
133 0, // 64 0x40 Undefined |
|
134 0, // 65 0x41 Undefined |
|
135 0, // 66 0x42 Undefined |
|
136 55, // 67 0x43 0x37 KP * QZ_KP_MULTIPLY |
|
137 0, // 68 0x44 Undefined |
|
138 78, // 69 0x45 0x4e KP + QZ_KP_PLUS |
|
139 0, // 70 0x46 Undefined |
|
140 69, // 71 0x47 0x45 NUM QZ_NUMLOCK |
|
141 0, // 72 0x48 Undefined |
|
142 0, // 73 0x49 Undefined |
|
143 0, // 74 0x4A Undefined |
|
144 181,// 75 0x4B 0xb5 E0,35 KP / QZ_KP_DIVIDE |
|
145 152,// 76 0x4C 0x9c E0,1C KP EN QZ_KP_ENTER |
|
146 0, // 77 0x4D undefined |
|
147 74, // 78 0x4E 0x4a KP - QZ_KP_MINUS |
|
148 0, // 79 0x4F Undefined |
|
149 0, // 80 0x50 Undefined |
|
150 0, // 81 0x51 QZ_KP_EQUALS |
|
151 82, // 82 0x52 0x52 KP 0 QZ_KP0 |
|
152 79, // 83 0x53 0x4f KP 1 QZ_KP1 |
|
153 80, // 84 0x54 0x50 KP 2 QZ_KP2 |
|
154 81, // 85 0x55 0x51 KP 3 QZ_KP3 |
|
155 75, // 86 0x56 0x4b KP 4 QZ_KP4 |
|
156 76, // 87 0x57 0x4c KP 5 QZ_KP5 |
|
157 77, // 88 0x58 0x4d KP 6 QZ_KP6 |
|
158 71, // 89 0x59 0x47 KP 7 QZ_KP7 |
|
159 0, // 90 0x5A Undefined |
|
160 72, // 91 0x5B 0x48 KP 8 QZ_KP8 |
|
161 73, // 92 0x5C 0x49 KP 9 QZ_KP9 |
|
162 0, // 93 0x5D Undefined |
|
163 0, // 94 0x5E Undefined |
|
164 0, // 95 0x5F Undefined |
|
165 63, // 96 0x60 0x3f F5 QZ_F5 |
|
166 64, // 97 0x61 0x40 F6 QZ_F6 |
|
167 65, // 98 0x62 0x41 F7 QZ_F7 |
|
168 61, // 99 0x63 0x3d F3 QZ_F3 |
|
169 66, // 100 0x64 0x42 F8 QZ_F8 |
|
170 67, // 101 0x65 0x43 F9 QZ_F9 |
|
171 0, // 102 0x66 Undefined |
|
172 87, // 103 0x67 0x57 F11 QZ_F11 |
|
173 0, // 104 0x68 Undefined |
|
174 183,// 105 0x69 0xb7 QZ_PRINT |
|
175 0, // 106 0x6A Undefined |
|
176 70, // 107 0x6B 0x46 SCROLL QZ_SCROLLOCK |
|
177 0, // 108 0x6C Undefined |
|
178 68, // 109 0x6D 0x44 F10 QZ_F10 |
|
179 0, // 110 0x6E Undefined |
|
180 88, // 111 0x6F 0x58 F12 QZ_F12 |
|
181 0, // 112 0x70 Undefined |
|
182 110,// 113 0x71 0x0 QZ_PAUSE |
|
183 210,// 114 0x72 0xd2 E0,52 INSERT QZ_INSERT |
|
184 199,// 115 0x73 0xc7 E0,47 HOME QZ_HOME |
|
185 201,// 116 0x74 0xc9 E0,49 PG UP QZ_PAGEUP |
|
186 211,// 117 0x75 0xd3 E0,53 DELETE QZ_DELETE |
|
187 62, // 118 0x76 0x3e F4 QZ_F4 |
|
188 207,// 119 0x77 0xcf E0,4f END QZ_END |
|
189 60, // 120 0x78 0x3c F2 QZ_F2 |
|
190 209,// 121 0x79 0xd1 E0,51 PG DN QZ_PAGEDOWN |
|
191 59, // 122 0x7A 0x3b F1 QZ_F1 |
|
192 203,// 123 0x7B 0xcb e0,4B L ARROW QZ_LEFT |
|
193 205,// 124 0x7C 0xcd e0,4D R ARROW QZ_RIGHT |
|
194 208,// 125 0x7D 0xd0 E0,50 D ARROW QZ_DOWN |
|
195 200,// 126 0x7E 0xc8 E0,48 U ARROW QZ_UP |
|
196 /* 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 */ |
|
197 |
|
198 /* Aditional 104 Key XP-Keyboard Scancodes from http://www.computer-engineering.org/ps2keyboard/scancodes1.html */ |
|
199 /* |
|
200 219 // 0xdb e0,5b L GUI |
|
201 220 // 0xdc e0,5c R GUI |
|
202 221 // 0xdd e0,5d APPS |
|
203 // E0,2A,E0,37 PRNT SCRN |
|
204 // E1,1D,45,E1,9D,C5 PAUSE |
|
205 83 // 0x53 0x53 KP . |
|
206 // ACPI Scan Codes |
|
207 222 // 0xde E0, 5E Power |
|
208 223 // 0xdf E0, 5F Sleep |
|
209 227 // 0xe3 E0, 63 Wake |
|
210 // Windows Multimedia Scan Codes |
|
211 153 // 0x99 E0, 19 Next Track |
|
212 144 // 0x90 E0, 10 Previous Track |
|
213 164 // 0xa4 E0, 24 Stop |
|
214 162 // 0xa2 E0, 22 Play/Pause |
|
215 160 // 0xa0 E0, 20 Mute |
|
216 176 // 0xb0 E0, 30 Volume Up |
|
217 174 // 0xae E0, 2E Volume Down |
|
218 237 // 0xed E0, 6D Media Select |
|
219 236 // 0xec E0, 6C E-Mail |
|
220 161 // 0xa1 E0, 21 Calculator |
|
221 235 // 0xeb E0, 6B My Computer |
|
222 229 // 0xe5 E0, 65 WWW Search |
|
223 178 // 0xb2 E0, 32 WWW Home |
|
224 234 // 0xea E0, 6A WWW Back |
|
225 233 // 0xe9 E0, 69 WWW Forward |
|
226 232 // 0xe8 E0, 68 WWW Stop |
|
227 231 // 0xe7 E0, 67 WWW Refresh |
|
228 230 // 0xe6 E0, 66 WWW Favorites |
|
229 */ |
|
230 }; |
|
231 |
|
232 int cocoa_keycode_to_qemu(int keycode) |
|
233 { |
|
234 if((sizeof(keymap)/sizeof(int)) <= keycode) |
|
235 { |
|
236 printf("(cocoa) warning unknow keycode 0x%x\n", keycode); |
|
237 return 0; |
|
238 } |
|
239 return keymap[keycode]; |
|
240 } |
|
241 |
|
242 |
|
243 |
|
244 /* |
|
245 ------------------------------------------------------ |
|
246 QemuCocoaView |
|
247 ------------------------------------------------------ |
|
248 */ |
|
249 @interface QemuCocoaView : NSView |
|
250 { |
|
251 QEMUScreen screen; |
|
252 NSWindow *fullScreenWindow; |
|
253 float cx,cy,cw,ch,cdx,cdy; |
|
254 CGDataProviderRef dataProviderRef; |
|
255 int modifiers_state[256]; |
|
256 BOOL isMouseGrabed; |
|
257 BOOL isFullscreen; |
|
258 BOOL isAbsoluteEnabled; |
|
259 BOOL isTabletEnabled; |
|
260 } |
|
261 - (void) resizeContentToWidth:(int)w height:(int)h displayState:(DisplayState *)ds; |
|
262 - (void) grabMouse; |
|
263 - (void) ungrabMouse; |
|
264 - (void) toggleFullScreen:(id)sender; |
|
265 - (void) handleEvent:(NSEvent *)event; |
|
266 - (void) setAbsoluteEnabled:(BOOL)tIsAbsoluteEnabled; |
|
267 - (BOOL) isMouseGrabed; |
|
268 - (BOOL) isAbsoluteEnabled; |
|
269 - (float) cdx; |
|
270 - (float) cdy; |
|
271 - (QEMUScreen) gscreen; |
|
272 @end |
|
273 |
|
274 @implementation QemuCocoaView |
|
275 - (id)initWithFrame:(NSRect)frameRect |
|
276 { |
|
277 COCOA_DEBUG("QemuCocoaView: initWithFrame\n"); |
|
278 |
|
279 self = [super initWithFrame:frameRect]; |
|
280 if (self) { |
|
281 |
|
282 screen.bitsPerComponent = 8; |
|
283 screen.bitsPerPixel = 32; |
|
284 screen.width = frameRect.size.width; |
|
285 screen.height = frameRect.size.height; |
|
286 |
|
287 } |
|
288 return self; |
|
289 } |
|
290 |
|
291 - (void) dealloc |
|
292 { |
|
293 COCOA_DEBUG("QemuCocoaView: dealloc\n"); |
|
294 |
|
295 if (screenBuffer) |
|
296 free(screenBuffer); |
|
297 |
|
298 if (dataProviderRef) |
|
299 CGDataProviderRelease(dataProviderRef); |
|
300 |
|
301 [super dealloc]; |
|
302 } |
|
303 |
|
304 - (void) drawRect:(NSRect) rect |
|
305 { |
|
306 COCOA_DEBUG("QemuCocoaView: drawRect\n"); |
|
307 |
|
308 if ((int)screenBuffer == -1) |
|
309 return; |
|
310 |
|
311 // get CoreGraphic context |
|
312 CGContextRef viewContextRef = [[NSGraphicsContext currentContext] graphicsPort]; |
|
313 CGContextSetInterpolationQuality (viewContextRef, kCGInterpolationNone); |
|
314 CGContextSetShouldAntialias (viewContextRef, NO); |
|
315 |
|
316 // draw screen bitmap directly to Core Graphics context |
|
317 if (dataProviderRef) { |
|
318 CGImageRef imageRef = CGImageCreate( |
|
319 screen.width, //width |
|
320 screen.height, //height |
|
321 screen.bitsPerComponent, //bitsPerComponent |
|
322 screen.bitsPerPixel, //bitsPerPixel |
|
323 (screen.width * 4), //bytesPerRow |
|
324 #if __LITTLE_ENDIAN__ |
|
325 CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB), //colorspace for OS X >= 10.4 |
|
326 kCGImageAlphaNoneSkipLast, |
|
327 #else |
|
328 CGColorSpaceCreateDeviceRGB(), //colorspace for OS X < 10.4 (actually ppc) |
|
329 kCGImageAlphaNoneSkipFirst, //bitmapInfo |
|
330 #endif |
|
331 dataProviderRef, //provider |
|
332 NULL, //decode |
|
333 0, //interpolate |
|
334 kCGRenderingIntentDefault //intent |
|
335 ); |
|
336 // test if host support "CGImageCreateWithImageInRect" at compiletime |
|
337 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4) |
|
338 if (CGImageCreateWithImageInRect == NULL) { // test if "CGImageCreateWithImageInRect" is supported on host at runtime |
|
339 #endif |
|
340 // compatibility drawing code (draws everything) (OS X < 10.4) |
|
341 CGContextDrawImage (viewContextRef, CGRectMake(0, 0, [self bounds].size.width, [self bounds].size.height), imageRef); |
|
342 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4) |
|
343 } else { |
|
344 // selective drawing code (draws only dirty rectangles) (OS X >= 10.4) |
|
345 const NSRect *rectList; |
|
346 int rectCount; |
|
347 int i; |
|
348 CGImageRef clipImageRef; |
|
349 CGRect clipRect; |
|
350 |
|
351 [self getRectsBeingDrawn:&rectList count:&rectCount]; |
|
352 for (i = 0; i < rectCount; i++) { |
|
353 clipRect.origin.x = rectList[i].origin.x / cdx; |
|
354 clipRect.origin.y = (float)screen.height - (rectList[i].origin.y + rectList[i].size.height) / cdy; |
|
355 clipRect.size.width = rectList[i].size.width / cdx; |
|
356 clipRect.size.height = rectList[i].size.height / cdy; |
|
357 clipImageRef = CGImageCreateWithImageInRect( |
|
358 imageRef, |
|
359 clipRect |
|
360 ); |
|
361 CGContextDrawImage (viewContextRef, cgrect(rectList[i]), clipImageRef); |
|
362 CGImageRelease (clipImageRef); |
|
363 } |
|
364 } |
|
365 #endif |
|
366 CGImageRelease (imageRef); |
|
367 } |
|
368 } |
|
369 |
|
370 - (void) setContentDimensions |
|
371 { |
|
372 COCOA_DEBUG("QemuCocoaView: setContentDimensions\n"); |
|
373 |
|
374 if (isFullscreen) { |
|
375 cdx = [[NSScreen mainScreen] frame].size.width / (float)screen.width; |
|
376 cdy = [[NSScreen mainScreen] frame].size.height / (float)screen.height; |
|
377 cw = screen.width * cdx; |
|
378 ch = screen.height * cdy; |
|
379 cx = ([[NSScreen mainScreen] frame].size.width - cw) / 2.0; |
|
380 cy = ([[NSScreen mainScreen] frame].size.height - ch) / 2.0; |
|
381 } else { |
|
382 cx = 0; |
|
383 cy = 0; |
|
384 cw = screen.width; |
|
385 ch = screen.height; |
|
386 cdx = 1.0; |
|
387 cdy = 1.0; |
|
388 } |
|
389 } |
|
390 |
|
391 - (void) resizeContentToWidth:(int)w height:(int)h displayState:(DisplayState *)ds |
|
392 { |
|
393 COCOA_DEBUG("QemuCocoaView: resizeContent\n"); |
|
394 |
|
395 // update screenBuffer |
|
396 if (dataProviderRef) |
|
397 CGDataProviderRelease(dataProviderRef); |
|
398 if (screenBuffer) |
|
399 free(screenBuffer); |
|
400 screenBuffer = malloc( w * 4 * h ); |
|
401 |
|
402 ds->data = screenBuffer; |
|
403 ds->linesize = (w * 4); |
|
404 ds->depth = 32; |
|
405 ds->width = w; |
|
406 ds->height = h; |
|
407 #ifdef __LITTLE_ENDIAN__ |
|
408 ds->bgr = 1; |
|
409 #else |
|
410 ds->bgr = 0; |
|
411 #endif |
|
412 |
|
413 dataProviderRef = CGDataProviderCreateWithData(NULL, screenBuffer, w * 4 * h, NULL); |
|
414 |
|
415 // update windows |
|
416 if (isFullscreen) { |
|
417 [[fullScreenWindow contentView] setFrame:[[NSScreen mainScreen] frame]]; |
|
418 [normalWindow setFrame:NSMakeRect([normalWindow frame].origin.x, [normalWindow frame].origin.y - h + screen.height, w, h + [normalWindow frame].size.height - screen.height) display:NO animate:NO]; |
|
419 } else { |
|
420 if (qemu_name) |
|
421 [normalWindow setTitle:[NSString stringWithFormat:@"QEMU %s", qemu_name]]; |
|
422 [normalWindow setFrame:NSMakeRect([normalWindow frame].origin.x, [normalWindow frame].origin.y - h + screen.height, w, h + [normalWindow frame].size.height - screen.height) display:YES animate:YES]; |
|
423 } |
|
424 screen.width = w; |
|
425 screen.height = h; |
|
426 [self setContentDimensions]; |
|
427 [self setFrame:NSMakeRect(cx, cy, cw, ch)]; |
|
428 } |
|
429 |
|
430 - (void) toggleFullScreen:(id)sender |
|
431 { |
|
432 COCOA_DEBUG("QemuCocoaView: toggleFullScreen\n"); |
|
433 |
|
434 if (isFullscreen) { // switch from fullscreen to desktop |
|
435 isFullscreen = FALSE; |
|
436 [self ungrabMouse]; |
|
437 [self setContentDimensions]; |
|
438 // test if host support "enterFullScreenMode:withOptions" at compiletime |
|
439 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4) |
|
440 if ([NSView respondsToSelector:@selector(exitFullScreenModeWithOptions:)]) { // test if "exitFullScreenModeWithOptions" is supported on host at runtime |
|
441 [self exitFullScreenModeWithOptions:nil]; |
|
442 } else { |
|
443 #endif |
|
444 [fullScreenWindow close]; |
|
445 [normalWindow setContentView: self]; |
|
446 [normalWindow makeKeyAndOrderFront: self]; |
|
447 [NSMenu setMenuBarVisible:YES]; |
|
448 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4) |
|
449 } |
|
450 #endif |
|
451 } else { // switch from desktop to fullscreen |
|
452 isFullscreen = TRUE; |
|
453 [self grabMouse]; |
|
454 [self setContentDimensions]; |
|
455 // test if host support "enterFullScreenMode:withOptions" at compiletime |
|
456 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4) |
|
457 if ([NSView respondsToSelector:@selector(enterFullScreenMode:withOptions:)]) { // test if "enterFullScreenMode:withOptions" is supported on host at runtime |
|
458 [self enterFullScreenMode:[NSScreen mainScreen] withOptions:[NSDictionary dictionaryWithObjectsAndKeys: |
|
459 [NSNumber numberWithBool:NO], NSFullScreenModeAllScreens, |
|
460 [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:NO], kCGDisplayModeIsStretched, nil], NSFullScreenModeSetting, |
|
461 nil]]; |
|
462 } else { |
|
463 #endif |
|
464 [NSMenu setMenuBarVisible:NO]; |
|
465 fullScreenWindow = [[NSWindow alloc] initWithContentRect:[[NSScreen mainScreen] frame] |
|
466 styleMask:NSBorderlessWindowMask |
|
467 backing:NSBackingStoreBuffered |
|
468 defer:NO]; |
|
469 [fullScreenWindow setHasShadow:NO]; |
|
470 [fullScreenWindow setContentView:self]; |
|
471 [fullScreenWindow makeKeyAndOrderFront:self]; |
|
472 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4) |
|
473 } |
|
474 #endif |
|
475 } |
|
476 } |
|
477 |
|
478 - (void) handleEvent:(NSEvent *)event |
|
479 { |
|
480 COCOA_DEBUG("QemuCocoaView: handleEvent\n"); |
|
481 |
|
482 int buttons = 0; |
|
483 int keycode; |
|
484 NSPoint p = [event locationInWindow]; |
|
485 |
|
486 switch ([event type]) { |
|
487 case NSFlagsChanged: |
|
488 keycode = cocoa_keycode_to_qemu([event keyCode]); |
|
489 if (keycode) { |
|
490 if (keycode == 58 || keycode == 69) { // emulate caps lock and num lock keydown and keyup |
|
491 kbd_put_keycode(keycode); |
|
492 kbd_put_keycode(keycode | 0x80); |
|
493 } else if (is_graphic_console()) { |
|
494 if (keycode & 0x80) |
|
495 kbd_put_keycode(0xe0); |
|
496 if (modifiers_state[keycode] == 0) { // keydown |
|
497 kbd_put_keycode(keycode & 0x7f); |
|
498 modifiers_state[keycode] = 1; |
|
499 } else { // keyup |
|
500 kbd_put_keycode(keycode | 0x80); |
|
501 modifiers_state[keycode] = 0; |
|
502 } |
|
503 } |
|
504 } |
|
505 |
|
506 // release Mouse grab when pressing ctrl+alt |
|
507 if (!isFullscreen && ([event modifierFlags] & NSControlKeyMask) && ([event modifierFlags] & NSAlternateKeyMask)) { |
|
508 [self ungrabMouse]; |
|
509 } |
|
510 break; |
|
511 case NSKeyDown: |
|
512 |
|
513 // forward command Key Combos |
|
514 if ([event modifierFlags] & NSCommandKeyMask) { |
|
515 [NSApp sendEvent:event]; |
|
516 return; |
|
517 } |
|
518 |
|
519 // default |
|
520 keycode = cocoa_keycode_to_qemu([event keyCode]); |
|
521 |
|
522 // handle control + alt Key Combos (ctrl+alt is reserved for QEMU) |
|
523 if (([event modifierFlags] & NSControlKeyMask) && ([event modifierFlags] & NSAlternateKeyMask)) { |
|
524 switch (keycode) { |
|
525 |
|
526 // enable graphic console |
|
527 case 0x02 ... 0x0a: // '1' to '9' keys |
|
528 console_select(keycode - 0x02); |
|
529 break; |
|
530 } |
|
531 |
|
532 // handle keys for graphic console |
|
533 } else if (is_graphic_console()) { |
|
534 if (keycode & 0x80) //check bit for e0 in front |
|
535 kbd_put_keycode(0xe0); |
|
536 kbd_put_keycode(keycode & 0x7f); //remove e0 bit in front |
|
537 |
|
538 // handlekeys for Monitor |
|
539 } else { |
|
540 int keysym = 0; |
|
541 switch([event keyCode]) { |
|
542 case 115: |
|
543 keysym = QEMU_KEY_HOME; |
|
544 break; |
|
545 case 117: |
|
546 keysym = QEMU_KEY_DELETE; |
|
547 break; |
|
548 case 119: |
|
549 keysym = QEMU_KEY_END; |
|
550 break; |
|
551 case 123: |
|
552 keysym = QEMU_KEY_LEFT; |
|
553 break; |
|
554 case 124: |
|
555 keysym = QEMU_KEY_RIGHT; |
|
556 break; |
|
557 case 125: |
|
558 keysym = QEMU_KEY_DOWN; |
|
559 break; |
|
560 case 126: |
|
561 keysym = QEMU_KEY_UP; |
|
562 break; |
|
563 default: |
|
564 { |
|
565 NSString *ks = [event characters]; |
|
566 if ([ks length] > 0) |
|
567 keysym = [ks characterAtIndex:0]; |
|
568 } |
|
569 } |
|
570 if (keysym) |
|
571 kbd_put_keysym(keysym); |
|
572 } |
|
573 break; |
|
574 case NSKeyUp: |
|
575 keycode = cocoa_keycode_to_qemu([event keyCode]); |
|
576 if (is_graphic_console()) { |
|
577 if (keycode & 0x80) |
|
578 kbd_put_keycode(0xe0); |
|
579 kbd_put_keycode(keycode | 0x80); //add 128 to signal release of key |
|
580 } |
|
581 break; |
|
582 case NSMouseMoved: |
|
583 if (isAbsoluteEnabled) { |
|
584 if (p.x < 0 || p.x > screen.width || p.y < 0 || p.y > screen.height || ![[self window] isKeyWindow]) { |
|
585 if (isTabletEnabled) { // if we leave the window, deactivate the tablet |
|
586 [NSCursor unhide]; |
|
587 isTabletEnabled = FALSE; |
|
588 } |
|
589 } else { |
|
590 if (!isTabletEnabled) { // if we enter the window, activate the tablet |
|
591 [NSCursor hide]; |
|
592 isTabletEnabled = TRUE; |
|
593 } |
|
594 } |
|
595 } |
|
596 COCOA_MOUSE_EVENT |
|
597 break; |
|
598 case NSLeftMouseDown: |
|
599 if ([event modifierFlags] & NSCommandKeyMask) { |
|
600 buttons |= MOUSE_EVENT_RBUTTON; |
|
601 } else { |
|
602 buttons |= MOUSE_EVENT_LBUTTON; |
|
603 } |
|
604 COCOA_MOUSE_EVENT |
|
605 break; |
|
606 case NSRightMouseDown: |
|
607 buttons |= MOUSE_EVENT_RBUTTON; |
|
608 COCOA_MOUSE_EVENT |
|
609 break; |
|
610 case NSOtherMouseDown: |
|
611 buttons |= MOUSE_EVENT_MBUTTON; |
|
612 COCOA_MOUSE_EVENT |
|
613 break; |
|
614 case NSLeftMouseDragged: |
|
615 if ([event modifierFlags] & NSCommandKeyMask) { |
|
616 buttons |= MOUSE_EVENT_RBUTTON; |
|
617 } else { |
|
618 buttons |= MOUSE_EVENT_LBUTTON; |
|
619 } |
|
620 COCOA_MOUSE_EVENT |
|
621 break; |
|
622 case NSRightMouseDragged: |
|
623 buttons |= MOUSE_EVENT_RBUTTON; |
|
624 COCOA_MOUSE_EVENT |
|
625 break; |
|
626 case NSOtherMouseDragged: |
|
627 buttons |= MOUSE_EVENT_MBUTTON; |
|
628 COCOA_MOUSE_EVENT |
|
629 break; |
|
630 case NSLeftMouseUp: |
|
631 if (isTabletEnabled) { |
|
632 COCOA_MOUSE_EVENT |
|
633 } else if (!isMouseGrabed) { |
|
634 if (p.x > -1 && p.x < screen.width && p.y > -1 && p.y < screen.height) { |
|
635 [self grabMouse]; |
|
636 } else { |
|
637 [NSApp sendEvent:event]; |
|
638 } |
|
639 } else { |
|
640 COCOA_MOUSE_EVENT |
|
641 } |
|
642 break; |
|
643 case NSRightMouseUp: |
|
644 COCOA_MOUSE_EVENT |
|
645 break; |
|
646 case NSOtherMouseUp: |
|
647 COCOA_MOUSE_EVENT |
|
648 break; |
|
649 case NSScrollWheel: |
|
650 if (isTabletEnabled || isMouseGrabed) { |
|
651 kbd_mouse_event(0, 0, -[event deltaY], 0); |
|
652 } else { |
|
653 [NSApp sendEvent:event]; |
|
654 } |
|
655 break; |
|
656 default: |
|
657 [NSApp sendEvent:event]; |
|
658 } |
|
659 } |
|
660 |
|
661 - (void) grabMouse |
|
662 { |
|
663 COCOA_DEBUG("QemuCocoaView: grabMouse\n"); |
|
664 |
|
665 if (!isFullscreen) { |
|
666 if (qemu_name) |
|
667 [normalWindow setTitle:[NSString stringWithFormat:@"QEMU %s - (Press ctrl + alt to release Mouse)", qemu_name]]; |
|
668 else |
|
669 [normalWindow setTitle:@"QEMU - (Press ctrl + alt to release Mouse)"]; |
|
670 } |
|
671 [NSCursor hide]; |
|
672 CGAssociateMouseAndMouseCursorPosition(FALSE); |
|
673 isMouseGrabed = TRUE; // while isMouseGrabed = TRUE, QemuCocoaApp sends all events to [cocoaView handleEvent:] |
|
674 } |
|
675 |
|
676 - (void) ungrabMouse |
|
677 { |
|
678 COCOA_DEBUG("QemuCocoaView: ungrabMouse\n"); |
|
679 |
|
680 if (!isFullscreen) { |
|
681 if (qemu_name) |
|
682 [normalWindow setTitle:[NSString stringWithFormat:@"QEMU %s", qemu_name]]; |
|
683 else |
|
684 [normalWindow setTitle:@"QEMU"]; |
|
685 } |
|
686 [NSCursor unhide]; |
|
687 CGAssociateMouseAndMouseCursorPosition(TRUE); |
|
688 isMouseGrabed = FALSE; |
|
689 } |
|
690 |
|
691 - (void) setAbsoluteEnabled:(BOOL)tIsAbsoluteEnabled {isAbsoluteEnabled = tIsAbsoluteEnabled;} |
|
692 - (BOOL) isMouseGrabed {return isMouseGrabed;} |
|
693 - (BOOL) isAbsoluteEnabled {return isAbsoluteEnabled;} |
|
694 - (float) cdx {return cdx;} |
|
695 - (float) cdy {return cdy;} |
|
696 - (QEMUScreen) gscreen {return screen;} |
|
697 @end |
|
698 |
|
699 |
|
700 |
|
701 /* |
|
702 ------------------------------------------------------ |
|
703 QemuCocoaAppController |
|
704 ------------------------------------------------------ |
|
705 */ |
|
706 @interface QemuCocoaAppController : NSObject |
|
707 { |
|
708 } |
|
709 - (void)startEmulationWithArgc:(int)argc argv:(char**)argv; |
|
710 - (void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo; |
|
711 - (void)toggleFullScreen:(id)sender; |
|
712 - (void)showQEMUDoc:(id)sender; |
|
713 - (void)showQEMUTec:(id)sender; |
|
714 @end |
|
715 |
|
716 @implementation QemuCocoaAppController |
|
717 - (id) init |
|
718 { |
|
719 COCOA_DEBUG("QemuCocoaAppController: init\n"); |
|
720 |
|
721 self = [super init]; |
|
722 if (self) { |
|
723 |
|
724 // create a view and add it to the window |
|
725 cocoaView = [[QemuCocoaView alloc] initWithFrame:NSMakeRect(0.0, 0.0, 640.0, 480.0)]; |
|
726 if(!cocoaView) { |
|
727 fprintf(stderr, "(cocoa) can't create a view\n"); |
|
728 exit(1); |
|
729 } |
|
730 |
|
731 // create a window |
|
732 normalWindow = [[NSWindow alloc] initWithContentRect:[cocoaView frame] |
|
733 styleMask:NSTitledWindowMask|NSMiniaturizableWindowMask|NSClosableWindowMask |
|
734 backing:NSBackingStoreBuffered defer:NO]; |
|
735 if(!normalWindow) { |
|
736 fprintf(stderr, "(cocoa) can't create window\n"); |
|
737 exit(1); |
|
738 } |
|
739 [normalWindow setAcceptsMouseMovedEvents:YES]; |
|
740 [normalWindow setTitle:[NSString stringWithFormat:@"QEMU"]]; |
|
741 [normalWindow setContentView:cocoaView]; |
|
742 [normalWindow makeKeyAndOrderFront:self]; |
|
743 |
|
744 } |
|
745 return self; |
|
746 } |
|
747 |
|
748 - (void) dealloc |
|
749 { |
|
750 COCOA_DEBUG("QemuCocoaAppController: dealloc\n"); |
|
751 |
|
752 if (cocoaView) |
|
753 [cocoaView release]; |
|
754 [super dealloc]; |
|
755 } |
|
756 |
|
757 - (void)applicationDidFinishLaunching: (NSNotification *) note |
|
758 { |
|
759 COCOA_DEBUG("QemuCocoaAppController: applicationDidFinishLaunching\n"); |
|
760 |
|
761 // Display an open dialog box if no argument were passed or |
|
762 // if qemu was launched from the finder ( the Finder passes "-psn" ) |
|
763 if( gArgc <= 1 || strncmp ((char *)gArgv[1], "-psn", 4) == 0) { |
|
764 NSOpenPanel *op = [[NSOpenPanel alloc] init]; |
|
765 [op setPrompt:@"Boot image"]; |
|
766 [op setMessage:@"Select the disk image you want to boot.\n\nHit the \"Cancel\" button to quit"]; |
|
767 [op beginSheetForDirectory:nil file:nil types:[NSArray arrayWithObjects:@"img",@"iso",@"dmg",@"qcow",@"cow",@"cloop",@"vmdk",nil] |
|
768 modalForWindow:normalWindow modalDelegate:self |
|
769 didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:) contextInfo:NULL]; |
|
770 } else { |
|
771 // or Launch Qemu, with the global args |
|
772 [self startEmulationWithArgc:gArgc argv:(char **)gArgv]; |
|
773 } |
|
774 } |
|
775 |
|
776 - (void)applicationWillTerminate:(NSNotification *)aNotification |
|
777 { |
|
778 COCOA_DEBUG("QemuCocoaAppController: applicationWillTerminate\n"); |
|
779 |
|
780 qemu_system_shutdown_request(); |
|
781 exit(0); |
|
782 } |
|
783 |
|
784 - (void)startEmulationWithArgc:(int)argc argv:(char**)argv |
|
785 { |
|
786 COCOA_DEBUG("QemuCocoaAppController: startEmulationWithArgc\n"); |
|
787 |
|
788 int status; |
|
789 status = qemu_main(argc, argv); |
|
790 exit(status); |
|
791 } |
|
792 |
|
793 - (void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo |
|
794 { |
|
795 COCOA_DEBUG("QemuCocoaAppController: openPanelDidEnd\n"); |
|
796 |
|
797 if(returnCode == NSCancelButton) { |
|
798 exit(0); |
|
799 } else if(returnCode == NSOKButton) { |
|
800 char *bin = "qemu"; |
|
801 char *img = (char*)[ [ sheet filename ] cStringUsingEncoding:NSASCIIStringEncoding]; |
|
802 |
|
803 char **argv = (char**)malloc( sizeof(char*)*3 ); |
|
804 |
|
805 asprintf(&argv[0], "%s", bin); |
|
806 asprintf(&argv[1], "-hda"); |
|
807 asprintf(&argv[2], "%s", img); |
|
808 |
|
809 printf("Using argc %d argv %s -hda %s\n", 3, bin, img); |
|
810 |
|
811 [self startEmulationWithArgc:3 argv:(char**)argv]; |
|
812 } |
|
813 } |
|
814 - (void)toggleFullScreen:(id)sender |
|
815 { |
|
816 COCOA_DEBUG("QemuCocoaAppController: toggleFullScreen\n"); |
|
817 |
|
818 [cocoaView toggleFullScreen:sender]; |
|
819 } |
|
820 |
|
821 - (void)showQEMUDoc:(id)sender |
|
822 { |
|
823 COCOA_DEBUG("QemuCocoaAppController: showQEMUDoc\n"); |
|
824 |
|
825 [[NSWorkspace sharedWorkspace] openFile:[NSString stringWithFormat:@"%@/../doc/qemu/qemu-doc.html", |
|
826 [[NSBundle mainBundle] resourcePath]] withApplication:@"Help Viewer"]; |
|
827 } |
|
828 |
|
829 - (void)showQEMUTec:(id)sender |
|
830 { |
|
831 COCOA_DEBUG("QemuCocoaAppController: showQEMUTec\n"); |
|
832 |
|
833 [[NSWorkspace sharedWorkspace] openFile:[NSString stringWithFormat:@"%@/../doc/qemu/qemu-tech.html", |
|
834 [[NSBundle mainBundle] resourcePath]] withApplication:@"Help Viewer"]; |
|
835 } |
|
836 @end |
|
837 |
|
838 |
|
839 |
|
840 // Dock Connection |
|
841 typedef struct CPSProcessSerNum |
|
842 { |
|
843 UInt32 lo; |
|
844 UInt32 hi; |
|
845 } CPSProcessSerNum; |
|
846 |
|
847 extern OSErr CPSGetCurrentProcess( CPSProcessSerNum *psn); |
|
848 extern OSErr CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5); |
|
849 extern OSErr CPSSetFrontProcess( CPSProcessSerNum *psn); |
|
850 |
|
851 int main (int argc, const char * argv[]) { |
|
852 |
|
853 gArgc = argc; |
|
854 gArgv = (char **)argv; |
|
855 CPSProcessSerNum PSN; |
|
856 |
|
857 NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; |
|
858 [NSApplication sharedApplication]; |
|
859 |
|
860 if (!CPSGetCurrentProcess(&PSN)) |
|
861 if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103)) |
|
862 if (!CPSSetFrontProcess(&PSN)) |
|
863 [NSApplication sharedApplication]; |
|
864 |
|
865 // Add menus |
|
866 NSMenu *menu; |
|
867 NSMenuItem *menuItem; |
|
868 |
|
869 [NSApp setMainMenu:[[NSMenu alloc] init]]; |
|
870 |
|
871 // Application menu |
|
872 menu = [[NSMenu alloc] initWithTitle:@""]; |
|
873 [menu addItemWithTitle:@"About QEMU" action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""]; // About QEMU |
|
874 [menu addItem:[NSMenuItem separatorItem]]; //Separator |
|
875 [menu addItemWithTitle:@"Hide QEMU" action:@selector(hide:) keyEquivalent:@"h"]; //Hide QEMU |
|
876 menuItem = (NSMenuItem *)[menu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"]; // Hide Others |
|
877 [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)]; |
|
878 [menu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""]; // Show All |
|
879 [menu addItem:[NSMenuItem separatorItem]]; //Separator |
|
880 [menu addItemWithTitle:@"Quit QEMU" action:@selector(terminate:) keyEquivalent:@"q"]; |
|
881 menuItem = [[NSMenuItem alloc] initWithTitle:@"Apple" action:nil keyEquivalent:@""]; |
|
882 [menuItem setSubmenu:menu]; |
|
883 [[NSApp mainMenu] addItem:menuItem]; |
|
884 [NSApp performSelector:@selector(setAppleMenu:) withObject:menu]; // Workaround (this method is private since 10.4+) |
|
885 |
|
886 // View menu |
|
887 menu = [[NSMenu alloc] initWithTitle:@"View"]; |
|
888 [menu addItem: [[[NSMenuItem alloc] initWithTitle:@"Enter Fullscreen" action:@selector(toggleFullScreen:) keyEquivalent:@"f"] autorelease]]; // Fullscreen |
|
889 menuItem = [[[NSMenuItem alloc] initWithTitle:@"View" action:nil keyEquivalent:@""] autorelease]; |
|
890 [menuItem setSubmenu:menu]; |
|
891 [[NSApp mainMenu] addItem:menuItem]; |
|
892 |
|
893 // Window menu |
|
894 menu = [[NSMenu alloc] initWithTitle:@"Window"]; |
|
895 [menu addItem: [[[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"] autorelease]]; // Miniaturize |
|
896 menuItem = [[[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""] autorelease]; |
|
897 [menuItem setSubmenu:menu]; |
|
898 [[NSApp mainMenu] addItem:menuItem]; |
|
899 [NSApp setWindowsMenu:menu]; |
|
900 |
|
901 // Help menu |
|
902 menu = [[NSMenu alloc] initWithTitle:@"Help"]; |
|
903 [menu addItem: [[[NSMenuItem alloc] initWithTitle:@"QEMU Documentation" action:@selector(showQEMUDoc:) keyEquivalent:@"?"] autorelease]]; // QEMU Help |
|
904 [menu addItem: [[[NSMenuItem alloc] initWithTitle:@"QEMU Technology" action:@selector(showQEMUTec:) keyEquivalent:@""] autorelease]]; // QEMU Help |
|
905 menuItem = [[[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""] autorelease]; |
|
906 [menuItem setSubmenu:menu]; |
|
907 [[NSApp mainMenu] addItem:menuItem]; |
|
908 |
|
909 // Create an Application controller |
|
910 QemuCocoaAppController *appController = [[QemuCocoaAppController alloc] init]; |
|
911 [NSApp setDelegate:appController]; |
|
912 |
|
913 // Start the main event loop |
|
914 [NSApp run]; |
|
915 |
|
916 [appController release]; |
|
917 [pool release]; |
|
918 |
|
919 return 0; |
|
920 } |
|
921 |
|
922 |
|
923 |
|
924 #pragma mark qemu |
|
925 static void cocoa_update(DisplayState *ds, int x, int y, int w, int h) |
|
926 { |
|
927 COCOA_DEBUG("qemu_cocoa: cocoa_update\n"); |
|
928 |
|
929 NSRect rect; |
|
930 if ([cocoaView cdx] == 1.0) { |
|
931 rect = NSMakeRect(x, [cocoaView gscreen].height - y - h, w, h); |
|
932 } else { |
|
933 rect = NSMakeRect( |
|
934 x * [cocoaView cdx], |
|
935 ([cocoaView gscreen].height - y - h) * [cocoaView cdy], |
|
936 w * [cocoaView cdx], |
|
937 h * [cocoaView cdy]); |
|
938 } |
|
939 [cocoaView displayRect:rect]; |
|
940 } |
|
941 |
|
942 static void cocoa_resize(DisplayState *ds, int w, int h) |
|
943 { |
|
944 COCOA_DEBUG("qemu_cocoa: cocoa_resize\n"); |
|
945 |
|
946 [cocoaView resizeContentToWidth:w height:h displayState:ds]; |
|
947 } |
|
948 |
|
949 static void cocoa_refresh(DisplayState *ds) |
|
950 { |
|
951 COCOA_DEBUG("qemu_cocoa: cocoa_refresh\n"); |
|
952 |
|
953 if (kbd_mouse_is_absolute()) { |
|
954 if (![cocoaView isAbsoluteEnabled]) { |
|
955 if ([cocoaView isMouseGrabed]) { |
|
956 [cocoaView ungrabMouse]; |
|
957 } |
|
958 } |
|
959 [cocoaView setAbsoluteEnabled:YES]; |
|
960 } |
|
961 |
|
962 NSDate *distantPast; |
|
963 NSEvent *event; |
|
964 distantPast = [NSDate distantPast]; |
|
965 do { |
|
966 event = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:distantPast |
|
967 inMode: NSDefaultRunLoopMode dequeue:YES]; |
|
968 if (event != nil) { |
|
969 [cocoaView handleEvent:event]; |
|
970 } |
|
971 } while(event != nil); |
|
972 vga_hw_update(); |
|
973 } |
|
974 |
|
975 static void cocoa_cleanup(void) |
|
976 { |
|
977 COCOA_DEBUG("qemu_cocoa: cocoa_cleanup\n"); |
|
978 |
|
979 } |
|
980 |
|
981 void cocoa_display_init(DisplayState *ds, int full_screen) |
|
982 { |
|
983 COCOA_DEBUG("qemu_cocoa: cocoa_display_init\n"); |
|
984 |
|
985 // register vga outpu callbacks |
|
986 ds->dpy_update = cocoa_update; |
|
987 ds->dpy_resize = cocoa_resize; |
|
988 ds->dpy_refresh = cocoa_refresh; |
|
989 |
|
990 // give window a initial Size |
|
991 cocoa_resize(ds, 640, 400); |
|
992 |
|
993 // register cleanup function |
|
994 atexit(cocoa_cleanup); |
|
995 } |