1
2 /*
3 * OSXvnc Copyright (C) 2001 Dan McGuirk <mcguirk@incompleteness.net>.
4 * Original Xvnc code Copyright (C) 1999 AT&T Laboratories Cambridge.
5 * All Rights Reserved.
6 *
7 * Cut in two parts by Johannes Schindelin (2001): libvncserver and OSXvnc.
8 *
9 *
10 * This file implements every system specific function for Mac OS X.
11 *
12 * It includes the keyboard functions:
13 *
14 void KbdAddEvent(down, keySym, cl)
15 rfbBool down;
16 rfbKeySym keySym;
17 rfbClientPtr cl;
18 void KbdReleaseAllKeys()
19 *
20 * the mouse functions:
21 *
22 void PtrAddEvent(buttonMask, x, y, cl)
23 int buttonMask;
24 int x;
25 int y;
26 rfbClientPtr cl;
27 *
28 */
29
30 #include <unistd.h>
31 #include <ApplicationServices/ApplicationServices.h>
32 #include <Carbon/Carbon.h>
33 /* zlib doesn't like Byte already defined */
34 #undef Byte
35 #undef TRUE
36 #undef rfbBool
37 #include <rfb/rfb.h>
38 #include <rfb/keysym.h>
39
40 #include <IOKit/pwr_mgt/IOPMLib.h>
41 #include <IOKit/pwr_mgt/IOPM.h>
42 #include <stdio.h>
43 #include <signal.h>
44 #include <pthread.h>
45
46 rfbBool rfbNoDimming = FALSE;
47 rfbBool rfbNoSleep = TRUE;
48
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;
57
58 static int
saveDimSettings(void)59 saveDimSettings(void)
60 {
61 if (IOPMGetAggressiveness(power_mgt,
62 kPMMinutesToDim,
63 &dim_time) != kIOReturnSuccess)
64 return -1;
65
66 dim_time_saved = TRUE;
67 return 0;
68 }
69
70 static int
restoreDimSettings(void)71 restoreDimSettings(void)
72 {
73 if (!dim_time_saved)
74 return -1;
75
76 if (IOPMSetAggressiveness(power_mgt,
77 kPMMinutesToDim,
78 dim_time) != kIOReturnSuccess)
79 return -1;
80
81 dim_time_saved = FALSE;
82 dim_time = 0;
83 return 0;
84 }
85
86 static int
saveSleepSettings(void)87 saveSleepSettings(void)
88 {
89 if (IOPMGetAggressiveness(power_mgt,
90 kPMMinutesToSleep,
91 &sleep_time) != kIOReturnSuccess)
92 return -1;
93
94 sleep_time_saved = TRUE;
95 return 0;
96 }
97
98 static int
restoreSleepSettings(void)99 restoreSleepSettings(void)
100 {
101 if (!sleep_time_saved)
102 return -1;
103
104 if (IOPMSetAggressiveness(power_mgt,
105 kPMMinutesToSleep,
106 sleep_time) != kIOReturnSuccess)
107 return -1;
108
109 sleep_time_saved = FALSE;
110 sleep_time = 0;
111 return 0;
112 }
113
114
115 int
rfbDimmingInit(void)116 rfbDimmingInit(void)
117 {
118 pthread_mutex_init(&dimming_mutex, NULL);
119
120 if (IOMasterPort(bootstrap_port, &master_dev_port) != kIOReturnSuccess)
121 return -1;
122
123 if (!(power_mgt = IOPMFindPowerManagement(master_dev_port)))
124 return -1;
125
126 if (rfbNoDimming) {
127 if (saveDimSettings() < 0)
128 return -1;
129 if (IOPMSetAggressiveness(power_mgt,
130 kPMMinutesToDim, 0) != kIOReturnSuccess)
131 return -1;
132 }
133
134 if (rfbNoSleep) {
135 if (saveSleepSettings() < 0)
136 return -1;
137 if (IOPMSetAggressiveness(power_mgt,
138 kPMMinutesToSleep, 0) != kIOReturnSuccess)
139 return -1;
140 }
141
142 initialized = TRUE;
143 return 0;
144 }
145
146
147 int
rfbUndim(void)148 rfbUndim(void)
149 {
150 int result = -1;
151
152 pthread_mutex_lock(&dimming_mutex);
153
154 if (!initialized)
155 goto DONE;
156
157 if (!rfbNoDimming) {
158 if (saveDimSettings() < 0)
159 goto DONE;
160 if (IOPMSetAggressiveness(power_mgt, kPMMinutesToDim, 0) != kIOReturnSuccess)
161 goto DONE;
162 if (restoreDimSettings() < 0)
163 goto DONE;
164 }
165
166 if (!rfbNoSleep) {
167 if (saveSleepSettings() < 0)
168 goto DONE;
169 if (IOPMSetAggressiveness(power_mgt, kPMMinutesToSleep, 0) != kIOReturnSuccess)
170 goto DONE;
171 if (restoreSleepSettings() < 0)
172 goto DONE;
173 }
174
175 result = 0;
176
177 DONE:
178 pthread_mutex_unlock(&dimming_mutex);
179 return result;
180 }
181
182
183 int
rfbDimmingShutdown(void)184 rfbDimmingShutdown(void)
185 {
186 int result = -1;
187
188 if (!initialized)
189 goto DONE;
190
191 pthread_mutex_lock(&dimming_mutex);
192 if (dim_time_saved)
193 if (restoreDimSettings() < 0)
194 goto DONE;
195 if (sleep_time_saved)
196 if (restoreSleepSettings() < 0)
197 goto DONE;
198
199 result = 0;
200
201 DONE:
202 pthread_mutex_unlock(&dimming_mutex);
203 return result;
204 }
205
206 rfbScreenInfoPtr rfbScreen;
207
208 void rfbShutdown(rfbClientPtr cl);
209
210 /* some variables to enable special behaviour */
211 int startTime = -1, maxSecsToConnect = 0;
212 rfbBool disconnectAfterFirstClient = TRUE;
213
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[] = {
218 /* The alphabet */
219 XK_A, 0, /* A */
220 XK_B, 11, /* B */
221 XK_C, 8, /* C */
222 XK_D, 2, /* D */
223 XK_E, 14, /* E */
224 XK_F, 3, /* F */
225 XK_G, 5, /* G */
226 XK_H, 4, /* H */
227 XK_I, 34, /* I */
228 XK_J, 38, /* J */
229 XK_K, 40, /* K */
230 XK_L, 37, /* L */
231 XK_M, 46, /* M */
232 XK_N, 45, /* N */
233 XK_O, 31, /* O */
234 XK_P, 35, /* P */
235 XK_Q, 12, /* Q */
236 XK_R, 15, /* R */
237 XK_S, 1, /* S */
238 XK_T, 17, /* T */
239 XK_U, 32, /* U */
240 XK_V, 9, /* V */
241 XK_W, 13, /* W */
242 XK_X, 7, /* X */
243 XK_Y, 16, /* Y */
244 XK_Z, 6, /* Z */
245 XK_a, 0, /* a */
246 XK_b, 11, /* b */
247 XK_c, 8, /* c */
248 XK_d, 2, /* d */
249 XK_e, 14, /* e */
250 XK_f, 3, /* f */
251 XK_g, 5, /* g */
252 XK_h, 4, /* h */
253 XK_i, 34, /* i */
254 XK_j, 38, /* j */
255 XK_k, 40, /* k */
256 XK_l, 37, /* l */
257 XK_m, 46, /* m */
258 XK_n, 45, /* n */
259 XK_o, 31, /* o */
260 XK_p, 35, /* p */
261 XK_q, 12, /* q */
262 XK_r, 15, /* r */
263 XK_s, 1, /* s */
264 XK_t, 17, /* t */
265 XK_u, 32, /* u */
266 XK_v, 9, /* v */
267 XK_w, 13, /* w */
268 XK_x, 7, /* x */
269 XK_y, 16, /* y */
270 XK_z, 6, /* z */
271
272 /* Numbers */
273 XK_0, 29, /* 0 */
274 XK_1, 18, /* 1 */
275 XK_2, 19, /* 2 */
276 XK_3, 20, /* 3 */
277 XK_4, 21, /* 4 */
278 XK_5, 23, /* 5 */
279 XK_6, 22, /* 6 */
280 XK_7, 26, /* 7 */
281 XK_8, 28, /* 8 */
282 XK_9, 25, /* 9 */
283
284 /* Symbols */
285 XK_exclam, 18, /* ! */
286 XK_at, 19, /* @ */
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, /* = */
298 XK_plus, 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, /* , */
310 XK_less, 43, /* < */
311 XK_period, 47, /* . */
312 XK_greater, 47, /* > */
313 XK_slash, 44, /* / */
314 XK_question, 44, /* ? */
315 XK_backslash, 42, /* \ */
316 XK_bar, 42, /* | */
317
318 /* "Special" keys */
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 */
330
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 */
340
341 /* Numeric keypad */
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 / */
358
359 /* Function keys */
360 XK_F1, 122, /* F1 */
361 XK_F2, 120, /* F2 */
362 XK_F3, 99, /* F3 */
363 XK_F4, 118, /* F4 */
364 XK_F5, 96, /* F5 */
365 XK_F6, 97, /* F6 */
366 XK_F7, 98, /* F7 */
367 XK_F8, 100, /* F8 */
368 XK_F9, 101, /* F9 */
369 XK_F10, 109, /* F10 */
370 XK_F11, 103, /* F11 */
371 XK_F12, 111, /* F12 */
372
373 /* Modifier keys */
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) */
382
383 /* Weirdness I can't figure out */
384 #if 0
385 XK_3270_PrintScreen, 105, /* PrintScrn */
386 ??? 94, 50, /* International */
387 XK_Menu, 50, /* Menu (-> International) */
388 #endif
389 };
390
391 void
KbdAddEvent(rfbBool down,rfbKeySym keySym,struct _rfbClientRec * cl)392 KbdAddEvent(rfbBool down, rfbKeySym keySym, struct _rfbClientRec* cl)
393 {
394 int i;
395 CGKeyCode keyCode = -1;
396 int found = 0;
397
398 if(((int)cl->clientData)==-1) return; /* viewOnly */
399
400 rfbUndim();
401
402 for (i = 0; i < (sizeof(keyTable) / sizeof(int)); i += 2) {
403 if (keyTable[i] == keySym) {
404 keyCode = keyTable[i+1];
405 found = 1;
406 break;
407 }
408 }
409
410 if (!found) {
411 rfbErr("warning: couldn't figure out keycode for X keysym %d (0x%x)\n",
412 (int)keySym, (int)keySym);
413 } else {
414 /* Hopefully I can get away with not specifying a CGCharCode.
415 (Why would you need both?) */
416 CGPostKeyboardEvent((CGCharCode)0, keyCode, down);
417 }
418 }
419
420 void
PtrAddEvent(buttonMask,x,y,cl)421 PtrAddEvent(buttonMask, x, y, cl)
422 int buttonMask;
423 int x;
424 int y;
425 rfbClientPtr cl;
426 {
427 CGPoint position;
428
429 if(((int)cl->clientData)==-1) return; /* viewOnly */
430
431 rfbUndim();
432
433 position.x = x;
434 position.y = y;
435
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);
445 }
446
447 rfbBool viewOnly = FALSE, sharedMode = FALSE;
448
449 void
ScreenInit(int argc,char ** argv)450 ScreenInit(int argc, char**argv)
451 {
452 int bitsPerSample=CGDisplayBitsPerSample(kCGDirectMainDisplay);
453 rfbScreen = rfbGetScreen(&argc,argv,
454 CGDisplayPixelsWide(kCGDirectMainDisplay),
455 CGDisplayPixelsHigh(kCGDirectMainDisplay),
456 bitsPerSample,
457 CGDisplaySamplesPerPixel(kCGDirectMainDisplay),4);
458 if(!rfbScreen)
459 exit(0);
460 rfbScreen->serverFormat.redShift = bitsPerSample*2;
461 rfbScreen->serverFormat.greenShift = bitsPerSample*1;
462 rfbScreen->serverFormat.blueShift = 0;
463
464 gethostname(rfbScreen->thisHost, 255);
465 rfbScreen->paddedWidthInBytes = CGDisplayBytesPerRow(kCGDirectMainDisplay);
466 rfbScreen->frameBuffer =
467 (char *)CGDisplayBaseAddress(kCGDirectMainDisplay);
468
469 /* we cannot write to the frame buffer */
470 rfbScreen->cursor = NULL;
471
472 rfbScreen->ptrAddEvent = PtrAddEvent;
473 rfbScreen->kbdAddEvent = KbdAddEvent;
474
475 if(sharedMode) {
476 rfbScreen->alwaysShared = TRUE;
477 }
478
479 rfbInitServer(rfbScreen);
480 }
481
482 static void
refreshCallback(CGRectCount count,const CGRect * rectArray,void * ignore)483 refreshCallback(CGRectCount count, const CGRect *rectArray, void *ignore)
484 {
485 int i;
486
487 if(startTime>0 && time(0)>startTime+maxSecsToConnect)
488 rfbShutdown(0);
489
490 for (i = 0; i < count; i++)
491 rfbMarkRectAsModified(rfbScreen,
492 rectArray[i].origin.x,rectArray[i].origin.y,
493 rectArray[i].origin.x + rectArray[i].size.width,
494 rectArray[i].origin.y + rectArray[i].size.height);
495 }
496
clientGone(rfbClientPtr cl)497 void clientGone(rfbClientPtr cl)
498 {
499 rfbShutdown(cl);
500 }
501
newClient(rfbClientPtr cl)502 enum rfbNewClientAction newClient(rfbClientPtr cl)
503 {
504 if(startTime>0 && time(0)>startTime+maxSecsToConnect)
505 rfbShutdown(cl);
506
507 if(disconnectAfterFirstClient)
508 cl->clientGoneHook = clientGone;
509
510 cl->clientData=(void*)((viewOnly)?-1:0);
511
512 return(RFB_CLIENT_ACCEPT);
513 }
514
main(int argc,char * argv[])515 int main(int argc,char *argv[])
516 {
517 int i;
518
519 for(i=argc-1;i>0;i--)
520 if(i<argc-1 && strcmp(argv[i],"-wait4client")==0) {
521 maxSecsToConnect = atoi(argv[i+1])/1000;
522 startTime = time(0);
523 } else if(strcmp(argv[i],"-runforever")==0) {
524 disconnectAfterFirstClient = FALSE;
525 } else if(strcmp(argv[i],"-viewonly")==0) {
526 viewOnly=TRUE;
527 } else if(strcmp(argv[i],"-shared")==0) {
528 sharedMode=TRUE;
529 }
530
531 rfbDimmingInit();
532
533 ScreenInit(argc,argv);
534 rfbScreen->newClientHook = newClient;
535
536 /* enter background event loop */
537 rfbRunEventLoop(rfbScreen,40,TRUE);
538
539 /* enter OS X loop */
540 CGRegisterScreenRefreshCallback(refreshCallback, NULL);
541 RunApplicationEventLoop();
542
543 rfbDimmingShutdown();
544
545 return(0); /* never ... */
546 }
547
rfbShutdown(rfbClientPtr cl)548 void rfbShutdown(rfbClientPtr cl)
549 {
550 rfbScreenCleanup(rfbScreen);
551 rfbDimmingShutdown();
552 exit(0);
553 }
554