static void do_allinput(long usec) { static double last = 0.0; static int meas = 0; int n, f = 1, cnt = 0; long usec0; double now; if (!screen || !screen->clientHead) { return; } if (usec < 0) { usec = 0; } usec0 = usec; if (last == 0.0) { last = dnow(); } while ((n = rfbCheckFds(screen, usec)) > 0) { if (f) { fprintf(stderr, " *"); f = 0; } if (cnt++ > 30) { break; } meas += n; } fprintf(stderr, "-%d", cnt); now = dnow(); if (now > last + 2.0) { double rate = meas / (now - last); fprintf(stderr, "\n%.2f ", rate); meas = 0; last = dnow(); } }
/* * utility wrapper to call rfbProcessEvents * checks that we are not in threaded mode. */ #define USEC_MAX 999999 /* libvncsever assumes < 1 second */ void rfbPE(long usec) { int uip0 = unixpw_in_progress; static int check_rate = -1; if (! screen) { return; } if (unixpw && unixpw_in_progress && !unixpw_in_rfbPE) { rfbLog("unixpw_in_rfbPE: skipping rfbPE\n"); return; } if (debug_tiles > 2) { double tm = dnow(); fprintf(stderr, "rfbPE(%d) t: %.4f\n", (int) usec, tm - x11vnc_start); } if (usec > USEC_MAX) { usec = USEC_MAX; } if (! use_threads) { rfbProcessEvents(screen, usec); } if (unixpw && unixpw_in_progress && !uip0) { if (!unixpw_in_rfbPE) { rfbLog("rfbPE: got new client in non-rfbPE\n"); ; /* this is new unixpw client */ } } if (check_rate != 0) { if (check_rate < 0) { if (getenv("CHECK_RATE")) { check_rate = 1; } else { check_rate = 0; } } if (check_rate && !all_input && x11vnc_current < last_client + 45) { check_allinput_rate(); } } if (all_input) { do_allinput(usec); } }
void rfbCFD(long usec) { int uip0 = unixpw_in_progress; if (! screen) { return; } if (unixpw && unixpw_in_progress && !unixpw_in_rfbPE) { rfbLog("unixpw_in_rfbPE: skipping rfbCFD\n"); return; } if (usec > USEC_MAX) { usec = USEC_MAX; } if (debug_tiles > 2) { double tm = dnow(); fprintf(stderr, "rfbCFD(%d) t: %.4f\n", (int) usec, tm - x11vnc_start); } #if 0 fprintf(stderr, "handleEventsEagerly: %d\n", screen->handleEventsEagerly); #endif if (! use_threads) { if (all_input) { do_allinput(usec); } else { /* XXX how for cmdline? */ if (all_input) { screen->handleEventsEagerly = TRUE; } else { screen->handleEventsEagerly = FALSE; } rfbCheckFds(screen, usec); } } if (unixpw && unixpw_in_progress && !uip0) { if (!unixpw_in_rfbPE) { rfbLog("rfbCFD: got new client in non-rfbPE\n"); ; /* this is new unixpw client */ } } }
void check_allinput_rate(void) { static double last_all_input_check = 0.0, last_all_input_start = 0.0; static int set = 0; if (! set) { set = 1; last_all_input_check = dnow(); } else { int dt = 4; if (x11vnc_current > last_all_input_check + dt) { int n, nq = 0; while ((n = rfbCheckFds(screen, 0))) { nq += n; } fprintf(stderr, "nqueued: %d\n", nq); if (0 && nq > 25 * dt) { double rate = nq / dt; rfbLog("Client is sending %.1f extra requests per second for the\n", rate); rfbLog("past %d seconds! Switching to -allpinput mode. (queued: %d)\n", dt, nq); all_input = 1; } set = 0; } } }
double dnowx(void) { return dnow() - x11vnc_start; }
int connect_tcp(char *host, int port) { double t0 = dnow(); int fd = -1; int fail4 = noipv4; if (getenv("IPV4_FAILS")) { fail4 = 2; } rfbLog("connect_tcp: trying: %s %d\n", host, port); if (fail4) { if (fail4 > 1) { rfbLog("TESTING: IPV4_FAILS for connect_tcp.\n"); } } else { fd = rfbConnectToTcpAddr(host, port); } if (fd >= 0) { return fd; } rfbLogPerror("connect_tcp: connection failed"); if (dnow() - t0 < 4.0) { rfbLog("connect_tcp: re-trying %s %d\n", host, port); usleep (100 * 1000); if (!fail4) { fd = rfbConnectToTcpAddr(host, port); } if (fd < 0) { rfbLogPerror("connect_tcp: connection failed"); } } if (fd < 0 && !noipv6) { #if X11VNC_IPV6 int err; struct addrinfo *ai; struct addrinfo hints; char service[32], *host2, *q; rfbLog("connect_tcp: trying IPv6 %s %d\n", host, port); memset(&hints, 0, sizeof(hints)); sprintf(service, "%d", port); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; #ifdef AI_ADDRCONFIG hints.ai_flags |= AI_ADDRCONFIG; #endif if(ipv6_ip(host)) { #ifdef AI_NUMERICHOST rfbLog("connect_tcp[ipv6]: setting AI_NUMERICHOST for %s\n", host); hints.ai_flags |= AI_NUMERICHOST; #endif } #ifdef AI_NUMERICSERV hints.ai_flags |= AI_NUMERICSERV; #endif if (!strcmp(host, "127.0.0.1")) { host2 = strdup("::1"); } else if (host[0] == '[') { host2 = strdup(host+1); } else { host2 = strdup(host); } q = strrchr(host2, ']'); if (q) { *q = '\0'; } err = getaddrinfo(host2, service, &hints, &ai); if (err != 0) { rfbLog("connect_tcp[ipv6]: getaddrinfo[%d]: %s\n", err, gai_strerror(err)); usleep(100 * 1000); err = getaddrinfo(host2, service, &hints, &ai); } free(host2); if (err != 0) { rfbLog("connect_tcp[ipv6]: getaddrinfo[%d]: %s\n", err, gai_strerror(err)); } else { struct addrinfo *ap = ai; while (ap != NULL) { int sock; if (fail4) { struct sockaddr_in6 *s6ptr; if (ap->ai_family != AF_INET6) { rfbLog("connect_tcp[ipv6]: skipping AF_INET address under -noipv4\n"); ap = ap->ai_next; continue; } #ifdef IN6_IS_ADDR_V4MAPPED s6ptr = (struct sockaddr_in6 *) ap->ai_addr; if (IN6_IS_ADDR_V4MAPPED(&(s6ptr->sin6_addr))) { rfbLog("connect_tcp[ipv6]: skipping V4MAPPED address under -noipv4\n"); ap = ap->ai_next; continue; } #endif } sock = socket(ap->ai_family, ap->ai_socktype, ap->ai_protocol); if (sock == -1) { rfbLogPerror("connect_tcp[ipv6]: socket"); if (0) rfbLog("(Ignore the above error if this system is IPv4-only.)\n"); } else { int res = -1, dmsg = 0; char *s = ipv6_getipaddr(ap->ai_addr, ap->ai_addrlen); if (!s) s = strdup("unknown"); rfbLog("connect_tcp[ipv6]: trying sock=%d fam=%d proto=%d using %s\n", sock, ap->ai_family, ap->ai_protocol, s); res = connect(sock, ap->ai_addr, ap->ai_addrlen); #if defined(SOL_IPV6) && defined(IPV6_V6ONLY) if (res != 0) { int zero = 0; rfbLogPerror("connect_tcp[ipv6]: connect"); dmsg = 1; if (setsockopt(sock, SOL_IPV6, IPV6_V6ONLY, (char *)&zero, sizeof(zero)) == 0) { rfbLog("connect_tcp[ipv6]: trying again with IPV6_V6ONLY=0\n"); res = connect(sock, ap->ai_addr, ap->ai_addrlen); dmsg = 0; } else { rfbLogPerror("connect_tcp[ipv6]: setsockopt IPV6_V6ONLY"); } } #endif if (res == 0) { rfbLog("connect_tcp[ipv6]: connect OK\n"); fd = sock; if (!ipv6_client_ip_str) { ipv6_client_ip_str = strdup(s); } free(s); break; } else { if (!dmsg) rfbLogPerror("connect_tcp[ipv6]: connect"); close(sock); } free(s); } ap = ap->ai_next; } freeaddrinfo(ai); } #endif } if (fd < 0 && !fail4) { /* this is a kludge for IPv4-only machines getting v4mapped string. */ char *q, *host2; if (host[0] == '[') { host2 = strdup(host+1); } else { host2 = strdup(host); } q = strrchr(host2, ']'); if (q) { *q = '\0'; } if (strstr(host2, "::ffff:") == host2 || strstr(host2, "::FFFF:") == host2) { char *host3 = host2 + strlen("::ffff:"); if (dotted_ip(host3, 0)) { rfbLog("connect_tcp[ipv4]: trying fallback to IPv4 for %s\n", host2); fd = rfbConnectToTcpAddr(host3, port); if (fd < 0) { rfbLogPerror("connect_tcp[ipv4]: connection failed"); } } } free(host2); } return fd; }
void measure_send_rates(int init) { double cmp_rate, raw_rate; static double now, start = 0.0; static rfbDisplayHookPtr orig_display_hook = NULL; double cmp_max = 1.0e+08; /* 100 MB/sec */ double cmp_min = 1000.0; /* 9600baud */ double lat_max = 5.0; /* 5 sec */ double lat_min = .0005; /* 0.5 ms */ int min_cmp = 10000, nclients; rfbClientIteratorPtr iter; rfbClientPtr cl0, cl; int msg = 0, clcnt0 = 0, cc; int db = 0, ouch_db = 0, ouch = 0; if (! measure_speeds) { return; } if (speeds_net_rate && speeds_net_latency) { return; } if (!client_count) { return; } if (! orig_display_hook) { orig_display_hook = screen->displayHook; } if (start == 0.0) { dtime(&start); } dtime0(&now); if (now < last_client_gone+4.0) { return; } now = now - start; nclients = 0; if (!screen) { return; } cl0 = NULL; iter = rfbGetClientIterator(screen); while( (cl = rfbClientIteratorNext(iter)) ) { ClientData *cd = (ClientData *) cl->clientData; if (! cd) { continue; } if (cd->send_cmp_rate > 0.0) { continue; } if (cl->onHold) { continue; } nclients++; if (cl0 == NULL) { cl0 = cl; } } rfbReleaseClientIterator(iter); cl = cl0; cc = 0; while (cl != NULL && cc++ == 0) { int defer, i, cbs, rbs; char *httpdir; double dt, dt1 = 0.0, dt2, dt3; double tm, spin_max = 15.0, spin_lat_max = 1.5; int got_t2 = 0, got_t3 = 0; ClientData *cd = (ClientData *) cl->clientData; #if 0 for (i=0; i<MAX_ENCODINGS; i++) { cbs += cl->bytesSent[i]; } rbs = cl->rawBytesEquivalent; #else #if LIBVNCSERVER_HAS_STATS cbs = rfbStatGetSentBytes(cl); rbs = rfbStatGetSentBytesIfRaw(cl); #endif #endif if (init) { if (db) fprintf(stderr, "%d client num rects req: %d mod: %d cbs: %d " "rbs: %d dt1: %.3f t: %.3f\n", init, (int) sraRgnCountRects(cl->requestedRegion), (int) sraRgnCountRects(cl->modifiedRegion), cbs, rbs, dt1, now); cd->timer = dnow(); cd->cmp_bytes_sent = cbs; cd->raw_bytes_sent = rbs; continue; } /* first part of the bulk transfer of initial screen */ dt1 = dtime(&cd->timer); if (db) fprintf(stderr, "%d client num rects req: %d mod: %d cbs: %d " "rbs: %d dt1: %.3f t: %.3f\n", init, (int) sraRgnCountRects(cl->requestedRegion), (int) sraRgnCountRects(cl->modifiedRegion), cbs, rbs, dt1, now); if (dt1 <= 0.0) { continue; } cbs = cbs - cd->cmp_bytes_sent; rbs = rbs - cd->raw_bytes_sent; if (cbs < min_cmp) { continue; } if (ouch_db) fprintf(stderr, "START-OUCH: %d\n", client_count); clcnt0 = client_count; #define OUCH ( ouch || (ouch = (!client_count || client_count != clcnt0 || dnow() < last_client_gone+4.0)) ) rfbPE(1000); if (OUCH && ouch_db) fprintf(stderr, "***OUCH-A\n"); if (OUCH) continue; if (use_threads) LOCK(cl->updateMutex); if (sraRgnCountRects(cl->modifiedRegion)) { rfbPE(1000); if (OUCH && ouch_db) fprintf(stderr, "***OUCH-B\n"); if (use_threads) UNLOCK(cl->updateMutex); if (OUCH) continue; } if (use_threads) UNLOCK(cl->updateMutex); defer = screen->deferUpdateTime; httpdir = screen->httpDir; screen->deferUpdateTime = 0; screen->httpDir = NULL; /* mark a small rectangle: */ mark_rect_as_modified(0, 0, 16, 16, 1); dtime0(&tm); dt2 = 0.0; dt3 = 0.0; if (dt1 < 0.25) { /* try to cut it down to avoid long pauses. */ spin_max = 5.0; } /* when req1 = 1 mod1 == 0, end of 2nd part of bulk transfer */ while (1) { int req0, req1, mod0, mod1; if (OUCH && ouch_db) fprintf(stderr, "***OUCH-C1\n"); if (OUCH) break; if (use_threads) LOCK(cl->updateMutex); req0 = sraRgnCountRects(cl->requestedRegion); mod0 = sraRgnCountRects(cl->modifiedRegion); if (use_threads) UNLOCK(cl->updateMutex); if (use_threads) { usleep(1000); } else { if (mod0) { rfbPE(1000); } else { rfbCFD(1000); } } dt = dtime(&tm); dt2 += dt; if (dt2 > spin_max) { break; } if (OUCH && ouch_db) fprintf(stderr, "***OUCH-C2\n"); if (OUCH) break; if (use_threads) LOCK(cl->updateMutex); req1 = sraRgnCountRects(cl->requestedRegion); mod1 = sraRgnCountRects(cl->modifiedRegion); if (use_threads) UNLOCK(cl->updateMutex); if (db) fprintf(stderr, "dt2 calc: num rects req: %d/%d mod: %d/%d " "fbu-sent: %d dt: %.4f dt2: %.4f tm: %.4f\n", req0, req1, mod0, mod1, #if 0 cl->framebufferUpdateMessagesSent, #else #if LIBVNCSERVER_HAS_STATS rfbStatGetMessageCountSent(cl, rfbFramebufferUpdate), #endif #endif dt, dt2, tm); if (req1 != 0 && mod1 == 0) { got_t2 = 1; break; } } if (OUCH && ouch_db) fprintf(stderr, "***OUCH-D\n"); if (OUCH) goto ouch; if (! got_t2) { dt2 = 0.0; } else { int tr, trm = 3; double dts[10]; /* * Note: since often select(2) cannot sleep * less than 1/HZ (e.g. 10ms), the resolution * of the latency may be messed up by something * of this order. Effect may occur on both ends, * i.e. the viewer may not respond immediately. */ for (tr = 0; tr < trm; tr++) { usleep(5000); /* mark a 2nd small rectangle: */ mark_rect_as_modified(0, 0, 16, 16, 1); i = 0; dtime0(&tm); dt3 = 0.0; /* * when req1 > 0 and mod1 == 0, we say * that is the "ping" time. */ while (1) { int req0, req1, mod0, mod1; if (use_threads) LOCK(cl->updateMutex); req0 = sraRgnCountRects(cl->requestedRegion); mod0 = sraRgnCountRects(cl->modifiedRegion); if (use_threads) UNLOCK(cl->updateMutex); if (i == 0) { rfbPE(0); } else { if (use_threads) { usleep(1000); } else { /* try to get it all */ rfbCFD(1000*1000); } } if (OUCH && ouch_db) fprintf(stderr, "***OUCH-E\n"); if (OUCH) goto ouch; dt = dtime(&tm); i++; dt3 += dt; if (dt3 > spin_lat_max) { break; } if (use_threads) LOCK(cl->updateMutex); req1 = sraRgnCountRects(cl->requestedRegion); mod1 = sraRgnCountRects(cl->modifiedRegion); if (use_threads) UNLOCK(cl->updateMutex); if (db) fprintf(stderr, "dt3 calc: num rects req: %d/%d mod: %d/%d " "fbu-sent: %d dt: %.4f dt3: %.4f tm: %.4f\n", req0, req1, mod0, mod1, #if 0 cl->framebufferUpdateMessagesSent, #else #if LIBVNCSERVER_HAS_STATS rfbStatGetMessageCountSent(cl, rfbFramebufferUpdate), #endif #endif dt, dt3, tm); if (req1 != 0 && mod1 == 0) { dts[got_t3++] = dt3; break; } } } if (! got_t3) { dt3 = 0.0; } else { if (got_t3 == 1) { dt3 = dts[0]; } else if (got_t3 == 2) { dt3 = dts[1]; } else { if (dts[2] > 0.0) { double rat = dts[1]/dts[2]; if (rat > 0.5 && rat < 2.0) { dt3 = dts[1]+dts[2]; dt3 *= 0.5; } else { dt3 = dts[1]; } } else { dt3 = dts[1]; } } } } ouch: screen->deferUpdateTime = defer; screen->httpDir = httpdir; if (OUCH && ouch_db) fprintf(stderr, "***OUCH-F\n"); if (OUCH) break; dt = dt1 + dt2; if (dt3 <= dt2/2.0) { /* guess only 1/2 a ping for reply... */ dt = dt - dt3/2.0; } cmp_rate = cbs/dt; raw_rate = rbs/dt; if (cmp_rate > cmp_max) { cmp_rate = cmp_max; } if (cmp_rate <= cmp_min) { cmp_rate = cmp_min; } cd->send_cmp_rate = cmp_rate; cd->send_raw_rate = raw_rate; if (dt3 > lat_max) { dt3 = lat_max; } if (dt3 <= lat_min) { dt3 = lat_min; } cd->latency = dt3; rfbLog("client %d network rate %.1f KB/sec (%.1f eff KB/sec)\n", cd->uid, cmp_rate/1000.0, raw_rate/1000.0); rfbLog("client %d latency: %.1f ms\n", cd->uid, 1000.0*dt3); rfbLog("dt1: %.4f, dt2: %.4f dt3: %.4f bytes: %d\n", dt1, dt2, dt3, cbs); msg = 1; } if (msg) { int link, latency, netrate; char *str = "error"; link = link_rate(&latency, &netrate); if (link == LR_UNSET) { str = "LR_UNSET"; } else if (link == LR_UNKNOWN) { str = "LR_UNKNOWN"; } else if (link == LR_DIALUP) { str = "LR_DIALUP"; } else if (link == LR_BROADBAND) { str = "LR_BROADBAND"; } else if (link == LR_LAN) { str = "LR_LAN"; } rfbLog("link_rate: %s - %d ms, %d KB/s\n", str, latency, netrate); } if (init) { if (nclients) { screen->displayHook = measure_display_hook; } } else { screen->displayHook = orig_display_hook; } }
int xdamage_hint_skip(int y) { static sraRegionPtr scanline = NULL; static sraRegionPtr tmpl_y = NULL; int fast_tmpl = 1; sraRegionPtr reg, tmpl; int ret, i, n, nreg; #ifndef NO_NCACHE static int ncache_no_skip = 0; static double last_ncache_no_skip = 0.0; static double last_ncache_no_skip_long = 0.0, ncache_fac = 0.25; #endif if (! xdamage_present || ! use_xdamage) { return 0; /* cannot skip */ } if (! xdamage_regions) { return 0; /* cannot skip */ } if (! scanline) { /* keep it around to avoid malloc etc, recreate */ scanline = sraRgnCreate(); } if (! tmpl_y) { tmpl_y = sraRgnCreateRect(0, 0, dpy_x, 1); } nreg = (xdamage_memory * NSCAN) + 1; #ifndef NO_NCACHE if (ncache > 0) { if (ncache_no_skip == 0) { double now = g_now; if (now > last_ncache_no_skip + 8.0) { ncache_no_skip = 1; } else if (now < last_bs_restore + 0.5) { ncache_no_skip = 1; } else if (now < last_su_restore + 0.5) { ncache_no_skip = 1; } else if (now < last_copyrect + 0.5) { ncache_no_skip = 1; } if (ncache_no_skip) { last_ncache_no_skip = dnow(); if (now > last_ncache_no_skip_long + 60.0) { ncache_fac = 2.0; last_ncache_no_skip_long = now; } else { ncache_fac = 0.25; } return 0; } } else { if (ncache_no_skip++ >= ncache_fac*nreg + 4) { ncache_no_skip = 0; } else { return 0; } } } #endif if (fast_tmpl) { sraRgnOffset(tmpl_y, 0, y); tmpl = tmpl_y; } else { tmpl = sraRgnCreateRect(0, y, dpy_x, y+1); } ret = 1; for (i=0; i<nreg; i++) { /* go back thru the history starting at most recent */ n = (xdamage_ticker + nreg - i) % nreg; reg = xdamage_regions[n]; if (reg == NULL) { continue; } if (sraRgnEmpty(reg)) { /* checking for emptiness is very fast */ continue; } sraRgnMakeEmpty(scanline); sraRgnOr(scanline, tmpl); if (sraRgnAnd(scanline, reg)) { ret = 0; break; } } if (fast_tmpl) { sraRgnOffset(tmpl_y, 0, -y); } else { sraRgnDestroy(tmpl); } if (0) fprintf(stderr, "xdamage_hint_skip: %d -> %d\n", y, ret); return ret; }
int collect_xdamage(int scancnt, int call) { #if HAVE_LIBXDAMAGE XDamageNotifyEvent *dev; XEvent ev; sraRegionPtr tmpregion; sraRegionPtr reg; static int rect_count = 0; int nreg, ccount = 0, dcount = 0, ecount = 0; static time_t last_rpt = 0; time_t now; int x, y, w, h, x2, y2; int i, dup, next = 0, dup_max = 0; #define DUPSZ 32 int dup_x[DUPSZ], dup_y[DUPSZ], dup_w[DUPSZ], dup_h[DUPSZ]; double tm, dt; int mark_all = 0, retries = 0, too_many = 1000, tot_ev = 0; RAWFB_RET(0) if (scancnt) {} /* unused vars warning: */ if (! xdamage_present || ! use_xdamage) { return 0; } if (! xdamage) { return 0; } if (! xdamage_base_event_type) { return 0; } if (! xdamage_regions) { return 0; } dtime0(&tm); nreg = (xdamage_memory * NSCAN) + 1; if (call == 0) { xdamage_ticker = (xdamage_ticker+1) % nreg; xdamage_direct_count = 0; reg = xdamage_regions[xdamage_ticker]; if (reg != NULL) { sraRgnMakeEmpty(reg); } } else { if (xdamage_ticker < 0) { xdamage_ticker = 0; } reg = xdamage_regions[xdamage_ticker]; } if (reg == NULL) { return 0; } X_LOCK; if (0) XFlush_wr(dpy); if (0) XEventsQueued(dpy, QueuedAfterFlush); come_back_for_more: while (XCheckTypedEvent(dpy, xdamage_base_event_type+XDamageNotify, &ev)) { /* * TODO max cut off time in this loop? * Could check QLength and if huge just mark the whole * screen. */ ecount++; tot_ev++; if (mark_all) { continue; } if (ecount == too_many) { int nqa = XEventsQueued(dpy, QueuedAlready); if (nqa >= too_many) { static double last_msg = 0.0; tmpregion = sraRgnCreateRect(0, 0, dpy_x, dpy_y); sraRgnOr(reg, tmpregion); sraRgnDestroy(tmpregion); if (dnow() > last_msg + xdamage_crazy_delay) { rfbLog("collect_xdamage: too many xdamage events %d+%d\n", ecount, nqa); last_msg = dnow(); } mark_all = 1; } } if (ev.type != xdamage_base_event_type + XDamageNotify) { break; } dev = (XDamageNotifyEvent *) &ev; if (dev->damage != xdamage) { continue; /* not ours! */ } x = dev->area.x; y = dev->area.y; w = dev->area.width; h = dev->area.height; /* * we try to manually remove some duplicates because * certain activities can lead to many 10's of dups * in a row. The region work can be costly and reg is * later used in xdamage_hint_skip loops, so it is good * to skip them if possible. */ dup = 0; for (i=0; i < dup_max; i++) { if (dup_x[i] == x && dup_y[i] == y && dup_w[i] == w && dup_h[i] == h) { dup = 1; break; } } if (dup) { dcount++; continue; } if (dup_max < DUPSZ) { next = dup_max; dup_max++; } else { next = (next+1) % DUPSZ; } dup_x[next] = x; dup_y[next] = y; dup_w[next] = w; dup_h[next] = h; /* translate if needed */ if (clipshift) { /* set coords relative to fb origin */ if (0 && rootshift) { /* * Note: not needed because damage is * relative to subwin, not rootwin. */ x = x - off_x; y = y - off_y; } if (clipshift) { x = x - coff_x; y = y - coff_y; } x2 = x + w; /* upper point */ x = nfix(x, dpy_x); /* place both in fb area */ x2 = nfix(x2, dpy_x+1); w = x2 - x; /* recompute w */ y2 = y + h; y = nfix(y, dpy_y); y2 = nfix(y2, dpy_y+1); h = y2 - y; if (w <= 0 || h <= 0) { continue; } } if (debug_xdamage > 2) { fprintf(stderr, "xdamage: -> event %dx%d+%d+%d area:" " %d dups: %d %s\n", w, h, x, y, w*h, dcount, (w*h > xdamage_max_area) ? "TOO_BIG" : ""); } record_desired_xdamage_rect(x, y, w, h); tmpregion = sraRgnCreateRect(x, y, x + w, y + h); sraRgnOr(reg, tmpregion); sraRgnDestroy(tmpregion); rect_count++; ccount++; } if (mark_all) { if (ecount + XEventsQueued(dpy, QueuedAlready) >= 3 * too_many && retries < 3) { retries++; XFlush_wr(dpy); usleep(20 * 1000); XFlush_wr(dpy); ecount = 0; goto come_back_for_more; } } /* clear the whole damage region for next time. XXX check */ if (call == 1) { XDamageSubtract(dpy, xdamage, None, None); } X_UNLOCK; if (tot_ev > 20 * too_many) { rfbLog("collect_xdamage: xdamage has gone crazy (screensaver or game?) ev: %d ret: %d\n", tot_ev, retries); rfbLog("collect_xdamage: disabling xdamage for %d seconds.\n", (int) xdamage_crazy_delay); destroy_xdamage_if_needed(); X_LOCK; XSync(dpy, False); while (XCheckTypedEvent(dpy, xdamage_base_event_type+XDamageNotify, &ev)) { ; } X_UNLOCK; xdamage_crazy_time = dnow(); } if (0 && xdamage_direct_count) { fb_push(); } dt = dtime(&tm); if ((debug_tiles > 1 && ecount) || (debug_tiles && ecount > 200) || debug_xdamage > 1) { fprintf(stderr, "collect_xdamage(%d): %.4f t: %.4f ev/dup/accept" "/direct %d/%d/%d/%d\n", call, dt, tm - x11vnc_start, ecount, dcount, ccount, xdamage_direct_count); } now = time(NULL); if (! last_rpt) { last_rpt = now; } if (now > last_rpt + 15) { double rat = -1.0; if (XD_tot) { rat = ((double) XD_skip)/XD_tot; } if (debug_tiles || debug_xdamage) { fprintf(stderr, "xdamage: == scanline skip/tot: " "%04d/%04d =%.3f rects: %d desired: %d\n", XD_skip, XD_tot, rat, rect_count, XD_des); } XD_skip = 0; XD_tot = 0; XD_des = 0; rect_count = 0; last_rpt = now; } #else if (0) scancnt++; /* compiler warnings */ if (0) call++; if (0) record_desired_xdamage_rect(0, 0, 0, 0); #endif return 0; }
void macosxCGS_get_all_windows(void) { static double last = 0.0; static int totcnt = 0; double dt = 0.0, now = dnow(); int i, db = 0, whist_prv = 0, maxwin = 0, whist_skip = 0; CGSWindowCount cap = (CGSWindowCount) MAXWINDAT; CGSError err; CGS_levelmax = 0; CGS_levels[CGS_levelmax++] = (int) kCGDraggingWindowLevel; /* 500 ? */ if (0) CGS_levels[CGS_levelmax++] = (int) kCGHelpWindowLevel; /* 102 ? */ if (macosx_ncache_macmenu) CGS_levels[CGS_levelmax++] = (int) kCGPopUpMenuWindowLevel; /* 101 pulldown menu */ CGS_levels[CGS_levelmax++] = (int) kCGMainMenuWindowLevelKey; /* 24 ? */ CGS_levels[CGS_levelmax++] = (int) kCGModalPanelWindowLevel; /* 8 open dialog box */ CGS_levels[CGS_levelmax++] = (int) kCGFloatingWindowLevel; /* 3 ? */ CGS_levels[CGS_levelmax++] = (int) kCGNormalWindowLevel; /* 0 regular window */ if (cid == NULL) { cid = _CGSDefaultConnection(); if (cid == NULL) { return; } } if (dt > 0.0 && now < last + dt) { return; } last = now; macwinmax = 0; totcnt++; if (ncache > 0) { whist_prv = whist_idx++; if (whist_prv < 0) { whist_skip = 1; whist_prv = 0; } whist_idx = whist_idx % WINHISTMAX; for (i=0; i < WINHISTNUM; i++) { whist[whist_idx][i] = 0; qlook[i] = -1; } } err = CGSGetWindowList(cid, NULL, cap, _wins_all, &_wins_all_cnt); if (db) fprintf(stderr, "cnt: %d err: %d\n", (int) _wins_all_cnt, err); if (err != 0) { return; } for (i=0; i < (int) _wins_all_cnt; i++) { CGSRect rect; CGSWindowLevel level; int j, keepit = 0; err = CGSGetScreenRectForWindow(cid, _wins_all[i], &rect); if (err != 0) { continue; } if (rect.origin.x == 0 && rect.origin.y == 0) { if (rect.size.width == dpy_x) { if (rect.size.height == dpy_y) { continue; } } } err = CGSGetWindowLevel(cid, _wins_all[i], &level); if (err != 0) { continue; } for (j=0; j<CGS_levelmax; j++) { if ((int) level == CGS_levels[j]) { keepit = 1; break; } } if (! keepit) { continue; } macwins[macwinmax].level = (int) level; macwins[macwinmax].win = (int) _wins_all[i]; macwins[macwinmax].x = (int) rect.origin.x; macwins[macwinmax].y = (int) rect.origin.y; macwins[macwinmax].width = (int) rect.size.width; macwins[macwinmax].height = (int) rect.size.height; macwins[macwinmax].mapped = 0; macwins[macwinmax].clipped = 0; macwins[macwinmax].ncache_only = 0; if (level == kCGPopUpMenuWindowLevel) { macwins[macwinmax].ncache_only = 1; } if (0 || db) fprintf(stderr, "i=%03d ID: %06d x: %03d y: %03d w: %03d h: %03d level: %d\n", i, _wins_all[i], (int) rect.origin.x, (int) rect.origin.y,(int) rect.size.width, (int) rect.size.height, (int) level); if (macwins[macwinmax].win < WINHISTNUM) { qlook[macwins[macwinmax].win] = macwinmax; if (macwins[macwinmax].win > maxwin) { maxwin = macwins[macwinmax].win; } } macwinmax++; } err = CGSGetOnScreenWindowList(cid, NULL, cap, _wins_mapped, &_wins_mapped_cnt); if (db) fprintf(stderr, "cnt: %d err: %d\n", (int) _wins_mapped_cnt, err); if (err != 0) { return; } for (i=0; i < (int) _wins_mapped_cnt; i++) { int j, idx = -1; int win = (int) _wins_mapped[i]; if (0 <= win && win < WINHISTNUM) { j = qlook[win]; if (j >= 0 && macwins[j].win == win) { idx = j; } } if (idx < 0) { for (j=0; j < macwinmax; j++) { if (macwins[j].win == win) { idx = j; break; } } } if (idx >= 0) { macwins[idx].mapped = 1; } } if (ncache > 0) { int nv= 0, NBMAX = 64; int nv_win[64]; int nv_lvl[64]; int nv_vis[64]; for (i=0; i < macwinmax; i++) { int win = macwins[i].win; char prev, curr; if (win >= WINHISTNUM) { continue; } whist[whist_idx][win] |= is_exist; if (macwins[i].mapped) { whist[whist_idx][win] |= is_mapped; if (check_clipped(win)) { whist[whist_idx][win] |= is_clipped; macwins[i].clipped = 1; } if (check_offscreen(win)) { whist[whist_idx][win] |= is_offscreen; } } else { whist[whist_idx][win] |= is_offscreen; } curr = whist[whist_idx][win]; prev = whist[whist_prv][win]; if (whist_skip) { ; } else if ( !(prev & is_mapped) && (curr & is_mapped)) { /* MapNotify */ if (0) fprintf(stderr, "MapNotify: %d/%d %d %.4f tot=%d\n", prev, curr, win, dnowx(), totcnt); macosx_add_mapnotify(win, macwins[i].level, 1); if (0) macosxCGS_follow_animation_win(win, i, 1); } else if ( !(curr & is_mapped) && (prev & is_mapped)) { /* UnmapNotify */ if (0) fprintf(stderr, "UnmapNotify: %d/%d %d %.4f A tot=%d\n", prev, curr, win, dnowx(), totcnt); macosx_add_mapnotify(win, macwins[i].level, 0); } else if ( !(prev & is_exist) && (curr & is_exist)) { /* CreateNotify */ 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); macosx_add_create(win, macwins[i].level); if (curr & is_mapped) { if (0) fprintf(stderr, "MapNotify: %d/%d %d %.4f tot=%d\n", prev, curr, win, dnowx(), totcnt); macosx_add_mapnotify(win, macwins[i].level, 1); } } if (whist_skip) { ; } else if (nv >= NBMAX) { ; } else if (!(curr & is_mapped)) { ; } else if (!(prev & is_mapped)) { if (1) { ; } else if (curr & is_clipped) { if (0) fprintf(stderr, "VisibNotify: %d/%d %d OBS tot=%d\n", prev, curr, win, totcnt); nv_win[nv] = win; nv_lvl[nv] = macwins[i].level; nv_vis[nv++] = 1; } else { if (0) fprintf(stderr, "VisibNotify: %d/%d %d UNOBS tot=%d\n", prev, curr, win, totcnt); nv_win[nv] = win; nv_lvl[nv] = macwins[i].level; nv_vis[nv++] = 0; } } else { if ( !(prev & is_clipped) && (curr & is_clipped) ) { if (0) fprintf(stderr, "VisibNotify: %d/%d %d OBS tot=%d\n", prev, curr, win, totcnt); nv_win[nv] = win; nv_lvl[nv] = macwins[i].level; nv_vis[nv++] = 1; } else if ( (prev & is_clipped) && !(curr & is_clipped) ) { if (0) fprintf(stderr, "VisibNotify: %d/%d %d UNOBS tot=%d\n", prev, curr, win, totcnt); nv_win[nv] = win; nv_lvl[nv] = macwins[i].level; nv_vis[nv++] = 0; } } } for (i=0; i < maxwin; i++) { char prev, curr; int win = i; int q = qlook[i]; int lvl = 0; if (whist_skip) { break; } if (q >= 0) { lvl = macwins[q].level; } curr = whist[whist_idx][win]; prev = whist[whist_prv][win]; if (!(curr & is_exist) && (prev & is_exist)) { if (prev & is_mapped) { if (0) fprintf(stderr, "UnmapNotify: %d/%d %d %.4f B tot=%d\n", prev, curr, win, dnowx(), totcnt); macosx_add_mapnotify(win, lvl, 0); } /* DestroyNotify */ if (0) fprintf(stderr, "DestroNotify:%d/%d %d %.4f tot=%d\n", prev, curr, win, dnowx(), totcnt); macosx_add_destroy(win, lvl); } } if (nv) { int k; for (k = 0; k < nv; k++) { macosx_add_visnotify(nv_win[k], nv_lvl[k], nv_vis[k]); } } } }
int macosxCGS_follow_animation_win(int win, int idx, int grow) { double t = dnow(); int diffs = 0; int x, y, w, h; int xp = -1, yp = -1, wp = -1, hp = -1; CGSRect rect; CGSError err; int reps = 0; if (cid == NULL) { cid = _CGSDefaultConnection(); if (cid == NULL) { return 0; } } if (idx < 0) { idx = macosxCGS_find_index(win); } if (idx < 0) { return 0; } while (dnow() < t + 0.001 * macosx_icon_anim_time) { err = CGSGetScreenRectForWindow(cid, win, &rect); if (err != 0) { break; } x = (int) rect.origin.x; y = (int) rect.origin.y; w = (int) rect.size.width; h = (int) rect.size.height; if (grow) { macwins[idx].x = x; macwins[idx].y = y; macwins[idx].width = w; macwins[idx].height = h; } if (0) fprintf(stderr, " chase: %03dx%03d+%03d+%03d %d\n", w, h, x, y, win); if (x == xp && y == yp && w == wp && h == hp) { reps++; if (reps >= 2) { break; } } else { diffs++; reps = 0; } xp = x; yp = y; wp = w; hp = h; usleep(50 * 1000); } if (diffs >= 2) { return 1; } else { return 0; } }