add libvncserver
[presencevnc] / libvnc / examples / mac.c
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
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
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
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
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
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
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
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
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
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 
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   rfbScreen->serverFormat.redShift = bitsPerSample*2;
459   rfbScreen->serverFormat.greenShift = bitsPerSample*1;
460   rfbScreen->serverFormat.blueShift = 0;
461
462   gethostname(rfbScreen->thisHost, 255);
463   rfbScreen->paddedWidthInBytes = CGDisplayBytesPerRow(kCGDirectMainDisplay);
464   rfbScreen->frameBuffer =
465     (char *)CGDisplayBaseAddress(kCGDirectMainDisplay);
466
467   /* we cannot write to the frame buffer */
468   rfbScreen->cursor = NULL;
469
470   rfbScreen->ptrAddEvent = PtrAddEvent;
471   rfbScreen->kbdAddEvent = KbdAddEvent;
472
473   if(sharedMode) {
474     rfbScreen->alwaysShared = TRUE;
475   }
476
477   rfbInitServer(rfbScreen);
478 }
479
480 static void 
481 refreshCallback(CGRectCount count, const CGRect *rectArray, void *ignore)
482 {
483   int i;
484
485   if(startTime>0 && time(0)>startTime+maxSecsToConnect)
486     rfbShutdown(0);
487
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);
493 }
494
495 void clientGone(rfbClientPtr cl)
496 {
497   rfbShutdown(cl);
498 }
499
500 enum rfbNewClientAction newClient(rfbClientPtr cl)
501 {
502   if(startTime>0 && time(0)>startTime+maxSecsToConnect)
503     rfbShutdown(cl);
504
505   if(disconnectAfterFirstClient)
506     cl->clientGoneHook = clientGone;
507
508   cl->clientData=(void*)((viewOnly)?-1:0);
509
510   return(RFB_CLIENT_ACCEPT);
511 }
512
513 int main(int argc,char *argv[])
514 {
515   int i;
516
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;
520       startTime = time(0);
521     } else if(strcmp(argv[i],"-runforever")==0) {
522       disconnectAfterFirstClient = FALSE;
523     } else if(strcmp(argv[i],"-viewonly")==0) {
524       viewOnly=TRUE;
525     } else if(strcmp(argv[i],"-shared")==0) {
526       sharedMode=TRUE;
527     }
528
529   rfbDimmingInit();
530
531   ScreenInit(argc,argv);
532   rfbScreen->newClientHook = newClient;
533
534   /* enter background event loop */
535   rfbRunEventLoop(rfbScreen,40,TRUE);
536
537   /* enter OS X loop */
538   CGRegisterScreenRefreshCallback(refreshCallback, NULL);
539   RunApplicationEventLoop();
540
541   rfbDimmingShutdown();
542
543   return(0); /* never ... */
544 }
545
546 void rfbShutdown(rfbClientPtr cl)
547 {
548   rfbScreenCleanup(rfbScreen);
549   rfbDimmingShutdown();
550   exit(0);
551 }