3 * OSXvnc Copyright (C) 2001 Dan McGuirk <mcguirk@incompleteness.net>.
4 * Original Xvnc code Copyright (C) 1999 AT&T Laboratories Cambridge.
7 * Cut in two parts by Johannes Schindelin (2001): libvncserver and OSXvnc.
10 * This file implements every system specific function for Mac OS X.
12 * It includes the keyboard functions:
14 void KbdAddEvent(down, keySym, cl)
18 void KbdReleaseAllKeys()
20 * the mouse functions:
22 void PtrAddEvent(buttonMask, x, y, cl)
31 #include <ApplicationServices/ApplicationServices.h>
32 #include <Carbon/Carbon.h>
33 /* zlib doesn't like Byte already defined */
38 #include <rfb/keysym.h>
40 #include <IOKit/pwr_mgt/IOPMLib.h>
41 #include <IOKit/pwr_mgt/IOPM.h>
46 rfbBool rfbNoDimming = FALSE;
47 rfbBool rfbNoSleep = TRUE;
49 static pthread_mutex_t dimming_mutex;
50 static unsigned long dim_time;
51 static unsigned long sleep_time;
52 static mach_port_t master_dev_port;
53 static io_connect_t power_mgt;
54 static rfbBool initialized = FALSE;
55 static rfbBool dim_time_saved = FALSE;
56 static rfbBool sleep_time_saved = FALSE;
61 if (IOPMGetAggressiveness(power_mgt,
63 &dim_time) != kIOReturnSuccess)
66 dim_time_saved = TRUE;
71 restoreDimSettings(void)
76 if (IOPMSetAggressiveness(power_mgt,
78 dim_time) != kIOReturnSuccess)
81 dim_time_saved = FALSE;
87 saveSleepSettings(void)
89 if (IOPMGetAggressiveness(power_mgt,
91 &sleep_time) != kIOReturnSuccess)
94 sleep_time_saved = TRUE;
99 restoreSleepSettings(void)
101 if (!sleep_time_saved)
104 if (IOPMSetAggressiveness(power_mgt,
106 sleep_time) != kIOReturnSuccess)
109 sleep_time_saved = FALSE;
118 pthread_mutex_init(&dimming_mutex, NULL);
120 if (IOMasterPort(bootstrap_port, &master_dev_port) != kIOReturnSuccess)
123 if (!(power_mgt = IOPMFindPowerManagement(master_dev_port)))
127 if (saveDimSettings() < 0)
129 if (IOPMSetAggressiveness(power_mgt,
130 kPMMinutesToDim, 0) != kIOReturnSuccess)
135 if (saveSleepSettings() < 0)
137 if (IOPMSetAggressiveness(power_mgt,
138 kPMMinutesToSleep, 0) != kIOReturnSuccess)
152 pthread_mutex_lock(&dimming_mutex);
158 if (saveDimSettings() < 0)
160 if (IOPMSetAggressiveness(power_mgt, kPMMinutesToDim, 0) != kIOReturnSuccess)
162 if (restoreDimSettings() < 0)
167 if (saveSleepSettings() < 0)
169 if (IOPMSetAggressiveness(power_mgt, kPMMinutesToSleep, 0) != kIOReturnSuccess)
171 if (restoreSleepSettings() < 0)
178 pthread_mutex_unlock(&dimming_mutex);
184 rfbDimmingShutdown(void)
191 pthread_mutex_lock(&dimming_mutex);
193 if (restoreDimSettings() < 0)
195 if (sleep_time_saved)
196 if (restoreSleepSettings() < 0)
202 pthread_mutex_unlock(&dimming_mutex);
206 rfbScreenInfoPtr rfbScreen;
208 void rfbShutdown(rfbClientPtr cl);
210 /* some variables to enable special behaviour */
211 int startTime = -1, maxSecsToConnect = 0;
212 rfbBool disconnectAfterFirstClient = TRUE;
214 /* Where do I get the "official" list of Mac key codes?
215 Ripped these out of a Mac II emulator called Basilisk II
216 that I found on the net. */
217 static int keyTable[] = {
285 XK_exclam, 18, /* ! */
287 XK_numbersign, 20, /* # */
288 XK_dollar, 21, /* $ */
289 XK_percent, 23, /* % */
290 XK_asciicircum, 22, /* ^ */
291 XK_ampersand, 26, /* & */
292 XK_asterisk, 28, /* * */
293 XK_parenleft, 25, /* ( */
294 XK_parenright, 29, /* ) */
295 XK_minus, 27, /* - */
296 XK_underscore, 27, /* _ */
297 XK_equal, 24, /* = */
299 XK_grave, 10, /* ` */ /* XXX ? */
300 XK_asciitilde, 10, /* ~ */
301 XK_bracketleft, 33, /* [ */
302 XK_braceleft, 33, /* { */
303 XK_bracketright, 30, /* ] */
304 XK_braceright, 30, /* } */
305 XK_semicolon, 41, /* ; */
306 XK_colon, 41, /* : */
307 XK_apostrophe, 39, /* ' */
308 XK_quotedbl, 39, /* " */
309 XK_comma, 43, /* , */
311 XK_period, 47, /* . */
312 XK_greater, 47, /* > */
313 XK_slash, 44, /* / */
314 XK_question, 44, /* ? */
315 XK_backslash, 42, /* \ */
319 XK_space, 49, /* Space */
320 XK_Return, 36, /* Return */
321 XK_Delete, 117, /* Delete */
322 XK_Tab, 48, /* Tab */
323 XK_Escape, 53, /* Esc */
324 XK_Caps_Lock, 57, /* Caps Lock */
325 XK_Num_Lock, 71, /* Num Lock */
326 XK_Scroll_Lock, 107, /* Scroll Lock */
327 XK_Pause, 113, /* Pause */
328 XK_BackSpace, 51, /* Backspace */
329 XK_Insert, 114, /* Insert */
331 /* Cursor movement */
332 XK_Up, 126, /* Cursor Up */
333 XK_Down, 125, /* Cursor Down */
334 XK_Left, 123, /* Cursor Left */
335 XK_Right, 124, /* Cursor Right */
336 XK_Page_Up, 116, /* Page Up */
337 XK_Page_Down, 121, /* Page Down */
338 XK_Home, 115, /* Home */
339 XK_End, 119, /* End */
342 XK_KP_0, 82, /* KP 0 */
343 XK_KP_1, 83, /* KP 1 */
344 XK_KP_2, 84, /* KP 2 */
345 XK_KP_3, 85, /* KP 3 */
346 XK_KP_4, 86, /* KP 4 */
347 XK_KP_5, 87, /* KP 5 */
348 XK_KP_6, 88, /* KP 6 */
349 XK_KP_7, 89, /* KP 7 */
350 XK_KP_8, 91, /* KP 8 */
351 XK_KP_9, 92, /* KP 9 */
352 XK_KP_Enter, 76, /* KP Enter */
353 XK_KP_Decimal, 65, /* KP . */
354 XK_KP_Add, 69, /* KP + */
355 XK_KP_Subtract, 78, /* KP - */
356 XK_KP_Multiply, 67, /* KP * */
357 XK_KP_Divide, 75, /* KP / */
369 XK_F10, 109, /* F10 */
370 XK_F11, 103, /* F11 */
371 XK_F12, 111, /* F12 */
374 XK_Shift_L, 56, /* Shift Left */
375 XK_Shift_R, 56, /* Shift Right */
376 XK_Control_L, 59, /* Ctrl Left */
377 XK_Control_R, 59, /* Ctrl Right */
378 XK_Meta_L, 58, /* Logo Left (-> Option) */
379 XK_Meta_R, 58, /* Logo Right (-> Option) */
380 XK_Alt_L, 55, /* Alt Left (-> Command) */
381 XK_Alt_R, 55, /* Alt Right (-> Command) */
383 /* Weirdness I can't figure out */
385 XK_3270_PrintScreen, 105, /* PrintScrn */
386 ??? 94, 50, /* International */
387 XK_Menu, 50, /* Menu (-> International) */
392 KbdAddEvent(rfbBool down, rfbKeySym keySym, struct _rfbClientRec* cl)
395 CGKeyCode keyCode = -1;
398 if(((int)cl->clientData)==-1) return; /* viewOnly */
402 for (i = 0; i < (sizeof(keyTable) / sizeof(int)); i += 2) {
403 if (keyTable[i] == keySym) {
404 keyCode = keyTable[i+1];
411 rfbErr("warning: couldn't figure out keycode for X keysym %d (0x%x)\n",
412 (int)keySym, (int)keySym);
414 /* Hopefully I can get away with not specifying a CGCharCode.
415 (Why would you need both?) */
416 CGPostKeyboardEvent((CGCharCode)0, keyCode, down);
421 PtrAddEvent(buttonMask, x, y, cl)
429 if(((int)cl->clientData)==-1) return; /* viewOnly */
436 CGPostMouseEvent(position, TRUE, 8,
437 (buttonMask & (1 << 0)) ? TRUE : FALSE,
438 (buttonMask & (1 << 1)) ? TRUE : FALSE,
439 (buttonMask & (1 << 2)) ? TRUE : FALSE,
440 (buttonMask & (1 << 3)) ? TRUE : FALSE,
441 (buttonMask & (1 << 4)) ? TRUE : FALSE,
442 (buttonMask & (1 << 5)) ? TRUE : FALSE,
443 (buttonMask & (1 << 6)) ? TRUE : FALSE,
444 (buttonMask & (1 << 7)) ? TRUE : FALSE);
447 rfbBool viewOnly = FALSE, sharedMode = FALSE;
450 ScreenInit(int argc, char**argv)
452 int bitsPerSample=CGDisplayBitsPerSample(kCGDirectMainDisplay);
453 rfbScreen = rfbGetScreen(&argc,argv,
454 CGDisplayPixelsWide(kCGDirectMainDisplay),
455 CGDisplayPixelsHigh(kCGDirectMainDisplay),
457 CGDisplaySamplesPerPixel(kCGDirectMainDisplay),4);
458 rfbScreen->serverFormat.redShift = bitsPerSample*2;
459 rfbScreen->serverFormat.greenShift = bitsPerSample*1;
460 rfbScreen->serverFormat.blueShift = 0;
462 gethostname(rfbScreen->thisHost, 255);
463 rfbScreen->paddedWidthInBytes = CGDisplayBytesPerRow(kCGDirectMainDisplay);
464 rfbScreen->frameBuffer =
465 (char *)CGDisplayBaseAddress(kCGDirectMainDisplay);
467 /* we cannot write to the frame buffer */
468 rfbScreen->cursor = NULL;
470 rfbScreen->ptrAddEvent = PtrAddEvent;
471 rfbScreen->kbdAddEvent = KbdAddEvent;
474 rfbScreen->alwaysShared = TRUE;
477 rfbInitServer(rfbScreen);
481 refreshCallback(CGRectCount count, const CGRect *rectArray, void *ignore)
485 if(startTime>0 && time(0)>startTime+maxSecsToConnect)
488 for (i = 0; i < count; i++)
489 rfbMarkRectAsModified(rfbScreen,
490 rectArray[i].origin.x,rectArray[i].origin.y,
491 rectArray[i].origin.x + rectArray[i].size.width,
492 rectArray[i].origin.y + rectArray[i].size.height);
495 void clientGone(rfbClientPtr cl)
500 enum rfbNewClientAction newClient(rfbClientPtr cl)
502 if(startTime>0 && time(0)>startTime+maxSecsToConnect)
505 if(disconnectAfterFirstClient)
506 cl->clientGoneHook = clientGone;
508 cl->clientData=(void*)((viewOnly)?-1:0);
510 return(RFB_CLIENT_ACCEPT);
513 int main(int argc,char *argv[])
517 for(i=argc-1;i>0;i--)
518 if(i<argc-1 && strcmp(argv[i],"-wait4client")==0) {
519 maxSecsToConnect = atoi(argv[i+1])/1000;
521 } else if(strcmp(argv[i],"-runforever")==0) {
522 disconnectAfterFirstClient = FALSE;
523 } else if(strcmp(argv[i],"-viewonly")==0) {
525 } else if(strcmp(argv[i],"-shared")==0) {
531 ScreenInit(argc,argv);
532 rfbScreen->newClientHook = newClient;
534 /* enter background event loop */
535 rfbRunEventLoop(rfbScreen,40,TRUE);
537 /* enter OS X loop */
538 CGRegisterScreenRefreshCallback(refreshCallback, NULL);
539 RunApplicationEventLoop();
541 rfbDimmingShutdown();
543 return(0); /* never ... */
546 void rfbShutdown(rfbClientPtr cl)
548 rfbScreenCleanup(rfbScreen);
549 rfbDimmingShutdown();