This is an automated email from the git hooks/post-receive script. x2go pushed a change to branch feature/rootless-mode in repository x2gokdrive. at 17ee1ef rootless mode for x2gokdrive This branch includes the following new commits: new 17ee1ef rootless mode for x2gokdrive The 1 revisions listed above as "new" are entirely new to this repository and will be described in separate emails. The revisions listed as "adds" were already present in the repository and have only been added to this reference. -- Alioth's /home/x2go-admin/maintenancescripts/git/hooks/post-receive-email on /srv/git/code.x2go.org/x2gokdrive.git
This is an automated email from the git hooks/post-receive script. x2go pushed a commit to branch feature/rootless-mode in repository x2gokdrive. commit 17ee1efbef7fb44c7d533384dea1900a67b3357a Author: Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> Date: Mon Jan 31 09:05:13 2022 -0600 rootless mode for x2gokdrive --- x2gokdriveinit.c | 5 + x2gokdriveremote.c | 839 ++++++++++++++++++++++++++++++++++++++++++++++++-- x2gokdriveremote.h | 44 ++- x2gokdriveselection.c | 5 +- 4 files changed, 864 insertions(+), 29 deletions(-) diff --git a/x2gokdriveinit.c b/x2gokdriveinit.c index 3468077..7a4bbfa 100644 --- a/x2gokdriveinit.c +++ b/x2gokdriveinit.c @@ -319,6 +319,11 @@ ddxProcessArgument(int argc, char **argv, int i) /* compat with nxagent */ return 1; } + else if (!strcmp(argv[i], "-R")) { + /* start in rootless mode */ + remote_set_rootless(); + return 1; + } else if (argv[i][0] == ':') remote_set_display_name(argv[i]); diff --git a/x2gokdriveremote.c b/x2gokdriveremote.c index e70ec89..e07f553 100644 --- a/x2gokdriveremote.c +++ b/x2gokdriveremote.c @@ -38,6 +38,7 @@ #include "x2gokdriveselection.h" #include "x2gokdrivelog.h" #include <zlib.h> +#include <propertyst.h> #ifdef EPHYR_WANT_DEBUG extern unsigned long long int debug_sendThreadId; @@ -47,7 +48,7 @@ extern unsigned long long int debug_selectThreadId; /* init it in OsInit() */ static struct _remoteHostVars remoteVars = {0}; -struct _remoteHostVars RemoteHostVars; +// struct _remoteHostVars RemoteHostVars; static BOOL remoteInitialized=FALSE; @@ -396,7 +397,7 @@ int32_t send_cursor(struct cursorFrame* cursor) } static -int32_t send_frame(u_int32_t width, uint32_t height, uint32_t x, uint32_t y, uint32_t crc, struct frame_region* regions) +int32_t send_frame(u_int32_t width, uint32_t height, uint32_t x, uint32_t y, uint32_t crc, struct frame_region* regions, uint32_t winId) { unsigned char buffer[64] = {0}; _X_UNUSED int ln = 0; @@ -418,6 +419,15 @@ int32_t send_frame(u_int32_t width, uint32_t height, uint32_t x, uint32_t y, uin *((uint32_t*)buffer+4)=y; *((uint32_t*)buffer+5)=numofregions; *((uint32_t*)buffer+6)=crc; + if(remoteVars.rootless) + { + *((uint32_t*)buffer+7)=winId; + /*if(winId) + { + EPHYR_DBG("Sending frame for Window 0x%X",winId); + }*/ + } + // if(numofregions) // EPHYR_DBG("SENDING NEW FRAME %x", crc); @@ -1369,7 +1379,7 @@ BOOL find_common_regions(struct cache_elem* source, struct cache_elem* dest, BOO /* use only from send thread */ static -void sendMainImageFromSendThread(uint32_t width, uint32_t height, int32_t dx ,int32_t dy) +void sendMainImageFromSendThread(uint32_t width, uint32_t height, int32_t dx ,int32_t dy, uint32_t winId) { _X_UNUSED uint32_t length = 0; struct frame_region regions[9] = {{0}}; @@ -1382,14 +1392,14 @@ void sendMainImageFromSendThread(uint32_t width, uint32_t height, int32_t dx ,in BOOL mainImage=FALSE; - if(width!=0) +/* if(width!=0) { EPHYR_DBG("sending UPDATE- %dx%d, %d,%d",width, height,dx,dy); } else { EPHYR_DBG("sending mainImage"); - } + }*/ pthread_mutex_lock(&remoteVars.mainimg_mutex); @@ -1433,11 +1443,11 @@ void sendMainImageFromSendThread(uint32_t width, uint32_t height, int32_t dx ,in if(mainImage) { - send_frame(width, height,-1,-1,0,regions); + send_frame(width, height,-1,-1,0,regions, winId); } else { - send_frame(width, height,dx,dy,0,regions); + send_frame(width, height,dx,dy,0,regions, winId); } @@ -1445,6 +1455,156 @@ void sendMainImageFromSendThread(uint32_t width, uint32_t height, int32_t dx ,in free(regions[0].compressed_data); } +static +void remote_send_win_updates(char* updateBuf, uint32_t bufSize) +{ + unsigned char buffer[56] = {0}; + int l = 0; + int sent = 0; + + *((uint32_t*)buffer)=WINUPDATE; + *((uint32_t*)buffer+1)=bufSize; + + write(remoteVars.clientsock,buffer,56); + + while(sent<bufSize) + { + l=write(remoteVars.clientsock,updateBuf+sent,((bufSize-sent)<MAXMSGSIZE)?(bufSize-sent):MAXMSGSIZE); + if(l<0) + { + EPHYR_DBG("Error sending windows update!!!!!"); + break; + } + sent+=l; + } +// EPHYR_DBG("SENT WIN UPDATES %d",bufSize); + free(updateBuf); +} + + +void remote_process_window_updates(void) +{ + /*sendqueue mutex is locked here*/ + struct remoteWindow* prev=NULL; + struct remoteWindow* rwin=remoteVars.windowList; + struct remoteWindow* tmp; + int bufSize=0; + int bufHead=0; + char* updateBuf=NULL; + int8_t state; + int16_t nameSize; + //calculate size of update buffer + while(rwin) + { + if((rwin->state == CHANGED)||(rwin->state == NEW)) + { + bufSize+=WINUPDSIZE; + if(rwin->name) + { + bufSize+=strlen(rwin->name); + } + } + if(rwin->state==WDEL) + { + bufSize+=WINUPDDELSIZE; + } + rwin=rwin->next; + } + //copy update data to buffer + updateBuf=malloc(bufSize); + rwin=remoteVars.windowList; + while(rwin) + { + if(rwin->state != UNCHANGED) + { + memcpy(updateBuf+bufHead, &(rwin->id), sizeof(uint32_t)); + bufHead+=sizeof(uint32_t); + state=rwin->state; + memcpy(updateBuf+bufHead, &state, sizeof(state)); + bufHead+=sizeof(state); + } + if((rwin->state == CHANGED)||(rwin->state==NEW)) + { + memcpy(updateBuf+bufHead, &(rwin->parentId), sizeof(uint32_t)); + bufHead+=sizeof(uint32_t); + + memcpy(updateBuf+bufHead, &(rwin->nextSibId), sizeof(uint32_t)); + bufHead+=sizeof(uint32_t); + + memcpy(updateBuf+bufHead, &(rwin->transWinId), sizeof(uint32_t)); + bufHead+=sizeof(uint32_t); + + memcpy(updateBuf+bufHead, &(rwin->x), sizeof(int16_t)); + bufHead+=sizeof(int16_t); + memcpy(updateBuf+bufHead, &(rwin->y), sizeof(int16_t)); + bufHead+=sizeof(int16_t); + memcpy(updateBuf+bufHead, &(rwin->w), sizeof(uint16_t)); + bufHead+=sizeof(uint16_t); + memcpy(updateBuf+bufHead, &(rwin->h), sizeof(uint16_t)); + bufHead+=sizeof(uint16_t); + memcpy(updateBuf+bufHead, &(rwin->bw), sizeof(uint16_t)); + bufHead+=sizeof(uint16_t); + memcpy(updateBuf+bufHead, &(rwin->visibility), sizeof(int8_t)); + bufHead+=sizeof(int8_t); + memcpy(updateBuf+bufHead, &(rwin->winType), sizeof(int8_t)); + bufHead+=sizeof(int8_t); + nameSize=0; + if(rwin->name) + { + nameSize=strlen(rwin->name); + } + memcpy(updateBuf+bufHead, &nameSize, sizeof(nameSize)); + bufHead+=sizeof(nameSize); + if(nameSize) + { + memcpy(updateBuf+bufHead, rwin->name, nameSize); + bufHead+=nameSize; + } + rwin->state=UNCHANGED; + } + if(rwin->state==WDEL) + { + //remove window from list and free resources + EPHYR_DBG("release window %p, %s",rwin->ptr, rwin->name); + if(rwin==remoteVars.windowList) + { + remoteVars.windowList=rwin->next; + } + if(prev) + { + prev->next=rwin->next; + } + tmp=rwin; + rwin=rwin->next; + if(tmp->name) + { + free(tmp->name); + } + free(tmp); + } + else + { + prev=rwin; + rwin=rwin->next; + } + } + /* + EPHYR_DBG("NEW LIST:"); + rwin=remoteVars.windowList; + while(rwin) + { + EPHYR_DBG("=====%p",rwin->ptr); + rwin=rwin->next; + }*/ + + //send win updates + remoteVars.windowsUpdated=FALSE; + pthread_mutex_unlock(&remoteVars.sendqueue_mutex); + //send_updates + remote_send_win_updates(updateBuf, bufSize); + pthread_mutex_lock(&remoteVars.sendqueue_mutex); +} + static void *send_frame_thread (void *threadid) { @@ -1479,7 +1639,7 @@ void *send_frame_thread (void *threadid) if(!remoteVars.first_sendqueue_element && !remoteVars.firstCursor && !remoteVars.selstruct.firstOutputChunk && - !remoteVars.cache_rebuilt) + !remoteVars.cache_rebuilt && !remoteVars.windowsUpdated) { /* sleep if frame queue is empty */ pthread_cond_wait(&remoteVars.have_sendqueue_cond, &remoteVars.sendqueue_mutex); @@ -1487,6 +1647,13 @@ void *send_frame_thread (void *threadid) /* mutex is locked on this point */ + //if windows list is updated send changes to client + if(remoteVars.windowsUpdated) + { + remote_process_window_updates(); + } + + /*mutex still locked*/ //send notification to client that cache is rebuilt if(remoteVars.cache_rebuilt) { @@ -1570,7 +1737,7 @@ void *send_frame_thread (void *threadid) int elems=queue_elements(); struct cache_elem* frame = NULL; struct sendqueue_element* current = NULL; - uint32_t x, y = 0; + uint32_t x=0, y = 0, winId=0; int32_t width, height = 0; if(remoteVars.maxfr<elems) @@ -1594,6 +1761,7 @@ void *send_frame_thread (void *threadid) y=current->y; width=current->width; height=current->height; + winId=current->winId; free(current); if(frame) @@ -1605,14 +1773,14 @@ void *send_frame_thread (void *threadid) /* unlock sendqueue for main thread */ pthread_mutex_unlock(&remoteVars.sendqueue_mutex); - send_frame(frame_width, frame_height, x, y, crc, frame->regions); + send_frame(frame_width, frame_height, x, y, crc, frame->regions, winId); } else { - EPHYR_DBG("Sending main image or screen update"); +// EPHYR_DBG("Sending main image or screen update"); pthread_mutex_unlock(&remoteVars.sendqueue_mutex); - sendMainImageFromSendThread(width, height, x, y); + sendMainImageFromSendThread(width, height, x, y, winId); } @@ -2283,17 +2451,22 @@ clientReadNotify(int fd, int ready, void *data) int32_t x=*((uint32_t*)buff+3); int32_t y=*((uint32_t*)buff+4); + uint32_t winid=0; + if(remoteVars.rootless) + { + winid=*((uint32_t*)buff+5); + } - EPHYR_DBG("HAVE UPDATE EVENT from client %dx%d %d,%d\n",width, height, x,y ); +// EPHYR_DBG("HAVE UPDATE request from client, window 0x%X %dx%d %d,%d\n",winid, width, height, x,y ); pthread_mutex_lock(&remoteVars.mainimg_mutex); - EPHYR_DBG("DBF: %p, %d, %d",remoteVars.main_img, remoteVars.main_img_width, remoteVars.main_img_height); +// EPHYR_DBG("DBF: %p, %d, %d",remoteVars.main_img, remoteVars.main_img_width, remoteVars.main_img_height); if(remoteVars.main_img && x+width <= remoteVars.main_img_width && y+height <= remoteVars.main_img_height ) { pthread_mutex_unlock(&remoteVars.mainimg_mutex); - add_frame(width, height, x, y, 0, 0); + add_frame(width, height, x, y, 0, 0, winid); } else { @@ -2335,6 +2508,11 @@ clientReadNotify(int fd, int ready, void *data) rebuild_caches(); break; } + case WINCHANGE: + { + client_win_change(buff); + break; + } default: { EPHYR_DBG("UNSUPPORTED EVENT: %d",event_type); @@ -2356,6 +2534,172 @@ clientReadNotify(int fd, int ready, void *data) } +#define SubSend(pWin) \ +((pWin->eventMask|wOtherEventMasks(pWin)) & SubstructureNotifyMask) + +#define StrSend(pWin) \ +((pWin->eventMask|wOtherEventMasks(pWin)) & StructureNotifyMask) + +#define SubStrSend(pWin,pParent) (StrSend(pWin) || SubSend(pParent)) + + +//this function is from dix/window.c +static void +ReflectStackChange(WindowPtr pWin, WindowPtr pSib, VTKind kind) +{ + /* Note that pSib might be NULL */ + Bool WasViewable = (Bool) pWin->viewable; + Bool anyMarked; + WindowPtr pFirstChange; + WindowPtr pLayerWin; + ScreenPtr pScreen = pWin->drawable.pScreen; + /* if this is a root window, can't be restacked */ + if (!pWin->parent) + return; + pFirstChange = MoveWindowInStack(pWin, pSib); + if (WasViewable) { + anyMarked = (*pScreen->MarkOverlappedWindows) (pWin, pFirstChange, + &pLayerWin); + if (pLayerWin != pWin) + pFirstChange = pLayerWin; + if (anyMarked) { + (*pScreen->ValidateTree) (pLayerWin->parent, pFirstChange, kind); + (*pScreen->HandleExposures) (pLayerWin->parent); + if (pWin->drawable.pScreen->PostValidateTree) + (*pScreen->PostValidateTree) (pLayerWin->parent, pFirstChange, + kind); + } + } + if (pWin->realized) + WindowsRestructured(); +} + + + +void client_win_change(char* buff) +{ + WindowPtr pWin, pParent, pSib; + uint32_t winId=*((uint32_t*)(buff+4)); + uint32_t newSibId=*((uint32_t*)(buff+8)); + struct remoteWindow* rw; + int16_t x,y; + uint16_t w,h,bw; + int16_t nx=*((int16_t*)(buff+12)); + int16_t ny=*((int16_t*)(buff+14)); + uint16_t nw=*((int16_t*)(buff+16)); + uint16_t nh=*((int16_t*)(buff+18)); + BOOL move=FALSE, resize=FALSE, restack=FALSE; +// EPHYR_DBG("Client request win change: %p %d:%d %dx%d",fptr, nx,ny,nw,nh); + pWin=remote_find_window_on_screen_by_id(winId, remoteVars.ephyrScreen->pScreen->root); + if(!pWin) + { + EPHYR_DBG("Window with ID 0x%X not found on current screen",winId); + return; + } + + pParent = pWin->parent; + pSib=0; + if(newSibId) + { + pSib=remote_find_window_on_screen_by_id(newSibId, remoteVars.ephyrScreen->pScreen->root); + if(!pSib) + { + EPHYR_DBG("New Sibling with ID 0x%X not found on current screen, Putting bellow all siblings",newSibId); + } + } + w = pWin->drawable.width; + h = pWin->drawable.height; + bw = pWin->borderWidth; + if (pParent) + { + x = pWin->drawable.x - pParent->drawable.x - (int16_t) bw; + y = pWin->drawable.y - pParent->drawable.y - (int16_t) bw; + } + else + { + x = pWin->drawable.x; + y = pWin->drawable.y; + } + if (SubStrSend(pWin, pParent)) + { + xEvent event = { + .u.configureNotify.window = pWin->drawable.id, + .u.configureNotify.aboveSibling = pSib ? pSib->drawable.id : None, + .u.configureNotify.x = x, + .u.configureNotify.y = y, + .u.configureNotify.width = w, + .u.configureNotify.height = h, + .u.configureNotify.borderWidth = bw, + .u.configureNotify.override = pWin->overrideRedirect + }; + event.u.u.type = ConfigureNotify; + #ifdef PANORAMIX + if (!noPanoramiXExtension && (!pParent || !pParent->parent)) { + event.u.configureNotify.x += screenInfo.screens[0]->x; + event.u.configureNotify.y += screenInfo.screens[0]->y; + } + #endif + DeliverEvents(pWin, &event, 1, NullWindow); + } + + pthread_mutex_lock(&remoteVars.sendqueue_mutex); + rw=remote_find_window(pWin); + if(!rw) + { + EPHYR_DBG("Error!!!! window %p not found in list of ext windows",pWin); + pthread_mutex_unlock(&remoteVars.sendqueue_mutex); + return; + } + + if( x!=nx || y!=ny) + { + if(rw) + { + rw->x=nx; + rw->y=ny; + } + move=TRUE; + } + if(w!=nw || h!=nh) + { + if(rw) + { + rw->w=nw; + rw->h=nh; + } + resize=TRUE; + } + if(pWin->nextSib!=pSib) + { + rw->nextSib=pSib; + if(pSib) + { + rw->nextSibId=pSib->drawable.id; + } + else + { + rw->nextSibId=0; + } + restack=TRUE; + } + pthread_mutex_unlock(&remoteVars.sendqueue_mutex); + if(move) + { + // EPHYR_DBG("MOVE from %d:%d to %d:%d",x,y,nx,ny); + (*pWin->drawable.pScreen->MoveWindow) (pWin, nx, ny, pSib,VTMove); + } + if(resize) + { + // EPHYR_DBG("RESIZE from %dx%d to %dx%d",w,h,nw,nh); + (*pWin->drawable.pScreen->ResizeWindow) (pWin, nx, ny, nw, nh, pSib); + } + if(restack) + { + EPHYR_DBG("Client request to move : %p on top of %p",pWin, pSib); + ReflectStackChange(pWin, pSib, VTOther); + } +} + void set_client_version(uint16_t ver, uint16_t os) { remoteVars.client_version=ver; @@ -2777,8 +3121,6 @@ remote_init(void) fclose(stdout); fclose(stdin); - memset(&remoteVars,0,sizeof(RemoteHostVars)); - remoteVars.serversock=-1; remoteVars.jpegQuality=JPG_QUALITY; @@ -3290,7 +3632,7 @@ void initFrameRegions(struct cache_elem* frame) frame->compressed_size=length; } -void add_frame(uint32_t width, uint32_t height, int32_t x, int32_t y, uint32_t crc, uint32_t size) +void add_frame(uint32_t width, uint32_t height, int32_t x, int32_t y, uint32_t crc, uint32_t size, uint32_t winId) { Bool isNewElement = FALSE; struct cache_elem* frame = 0; @@ -3348,6 +3690,7 @@ void add_frame(uint32_t width, uint32_t height, int32_t x, int32_t y, uint32_t c element->y=y; element->width=width; element->height=height; + element->winId=winId; if(remoteVars.last_sendqueue_element) { remoteVars.last_sendqueue_element->next=element; @@ -3366,7 +3709,446 @@ void add_frame(uint32_t width, uint32_t height, int32_t x, int32_t y, uint32_t c void remote_send_main_image(void) { - add_frame(0, 0, 0, 0, 0, 0); + add_frame(0, 0, 0, 0, 0, 0,0); +} + +struct remoteWindow* remote_find_window(WindowPtr win) +{ + struct remoteWindow* rw=remoteVars.windowList; +// EPHYR_DBG("LOOK for %p in list",win); + while(rw) + { + if(rw->ptr==win) + { + return rw; + } + rw=rw->next; + } +// EPHYR_DBG("WINDOW %p not found in list",win); + return NULL; +} + +void remote_check_window(WindowPtr win) +{ + char *name=NULL; + int nameSize=0; + char *netName=NULL; + int netNameSize=0; + char *dispName=NULL; + int dispNameSize=0; + BOOL ignore = TRUE; + struct remoteWindow* rwin; + uint32_t transWinId=0; + uint8_t winType=WINDOW_TYPE_NORMAL; + int16_t x,y; + uint16_t w,h,bw; + WindowPtr parPtr; + WindowPtr nextSibPtr, tmpPtr; + parPtr=win->parent; + nextSibPtr=NULL; + + //if prentwindow is root, set it to 0 + if(parPtr == remoteVars.ephyrScreen->pScreen->root) + { + parPtr=NULL; + } + w = win->drawable.width; + h = win->drawable.height; + bw = win->borderWidth; + if (win->parent) + { + x = win->drawable.x - win->parent->drawable.x - (int) bw; + y = win->drawable.y - win->parent->drawable.y - (int) bw; + } + else + { + x = win->drawable.x; + y = win->drawable.y; + } + +// EPHYR_DBG("Check win %p",win); + if(!win->optional || !win->optional->userProps || !win->mapped) + { + return; + } + //find nextSib + tmpPtr=win->nextSib; + while(tmpPtr) + { + if(remote_find_window(tmpPtr)) + { + nextSibPtr=tmpPtr; + break; + } + tmpPtr=tmpPtr->nextSib; + } + /* + * if window is not in list, create and send to client. If not same, update and send to client + * if some list windows not there anymore, delete and send notification + */ + + if(win->optional && win->optional->userProps) + { + PropertyPtr prop=win->optional->userProps; +// EPHYR_DBG("======%p - PARENT %p = VIS %d === MAP %d =============",win, parPtr, win->visibility, win->mapped); + while(prop) + { + if(prop->propertyName==MakeAtom("WM_NAME", strlen("WM_NAME"),FALSE) && prop->data) + { + name=prop->data; + nameSize=prop->size; + } + if(prop->propertyName==MakeAtom("WM_HINTS", strlen("WM_HINTS"),FALSE) && prop->data) + { + ignore=FALSE; + } + if(prop->propertyName==MakeAtom("_NET_WM_NAME", strlen("_NET_WM_NAME"),FALSE) && prop->data) + { + netName=prop->data; + netNameSize=prop->size; + } + if(prop->propertyName==MakeAtom("WM_TRANSIENT_FOR", strlen("WM_TRANSIENT_FOR"),FALSE) && prop->data) + { + transWinId=((uint32_t*)prop->data)[0]; + EPHYR_DBG("Trans Win 0x%X = 0x%X", transWinId, win->drawable.id); + } +// EPHYR_DBG("%s %s, Format %d, Size %d",NameForAtom(prop->propertyName), NameForAtom(prop->type), prop->format, prop->size); + if( prop->type == MakeAtom("STRING", strlen("STRING"),FALSE) || prop->type == MakeAtom("UTF8_STRING", strlen("UTF8_STRING"),FALSE)) + { +// EPHYR_DBG("-- %s",(char*)prop->data); + } + if( prop->type == MakeAtom("ATOM", strlen("ATOM"),FALSE)) + { + ATOM* at=prop->data; + if(prop->propertyName==MakeAtom("_NET_WM_STATE", strlen("_NET_WM_STATE"),FALSE)) + { + EPHYR_DBG("--WINDOW STATE: %s, my ID 0x%X",NameForAtom( at[0] ), win->drawable.id); + } + // EPHYR_DBG("-- %s",NameForAtom( at[0] )); + if(prop->propertyName==MakeAtom("_NET_WM_WINDOW_TYPE", strlen("_NET_WM_WINDOW_TYPE"),FALSE)) + { + EPHYR_DBG("WINDOW Type: %s, my ID 0x%X",NameForAtom( at[0] ), win->drawable.id); + if(at[0]==MakeAtom("_NET_WM_WINDOW_TYPE_NORMAL", strlen("_NET_WM_WINDOW_TYPE_NORMAL"),FALSE)) + { +// EPHYR_DBG("Normal window"); + winType=WINDOW_TYPE_NORMAL; + } + else if(at[0] ==MakeAtom("_NET_WM_WINDOW_TYPE_DIALOG", strlen("_NET_WM_WINDOW_TYPE_DIALOG"),FALSE)) + { +// EPHYR_DBG("Dialog"); + winType=WINDOW_TYPE_DIALOG; + } + else if(at[0] ==MakeAtom("_NET_WM_WINDOW_TYPE_DROPDOWN_MENU", strlen("_NET_WM_WINDOW_TYPE_DROPDOWN_MENU"),FALSE)) + { +// EPHYR_DBG("Dropdown menu"); + winType=WINDOW_TYPE_DROPDOWN_MENU; + } + else if(at[0] ==MakeAtom("_NET_WM_WINDOW_TYPE_POPUP_MENU", strlen("_NET_WM_WINDOW_TYPE_POPUP_MENU"),FALSE)) + { +// EPHYR_DBG("Popup menu"); + winType=WINDOW_TYPE_POPUP_MENU; + } + else if( at[0] ==MakeAtom("_NET_WM_WINDOW_TYPE_SPLASH", strlen("_NET_WM_WINDOW_TYPE_SPLASH"),FALSE)) + { + // EPHYR_DBG("Splash"); + winType=WINDOW_TYPE_SPLASH; + } + else if( at[0] ==MakeAtom("_NET_WM_WINDOW_TYPE_TOOLTIP", strlen("_NET_WM_WINDOW_TYPE_TOOLTIP"),FALSE)) + { + // EPHYR_DBG("Splash"); + winType=WINDOW_TYPE_TOOLTIP; + } + else if( at[0] ==MakeAtom("_NET_WM_WINDOW_TYPE_COMBO", strlen("_NET_WM_WINDOW_TYPE_COMBO"),FALSE)) + { + // EPHYR_DBG("Splash"); + winType=WINDOW_TYPE_COMBO; + } + } + } + if(prop->propertyName==MakeAtom("WM_NAME", strlen("WM_NAME"),FALSE) && prop->data) + { +// EPHYR_DBG("-- Name: %s",(char*)prop->data); + } + if(prop->propertyName==MakeAtom("WM_WINDOW_ROLE", strlen("WM_WINDOW_ROLE"),FALSE) && prop->data) + { +// EPHYR_DBG("-- Role: %s",(char*)prop->data); + } + if(prop->propertyName==MakeAtom("WM_CLASS", strlen("WM_CLASS"),FALSE) && prop->data) + { +// EPHYR_DBG("-- Class: %s",(char*)prop->data); + } + if(prop->propertyName==MakeAtom("WM_PROTOCOLS", strlen("WM_PROTOCOLS"),FALSE) && prop->data) + { +// ATOM* at=prop->data; +// EPHYR_DBG("-- WM_PROTOCOLS: %s",NameForAtom( at[0] )); + } + prop=prop->next; + } + } + if(ignore) + { +// EPHYR_DBG("=======IGNORE THIS WINDOW=============="); + return; + } + if(netNameSize && netName) + { + dispName=netName; + dispNameSize=netNameSize; + } + else + { + dispName=name; + dispNameSize=nameSize; + } +// EPHYR_DBG("\n\nWIN: %p, %s, PAR: %p, %d:%d %dx%d, border %d, visibility: %d, view %d, map %d ID %d", win, dispName, parPtr, x, y, +// w, h, bw, win->visibility, win->viewable, win->mapped, win->drawable.id); + + if(winType == WINDOW_TYPE_NORMAL && transWinId) + { + winType=WINDOW_TYPE_DIALOG; + } + rwin=remote_find_window(win); + if(!rwin) + { + /*create new window and put it as a first element of the list*/ + rwin=malloc(sizeof(struct remoteWindow)); + rwin->state=NEW; + rwin->ptr=win; + rwin->next=remoteVars.windowList; + remoteVars.windowList=rwin; + rwin->name=NULL; + +// EPHYR_DBG("Add to list: %p, %s, %d:%d %dx%d, visibility: %d", rwin->ptr, rwin->name, rwin->x,rwin->y, +// rwin->w, rwin->h, rwin->visibility); + } + else + { +// EPHYR_DBG("found in list: %p, %s, %d:%d %dx%d, visibility: %d", rwin->ptr, rwin->name, rwin->x,rwin->y, +// rwin->w, rwin->h,rwin->visibility); + + if(rwin->name || dispName) + { + if(rwin->name==NULL && dispName) + { + rwin->state=CHANGED; + }else if(strlen(rwin->name)!=dispNameSize) + { + rwin->state=CHANGED; + }else if (strncmp(rwin->name,dispName, dispNameSize)) + { + rwin->state=CHANGED; + } + } + + if(rwin->x != x || rwin->y != y || + rwin->w != w || rwin->h != h || rwin->bw != bw || rwin->visibility != win->visibility) + { + rwin->state=CHANGED; + } + if(rwin->parent != parPtr || rwin->nextSib != nextSibPtr) + { + EPHYR_DBG("STACK order changed for %p %s old parent %p new parent %p, old nextsib %p, new nextsib %p", rwin->ptr, rwin->name, rwin->parent, parPtr, rwin->nextSib, nextSibPtr); + rwin->state=CHANGED; + } + } + + rwin->foundInWinTree=TRUE; + rwin->x=x; + rwin->y=y; + rwin->w=w; + rwin->h=h; + rwin->bw=bw; + rwin->visibility=win->visibility; + rwin->parent=parPtr; + rwin->nextSib=nextSibPtr; + rwin->winType=winType; + rwin->id=win->drawable.id; + rwin->transWinId=transWinId; + if(rwin->parent) + rwin->parentId=rwin->parent->drawable.id; + else + rwin->parentId=0; + if(rwin->nextSib) + rwin->nextSibId=rwin->nextSib->drawable.id; + else + rwin->nextSibId=0; + + if(!rwin->name || strlen(rwin->name)!=dispNameSize || strncmp(rwin->name,dispName,dispNameSize)) + { + if(rwin->name) + { + free(rwin->name); + rwin->name=NULL; + } + if(dispNameSize) + { + rwin->name=malloc(dispNameSize+1); + strncpy(rwin->name, dispName, dispNameSize); + rwin->name[dispNameSize]='\0'; + } + } + if(rwin->state != UNCHANGED) + { + remoteVars.windowsUpdated=TRUE; + if(rwin->state==NEW) + { + EPHYR_DBG("NEW WINDOW %p, %s, %d:%d %dx%d bw-%d, visibility: %d parent %p nextSib %p",rwin->ptr, rwin->name, rwin->x,rwin->y, + rwin->w, rwin->h, rwin->bw ,rwin->visibility, rwin->parent, rwin->nextSib); + } + else + { +// EPHYR_DBG("WINDOW CHANGED:"); + } +/* if(rwin->name &&( !strncmp (rwin->name, "xterm",4))) + { + EPHYR_DBG("=======WIN: %p, %s, %d:%d %dx%d bw-%d, visibility: %d parent %p nextSib %p", rwin->ptr, rwin->name, rwin->x,rwin->y, + rwin->w, rwin->h, rwin->bw ,rwin->visibility, rwin->parent, rwin->nextSib); + + }*/ + + //only for debug purpose + /* + EPHYR_DBG("CURRENT STACK:"); + WindowPtr wn = remoteVars.ephyrScreen->pScreen->root->firstChild; + while(wn) + { + char* nm=NULL; + struct remoteWindow* rw=remote_find_window(wn); + if(rw) + { + nm=rw->name; + } + if(wn->mapped) + { + EPHYR_DBG("%p (%s) mapped: %d",wn,nm,wn->mapped); + } + wn=wn->nextSib; + } + EPHYR_DBG("END OF STACK:");*/ + // + } +// EPHYR_DBG("========================================================"); + +} + +void remote_check_windowstree(WindowPtr root) +{ + WindowPtr child; + child=root->firstChild; + while(child) + { + remote_check_windowstree(child); + remote_check_window(child); + child=child->nextSib; + } +} + +WindowPtr remote_find_window_on_screen_by_id(uint32_t winId, WindowPtr root) +{ + WindowPtr child; + child=root->firstChild; + while(child) + { + if(child->drawable.id == winId) + { + return child; + } + if(remote_find_window_on_screen_by_id(winId,child)) + { + return child; + } + child=child->nextSib; + } + return NULL; +} + +WindowPtr remote_find_window_on_screen(WindowPtr win, WindowPtr root) +{ + WindowPtr child; + child=root->firstChild; + while(child) + { + if(child == win) + { + return win; + } + if(remote_find_window_on_screen(win,child)) + { + return win; + } + child=child->nextSib; + } + return NULL; +} + +void remote_check_rootless_windows_for_updates(KdScreenInfo *screen) +{ + struct remoteWindow* rwin; + pthread_mutex_lock(&remoteVars.sendqueue_mutex); + + //don't check windows if no client is connected + if(remoteVars.client_connected==FALSE) + { + pthread_mutex_unlock(&remoteVars.sendqueue_mutex); + return; + } + + // EPHYR_DBG("START TREE CHECK"); + remote_check_windowstree(screen->pScreen->root); + + //check all windows in list and mark as deleted if not found in the tree + rwin=remoteVars.windowList; + while(rwin) + { + if(!rwin->foundInWinTree) + { + remoteVars.windowsUpdated=TRUE; + //mark window as deleted + rwin->state=WDEL; +// EPHYR_DBG("DELETED WINDOW: %p, %s",rwin->ptr, rwin->name); + } + rwin->foundInWinTree=FALSE; + rwin=rwin->next; + } + /* + // EPHYR_DBG("END TREE CHECK"); + //if client is not connected, release deleted windows here + if(remoteVars.client_connected==FALSE) + { + //sendqueue mutex is locked here + prev=NULL; + rwin=remoteVars.windowList; + while(rwin) + { + if(rwin->state==WDEL) + { + //remove window from list and free resources +// EPHYR_DBG("release window %p, %s",rwin->ptr, rwin->name); + if(rwin==remoteVars.windowList) + { + remoteVars.windowList=rwin->next; + } + if(prev) + { + prev->next=rwin->next; + } + tmp=rwin; + rwin=rwin->next; + if(tmp->name) + { + free(tmp->name); + } + free(tmp); + } + else + { + prev=rwin; + rwin=rwin->next; + } + } + remoteVars.windowsUpdated=FALSE; + }*/ + pthread_mutex_unlock(&remoteVars.sendqueue_mutex); } void @@ -3378,7 +4160,10 @@ remote_paint_rect(KdScreenInfo *screen, uint32_t size=width*height*XSERVERBPP; - + if(remoteVars.rootless) + { + remote_check_rootless_windows_for_updates(screen); + } if(size) { int32_t dirtyx_max = 0; @@ -3492,7 +4277,7 @@ remote_paint_rect(KdScreenInfo *screen, // EPHYR_DBG("new update rect dimensions: %dx%d", width, height); // } - add_frame(width, height, dx, dy, calculate_crc(width, height,dx,dy), size); + add_frame(width, height, dx, dy, calculate_crc(width, height,dx,dy), size,0); } } @@ -3520,9 +4305,15 @@ void remote_set_display_name(const char* name) { max_len=strlen(name); } - strncpy(RemoteHostVars.displayName, name, max_len); - RemoteHostVars.displayName[max_len]='\0'; - EPHYR_DBG("DISPLAY name: %s",RemoteHostVars.displayName); + strncpy(remoteVars.displayName, name, max_len); + remoteVars.displayName[max_len]='\0'; + EPHYR_DBG("DISPLAY name: %s",remoteVars.displayName); +} + +void remote_set_rootless(void) +{ + EPHYR_DBG("Running in ROOTLESS mode"); + remoteVars.rootless=TRUE; } void * diff --git a/x2gokdriveremote.h b/x2gokdriveremote.h index 7770c36..0e6ecc9 100644 --- a/x2gokdriveremote.h +++ b/x2gokdriveremote.h @@ -121,13 +121,22 @@ //always 4 #define XSERVERBPP 4 -enum msg_type{FRAME,DELETED, CURSOR, DELETEDCURSOR, SELECTION, SERVERVERSION, DEMANDCLIENTSELECTION, REINIT}; +enum msg_type{FRAME,DELETED, CURSOR, DELETEDCURSOR, SELECTION, SERVERVERSION, DEMANDCLIENTSELECTION, REINIT, WINUPDATE}; enum AgentState{STARTING, RUNNING, RESUMING, SUSPENDING, SUSPENDED, TERMINATING, TERMINATED}; enum Compressions{JPEG,PNG}; enum SelectionType{PRIMARY,CLIPBOARD}; enum SelectionMime{STRING,UTF_STRING,PIXMAP}; enum ClipboardMode{CLIP_NONE,CLIP_CLIENT,CLIP_SERVER,CLIP_BOTH}; enum OS_VERSION{OS_LINUX, OS_WINDOWS, OS_DARWIN, WEB}; +enum WinUpdateType{UPD_NEW,UPD_CHANGED,UPD_DELETED}; +enum WinType{WINDOW_TYPE_DESKTOP, WINDOW_TYPE_DOCK, WINDOW_TYPE_TOOLBAR, WINDOW_TYPE_MENU, WINDOW_TYPE_UTILITY, WINDOW_TYPE_SPLASH, + WINDOW_TYPE_DIALOG, WINDOW_TYPE_DROPDOWN_MENU, WINDOW_TYPE_POPUP_MENU, WINDOW_TYPE_TOOLTIP, WINDOW_TYPE_NOTIFICATION, + WINDOW_TYPE_COMBO, WINDOW_TYPE_DND, WINDOW_TYPE_NORMAL}; + +//Size of 1 window update (new or changed window) = 4xwinId + type of update + 5 coordinates + visibility + type of window + size of name buffer + #define WINUPDSIZE 4*sizeof(uint32_t) + sizeof(int8_t) + 5*sizeof(int16_t) + sizeof(int8_t) + sizeof(int8_t) + sizeof(int16_t) +//Size of 1 window update (deleted window) = winId + type of update +#define WINUPDDELSIZE sizeof(uint32_t) + sizeof(int8_t) #define DEFAULT_COMPRESSION JPEG @@ -153,6 +162,8 @@ enum OS_VERSION{OS_LINUX, OS_WINDOWS, OS_DARWIN, WEB}; #define DEMANDSELECTION 11 #define KEEPALIVE 12 #define CACHEREBUILD 13 +#define WINCHANGE 14 + #define EVLENGTH 41 @@ -257,6 +268,7 @@ struct sendqueue_element int32_t x, y; uint32_t width, height; uint32_t crc; + uint32_t winId; struct sendqueue_element* next; }; @@ -348,6 +360,20 @@ struct SelectionStructure pthread_mutex_t inMutex; //mutex for synchronization of incoming selection }; +struct remoteWindow +{ + enum {UNCHANGED, CHANGED, NEW, WDEL}state; + int16_t x,y; + uint16_t w,h,bw; + int8_t visibility; + uint8_t winType; + char* name; + BOOL foundInWinTree; + uint32_t id; + uint32_t parentId, nextSibId, transWinId; + struct remoteWindow *next; + WindowPtr ptr, parent, nextSib; +}; struct _remoteHostVars { @@ -392,6 +418,7 @@ struct _remoteHostVars int numofimg; int clientsock, serversock; + BOOL rootless; struct cache_elem* first_cache_element; @@ -420,6 +447,9 @@ struct _remoteHostVars struct sentCursor* sentCursorsHead; struct sentCursor* sentCursorsTail; + struct remoteWindow* windowList; + BOOL windowsUpdated; + pthread_mutex_t sendqueue_mutex; pthread_mutex_t mainimg_mutex; pthread_cond_t have_sendqueue_cond; @@ -481,7 +511,7 @@ unsigned char* png_compress(uint32_t image_width, uint32_t image_height, void clientReadNotify(int fd, int ready, void *data); void serverAcceptNotify(int fd, int ready, void *data); -void add_frame(uint32_t width, uint32_t height, int32_t x, int32_t y, uint32_t crc, uint32_t size); +void add_frame(uint32_t width, uint32_t height, int32_t x, int32_t y, uint32_t crc, uint32_t size, uint32_t winId); void clear_output_selection(void); @@ -516,5 +546,15 @@ remote_paint_rect(KdScreenInfo *screen, void request_selection_from_client(enum SelectionType selection); void rebuild_caches(void); +void remote_set_rootless(void); +void remote_check_windowstree(WindowPtr root); +void remote_check_window(WindowPtr win); +struct remoteWindow* remote_find_window(WindowPtr win); +WindowPtr remote_find_window_on_screen(WindowPtr win, WindowPtr root); +WindowPtr remote_find_window_on_screen_by_id(uint32_t winId, WindowPtr root); +void remote_process_window_updates(void); +void send_reinit_notification(void); +void client_win_change(char* buff); +void remote_check_rootless_windows_for_updates(KdScreenInfo *screen); #endif /* X2GOKDRIVE_REMOTE_H */ diff --git a/x2gokdriveselection.c b/x2gokdriveselection.c index 4f29a6d..8738c7c 100644 --- a/x2gokdriveselection.c +++ b/x2gokdriveselection.c @@ -58,7 +58,6 @@ extern unsigned long long int debug_selectThreadId; static struct _remoteHostVars *remoteVars = NULL; -extern struct _remoteHostVars RemoteHostVars; //internal atoms static xcb_atom_t ATOM_ATOM; @@ -943,10 +942,10 @@ void *selection_thread (void* id) #endif /* EPHYR_WANT_DEBUG */ /* Create the window */ - remoteVars->selstruct.xcbConnection = xcb_connect (RemoteHostVars.displayName, NULL); + remoteVars->selstruct.xcbConnection = xcb_connect (remoteVars->displayName, NULL); if(xcb_connection_has_error(remoteVars->selstruct.xcbConnection)) { - EPHYR_DBG("Warning! can't create XCB connection to display %s, selections exchange between client and server will be disabled", RemoteHostVars.displayName); + EPHYR_DBG("Warning! can't create XCB connection to display %s, selections exchange between client and server will be disabled", remoteVars->displayName); remoteVars->selstruct.xcbConnection=0; pthread_exit(0); return NULL; -- Alioth's /home/x2go-admin/maintenancescripts/git/hooks/post-receive-email on /srv/git/code.x2go.org/x2gokdrive.git