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