chiark / gitweb /
keystrokes
[moebius2.git] / view.c
diff --git a/view.c b/view.c
index 1ce6db66d492867a869ed833b2a9e9c6931067a8..712623c02f6667694c760b65e37cd6306f41ede8 100644 (file)
--- a/view.c
+++ b/view.c
@@ -5,6 +5,10 @@
 #include <X11/Xlib.h>
 #include <X11/Xutil.h>
 
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/poll.h>
+
 #include "mgraph.h"
 
 #define MAXTRIS (N*2)
@@ -18,16 +22,21 @@ static Vertices conformation;
 static double transform[D3][D3]= {{1,0,0}, {0,1,0}, {0,0,1}};
 static GSL_MATRIX(transform);
 
-const char *input_filename;
+static FILE *input_f;
+static struct stat input_stab;
+static const char *input_filename;
 
 static void read_input(void) {
-  FILE *f;
   int r;
   
-  f= fopen(input_filename, "rb");  if (!f) diee("input file");
+  if (input_f) fclose(input_f);
+  input_f= fopen(input_filename, "rb");  if (!input_f) diee("input file");
+
+  if (fstat(fileno(input_f), &input_stab)) diee("fstat input file");
+
   errno= 0;
-  r= fread(&conformation,sizeof(conformation),1,f);  if (r!=1) diee("fread");
-  fclose(f);
+  r= fread(&conformation,sizeof(conformation),1,input_f);
+  if (r!=1) diee("fread");
 }
 
 static void transform_coordinates(void) {
@@ -111,6 +120,8 @@ XVisualInfo visinfo;
 static double sizeadj_scale= 0.3, eyes_apart, scale_wmindim;
 static double eye_z= -10, eye_x=0;
 static double cut_z= -9;
+static const double eyes_apart_preferred=0.05, eyes_apart_min= -0.02;
+
 
 static void drawtriangle(const Triangle *t) {
   XPoint points[4];
@@ -137,7 +148,8 @@ static void drawtriangle(const Triangle *t) {
 }
 
 static const unsigned long core_event_mask=
-  ButtonPressMask|ButtonReleaseMask|StructureNotifyMask|ButtonMotionMask;
+  ButtonPressMask|ButtonReleaseMask|StructureNotifyMask|ButtonMotionMask|
+  KeyPressMask;
 
 static void mkpixmaps(void) {
   for (currentbuffer=0; currentbuffer<2; currentbuffer++) {
@@ -205,11 +217,13 @@ static void display_conformation(void) {
   XA( XFillRectangle(display,pixmap,dmwhite.fillgc,0,0,wwidth,wheight) );
 
   if (eyes_apart > 0) {
-    const double preferred=0.05, beyond=0.07;
+    const double stationary= 0.07;
 
-    eye_x= eyes_apart < preferred ? eyes_apart :
-           eyes_apart < beyond ? preferred :
-           eyes_apart - (beyond - preferred);
+    eye_x= eyes_apart < eyes_apart_preferred
+              ? eyes_apart :
+           eyes_apart < (eyes_apart_preferred + stationary)
+              ? eyes_apart_preferred
+              : eyes_apart - stationary;
     eye_x /= sizeadj_scale;
     drawtriangles(&dmblue);
     eye_x= -eye_x;
@@ -398,9 +412,8 @@ static void drag_sizeadj_delta(double dx, double dy) {
 DRAG_SAVING(sizeadj, sizeadj_scale);
 
 static void drag_3d_delta(double dx, double dy) {
-  const double min_eyes_apart= -0.02;
   eyes_apart += dx * 0.1;
-  if (eyes_apart < min_eyes_apart) eyes_apart= min_eyes_apart;
+  if (eyes_apart < eyes_apart_min) eyes_apart= eyes_apart_min;
   printf("sizeadj eyes_apart %g\n", eyes_apart);
   show();
 }
@@ -452,6 +465,26 @@ static void event_motion(int x, int y) {
   drag_position(x,y);
 }
 
+static void event_key(XKeyEvent *e) {
+  KeySym ks;
+  char buf[10];
+  int r;
+
+  r= XLookupString(e,buf,sizeof(buf)-1,&ks,0);
+  if (!r) {
+    printf("XLookupString keycode=%u state=0x%x gave %d\n",
+          e->keycode, e->state, r);
+    return;
+  }
+
+  if (!strcmp(buf,"q")) exit(0);
+  if (!strcmp(buf,"d")) {
+    eyes_apart= eyes_apart>0 ? eyes_apart_min : eyes_apart_preferred;
+    show();
+    return;
+  }
+}
+
 static void event_config(XConfigureEvent *e) {
   if (e->width == wwidth && e->height == wheight)
     return;
@@ -468,9 +501,31 @@ static void event_config(XConfigureEvent *e) {
   show();
 }
 
+static void check_input(void) {
+  struct stat newstab;
+  int r;
+
+  r= stat(input_filename, &newstab);
+  if (r<0) diee("could not check input");
+
+#define CI(x) if (newstab.st_##x == input_stab.st_##x) ; else goto changed
+  CI(dev);
+  CI(ino);
+  CI(size);
+  CI(mtime);
+#undef CI
+  return;
+
+ changed:
+  show();
+}
+
 int main(int argc, const char *const *argv) {
+  static const int wantedevents= POLLIN|POLLPRI|POLLERR|POLLHUP;
+
   XEvent event;
-  int k;
+  int k, i, r, *xfds, nxfds, polls_alloc=0;
+  struct pollfd *polls=0;
   int motion_deferred=0, motion_x=-1, motion_y=-1;
   
   if (argc != 2 || argv[1][0]=='-') {
@@ -485,21 +540,47 @@ int main(int argc, const char *const *argv) {
 
   XMapWindow(display,window);
   for (;;) {
-    if (motion_deferred) {
-      int r= XCheckMaskEvent(display,~0UL,&event);
-      if (!r) {
+
+    XA( XInternalConnectionNumbers(display, &xfds, &nxfds) );
+    if (polls_alloc <= nxfds) {
+      polls_alloc= nxfds + polls_alloc + 1;
+      polls= realloc(polls, sizeof(*polls) * polls_alloc);
+      if (!polls) diee("realloc for pollfds");
+    }
+    for (i=0; i<nxfds; i++) {
+      polls[i].fd= xfds[i];
+      polls[i].events= wantedevents;
+      polls[i].revents= 0;
+    }
+    XFree(xfds);
+
+    polls[i].fd= ConnectionNumber(display);
+    polls[i].events= wantedevents;
+
+    r= poll(polls, nxfds+1, motion_deferred ? 0 : 200);
+    if (r<0) diee("poll");
+
+    for (i=0; i<nxfds; i++)
+      if (polls[i].revents)
+       XProcessInternalConnection(display, polls[i].fd);
+
+    r= XCheckMaskEvent(display,~0UL,&event);
+    if (!r) {
+      if (motion_deferred) {
        event_motion(motion_x, motion_y);
        motion_deferred=0;
-       continue;
       }
-    } else {
-      XNextEvent(display,&event);
+      check_input();
+      continue;
     }
+    
     switch (event.type) {
 
     case ButtonPress:
     case ButtonRelease:     event_button(&event.xbutton);     break;
       
+    case KeyPress:          event_key(&event.xkey);           break;
+
     case ConfigureNotify:   event_config(&event.xconfigure);  break;
 
     case MotionNotify: