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