chiark / gitweb /
Merge branch 'master' of ijackson@chiark:things/ypp-sc-tools
[ypp-sc-tools.db-live.git] / pctb / pages.c
index dfa9108537bbf7b5a9c19d507a443f6caa13851c..56fb4092b8e35650586c35a4ffd18c3b400e1f70 100644 (file)
 #include <X11/keysym.h>
 #include <X11/Xutil.h>
 
+#include <X11/extensions/XShm.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+
 CanonImage *page_images[MAX_PAGES];
 int npages;
 RgbImage *page0_rgbimage;
@@ -50,6 +54,9 @@ static struct timeval tv_startup;
 static unsigned wwidth, wheight;
 static int max_relevant_y= -1;
 
+static XImage *shmim;
+static XShmSegmentInfo shminfo;
+
 DEBUG_DEFINE_DEBUGF(pages)
 
 #define xassert(what)                                  \
@@ -321,6 +328,55 @@ static void raise_and_get_details(void) {
     fatal("YPP client window is implausibly small?");
 
   check_client_window_all_on_screen();
+
+  int shm= XShmQueryExtension(disp);
+  if (shm) {
+    xassert( shmim= XShmCreateImage(disp, attr.visual, attr.depth, ZPixmap,
+                                   0,&shminfo, wwidth,wheight) );
+
+    sigset_t oldset, all;
+    sigfillset(&all);
+    sysassert(! sigprocmask(SIG_BLOCK,&all,&oldset) );
+
+    int pfd[2];
+    pid_t cleaner;
+    sysassert(! pipe(pfd) );
+    sysassert( (cleaner= fork()) != -1 );
+    if (!cleaner) {
+      sysassert(! close(pfd[1]) );
+      for (;;) {
+       int r= read(pfd[0], &shminfo.shmid, sizeof(shminfo.shmid));
+       if (!r) exit(0);
+       if (r==sizeof(shminfo.shmid)) break;
+       assert(r==-1 && errno==EINTR);
+      }
+      for (;;) {
+       char bc;
+       int r= read(pfd[0],&bc,1);
+       if (r>=0) break;
+       assert(r==-1 && errno==EINTR);
+      }
+      sysassert(! shmctl(shminfo.shmid,IPC_RMID,0) );
+      exit(0);
+    }
+    sysassert(! close(pfd[0]) );
+
+    sysassert(! sigprocmask(SIG_SETMASK,&oldset,0) );
+
+    assert(shmim->height == wheight);
+    sysassert( (shminfo.shmid=
+               shmget(IPC_PRIVATE, shmim->bytes_per_line * wheight,
+                      IPC_CREAT|0600)) >= 0 );
+
+    sysassert( write(pfd[1],&shminfo.shmid,sizeof(shminfo.shmid)) ==
+              sizeof(shminfo.shmid) );
+    sysassert( shminfo.shmaddr= shmat(shminfo.shmid,0,0) );
+    shmim->data= shminfo.shmaddr;
+    shminfo.readOnly= False;
+    xassert( XShmAttach(disp,&shminfo) );
+
+    close(pfd[1]); /* causes IPC_RMID */
+  }
 }
 
 static void set_focus_commodity(void) {