blob: 34126f4459677e021e8efb1552086b58cd78fe19 [file] [log] [blame]
San Mehata430b2b2014-09-23 08:30:51 -07001/*
2 Copyright (C) 2002-2010 Karl J. Runge <runge@karlrunge.com>
3 All rights reserved.
4
5This file is part of x11vnc.
6
7x11vnc is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 2 of the License, or (at
10your option) any later version.
11
12x11vnc is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with x11vnc; if not, write to the Free Software
19Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA
20or see <http://www.gnu.org/licenses/>.
21
22In addition, as a special exception, Karl J. Runge
23gives permission to link the code of its release of x11vnc with the
24OpenSSL project's "OpenSSL" library (or with modified versions of it
25that use the same license as the "OpenSSL" library), and distribute
26the linked executables. You must obey the GNU General Public License
27in all respects for all of the code used other than "OpenSSL". If you
28modify this file, you may extend this exception to your version of the
29file, but you are not obligated to do so. If you do not wish to do
30so, delete this exception statement from your version.
31*/
32
33/* -- macosx.c -- */
34
35#include "rfb/rfbconfig.h"
36#if (defined(__MACH__) && defined(__APPLE__) && defined(LIBVNCSERVER_HAVE_MACOSX_NATIVE_DISPLAY))
37
38#define DOMAC 1
39
40#else
41
42#define DOMAC 0
43
44#endif
45
46#include "x11vnc.h"
47#include "cleanup.h"
48#include "scan.h"
49#include "screen.h"
50#include "pointer.h"
51#include "allowed_input_t.h"
52#include "keyboard.h"
53#include "cursor.h"
54#include "connections.h"
55#include "macosxCG.h"
56#include "macosxCGP.h"
57#include "macosxCGS.h"
58
59void macosx_log(char *);
60char *macosx_console_guess(char *str, int *fd);
61void macosx_key_command(rfbBool down, rfbKeySym keysym, rfbClientPtr client);
62void macosx_pointer_command(int mask, int x, int y, rfbClientPtr client);
63char *macosx_get_fb_addr(void);
64int macosx_get_cursor(void);
65int macosx_get_cursor_pos(int *, int *);
66void macosx_send_sel(char *, int);
67void macosx_set_sel(char *, int);
68int macosx_valid_window(Window, XWindowAttributes*);
69
70Status macosx_xquerytree(Window w, Window *root_return, Window *parent_return,
71 Window **children_return, unsigned int *nchildren_return);
72int macosx_get_wm_frame_pos(int *px, int *py, int *x, int *y, int *w, int *h,
73 Window *frame, Window *win);
74
75void macosx_add_mapnotify(Window win, int level, int map);
76void macosx_add_create(Window win, int level);
77void macosx_add_destroy(Window win, int level);
78void macosx_add_visnotify(Window win, int level, int obscured);
79int macosx_checkevent(XEvent *ev);
80
81void macosx_log(char *str) {
82 rfbLog(str);
83}
84
85#if (! DOMAC)
86
87void macosx_event_loop(void) {
88 return;
89}
90char *macosx_console_guess(char *str, int *fd) {
91 if (!str || !fd) {}
92 return NULL;
93}
94void macosx_key_command(rfbBool down, rfbKeySym keysym, rfbClientPtr client) {
95 if (!down || !keysym || !client) {}
96 return;
97}
98void macosx_pointer_command(int mask, int x, int y, rfbClientPtr client) {
99 if (!mask || !x || !y || !client) {}
100 return;
101}
102char *macosx_get_fb_addr(void) {
103 return NULL;
104}
105int macosx_get_cursor(void) {
106 return 0;
107}
108int macosx_get_cursor_pos(int *x, int *y) {
109 if (!x || !y) {}
110 return 0;
111}
112void macosx_send_sel(char * str, int len) {
113 if (!str || !len) {}
114 return;
115}
116void macosx_set_sel(char * str, int len) {
117 if (!str || !len) {}
118 return;
119}
120int macosx_valid_window(Window w, XWindowAttributes* a) {
121 if (!w || !a) {}
122 return 0;
123}
124Status macosx_xquerytree(Window w, Window *root_return, Window *parent_return,
125 Window **children_return, unsigned int *nchildren_return) {
126 if (!w || !root_return || !parent_return || !children_return || !nchildren_return) {}
127 return (Status) 0;
128}
129void macosx_add_mapnotify(Window win, int level, int map) {
130 if (!win || !level || !map) {}
131 return;
132}
133void macosx_add_create(Window win, int level) {
134 if (!win || !level) {}
135 return;
136}
137void macosx_add_destroy(Window win, int level) {
138 if (!win || !level) {}
139 return;
140}
141void macosx_add_visnotify(Window win, int level, int obscured) {
142 if (!win || !level || !obscured) {}
143 return;
144}
145
146int macosx_checkevent(XEvent *ev) {
147 if (!ev) {}
148 return 0;
149}
150
151
152#else
153
154void macosx_event_loop(void) {
155 macosxCG_event_loop();
156}
157
158char *macosx_get_fb_addr(void) {
159 macosxCG_init();
160 return macosxCG_get_fb_addr();
161}
162
163int macosx_opengl_get_width(void);
164int macosx_opengl_get_height(void);
165int macosx_opengl_get_bpp(void);
166int macosx_opengl_get_bps(void);
167int macosx_opengl_get_spp(void);
168
169char *macosx_console_guess(char *str, int *fd) {
170 char *q, *in = strdup(str);
171 char *atparms = NULL, *file = NULL;
172
173 macosxCG_init();
174
175 if (strstr(in, "console") != in) {
176 rfbLog("console_guess: unrecognized console/fb format: %s\n", str);
177 free(in);
178 return NULL;
179 }
180
181 *fd = -1;
182
183 q = strrchr(in, '@');
184 if (q) {
185 atparms = strdup(q+1);
186 *q = '\0';
187 }
188 q = strrchr(in, ':');
189 if (q) {
190 file = strdup(q+1);
191 *q = '\0';
192 }
193 if (! file || file[0] == '\0') {
194 file = strdup("/dev/null");
195 }
196 rfbLog("console_guess: file is %s\n", file);
197
198 if (! pipeinput_str) {
199 pipeinput_str = strdup("MACOSX");
200 initialize_pipeinput();
201 }
202
203 if (! atparms) {
204 int w, h, b, bps, dep;
205 unsigned long rm = 0, gm = 0, bm = 0;
206
207 if (macosx_read_opengl) {
208 w = macosx_opengl_get_width();
209 h = macosx_opengl_get_height();
210 b = macosx_opengl_get_bpp();
211
212 bps = macosx_opengl_get_bps();
213 dep = macosx_opengl_get_spp() * bps;
214
215 } else {
216 w = macosxCG_CGDisplayPixelsWide();
217 h = macosxCG_CGDisplayPixelsHigh();
218 b = macosxCG_CGDisplayBitsPerPixel();
219
220 bps = macosxCG_CGDisplayBitsPerSample();
221 dep = macosxCG_CGDisplaySamplesPerPixel() * bps;
222 }
223
224 rm = (1 << bps) - 1;
225 gm = (1 << bps) - 1;
226 bm = (1 << bps) - 1;
227 rm = rm << 2 * bps;
228 gm = gm << 1 * bps;
229 bm = bm << 0 * bps;
230
231 if (b == 8 && rm == 0xff && gm == 0xff && bm == 0xff) {
232 /* I don't believe it... */
233 rm = 0x07;
234 gm = 0x38;
235 bm = 0xc0;
236 }
237
238 /* @66666x66666x32:0xffffffff:... */
239 atparms = (char *) malloc(200);
240 sprintf(atparms, "%dx%dx%d:%lx/%lx/%lx", w, h, b, rm, gm, bm);
241 }
242 if (atparms) {
243 int gw, gh, gb;
244 if (sscanf(atparms, "%dx%dx%d", &gw, &gh, &gb) == 3) {
245 fb_x = gw;
246 fb_y = gh;
247 fb_b = gb;
248 }
249 }
250 if (! atparms) {
251 rfbLog("console_guess: could not get @ parameters.\n");
252 return NULL;
253 }
254
255 q = (char *) malloc(strlen("map:macosx:") + strlen(file) + 1 + strlen(atparms) + 1);
256 sprintf(q, "map:macosx:%s@%s", file, atparms);
257 free(atparms);
258 return q;
259}
260
261Window macosx_click_frame = None;
262
263void macosx_pointer_command(int mask, int x, int y, rfbClientPtr client) {
264 allowed_input_t input;
265 static int last_mask = 0;
266 int rc;
267
268 if (0) fprintf(stderr, "macosx_pointer_command: %d %d - %d\n", x, y, mask);
269
270 if (mask >= 0) {
271 got_pointer_calls++;
272 }
273
274 if (view_only) {
275 return;
276 }
277
278 get_allowed_input(client, &input);
279
280 if (! input.motion || ! input.button) {
281 /* XXX fix me with last_x, last_y, etc. */
282 return;
283 }
284
285 if (mask >= 0) {
286 got_user_input++;
287 got_pointer_input++;
288 last_pointer_client = client;
289 last_pointer_time = time(NULL);
290 }
291 if (last_mask != mask) {
292 if (0) fprintf(stderr, "about to inject mask change %d -> %d: %.4f\n", last_mask, mask, dnowx());
293 if (mask) {
294 int px, py, x, y, w, h;
295 macosx_click_frame = None;
296 if (!macosx_get_wm_frame_pos(&px, &py, &x, &y, &w, &h, &macosx_click_frame, NULL)) {
297 macosx_click_frame = None;
298 }
299 }
300 }
301
302 macosxCG_pointer_inject(mask, x, y);
303
304 if (cursor_x != x || cursor_y != y) {
305 last_pointer_motion_time = dnow();
306 }
307
308 cursor_x = x;
309 cursor_y = y;
310
311 if (last_mask != mask) {
312 last_pointer_click_time = dnow();
313 if (ncache > 0) {
314 /* XXX Y */
315 int i;
316if (0) fprintf(stderr, "about to get all windows: %.4f\n", dnowx());
317 for (i=0; i < 2; i++) {
318 macosxCGS_get_all_windows();
319 if (0) fprintf(stderr, "!");
320 if (macosx_checkevent(NULL)) {
321 break;
322 }
323 }
324if (0) fprintf(stderr, "\ndone: %.4f\n", dnowx());
325 }
326 }
327 last_mask = mask;
328
329 /* record the x, y position for the rfb screen as well. */
330 cursor_position(x, y);
331
332 /* change the cursor shape if necessary */
333 rc = set_cursor(x, y, get_which_cursor());
334 cursor_changes += rc;
335
336 last_event = last_input = last_pointer_input = time(NULL);
337}
338
339void init_key_table(void) {
340 macosxCG_init_key_table();
341}
342
343void macosx_key_command(rfbBool down, rfbKeySym keysym, rfbClientPtr client) {
344 allowed_input_t input;
345 if (debug_keyboard) fprintf(stderr, "macosx_key_command: %d %s\n", (int) keysym, down ? "down" : "up");
346
347 if (view_only) {
348 return;
349 }
350 get_allowed_input(client, &input);
351 if (! input.keystroke) {
352 return;
353 }
354
355 init_key_table();
356 macosxCG_keysym_inject((int) down, (unsigned int) keysym);
357}
358
359extern void macosxGCS_poll_pb(void);
360
361int macosx_get_cursor_pos(int *x, int *y) {
362 macosxCG_get_cursor_pos(x, y);
363 if (nofb) {
364 /* good time to poll the pasteboard */
365 macosxGCS_poll_pb();
366 }
367 return 1;
368}
369
370static char *cuttext = NULL;
371static int cutlen = 0;
372
373void macosx_send_sel(char *str, int len) {
374 if (screen && all_clients_initialized()) {
375 if (cuttext) {
376 int n = cutlen;
377 if (len < n) {
378 n = len;
379 }
380 if (!memcmp(str, cuttext, (size_t) n)) {
381 /* the same text we set pasteboard to ... */
382 return;
383 }
384 }
385 if (debug_sel) {
386 rfbLog("macosx_send_sel: %d\n", len);
387 }
388 rfbSendServerCutText(screen, str, len);
389 }
390}
391
392void macosx_set_sel(char *str, int len) {
393 if (screen && all_clients_initialized()) {
394 if (cutlen <= len) {
395 if (cuttext) {
396 free(cuttext);
397 }
398 cutlen = 2*(len+1);
399 cuttext = (char *) calloc(cutlen, 1);
400 }
401 memcpy(cuttext, str, (size_t) len);
402 cuttext[len] = '\0';
403 if (debug_sel) {
404 rfbLog("macosx_set_sel: %d\n", len);
405 }
406 macosxGCS_set_pasteboard(str, len);
407 }
408}
409
410int macosx_get_cursor(void) {
411 return macosxCG_get_cursor();
412}
413
414typedef struct evdat {
415 int win;
416 int map;
417 int level;
418 int vis;
419 int type;
420} evdat_t;
421
422#define MAX_EVENTS 1024
423evdat_t mac_events[MAX_EVENTS];
424int mac_events_ptr = 0;
425int mac_events_last = 0;
426
427void macosx_add_mapnotify(Window win, int level, int map) {
428 int i = mac_events_last++;
429 mac_events[i].win = win;
430 mac_events[i].level = level;
431
432 if (map) {
433 mac_events[i].type = MapNotify;
434 } else {
435 mac_events[i].type = UnmapNotify;
436 }
437 mac_events[i].map = map;
438 mac_events[i].vis = -1;
439
440 mac_events_last = mac_events_last % MAX_EVENTS;
441
442 return;
443}
444
445void macosx_add_create(Window win, int level) {
446 int i = mac_events_last++;
447 mac_events[i].win = win;
448 mac_events[i].level = level;
449
450 mac_events[i].type = CreateNotify;
451 mac_events[i].map = -1;
452 mac_events[i].vis = -1;
453
454 mac_events_last = mac_events_last % MAX_EVENTS;
455
456 return;
457}
458
459void macosx_add_destroy(Window win, int level) {
460 int i = mac_events_last++;
461 mac_events[i].win = win;
462 mac_events[i].level = level;
463
464 mac_events[i].type = DestroyNotify;
465 mac_events[i].map = -1;
466 mac_events[i].vis = -1;
467
468 mac_events_last = mac_events_last % MAX_EVENTS;
469
470 return;
471}
472
473void macosx_add_visnotify(Window win, int level, int obscured) {
474 int i = mac_events_last++;
475 mac_events[i].win = win;
476 mac_events[i].level = level;
477
478 mac_events[i].type = VisibilityNotify;
479 mac_events[i].map = -1;
480
481 mac_events[i].vis = 1;
482 if (obscured == 0) {
483 mac_events[i].vis = VisibilityUnobscured;
484 } else if (obscured == 1) {
485 mac_events[i].vis = VisibilityPartiallyObscured;
486 } else if (obscured == 2) {
487 mac_events[i].vis = VisibilityFullyObscured; /* NI */
488 }
489
490 mac_events_last = mac_events_last % MAX_EVENTS;
491
492 return;
493}
494
495int macosx_checkevent(XEvent *ev) {
496 int i = mac_events_ptr;
497
498 if (mac_events_ptr == mac_events_last) {
499 return 0;
500 }
501 if (ev == NULL) {
502 return mac_events[i].type;
503 }
504
505 ev->xany.window = mac_events[i].win;
506
507 if (mac_events[i].type == CreateNotify) {
508 ev->type = CreateNotify;
509 ev->xany.window = rootwin;
510 ev->xcreatewindow.window = mac_events[i].win;
511 } else if (mac_events[i].type == DestroyNotify) {
512 ev->type = DestroyNotify;
513 ev->xdestroywindow.window = mac_events[i].win;
514 } else if (mac_events[i].type == VisibilityNotify) {
515 ev->type = VisibilityNotify;
516 ev->xvisibility.state = mac_events[i].vis;
517 } else if (mac_events[i].type == MapNotify) {
518 ev->type = MapNotify;
519 } else if (mac_events[i].type == UnmapNotify) {
520 ev->type = UnmapNotify;
521 } else {
522 fprintf(stderr, "unknown macosx_checkevent: %d\n", mac_events[i].type);
523 }
524 mac_events_ptr++;
525 mac_events_ptr = mac_events_ptr % MAX_EVENTS;
526
527 return mac_events[i].type;
528}
529
530typedef struct windat {
531 int win;
532 int x, y;
533 int width, height;
534 int level;
535 int mapped;
536 int clipped;
537 int ncache_only;
538} windat_t;
539
540extern int macwinmax;
541extern windat_t macwins[];
542
543int macosx_get_wm_frame_pos(int *px, int *py, int *x, int *y, int *w, int *h,
544 Window *frame, Window *win) {
545 static int last_idx = -1;
546 int x1, x2, y1, y2;
547 int idx = -1, k;
548 macosxCGS_get_all_windows();
549 macosxCG_get_cursor_pos(px, py);
550
551 for (k = 0; k<macwinmax; k++) {
552 if (! macwins[k].mapped) {
553 continue;
554 }
555 x1 = macwins[k].x;
556 x2 = macwins[k].x + macwins[k].width;
557 y1 = macwins[k].y;
558 y2 = macwins[k].y + macwins[k].height;
559if (debug_wireframe) fprintf(stderr, "%d/%d: %d %d %d - %d %d %d\n", k, macwins[k].win, x1, *px, x2, y1, *py, y2);
560 if (x1 <= *px && *px < x2) {
561 if (y1 <= *py && *py < y2) {
562 idx = k;
563 break;
564 }
565 }
566 }
567 if (idx < 0) {
568 return 0;
569 }
570
571 *x = macwins[idx].x;
572 *y = macwins[idx].y;
573 *w = macwins[idx].width;
574 *h = macwins[idx].height;
575 *frame = (Window) macwins[idx].win;
576 if (win != NULL) {
577 *win = *frame;
578 }
579
580 last_idx = idx;
581
582 return 1;
583}
584
585int macosx_valid_window(Window w, XWindowAttributes* a) {
586 static int last_idx = -1;
587 int win = (int) w;
588 int i, k, idx = -1;
589
590 if (last_idx >= 0 && last_idx < macwinmax) {
591 if (macwins[last_idx].win == win) {
592 idx = last_idx;
593 }
594 }
595
596 if (idx < 0) {
597 idx = macosxCGS_get_qlook(w);
598 if (idx >= 0 && idx < macwinmax) {
599 if (macwins[idx].win != win) {
600 idx = -1;
601 }
602 } else {
603 idx = -1;
604 }
605 }
606
607 if (idx < 0) {
608 for (i = 0; i<macwinmax; i++) {
609 k = i;
610 if (i == -1) {
611 if (last_idx >= 0 && last_idx < macwinmax) {
612 k = last_idx;
613 } else {
614 last_idx = -1;
615 continue;
616 }
617 }
618 if (macwins[k].win == win) {
619 idx = k;
620 break;
621 }
622 }
623 }
624 if (idx < 0) {
625 return 0;
626 }
627
628 a->x = macwins[idx].x;
629 a->y = macwins[idx].y;
630 a->width = macwins[idx].width;
631 a->height = macwins[idx].height;
632 a->depth = depth;
633 a->border_width = 0;
634 a->backing_store = 0;
635 if (macwins[idx].mapped) {
636 a->map_state = IsViewable;
637 } else {
638 a->map_state = IsUnmapped;
639 }
640
641 last_idx = idx;
642
643 return 1;
644}
645
646#define QTMAX 2048
647static Window cret[QTMAX];
648
649extern int CGS_levelmax;
650extern int CGS_levels[];
651
652Status macosx_xquerytree(Window w, Window *root_return, Window *parent_return,
653 Window **children_return, unsigned int *nchildren_return) {
654
655 int i, n, k;
656
657 *root_return = (Window) 0;
658 *parent_return = (Window) 0;
659 if (!w) {}
660
661 macosxCGS_get_all_windows();
662
663 n = 0;
664 for (k = CGS_levelmax - 1; k >= 0; k--) {
665 for (i = macwinmax - 1; i >= 0; i--) {
666 if (n >= QTMAX) break;
667 if (macwins[i].level == CGS_levels[k]) {
668if (0) fprintf(stderr, "k=%d i=%d n=%d\n", k, i, n);
669 cret[n++] = (Window) macwins[i].win;
670 }
671 }
672 }
673 *children_return = cret;
674 *nchildren_return = (unsigned int) macwinmax;
675
676 return (Status) 1;
677}
678
679int macosx_check_offscreen(int win) {
680 sraRegionPtr r0, r1;
681 int x1, y1, x2, y2;
682 int ret;
683 int i = macosxCGS_find_index(win);
684
685 if (i < 0) {
686 return 0;
687 }
688
689 x1 = macwins[i].x;
690 y1 = macwins[i].y;
691 x2 = macwins[i].x + macwins[i].width;
692 y2 = macwins[i].y + macwins[i].height;
693
694 r0 = sraRgnCreateRect(0, 0, dpy_x, dpy_y);
695 r1 = sraRgnCreateRect(x1, y1, x2, y2);
696
697 if (sraRgnAnd(r1, r0)) {
698 ret = 0;
699 } else {
700 ret = 1;
701 }
702 sraRgnDestroy(r0);
703 sraRgnDestroy(r1);
704
705 return ret;
706}
707
708int macosx_check_clipped(int win, int *list, int n) {
709 sraRegionPtr r0, r1, r2;
710 int x1, y1, x2, y2;
711 int ret = 0;
712 int k, j, i = macosxCGS_find_index(win);
713
714 if (i < 0) {
715 return 0;
716 }
717
718 x1 = macwins[i].x;
719 y1 = macwins[i].y;
720 x2 = macwins[i].x + macwins[i].width;
721 y2 = macwins[i].y + macwins[i].height;
722
723 r0 = sraRgnCreateRect(0, 0, dpy_x, dpy_y);
724 r1 = sraRgnCreateRect(x1, y1, x2, y2);
725 sraRgnAnd(r1, r0);
726
727 for (k = 0; k < n; k++) {
728 j = macosxCGS_find_index(list[k]); /* XXX slow? */
729 if (j < 0) {
730 continue;
731 }
732 x1 = macwins[j].x;
733 y1 = macwins[j].y;
734 x2 = macwins[j].x + macwins[j].width;
735 y2 = macwins[j].y + macwins[j].height;
736 r2 = sraRgnCreateRect(x1, y1, x2, y2);
737 if (sraRgnAnd(r2, r1)) {
738 ret = 1;
739 sraRgnDestroy(r2);
740 break;
741 }
742 sraRgnDestroy(r2);
743 }
744 sraRgnDestroy(r0);
745 sraRgnDestroy(r1);
746
747 return ret;
748}
749
750
751#endif /* LIBVNCSERVER_HAVE_MACOSX_NATIVE_DISPLAY */
752