diff options
Diffstat (limited to 'x11vnc/screen.c')
-rw-r--r-- | x11vnc/screen.c | 367 |
1 files changed, 305 insertions, 62 deletions
diff --git a/x11vnc/screen.c b/x11vnc/screen.c index 66dd3f5..b34a941 100644 --- a/x11vnc/screen.c +++ b/x11vnc/screen.c @@ -125,6 +125,7 @@ void set_greyscale_colormap(void) { if (! screen) { return; } + /* mutex */ if (screen->colourMap.data.shorts) { free(screen->colourMap.data.shorts); screen->colourMap.data.shorts = NULL; @@ -154,6 +155,7 @@ void set_hi240_colormap(void) { if (! screen) { return; } + /* mutex */ if (0) fprintf(stderr, "set_hi240_colormap: %s\n", raw_fb_pixfmt); if (screen->colourMap.data.shorts) { free(screen->colourMap.data.shorts); @@ -211,6 +213,7 @@ void set_colormap(int reset) { if (reset) { init = 1; ncolor = 0; + /* mutex */ if (screen->colourMap.data.shorts) { free(screen->colourMap.data.shorts); screen->colourMap.data.shorts = NULL; @@ -233,6 +236,7 @@ void set_colormap(int reset) { } else { ncolor = NCOLOR; } + /* mutex */ screen->colourMap.count = ncolor; screen->serverFormat.trueColour = FALSE; screen->colourMap.is16 = TRUE; @@ -777,6 +781,7 @@ static void nofb_hook(rfbClientPtr cl) { } main_fb = fb->data; rfb_fb = main_fb; + /* mutex */ screen->frameBuffer = rfb_fb; screen->displayHook = NULL; } @@ -813,13 +818,214 @@ void free_old_fb(void) { } } +static char _lcs_tmp[128]; +static int _bytes0_size = 128, _bytes0[128]; + +static char *lcs(rfbClientPtr cl) { + sprintf(_lcs_tmp, "%d/%d/%d/%d/%d-%d/%d/%d", + !!(cl->newFBSizePending), + !!(cl->cursorWasChanged), + !!(cl->cursorWasMoved), + !!(cl->reverseConnection), + cl->state, + cl->modifiedRegion ? !!(sraRgnEmpty(cl->modifiedRegion)) : 2, + cl->requestedRegion ? !!(sraRgnEmpty(cl->requestedRegion)) : 2, + cl->copyRegion ? !!(sraRgnEmpty(cl->copyRegion)) : 2 + ); + return _lcs_tmp; +} + +static int lock_client_sends(int lock) { + static rfbClientPtr *cls = NULL; + static int cls_len = 0; + static int blocked = 0; + static int state = 0; + rfbClientIteratorPtr iter; + rfbClientPtr cl; + char *s; + + if (!use_threads || !screen) { + return 0; + } + if (lock < 0) { + return state; + } + state = lock; + + if (lock) { + if (cls_len < client_count + 128) { + if (cls != NULL) { + free(cls); + } + cls_len = client_count + 256; + cls = (rfbClientPtr *) calloc(cls_len * sizeof(rfbClientPtr), 1); + } + + iter = rfbGetClientIterator(screen); + blocked = 0; + while ((cl = rfbClientIteratorNext(iter)) != NULL) { + s = lcs(cl); + SEND_LOCK(cl); + rfbLog("locked client: %p %.6f %s\n", cl, dnowx(), s); + cls[blocked++] = cl; + } + rfbReleaseClientIterator(iter); + } else { + int i; + for (i=0; i < blocked; i++) { + cl = cls[i]; + if (cl != NULL) { + s = lcs(cl); + SEND_UNLOCK(cl) + rfbLog("unlocked client: %p %.6f %s\n", cl, dnowx(), s); + } + cls[i] = NULL; + } + blocked = 0; + } + return state; +} + +static void settle_clients(int init) { + rfbClientIteratorPtr iter; + rfbClientPtr cl; + int fb_pend, i, ms = 1000; + char *s; + + if (!use_threads || !screen) { + return; + } + + if (init) { + iter = rfbGetClientIterator(screen); + i = 0; + while ((cl = rfbClientIteratorNext(iter)) != NULL) { + if (i < _bytes0_size) { + _bytes0[i] = rfbStatGetSentBytesIfRaw(cl); + } + i++; + } + rfbReleaseClientIterator(iter); + + if (getenv("X11VNC_THREADS_NEW_FB_SLEEP")) { + ms = atoi(getenv("X11VNC_THREADS_NEW_FB_SLEEP")); + } else if (subwin) { + ms = 250; + } else { + ms = 500; + } + usleep(ms * 1000); + return; + } + + if (getenv("X11VNC_THREADS_NEW_FB_SLEEP")) { + ms = atoi(getenv("X11VNC_THREADS_NEW_FB_SLEEP")); + } else if (subwin) { + ms = 500; + } else { + ms = 1000; + } + usleep(ms * 1000); + + for (i=0; i < 5; i++) { + fb_pend = 0; + iter = rfbGetClientIterator(screen); + while ((cl = rfbClientIteratorNext(iter)) != NULL) { + s = lcs(cl); + if (cl->newFBSizePending) { + fb_pend++; + rfbLog("pending fb size: %p %.6f %s\n", cl, dnowx(), s); + } + } + rfbReleaseClientIterator(iter); + if (fb_pend > 0) { + rfbLog("do_new_fb: newFBSizePending extra -threads sleep (%d)\n", i+1); + usleep(ms * 1000); + } else { + break; + } + } + for (i=0; i < 5; i++) { + int stuck = 0, tot = 0, j = 0; + iter = rfbGetClientIterator(screen); + while ((cl = rfbClientIteratorNext(iter)) != NULL) { + if (j < _bytes0_size) { + int db = rfbStatGetSentBytesIfRaw(cl) - _bytes0[j]; + int Bpp = cl->format.bitsPerPixel / 8; + + s = lcs(cl); + rfbLog("addl bytes sent: %p %.6f %s %d %d\n", + cl, dnowx(), s, db, _bytes0[j]); + + if (i==0) { + if (db < Bpp * dpy_x * dpy_y) { + stuck++; + } + } else if (i==1) { + if (db < 0.5 * Bpp * dpy_x * dpy_y) { + stuck++; + } + } else { + if (db <= 0) { + stuck++; + } + } + } + tot++; + j++; + } + rfbReleaseClientIterator(iter); + if (stuck > 0) { + rfbLog("clients stuck: %d/%d sleep(%d)\n", stuck, tot, i); + usleep(2 * ms * 1000); + } else { + break; + } + } +} + +static void prep_clients_for_new_fb(void) { + rfbClientIteratorPtr iter; + rfbClientPtr cl; + + if (!use_threads || !screen) { + return; + } + iter = rfbGetClientIterator(screen); + while ((cl = rfbClientIteratorNext(iter)) != NULL) { + if (!cl->newFBSizePending) { + rfbLog("** set_new_fb_size_pending client: %p\n", cl); + cl->newFBSizePending = TRUE; + } + cl->cursorWasChanged = FALSE; + cl->cursorWasMoved = FALSE; + } + rfbReleaseClientIterator(iter); +} + void do_new_fb(int reset_mem) { XImage *fb; /* for threaded we really should lock libvncserver out. */ if (use_threads) { - rfbLog("warning: changing framebuffers while threaded may\n"); - rfbLog(" not work, do not use -threads if problems arise.\n"); + int ms = 1000; + if (getenv("X11VNC_THREADS_NEW_FB_SLEEP")) { + ms = atoi(getenv("X11VNC_THREADS_NEW_FB_SLEEP")); + } else if (subwin) { + ms = 500; + } else { + ms = 1000; + } + rfbLog("Warning: changing framebuffers in threaded mode may be unstable.\n"); + threads_drop_input = 1; + usleep(ms * 1000); + } + + INPUT_LOCK; + lock_client_sends(1); + + if (use_threads) { + settle_clients(1); } if (reset_mem == 1) { @@ -842,6 +1048,16 @@ void do_new_fb(int reset_mem) { if (ncache) { check_ncache(1, 0); } + + prep_clients_for_new_fb(); + lock_client_sends(0); + INPUT_UNLOCK; + + if (use_threads) { + /* need to let things settle... */ + settle_clients(0); + threads_drop_input = 0; + } } static void remove_fake_fb(void) { @@ -859,51 +1075,6 @@ static void remove_fake_fb(void) { fake_fb = NULL; } -static void lock_client_sends(int lock) { - static rfbClientPtr *cls = NULL; - static int cls_len = 0; - static int blocked = 0; - rfbClientIteratorPtr iter; - rfbClientPtr cl; - - if (!use_threads) { - return; - } - if (!screen) { - return; - } - - if (lock) { - if (cls_len < client_count + 128) { - if (cls != NULL) { - free(cls); - } - cls_len = client_count + 128; - cls = (rfbClientPtr *) calloc(cls_len * sizeof(rfbClientPtr), 1); - } - - iter = rfbGetClientIterator(screen); - blocked = 0; - while ((cl = rfbClientIteratorNext(iter)) != NULL) { - SEND_LOCK(cl); -rfbLog("locked client: %p\n", cl); - cls[blocked++] = cl; - } - rfbReleaseClientIterator(iter); - } else { - int i; - for (i=0; i < blocked; i++) { - cl = cls[i]; - if (cl != NULL) { - SEND_UNLOCK(cl) -rfbLog("unlocked client: %p\n", cl); - } - cls[i] = NULL; - } - blocked = 0; - } -} - static void rfb_new_framebuffer(rfbScreenInfoPtr rfbScreen, char *framebuffer, int width,int height, int bitsPerSample,int samplesPerPixel, int bytesPerPixel) { @@ -918,12 +1089,14 @@ static void install_fake_fb(int w, int h, int bpp) { if (! screen) { return; } + lock_client_sends(1); if (fake_fb) { free(fake_fb); } fake_fb = (char *) calloc(w*h*bpp/8, 1); if (! fake_fb) { rfbLog("could not create fake fb: %dx%d %d\n", w, h, bpp); + lock_client_sends(0); return; } bpc = guess_bits_per_color(bpp); @@ -931,7 +1104,6 @@ static void install_fake_fb(int w, int h, int bpp) { rfbLog("rfbNewFramebuffer(0x%x, 0x%x, %d, %d, %d, %d, %d)\n", screen, fake_fb, w, h, bpc, 1, bpp/8); - lock_client_sends(1); rfb_new_framebuffer(screen, fake_fb, w, h, bpc, 1, bpp/8); lock_client_sends(0); } @@ -2275,6 +2447,8 @@ if (0) fprintf(stderr, "vis_str %s\n", vis_str ? vis_str : "notset"); /* set up parameters for subwin or non-subwin cases: */ + again: + if (! subwin) { /* full screen */ window = rootwin; @@ -2368,7 +2542,6 @@ if (0) fprintf(stderr, "DefaultDepth: %d visial_id: %d\n", depth, (int) visual_ (int) XVisualIDFromVisual(default_visual)); } - again: if (subwin) { int shift = 0, resize = 0; int subwin_x, subwin_y; @@ -2435,7 +2608,9 @@ if (0) fprintf(stderr, "DefaultDepth: %d visial_id: %d\n", depth, (int) visual_ */ fb = XCreateImage_wr(dpy, default_visual, depth, ZPixmap, 0, NULL, dpy_x, dpy_y, BitmapPad(dpy), 0); - fb->data = (char *) malloc(fb->bytes_per_line * fb->height); + if (fb) { + fb->data = (char *) malloc(fb->bytes_per_line * fb->height); + } } else { fb = XGetImage_wr(dpy, window, 0, 0, dpy_x, dpy_y, AllPlanes, @@ -2448,7 +2623,7 @@ if (0) fprintf(stderr, "DefaultDepth: %d visial_id: %d\n", depth, (int) visual_ if (subwin) { XSetErrorHandler(old_handler); - if (trapped_xerror) { + if (trapped_xerror || fb == NULL) { rfbLog("trapped GetImage at SUBWIN creation.\n"); if (try < subwin_tries) { usleep(250 * 1000); @@ -2464,10 +2639,51 @@ if (0) fprintf(stderr, "DefaultDepth: %d visial_id: %d\n", depth, (int) visual_ } trapped_xerror = 0; - } else if (! fb && try == 1) { - /* try once more */ - usleep(250 * 1000); - goto again; + } else if (fb == NULL) { + XEvent xev; + rfbLog("initialize_xdisplay_fb: *** fb creation failed: 0x%x try: %d\n", fb, try); +#if LIBVNCSERVER_HAVE_LIBXRANDR + if (xrandr_present && xrandr_base_event_type) { + int cnt = 0; + while (XCheckTypedEvent(dpy, xrandr_base_event_type + RRScreenChangeNotify, &xev)) { + XRRScreenChangeNotifyEvent *rev; + rev = (XRRScreenChangeNotifyEvent *) &xev; + + rfbLog("initialize_xdisplay_fb: XRANDR event while redoing fb[%d]:\n", cnt++); + rfbLog(" serial: %d\n", (int) rev->serial); + rfbLog(" timestamp: %d\n", (int) rev->timestamp); + rfbLog(" cfg_timestamp: %d\n", (int) rev->config_timestamp); + rfbLog(" size_id: %d\n", (int) rev->size_index); + rfbLog(" sub_pixel: %d\n", (int) rev->subpixel_order); + rfbLog(" rotation: %d\n", (int) rev->rotation); + rfbLog(" width: %d\n", (int) rev->width); + rfbLog(" height: %d\n", (int) rev->height); + rfbLog(" mwidth: %d mm\n", (int) rev->mwidth); + rfbLog(" mheight: %d mm\n", (int) rev->mheight); + rfbLog("\n"); + rfbLog("previous WxH: %dx%d\n", wdpy_x, wdpy_y); + + xrandr_width = rev->width; + xrandr_height = rev->height; + xrandr_timestamp = rev->timestamp; + xrandr_cfg_time = rev->config_timestamp; + xrandr_rotation = (int) rev->rotation; + + rfbLog("initialize_xdisplay_fb: updating XRANDR config...\n"); + XRRUpdateConfiguration(&xev); + } + } +#endif + if (try < 5) { + XFlush_wr(dpy); + usleep(250 * 1000); + if (try < 3) { + XSync(dpy, False); + } else if (try >= 3) { + XSync(dpy, True); + } + goto again; + } } if (use_snapfb) { initialize_snap_fb(); @@ -2734,9 +2950,11 @@ static rfbBool set_xlate_wrapper(rfbClientPtr cl) { } else if (ncache) { int save = ncache_xrootpmap; rfbLog("set_xlate_wrapper: clearing -ncache for new pixel format.\n"); + INPUT_LOCK; ncache_xrootpmap = 0; check_ncache(1, 0); ncache_xrootpmap = save; + INPUT_UNLOCK; } return rfbSetTranslateFunction(cl); } @@ -2751,7 +2969,8 @@ void initialize_screen(int *argc, char **argv, XImage *fb) { int create_screen = screen ? 0 : 1; int bits_per_color; int fb_bpp, fb_Bpl, fb_depth; - + int locked_sends = 0; + bpp = fb->bits_per_pixel; fb_bpp = (int) fb->bits_per_pixel; @@ -2860,7 +3079,10 @@ void initialize_screen(int *argc, char **argv, XImage *fb) { */ bits_per_color = guess_bits_per_color(fb_bpp); - lock_client_sends(1); + if (lock_client_sends(-1) == 0) { + lock_client_sends(1); + locked_sends = 1; + } /* n.b. samplesPerPixel (set = 1 here) seems to be unused. */ if (create_screen) { @@ -3274,7 +3496,6 @@ void initialize_screen(int *argc, char **argv, XImage *fb) { /* may need, bpp, main_red_max, etc. */ parse_wireframe(); parse_scroll_copyrect(); - setup_cursors_and_push(); if (scaling || rotating || cmap8to24) { @@ -3297,10 +3518,13 @@ void initialize_screen(int *argc, char **argv, XImage *fb) { } rfbReleaseClientIterator(iter); if (!quiet) rfbLog(" done.\n"); - do_copy_screen = 1; /* done for framebuffer change case */ - lock_client_sends(0); + if (locked_sends) { + lock_client_sends(0); + } + + do_copy_screen = 1; return; } @@ -3376,7 +3600,10 @@ void initialize_screen(int *argc, char **argv, XImage *fb) { install_passwds(); - lock_client_sends(0); + if (locked_sends) { + lock_client_sends(0); + } + return; } #define DO_AVAHI \ @@ -3981,6 +4208,7 @@ void watch_loop(void) { while (1) { char msg[] = "new client: %s taking unixpw client off hold.\n"; + int skip_scan_for_updates = 0; got_user_input = 0; got_pointer_input = 0; @@ -4187,8 +4415,20 @@ void watch_loop(void) { if (x11vnc_current < last_new_client + 0.5 && !all_clients_initialized()) { continue; } + if (subwin && freeze_when_obscured) { + /* XXX not working */ + X_LOCK; + XFlush_wr(dpy); + X_UNLOCK; + check_xevents(0); + if (subwin_obscured) { + skip_scan_for_updates = 1; + } + } - if (button_mask && (!show_dragging || pointer_mode == 0)) { + if (skip_scan_for_updates) { + ; + } else if (button_mask && (!show_dragging || pointer_mode == 0)) { /* * if any button is pressed in this mode do * not update rfb screen, but do flush the @@ -4216,6 +4456,7 @@ void watch_loop(void) { if (rawfb_vnc_reflect) { vnc_reflect_process_client(); } + dtime0(&tm); #if !NO_X11 @@ -4235,7 +4476,9 @@ void watch_loop(void) { } X_UNLOCK; } + X_LOCK; check_xrandr_event("before-scan"); + X_UNLOCK; } #endif if (use_snapfb) { |