summaryrefslogtreecommitdiffstats
path: root/x11vnc/screen.c
diff options
context:
space:
mode:
Diffstat (limited to 'x11vnc/screen.c')
-rw-r--r--x11vnc/screen.c367
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) {