diff --git a/unix/kasmxproxy/kasmxproxy.c b/unix/kasmxproxy/kasmxproxy.c index cea6c4d..f74371f 100644 --- a/unix/kasmxproxy/kasmxproxy.c +++ b/unix/kasmxproxy/kasmxproxy.c @@ -21,8 +21,14 @@ #include #include #include +#include +#include #include #include +#include +#include + +#define min(a, b) ((a) < (b) ? (a) : (b)) static void help(const char name[]) { printf("Usage: %s [opts]\n\n" @@ -80,5 +86,96 @@ int main(int argc, char **argv) { } } + Display *appdisp = XOpenDisplay(appstr); + if (!appdisp) { + printf("Cannot open display %s\n", appstr); + return 1; + } + if (!XShmQueryExtension(appdisp)) { + printf("Display %s lacks SHM extension\n", appstr); + return 1; + } + + Display *vncdisp = XOpenDisplay(vncstr); + if (!vncdisp) { + printf("Cannot open display %s\n", vncstr); + return 1; + } + if (!XShmQueryExtension(vncdisp)) { + printf("Display %s lacks SHM extension\n", vncstr); + return 1; + } + + const int appscreen = DefaultScreen(appdisp); + const int vncscreen = DefaultScreen(vncdisp); + Visual *appvis = DefaultVisual(appdisp, appscreen); + Visual *vncvis = DefaultVisual(vncdisp, vncscreen); + const int appdepth = DefaultDepth(appdisp, appscreen); + const int vncdepth = DefaultDepth(vncdisp, vncscreen); + if (appdepth != vncdepth) { + printf("Depths don't match, app %u vnc %u\n", appdepth, vncdepth); + return 1; + } + + Window approot = DefaultRootWindow(appdisp); + Window vncroot = DefaultRootWindow(vncdisp); + XWindowAttributes appattr, vncattr; + + XGCValues gcval; + gcval.plane_mask = AllPlanes; + gcval.function = GXcopy; + GC gc = XCreateGC(vncdisp, vncroot, GCFunction | GCPlaneMask, &gcval); + + XImage *img = NULL; + XShmSegmentInfo shminfo; + unsigned imgw = 0, imgh = 0; + + const unsigned sleeptime = 1000 * 1000 / fps; + + while (1) { + if (!XGetWindowAttributes(appdisp, approot, &appattr)) + break; + if (!XGetWindowAttributes(vncdisp, vncroot, &vncattr)) + break; + if (resize && (appattr.width != vncattr.width || + appattr.height != vncattr.height)) { + // TODO resize app display to VNC display size + } + + const unsigned w = min(appattr.width, vncattr.width); + const unsigned h = min(appattr.height, vncattr.height); + + if (w != imgw || h != imgh) { + if (img) { + XShmDetach(appdisp, &shminfo); + XDestroyImage(img); + shmdt(shminfo.shmaddr); + shmctl(shminfo.shmid, IPC_RMID, NULL); + } + img = XShmCreateImage(appdisp, appvis, appdepth, ZPixmap, + NULL, &shminfo, w, h); + if (!img) + break; + + shminfo.shmid = shmget(IPC_PRIVATE, + img->bytes_per_line * img->height, + IPC_CREAT | 0666); + if (shminfo.shmid == -1) + break; + shminfo.shmaddr = img->data = shmat(shminfo.shmid, 0, 0); + shminfo.readOnly = False; + if (!XShmAttach(appdisp, &shminfo)) + break; + + imgw = w; + imgh = h; + } + + XShmGetImage(appdisp, approot, img, 0, 0, 0xffffffff); + XPutImage(vncdisp, vncroot, gc, img, 0, 0, 0, 0, w, h); + + usleep(sleeptime); + } + return 0; }