[X2Go-Commits] [x2gokdrive] 01/01: rootless mode for x2gokdrive

git-admin at x2go.org git-admin at x2go.org
Mon Jan 31 16:39:44 CET 2022


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 at 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


More information about the x2go-commits mailing list