From 56eb45a5f8ab93abb1e15d4c0b8214d06a3d6d18 Mon Sep 17 00:00:00 2001 From: runge Date: Thu, 28 Dec 2006 05:24:25 +0000 Subject: x11vnc: more work on -ncache. --- x11vnc/userinput.c | 3628 +++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 3056 insertions(+), 572 deletions(-) (limited to 'x11vnc/userinput.c') diff --git a/x11vnc/userinput.c b/x11vnc/userinput.c index 60fa75d..31f1864 100644 --- a/x11vnc/userinput.c +++ b/x11vnc/userinput.c @@ -16,6 +16,8 @@ #include "xrandr.h" #include "8to24.h" #include "unixpw.h" +#include "macosx.h" +#include "macosxCGS.h" /* * user input handling heuristics @@ -39,7 +41,7 @@ void initialize_max_keyrepeat(void); int direct_fb_copy(int x1, int y1, int x2, int y2, int mark); void fb_push(void); -void fb_push_wait(double max_wait, int flags); +int fb_push_wait(double max_wait, int flags); void eat_viewonly_input(int max_eat, int keep); void mark_for_xdamage(int x, int y, int w, int h); @@ -53,7 +55,7 @@ int check_xrecord(void); int check_wireframe(void); int fb_update_sent(int *count); int check_user_input(double dt, double dtr, int tile_diffs, int *cnt); -void do_copyregion(sraRegionPtr region, int dx, int dy); +void do_copyregion(sraRegionPtr region, int dx, int dy, int mode); static void get_client_regions(int *req, int *mod, int *cpy, int *num) ; static void parse_scroll_copyrect_str(char *scr); @@ -63,9 +65,9 @@ static void draw_box(int x, int y, int w, int h, int restore); static int do_bdpush(Window wm_win, int x0, int y0, int w0, int h0, int bdx, int bdy, int bdskinny); static int set_ypad(void); -static void scale_mark(int x1, int y1, int x2, int y2); +static void scale_mark(int x1, int y1, int x2, int y2, int mark); static int push_scr_ev(double *age, int type, int bdpush, int bdx, int bdy, - int bdskinny); + int bdskinny, int first_push); static int crfix(int x, int dx, int Lx); static int scrollability(Window win, int set); static int eat_pointer(int max_ptr_eat, int keep); @@ -74,7 +76,7 @@ static int repeat_check(double last_key_scroll); static int check_xrecord_keys(void); static int check_xrecord_mouse(void); static int try_copyrect(Window frame, int x, int y, int w, int h, int dx, int dy, - int *obscured, sraRegionPtr extra_clip, double max_wait); + int *obscured, sraRegionPtr extra_clip, double max_wait, int *nbatch); static int wireframe_mod_state(); static void check_user_input2(double dt); static void check_user_input3(double dt, double dtr, int tile_diffs); @@ -1336,13 +1338,13 @@ static int set_ypad(void) { return y_accum; } -static void scale_mark(int x1, int y1, int x2, int y2) { +static void scale_mark(int x1, int y1, int x2, int y2, int mark) { int s = 2; x1 = nfix(x1 - s, dpy_x); y1 = nfix(y1 - s, dpy_y); x2 = nfix(x2 + s, dpy_x+1); y2 = nfix(y2 + s, dpy_y+1); - scale_and_mark_rect(x1, y1, x2, y2); + scale_and_mark_rect(x1, y1, x2, y2, mark); } #define PUSH_TEST(n) \ @@ -1353,8 +1355,12 @@ if (n) { \ fprintf(stderr, "---PUSH\n"); \ } +int batch_dxs[], batch_dys[]; +sraRegionPtr batch_reg[]; +void batch_copyregion(sraRegionPtr* region, int *dx, int *dy, int ncr, double delay); + static int push_scr_ev(double *age, int type, int bdpush, int bdx, int bdy, - int bdskinny) { + int bdskinny, int first_push) { Window frame, win, win0; int x, y, w, h, wx, wy, ww, wh, dx, dy; int x0, y0, w0, h0; @@ -1368,6 +1374,7 @@ static int push_scr_ev(double *age, int type, int bdpush, int bdx, int bdy, int link, latency, netrate; int ypad = 0; double last_scroll_event_save = last_scroll_event; + int fast_push = 0, rc; /* we return the oldest one. */ *age = 0.0; @@ -1403,7 +1410,7 @@ static int push_scr_ev(double *age, int type, int bdpush, int bdx, int bdy, ypad = set_ypad(); -if (db) fprintf(stderr, "ypad: %d dy[0]: %d\n", ypad, scr_ev[0].dy); +if (db) fprintf(stderr, "ypad: %d dy[0]: %d ev_tot: %d\n", ypad, scr_ev[0].dy, ev_tot); for (ev=0; ev < ev_tot; ev++) { double ag; @@ -1545,19 +1552,39 @@ if (db > 1) fprintf(stderr, "------------ got: %d x: %4d y: %3d" } } } - - if (try_copyrect(frame, x, y, w, h, dx, dy, &obscured, - tmpregion, waittime)) { - last_scroll_type = type; - dtime0(&last_scroll_event); - do_fb_push++; - urgent_update = 1; - sraRgnDestroy(tmpregion); - -PUSH_TEST(0); + if (fast_push) { + int k, nbatch = 0; + double delay, d1 = 0.1, d2 = 0.02; + rc = try_copyrect(frame, x, y, w, h, dx, dy, &obscured, + tmpregion, waittime, &nbatch); + + if (first_push) { + delay = d1; + } else { + delay = d2; + } + batch_copyregion(batch_reg, batch_dxs, batch_dys, nbatch, delay); + for (k=0; k < nbatch; k++) { + sraRgnDestroy(batch_reg[k]); + } + fb_push(); } else { + rc = try_copyrect(frame, x, y, w, h, dx, dy, &obscured, + tmpregion, waittime, NULL); + if (rc) { + last_scroll_type = type; + dtime0(&last_scroll_event); + + do_fb_push++; + urgent_update = 1; + sraRgnDestroy(tmpregion); +PUSH_TEST(0); + } + } + + if (! rc) { dret = 0; sraRgnDestroy(tmpregion); break; @@ -1661,6 +1688,10 @@ if (db) fprintf(stderr, " EST_TOO_LARGE"); dtime(&tm); if (db) fprintf(stderr, " DFC(%d,%d-%d,%d)", tx1, ty1, tx2, ty2); direct_fb_copy(tx1, ty1, tx2, ty2, 1); + if (fast_push) { + fb_push(); + } +//fb_push(); do_fb_push++; PUSH_TEST(0); } @@ -1685,6 +1716,9 @@ if (db && bdpush) fprintf(stderr, "BDPUSH-TIME: 0x%lx\n", xrecord_wm_window); h = scr_ev[0].h; do_fb_push += do_bdpush(xrecord_wm_window, x, y, w, h, bdx, bdy, bdskinny); + if (fast_push) { + fb_push(); + } } if (do_fb_push) { @@ -1721,7 +1755,7 @@ if (0) fprintf(stderr, " fb_push dt: %.4f", dt); */ } else if (now > last_time + delay) { - scale_mark(x0, y0, x0 + w0, y0 + h0); + scale_mark(x0, y0, x0 + w0, y0 + h0, 1); last_copyrect_fix = now; } last_time = now; @@ -1758,7 +1792,11 @@ static void get_client_regions(int *req, int *mod, int *cpy, int *num) { * is being done. Note that copyrect under the scaling case is often * only approximate. */ -void do_copyregion(sraRegionPtr region, int dx, int dy) { +int DCR_Normal = 0; +int DCR_FBOnly = 1; +int DCR_Direct = 2; + +void do_copyregion(sraRegionPtr region, int dx, int dy, int mode) { sraRectangleIterator *iter; sraRect rect; int Bpp0 = bpp/8, Bpp; @@ -1769,14 +1807,15 @@ void do_copyregion(sraRegionPtr region, int dx, int dy) { last_copyrect = dnow(); - if (rfb_fb == main_fb && ! rotating) { + if (rfb_fb == main_fb && ! rotating && mode == DCR_Normal) { /* normal case, no -scale or -8to24 */ get_client_regions(&req, &mod, &cpy, &ncli); -if (debug_scroll > 1) fprintf(stderr, "<<<-rfbDoCopyRect req: %d mod: %d cpy: %d\n", req, mod, cpy); +if (debug_scroll > 1) fprintf(stderr, ">>>-rfbDoCopyRect req: %d mod: %d cpy: %d\n", req, mod, cpy); + rfbDoCopyRegion(screen, region, dx, dy); get_client_regions(&req, &mod, &cpy, &ncli); -if (debug_scroll > 1) fprintf(stderr, ">>>-rfbDoCopyRect req: %d mod: %d cpy: %d\n", req, mod, cpy); +if (debug_scroll > 1) fprintf(stderr, "<<<-rfbDoCopyRect req: %d mod: %d cpy: %d\n", req, mod, cpy); return; } @@ -1786,14 +1825,13 @@ if (debug_scroll > 1) fprintf(stderr, ">>>-rfbDoCopyRect req: %d mod: %d cpy: %d iter = sraRgnGetReverseIterator(region, dx < 0, dy < 0); while(sraRgnIteratorNext(iter, &rect)) { - int j, c, t; + int j, c, t, Dx, Dy; x1 = rect.x1; y1 = rect.y1; x2 = rect.x2; y2 = rect.y2; - for (c= 0; c < 2; c++) { Bpp = Bpp0; @@ -1834,6 +1872,10 @@ if (debug_scroll > 1) fprintf(stderr, ">>>-rfbDoCopyRect req: %d mod: %d cpy: %d } } + if (mode == DCR_FBOnly) { + continue; + } + if (scaling) { sx1 = ((double) x1 / dpy_x) * scaled_x; @@ -1851,6 +1893,7 @@ if (debug_scroll > 1) fprintf(stderr, ">>>-rfbDoCopyRect req: %d mod: %d cpy: %d sdy = dy; } if (0) fprintf(stderr, "s... %d %d %d %d %d %d\n", sx1, sy1, sx2, sy2, sdx, sdy); + if (rotating) { rotate_coords(sx1, sy1, &sx1, &sy1, -1, -1); rotate_coords(sx2, sy2, &sx2, &sy2, -1, -1); @@ -1879,6 +1922,11 @@ if (0) fprintf(stderr, "s... %d %d %d %d %d %d\n", sx1, sy1, sx2, sy2, sdx, sdy) sdy = -t; } } + + /* XXX -1? */ + if (sx2 < 0) sx2 = 0; + if (sy2 < 0) sy2 = 0; + if (sx2 < sx1) { t = sx1; sx1 = sx2; @@ -1891,12 +1939,80 @@ if (0) fprintf(stderr, "s... %d %d %d %d %d %d\n", sx1, sy1, sx2, sy2, sdx, sdy) } if (0) fprintf(stderr, "s... %d %d %d %d %d %d\n", sx1, sy1, sx2, sy2, sdx, sdy); - rfbDoCopyRect(screen, sx1, sy1, sx2, sy2, sdx, sdy); + if (mode == DCR_Direct) { + rfbClientIteratorPtr i; + rfbClientPtr cl; + sraRegionPtr r = sraRgnCreateRect(sx1, sy1, sx2, sy2); + + i = rfbGetClientIterator(screen); + while( (cl = rfbClientIteratorNext(i)) ) { + rfbSendCopyRegion(cl, r, sdx, sdy); + } + rfbReleaseClientIterator(i); + sraRgnDestroy(r); + + } else { + rfbDoCopyRect(screen, sx1, sy1, sx2, sy2, sdx, sdy); + } } sraRgnReleaseIterator(iter); } -void fb_push(void) { +void batch_copyregion(sraRegionPtr* region, int *dx, int *dy, int ncr, double delay) { + rfbClientIteratorPtr i; + rfbClientPtr cl; + int k, direct, mode, nrects = 0; + int hid_cursor = 0; + +/* XXX Y */ + + if (delay < 0.0) { + delay = 0.1; + } + fb_push_wait(delay, FB_COPY|FB_MOD); + + for (k=0; k < ncr; k++) { + nrects += sraRgnCountRects(region[k]); + } + + i = rfbGetClientIterator(screen); + while( (cl = rfbClientIteratorNext(i)) ) { + rfbFramebufferUpdateMsg *fu = (rfbFramebufferUpdateMsg *)cl->updateBuf; + fu->nRects = Swap16IfLE((uint16_t)(nrects)); + fu->type = rfbFramebufferUpdate; + + if (cl->ublen != 0) fprintf(stderr, "batch_copyregion: *** ublen != 0: %d\n", cl->ublen); + + cl->ublen = sz_rfbFramebufferUpdateMsg; + } + rfbReleaseClientIterator(i); + + if (rfb_fb == main_fb && !rotating) { + direct = 0; + mode = DCR_FBOnly; + } else { + direct = 1; + mode = DCR_Direct; + } + for (k=0; k < ncr; k++) { + do_copyregion(region[k], dx[k], dy[k], mode); + } + i = rfbGetClientIterator(screen); + while( (cl = rfbClientIteratorNext(i)) ) { + if (!direct) { + for (k=0; k < ncr; k++) { + rfbSendCopyRegion(cl, region[k], dx[k], dy[k]); + } + } + rfbSendUpdateBuf(cl); + } + rfbReleaseClientIterator(i); + +fprintf(stderr, "batch_copyregion: nrects: %d nregions: %d\n", nrects, ncr); + +} + +void fb_push0(void) { char *httpdir = screen->httpDir; int defer = screen->deferUpdateTime; int req0, mod0, cpy0, req1, mod1, cpy1, ncli; @@ -1912,17 +2028,51 @@ if (db) get_client_regions(&req0, &mod0, &cpy0, &ncli); screen->httpDir = httpdir; screen->deferUpdateTime = defer; - if (db) { +if (db) { get_client_regions(&req1, &mod1, &cpy1, &ncli); fprintf(stderr, "\nFB_push: req: %d/%d mod: %d/%d cpy: %d/%d %.4f\n", - req0, req1, mod0, mod1, cpy0, cpy1, dnow() - x11vnc_start); - } + req0, req1, mod0, mod1, cpy0, cpy1, dnowx()); +} + +} + +void fb_push(void) { + int req0, mod0, cpy0, req1, mod1, cpy1, ncli; + int db = (debug_scroll || debug_wireframe); + rfbClientIteratorPtr i; + rfbClientPtr cl; + +/* XXX Y */ +db = 0; + +if (db) get_client_regions(&req0, &mod0, &cpy0, &ncli); + + i = rfbGetClientIterator(screen); + while( (cl = rfbClientIteratorNext(i)) ) { + if (cl->sock >= 0 && !cl->onHold && FB_UPDATE_PENDING(cl) && + !sraRgnEmpty(cl->requestedRegion)) { + if (!rfbSendFramebufferUpdate(cl, cl->modifiedRegion)) { + fprintf(stderr, "*** rfbSendFramebufferUpdate FAILED #1\n"); + if (cl->ublen) fprintf(stderr, "*** fb_push ublen not zero: %d\n", cl->ublen); + break; + } + if (cl->ublen) fprintf(stderr, "*** fb_push ublen not zero: %d\n", cl->ublen); + } + } + rfbReleaseClientIterator(i); + +if (db) { + get_client_regions(&req1, &mod1, &cpy1, &ncli); + fprintf(stderr, "\nFB_push: req: %d/%d mod: %d/%d cpy: %d/%d %.4f\n", + req0, req1, mod0, mod1, cpy0, cpy1, dnowx()); +} } -void fb_push_wait(double max_wait, int flags) { +int fb_push_wait0(double max_wait, int flags) { double tm, dt = 0.0; int req, mod, cpy, ncli; + int ok = 0; dtime0(&tm); while (dt < max_wait) { @@ -1939,6 +2089,7 @@ void fb_push_wait(double max_wait, int flags) { done = 0; } if (done) { + ok = 1; break; } @@ -1946,6 +2097,42 @@ void fb_push_wait(double max_wait, int flags) { fb_push(); dt += dtime(&tm); } + return ok; +} + +int fb_push_wait(double max_wait, int flags) { + double tm, dt = 0.0; + int req, mod, cpy, ncli; + int ok = 0, first = 1; + + dtime0(&tm); + while (dt < max_wait) { + int done = 1; + fb_push(); + get_client_regions(&req, &mod, &cpy, &ncli); + if (flags & FB_COPY && cpy) { + done = 0; + } + if (flags & FB_MOD && mod) { + done = 0; + } + if (flags & FB_REQ && req) { + done = 0; + } + if (done) { + ok = 1; + break; + } + if (first) { + first = 0; + continue; + } + + rfbCFD(0); + usleep(1000); + dt += dtime(&tm); + } + return ok; } /* @@ -2359,7 +2546,7 @@ if (0 || db) fprintf(stderr, "check_xrecord: SPIN-OUT: %.3f/%.3f\n", spin, dtime0(&tm); age = max_age; - dret = push_scr_ev(&age, SCR_KEY, bdpush, bdx, bdy, bdskinny); + dret = push_scr_ev(&age, SCR_KEY, bdpush, bdx, bdy, bdskinny, 1); dt = dtime(&tm); ret = 1 + dret; @@ -2441,6 +2628,7 @@ static int check_xrecord_mouse(void) { int already_down = 0, max_ptr_eat = 20; static int want_back_in = 0; int came_back_in; + int first_push = 1; int scroll_wheel = 0; int btn4 = (1<<3); @@ -2475,6 +2663,7 @@ if (0) fprintf(stderr, "check_xrecord_mouse: IN xrecording: %d\n", xrecording); } if (want_back_in) { came_back_in = 1; + first_push = 0; } else { came_back_in = 0; } @@ -2576,7 +2765,8 @@ if (db) fprintf(stderr, "check_xrecord_mouse: BEGIN LOOP: scr_ev_cnt: " dtime0(&tm); dret = push_scr_ev(&age, SCR_MOUSE, bdpush, bdx, - bdy, bdskinny); + bdy, bdskinny, first_push); + if (first_push) first_push = 0; ret = 1 + dret; dt = dtime(&tm); @@ -2837,8 +3027,12 @@ if (0) fprintf(stderr, "check_xrecord: button_mask: %d mouse_wants_back_in: %d\ db2 = 1; \ } +#define NBATCHMAX 1024 +int batch_dxs[NBATCHMAX], batch_dys[NBATCHMAX]; +sraRegionPtr batch_reg[NBATCHMAX]; + static int try_copyrect(Window frame, int x, int y, int w, int h, int dx, int dy, - int *obscured, sraRegionPtr extra_clip, double max_wait) { + int *obscured, sraRegionPtr extra_clip, double max_wait, int *nbatch) { static int dt_bad = 0; static time_t dt_bad_check = 0; @@ -2847,15 +3041,19 @@ static int try_copyrect(Window frame, int x, int y, int w, int h, int dx, int dy double tm, dt; DB_SET - get_client_regions(&req, &mod, &cpy, &ncli); - if (cpy) { - /* one is still pending... try to force it out: */ - fb_push_wait(max_wait, FB_COPY); - + if (nbatch == NULL) { get_client_regions(&req, &mod, &cpy, &ncli); - } - if (cpy) { - return 0; + if (cpy) { + /* one is still pending... try to force it out: */ + if (!fb_push_wait(max_wait, FB_COPY)) { + fb_push_wait(max_wait/2, FB_COPY); + } + + get_client_regions(&req, &mod, &cpy, &ncli); + } + if (cpy) { + return 0; + } } *obscured = 0; @@ -2907,7 +3105,14 @@ if (db2) fprintf(stderr, "try_copyrect: 0x%lx bad: %d stack_list_num: %d\n", fr sraRgnDestroy(bo_rect); } } - do_copyregion(rect, dx, dy); + if (!nbatch) { + do_copyregion(rect, dx, dy, 0); + } else { + batch_dxs[*nbatch] = dx; + batch_dys[*nbatch] = dy; + batch_reg[*nbatch] = sraRgnCreateRgn(rect); + (*nbatch)++; + } sraRgnDestroy(rect); sent_copyrect = 1; @@ -3136,7 +3341,15 @@ if (db2) fprintf(stderr, " stack_work dt: %.4f\n", dt); /* now send the CopyRegion: */ if (! sraRgnEmpty(shifted_region)) { dtime0(&tm); - do_copyregion(shifted_region, dx, dy); + if (!nbatch) { + do_copyregion(shifted_region, dx, dy, 0); + } else { + batch_dxs[*nbatch] = dx; + batch_dys[*nbatch] = dy; + batch_reg[*nbatch] = sraRgnCreateRgn(shifted_region); + (*nbatch)++; + + } dt = dtime(&tm); if (0 || db2) fprintf(stderr, "do_copyregion: %d %d %d %d dx: %d dy: %d dt: %.4f\n", tx1, ty1, tx2, ty2, dx, dy, dt); @@ -3255,7 +3468,7 @@ void check_fixscreen(void) { double delay = 3.0; if (now > last + delay) { if (! didfull) { - scale_and_mark_rect(0, 0, dpy_x, dpy_y); + scale_and_mark_rect(0, 0, dpy_x, dpy_y, 1); if (db) rfbLog("doing scale screen_fixup\n"); } last_copyrect_fix = now; @@ -3316,118 +3529,713 @@ static int wireframe_mod_state() { return 0; } -/* - * Applied just before any check_user_input() modes. Look for a - * ButtonPress; find window it happened in; find the wm frame window - * for it; watch for that window moving or resizing. If it does, do the - * wireframe animation. Do this until ButtonRelease or timeouts occur. - * Remove wireframe. - * - * Under -nowirecopyrect, return control to base scheme - * (check_user_input() ...) that will repaint the screen with the window - * in the new postion or size. Under -wirecopyrect, apply rfbDoCopyRect - * or rfbDoCopyRegion: this "pollutes" our framebuffer, but the normal - * polling will quickly repair it. Under happy circumstances, this - * reduces actual XShmGetImage work (i.e. if we correctly predicted how - * the X fb has changed. - * - * -scale doesn't always work under -wirecopyrect, but the wireframe does. - * - * testing of this mode under -threads is incomplete. - * - * returns 1 if it did an animation, 0 if no move/resize triggers - * went off. - * - * TBD: see if we can select StructureNotify ConfigureNotify events for - * the toplevel windows to get better info on moves and resizes. - */ -int check_wireframe(void) { - Window frame = None, orig_frame = None; - XWindowAttributes attr; - int dx, dy; +static int NPP_nreg = 0; +static sraRegionPtr NPP_roffscreen = NULL; +static sraRegionPtr NPP_r_bs_tmp = NULL; +static Window NPP_nwin = None; - int orig_px, orig_py, orig_x, orig_y, orig_w, orig_h; - int px, py, x, y, w, h; - int box_x, box_y, box_w, box_h; - int orig_cursor_x, orig_cursor_y, g, gd; - int already_down = 0, win_gone = 0, win_unmapped = 0; - double spin = 0.0, tm, last_ptr = 0.0, last_draw; - int frame_changed = 0, drew_box = 0, got_2nd_pointer = 0; - int special_t1 = 0, break_reason = 0; - static double first_dt_ave = 0.0; - static int first_dt_cnt = 0; - static time_t last_save_stacklist = 0; - int bdown0, bdown, gotui, cnt = 0; - - /* heuristics: */ - double first_event_spin = wireframe_t1; - double frame_changed_spin = wireframe_t2; - double max_spin = wireframe_t3; - double min_draw = wireframe_t4; - int try_it = 0; - Window desc[6]; - DB_SET +void clear_win_events(void) { +#if !NO_X11 + if (dpy && NPP_nwin != None) { + XEvent ev; + XErrorHandler old_handler; + old_handler = XSetErrorHandler(trap_xerror); + trapped_xerror = 0; + while (XCheckTypedWindowEvent(dpy, NPP_nwin, ConfigureNotify, &ev)) { + fprintf(stderr, "."); + if (trapped_xerror) { + break; + } + trapped_xerror = 0; + } + while (XCheckTypedWindowEvent(dpy, NPP_nwin, VisibilityNotify, &ev)) { + fprintf(stderr, "+"); + if (trapped_xerror) { + break; + } + trapped_xerror = 0; + } + XSetErrorHandler(old_handler); + fprintf(stderr, " 0x%x\n", NPP_nwin); + } +#endif +} - if (unixpw_in_progress) return 0; +void push_borders(sraRect *rects, int nrect) { + int i, s = 2; + sraRegionPtr r0, r1, r2; + + r0 = sraRgnCreate(); + r1 = sraRgnCreateRect(0, 0, dpy_x, dpy_y); + + for (i=0; i 0 && h > 0 && w * h > 64 * 64) { + r2 = sraRgnCreateRect(x - s, y , x , y + h); + sraRgnOr(r0, r2); + sraRgnDestroy(r2); + + r2 = sraRgnCreateRect(x + w, y , x + w + s, y + h); + sraRgnOr(r0, r2); + sraRgnDestroy(r2); + + r2 = sraRgnCreateRect(x - s, y - s, x + w + s, y + s); + sraRgnOr(r0, r2); + sraRgnDestroy(r2); + + r2 = sraRgnCreateRect(x - s, y , x + w + s, y + h + s); + sraRgnOr(r0, r2); + sraRgnDestroy(r2); + } + } -#ifdef MACOSX - if (macosx_console) { - ; - } else { - RAWFB_RET(0) - } -#else - RAWFB_RET(0) -#endif + sraRgnAnd(r0, r1); - if (nofb) { - return 0; - } - if (subwin) { - return 0; /* don't even bother for -id case */ - } + if (!sraRgnEmpty(r0)) { + double d = dnow(); + sraRectangleIterator *iter; + sraRect rect; + int db = 0; -if (db > 1 && button_mask) fprintf(stderr, "check_wireframe: bm: %d gpi: %d\n", button_mask, got_pointer_input); + if (db) fprintf(stderr, "SCALE_BORDER\n"); + fb_push_wait(0.05, FB_MOD|FB_COPY); - bdown0 = 0; - if (button_mask) { - bdown0 = 1; - } else if (wireframe_local && display_button_mask) { - bdown0 = 2; - } - if (! bdown0) { - return 0; /* no button pressed down */ - } + iter = sraRgnGetIterator(r0); + while (sraRgnIteratorNext(iter, &rect)) { + /* clip the window to the visible screen: */ + int tx1 = rect.x1; + int ty1 = rect.y1; + int tx2 = rect.x2; + int ty2 = rect.y2; + scale_and_mark_rect(tx1, ty1, tx2, ty2, 1); + } + sraRgnReleaseIterator(iter); - gotui = 0; - if (got_pointer_input) { - gotui = 1; - } else if (wireframe_local && display_button_mask) { - gotui = 2; - } - if (!use_threads && !gotui) { - return 0; /* need ptr input, e.g. button down, motion */ - } + if (db) fprintf(stderr, "SCALE_BORDER %.4f\n", dnow() - d); + fb_push_wait(0.1, FB_MOD|FB_COPY); + if (db) fprintf(stderr, "SCALE_BORDER %.4f\n", dnow() - d); + } + sraRgnDestroy(r0); + sraRgnDestroy(r1); +} -if (db > 1) fprintf(stderr, "check_wireframe: %d\n", db); +void ncache_pre_portions(Window orig_frame, Window frame, int *nidx_in, int try_batch, int *use_batch, + int orig_x, int orig_y, int orig_w, int orig_h, int x, int y, int w, int h, double ntim) { + int nidx, np = ncache_pad; -if (db) fprintf(stderr, "\n*** button down!! x: %d y: %d\n", cursor_x, cursor_y); + *use_batch = 0; + *nidx_in = -1; + NPP_nreg = 0; + NPP_roffscreen = NULL; + NPP_r_bs_tmp = NULL; + NPP_nwin = None; + + if (ncache <= 0) { + return; + } - /* - * Query where the pointer is and which child of the root - * window. We will assume this is the frame the window manager - * makes when it reparents the toplevel window. - */ - X_LOCK; - if (! get_wm_frame_pos(&px, &py, &x, &y, &w, &h, &frame, NULL)) { -if (db) fprintf(stderr, "NO get_wm_frame_pos-1: 0x%lx\n", frame); - X_UNLOCK; - return 0; + if (rotating) { + try_batch = 0; } - X_UNLOCK; -if (db) fprintf(stderr, "a: %d wf: %.3f A: %d frm: 0x%lx\n", w*h, wireframe_frac, (dpy_x*dpy_y), frame); - /* + if (*nidx_in == -1) { + nidx = lookup_win_index(orig_frame); + NPP_nwin = orig_frame; + if (nidx < 0) { + nidx = lookup_win_index(frame); + NPP_nwin = frame; + } + } else { + nidx = *nidx_in; + } + if (nidx > 0) { + sraRegionPtr r0, r1, r2; + int dx, dy; + int bs_x = cache_list[nidx].bs_x; + int bs_y = cache_list[nidx].bs_y; + int bs_w = cache_list[nidx].bs_w; + int bs_h = cache_list[nidx].bs_h; + + *nidx_in = nidx; + + if (bs_x < 0) { + if (!find_rect(nidx, x, y, w, h)) { + nidx = -1; + return; + } + bs_x = cache_list[nidx].bs_x; + bs_y = cache_list[nidx].bs_y; + bs_w = cache_list[nidx].bs_w; + bs_h = cache_list[nidx].bs_h; + } + if (bs_x < 0) { + nidx = -1; + return; + } + + if (try_batch) { + *use_batch = 1; + } + + if (ncache_pad) { + orig_x -= np; + orig_y -= np; + orig_w += 2 * np; + orig_h += 2 * np; + x -= np; + y -= np; + w += 2 * np; + h += 2 * np; + } + + if (clipshift) { + orig_x -= coff_x; + orig_y -= coff_y; + x -= coff_x; + y -= coff_y; + } + + r0 = sraRgnCreateRect(0, 0, dpy_x, dpy_y); + + r2 = sraRgnCreateRect(orig_x, orig_y, orig_x + orig_w, orig_y + orig_h); + sraRgnSubtract(r2, r0); + if (! sraRgnEmpty(r2) && cache_list[nidx].bs_time > 0.0) { + /* some is initially offscreen */ + dx = bs_x - orig_x; + dy = bs_y - orig_y; + sraRgnOffset(r2, dx, dy); + dx = 0; + dy = dpy_y; + sraRgnOffset(r2, dx, dy); +//fprintf(stderr, "FB_COPY: %.4f 1) offscreen check:\n", dnow() - ntim); + + /* 0) save it in the invalid (offscreen) SU portion */ + if (! *use_batch) { + do_copyregion(r2, dx, dy, 0); + if (! fb_push_wait(0.2, FB_COPY)) { + fb_push_wait(0.1, FB_COPY); + } + } else { + batch_dxs[NPP_nreg] = dx; + batch_dys[NPP_nreg] = dy; + batch_reg[NPP_nreg++] = sraRgnCreateRgn(r2); + } + NPP_roffscreen = sraRgnCreateRgn(r2); + } + sraRgnDestroy(r2); + + /* 1) use bs for temp storage of the new save under. */ + r1 = sraRgnCreateRect(x, y, x + w, y + h); + sraRgnAnd(r1, r0); + + dx = bs_x - x; + dy = bs_y - y; + sraRgnOffset(r1, dx, dy); + +//fprintf(stderr, "FB_COPY: %.4f 1) use tmp bs:\n", dnow() - ntim); + if (! *use_batch) { + do_copyregion(r1, dx, dy, 0); + if (! fb_push_wait(0.2, FB_COPY)) { +//fprintf(stderr, "FB_COPY: %.4f 1) FAILED.\n", dnow() - ntim); + fb_push_wait(0.1, FB_COPY); + } + } else { + batch_dxs[NPP_nreg] = dx; + batch_dys[NPP_nreg] = dy; + batch_reg[NPP_nreg++] = sraRgnCreateRgn(r1); + } + NPP_r_bs_tmp = sraRgnCreateRgn(r1); + sraRgnDestroy(r0); + sraRgnDestroy(r1); + } +} + +ncache_post_portions(int nidx, int use_batch, int orig_x, int orig_y, int orig_w, int orig_h, + int x, int y, int w, int h, double batch_delay, double ntim) { + int np = ncache_pad; + + if (ncache > 0 && nidx >= 0) { + sraRegionPtr r0, r1, r2, r3; + int dx, dy; + int su_x = cache_list[nidx].su_x; + int su_y = cache_list[nidx].su_y; + int su_w = cache_list[nidx].su_w; + int su_h = cache_list[nidx].su_h; + int bs_x = cache_list[nidx].bs_x; + int bs_y = cache_list[nidx].bs_y; + int bs_w = cache_list[nidx].bs_w; + int bs_h = cache_list[nidx].bs_h; + int some_su = 0; + +//fprintf(stderr, "su: %dx%d+%d+%d bs: %dx%d+%d+%d\n", su_w, su_h, su_x, su_y, bs_w, bs_h, bs_x, bs_y); + + if (bs_x < 0) { + if (!find_rect(nidx, x, y, w, h)) { + return; + } + su_x = cache_list[nidx].su_x; + su_y = cache_list[nidx].su_y; + su_w = cache_list[nidx].su_w; + su_h = cache_list[nidx].su_h; + bs_x = cache_list[nidx].bs_x; + bs_y = cache_list[nidx].bs_y; + bs_w = cache_list[nidx].bs_w; + bs_h = cache_list[nidx].bs_h; + } + if (bs_x < 0) { + return; + } + + if (ncache_pad) { + orig_x -= np; + orig_y -= np; + orig_w += 2 * np; + orig_h += 2 * np; + x -= np; + y -= np; + w += 2 * np; + h += 2 * np; + } + + if (clipshift) { + orig_x -= coff_x; + orig_y -= coff_y; + x -= coff_x; + y -= coff_y; + } + + r0 = sraRgnCreateRect(0, 0, dpy_x, dpy_y); + + /* 0b) copy this bs part stored in saveunder */ + if (NPP_roffscreen != NULL) { + dx = x - su_x; + dy = y - su_y; + sraRgnOffset(NPP_roffscreen, dx, dy); + sraRgnAnd(NPP_roffscreen, r0); + + if (! use_batch) { + do_copyregion(NPP_roffscreen, dx, dy, 0); + if (!fb_push_wait(0.2, FB_COPY)) { + fb_push_wait(0.1, FB_COPY); + } + } else { + batch_dxs[NPP_nreg] = dx; + batch_dys[NPP_nreg] = dy; + batch_reg[NPP_nreg++] = sraRgnCreateRgn(NPP_roffscreen); + } + sraRgnDestroy(NPP_roffscreen); + } + + /* 3) copy from the saveunder to where orig win was */ + r1 = sraRgnCreateRect(orig_x, orig_y, orig_x + orig_w, orig_y + orig_h); + sraRgnAnd(r1, r0); + r2 = sraRgnCreateRect(x+np, y+np, x + w-np, y + h-np); + sraRgnAnd(r2, r0); + sraRgnSubtract(r1, r2); + + dx = orig_x - su_x; + dy = orig_y - su_y; +//fprintf(stderr, "FB_COPY: %.4f 3) sent_copyrect: su_restore: %d %d\n", dnow() - ntim, dx, dy); + if (cache_list[nidx].su_time == 0.0) { + ; + } else if (! use_batch) { + do_copyregion(r1, dx, dy, 0); + if (!fb_push_wait(0.2, FB_COPY)) { +//fprintf(stderr, "FB_COPY: %.4f 3) FAILED.\n", dnow() - ntim); + fb_push_wait(0.1, FB_COPY); + } + } else { + batch_dxs[NPP_nreg] = dx; + batch_dys[NPP_nreg] = dy; + batch_reg[NPP_nreg++] = sraRgnCreateRgn(r1); + } +//fprintf(stderr, "sent_copyrect: %.4f su_restore: done.\n", dnow() - ntim); + sraRgnDestroy(r0); + sraRgnDestroy(r1); + sraRgnDestroy(r2); + + /* 4) if overlap between orig and displaced, move the corner that will still be su: */ + r0 = sraRgnCreateRect(0, 0, dpy_x, dpy_y); + + r1 = sraRgnCreateRect(orig_x, orig_y, orig_x + orig_w, orig_y + orig_h); + sraRgnAnd(r1, r0); + r2 = sraRgnCreateRect(x, y, x + w, y + h); + sraRgnAnd(r2, r0); + r3 = NULL; + if (sraRgnAnd(r2, r1) && cache_list[nidx].su_time > 0.0) { + int dx2 = su_x - orig_x; + int dy2 = su_y - orig_y; + + r3 = sraRgnCreateRgn(r2); + sraRgnOffset(r2, dx2, dy2); + + dx = su_x - x; + dy = su_y - y; + sraRgnOffset(r3, dx, dy); + + dx = dx - dx2; + dy = dy - dy2; + +//fprintf(stderr, "FB_COPY: %.4f 4) move overlap inside su:\n", dnow() - ntim); + if (! use_batch) { + do_copyregion(r3, dx, dy, 0); + if (!fb_push_wait(0.2, FB_COPY)) { +//fprintf(stderr, "FB_COPY: %.4f 4) FAILED.\n", dnow() - ntim); + fb_push_wait(0.1, FB_COPY); + } + } else { + batch_dxs[NPP_nreg] = dx; + batch_dys[NPP_nreg] = dy; + batch_reg[NPP_nreg++] = sraRgnCreateRgn(r3); + } + } + sraRgnDestroy(r0); + sraRgnDestroy(r1); + sraRgnDestroy(r2); + + /* 5) copy our temporary stuff from bs to su: */ + dx = su_x - bs_x; + dy = su_y - bs_y; + if (NPP_r_bs_tmp == NULL) { + r1 = sraRgnCreateRect(su_x, su_y, su_x + su_w, su_y + su_h); + } else { + r1 = sraRgnCreateRgn(NPP_r_bs_tmp); + sraRgnOffset(r1, dx, dy); + sraRgnDestroy(NPP_r_bs_tmp); + } + if (r3 != NULL) { + sraRgnSubtract(r1, r3); + sraRgnDestroy(r3); + } +//fprintf(stderr, "FB_COPY: %.4f 5) move tmp bs to su:\n", dnow() - ntim); + if (! use_batch) { + do_copyregion(r1, dx, dy, 0); + if (!fb_push_wait(0.2, FB_COPY)) { +//fprintf(stderr, "FB_COPY: %.4f 5) FAILED.\n", dnow() - ntim); + fb_push_wait(0.1, FB_COPY); + } + } else { + batch_dxs[NPP_nreg] = dx; + batch_dys[NPP_nreg] = dy; + batch_reg[NPP_nreg++] = sraRgnCreateRgn(r1); + } + if (! sraRgnEmpty(r1)) { + some_su = 1; + } + sraRgnDestroy(r1); + + /* 6) not really necessary, update bs with current view: */ + r0 = sraRgnCreateRect(0, 0, dpy_x, dpy_y); + r1 = sraRgnCreateRect(x, y, x + w, y + h); + sraRgnAnd(r1, r0); + dx = bs_x - x; + dy = bs_y - y; + sraRgnOffset(r1, dx, dy); +//fprintf(stderr, "FB_COPY: %.4f 6) snapshot bs:\n", dnow() - ntim); + if (! use_batch) { + do_copyregion(r1, dx, dy, 0); + if (!fb_push_wait(0.2, FB_COPY)) { +//fprintf(stderr, "FB_COPY: %.4f 6) FAILED.\n", dnow() - ntim); + fb_push_wait(0.1, FB_COPY); + } + } else { + batch_dxs[NPP_nreg] = dx; + batch_dys[NPP_nreg] = dy; + batch_reg[NPP_nreg++] = sraRgnCreateRgn(r1); + } + sraRgnDestroy(r0); + sraRgnDestroy(r1); + + if (use_batch) { + int k; + batch_copyregion(batch_reg, batch_dxs, batch_dys, NPP_nreg, batch_delay); + for (k=0; k < NPP_nreg; k++) { + sraRgnDestroy(batch_reg[k]); + } +fprintf(stderr, "FB_COPY: %.4f XX did batch 0x%x %3d su: %dx%d+%d+%d bs: %dx%d+%d+%d\n", dnow() - ntim, + cache_list[nidx].win, nidx, su_w, su_h, su_x, su_y, bs_w, bs_h, bs_x, bs_y); + } + cache_list[nidx].x = x + np; + cache_list[nidx].y = y + np; + cache_list[nidx].bs_time = dnow(); + if (some_su) { + cache_list[nidx].su_time = dnow(); + } + } else { + if (use_batch) { + int k; + batch_copyregion(batch_reg, batch_dxs, batch_dys, NPP_nreg, batch_delay); + for (k=0; k < NPP_nreg; k++) { + sraRgnDestroy(batch_reg[k]); + } + } + } + + if (scaling) { + sraRect rects[2]; + + rects[0].x1 = orig_x; + rects[0].y1 = orig_y; + rects[0].x2 = orig_w; + rects[0].y2 = orig_h; + + rects[1].x1 = x; + rects[1].y1 = y; + rects[1].x2 = w; + rects[1].y2 = h; + push_borders(rects, 2); + } +} + +void do_copyrect_drag_move(Window orig_frame, Window frame, int *nidx, int try_batch, + int now_x, int now_y, int orig_w, int orig_h, int x, int y, int w, int h, double batch_delay) { + + int sent_copyrect, obscured; + int dx, dy; + int use_batch = 0; + double ntim = dnow(); + sraRegionPtr r0, r1; + + dx = x - now_x; + dy = y - now_y; + if (dx == 0 && dy == 0) { + return; + } + + ncache_pre_portions(orig_frame, frame, nidx, try_batch, &use_batch, + now_x, now_y, orig_w, orig_h, x, y, w, h, ntim); + + r0 = sraRgnCreateRect(0, 0, dpy_x, dpy_y); + r1 = sraRgnCreateRect(x, y, x + w, y + h); + sraRgnAnd(r1, r0); + + dx = x - now_x; + dy = y - now_y; + if (! use_batch) { + do_copyregion(r1, dx, dy, 0); + if (!fb_push_wait(0.2, FB_COPY)) { +fprintf(stderr, "FB_COPY: %.4f 3) FAILED.\n", dnow() - ntim); + fb_push_wait(0.1, FB_COPY); + } + } else { + batch_dxs[NPP_nreg] = dx; + batch_dys[NPP_nreg] = dy; + batch_reg[NPP_nreg++] = sraRgnCreateRgn(r1); + } + sraRgnDestroy(r0); + sraRgnDestroy(r1); + sent_copyrect = 1; + + if (sent_copyrect) { + if (use_batch) { + ; + } else if (! obscured) { + fb_push_wait(0.1, FB_COPY); + } else { + /* no diff for now... */ + fb_push_wait(0.1, FB_COPY); + } + ncache_post_portions(*nidx, use_batch, + now_x, now_y, orig_w, orig_h, x, y, w, h, batch_delay, ntim); + } +fprintf(stderr, "do_COPY: %.4f -- post_portion done.\n", dnow() - ntim); +} + +void check_macosx_iconify(Window orig_frame, Window frame, int flush) { +#ifdef MACOSX + static double last = 0.0; + double now; + int j, m = 5, idx = -1, ok = 0, unmapped = 0; + + if (! macosx_console) { + return; + } + + now = dnow(); + if (now < last + 0.3) { + return; + } + last = now; + + if (ncache > 0 && orig_frame != None) { + idx = lookup_win_index(orig_frame); + if (idx >= 0) { + if (cache_list[idx].map_state == IsUnmapped) { +fprintf(stderr, "FAW orig_frame unmapped.\n"); + unmapped = 1; + m = 3; + } + } + } + + if (unmapped) { + ; + } else if (orig_frame && macosxCGS_follow_animation_win(orig_frame, -1, 0)) { + fprintf(stderr, "FAW orig_frame %d\n", orig_frame); + } else if (0 && frame && macosxCGS_follow_animation_win(frame, -1, 0)) { + fprintf(stderr, "FAW frame %d\n", frame); + } + for (j=0; j 1 && button_mask) fprintf(stderr, "check_wireframe: bm: %d gpi: %d\n", button_mask, got_pointer_input); + + bdown0 = 0; + if (button_mask) { + bdown0 = 1; + } else if (wireframe_local && display_button_mask) { + bdown0 = 2; + } + if (! bdown0) { + return 0; /* no button pressed down */ + } + + gotui = 0; + if (got_pointer_input) { + gotui = 1; + } else if (wireframe_local && display_button_mask) { + gotui = 2; + } + if (!use_threads && !gotui) { + return 0; /* need ptr input, e.g. button down, motion */ + } + +if (db > 1) fprintf(stderr, "check_wireframe: %d\n", db); + +if (db) fprintf(stderr, "\n*** button down!! x: %d y: %d\n", cursor_x, cursor_y); + + /* + * Query where the pointer is and which child of the root + * window. We will assume this is the frame the window manager + * makes when it reparents the toplevel window. + */ + X_LOCK; + if (! get_wm_frame_pos(&px, &py, &x, &y, &w, &h, &frame, NULL)) { +if (db) fprintf(stderr, "NO get_wm_frame_pos-1: 0x%lx\n", frame); + X_UNLOCK; +#ifdef MACOSX + check_macosx_click_frame(); +#endif + return 0; + } + X_UNLOCK; +if (db) fprintf(stderr, "a: %d wf: %.3f A: %d frm: 0x%lx\n", w*h, wireframe_frac, (dpy_x*dpy_y), frame); + + /* * apply the percentage size criterion (allow opaque moves for * small windows) */ @@ -3450,6 +4258,9 @@ if (db) fprintf(stderr, " frame: x: %d y: %d w: %d h: %d px: %d py: %d fr } if (! try_it) { if (db) fprintf(stderr, "INTERIOR\n"); +#ifdef MACOSX + check_macosx_click_frame(); +#endif return 0; } @@ -3540,6 +4351,13 @@ if (db) fprintf(stderr, "INTERIOR\n"); pointer(-1, 0, 0, NULL); } + if (cursor_noshape_updates_clients(screen)) { + try_batch = 0; + } + if (rotating) { + try_batch = 0; + } + g = got_pointer_input; gd = got_local_pointer_input; @@ -3552,7 +4370,7 @@ if (db) fprintf(stderr, "INTERIOR\n"); /* try do induce/waitfor some more user input */ if (use_threads) { usleep(1000); - } else if (drew_box) { + } else if (drew_box && do_copyrect_drag != 1) { rfbPE(1000); } else { rfbCFD(1000); @@ -3577,7 +4395,6 @@ if (db) fprintf(stderr, "INTERIOR\n"); #endif } - cnt++; spin += dtime(&tm); @@ -3624,6 +4441,8 @@ if (db || db2) fprintf(stderr, " SPIN-OUT-NO2ND_PTR: %.3f\n", spin); break; } } + + gpi = 0; /* see if some pointer input occurred: */ if (got_pointer_input > g || (wireframe_local && (got_local_pointer_input > gd))) { @@ -3633,6 +4452,7 @@ if (db) fprintf(stderr, " ++pointer event!! [%02d] dt: %.3f x: %d y: %d mas g = got_pointer_input; gd = got_local_pointer_input; + gpi = 1; X_LOCK; XFlush_wr(dpy); @@ -3729,38 +4549,104 @@ if (db) fprintf(stderr, "WIN RESIZE 1st-dt: %.3f\n", first_dt_ave/n); frame_changed = 1; if (db) fprintf(stderr, "FRAME MOVE 1st-dt: %.3f\n", first_dt_ave/n); } + } - /* - * see if it is time to draw any or a new wireframe box - */ - if (frame_changed) { - int drawit = 0; - if (x != box_x || y != box_y) { - /* moved since last */ - drawit = 1; - } else if (w != box_w || h != box_h) { - /* resize since last */ - drawit = 1; - } - if (drawit) { - /* - * check time (to avoid too much - * animations on slow machines - * or links). - */ - if (spin > last_draw + min_draw || - ! drew_box) { - draw_box(x, y, w, h, 0); - drew_box = 1; - rfbPE(1000); - last_draw = spin; + /* + * see if it is time to draw any or a new wireframe box + */ + + if (frame_changed) { + int drawit = 0; + if (x != box_x || y != box_y) { + /* moved since last */ +//fprintf(stderr, "DRAW1 %d %d\n", x - box_x, y - box_y); + drawit = 1; + } else if (w != box_w || h != box_h) { + /* resize since last */ + drawit = 1; + } + if (drawit) { + int doit = 0; + /* + * check time (to avoid too much + * animations on slow machines + * or links). + */ + if (gpi) { + if (spin > last_draw + min_draw || ! drew_box) { + doit = 1; + } + if (macosx_console && doit && !mac_skip) { + if (x != box_x && y != box_y && w != box_w && h != box_h) { + doit = 0; + } else if (!button_mask) { + doit = 0; + } + mac_skip++; + } + } else { + if (drew_box && cnt > last_draw_cnt) { + doit = 1; +fprintf(stderr, "*** NO GPI DRAW_BOX\n"); + } + } + + if (doit) { + if (try_copyrect_drag) { + if (!ncache_copyrect) { + do_copyrect_drag = 0; + } else if (w != box_w || h != box_h) { + do_copyrect_drag = 0; + } else if (do_copyrect_drag < 0) { + int idx = lookup_win_index(orig_frame); + if (idx < 0) { + idx = lookup_win_index(frame); + } + if (idx >= 0) { + if (cache_list[idx].su_time > 0.0) { + double min_draw0 = min_draw; + min_draw *= 0.66; + do_copyrect_drag = 1; +//fprintf(stderr, "min_draw: %.4f -> %.4f\n", min_draw0, min_draw); + } + nidx = idx; + } + now_x = orig_x; + now_y = orig_y; + } + if (do_copyrect_drag) { + if (orig_w != w || orig_h != h) { + do_copyrect_drag = 0; + } + } } + + drew_box = 1; + if (do_copyrect_drag <= 0) { + draw_box(x, y, w, h, 0); + fb_push(); /* XXX Y */ + rfbPE(1000); + } else { +#ifndef NO_NCACHE + do_copyrect_drag_move(orig_frame, frame, &nidx, + try_batch, now_x, now_y, orig_w, orig_h, x, y, w, h, + copyrect_drag_delay); + now_x = x; + now_y = y; + if (copyrect_drag_delay == -1.0) { + copyrect_drag_delay = 0.04; + } +#endif + } + + last_draw = spin; + last_draw_cnt = cnt; } - box_x = x; - box_y = y; - box_w = w; - box_h = h; } + box_x = x; + box_y = y; + box_w = w; + box_h = h; } /* @@ -3787,11 +4673,21 @@ if (db || db2) fprintf(stderr, "NO button_mask\n"); stack_list_num = 0; } wireframe_in_progress = 0; + if (macosx_console && (break_reason == 6 || break_reason == 5)) { + check_macosx_iconify(orig_frame, frame, drew_box); + } return 0; } /* remove the wireframe */ - draw_box(0, 0, 0, 0, 1); + if (do_copyrect_drag <= 0) { + draw_box(0, 0, 0, 0, 1); + fb_push(); /* XXX Y */ + } else { + do_copyrect_drag_move(orig_frame, frame, &nidx, + try_batch, now_x, now_y, orig_w, orig_h, x, y, w, h, -1.0); + fb_push_wait(0.15, FB_COPY|FB_MOD); + } dx = x - orig_x; dy = y - orig_y; @@ -3809,9 +4705,16 @@ if (db || db2) fprintf(stderr, "NO button_mask\n"); ; } else if (dx == 0 && dy == 0) { ; + } else if (do_copyrect_drag > 0) { + clear_win_events(); } else { int spin_ms = (int) (spin * 1000 * 1000); int obscured, sent_copyrect = 0; + int np = ncache_pad; + + int nidx = -1; + int use_batch = 0; + double ntim; /* * set a timescale comparable to the spin time, @@ -3822,61 +4725,57 @@ if (db || db2) fprintf(stderr, "NO button_mask\n"); } else if (spin_ms > 400) { spin_ms = 400; } + ntim = dnow(); /* try to flush the wireframe removal: */ - fb_push_wait(0.1, FB_COPY|FB_MOD); +fprintf(stderr, "\nSEND_COPYRECT %.4f %.4f\n", dnowx(), dnow() - ntim); + + if (! fb_push_wait(0.15, FB_COPY|FB_MOD)) { + +fprintf(stderr, "FB_COPY failed, try one more...", dnow() - ntim); + + if (! fb_push_wait(0.15, FB_COPY|FB_MOD)) { + +fprintf(stderr, "FB_COPY failed again!", dnow() - ntim); - /* try to send a clipped copyrect of translation: */ - sent_copyrect = try_copyrect(frame, x, y, w, h, dx, dy, - &obscured, NULL, 0.15); + } + } + +#ifndef NO_NCACHE + ncache_pre_portions(orig_frame, frame, &nidx, try_batch, &use_batch, + orig_x, orig_y, orig_w, orig_h, x, y, w, h, ntim); +#endif + + /* 2) try to send a clipped copyrect of translation: */ + + if (! try_batch) { + sent_copyrect = try_copyrect(frame, x, y, w, h, dx, dy, + &obscured, NULL, 0.15, NULL); + } else { + try_copyrect(frame, x, y, w, h, dx, dy, + &obscured, NULL, 0.15, &NPP_nreg); /* XXX */ + sent_copyrect = 1; + use_batch = 1; + } if (db) fprintf(stderr, "sent_copyrect: %d - obs: %d frame: 0x%lx\n", sent_copyrect, obscured, frame); if (sent_copyrect) { /* try to push the changes to viewers: */ - if (! obscured) { + if (use_batch) { + ; + } else if (! obscured) { fb_push_wait(0.1, FB_COPY); } else { /* no diff for now... */ fb_push_wait(0.1, FB_COPY); } #ifndef NO_NCACHE - if (ncache > 0) { - int idx = lookup_win_index(frame); -fprintf(stderr, "sent_copyrect: idx=%d 0x%x\n", idx, frame); - if (idx < 0) { - idx = lookup_win_index(orig_frame); -fprintf(stderr, "sent_copyrect: idx=%d 0x%x\n", idx, orig_frame); - } - if (idx >= 0 && cache_list[idx].su_time > 0.0) { - sraRegionPtr r0, r1, r2; - sraRectangleIterator *iter; - sraRect rt; - int su_x = cache_list[idx].su_x; - int su_y = cache_list[idx].su_y; - int dx, dy; - - r0 = sraRgnCreateRect(0, 0, dpy_x, dpy_y); - r1 = sraRgnCreateRect(orig_x, orig_y, orig_x + orig_w, orig_y + orig_h); - sraRgnAnd(r1, r0); - r2 = sraRgnCreateRect(x, y, x + w, y + h); - sraRgnAnd(r2, r0); - sraRgnSubtract(r1, r2); - - dx = orig_x - su_x; - dy = orig_y - su_y; -fprintf(stderr, "sent_copyrect: su_restore: %d %d\n", dx, dy); - do_copyregion(r1, dx, dy); - fb_push_wait(0.1, FB_COPY); -fprintf(stderr, "sent_copyrect: su_restore: done.\n"); - sraRgnDestroy(r0); - sraRgnDestroy(r1); - sraRgnDestroy(r2); - - cache_list[idx].su_time = 0.0; - } - } + ncache_post_portions(nidx, use_batch, + orig_x, orig_y, orig_w, orig_h, x, y, w, h, -1.0, ntim); + clear_win_events(); #endif - if (scaling) { + + if (scaling && !use_batch) { static double last_time = 0.0; double now = dnow(), delay = 0.35; @@ -3894,7 +4793,7 @@ fprintf(stderr, "sent_copyrect: su_restore: done.\n"); yt -= off_y; } - scale_mark(xt, yt, xt+w, yt+h); + scale_mark(xt, yt, xt+w, yt+h, 1); last_time = now; last_copyrect_fix = now; } @@ -3944,6 +4843,10 @@ fprintf(stderr, "sent_copyrect: su_restore: done.\n"); xdamage_scheduled_mark = dnow() + 2.0; } + if (macosx_console && (break_reason == 6 || break_reason == 5)) { + check_macosx_iconify(orig_frame, frame, drew_box); + } + return 1; } @@ -4503,8 +5406,10 @@ if (debug_scroll && rc > 1) fprintf(stderr, " CXR: check_user_input ret %d\n", if (wireframe) { if (check_wireframe()) { +fprintf(stderr, "check_wireframe: 1\n"); return 0; } +//fprintf(stderr, "check_wireframe: 0\n"); } if (pointer_mode == 1) { @@ -4543,13 +5448,16 @@ if (debug_scroll && rc > 1) fprintf(stderr, " CXR: check_user_input ret %d\n", return 0; } -#if defined(NO_NCACHE) || NO_X11 -void check_ncache(void) { +#if defined(NO_NCACHE) || (NO_X11 && !defined(MACOSX)) +int check_ncache(int a, int b) { return; } int lookup_win_index(Window win) { return -1; } +int find_rect(int idx, int x, int y, int w, int h) { + return 0; +} #else /* maybe ncache.c it if works */ @@ -4560,14 +5468,14 @@ int cache_list_len = 0; void snapshot_cache_list(int free_only, double allowed_age) { static double last_snap = 0.0, last_free = 0.0; double now; - int num, rc, i, j; + int num, rc, i; unsigned int ui; Window r, w; Window *list; - int start = 2048; + int start = 512; if (! cache_list) { - cache_list = (winattr_t *) malloc(start*sizeof(winattr_t)); + cache_list = (winattr_t *) calloc(start*sizeof(winattr_t), 1); cache_list_num = 0; cache_list_len = start; } @@ -4602,38 +5510,72 @@ void snapshot_cache_list(int free_only, double allowed_age) { X_LOCK; /* no need to trap error since rootwin */ rc = XQueryTree_wr(dpy, rootwin, &r, &w, &list, &ui); + X_UNLOCK; num = (int) ui; if (! rc) { cache_list_num = 0; last_free = now; last_snap = 0.0; - X_UNLOCK; return; } last_snap = now; if (num > cache_list_len) { int n = 2*num; + n = num + 3; free(cache_list); - cache_list = (winattr_t *) malloc(n*sizeof(winattr_t)); + cache_list = (winattr_t *) calloc(n*sizeof(winattr_t), 1); cache_list_len = n; } - j = 0; for (i=0; i= 100) { +fprintf(stderr, "lookup_win_index recent hit stats: %d/%d/%d\n", s1, s2, s3); + s1 = s2 = s3 = 0; + } return idx; } @@ -4697,12 +5647,36 @@ fprintf(stderr, "lookup_freeA: %d\n", rfree); } } if (rfree < 0) { + fprintf(stderr, "*** LOOKUP_FREE_INDEX: incrementing cache_list_num %d/%d\n", cache_list_num, cache_list_len); + rfree = cache_list_num++; if (rfree >= cache_list_len) { - /* bad news... */ - fprintf(stderr, "Whoops: %d %d\n", rfree, cache_list_len); - } + int i, n = 2*cache_list_len; + winattr_t *cache_new; + + fprintf(stderr, "lookup_free_index: growing cache_list_len: %d -> %d\n", cache_list_len, n); + + cache_new = (winattr_t *) calloc(n*sizeof(winattr_t), 1); + for (i=0; i= w && rh >= h) { - if (rt.x1 < rt.x2) { - x_hit = rt.x1; - } else { - x_hit = rt.x2; - } - if (rt.y1 < rt.y2) { - y_hit = rt.y1; - } else { - y_hit = rt.y2; - } - r2 = sraRgnCreateRect(x_hit, y_hit, x_hit + w, y_hit + h); - break; - } - } - sraRgnReleaseIterator(iter); - if (r2 != NULL) { - sraRgnSubtract(r1, r2); - sraRgnDestroy(r2); - break; - } - } - if (x_hit < 0) { - /* bad news */ - fprintf(stderr, "*FAIL rect: %d %d %d %d -- %d %d\n", x, y, w, h, x_hit, y_hit); - } else { - fprintf(stderr, "found rect: %d %d %d %d -- %d %d\n", x, y, w, h, x_hit, y_hit); - } - - cache_list[idx].bs_x = x_hit; - cache_list[idx].bs_y = y_hit; - cache_list[idx].bs_w = w; - cache_list[idx].bs_h = h; - - cache_list[idx].su_x = x_hit; - cache_list[idx].su_y = y_hit + dpy_y; - cache_list[idx].su_w = w; - cache_list[idx].su_h = h; +char *VState(int state) { + if (state == VisibilityFullyObscured) return "VisibilityFullyObscured"; + if (state == VisibilityPartiallyObscured) return "VisibilityPartiallyObscured"; + if (state == VisibilityUnobscured) return "VisibilityUnobscured"; + sprintf(unk, "Unknown %d", state); + return unk; +} +char *MState(int state) { + if (state == IsViewable) return "IsViewable"; + if (state == IsUnmapped) return "IsUnmapped"; + sprintf(unk, "Unknown %d", state); + return unk; } +sraRegionPtr rect_reg[64]; +sraRegionPtr zero_rects = NULL; int free_rect(int idx) { int n, ok = 0; sraRegionPtr r1, r2; int x, y, w, h; + if (idx < 0 || idx >= cache_list_num) { +fprintf(stderr, "free_rect: bad index: %d\n", idx); + clean_up_exit(1); + } + x = cache_list[idx].bs_x; y = cache_list[idx].bs_y; w = cache_list[idx].bs_w; @@ -4849,161 +5791,960 @@ int free_rect(int idx) { if (x < 0) { CLEAR(idx); -fprintf(stderr, "free_rect: invalid: %d\n", idx); - return 0; +if (dnow() > last_client + 5) fprintf(stderr, "free_rect: already bs_x invalidated: %d bs_x: %d\n", idx, x); + return 1; } r2 = sraRgnCreateRect(x, y, x+w, y+h); - for (n = 1; n < ncache; n += 2) { - if (y >= n*dpy_y && y < (n+1)*dpy_y) { - r1 = rect_reg[n]; - sraRgnOr(r1, r2); - ok = 1; -fprintf(stderr, "free_rect: found %d region: %d\n", idx, n); - break; + n = get_bs_n(y); + if (n >= 0) { + r1 = rect_reg[n]; + sraRgnOr(r1, r2); + ok = 1; + } + + if (zero_rects) { + sraRgnOr(zero_rects, r2); + x = cache_list[idx].su_x; + y = cache_list[idx].su_y; + w = cache_list[idx].su_w; + h = cache_list[idx].su_h; + if (x >= 0) { + sraRgnDestroy(r2); + r2 = sraRgnCreateRect(x, y, x+w, y+h); + sraRgnOr(zero_rects, r2); } } sraRgnDestroy(r2); CLEAR(idx); -if (! ok) fprintf(stderr, "free_rect: not-found %d\n", idx); +if (! ok) fprintf(stderr, "**** free_rect: not-found %d\n", idx); return ok; } -int bs_save(int idx) { - Window win = cache_list[idx].win; - XWindowAttributes attr; - int x1, y1, w1, h1; - int x2, y2, w2, h2; - int x, y, w, h; - int dx, dy; - sraRegionPtr r; - - - x1 = cache_list[idx].x; - y1 = cache_list[idx].y; - w1 = cache_list[idx].width; - h1 = cache_list[idx].height; - - if (! valid_window(win, &attr, 1)) { -fprintf(stderr, "bs_save: not valid\n"); -// DELETE(idx); - return 0; - } - - x2 = attr.x; - y2 = attr.y; - w2 = attr.width; - h2 = attr.height; +int fr_BIG1 = 0; +int fr_BIG2 = 0; +int fr_REGION = 0; +int fr_GRID = 0; +int fr_EXPIRE = 0; +int fr_FORCE = 0; +int fr_FAIL = 0; +int fr_BIG1t = 0; +int fr_BIG2t = 0; +int fr_REGIONt = 0; +int fr_GRIDt = 0; +int fr_EXPIREt = 0; +int fr_FORCEt = 0; +int fr_FAILt = 0; + +void expire_rects1(int idx, int w, int h, int *x_hit, int *y_hit, int big1, int big2, int cram) { + sraRegionPtr r1, r2, r3; + sraRectangleIterator *iter; + sraRect rt; + int x, y, n; - if (cache_list[idx].bs_x < 0 || w2 > cache_list[idx].bs_w || h2 > cache_list[idx].bs_h) { - find_rect(idx, x2, y2, w2, h2); - } - x = cache_list[idx].bs_x; - y = cache_list[idx].bs_y; - w = cache_list[idx].bs_w; - h = cache_list[idx].bs_h; + if (*x_hit < 0) { + int i, k, old[10], N = 4; + double dold[10], fa, d, d1, d2, d3; + int a0 = w * h, a1; - if (x < 0) { - STORE(idx, win, attr); - return 0; - } + for (k=1; k<=N; k++) { + old[k] = -1; + dold[k] = -1.0; + } + for (i=0; i wb || h > hb) { + continue; + } + if (wb == 0 || hb == 0) { + continue; + } + if (a0 == 0) { + continue; + } + if (i == idx) { + continue; + } + a1 = wb * hb; + fa = ((double) a1) / a0; + k = (int) fa; - dx = x - x2; - dy = y - y2; + if (k < 1) k = 1; + if (k > N) continue; - r = sraRgnCreateRect(x2+dx, y2+dy, x2+w2+dx, y2+h2+dy); -fprintf(stderr, "bs_save: dx=%d dy=%d\n", dx, dy); - do_copyregion(r, dx, dy); - fb_push_wait(0.01, FB_COPY); -fprintf(stderr, "bs_save: done. %dx%d+%d+%d %dx%d+%d+%d %.2f %.2f\n", w1, h1, x1, y1, w2, h2, x2, y2, cache_list[idx].bs_time, dnow()); - sraRgnDestroy(r); + d1 = cache_list[i].time; + d2 = cache_list[i].bs_time; + d3 = cache_list[i].su_time; - STORE(idx, win, attr); - cache_list[idx].bs_time = dnow(); - - return 1; -} + d = d1; + if (d2 > d) d = d2; + if (d3 > d) d = d3; -int su_save(int idx) { - Window win = cache_list[idx].win; - XWindowAttributes attr; - int x1, y1, w1, h1; - int x2, y2, w2, h2; - int x, y, w, h; - int dx, dy; - sraRegionPtr r; - + if (dold[k] == -1.0 || d < dold[k]) { + old[k] = i; + dold[k] = d; + } + } - x1 = cache_list[idx].x; - y1 = cache_list[idx].y; - w1 = cache_list[idx].width; - h1 = cache_list[idx].height; - - if (! valid_window(win, &attr, 1)) { -fprintf(stderr, "su_save: not valid\n"); -// DELETE(idx); - return 0; + for (k=1; k<=N; k++) { + if (old[k] >= 0) { + int ik = old[k]; + int k_x = cache_list[ik].bs_x; + int k_y = cache_list[ik].bs_y; + int k_w = cache_list[ik].bs_w; + int k_h = cache_list[ik].bs_h; + +fprintf(stderr, ">>**--**>> found rect via EXPIRE: %d 0x%x -- %dx%d+%d+%d %d %d -- %dx%d+%d+%d A: %d/%d\n", + ik, cache_list[ik].win, w, h, x, y, *x_hit, *y_hit, k_w, k_h, k_x, k_y, k_w * k_h, w * h); + + free_rect(ik); + fr_EXPIRE++; + fr_EXPIREt++; + *x_hit = k_x; + *y_hit = k_y; + n = get_bs_n(*y_hit); + if (n >= 0) { + r1 = rect_reg[n]; + r2 = sraRgnCreateRect(*x_hit, *y_hit, *x_hit + w, *y_hit + h); + sraRgnSubtract(r1, r2); + sraRgnDestroy(r2); + } else { + fprintf(stderr, "failure to find y n in find_rect\n"); + clean_up_exit(1); + } + break; + } + } } - x2 = attr.x; - y2 = attr.y; - w2 = attr.width; - h2 = attr.height; + /* next, force ourselves into some corner, expiring many */ + if (*x_hit < 0) { + int corner_x = (int) (2 * rfac()); + int corner_y = (int) (2 * rfac()); + int x0 = 0, y0 = 0, i, nrand, nr = ncache/2; + if (nr == 1) { + nrand = 1; + } else { + if (! big1) { + nrand = 1; + } else { + if (big2 && nr > 2) { + nrand = 1 + (int) ((nr - 2) * rfac()); + nrand += 2; + } else { + nrand = 1 + (int) ((nr - 1) * rfac()); + nrand += 1; + } + } + } + if (nrand < 0 || nrand > nr) { + nrand = nr; + } + if (cram && big1) { + corner_x = 1; + } - if (cache_list[idx].su_x < 0 || w2 > cache_list[idx].su_w || h2 > cache_list[idx].su_h) { - find_rect(idx, x2, y2, w2, h2); - } - x = cache_list[idx].su_x; - y = cache_list[idx].su_y; - w = cache_list[idx].su_w; - h = cache_list[idx].su_h; + y0 += dpy_y; + if (nrand > 1) { + y0 += 2 * (nrand - 1) * dpy_y; + } + if (corner_y) { + y0 += dpy_y - h; + } + if (corner_x) { + x0 += dpy_x - w; + } + r1 = sraRgnCreateRect(x0, y0, x0+w, y0+h); - if (x < 0) { - STORE(idx, win, attr); - return 0; - } + for (i=0; i dpy_y) { + continue; + } + r2 = sraRgnCreateRect(xb, yb, xb+wb, yb+hb); + if (sraRgnAnd(r2, r1)) { + free_rect(i); + } + sraRgnDestroy(r2); + } + *x_hit = x0; + *y_hit = y0; + r3 = rect_reg[2*nrand-1]; + sraRgnSubtract(r3, r1); + sraRgnDestroy(r1); - dx = x - x2; - dy = y - y2; +fprintf(stderr, ">>**--**>> found rect via FORCE: %dx%d+%d+%d -- %d %d\n", w, h, x, y, *x_hit, *y_hit); - r = sraRgnCreateRect(x2+dx, y2+dy, x2+w2+dx, y2+h2+dy); -fprintf(stderr, "su_save: dx=%d dy=%d\n", dx, dy); - do_copyregion(r, dx, dy); - fb_push_wait(0.01, FB_COPY); -fprintf(stderr, "su_save: done. %dx%d+%d+%d %dx%d+%d+%d %.2f %.2f\n", w1, h1, x1, y1, w2, h2, x2, y2, cache_list[idx].su_time, dnow()); - sraRgnDestroy(r); + fr_FORCE++; + fr_FORCEt++; + } +} + +void expire_rects2(int idx, int w, int h, int *x_hit, int *y_hit, int big1, int big2, int cram) { + sraRegionPtr r1, r2, r3; + int x, y, n, i, j, k; + int nwgt_max = 128, nwgt = 0; + int type[128]; + int val[4][128]; + double wgt[128], norm; + int Expire = 1, Force = 2; + int do_expire = 1; + int do_force = 1; + double now = dnow(), r; + + if (do_expire) { + int old[10], N = 4; + double dold[10], fa, d, d1, d2, d3; + int a0 = w * h, a1; + + for (k=1; k<=N; k++) { + old[k] = -1; + dold[k] = -1.0; + } + for (i=0; i wb || h > hb) { + continue; + } + if (wb == 0 || hb == 0) { + continue; + } + if (a0 == 0) { + continue; + } + if (i == idx) { + continue; + } + + a1 = wb * hb; + fa = ((double) a1) / a0; + k = (int) fa; + + if (k < 1) k = 1; + if (k > N) continue; + + d1 = cache_list[i].time; + d2 = cache_list[i].bs_time; + d3 = cache_list[i].su_time; + + d = d1; + if (d2 > d) d = d2; + if (d3 > d) d = d3; + + if (dold[k] == -1.0 || d < dold[k]) { + old[k] = i; + dold[k] = d; + } + } + + for (k=1; k<=N; k++) { + if (old[k] >= 0) { + int ik = old[k]; + int k_w = cache_list[ik].bs_w; + int k_h = cache_list[ik].bs_h; + + wgt[nwgt] = (now - dold[k]) / (k_w * k_h); + type[nwgt] = Expire; + val[0][nwgt] = ik; +fprintf(stderr, "Expire[%02d] %9.5f age=%9.4f area=%8d need=%8d\n", nwgt, 10000 * wgt[nwgt], now - dold[k], k_w * k_h, w*h); + nwgt++; + if (nwgt >= nwgt_max) { + break; + } + } + } + } + + /* next, force ourselves into some corner, expiring many rect */ + if (do_force) { + int corner_x, corner_y; + int x0, y0; + double nfac = 1.0; + + for (n = 1; n < ncache; n += 2) { + if (big1 && ncache > 2 && n == 1) { + continue; + } + if (big2 && ncache > 4 && n <= 3) { + continue; + } + for (corner_x = 0; corner_x < 2; corner_x++) { + if (cram && big1 && corner_x == 0) { + continue; + } + for (corner_y = 0; corner_y < 2; corner_y++) { + double age = 0.0, area = 0.0, a; + double d, d1, d2, d3, score; + int nc = 0; + + x0 = 0; + y0 = 0; + y0 += n * dpy_y; + + if (corner_y) { + y0 += dpy_y - h; + } + if (corner_x) { + x0 += dpy_x - w; + } + r1 = sraRgnCreateRect(x0, y0, x0+w, y0+h); + + for (i=0; i dpy_y) { + continue; + } + + r2 = sraRgnCreateRect(xb, yb, xb+wb, yb+hb); + if (! sraRgnAnd(r2, r1)) { + sraRgnDestroy(r2); + continue; + } + sraRgnDestroy(r2); + + a = wb * hb; + + d1 = cache_list[i].time; + d2 = cache_list[i].bs_time; + d3 = cache_list[i].su_time; + + d = d1; + if (d2 > d) d = d2; + if (d3 > d) d = d3; + + area += a; + age += (now - d) * a; + nc++; + } + if (nc == 0) { + score = 999999.9; + } else { + age = age / area; + score = age / area; + } + + wgt[nwgt] = score; + type[nwgt] = Force; + val[0][nwgt] = n; + val[1][nwgt] = x0; + val[2][nwgt] = y0; +fprintf(stderr, "Force [%02d] %9.5f age=%9.4f area=%8d need=%8d\n", nwgt, 10000 * wgt[nwgt], age, (int) area, w*h); + nwgt++; + if (nwgt >= nwgt_max) break; + sraRgnDestroy(r1); + } + if (nwgt >= nwgt_max) break; + } + if (nwgt >= nwgt_max) break; + } + } + + if (nwgt == 0) { +fprintf(stderr, "nwgt=0\n"); + *x_hit = -1; + return; + } + + norm = 0.0; + for (i=0; i < nwgt; i++) { + norm += wgt[i]; + } + for (i=0; i < nwgt; i++) { + wgt[i] /= norm; + } + + r = rfac(); + + norm = 0.0; + for (j=0; j < nwgt; j++) { + norm += wgt[j]; +fprintf(stderr, "j=%2d acc=%.6f r=%.6f\n", j, norm, r); + if (r < norm) { + break; + } + } + if (j >= nwgt) { + j = nwgt - 1; + } + + if (type[j] == Expire) { + int ik = val[0][j]; + int k_x = cache_list[ik].bs_x; + int k_y = cache_list[ik].bs_y; + int k_w = cache_list[ik].bs_w; + int k_h = cache_list[ik].bs_h; + +fprintf(stderr, ">>**--**>> found rect [%d] via RAN EXPIRE: %d 0x%x -- %dx%d+%d+%d %d %d -- %dx%d+%d+%d A: %d/%d\n", + get_bs_n(*y_hit), ik, cache_list[ik].win, w, h, x, y, *x_hit, *y_hit, k_w, k_h, k_x, k_y, k_w * k_h, w * h); + + free_rect(ik); + fr_EXPIRE++; + fr_EXPIREt++; + *x_hit = k_x; + *y_hit = k_y; + n = get_bs_n(*y_hit); + if (n >= 0) { + r1 = rect_reg[n]; + r2 = sraRgnCreateRect(*x_hit, *y_hit, *x_hit + w, *y_hit + h); + sraRgnSubtract(r1, r2); + sraRgnDestroy(r2); + } else { + fprintf(stderr, "failure to find y n in find_rect\n"); + clean_up_exit(1); + } + + } else if (type[j] == Force) { + + int x0 = val[1][j]; + int y0 = val[2][j]; + n = val[0][j]; + + r1 = sraRgnCreateRect(x0, y0, x0+w, y0+h); + + for (i=0; i dpy_y) { + continue; + } + r2 = sraRgnCreateRect(xb, yb, xb+wb, yb+hb); + if (sraRgnAnd(r2, r1)) { + free_rect(i); + } + sraRgnDestroy(r2); + } + *x_hit = x0; + *y_hit = y0; + r3 = rect_reg[2*n-1]; + sraRgnSubtract(r3, r1); + sraRgnDestroy(r1); + +fprintf(stderr, ">>**--**>> found rect [%d] via RAN FORCE: %dx%d+%d+%d -- %d %d\n", n, w, h, x, y, *x_hit, *y_hit); + + fr_FORCE++; + fr_FORCEt++; + } +} + +void expire_rects(int idx, int w, int h, int *x_hit, int *y_hit, int big1, int big2, int cram) { + int method = 2; + if (method == 1) { + expire_rects1(idx, w, h, x_hit, y_hit, big1, big2, cram); + } else if (method == 2) { + expire_rects2(idx, w, h, x_hit, y_hit, big1, big2, cram); + } +} + +int find_rect(int idx, int x, int y, int w, int h) { + sraRegionPtr r1, r2, r3; + sraRectangleIterator *iter; + sraRect rt; + int n, x_hit = -1, y_hit = -1; + int big1 = 0, big2 = 0, cram = 0; + double fac1 = 0.1, fac2 = 0.25; + double last_clean = 0.0; + double now = dnow(); + + if (rect_reg[1] == NULL) { + for (n = 1; n <= ncache; n++) { + rect_reg[n] = sraRgnCreateRect(0, n * dpy_y, dpy_x, (n+1) * dpy_y); + } + } else if (now > last_clean + 60) { +//fprintf(stderr, "free_rect: cleaning up regions:\n"); + last_clean = now; + for (n = 1; n < ncache; n += 2) { + int i, n2 = n+1; + + /* n */ + sraRgnDestroy(rect_reg[n]); + r1 = sraRgnCreateRect(0, n * dpy_y, dpy_x, (n+1) * dpy_y); + for (i=0; i= cache_list_num) { +fprintf(stderr, "free_rect: bad index: %d\n", idx); + clean_up_exit(1); + } + + cache_list[idx].bs_x = -1; + cache_list[idx].su_x = -1; + cache_list[idx].bs_time = 0.0; + cache_list[idx].su_time = 0.0; + + if (ncache_pad) { + x -= ncache_pad; + y -= ncache_pad; + w += 2 * ncache_pad; + h += 2 * ncache_pad; + } + + if (ncache <= 2) { + cram = 1; + fac2 = 0.45; + } else if (ncache <= 4) { + fac1 = 0.18; + fac2 = 0.35; + } + if (w * h > fac1 * (dpy_x * dpy_y)) { + big1 = 1; + } + if (w * h > fac2 * (dpy_x * dpy_y)) { + big2 = 1; + } + + if (w > dpy_x || h > dpy_y) { +fprintf(stderr, ">>**--**>> BIG1 rect: %dx%d+%d+%d -- %d %d\n", w, h, x, y, x_hit, y_hit); + fr_BIG1++; + fr_BIG1t++; + return 0; + } + if (w == dpy_x && h && dpy_y) { +fprintf(stderr, ">>**--**>> BIG1 rect: %dx%d+%d+%d -- %d %d (FULL DISPLAY)\n", w, h, x, y, x_hit, y_hit); + fr_BIG1++; + fr_BIG1t++; + return 0; + } + if (cram && big2) { +fprintf(stderr, ">>**--**>> BIG2 rect: %dx%d+%d+%d -- %d %d\n", w, h, x, y, x_hit, y_hit); + fr_BIG2++; + fr_BIG2t++; + return 0; + } + + /* first try individual rects of unused region */ + for (n = 1; n < ncache; n += 2) { + r1 = rect_reg[n]; + r2 = NULL; + if (big1 && n == 1 && ncache > 2) { + continue; + } + if (big2 && n <= 3 && ncache > 4) { + continue; + } + iter = sraRgnGetIterator(r1); + while (sraRgnIteratorNext(iter, &rt)) { + int rw = rt.x2 - rt.x1; + int rh = rt.y2 - rt.y1; + if (cram && big1 && rt.x1 < dpy_x/4) { + continue; + } + if (rw >= w && rh >= h) { + x_hit = rt.x1; + y_hit = rt.y1; + if (cram && big1) { + x_hit = rt.x2 - w; + } + r2 = sraRgnCreateRect(x_hit, y_hit, x_hit + w, y_hit + h); + break; + } + } + sraRgnReleaseIterator(iter); + if (r2 != NULL) { +fprintf(stderr, ">>**--**>> found rect via REGION: %dx%d+%d+%d -- %d %d\n", w, h, x, y, x_hit, y_hit); + fr_REGION++; + fr_REGIONt++; + sraRgnSubtract(r1, r2); + sraRgnDestroy(r2); + break; + } + } + + + /* next try moving corner to grid points */ + if (x_hit < 0) { + for (n = 1; n < ncache; n += 2) { + int rx, ry, Nx = 48, Ny = 24, ny = n * dpy_y; + + if (big1 && n == 1 && ncache > 2) { + continue; + } + if (big2 && n == 3 && ncache > 4) { + continue; + } + + r1 = sraRgnCreateRect(0, n * dpy_y, dpy_x, (n+1) * dpy_y); + sraRgnSubtract(r1, rect_reg[n]); + r2 = NULL; + + rx = 0; + while (rx + w <= dpy_x) { + ry = 0; + if (cram && big1 && rx < dpy_x/4) { + rx += dpy_x/Nx; + continue; + } + while (ry + h <= dpy_y) { + r2 = sraRgnCreateRect(rx, ry+ny, rx + w, ry+ny + h); + if (sraRgnAnd(r2, r1)) { + sraRgnDestroy(r2); + r2 = NULL; + } else { + sraRgnDestroy(r2); + r2 = sraRgnCreateRect(rx, ry+ny, rx + w, ry+ny + h); + x_hit = rx; + y_hit = ry+ny; + } + ry += dpy_y/Ny; + if (r2) break; + } + rx += dpy_x/Nx; + if (r2) break; + } + sraRgnDestroy(r1); + if (r2 != NULL) { + sraRgnSubtract(rect_reg[n], r2); + sraRgnDestroy(r2); +fprintf(stderr, ">>**--**>> found rect via GRID: %dx%d+%d+%d -- %d %d\n", w, h, x, y, x_hit, y_hit); + fr_GRID++; + fr_GRIDt++; + break; + } + } + } + + /* next, try expiring the oldest/smallest used bs/su rectangle we fit in */ + + if (x_hit < 0) { + expire_rects(idx, w, h, &x_hit, &y_hit, big1, big2, cram); + } + + cache_list[idx].bs_x = x_hit; + cache_list[idx].bs_y = y_hit; + cache_list[idx].bs_w = w; + cache_list[idx].bs_h = h; + + cache_list[idx].su_x = x_hit; + cache_list[idx].su_y = y_hit + dpy_y; + cache_list[idx].su_w = w; + cache_list[idx].su_h = h; + + if (x_hit < 0) { + /* bad news, can it still happen? */ + fprintf(stderr, ">>**--**>> *FAIL rect: %dx%d+%d+%d -- %d %d\n", w, h, x, y, x_hit, y_hit); + fr_FAIL++; + fr_FAILt++; + return 0; + } else { + //fprintf(stderr, ">>**--**>> found rect: %dx%d+%d+%d -- %d %d\n", w, h, x, y, x_hit, y_hit); + } + + if (zero_rects) { + r1 = sraRgnCreateRect(x_hit, y_hit, x_hit+w, y_hit+h); + sraRgnSubtract(zero_rects, r1); + sraRgnDestroy(r1); + r1 = sraRgnCreateRect(x_hit, y_hit+dpy_y, x_hit+w, y_hit+dpy_y+h); + sraRgnSubtract(zero_rects, r1); + sraRgnDestroy(r1); + } + + return 1; +} + +static void cache_cr(sraRegionPtr r, int dx, int dy, double d0, double d1, int *nbatch) { + if (sraRgnEmpty(r)) { + return; + } + if (nbatch == NULL) { + if (!fb_push_wait(d0, FB_COPY)) { + fb_push_wait(d0/2, FB_COPY); + } + do_copyregion(r, dx, dy, 0); + if (!fb_push_wait(d1, FB_COPY)) { + fb_push_wait(d1/2, FB_COPY); + } + } else { + batch_dxs[*nbatch] = dx; + batch_dys[*nbatch] = dy; + batch_reg[*nbatch] = sraRgnCreateRgn(r); + (*nbatch)++; + } +} + +double save_delay0 = 0.02; +double restore_delay0 = 0.02; +double save_delay1 = 0.05; +double restore_delay1 = 0.05; +static double dtA, dtB; + +int valid_wr(int idx, Window win, XWindowAttributes *attr) { +#ifdef MACOSX + if (macosx_console) { + /* this is all to avoid animation changing WxH+X+Y... */ + if (idx >= 0) { + int rc = valid_window(win, attr, 1); + attr->x = cache_list[idx].x; + attr->y = cache_list[idx].y; + attr->width = cache_list[idx].width; + attr->height = cache_list[idx].height; + return rc; + } else { + return valid_window(win, attr, 1); + } + } +#endif + return valid_window(win, attr, 1); +} + +int bs_save(int idx, int *nbatch) { + Window win = cache_list[idx].win; + XWindowAttributes attr; + int x1, y1, w1, h1; + int x2, y2, w2, h2; + int x, y, w, h; + int dx, dy, rc = 1; + sraRegionPtr r, r0; + + x1 = cache_list[idx].x; + y1 = cache_list[idx].y; + w1 = cache_list[idx].width; + h1 = cache_list[idx].height; + +fprintf(stderr, "backingstore save: 0x%x %3d \n", win, idx); + + X_LOCK; + if (! valid_wr(idx, win, &attr)) { +fprintf(stderr, "bs_save: not a valid X window: 0x%x\n", win); +/* XXX Y */ +// DELETE(idx); + X_UNLOCK; + cache_list[idx].valid = 0; + return 0; + } + X_UNLOCK; + + x2 = attr.x; + y2 = attr.y; + w2 = attr.width; + h2 = attr.height; + + if (cache_list[idx].bs_x < 0) { + rc = find_rect(idx, x2, y2, w2, h2); + } else if (w2 > cache_list[idx].bs_w || h2 > cache_list[idx].bs_h) { + free_rect(idx); + rc = find_rect(idx, x2, y2, w2, h2); + } + + x = cache_list[idx].bs_x; + y = cache_list[idx].bs_y; + w = cache_list[idx].bs_w; + h = cache_list[idx].bs_h; + + if (x < 0 || ! rc) { + STORE(idx, win, attr); +fprintf(stderr, "BS_save: FAIL FOR: %d\n", idx); + return 0; + } + + if (ncache_pad) { + x2 -= ncache_pad; + y2 -= ncache_pad; + w2 += 2 * ncache_pad; + h2 += 2 * ncache_pad; + } + + if (clipshift) { + x2 -= coff_x; + y2 -= coff_y; + } + + dx = x - x2; + dy = y - y2; + + r0 = sraRgnCreateRect(0, 0, dpy_x, dpy_y); + r = sraRgnCreateRect(x2, y2, x2+w2, y2+h2); + sraRgnAnd(r, r0); + sraRgnOffset(r, dx, dy); + + dtA = dnowx(); +fprintf(stderr, "BS_save: %.4f %d dx=%d dy=%d\n", dtA, idx, dx, dy); + if (w2 > 0 && h2 > 0) { + cache_cr(r, dx, dy, save_delay0, save_delay1, nbatch); + } + dtB = dnowx(); +fprintf(stderr, "BS_save: %.4f %.2f %d done. %dx%d+%d+%d %dx%d+%d+%d %.2f %.2f\n", dtB, dtB-dtA, idx, w1, h1, x1, y1, w2, h2, x2, y2, cache_list[idx].bs_time - x11vnc_start, dnowx()); + + sraRgnDestroy(r0); + sraRgnDestroy(r); STORE(idx, win, attr); - cache_list[idx].su_time = dnow(); + cache_list[idx].bs_time = dnow(); return 1; } -int bs_restore(int idx) { +int su_save(int idx, int *nbatch) { Window win = cache_list[idx].win; XWindowAttributes attr; int x1, y1, w1, h1; int x2, y2, w2, h2; int x, y, w, h; - int dx, dy; - sraRegionPtr r; + int dx, dy, rc = 1; + sraRegionPtr r, r0; + +fprintf(stderr, "save-unders save: 0x%x %3d \n", win, idx); + + x1 = cache_list[idx].x; + y1 = cache_list[idx].y; + w1 = cache_list[idx].width; + h1 = cache_list[idx].height; - if (cache_list[idx].bs_x < 0 || cache_list[idx].bs_time == 0.0) { + X_LOCK; + if (! valid_wr(idx, win, &attr)) { +fprintf(stderr, "su_save: not a valid X window: 0x%x\n", win); +/* XXX Y */ +// DELETE(idx); + X_UNLOCK; + cache_list[idx].valid = 0; return 0; } + X_UNLOCK; + + x2 = attr.x; + y2 = attr.y; + w2 = attr.width; + h2 = attr.height; + + if (cache_list[idx].bs_x < 0) { + rc = find_rect(idx, x2, y2, w2, h2); + } else if (w2 > cache_list[idx].su_w || h2 > cache_list[idx].su_h) { + free_rect(idx); + rc = find_rect(idx, x2, y2, w2, h2); + } + x = cache_list[idx].su_x; + y = cache_list[idx].su_y; + w = cache_list[idx].su_w; + h = cache_list[idx].su_h; + + if (x < 0 || ! rc) { + STORE(idx, win, attr); +fprintf(stderr, "SU_save: FAIL FOR: %d\n", idx); + return 0; + } + + if (ncache_pad) { + x2 -= ncache_pad; + y2 -= ncache_pad; + w2 += 2 * ncache_pad; + h2 += 2 * ncache_pad; + } + + if (clipshift) { + x2 -= coff_x; + y2 -= coff_y; + } + + dx = x - x2; + dy = y - y2; + + r0 = sraRgnCreateRect(0, 0, dpy_x, dpy_y); + r = sraRgnCreateRect(x2, y2, x2+w2, y2+h2); + sraRgnAnd(r, r0); + sraRgnOffset(r, dx, dy); + + dtA = dnowx(); +fprintf(stderr, "SU_save: %.4f %d dx=%d dy=%d\n", dtA, idx, dx, dy); + if (w2 > 0 && h2 > 0) { + cache_cr(r, dx, dy, save_delay0, save_delay1, nbatch); + } + dtB = dnowx(); +fprintf(stderr, "SU_save: %.4f %.2f %d done. %dx%d+%d+%d %dx%d+%d+%d %.2f %.2f\n", dtB, dtB-dtA, idx, w1, h1, x1, y1, w2, h2, x2, y2, cache_list[idx].su_time - x11vnc_start, dnowx()); + + sraRgnDestroy(r0); + sraRgnDestroy(r); + + STORE(idx, win, attr); + cache_list[idx].su_time = dnow(); + + return 1; +} + +int bs_restore(int idx, int *nbatch, int nopad) { + Window win = cache_list[idx].win; + XWindowAttributes attr; + int x1, y1, w1, h1; + int x2, y2, w2, h2; + int x, y, w, h; + int dx, dy; + sraRegionPtr r, r0; + +fprintf(stderr, "backingstore restore: 0x%x %3d \n", win, idx); x1 = cache_list[idx].x; y1 = cache_list[idx].y; w1 = cache_list[idx].width; h1 = cache_list[idx].height; - if (! valid_window(win, &attr, 1)) { -fprintf(stderr, "bs_restore: not valid\n"); + X_LOCK; + if (! valid_wr(idx, win, &attr)) { +fprintf(stderr, "BS_restore: not a valid X window: 0x%x\n", win); DELETE(idx); + X_UNLOCK; return 0; } + X_UNLOCK; x2 = attr.x; y2 = attr.y; @@ -5015,19 +6756,54 @@ fprintf(stderr, "bs_restore: not valid\n"); w = cache_list[idx].bs_w; h = cache_list[idx].bs_h; - if (x < 0) { + if (x < 0 || cache_list[idx].bs_time == 0.0) { STORE(idx, win, attr); return 0; } + if (ncache_pad) { + if (nopad) { + x += ncache_pad; + y += ncache_pad; + w -= 2 * ncache_pad; + h -= 2 * ncache_pad; + } else { + x2 -= ncache_pad; + y2 -= ncache_pad; + w2 += 2 * ncache_pad; + h2 += 2 * ncache_pad; + } + } + + if (clipshift) { + x2 -= coff_x; + y2 -= coff_y; + } + dx = x2 - x; dy = y2 - y; - r = sraRgnCreateRect(x+dx, y+dy, x+w2+dx, y+h2+dy); -fprintf(stderr, "bs_restore: dx=%d dy=%d\n", dx, dy); - do_copyregion(r, dx, dy); - fb_push_wait(0.01, FB_COPY); -fprintf(stderr, "bs_rest: done. %dx%d+%d+%d %dx%d+%d+%d %.2f %.2f\n", w1, h1, x1, y1, w2, h2, x2, y2, cache_list[idx].bs_time, dnow()); + if (w2 > w) { + w2 = w; + } + if (h2 > h) { + h2 = h; + } + + r0 = sraRgnCreateRect(0, 0, dpy_x, dpy_y); + r = sraRgnCreateRect(x, y, x+w2, y+h2); + sraRgnOffset(r, dx, dy); + sraRgnAnd(r, r0); + + dtA = dnowx(); +fprintf(stderr, "BS_rest: %.4f %d dx=%d dy=%d\n", dtA, idx, dx, dy); + if (w2 > 0 && h2 > 0) { + cache_cr(r, dx, dy, restore_delay0, restore_delay1, nbatch); + } + dtB = dnowx(); +fprintf(stderr, "BS_rest: %.4f %.2f %d done. %dx%d+%d+%d %dx%d+%d+%d %.2f %.2f\n", dtB, dtB-dtA, idx, w1, h1, x1, y1, w2, h2, x2, y2, cache_list[idx].bs_time - x11vnc_start, dnowx()); + + sraRgnDestroy(r0); sraRgnDestroy(r); STORE(idx, win, attr); @@ -5035,27 +6811,26 @@ fprintf(stderr, "bs_rest: done. %dx%d+%d+%d %dx%d+%d+%d %.2f %.2f\n", w1, h1, return 1; } -int su_restore(int idx) { +int su_restore(int idx, int *nbatch, int nopad) { Window win = cache_list[idx].win; XWindowAttributes attr; int x1, y1, w1, h1; int x2, y2, w2, h2; int x, y, w, h; int dx, dy; - sraRegionPtr r; + sraRegionPtr r, r0; int invalid = 0; - - if (cache_list[idx].su_x < 0 || cache_list[idx].su_time == 0.0) { - return 0; - } +fprintf(stderr, "save-unders restore: 0x%x %3d \n", win, idx); + x1 = cache_list[idx].x; y1 = cache_list[idx].y; w1 = cache_list[idx].width; h1 = cache_list[idx].height; - if (! valid_window(win, &attr, 1)) { -fprintf(stderr, "su_restore: not valid\n"); + X_LOCK; + if (! valid_wr(idx, win, &attr)) { +fprintf(stderr, "SU_restore: not a valid X window: 0x%x\n", win); invalid = 1; x2 = x1; y2 = y1; @@ -5067,237 +6842,946 @@ fprintf(stderr, "su_restore: not valid\n"); w2 = attr.width; h2 = attr.height; } + X_UNLOCK; x = cache_list[idx].su_x; y = cache_list[idx].su_y; w = cache_list[idx].su_w; h = cache_list[idx].su_h; - if (x < 0) { + if (x < 0 || cache_list[idx].bs_x < 0 || cache_list[idx].su_time == 0.0) { +fprintf(stderr, "SU_rest: su_x/bs_x/su_time: %d %d %.3f\n", x, cache_list[idx].bs_x, cache_list[idx].su_time); if (invalid) { DELETE(idx); } return 0; } - dx = x2 - x; - dy = y2 - y; + if (ncache_pad) { + if (nopad) { + x += ncache_pad; + y += ncache_pad; + w -= 2 * ncache_pad; + h -= 2 * ncache_pad; + } else { + x2 -= ncache_pad; + y2 -= ncache_pad; + w2 += 2 * ncache_pad; + h2 += 2 * ncache_pad; + } + } + + if (clipshift) { + x2 -= coff_x; + y2 -= coff_y; + } + + dx = x2 - x; + dy = y2 - y; + + if (w2 > w) { + w2 = w; + } + if (h2 > h) { + h2 = h; + } + + r0 = sraRgnCreateRect(0, 0, dpy_x, dpy_y); + r = sraRgnCreateRect(x, y, x+w2, y+h2); + sraRgnOffset(r, dx, dy); + sraRgnAnd(r, r0); + + dtA = dnowx(); +fprintf(stderr, "SU_rest: %.4f %d dx=%d dy=%d\n", dtA, idx, dx, dy); + if (w2 > 0 && h2 > 0) { + cache_cr(r, dx, dy, restore_delay0, restore_delay1, nbatch); + } + dtB = dnowx(); +fprintf(stderr, "SU_rest: %.4f %.2f %d done. %dx%d+%d+%d %dx%d+%d+%d %.2f %.2f\n", dtB, dtB-dtA, idx, w1, h1, x1, y1, w2, h2, x2, y2, cache_list[idx].su_time - x11vnc_start, dnowx()); + + sraRgnDestroy(r0); + sraRgnDestroy(r); + + if (invalid) { + DELETE(idx); + return 0; + } else { + STORE(idx, win, attr); + return 1; + } +} + +void check_zero_rects(void) { + sraRect rt; + sraRectangleIterator *iter; + if (! zero_rects) { + zero_rects = sraRgnCreate(); + } + if (sraRgnEmpty(zero_rects)) { + return; + } + + iter = sraRgnGetIterator(zero_rects); + while (sraRgnIteratorNext(iter, &rt)) { + zero_fb(rt.x1, rt.y1, rt.x2, rt.y2); + mark_rect_as_modified(rt.x1, rt.y1, rt.x2, rt.y2, 0); + } + sraRgnReleaseIterator(iter); + sraRgnMakeEmpty(zero_rects); +} + +void block_stats(void) { + int n, k, area, s1, s2; + static int t = -1; + int vcnt, icnt, tcnt, vtot = 0, itot = 0, ttot = 0; + t++; + for (n = 1; n < ncache+1; n += 2) { + double area = 0.0, frac; + vcnt = 0; + icnt = 0; + tcnt = 0; + for(k=0; k= 0) { + ttot++; + } + } + if (y < n*dpy_y || y > (n+1)*dpy_y) { + continue; + } + if (n != 1) { + X_LOCK; + rc = valid_window(win, &attr, 1); + X_UNLOCK; + } + if (rc) { + vcnt++; + } else { + icnt++; + } + if (x >= 0) { + tcnt++; + } + if (x < 0) { + continue; + } + area += cache_list[k].width * cache_list[k].height; + if (! rc && ! macosx_console) { + char *u = getenv("USER"); + if (u && !strcmp(u, "runge")) fprintf(stderr, "\a"); + fprintf(stderr, "\n *** UNRECLAIMED WINDOW: 0x%x %dx%d+%d+%d\n\n", win, w, h, x, y); + DELETE(k); + } + if (t < 3 || (t % 4) == 0 || hack_val || macosx_console) { + double t1 = cache_list[k].su_time; + double t2 = cache_list[k].bs_time; + if (t1 > 0.0) {t1 = dnow() - t1;} else {t1 = -1.0;} + if (t2 > 0.0) {t2 = dnow() - t2;} else {t2 = -1.0;} + fprintf(stderr, " [%02d] %04d 0x%08x bs: %04dx%04d+%04d+%05d vw: %04dx%04d+%04d+%04d cl: %04dx%04d+%04d+%04d map=%d su=%9.3f bs=%9.3f\n", + n, k, win, w, h, x, y, attr.width, attr.height, attr.x, attr.y, + cache_list[k].width, cache_list[k].height, cache_list[k].x, cache_list[k].y, + attr.map_state == IsViewable, t1, t2); + } + } + frac = area /(dpy_x * dpy_y); + fprintf(stderr, "block[%02d] %.3f %8d trak/val/inval: %d/%d/%d of %d\n", n, frac, (int) area, tcnt, vcnt, icnt, vcnt+icnt); + } + + fprintf(stderr, "\n"); + fprintf(stderr, "block: trak/val/inval %d/%d/%d of %d\n", ttot, vtot, itot, vtot+itot); + + s1 = fr_REGION + fr_GRID + fr_EXPIRE + fr_FORCE + fr_BIG1 + fr_BIG2 + fr_FAIL; + s2 = fr_REGIONt + fr_GRIDt + fr_EXPIREt + fr_FORCEt + fr_BIG1t + fr_BIG2t + fr_FAILt; + fprintf(stderr, "\n"); + fprintf(stderr, "find_rect: REGION/GRID/EXPIRE/FORCE - BIG1/BIG2/FAIL %d/%d/%d/%d - %d/%d/%d of %d\n", + fr_REGION, fr_GRID, fr_EXPIRE, fr_FORCE, fr_BIG1, fr_BIG2, fr_FAIL, s1); + fprintf(stderr, " totals: %d/%d/%d/%d - %d/%d/%d of %d\n", + fr_REGIONt, fr_GRIDt, fr_EXPIREt, fr_FORCEt, fr_BIG1t, fr_BIG2t, fr_FAILt, s2); + + fr_BIG1 = 0; + fr_BIG2 = 0; + fr_REGION = 0; + fr_GRID = 0; + fr_EXPIRE = 0; + fr_FORCE = 0; + fr_FAIL = 0; + fprintf(stderr, "\n"); +} + +#define NSCHED 64 +Window sched_bs[NSCHED]; +double sched_tm[NSCHED]; +double last_sched_bs = 0.0; + +#define SCHED(w) \ +{ \ + int k, save = -1, empty = 1; \ + for (k=0; k < NSCHED; k++) { \ + if (sched_bs[k] == None) { \ + save = k; \ + } \ + if (sched_bs[k] == w) { \ + save = k; \ + empty = 0; \ + break; \ + } \ + } \ + if (save >= 0) { \ + sched_bs[save] = w; \ + if (empty) { \ + sched_tm[save] = dnow(); \ + fprintf(stderr, "SCHED: %d %f\n", save, dnowx()); \ + } \ + } \ +} + +void xselectinput(Window w, unsigned long evmask, int sync) { +#if NO_X11 + trapped_xerror = 0; + trapped_xioerror = 0; +#else + XErrorHandler old_handler1; + XIOErrorHandler old_handler2; + + old_handler1 = XSetErrorHandler(trap_xerror); + old_handler2 = XSetIOErrorHandler(trap_xioerror); + trapped_xerror = 0; + trapped_xioerror = 0; + + XSelectInput(dpy, w, evmask); + + /* + * We seem to need to synchronize right away since the window + * might go away quickly. + */ + if (sync) { + XSync(dpy, False); + } else { + XFlush_wr(dpy); + } + + XSetErrorHandler(old_handler1); + XSetIOErrorHandler(old_handler2); +#endif - r = sraRgnCreateRect(x+dx, y+dy, x+w2+dx, y+h2+dy); -fprintf(stderr, "su_restore: dx=%d dy=%d\n", dx, dy); - do_copyregion(r, dx, dy); - fb_push_wait(0.01, FB_COPY); -fprintf(stderr, "su_rest: done. %dx%d+%d+%d %dx%d+%d+%d %.2f %.2f\n", w1, h1, x1, y1, w2, h2, x2, y2, cache_list[idx].su_time, dnow()); - sraRgnDestroy(r); + if (trapped_xerror) { + fprintf(stderr, "XSELECTINPUT: trapped X Error."); + } + if (trapped_xioerror) { + fprintf(stderr, "XSELECTINPUT: trapped XIO Error."); + } +if (sync) fprintf(stderr, "XSELECTINPUT: 0x%x sync=%d err=%d/%d\n", w, sync, trapped_xerror, trapped_xioerror); +} - if (invalid) { - DELETE(idx); - return 0; - } else { - STORE(idx, win, attr); - return 1; +Bool xcheckmaskevent(Display *d, long mask, XEvent *ev) { +#ifdef MACOSX + if (macosx_console) { + if (macosx_checkevent(ev)) { + return True; + } else { + return False; + } } +#endif + RAWFB_RET(False); + +#if NO_X11 + return False; +#else + return XCheckMaskEvent(d, mask, ev); +#endif } #include -void check_ncache(void) { +#define EVMAX 2048 +XEvent Ev[EVMAX]; +int Ev_done[EVMAX]; +int Ev_area[EVMAX]; +Window Ev_win[EVMAX]; +Window Ev_map[EVMAX]; +Window Ev_unmap[EVMAX]; +sraRect Ev_rects[EVMAX]; + +int check_ncache(int reset, int mode) { static int last_map = -1; static double last_root = 0.0; static int first = 1; - int i, j, k; + static int last_client_count = -1; + int i, j, k, n, t; + int n_CN = 0, n_RN = 0, n_DN = 0, n_ON = 0, n_MN = 0, n_UN = 0; + int n_VN = 0, n_VN_p = 0, n_VN_u = 0; + double now, refresh = 60.0; Window win, win2; XWindowAttributes attr; XEvent ev; + unsigned long all_ev = SubstructureNotifyMask|StructureNotifyMask|VisibilityChangeMask; + unsigned long win_ev = StructureNotifyMask|VisibilityChangeMask; + + Window awin0, awin1, awin2; + int area0, area1, area2; + int try_batch = 1; /* XXX Y */ + int use_batch = 0; + int nreg = 0, *nbatch; + static int didtopmost = 0; + int create_cnt, create_tot; + int pixels = 0; + + int nrects = 0; + + Window resize_inc[16]; + Window resize_dec[16]; + XWindowAttributes attr_inc[16]; + XWindowAttributes attr_dec[16]; + int nresize = 16; - if (! ncache || ! ncache0) { - return; +#ifdef MACOSX + if (! macosx_console) { + RAWFB_RET(-1) } +#else + RAWFB_RET(-1) +#endif + if (! screen) { - return; + return -1; } - if (! dpy) { - return; + + now = dnow(); + + if (ncache0) { + if (reset) { + ; + } else if (! client_count || !ncache) { + static double last_purge = 0.0; + double delay = client_count ? 0.5 : 2.0; + if (now > last_purge + delay) { + int c = 0; + XEvent ev; + X_LOCK; + while (xcheckmaskevent(dpy, all_ev, &ev)) { + c++; + } + X_UNLOCK; + last_purge = dnow(); +if (c) fprintf(stderr, "check_ncache purged %d events\n", c); + } + if (!client_count && last_client_count >= 0 && + client_count != last_client_count) { + /* this should use less RAM when no clients */ + do_new_fb(1); + } + last_client_count = client_count; + return -1; + } + } + last_client_count = client_count; + + if (ncache && ! ncache0) { + ncache0 = ncache; + } + + if (! ncache || ! ncache0) { + return -1; + } + if (subwin) { + return -1; + } + + if (reset) { + rfbLog("check_ncache: resetting cache\n"); + for (i=0; i < cache_list_num; i++) { + free_rect(i); + CLEAR(i); + } + for (n = 1; n <= ncache; n++) { + if (rect_reg[n] != NULL) { + sraRgnDestroy(rect_reg[n]); + rect_reg[n] = NULL; + } + } + zero_fb(0, dpy_y, dpy_x, (ncache+1)*dpy_y); + mark_rect_as_modified(0, dpy_y, dpy_x, (ncache+1)*dpy_y, 0); + return -1; } if (first) { - int dx = 10, dy = 24; + int dx = 10, dy = 24, ds = 0; + int Dx = dpy_x, Dy = dpy_y; + first = 0; for (i=0; i < NRECENT; i++) { recent[i] = None; } + for (i=0; i < NSCHED; i++) { + sched_bs[i] = None; + } rlast = 0; + X_LOCK; /* event leak with client_count == 0 */ xselectinput_rootwin |= SubstructureNotifyMask; - XSelectInput(dpy, rootwin, xselectinput_rootwin); + XSelectInput_wr(dpy, rootwin, xselectinput_rootwin); X_UNLOCK; - first = 0; - rfbDrawString(screen, &default8x16Font, dx, dpy_y+1*dy, - "This is the Pixel buffer cache region. Your VNC Viewer is not hiding it from you.", - white_pixel()); - rfbDrawString(screen, &default8x16Font, dx, dpy_y+2*dy, - "Try resizing your VNC Viewer so you don't see it !!", - white_pixel()); - rfbDrawString(screen, &default8x16Font, dx, dpy_y+3*dy, - "To disable run the server with: x11vnc -ncache 0 ...", - white_pixel()); - rfbDrawString(screen, &default8x16Font, dx, dpy_y+4*dy, - "More info: http://www.karlrunge.com/x11vnc/#faq-client-caching", - white_pixel()); + + if (scaling) { + Dx = scaled_x; + Dy = scaled_y; + } + if (!rotating_same) { + int t = Dx; + Dx = Dy; + Dy = t; + } + + for (i = 0; i < 3; i++) { + rfbDrawString(screen, &default8x16Font, dx, ds + Dy+1*dy, + "This is the Pixel buffer cache region. Your VNC Viewer is not hiding it from you.", + white_pixel()); + rfbDrawString(screen, &default8x16Font, dx, ds + Dy+2*dy, + "Try resizing your VNC Viewer so you don't see it !!", + white_pixel()); + rfbDrawString(screen, &default8x16Font, dx, ds + Dy+3*dy, + "To disable run the server with: x11vnc -ncache 0 ...", + white_pixel()); + rfbDrawString(screen, &default8x16Font, dx, ds + Dy+4*dy, + "More info: http://www.karlrunge.com/x11vnc/#faq-client-caching", + white_pixel()); + + ds += 8 * dy; + } + snapshot_cache_list(0, 100.0); +fprintf(stderr, "cache_list_num: %d\n", cache_list_num); + for (i=0; i < cache_list_num; i++) { + CLEAR(i); + } + for (n = 1; n <= ncache; n++) { + rect_reg[n] = NULL; + } } - if (! client_count) { - return; + if (now < last_client + 2) { + return -1; } - now = dnow(); + +if (hack_val == 2) { + block_stats(); + hack_val = 1; +} +#ifdef MACOSX + if (macosx_console) { + static double last_all_windows = 0.0; + if (! macosx_checkevent(NULL)) { + if (now > last_all_windows + 0.05) { + macosxCGS_get_all_windows(); + last_all_windows = dnow(); + } + } + /* XXX Y */ + rootwin = -1; + } +#endif if (now > last_root + refresh) { + Window topmapped = None; + fprintf(stderr, "\n**** checking cache_list[%d]\n\n", cache_list_num); + block_stats(); + for(k=0; k now - refresh) { -fprintf(stderr, " Young[%d]: 0x%x\n", k, win); + ; } else if (valid_window(win, &attr, 1)) { STORE(k, win, attr); +//fprintf(stderr, "STORE(%2d) %03dx%03d+%03d+%03d\n", k, cache_list[k].width, cache_list[k].height, cache_list[k].x, cache_list[k].y); if (! cache_list[k].selectinput) { - X_LOCK; -fprintf(stderr, " XSelectInput[%d]: 0x%x\n", k, win); - XSelectInput(dpy, win, StructureNotifyMask); - X_UNLOCK; + xselectinput(win, win_ev, 0); CLEAR(k); cache_list[k].selectinput = 1; } else { -//fprintf(stderr, " SKIP XSelectInput[%d]: 0x%x\n", k, win); + ; + } + if (attr.map_state == IsViewable) { + topmapped = win; } + valid = 1; } else { -fprintf(stderr, " DELETE(%d) 0x%x\n", k, win); +fprintf(stderr, "DELETE(%d) %dx%d+%d+%d\n", k, cache_list[k].width, cache_list[k].height, cache_list[k].x, cache_list[k].y); DELETE(k); } + X_UNLOCK; +/* XXX Y */ + if (valid) { + if (cache_list[k].create_cnt && attr.map_state != IsViewable && cache_list[k].map_cnt == 0) { + if (cache_list[k].bs_x >= 0) { +fprintf(stderr, "Created window never mapped: freeing(%d) 0x%x\n", k, win); + free_rect(k); + } + } + } } last_root = dnow(); + if (0 && ! didtopmost && topmapped != None) { + int idx = lookup_win_index(topmapped); + if (idx >= 0) { + if (! macosx_console) { + bs_save(idx, NULL); + } + } + } + didtopmost = 1; + } + + check_zero_rects(); + + if (now > last_sched_bs + 0.2) { + static double last_sched_vis = 0.0; + int nr = 0, *bat = NULL; + + if (try_batch) { + bat = &nr; + } + + for (i=0; i < NSCHED; i++) { + if (sched_bs[i] != None) { + int idx; + win = sched_bs[i]; + if (now < sched_tm[i] + 0.65) { + continue; + } + idx = lookup_win_index(win); + if (idx >= 0) { + int aw = cache_list[idx].width; + int ah = cache_list[idx].height; + if (cache_list[idx].map_state != IsViewable) { + ; + } else if (cache_list[idx].vis_state != VisibilityUnobscured) { + ; + } else if (aw * ah < 64 * 64) { + ; + } else { +fprintf(stderr, "*NEW BS_save: 0x%x %d %d %d\n", win, aw, ah, cache_list[idx].map_state); + bs_save(idx, bat); + } + } + } + sched_bs[i] = None; + } + if (nr) { + int k; + batch_copyregion(batch_reg, batch_dxs, batch_dys, nr, -1.0); + for (k=0; k < nr; k++) { + sraRgnDestroy(batch_reg[k]); + } + } + last_sched_bs = dnow(); + + if (now > last_sched_vis + 3.0) { + for (i=0; i < cache_list_num; i++) { + if (cache_list[i].map_state == IsViewable) { + if (cache_list[i].vis_state == VisibilityUnobscured) { + if (cache_list[i].valid) { + if (cache_list[i].win != None) { + SCHED(cache_list[i].win) + } + } + } + } + } + last_sched_vis = dnow(); + } + } + + n = 0; + create_tot = 0; + + X_LOCK; + while (xcheckmaskevent(dpy, all_ev, &Ev[n])) { + int type = Ev[n].type; + win = Ev[n].xany.window; + Ev_done[n] = 0; + Ev_area[n] = 0; + Ev_win[n] = None; + Ev_map[n] = None; + Ev_unmap[n] = None; + + if (win == rootwin) { + if (type == CreateNotify) { + n++; + create_tot++; + n_CN++; + } else if (type == ReparentNotify) { + n++; + n_RN++; + } else { + Window w = None; + /* skip rest */ +#if 0 +if (type == DestroyNotify) w = Ev[n].xdestroywindow.window; +if (type == UnmapNotify) w = Ev[n].xunmap.window; +if (type == MapNotify) w = Ev[n].xmap.window; +if (type == Expose) w = Ev[n].xexpose.window; +if (type == ConfigureNotify) w = Ev[n].xconfigure.window; +if (type != ConfigureNotify) fprintf(stderr, "root: skip %s for 0x%x\n", Etype(type), w); +#endif + + } + } else { + if (type == ReparentNotify) { + n++; + n_RN++; + } else if (type == DestroyNotify) { + n++; + n_DN++; + } else if (type == ConfigureNotify) { + n++; + n_ON++; + } else if (type == VisibilityNotify) { + if (Ev[n].xvisibility.state == VisibilityUnobscured) { + n_VN_u++; + } else { + n_VN_p++; + } + n++; + n_VN++; + } else if (type == MapNotify) { + n++; + n_MN++; + } else if (type == UnmapNotify) { + n++; + n_UN++; + } else { + /* skip rest */ +fprintf(stderr, "----- skip %s\n", Etype(type)); + } + } + if (n >= EVMAX) { + break; + } + } + X_UNLOCK; + + if (n == 0) { + return 0; + } +fprintf(stderr, "\n"); rfbLog("IN check_ncache() %d events.\n", n); + + for (i=0; i < n; i++) { + XEvent ev = Ev[i]; + int a, w, h, type, idx = -1; + + type = ev.type; + win = ev.xany.window; + Ev_win[i] = win; + + } + + if (try_batch) { + use_batch = 1; } + if (rotating) { + use_batch = 0; + } + if (cursor_noshape_updates_clients(screen)) { + use_batch = 0; + } + + if (! use_batch) { + nbatch = NULL; + } else { + nreg = 0; + nbatch = &nreg; + } + + create_cnt = 0; + X_LOCK; - while (XCheckMaskEvent(dpy, SubstructureNotifyMask|StructureNotifyMask, &ev)) { - int type = ev.type; - int idx; - win = ev.xany.window; + for (i=0; i < n; i++) { + XEvent ev; + int a, w, h, type, idx = -1; + + if (Ev_done[i]) continue; + win = Ev_win[i]; -//fprintf(stderr, "evnt: 0x%x %d pending: %d\n", win, type, XPending(dpy)); + ev = Ev[i]; + type = ev.type; + Ev_done[i] = 1; + if (win == rootwin) { if (type == CreateNotify) { - int x=0,y=0,w=0,h=0; + int x=0, y=0, w=0, h=0; + int valid = 0; win2 = ev.xcreatewindow.window; idx = lookup_win_index(win2); if (idx < 0) { idx = lookup_free_index(); + if (idx < 0) { + continue; + } + CLEAR(idx); } if (valid_window(win2, &attr, 1)) { STORE(idx, win2, attr); CLEAR(idx); -// su_save(idx); // not working x=attr.x; y=attr.y; w=attr.width; h=attr.height; - XSelectInput(dpy, win2, StructureNotifyMask); - cache_list[idx].selectinput = 1; +/* XXX Y */ + if (create_tot <= 6 && create_cnt++ < 3) { + if (w*h > 64 * 64) { + X_UNLOCK; + su_save(idx, nbatch); + X_LOCK; + if (cache_list[idx].valid) { + SCHED(win2) + } + create_cnt++; + } + } + if (cache_list[idx].valid) { + xselectinput(win2, win_ev, 1); + cache_list[idx].selectinput = 1; + cache_list[idx].create_cnt = 1; + valid = 1; + } else { + DELETE(idx); + } } -fprintf(stderr, "root: ** CreateNotify 0x%x %d -- %dx%d+%d+%d\n", win2, idx, w, h, x, y); +fprintf(stderr, "root%02d: ** CreateNotify 0x%x %3d -- %dx%d+%d+%d valid=%d\n", i, win2, idx, w, h, x, y, valid); + } else if (type == ReparentNotify) { if (ev.xreparent.parent != rootwin) { win2 = ev.xreparent.window; if (win2 != rootwin) { idx = lookup_win_index(win2); -fprintf(stderr, "root: ReparentNotify RM: 0x%x %d\n", win2, idx); +fprintf(stderr, "root%02d: ReparentNotifyRM 0x%x %3d\n", i, win2, idx); if (idx >= 0) { DELETE(idx); } - XSelectInput(dpy, win2, 0); + xselectinput(win2, 0, 1); } } - } else { - Window ww = None; - /* skip rest */ -if (type == DestroyNotify) ww = ev.xdestroywindow.window; -if (type == UnmapNotify) ww = ev.xunmap.window; -if (type == MapNotify) ww = ev.xmap.window; -if (type == Expose) ww = ev.xexpose.window; -if (type == ConfigureNotify) ww = ev.xconfigure.window; -fprintf(stderr, "root: skip %s for 0x%x\n", Etype(type), ww); } } else { - if (type == ReparentNotify) { - if (ev.xreparent.parent != rootwin) { - win2 = ev.xreparent.window; - if (win2 != rootwin) { - idx = lookup_win_index(win2); -fprintf(stderr, "----- ReparentNotify RM: 0x%x %d\n", win2, idx); - if (idx >= 0) { - DELETE(idx); - } - XSelectInput(dpy, win2, 0); - } - } + if (type == ConfigureNotify) { + int x_new, y_new, w_new, h_new; + int x_old, y_old, w_old, h_old; + Window oabove = None; + + idx = lookup_win_index(win); - } else if (type == DestroyNotify) { - win2 = ev.xdestroywindow.window; - idx = lookup_win_index(win2); -fprintf(stderr, "----- DestroyNotify 0x%x %d\n", win2, idx); if (idx >= 0) { - DELETE(idx); + oabove = cache_list[idx].above; } - } else if (type == ConfigureNotify) { +fprintf(stderr, "----%02d: ConfigureNotify 0x%x %3d -- above: 0x%x -> 0x%x %dx%d+%d+%d\n", i, win, idx, + oabove, ev.xconfigure.above, ev.xconfigure.width, ev.xconfigure.height, ev.xconfigure.x, ev.xconfigure.y); + + if (idx < 0) { + continue; + } + + x_new = ev.xconfigure.x; + y_new = ev.xconfigure.y; + w_new = ev.xconfigure.width; + h_new = ev.xconfigure.height; + x_old = cache_list[idx].x; + y_old = cache_list[idx].y; + w_old = cache_list[idx].width; + h_old = cache_list[idx].height; + + if (x_old != x_new || y_old != y_new) { + /* invalidate su */ + cache_list[idx].su_time = 0.0; +fprintf(stderr, " invalidate su: 0x%x xy: %d/%d %d/%d \n", win, x_old, y_old, x_new, y_new); + } + if (w_old != w_new || h_old != h_new) { + /* invalidate bs */ + cache_list[idx].bs_time = 0.0; +fprintf(stderr, " invalidate bs: 0x%x wh: %d/%d %d/%d \n", win, w_old, h_old, w_new, h_new); + } + + cache_list[idx].x = x_new; + cache_list[idx].y = y_new; + cache_list[idx].width = w_new; + cache_list[idx].height = h_new; + cache_list[idx].above = ev.xconfigure.above; + cache_list[idx].time = dnow(); + + } else if (type == VisibilityNotify) { + int state = ev.xvisibility.state; idx = lookup_win_index(win); -fprintf(stderr, "----- ConfigureNotify 0x%x %d -- %dx%d+%d+%d\n", win, idx, ev.xconfigure.width, ev.xconfigure.height, ev.xconfigure.x, ev.xconfigure.y); - if (idx >= 0) { - /* XXX invalidate su and/or bs */ - cache_list[idx].x = ev.xconfigure.x; - cache_list[idx].y = ev.xconfigure.y; - cache_list[idx].width = ev.xconfigure.width; - cache_list[idx].height = ev.xconfigure.height; +fprintf(stderr, "----%02d: VisibilityNotify 0x%x %3d state: %s U/P %d/%d\n", i, win, idx, VState(state), n_VN_u, n_VN_p); + + if (idx < 0) { + continue; } + if (macosx_console && n_VN_p == 0) { + ; /* XXXX not working well yet with UnmapNotify ... */ + } else if (state == VisibilityUnobscured) { + int i2, ok = 1; + for (i2=0; i2 < n; i2++) { + if (Ev_map[i2] == win) { + ok = 0; + break; + } + } + if (ncache <= 2) { + ok = 0; + } + if (ok) { + X_UNLOCK; + bs_restore(idx, nbatch, 1); + X_LOCK; + cache_list[idx].time = dnow(); + cache_list[idx].vis_cnt++; + Ev_map[i] = win; + Ev_rects[nrects].x1 = cache_list[idx].x; + Ev_rects[nrects].y1 = cache_list[idx].y; + Ev_rects[nrects].x2 = cache_list[idx].width; + Ev_rects[nrects].y2 = cache_list[idx].height; + nrects++; + SCHED(win) + } + } + cache_list[idx].vis_state = state; } else if (type == MapNotify) { idx = lookup_win_index(win); -fprintf(stderr, "----- MapNotify 0x%x %d\n", win, idx); +fprintf(stderr, "----%02d: MapNotify 0x%x %3d\n", i, win, idx); + if (idx < 0) { continue; } - if (cache_list[idx].map_state == IsUnmapped) { + + if (cache_list[idx].map_state == IsUnmapped || macosx_console) { X_UNLOCK; - su_save(idx); - bs_restore(idx); + su_save(idx, nbatch); + bs_restore(idx, nbatch, 0); + if (macosx_console) { +#ifdef MACOSX + macosxCGS_follow_animation_win(win, -1, 1); + if (valid_window(win, &attr, 1)) { + STORE(idx, win, attr); + SCHED(win); + } + /* XXX Y */ + if (cache_list[idx].vis_state == -1) { + cache_list[idx].vis_state = VisibilityUnobscured; + } +#endif + } X_LOCK; + pixels += cache_list[idx].width * cache_list[idx].height; + cache_list[idx].time = dnow(); + cache_list[idx].map_cnt++; + Ev_map[i] = win; + Ev_rects[nrects].x1 = cache_list[idx].x; + Ev_rects[nrects].y1 = cache_list[idx].y; + Ev_rects[nrects].x2 = cache_list[idx].width; + Ev_rects[nrects].y2 = cache_list[idx].height; + nrects++; } + cache_list[idx].map_state = IsViewable; } else if (type == UnmapNotify) { idx = lookup_win_index(win); -fprintf(stderr, "----- UnmapNotify 0x%x %d\n", win, idx); +fprintf(stderr, "----%02d: UnmapNotify 0x%x %3d\n", i, win, idx); + if (idx < 0) { continue; } - if (cache_list[idx].map_state == IsViewable) { + if (macosx_console) { + if (mode == 2) { + cache_list[idx].map_state = IsViewable; + } + } + + if (cache_list[idx].map_state == IsViewable || macosx_console) { X_UNLOCK; - bs_save(idx); - su_restore(idx); + bs_save(idx, nbatch); + su_restore(idx, nbatch, 0); X_LOCK; + pixels += cache_list[idx].width * cache_list[idx].height; + cache_list[idx].time = dnow(); + cache_list[idx].unmap_cnt++; + Ev_unmap[i] = win; + Ev_rects[nrects].x1 = cache_list[idx].x; + Ev_rects[nrects].y1 = cache_list[idx].y; + Ev_rects[nrects].x2 = cache_list[idx].width; + Ev_rects[nrects].y2 = cache_list[idx].height; + nrects++; + } + cache_list[idx].map_state = IsUnmapped; + + } else if (type == ReparentNotify) { + if (ev.xreparent.parent != rootwin) { + win2 = ev.xreparent.window; + if (win2 != rootwin) { + idx = lookup_win_index(win2); +fprintf(stderr, "----%02d: ReparentNotifyRM 0x%x %3d\n", i, win2, idx); + if (idx >= 0) { + DELETE(idx); + } + xselectinput(win2, 0, 1); + } + } + + } else if (type == DestroyNotify) { + win2 = ev.xdestroywindow.window; + idx = lookup_win_index(win2); +fprintf(stderr, "----%02d: DestroyNotify 0x%x %3d\n", i, win2, idx); + + if (idx >= 0) { + DELETE(idx); } - } else { - /* skip rest */ -fprintf(stderr, "----- skip %s\n", Etype(type)); } + } } -//fprintf(stderr, "pending2: %d\n", XPending(dpy)); X_UNLOCK; -if (dnow() - now > 0.05) fprintf(stderr, "check_ncache OUT: %f\n", dnow() - now); + + if (use_batch && nreg) { + int k; + batch_copyregion(batch_reg, batch_dxs, batch_dys, nreg, -1.0); + for (k=0; k < nreg; k++) { + sraRgnDestroy(batch_reg[k]); + } + } + if (nrects) { + if (scaling) { + push_borders(Ev_rects, nrects); + } + } + +rfbLog("OUT check_ncache(): %.6f events: %d pixels: %d\n", dnow() - now, n, pixels); + return pixels; } #endif - -- cgit v1.2.3