#include"viewer.h"
#define MASK KeyPressMask|ButtonPressMask|ButtonReleaseMask|ExposureMask
void ViewerInit(Viewer*vw, int _W,int _H){
Atom t;
vw->W = _W;
vw->H = _H;
vw->d = XOpenDisplay(0);
vw->w = XCreateSimpleWindow(vw->d,RootWindow(vw->d,0), 0,0, _W,_H,1, 0,0);
vw->lx=-1;
vw->ly=-1;
XSelectInput(vw->d,vw->w, MASK );
t=XInternAtom(vw->d,"WM_DELETE_WINDOW",False);
XSetWMProtocols(vw->d,vw->w,&t,1);
XMapWindow(vw->d,vw->w);
vw->data = (PixType*)malloc(_W*_H*sizeof(PixType));
vw->img = XCreateImage(vw->d,DefaultVisual(vw->d,0), BPP, ZPixmap, 0, (char*)vw->data, _W,_H,8,sizeof(PixType)*_W);
}
static int select1(int fd,float t){
fd_set a;
struct timeval tm;
tm.tv_sec=(int)t;
tm.tv_usec=(int)((t-(int)t)*1000000);
FD_ZERO(&a);
FD_SET(fd,&a);
return select(fd+1,&a,0,0,&tm);
}
static int getEv(Display*d,XEvent*e,int i){
if(i){
do{
if( XCheckMaskEvent(d,MASK,e) ||
XCheckTypedEvent(d,ClientMessage,e) || // delete window
XPending(d) && ( XNextEvent(d,e), 1 ) ) return 1; // cut/paste
}while(i>1 && select1( ConnectionNumber(d), i*1e-3) ); // do not use Sleep (usleep)
return 0;
}else{
XNextEvent(d,e);
return 1;
}
}
void ViewerEvent(Viewer*vw,int ev[4]){
while(1){
XEvent e;
//XNextEvent(vw->d, &e);
if( getEv(vw->d, &e, 30) == 0){
Window dmy1;
int dmy,x,y;
XQueryPointer(vw->d, vw->w, &dmy1, &dmy1, &dmy,&dmy, &x,&y, &ev[1]);
ev[0]= ((((unsigned)x<vw->W)&((unsigned)y<vw->H))==0)*2 | ( ((x-vw->lx)|(y-vw->ly)) != 0 );
vw->lx=ev[2]; ev[2]=x;
vw->ly=ev[3]; ev[3]=y;
return;
}
/*
If you want to create multiple windows,
you can create one thread for each window and be sure that each thread has its own Display*d.
Then XNextEvent does not receive events for other threads' windows.
XWindowEvent does not respond to the [x] button (delete window button).
*/
switch(e.type){
case Expose:
XPutImage(vw->d,vw->w,DefaultGC(vw->d,0),vw->img,
e.xexpose.x,e.xexpose.y,
e.xexpose.x,e.xexpose.y,e.xexpose.width,e.xexpose.height);
break;
case ButtonPress:
ev[0]=240+e.xbutton.button;
ev[1]=e.xbutton.state;
ev[2]=e.xbutton.x;
ev[3]=e.xbutton.y;
return;
case ButtonRelease:
ev[0]=240+256+e.xbutton.button;
ev[1]=e.xbutton.state;
ev[2]=e.xbutton.x;
ev[3]=e.xbutton.y;
return;
case KeyPress:
ev[0]=XKeycodeToKeysym(vw->d,e.xkey.keycode,e.xkey.state);
if(ev[0]==65293) ev[0]=='\n';
ev[1]=e.xkey.state;
ev[2]=e.xkey.x;
ev[3]=e.xkey.y;
return;
case ClientMessage:
if(e.xclient.message_type == XInternAtom(vw->d,"WM_PROTOCOLS",False) &&
e.xclient.format == 32 &&
e.xclient.data.l[0] == XInternAtom(vw->d,"WM_DELETE_WINDOW",False) ){
ev[0]=248;
return;
}
}
}
}
void ViewerImageWrite(Viewer*vw,Image*im){
int i,j;
for(i=0;i<im->H;i++) for(j=0;j<im->W;j++) {
int r=im->data[(i*im->W+j)*3+0],
g=im->data[(i*im->W+j)*3+1],
b=im->data[(i*im->W+j)*3+2];
vw->data[i*vw->W+j]=MakePix(r,g,b);
}
XPutImage(vw->d,vw->w,DefaultGC(vw->d,0),vw->img, 0,0, 0,0,vw->W,vw->H);
}