1/* 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 753