#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)
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) {
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];
}
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++) {
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;
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();
}
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;
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]=='-') {
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: