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
46rfbBool rfbNoDimming = FALSE;
47rfbBool rfbNoSleep   = TRUE;
48
49static pthread_mutex_t  dimming_mutex;
50static unsigned long    dim_time;
51static unsigned long    sleep_time;
52static mach_port_t      master_dev_port;
53static io_connect_t     power_mgt;
54static rfbBool initialized            = FALSE;
55static rfbBool dim_time_saved         = FALSE;
56static rfbBool sleep_time_saved       = FALSE;
57
58static int
59saveDimSettings(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
70static int
71restoreDimSettings(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
86static int
87saveSleepSettings(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
98static int
99restoreSleepSettings(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
115int
116rfbDimmingInit(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
147int
148rfbUndim(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
183int
184rfbDimmingShutdown(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
206rfbScreenInfoPtr rfbScreen;
207
208void rfbShutdown(rfbClientPtr cl);
209
210/* some variables to enable special behaviour */
211int startTime = -1, maxSecsToConnect = 0;
212rfbBool 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. */
217static 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
391void
392KbdAddEvent(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
420void
421PtrAddEvent(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
447rfbBool viewOnly = FALSE, sharedMode = FALSE;
448
449void
450ScreenInit(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
482static void
483refreshCallback(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
497void clientGone(rfbClientPtr cl)
498{
499  rfbShutdown(cl);
500}
501
502enum 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
515int 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
548void rfbShutdown(rfbClientPtr cl)
549{
550  rfbScreenCleanup(rfbScreen);
551  rfbDimmingShutdown();
552  exit(0);
553}
554