Home | History | Annotate | Download | only in x11vnc
      1 /*
      2    Copyright (C) 2002-2010 Karl J. Runge <runge (at) karlrunge.com>
      3    All rights reserved.
      4 
      5 This file is part of x11vnc.
      6 
      7 x11vnc is free software; you can redistribute it and/or modify
      8 it under the terms of the GNU General Public License as published by
      9 the Free Software Foundation; either version 2 of the License, or (at
     10 your option) any later version.
     11 
     12 x11vnc is distributed in the hope that it will be useful,
     13 but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 GNU General Public License for more details.
     16 
     17 You should have received a copy of the GNU General Public License
     18 along with x11vnc; if not, write to the Free Software
     19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA
     20 or see <http://www.gnu.org/licenses/>.
     21 
     22 In addition, as a special exception, Karl J. Runge
     23 gives permission to link the code of its release of x11vnc with the
     24 OpenSSL project's "OpenSSL" library (or with modified versions of it
     25 that use the same license as the "OpenSSL" library), and distribute
     26 the linked executables.  You must obey the GNU General Public License
     27 in all respects for all of the code used other than "OpenSSL".  If you
     28 modify this file, you may extend this exception to your version of the
     29 file, but you are not obligated to do so.  If you do not wish to do
     30 so, 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 
     59 void macosx_log(char *);
     60 char *macosx_console_guess(char *str, int *fd);
     61 void macosx_key_command(rfbBool down, rfbKeySym keysym, rfbClientPtr client);
     62 void macosx_pointer_command(int mask, int x, int y, rfbClientPtr client);
     63 char *macosx_get_fb_addr(void);
     64 int macosx_get_cursor(void);
     65 int macosx_get_cursor_pos(int *, int *);
     66 void macosx_send_sel(char *, int);
     67 void macosx_set_sel(char *, int);
     68 int macosx_valid_window(Window, XWindowAttributes*);
     69 
     70 Status macosx_xquerytree(Window w, Window *root_return, Window *parent_return,
     71     Window **children_return, unsigned int *nchildren_return);
     72 int macosx_get_wm_frame_pos(int *px, int *py, int *x, int *y, int *w, int *h,
     73     Window *frame, Window *win);
     74 
     75 void macosx_add_mapnotify(Window win, int level, int map);
     76 void macosx_add_create(Window win, int level);
     77 void macosx_add_destroy(Window win, int level);
     78 void macosx_add_visnotify(Window win, int level, int obscured);
     79 int macosx_checkevent(XEvent *ev);
     80 
     81 void macosx_log(char *str) {
     82 	rfbLog(str);
     83 }
     84 
     85 #if (! DOMAC)
     86 
     87 void macosx_event_loop(void) {
     88 	return;
     89 }
     90 char *macosx_console_guess(char *str, int *fd) {
     91 	if (!str || !fd) {}
     92 	return NULL;
     93 }
     94 void macosx_key_command(rfbBool down, rfbKeySym keysym, rfbClientPtr client) {
     95 	if (!down || !keysym || !client) {}
     96 	return;
     97 }
     98 void macosx_pointer_command(int mask, int x, int y, rfbClientPtr client) {
     99 	if (!mask || !x || !y || !client) {}
    100 	return;
    101 }
    102 char *macosx_get_fb_addr(void) {
    103 	return NULL;
    104 }
    105 int macosx_get_cursor(void) {
    106 	return 0;
    107 }
    108 int macosx_get_cursor_pos(int *x, int *y) {
    109 	if (!x || !y) {}
    110 	return 0;
    111 }
    112 void macosx_send_sel(char * str, int len) {
    113 	if (!str || !len) {}
    114 	return;
    115 }
    116 void macosx_set_sel(char * str, int len) {
    117 	if (!str || !len) {}
    118 	return;
    119 }
    120 int macosx_valid_window(Window w, XWindowAttributes* a) {
    121 	if (!w || !a) {}
    122 	return 0;
    123 }
    124 Status 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 }
    129 void macosx_add_mapnotify(Window win, int level, int map) {
    130 	if (!win || !level || !map) {}
    131 	return;
    132 }
    133 void macosx_add_create(Window win, int level) {
    134 	if (!win || !level) {}
    135 	return;
    136 }
    137 void macosx_add_destroy(Window win, int level) {
    138 	if (!win || !level) {}
    139 	return;
    140 }
    141 void macosx_add_visnotify(Window win, int level, int obscured) {
    142 	if (!win || !level || !obscured) {}
    143 	return;
    144 }
    145 
    146 int macosx_checkevent(XEvent *ev) {
    147 	if (!ev) {}
    148 	return 0;
    149 }
    150 
    151 
    152 #else
    153 
    154 void macosx_event_loop(void) {
    155 	macosxCG_event_loop();
    156 }
    157 
    158 char *macosx_get_fb_addr(void) {
    159 	macosxCG_init();
    160 	return macosxCG_get_fb_addr();
    161 }
    162 
    163 int macosx_opengl_get_width(void);
    164 int macosx_opengl_get_height(void);
    165 int macosx_opengl_get_bpp(void);
    166 int macosx_opengl_get_bps(void);
    167 int macosx_opengl_get_spp(void);
    168 
    169 char *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 
    261 Window macosx_click_frame = None;
    262 
    263 void 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;
    316 if (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 			}
    324 if (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 
    339 void init_key_table(void) {
    340 	macosxCG_init_key_table();
    341 }
    342 
    343 void 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 
    359 extern void macosxGCS_poll_pb(void);
    360 
    361 int 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 
    370 static char *cuttext = NULL;
    371 static int cutlen = 0;
    372 
    373 void 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 
    392 void 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 
    410 int macosx_get_cursor(void) {
    411 	return macosxCG_get_cursor();
    412 }
    413 
    414 typedef 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
    423 evdat_t mac_events[MAX_EVENTS];
    424 int mac_events_ptr = 0;
    425 int mac_events_last = 0;
    426 
    427 void 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 
    445 void 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 
    459 void 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 
    473 void 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 
    495 int 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 
    530 typedef 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 
    540 extern int macwinmax;
    541 extern windat_t macwins[];
    542 
    543 int 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;
    559 if (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 
    585 int 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
    647 static Window cret[QTMAX];
    648 
    649 extern int CGS_levelmax;
    650 extern int CGS_levels[];
    651 
    652 Status 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]) {
    668 if (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 
    679 int 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 
    708 int 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 
    753