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 /* -- macosxCGS.c -- */ 34 35 /* 36 * We need to keep this separate from nearly everything else, e.g. rfb.h 37 * and the other stuff, otherwise it does not work properly, mouse drags 38 * will not work!! 39 */ 40 void macosxCGS_unused(void) {} 41 42 #if (defined(__MACH__) && defined(__APPLE__)) 43 44 #include <ApplicationServices/ApplicationServices.h> 45 #include <Cocoa/Cocoa.h> 46 #include <Carbon/Carbon.h> 47 48 extern CGDirectDisplayID displayID; 49 50 void macosxCGS_get_all_windows(void); 51 int macosxCGS_get_qlook(int); 52 void macosxGCS_set_pasteboard(char *str, int len); 53 54 typedef CGError CGSError; 55 typedef long CGSWindowCount; 56 typedef void * CGSConnectionID; 57 typedef int CGSWindowID; 58 typedef CGSWindowID* CGSWindowIDList; 59 typedef CGWindowLevel CGSWindowLevel; 60 typedef NSRect CGSRect; 61 62 extern CGSConnectionID _CGSDefaultConnection (); 63 64 extern CGSError CGSGetOnScreenWindowList (CGSConnectionID cid, 65 CGSConnectionID owner, CGSWindowCount listCapacity, 66 CGSWindowIDList list, CGSWindowCount *listCount); 67 68 extern CGSError CGSGetWindowList (CGSConnectionID cid, 69 CGSConnectionID owner, CGSWindowCount listCapacity, 70 CGSWindowIDList list, CGSWindowCount *listCount); 71 72 extern CGSError CGSGetScreenRectForWindow (CGSConnectionID cid, 73 CGSWindowID wid, CGSRect *rect); 74 75 extern CGWindowLevel CGSGetWindowLevel (CGSConnectionID cid, 76 CGSWindowID wid, CGSWindowLevel *level); 77 78 typedef enum _CGSWindowOrderingMode { 79 kCGSOrderAbove = 1, /* Window is ordered above target. */ 80 kCGSOrderBelow = -1, /* Window is ordered below target. */ 81 kCGSOrderOut = 0 /* Window is removed from the on-screen window list. */ 82 } CGSWindowOrderingMode; 83 84 extern OSStatus CGSOrderWindow(const CGSConnectionID cid, 85 const CGSWindowID wid, CGSWindowOrderingMode place, CGSWindowID relativeToWindowID); 86 87 static CGSConnectionID cid = NULL; 88 89 extern void macosx_log(char *); 90 91 int macwinmax = 0; 92 typedef struct windat { 93 int win; 94 int x, y; 95 int width, height; 96 int level; 97 int mapped; 98 int clipped; 99 int ncache_only; 100 } windat_t; 101 102 extern int ncache; 103 104 #define MAXWINDAT 4096 105 windat_t macwins[MAXWINDAT]; 106 static CGSWindowID _wins_all[MAXWINDAT]; 107 static CGSWindowID _wins_mapped[MAXWINDAT]; 108 static CGSWindowCount _wins_all_cnt, _wins_mapped_cnt; 109 static int _wins_int[MAXWINDAT]; 110 111 #define WINHISTNUM 32768 112 #define WINHISTMAX 4 113 char whist[WINHISTMAX][WINHISTNUM]; 114 int whist_idx = -1; 115 int qlook[WINHISTNUM]; 116 117 char is_exist = 0x1; 118 char is_mapped = 0x2; 119 char is_clipped = 0x4; 120 char is_offscreen = 0x8; 121 122 extern double dnow(void); 123 extern double dnowx(void); 124 125 extern int dpy_x, dpy_y; 126 extern int macosx_icon_anim_time; 127 128 extern void macosx_add_mapnotify(int, int, int); 129 extern void macosx_add_create(int, int); 130 extern void macosx_add_destroy(int, int); 131 extern void macosx_add_visnotify(int, int, int); 132 133 int CGS_levelmax; 134 int CGS_levels[16]; 135 136 int macosxCGS_get_qlook(int w) { 137 if (w >= WINHISTNUM) { 138 return -1; 139 } 140 return qlook[w]; 141 } 142 143 int macosxCGS_find_index(int w) { 144 static int last_index = -1; 145 int idx; 146 147 if (last_index >= 0) { 148 if (macwins[last_index].win == w) { 149 return last_index; 150 } 151 } 152 153 idx = macosxCGS_get_qlook(w); 154 if (idx >= 0) { 155 if (macwins[idx].win == w) { 156 last_index = idx; 157 return idx; 158 } 159 } 160 161 for (idx=0; idx < macwinmax; idx++) { 162 if (macwins[idx].win == w) { 163 last_index = idx; 164 return idx; 165 } 166 } 167 return -1; 168 } 169 170 #if 0 171 extern void usleep(unsigned long usec); 172 #else 173 extern int usleep(useconds_t usec); 174 #endif 175 176 int macosxCGS_follow_animation_win(int win, int idx, int grow) { 177 double t = dnow(); 178 int diffs = 0; 179 int x, y, w, h; 180 int xp = -1, yp = -1, wp = -1, hp = -1; 181 CGSRect rect; 182 CGSError err; 183 184 int reps = 0; 185 186 if (cid == NULL) { 187 cid = _CGSDefaultConnection(); 188 if (cid == NULL) { 189 return 0; 190 } 191 } 192 193 if (idx < 0) { 194 idx = macosxCGS_find_index(win); 195 } 196 if (idx < 0) { 197 return 0; 198 } 199 200 while (dnow() < t + 0.001 * macosx_icon_anim_time) { 201 err = CGSGetScreenRectForWindow(cid, win, &rect); 202 if (err != 0) { 203 break; 204 } 205 x = (int) rect.origin.x; 206 y = (int) rect.origin.y; 207 w = (int) rect.size.width; 208 h = (int) rect.size.height; 209 210 if (grow) { 211 macwins[idx].x = x; 212 macwins[idx].y = y; 213 macwins[idx].width = w; 214 macwins[idx].height = h; 215 } 216 217 if (0) fprintf(stderr, " chase: %03dx%03d+%03d+%03d %d\n", w, h, x, y, win); 218 if (x == xp && y == yp && w == wp && h == hp) { 219 reps++; 220 if (reps >= 2) { 221 break; 222 } 223 } else { 224 diffs++; 225 reps = 0; 226 } 227 xp = x; 228 yp = y; 229 wp = w; 230 hp = h; 231 usleep(50 * 1000); 232 } 233 if (diffs >= 2) { 234 return 1; 235 } else { 236 return 0; 237 } 238 } 239 240 extern int macosx_check_clipped(int win, int *list, int n); 241 extern int macosx_check_offscreen(int win); 242 243 static int check_clipped(int win) { 244 int i, n = 0, win2; 245 for (i = 0; i < (int) _wins_mapped_cnt; i++) { 246 win2 = (int) _wins_mapped[i]; 247 if (win2 == win) { 248 break; 249 } 250 _wins_int[n++] = win2; 251 } 252 return macosx_check_clipped(win, _wins_int, n); 253 } 254 255 static int check_offscreen(int win) { 256 return macosx_check_offscreen(win); 257 } 258 259 extern int macosx_ncache_macmenu; 260 261 262 void macosxCGS_get_all_windows(void) { 263 static double last = 0.0; 264 static int totcnt = 0; 265 double dt = 0.0, now = dnow(); 266 int i, db = 0, whist_prv = 0, maxwin = 0, whist_skip = 0; 267 CGSWindowCount cap = (CGSWindowCount) MAXWINDAT; 268 CGSError err; 269 270 CGS_levelmax = 0; 271 CGS_levels[CGS_levelmax++] = (int) kCGDraggingWindowLevel; /* 500 ? */ 272 if (0) CGS_levels[CGS_levelmax++] = (int) kCGHelpWindowLevel; /* 102 ? */ 273 if (macosx_ncache_macmenu) CGS_levels[CGS_levelmax++] = (int) kCGPopUpMenuWindowLevel; /* 101 pulldown menu */ 274 CGS_levels[CGS_levelmax++] = (int) kCGMainMenuWindowLevelKey; /* 24 ? */ 275 CGS_levels[CGS_levelmax++] = (int) kCGModalPanelWindowLevel; /* 8 open dialog box */ 276 CGS_levels[CGS_levelmax++] = (int) kCGFloatingWindowLevel; /* 3 ? */ 277 CGS_levels[CGS_levelmax++] = (int) kCGNormalWindowLevel; /* 0 regular window */ 278 279 if (cid == NULL) { 280 cid = _CGSDefaultConnection(); 281 if (cid == NULL) { 282 return; 283 } 284 } 285 286 if (dt > 0.0 && now < last + dt) { 287 return; 288 } 289 290 last = now; 291 292 macwinmax = 0; 293 294 totcnt++; 295 296 if (ncache > 0) { 297 whist_prv = whist_idx++; 298 if (whist_prv < 0) { 299 whist_skip = 1; 300 whist_prv = 0; 301 } 302 whist_idx = whist_idx % WINHISTMAX; 303 for (i=0; i < WINHISTNUM; i++) { 304 whist[whist_idx][i] = 0; 305 qlook[i] = -1; 306 } 307 } 308 309 err = CGSGetWindowList(cid, NULL, cap, _wins_all, &_wins_all_cnt); 310 311 if (db) fprintf(stderr, "cnt: %d err: %d\n", (int) _wins_all_cnt, err); 312 313 if (err != 0) { 314 return; 315 } 316 317 for (i=0; i < (int) _wins_all_cnt; i++) { 318 CGSRect rect; 319 CGSWindowLevel level; 320 int j, keepit = 0; 321 err = CGSGetScreenRectForWindow(cid, _wins_all[i], &rect); 322 if (err != 0) { 323 continue; 324 } 325 if (rect.origin.x == 0 && rect.origin.y == 0) { 326 if (rect.size.width == dpy_x) { 327 if (rect.size.height == dpy_y) { 328 continue; 329 } 330 } 331 } 332 err = CGSGetWindowLevel(cid, _wins_all[i], &level); 333 if (err != 0) { 334 continue; 335 } 336 for (j=0; j<CGS_levelmax; j++) { 337 if ((int) level == CGS_levels[j]) { 338 keepit = 1; 339 break; 340 } 341 } 342 if (! keepit) { 343 continue; 344 } 345 346 macwins[macwinmax].level = (int) level; 347 macwins[macwinmax].win = (int) _wins_all[i]; 348 macwins[macwinmax].x = (int) rect.origin.x; 349 macwins[macwinmax].y = (int) rect.origin.y; 350 macwins[macwinmax].width = (int) rect.size.width; 351 macwins[macwinmax].height = (int) rect.size.height; 352 macwins[macwinmax].mapped = 0; 353 macwins[macwinmax].clipped = 0; 354 macwins[macwinmax].ncache_only = 0; 355 if (level == kCGPopUpMenuWindowLevel) { 356 macwins[macwinmax].ncache_only = 1; 357 } 358 359 if (0 || db) fprintf(stderr, "i=%03d ID: %06d x: %03d y: %03d w: %03d h: %03d level: %d\n", i, _wins_all[i], 360 (int) rect.origin.x, (int) rect.origin.y,(int) rect.size.width, (int) rect.size.height, (int) level); 361 362 if (macwins[macwinmax].win < WINHISTNUM) { 363 qlook[macwins[macwinmax].win] = macwinmax; 364 if (macwins[macwinmax].win > maxwin) { 365 maxwin = macwins[macwinmax].win; 366 } 367 } 368 369 macwinmax++; 370 } 371 372 err = CGSGetOnScreenWindowList(cid, NULL, cap, _wins_mapped, &_wins_mapped_cnt); 373 374 if (db) fprintf(stderr, "cnt: %d err: %d\n", (int) _wins_mapped_cnt, err); 375 376 if (err != 0) { 377 return; 378 } 379 380 for (i=0; i < (int) _wins_mapped_cnt; i++) { 381 int j, idx = -1; 382 int win = (int) _wins_mapped[i]; 383 384 if (0 <= win && win < WINHISTNUM) { 385 j = qlook[win]; 386 if (j >= 0 && macwins[j].win == win) { 387 idx = j; 388 } 389 } 390 if (idx < 0) { 391 for (j=0; j < macwinmax; j++) { 392 if (macwins[j].win == win) { 393 idx = j; 394 break; 395 } 396 } 397 } 398 if (idx >= 0) { 399 macwins[idx].mapped = 1; 400 } 401 } 402 403 if (ncache > 0) { 404 int nv= 0, NBMAX = 64; 405 int nv_win[64]; 406 int nv_lvl[64]; 407 int nv_vis[64]; 408 409 for (i=0; i < macwinmax; i++) { 410 int win = macwins[i].win; 411 char prev, curr; 412 413 if (win >= WINHISTNUM) { 414 continue; 415 } 416 417 whist[whist_idx][win] |= is_exist; 418 if (macwins[i].mapped) { 419 whist[whist_idx][win] |= is_mapped; 420 if (check_clipped(win)) { 421 whist[whist_idx][win] |= is_clipped; 422 macwins[i].clipped = 1; 423 } 424 if (check_offscreen(win)) { 425 whist[whist_idx][win] |= is_offscreen; 426 } 427 } else { 428 whist[whist_idx][win] |= is_offscreen; 429 } 430 431 curr = whist[whist_idx][win]; 432 prev = whist[whist_prv][win]; 433 434 if (whist_skip) { 435 ; 436 } else if ( !(prev & is_mapped) && (curr & is_mapped)) { 437 /* MapNotify */ 438 if (0) fprintf(stderr, "MapNotify: %d/%d %d %.4f tot=%d\n", prev, curr, win, dnowx(), totcnt); 439 macosx_add_mapnotify(win, macwins[i].level, 1); 440 if (0) macosxCGS_follow_animation_win(win, i, 1); 441 442 } else if ( !(curr & is_mapped) && (prev & is_mapped)) { 443 /* UnmapNotify */ 444 if (0) fprintf(stderr, "UnmapNotify: %d/%d %d %.4f A tot=%d\n", prev, curr, win, dnowx(), totcnt); 445 macosx_add_mapnotify(win, macwins[i].level, 0); 446 } else if ( !(prev & is_exist) && (curr & is_exist)) { 447 /* CreateNotify */ 448 if (0) fprintf(stderr, "CreateNotify:%d/%d %d %.4f whist: %d/%d 0x%x tot=%d\n", prev, curr, win, dnowx(), whist_prv, whist_idx, win, totcnt); 449 macosx_add_create(win, macwins[i].level); 450 if (curr & is_mapped) { 451 if (0) fprintf(stderr, "MapNotify: %d/%d %d %.4f tot=%d\n", prev, curr, win, dnowx(), totcnt); 452 macosx_add_mapnotify(win, macwins[i].level, 1); 453 } 454 } 455 if (whist_skip) { 456 ; 457 } else if (nv >= NBMAX) { 458 ; 459 } else if (!(curr & is_mapped)) { 460 ; 461 } else if (!(prev & is_mapped)) { 462 if (1) { 463 ; 464 } else if (curr & is_clipped) { 465 if (0) fprintf(stderr, "VisibNotify: %d/%d %d OBS tot=%d\n", prev, curr, win, totcnt); 466 nv_win[nv] = win; 467 nv_lvl[nv] = macwins[i].level; 468 nv_vis[nv++] = 1; 469 } else { 470 if (0) fprintf(stderr, "VisibNotify: %d/%d %d UNOBS tot=%d\n", prev, curr, win, totcnt); 471 nv_win[nv] = win; 472 nv_lvl[nv] = macwins[i].level; 473 nv_vis[nv++] = 0; 474 } 475 } else { 476 if ( !(prev & is_clipped) && (curr & is_clipped) ) { 477 if (0) fprintf(stderr, "VisibNotify: %d/%d %d OBS tot=%d\n", prev, curr, win, totcnt); 478 nv_win[nv] = win; 479 nv_lvl[nv] = macwins[i].level; 480 nv_vis[nv++] = 1; 481 } else if ( (prev & is_clipped) && !(curr & is_clipped) ) { 482 if (0) fprintf(stderr, "VisibNotify: %d/%d %d UNOBS tot=%d\n", prev, curr, win, totcnt); 483 nv_win[nv] = win; 484 nv_lvl[nv] = macwins[i].level; 485 nv_vis[nv++] = 0; 486 } 487 } 488 } 489 for (i=0; i < maxwin; i++) { 490 char prev, curr; 491 int win = i; 492 int q = qlook[i]; 493 int lvl = 0; 494 495 if (whist_skip) { 496 break; 497 } 498 499 if (q >= 0) { 500 lvl = macwins[q].level; 501 } 502 curr = whist[whist_idx][win]; 503 prev = whist[whist_prv][win]; 504 if (!(curr & is_exist) && (prev & is_exist)) { 505 if (prev & is_mapped) { 506 if (0) fprintf(stderr, "UnmapNotify: %d/%d %d %.4f B tot=%d\n", prev, curr, win, dnowx(), totcnt); 507 macosx_add_mapnotify(win, lvl, 0); 508 } 509 /* DestroyNotify */ 510 if (0) fprintf(stderr, "DestroNotify:%d/%d %d %.4f tot=%d\n", prev, curr, win, dnowx(), totcnt); 511 macosx_add_destroy(win, lvl); 512 } 513 } 514 if (nv) { 515 int k; 516 for (k = 0; k < nv; k++) { 517 macosx_add_visnotify(nv_win[k], nv_lvl[k], nv_vis[k]); 518 } 519 } 520 } 521 } 522 523 #if 1 524 NSLock *pblock = nil; 525 NSString *pbstr = nil; 526 NSString *cuttext = nil; 527 528 int pbcnt = -1; 529 NSStringEncoding pbenc = NSWindowsCP1252StringEncoding; 530 531 void macosxGCS_initpb(void) { 532 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 533 pblock = [[NSLock alloc] init]; 534 if (![NSPasteboard generalPasteboard]) { 535 macosx_log("macosxGCS_initpb: **PASTEBOARD INACCESSIBLE**.\n"); 536 macosx_log("macosxGCS_initpb: Clipboard exchange will NOT work.\n"); 537 macosx_log("macosxGCS_initpb: Start x11vnc *inside* Aqua for Clipboard.\n"); 538 pbcnt = 0; 539 pbstr = [[NSString alloc] initWithString:@"\e<PASTEBOARD INACCESSIBLE>\e"]; 540 } 541 [pool release]; 542 } 543 544 void macosxGCS_set_pasteboard(char *str, int len) { 545 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 546 if (pbcnt != 0) { 547 [pblock lock]; 548 [cuttext release]; 549 cuttext = [[NSString alloc] initWithData:[NSData dataWithBytes:str length:len] encoding: pbenc]; 550 if ([[NSPasteboard generalPasteboard] declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:nil]) { 551 NS_DURING 552 [[NSPasteboard generalPasteboard] setString:cuttext forType:NSStringPboardType]; 553 NS_HANDLER 554 fprintf(stderr, "macosxGCS_set_pasteboard: problem writing to pasteboard\n"); 555 NS_ENDHANDLER 556 } else { 557 fprintf(stderr, "macosxGCS_set_pasteboard: problem writing to pasteboard\n"); 558 } 559 [cuttext release]; 560 cuttext = nil; 561 [pblock unlock]; 562 } 563 [pool release]; 564 } 565 566 extern void macosx_send_sel(char *, int); 567 568 void macosxGCS_poll_pb(void) { 569 570 static double dlast = 0.0; 571 double now = dnow(); 572 573 if (now < dlast + 0.2) { 574 return; 575 } 576 dlast = now; 577 578 { 579 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 580 [pblock lock]; 581 if (pbcnt != [[NSPasteboard generalPasteboard] changeCount]) { 582 pbcnt = [[NSPasteboard generalPasteboard] changeCount]; 583 [pbstr release]; 584 pbstr = nil; 585 if ([[NSPasteboard generalPasteboard] availableTypeFromArray:[NSArray arrayWithObject:NSStringPboardType]]) { 586 pbstr = [[[NSPasteboard generalPasteboard] stringForType:NSStringPboardType] copy]; 587 if (pbstr) { 588 NSData *str = [pbstr dataUsingEncoding:pbenc allowLossyConversion:YES]; 589 if ([str length]) { 590 macosx_send_sel((char *) [str bytes], [str length]); 591 } 592 } 593 } 594 } 595 [pblock unlock]; 596 [pool release]; 597 } 598 } 599 #endif 600 601 #endif /* __APPLE__ */ 602 603