cocoa.m 38 KB

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