chiark / gitweb /
WIP MIT-SHM; can create shm segment
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Mon, 15 Jun 2009 12:31:41 +0000 (13:31 +0100)
committerIan Jackson <Ian.Jackson@eu.citrix.com>
Mon, 15 Jun 2009 12:31:41 +0000 (13:31 +0100)
pctb/pages.c

index ab3a2b0..1fba5a6 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;
 
@@ -49,6 +53,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)                                  \
@@ -307,6 +314,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(void) {