Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 18 additions & 2 deletions include/rfb/rfb.h
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ typedef struct _rfbScreenInfo
rfbBool neverShared;
rfbBool dontDisconnect;
struct _rfbClientRec* clientHead;
struct _rfbClientRec* pointerClient; /**< "Mutex" for pointer events */
struct _rfbClientRec* pointerClient; /**< "Mutex" for pointer drag events */


/* cursor */
Expand Down Expand Up @@ -372,6 +372,20 @@ typedef struct _rfbScreenInfo
#ifdef LIBVNCSERVER_HAVE_LIBZ
rfbSetXCutTextUTF8ProcPtr setXCutTextUTF8;
#endif

/** how many clients have requested to show the cursor in the framebuffer */
int showCursorRefCount;
/** where the cursor is shown */
int underCursorBufferX, underCursorBufferY;
RWLOCK(showCursorRWLock);

/* The client that last moved the pointer
Other clients will automatically receive cursor updates via the traditional
mechanism of drawing the cursor into the framebuffer (AKA "server-side
cursor rendering") so they can track the pointer's movement regardless of
whether cursor shape updates (AKA "client-side cursor rendering") are
enabled. */
struct _rfbClientRec* pointerOwner;
} rfbScreenInfo, *rfbScreenInfoPtr;


Expand Down Expand Up @@ -716,7 +730,9 @@ typedef struct _rfbClientRec {

#define FB_UPDATE_PENDING(cl) \
(((cl)->enableCursorShapeUpdates && (cl)->cursorWasChanged) || \
(((cl)->enableCursorShapeUpdates == FALSE && \
(( \
((cl)->enableCursorShapeUpdates == FALSE || \
(cl)->screen->pointerOwner != (cl)) && \
((cl)->cursorX != (cl)->screen->cursorX || \
(cl)->cursorY != (cl)->screen->cursorY))) || \
((cl)->useNewFBSize && (cl)->newFBSizePending) || \
Expand Down
28 changes: 28 additions & 0 deletions include/rfb/threading.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@
#if 0 /* debugging */
#define LOCK(mutex) (rfbLog("%s:%d LOCK(%s,0x%x)\n",__FILE__,__LINE__,#mutex,&(mutex)), pthread_mutex_lock(&(mutex)))
#define UNLOCK(mutex) (rfbLog("%s:%d UNLOCK(%s,0x%x)\n",__FILE__,__LINE__,#mutex,&(mutex)), pthread_mutex_unlock(&(mutex)))
#define RDLOCK(rwlock) (rfbLog("%s:%d RDLOCK(%s,0x%x)\n",__FILE__,__LINE__,#rwlock,&(rwlock)), pthread_rwlock_rdlock(&(rwlock)))
#define WRLOCK(rwlock) (rfbLog("%s:%d WRLOCK(%s,0x%x)\n",__FILE__,__LINE__,#rwlock,&(rwlock)), pthread_rwlock_wrlock(&(rwlock)))
#define RWUNLOCK(rwlock) (rfbLog("%s:%d RWUNLOCK(%s,0x%x)\n",__FILE__,__LINE__,#rwlock,&(rwlock)), pthread_rwlock_unlock(&(rwlock)))
#define MUTEX(mutex) pthread_mutex_t (mutex)
#define INIT_MUTEX(mutex) (rfbLog("%s:%d INIT_MUTEX(%s,0x%x)\n",__FILE__,__LINE__,#mutex,&(mutex)), pthread_mutex_init(&(mutex),NULL))
#define TINI_MUTEX(mutex) (rfbLog("%s:%d TINI_MUTEX(%s)\n",__FILE__,__LINE__,#mutex), pthread_mutex_destroy(&(mutex)))
Expand All @@ -37,11 +40,22 @@
#define COND(cond) pthread_cond_t (cond)
#define INIT_COND(cond) (rfbLog("%s:%d INIT_COND(%s)\n",__FILE__,__LINE__,#cond), pthread_cond_init(&(cond),NULL))
#define TINI_COND(cond) (rfbLog("%s:%d TINI_COND(%s)\n",__FILE__,__LINE__,#cond), pthread_cond_destroy(&(cond)))
#define RWLOCK(rwlock) pthread_rwlock_t (rwlock)
#define INIT_RWLOCK(rwlock) (rfbLog("%s:%d INIT_RWLOCK(%s)\n",__FILE__,__LINE__,#rwlock), pthread_rwlock_init(&(rwlock),NULL))
#define TINI_RWLOCK(rwlock) (rfbLog("%s:%d TINI_RWLOCK(%s)\n",__FILE__,__LINE__,#rwlock), pthread_rwlock_destroy(&(rwlock)))
#define IF_PTHREADS(x) x
#define THREAD_ROUTINE_RETURN_TYPE void*
#define THREAD_ROUTINE_RETURN_VALUE NULL
#define THREAD_SLEEP_MS(ms) usleep(ms*1000)
#define THREAD_JOIN(thread) pthread_join(thread, NULL)
#define CURRENT_THREAD_ID pthread_self()
#else
#if !NONETWORK
#define LOCK(mutex) pthread_mutex_lock(&(mutex))
#define UNLOCK(mutex) pthread_mutex_unlock(&(mutex))
#define RDLOCK(rwlock) pthread_rwlock_rdlock(&(rwlock))
#define WRLOCK(rwlock) pthread_rwlock_wrlock(&(rwlock))
#define RWUNLOCK(rwlock) pthread_rwlock_unlock(&(rwlock))
#endif
#define MUTEX(mutex) pthread_mutex_t (mutex)
#define MUTEX_SIZE (sizeof(pthread_mutex_t))
Expand All @@ -52,6 +66,9 @@
#define COND(cond) pthread_cond_t (cond)
#define INIT_COND(cond) pthread_cond_init(&(cond),NULL)
#define TINI_COND(cond) pthread_cond_destroy(&(cond))
#define RWLOCK(rwlock) pthread_rwlock_t (rwlock)
#define INIT_RWLOCK(rwlock) pthread_rwlock_init(&(rwlock),NULL)
#define TINI_RWLOCK(rwlock) pthread_rwlock_destroy(&(rwlock))
#define IF_PTHREADS(x) x
#define THREAD_ROUTINE_RETURN_TYPE void*
#define THREAD_ROUTINE_RETURN_VALUE NULL
Expand All @@ -63,6 +80,9 @@
#include <process.h>
#define LOCK(mutex) EnterCriticalSection(&(mutex))
#define UNLOCK(mutex) LeaveCriticalSection(&(mutex))
#define RDLOCK(rwlock) LOCK((rwlock))
#define WRLOCK(rwlock) LOCK((rwlock))
#define RWUNLOCK(rwlock) UNLOCK((rwlock))
#define MUTEX(mutex) CRITICAL_SECTION (mutex)
#define MUTEX_SIZE (sizeof(CRITICAL_SECTION))
#define INIT_MUTEX(mutex) InitializeCriticalSection(&(mutex))
Expand All @@ -72,6 +92,9 @@
#define COND(cond) CONDITION_VARIABLE (cond)
#define INIT_COND(cond) InitializeConditionVariable(&(cond));
#define TINI_COND(cond)
#define RWLOCK(rwlock) MUTEX((rwlock))
#define INIT_RWLOCK(rwlock) INIT_MUTEX((rwlock))
#define TINI_RWLOCK(rwlock) TINI_MUTEX((rwlock))
#define IF_PTHREADS(x)
#define THREAD_ROUTINE_RETURN_TYPE void
#define THREAD_ROUTINE_RETURN_VALUE
Expand All @@ -81,6 +104,8 @@
#else
#define LOCK(mutex)
#define UNLOCK(mutex)
#define WRLOCK(rwlock)
#define RWUNLOCK(rwlock)
#define MUTEX(mutex)
#define INIT_MUTEX(mutex)
#define TINI_MUTEX(mutex)
Expand All @@ -89,6 +114,9 @@
#define COND(cond)
#define INIT_COND(cond)
#define TINI_COND(cond)
#define RWLOCK(rwlock)
#define INIT_RWLOCK(rwlock)
#define TINI_RWLOCK(rwlock)
#define IF_PTHREADS(x)
#endif

Expand Down
36 changes: 26 additions & 10 deletions src/libvncserver/cursor.c
Original file line number Diff line number Diff line change
Expand Up @@ -500,29 +500,32 @@ void rfbMakeRichCursorFromXCursor(rfbScreenInfoPtr rfbScreen,rfbCursorPtr cursor

/* functions to draw/hide cursor directly in the frame buffer */

void rfbHideCursor(rfbClientPtr cl)
void rfbHideCursor(rfbScreenInfoPtr s)
{
rfbScreenInfoPtr s=cl->screen;
rfbCursorPtr c;
int j,x1,x2,y1,y2,bpp=s->serverFormat.bitsPerPixel/8,
rowstride=s->paddedWidthInBytes;
LOCK(s->cursorMutex);
if(--s->showCursorRefCount != 0) {
UNLOCK(s->cursorMutex);
return;
}
c=s->cursor;
if(!c) {
UNLOCK(s->cursorMutex);
return;
}

/* restore what is under the cursor */
x1=cl->cursorX-c->xhot;
x1=s->underCursorBufferX-c->xhot;
x2=x1+c->width;
if(x1<0) x1=0;
if(x2>=s->width) x2=s->width-1;
x2-=x1; if(x2<=0) {
UNLOCK(s->cursorMutex);
return;
}
y1=cl->cursorY-c->yhot;
y1=s->underCursorBufferY-c->yhot;
y2=y1+c->height;
if(y1<0) y1=0;
if(y2>=s->height) y2=s->height-1;
Expand All @@ -543,16 +546,19 @@ void rfbHideCursor(rfbClientPtr cl)
UNLOCK(s->cursorMutex);
}

void rfbShowCursor(rfbClientPtr cl)
void rfbShowCursor(rfbScreenInfoPtr s)
{
rfbScreenInfoPtr s=cl->screen;
rfbCursorPtr c;
int i,j,x1,x2,y1,y2,i1,j1,bpp=s->serverFormat.bitsPerPixel/8,
rowstride=s->paddedWidthInBytes,
bufSize,w;
rfbBool wasChanged=FALSE;

LOCK(s->cursorMutex);
if(++s->showCursorRefCount != 1) {
UNLOCK(s->cursorMutex);
return;
}
c=s->cursor;
if(!c) {
UNLOCK(s->cursorMutex);
Expand All @@ -570,7 +576,7 @@ void rfbShowCursor(rfbClientPtr cl)

/* save what is under the cursor */
i1=j1=0; /* offset in cursor */
x1=cl->cursorX-c->xhot;
x1=s->cursorX-c->xhot;
x2=x1+c->width;
if(x1<0) { i1=-x1; x1=0; }
if(x2>=s->width) x2=s->width-1;
Expand All @@ -579,7 +585,7 @@ void rfbShowCursor(rfbClientPtr cl)
return; /* nothing to do */
}

y1=cl->cursorY-c->yhot;
y1=s->cursorY-c->yhot;
y2=y1+c->height;
if(y1<0) { j1=-y1; y1=0; }
if(y2>=s->height) y2=s->height-1;
Expand Down Expand Up @@ -704,6 +710,10 @@ void rfbShowCursor(rfbClientPtr cl)
/* Copy to all scaled versions */
rfbScaledScreenUpdate(s, x1, y1, x1+x2, y1+y2);

/* Memorize the coords where the cursor was drawn */
s->underCursorBufferX = s->cursorX;
s->underCursorBufferY = s->cursorY;

UNLOCK(s->cursorMutex);
}

Expand Down Expand Up @@ -764,12 +774,14 @@ void rfbSetCursor(rfbScreenInfoPtr rfbScreen,rfbCursorPtr c)
rfbClientIteratorPtr iterator;
rfbClientPtr cl;

/* wait until the cursor is not shown in the framebuffer */
WRLOCK(rfbScreen->showCursorRWLock);
LOCK(rfbScreen->cursorMutex);

if(rfbScreen->cursor) {
iterator=rfbGetClientIterator(rfbScreen);
while((cl=rfbClientIteratorNext(iterator)))
if(!cl->enableCursorShapeUpdates)
if(!cl->enableCursorShapeUpdates || (cl->screen->pointerOwner && cl->screen->pointerOwner != cl))
rfbRedrawAfterHideCursor(cl,NULL);
rfbReleaseClientIterator(iterator);

Expand All @@ -782,11 +794,15 @@ void rfbSetCursor(rfbScreenInfoPtr rfbScreen,rfbCursorPtr c)
iterator=rfbGetClientIterator(rfbScreen);
while((cl=rfbClientIteratorNext(iterator))) {
cl->cursorWasChanged = TRUE;
if(!cl->enableCursorShapeUpdates)
if(!cl->enableCursorShapeUpdates || (cl->screen->pointerOwner && cl->screen->pointerOwner != cl))
rfbRedrawAfterHideCursor(cl,NULL);
LOCK(cl->updateMutex);
TSIGNAL(cl->updateCond);
UNLOCK(cl->updateMutex);
}
rfbReleaseClientIterator(iterator);

UNLOCK(rfbScreen->cursorMutex);
RWUNLOCK(rfbScreen->showCursorRWLock);
}

28 changes: 26 additions & 2 deletions src/libvncserver/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -732,11 +732,26 @@ rfbDefaultPtrAddEvent(int buttonMask, int x, int y, rfbClientPtr cl)
if (cl->enableCursorPosUpdates)
cl->cursorWasMoved = FALSE;

/* Will become the pointer owner, need to hide the server-side cursor. */
if (!cl->screen->pointerOwner) {
rfbRedrawAfterHideCursor(cl, NULL);
LOCK(cl->updateMutex);
TSIGNAL(cl->updateCond);
UNLOCK(cl->updateMutex);
}

/* But inform all remaining clients about this cursor movement. */
iterator = rfbGetClientIterator(s);
while ((other_client = rfbClientIteratorNext(iterator)) != NULL) {
if (other_client != cl && other_client->enableCursorPosUpdates) {
other_client->cursorWasMoved = TRUE;
if (other_client != cl) {
if (other_client->enableCursorPosUpdates) {
other_client->cursorWasMoved = TRUE;
}
if (other_client != cl->screen->pointerOwner) {
LOCK(other_client->updateMutex);
TSIGNAL(other_client->updateCond);
UNLOCK(other_client->updateMutex);
}
}
}
rfbReleaseClientIterator(iterator);
Expand Down Expand Up @@ -996,6 +1011,13 @@ rfbScreenInfoPtr rfbGetScreen(int* argc,char** argv,

screen->permitFileTransfer = FALSE;

screen->showCursorRefCount = 0;
screen->underCursorBufferX = 0;
screen->underCursorBufferY = 0;
INIT_RWLOCK(screen->showCursorRWLock);

screen->pointerOwner = NULL;

if(!rfbProcessArguments(screen,argc,argv)) {
free(screen);
return NULL;
Expand Down Expand Up @@ -1156,6 +1178,8 @@ void rfbScreenCleanup(rfbScreenInfoPtr screen)
cl1=cl;
}
rfbReleaseClientIterator(i);

TINI_RWLOCK(screen->showCursorRWLock);

#define FREE_IF(x) if(screen->x) free(screen->x)
FREE_IF(colourMap.data.bytes);
Expand Down
4 changes: 2 additions & 2 deletions src/libvncserver/private.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@

/* from cursor.c */

void rfbShowCursor(rfbClientPtr cl);
void rfbHideCursor(rfbClientPtr cl);
void rfbShowCursor(rfbScreenInfoPtr s);
void rfbHideCursor(rfbScreenInfoPtr s);
void rfbRedrawAfterHideCursor(rfbClientPtr cl,sraRegionPtr updateRegion);

/* from main.c */
Expand Down
34 changes: 27 additions & 7 deletions src/libvncserver/rfbserver.c
Original file line number Diff line number Diff line change
Expand Up @@ -627,6 +627,9 @@ rfbClientConnectionGone(rfbClientPtr cl)
if (cl->screen->pointerClient == cl)
cl->screen->pointerClient = NULL;

if (cl->screen->pointerOwner == cl)
cl->screen->pointerOwner = NULL;

sraRgnDestroy(cl->modifiedRegion);
sraRgnDestroy(cl->requestedRegion);
sraRgnDestroy(cl->copyRegion);
Expand Down Expand Up @@ -2688,6 +2691,14 @@ rfbProcessClientNormalMessage(rfbClientPtr cl)
cl->screen->pointerClient = cl;

if(!cl->viewOnly) {
/* If the pointer was most recently moved by another client, we set
pointerOwner to NULL here so that the client that is currently
moving the pointer (cl), assuming it understands cursor shape
updates, will receive a cursor shape update with the last known
pointer position. */
if (cl->screen->pointerOwner != cl)
cl->screen->pointerOwner = NULL;

if (msg.pe.buttonMask != cl->lastPtrButtons ||
cl->screen->deferPtrUpdateTime == 0) {
cl->screen->ptrAddEvent(msg.pe.buttonMask,
Expand All @@ -2700,6 +2711,8 @@ rfbProcessClientNormalMessage(rfbClientPtr cl)
cl->lastPtrY = ScaleY(cl->scaledScreen, cl->screen, Swap16IfLE(msg.pe.y));
cl->lastPtrButtons = msg.pe.buttonMask;
}

cl->screen->pointerOwner = cl;
}
return;

Expand Down Expand Up @@ -3158,8 +3171,9 @@ rfbSendFramebufferUpdate(rfbClientPtr cl,
}

/*
* If this client understands cursor shape updates, cursor should be
* removed from the framebuffer. Otherwise, make sure it's put up.
* If this client understands cursor shape updates and owns the pointer or is
* about to own the pointer, then the cursor should be removed from the
* framebuffer. Otherwise, make sure it's drawn.
*/

if (cl->enableCursorShapeUpdates) {
Expand Down Expand Up @@ -3264,7 +3278,7 @@ rfbSendFramebufferUpdate(rfbClientPtr cl,
sraRgnOr(updateRegion,cl->copyRegion);
if(!sraRgnAnd(updateRegion,cl->requestedRegion) &&
sraRgnEmpty(updateRegion) &&
(cl->enableCursorShapeUpdates ||
((cl->enableCursorShapeUpdates && (!cl->screen->pointerOwner || cl->screen->pointerOwner == cl)) ||
(cl->cursorX == cl->screen->cursorX && cl->cursorY == cl->screen->cursorY)) &&
!sendCursorShape && !sendCursorPos && !sendKeyboardLedState &&
!sendSupportedMessages && !sendSupportedEncodings && !sendServerIdentity) {
Expand Down Expand Up @@ -3319,7 +3333,7 @@ rfbSendFramebufferUpdate(rfbClientPtr cl,

UNLOCK(cl->updateMutex);

if (!cl->enableCursorShapeUpdates) {
if (!cl->enableCursorShapeUpdates || (cl->screen->pointerOwner && cl->screen->pointerOwner != cl)) {
if(cl->cursorX != cl->screen->cursorX || cl->cursorY != cl->screen->cursorY) {
rfbRedrawAfterHideCursor(cl,updateRegion);
LOCK(cl->screen->cursorMutex);
Expand All @@ -3328,7 +3342,12 @@ rfbSendFramebufferUpdate(rfbClientPtr cl,
UNLOCK(cl->screen->cursorMutex);
rfbRedrawAfterHideCursor(cl,updateRegion);
}
rfbShowCursor(cl);
/* show the cursor if the cursor is not shown in the framebuffer, increment the refcount */
RDLOCK(cl->screen->showCursorRWLock);
rfbShowCursor(cl->screen);
} else {
/* wait until the cursor is not shown in the framebuffer */
WRLOCK(cl->screen->showCursorRWLock);
}

/*
Expand Down Expand Up @@ -3571,9 +3590,10 @@ rfbSendFramebufferUpdate(rfbClientPtr cl,
result = FALSE;
}

if (!cl->enableCursorShapeUpdates) {
rfbHideCursor(cl);
if (!cl->enableCursorShapeUpdates || (cl->screen->pointerOwner && cl->screen->pointerOwner != cl)) {
rfbHideCursor(cl->screen);
}
RWUNLOCK(cl->screen->showCursorRWLock);

if(i)
sraRgnReleaseIterator(i);
Expand Down