summaryrefslogtreecommitdiff
path: root/Xbit.c
diff options
context:
space:
mode:
Diffstat (limited to 'Xbit.c')
-rw-r--r--Xbit.c1877
1 files changed, 1877 insertions, 0 deletions
diff --git a/Xbit.c b/Xbit.c
new file mode 100644
index 0000000..83fdb3c
--- /dev/null
+++ b/Xbit.c
@@ -0,0 +1,1877 @@
+/*
+
+ Xbit - Simple xlib interface
+
+ Copyright (C) 2005 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ -------------------------------------------------------------------------
+
+ This is a bit messy as it based on very old K&R code.
+
+*/
+static char rcs_id[]="$Id: Xbit.c 11 2006-05-02 19:02:49Z ianc $";
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xos.h>
+#include <X11/Xatom.h>
+
+#include <X11/extensions/XShm.h>
+
+/* #include <machine/param.h> */
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include <netinet/in.h>
+
+#include "Xbit.h"
+
+#include "icon.bmp"
+
+#define WARN(x) fprintf(stderr,"%s(%d) : Warning:%s\n",__FILE__,__LINE__,x);
+#define WARN1(x,y) fprintf(stderr,"%s(%d) : Warning:%s %s\n",__FILE__,__LINE__,x,y);
+
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#define ABS(x) ((x) < 0 ? (-(x)) : (x))
+
+
+/* GLOBALS
+*/
+
+#define MAXPM 256
+
+typedef struct WEntry
+{
+ Window w;
+ Pixmap pm[MAXPM];
+ int used_MIT_SHM;
+ XShmSegmentInfo
+ shm_info;
+ int pmi;
+ int buffer;
+ int use_pm;
+ int multi;
+ int multino;
+ ulong multicls;
+ GC gc;
+ int ox;
+ int oy;
+ int ww;
+ int wh;
+ int pw;
+ int ph;
+ int func;
+ int lastuserfunc;
+ ulong lastfg;
+ int spline_thresh;
+ struct WEntry *next;
+} WEntry;
+
+
+static WEntry *whead=NULL;
+static WEntry *wtail=NULL;
+
+static WEntry *current=NULL;
+
+static WEntry *stack[128];
+static int sttop;
+
+static Display *display=NULL;
+static XVisualInfo vinfo;
+static int screen;
+
+static int use_shm=True;
+
+static ulong xb_black;
+static ulong xb_white;
+
+/* Buffer for Xprintf() and XIprintf()
+*/
+static char prbuf[1024];
+
+/* Definitions for XImage 8x8 charset
+*/
+#include "fontset.h"
+
+
+/* Put globals
+*/
+static int no_plots;
+static XPoint points[MAX_PUTPLOTS];
+
+
+/* Set write mode
+*/
+#define WM(c) do {if ((c)!=current->func) { \
+ XSetFunction(display,current->gc,c); \
+ current->func=c; } } while(0)
+
+
+/* Set foreground funcrion
+*/
+#define FG(c) do {if ((c)!=current->lastfg) { \
+ XSetForeground(display,current->gc,c); \
+ current->lastfg=c; } } while(0)
+
+
+/* Stack current windows
+*/
+#define PUSHW do {stack[sttop++]=current;} while(0)
+#define POPW do {current=stack[--sttop];} while(0)
+
+
+/* ------------- FUNCTIONS ------------- */
+
+static void CreateWEntry(Window w, GC g, int ww, int wh)
+{
+ WEntry *new;
+
+ if (!(new=malloc(sizeof(WEntry))))
+ {
+ fprintf(stderr,"%s(%d) : FATAL:%s\n",__FILE__,__LINE__,
+ "Couldn't malloc() WEntry");
+ exit(1);
+ }
+
+ if (!whead)
+ {
+ whead=new;
+ wtail=new;
+ }
+ else
+ {
+ wtail->next=new;
+ wtail=new;
+ }
+
+ new->next=NULL;
+
+ new->w=w;
+ new->gc=g;
+
+ new->pm[0]=0;
+ new->pm[1]=0;
+ new->pmi=0;
+ new->buffer=True;
+ new->use_pm=True;
+ new->multi=False;
+ new->ox=0;
+ new->oy=0;
+ new->ww=ww;
+ new->wh=wh;
+ new->pw=0;
+ new->ph=0;
+ new->func=GXcopy;
+ new->lastuserfunc=GXcopy;
+ new->lastfg=-1;
+ new->spline_thresh=1;
+ new->used_MIT_SHM=False;
+}
+
+
+XImage *CreateXImage(void)
+{
+ XImage *img;
+ char *p;
+
+ if (!use_shm)
+ {
+ switch(vinfo.depth)
+ {
+ case 8:
+ p=malloc(current->pw*current->ph*1);
+ break;
+ case 16:
+ p=malloc(current->pw*current->ph*2);
+ break;
+ default:
+ p=malloc(current->pw*current->ph*4);
+ break;
+ }
+
+ if (!p)
+ {
+ fprintf(stderr,"%s(%d) : FATAL:%s\n",__FILE__,__LINE__,
+ "Couldn't malloc() XImage data");
+ exit(1);
+ }
+
+ img=XCreateImage
+ (display,
+ vinfo.visual,
+ vinfo.depth, /* Image depth */
+ ZPixmap, /* Image format */
+ 0, /* Offset */
+ p, /* Data */
+ current->pw, /* Width */
+ current->ph, /* Height */
+ 8, /* Bitmap pad */
+ 0);
+ }
+ else
+ {
+ img=XShmCreateImage(display,
+ vinfo.visual,
+ vinfo.depth,
+ ZPixmap,
+ NULL,
+ &(current->shm_info),
+ current->pw,
+ current->ph);
+
+ if (!img)
+ return(NULL);
+
+ current->used_MIT_SHM=True;
+
+ /* Get shared memory for image
+ */
+ current->shm_info.shmid=shmget(IPC_PRIVATE,
+ img->bytes_per_line*img->height,
+ IPC_CREAT|0777);
+
+ if (current->shm_info.shmid<0)
+ {
+ WARN("Couldn't get MITSHM mem");
+ exit(1);
+ }
+
+ current->shm_info.shmaddr=shmat(current->shm_info.shmid,0,0);
+ img->data=current->shm_info.shmaddr;
+
+ current->shm_info.readOnly=False;
+
+ /* Try and attached shared memory
+ */
+ if (!XShmAttach(display,&(current->shm_info)))
+ {
+ WARN("Failed to attach MITSHM block");
+ exit(1);
+ }
+
+ XSync(display,False);
+ }
+
+ ClsXImage(img);
+ return img;
+}
+
+
+void ClsXImage(XImage *img)
+{
+ memset(img->data,0,img->bytes_per_line*img->height);
+}
+
+
+void DestroyXImage(XImage *img)
+{
+ if (current->used_MIT_SHM)
+ {
+ XShmDetach(display,&(current->shm_info));
+
+ if (current->shm_info.shmaddr)
+ shmdt(current->shm_info.shmaddr);
+
+ if (current->shm_info.shmid>=0)
+ shmctl(current->shm_info.shmid,IPC_RMID,0);
+
+ current->used_MIT_SHM=False;
+ }
+
+ XDestroyImage(img);
+ XSync(display,False);
+}
+
+
+void SetCurrentWin(Window w)
+{
+ WEntry *l;
+
+ l=whead;
+
+ while(l)
+ {
+ if (l->w==w)
+ {
+ current=l;
+ return;
+ }
+
+ l=l->next;
+ }
+
+ WARN("Asked for non-existant window");
+}
+
+
+int GetVisualDepth(void)
+{
+ return vinfo.depth;
+}
+
+
+Window OpenWin (int argc,
+ char **argv,
+ char *title,
+ int wx, int wy, int ww, int wh,
+ int pw, int ph,
+ unsigned long ev,
+ XSizeHints *hints,
+ ulong *black, ulong *white)
+{
+ Window window;
+ GC gc;
+ char *display_name=NULL;
+ Pixmap icon_pixmap;
+ int i,j,k;
+
+ if (!display)
+ {
+ if ((display=XOpenDisplay(display_name))==NULL)
+ {
+ fprintf(stderr,"%s: can't connect to %s\n",
+ argv[0], XDisplayName(display_name));
+ exit(-1);
+ }
+
+ /* Try and find shared memory extension
+ */
+ use_shm=XQueryExtension(display,"MIT-SHM",&i,&j,&k);
+
+ /* Find a nice 8-bit visual for us to use...
+ */
+ if (!XMatchVisualInfo(display,DefaultScreen(display),8,
+ PseudoColor,&vinfo))
+ if (!XMatchVisualInfo(display,DefaultScreen(display),16,
+ TrueColor,&vinfo))
+ if (!XMatchVisualInfo(display,DefaultScreen(display),24,
+ TrueColor,&vinfo))
+ if (!XMatchVisualInfo(display,DefaultScreen(display),32,
+ TrueColor,&vinfo))
+ {
+ WARN("no visual found!\n");
+ exit(1);
+ }
+ }
+
+ screen=DefaultScreen(display);
+
+ xb_black=BlackPixel(display,screen);
+ xb_white=WhitePixel(display,screen);
+ *black=xb_black;
+ *white=xb_white;
+
+ window=XCreateWindow(display,
+ RootWindow(display,screen),
+ wx,wy,ww,wh,1,
+ vinfo.depth,
+ InputOutput,
+ vinfo.visual,
+ 0,NULL);
+
+ icon_pixmap=XCreateBitmapFromData(
+ display,
+ window,
+ icon_bits,
+ icon_width,icon_height);
+
+ XSetStandardProperties(
+ display,
+ window,
+ title,
+ title,
+ icon_pixmap,
+ argv,argc,
+ hints);
+
+ XSelectInput (display,window,ev);
+
+ gc=XCreateGC(display,window,0,NULL);
+
+ XSetForeground(display,gc,*black);
+ XSetBackground(display,gc,*white);
+ XSetPlaneMask(display,gc,AllPlanes);
+ XSetGraphicsExposures(display,gc,False);
+
+ XMapWindow (display,window);
+
+ CreateWEntry(window,gc,ww,wh);
+ SetCurrentWin(window);
+
+ Resize(pw,ph);
+
+ return window;
+}
+
+
+Window OpenRootWin (ulong *black,ulong *white,int *w,int *h,int pw,int ph)
+{
+ Window window;
+ GC gc;
+ char *display_name=NULL;
+ int i,j,k;
+
+ if (!display)
+ {
+ int depth;
+
+ if ((display=XOpenDisplay(display_name))==NULL)
+ {
+ fprintf(stderr,"can't connect to %s\n",XDisplayName(display_name));
+ exit(-1);
+ }
+
+ screen=DefaultScreen(display);
+
+ depth=DefaultDepth(display,screen);
+
+ /* Try and find shared memory extension
+ */
+ use_shm=XQueryExtension(display,"MIT-SHM",&i,&j,&k);
+
+ /* Find a visual for us to use...
+ */
+ if (!XMatchVisualInfo(display,DefaultScreen(display),depth,
+ depth==8 ? PseudoColor:TrueColor,&vinfo))
+ {
+ WARN("no visual to match the root window!");
+ exit(1);
+ }
+ }
+
+ xb_black=BlackPixel(display,screen);
+ xb_white=WhitePixel(display,screen);
+ *black=xb_black;
+ *white=xb_white;
+
+ window=RootWindow(display,screen);
+
+ gc=XCreateGC(display,window,0,NULL);
+
+ XSetForeground(display,gc,*black);
+ XSetBackground(display,gc,*white);
+ XSetPlaneMask(display,gc,AllPlanes);
+
+ XMapWindow (display,window);
+
+ *w=DisplayWidth(display,screen);
+ *h=DisplayHeight(display,screen);
+
+ CreateWEntry(window,gc,*w,*h);
+ SetCurrentWin(window);
+
+ Resize(pw,ph);
+
+ return window;
+}
+
+
+XFontStruct *XUseFont(const char *n)
+{
+ XFontStruct *ft;
+
+ if (ft=XLoadQueryFont(display,n))
+ XSetFont(display,current->gc,ft->fid);
+ else
+ WARN1("couldn't load font:",n);
+
+ return ft;
+}
+
+
+void XUseCursor(const char *bm, const char *mask, XColor fg, XColor bg)
+{
+ Pixmap b,m;
+ Cursor curs;
+ int bmw,bmh,bmx,bmy;
+ int maskw,maskh,maskx,masky;
+
+ if (XReadBitmapFile(display,current->w,bm,&bmw,&bmh,&b,&bmx,&bmy)
+ ==BitmapOpenFailed)
+ {
+ WARN1("Couldn't read in cursor file:",bm);
+ return;
+ }
+
+ if (XReadBitmapFile(display,current->w,mask,&maskw,&maskh,&m,&maskx,&masky)
+ ==BitmapOpenFailed)
+ {
+ WARN1("Couldn't read in mask file:",bm);
+ return;
+ }
+
+ curs=XCreatePixmapCursor(display,b,m,&fg,&bg,bmx,bmy);
+
+ XDefineCursor(display,current->w,curs);
+
+ XFreePixmap(display,b);
+ XFreePixmap(display,m);
+}
+
+
+void LoadBitmap(const char *fn,int x,int y, int resize)
+{
+ Pixmap bm;
+ int w,h,hx,hy;
+ int cw,ch;
+
+ if (!current->use_pm)
+ {
+ WARN("Need pixmaps to load in bitmap");
+ }
+
+ if (XReadBitmapFile(display,current->w,fn,&w,&h,&bm,&hx,&hy)
+ ==BitmapOpenFailed)
+ {
+ WARN1("Couldn't read in bitmap file:",fn);
+ return;
+ }
+
+ if ((w!=current->pw)||(h!=current->ph))
+ {
+ if (resize)
+ {
+ Resize(w+x,h+y);
+ cw=w;
+ ch=h;
+ }
+ else
+ {
+ cw=current->pw-x;
+ ch=current->ph-y;
+ }
+ }
+
+ XCopyPlane(display,bm,current->pm[current->pmi],
+ current->gc,0,0,cw,ch,x,y,1L);
+
+ XFreePixmap(display,bm);
+}
+
+
+Pixmap GetBitmap(const char *fn, int *w, int *h, int *hx, int *hy)
+{
+ Pixmap bm,ret;
+
+ if (XReadBitmapFile(display,current->w,fn,w,h,&bm,hx,hy)
+ ==BitmapOpenFailed)
+ {
+ WARN1("Couldn't read in bitmap file:",fn);
+ return(0);
+ }
+
+ ret=XCreatePixmap(display,current->w,*w,*h,vinfo.depth);
+
+ XCopyPlane(display,bm,ret,current->gc,0,0,*w,*h,0,0,1L);
+
+ XFreePixmap(display,bm);
+
+ return ret;
+}
+
+
+void DrawXImage(XImage *img)
+{
+ if (use_shm)
+ XShmPutImage (display,
+ current->pm[0],
+ current->gc,
+ img,
+ 0,0,
+ 0,0,
+ current->pw,current->ph,
+ False);
+ else
+ XPutImage (display,
+ current->pm[0],
+ current->gc,
+ img,
+ 0,0,
+ 0,0,
+ current->pw,current->ph);
+}
+
+
+void Resize(int w,int h)
+{
+ int f;
+
+ if (w<current->ww)
+ w=current->ww;
+
+ if (h<current->wh)
+ h=current->wh;
+
+ current->pw=w;
+ current->ph=h;
+
+ if (!current->use_pm)
+ return;
+
+ if (current->multi)
+ {
+ WM(GXcopy);
+ FG(current->multicls);
+ for(f=0;f<current->multino;f++)
+ {
+ XFreePixmap(display,current->pm[f]);
+ current->pm[f]=XCreatePixmap(display,current->w,w,h,vinfo.depth);
+ XFillRectangle(display,current->pm[f],
+ current->gc,0,0,current->pw,current->ph);
+ }
+ WM(current->lastuserfunc);
+ return;
+ }
+
+ if (current->pm[0])
+ {
+ XFreePixmap(display,current->pm[0]);
+
+ if (current->buffer)
+ XFreePixmap(display,current->pm[1]);
+ }
+
+ current->pmi=0;
+
+ current->pm[0]=XCreatePixmap(display,current->w,w,h,vinfo.depth);
+
+ if (current->buffer)
+ current->pm[1]=XCreatePixmap(display,current->w,w,h,vinfo.depth);
+}
+
+
+void Redraw(int x,int y)
+{
+ if ((x+current->ww)>current->pw)
+ x=current->pw-current->ww;
+
+ if ((y+current->wh)>current->ph)
+ y=current->ph-current->wh;
+
+ current->ox=x;
+ current->oy=y;
+
+ if (!current->use_pm)
+ {
+ XSync(display,False);
+ return;
+ }
+
+ WM(GXcopy);
+
+ if (current->buffer)
+ {
+ XCopyArea(display,current->pm[current->pmi^1],current->w,
+ current->gc,x,y,current->ww,current->wh,0,0);
+ XSync(display,False);
+ }
+ else
+ {
+ XCopyArea(display,current->pm[current->pmi],current->w,
+ current->gc,x,y,current->ww,current->wh,0,0);
+ XSync(display,False);
+ }
+
+ WM(current->lastuserfunc);
+}
+
+
+Pixmap GetCurrentPixmap(void)
+
+{
+ if (!current->use_pm)
+ return(0);
+
+ return current->pm[current->pmi];
+}
+
+GC GetCurrentGC(void)
+
+{
+ return current->gc;
+}
+
+
+void DisableDoubleBuffer(void)
+
+{
+ current->pmi=0;
+ XFreePixmap(display,current->pm[1]);
+ current->buffer=False;
+}
+
+
+void DisablePixmap(void)
+
+{
+ current->pmi=0;
+
+ if (current->use_pm)
+ XFreePixmap(display,current->pm[0]);
+
+ if (current->buffer)
+ XFreePixmap(display,current->pm[1]);
+
+ current->buffer=False;
+ current->use_pm=False;
+ current->pm[0]=current->w;
+}
+
+
+void DisableShm(void)
+{
+ use_shm=False;
+}
+
+
+void EnableBuffers(int no, ulong clscol)
+{
+ int f;
+
+ current->pmi=0;
+
+ if (current->use_pm)
+ XFreePixmap(display,current->pm[0]);
+
+ if (current->buffer)
+ XFreePixmap(display,current->pm[1]);
+
+ current->buffer=False;
+ current->use_pm=True;
+ current->multi=True;
+
+ if (no>MAXPM)
+ current->multino=MAXPM;
+ else
+ current->multino=no;
+
+ current->multicls=clscol;
+
+ WM(GXcopy);
+ FG(current->multicls);
+ for(f=0;f<current->multino;f++)
+ {
+ current->pm[f]=XCreatePixmap(display,current->w,current->ww,current->wh,
+ vinfo.depth);
+ XFillRectangle(display,current->pm[f],
+ current->gc,0,0,current->pw,current->ph);
+ }
+
+ WM(current->lastuserfunc);
+}
+
+
+void Pageflip(void)
+{
+ if (current->buffer)
+ current->pmi=current->pmi^1;
+
+ if (current->multi)
+ if ((++current->pmi)>=current->multino)
+ current->pmi=0;
+}
+
+
+void SetAsBackdrop(void)
+{
+ XSetWindowBackgroundPixmap (display, current->w, current->pm[current->pmi]);
+ XSync(display,False);
+}
+
+
+void XUseFunction(int f)
+{
+ WM(f);
+ current->lastuserfunc=f;
+}
+
+
+void XSetLineStyle(unsigned int w, int ls, int cs, int js)
+{
+ XSetLineAttributes(display,current->gc,w,ls,cs,js);
+}
+
+
+void XCls(ulong c)
+{
+ if (current->use_pm)
+ {
+ WM(GXcopy);
+ FG(c);
+ XFillRectangle(display,current->pm[current->pmi],
+ current->gc,0,0,current->pw,current->ph);
+ WM(current->lastuserfunc);
+ }
+ else
+ {
+ /*
+ XSetBackground(display,current->gc,c);
+ XClearWindow(display,current->pm[0]);
+ */
+ WM(GXcopy);
+ FG(c);
+ XFillRectangle(display,current->pm[current->pmi],
+ current->gc,0,0,current->pw,current->ph);
+ WM(current->lastuserfunc);
+ }
+}
+
+
+void XPlot(int x,int y, ulong c)
+{
+ FG(c);
+ XDrawPoint(display,current->pm[current->pmi],current->gc,x,y);
+}
+
+
+void XLine(int x1,int y1,int x2,int y2, ulong c)
+{
+ FG(c);
+ XDrawLine(display,current->pm[current->pmi],current->gc,x1,y1,x2,y2);
+}
+
+
+void SetSplineThresh(int t)
+{
+ current->spline_thresh=t;
+}
+
+
+static void XDoSpline(int x0,int y0,int x1,int y1,int x2,int y2,ulong c)
+{
+ int xa, ya, xb, yb, xc, yc, xp, yp;
+
+ if ((x0==x1==x2)&&(y0==y1==y2))
+ {
+ XPlot(x0,y0,c);
+ return;
+ }
+
+ if ((x0==x1)&&(y0==y1))
+ {
+ XLine(x1,y1,x2,y2,c);
+ return;
+ }
+
+ if ((x0==x2)&&(y0==y2))
+ {
+ XLine(x0,y0,x1,y1,c);
+ return;
+ }
+
+ if ((x1==x2)&&(y1==y2))
+ {
+ XLine(x0,y0,x2,y2,c);
+ return;
+ }
+
+ xa = ( x0 + x1 ) / 2;
+ ya = ( y0 + y1 ) / 2;
+ xc = ( x1 + x2 ) / 2;
+ yc = ( y1 + y2 ) / 2;
+ xb = ( xa + xc ) / 2;
+ yb = ( ya + yc ) / 2;
+
+ xp = ( x0 + xb ) / 2;
+ yp = ( y0 + yb ) / 2;
+
+ if ( ABS( xa - xp ) + ABS( ya - yp ) > current->spline_thresh )
+ XDoSpline(x0,y0,xa,ya,xb,yb,c);
+ else
+ XDrawLine(display,current->pm[current->pmi],current->gc,x0,y0,xb,yb);
+
+ xp = ( x2 + xb ) / 2;
+ yp = ( y2 + yb ) / 2;
+ if ( ABS( xc - xp ) + ABS( yc - yp ) > current->spline_thresh )
+ XDoSpline(xb,yb,xc,yc,x2,y2,c);
+ else
+ XDrawLine(display,current->pm[current->pmi],current->gc,xb,yb,x2,y2);
+}
+
+
+void XSpline(int x1,int y1,int x2,int y2,int x3,int y3,ulong c)
+{
+ FG(c);
+
+ if ((x1==x2==x3)&&(y1==y2==y3))
+ {
+ XPlot(x1,y1,c);
+ return;
+ }
+
+ if ((x1==x2)&&(y1==y2))
+ {
+ XLine(x2,y2,x3,y3,c);
+ return;
+ }
+
+ if ((x1==x3)&&(y1==y3))
+ {
+ XLine(x1,y1,x2,y2,c);
+ return;
+ }
+
+ if ((x2==x3)&&(y2==y3))
+ {
+ XLine(x1,y1,x3,y3,c);
+ return;
+ }
+
+ XDoSpline(x1,y1,x2,y2,x3,y3,c);
+}
+
+
+void XPrint(int x,int y, const char *s, ulong c)
+
+{
+ FG(c);
+ XDrawString(display,current->pm[current->pmi],current->gc,x,y,s,strlen(s));
+}
+
+
+void Xprintf(int x, int y, ulong colour, const char *fmt, ...)
+{
+ va_list va;
+
+ va_start(va,fmt);
+ vsprintf(prbuf,fmt,va);
+ va_end(va);
+
+ FG(colour);
+ XDrawString(display,current->pm[current->pmi],current->gc,
+ x,y,prbuf,strlen(prbuf));
+}
+
+
+void XISetFont(XImageFont n)
+{
+ switch(n)
+ {
+ case XI_FONT1:
+ xifont=xifont1;
+ break;
+ case XI_FONT2:
+ xifont=xifont2;
+ break;
+ }
+}
+
+
+static void XIPlot(XImage *img,int x,int y, ulong c)
+{
+ if ((y<0)||(y>=img->height)||(x<0)||(x>=img->width))
+ return;
+
+ XPutPixel(img,x,y,c);
+}
+
+
+void XIprintf(XImage *img, int x, int y, int sx, int sy, ulong col,
+ const char *fmt, ...)
+{
+ int f,px,py,psx,psy,ch;
+ char *data;
+ va_list arg;
+
+ va_start(arg,fmt);
+ vsprintf(prbuf,fmt,arg);
+ va_end(arg);
+
+ if ((sx==1)&&(sy==1))
+ {
+ for(f=0;f<strlen(prbuf);f++)
+ {
+ ch=prbuf[f];
+
+ for(py=0;py<XIFONTH;py++)
+ if ((y+py>=0)&&(y+py<img->height))
+ for(px=0;px<XIFONTW;px++)
+ if ((x+px>=0)&&(x+px<img->width))
+ if (xifont[ch].data[py][px])
+ XPutPixel(img,x+px,y+py,col);
+
+ x+=XIFONTW;
+ }
+ }
+ else
+ {
+ for(f=0;f<strlen(prbuf);f++)
+ {
+ ch=prbuf[f];
+
+ for(py=0;py<XIFONTH;py++)
+ for(px=0;px<XIFONTW;px++)
+ if (xifont[ch].data[py][px])
+ for(psx=0;psx<sx;psx++)
+ for(psy=0;psy<sy;psy++)
+ XPutPixel(img,x+px*sx+psx,y+py*sy+psy,col);
+
+ x+=XIFONTW*sx;
+ }
+ }
+}
+
+
+void XBox(int x,int y,int w,int h,ulong c)
+{
+ FG(c);
+ XDrawRectangle(display,current->pm[current->pmi],current->gc,x,y,w,h);
+}
+
+
+void XFillBox(int x,int y,int w,int h,ulong c)
+{
+ FG(c);
+ XFillRectangle(display,current->pm[current->pmi],current->gc,x,y,w,h);
+}
+
+
+void XCircle(int x,int y,int rx,int ry,int a1,int a2,ulong c)
+{
+ FG(c);
+ XDrawArc(display,current->pm[current->pmi],current->gc,x,y,rx,ry,a1,a2);
+}
+
+
+void XFillCircle(int x,int y,int rx,int ry,int a1,int a2,ulong c)
+{
+ FG(c);
+ XFillArc(display,current->pm[current->pmi],current->gc,x,y,rx,ry,a1,a2);
+}
+
+
+void XStartPlots(void)
+{
+ no_plots=0;
+}
+
+
+void XAddPlot(int x,int y)
+{
+ points[no_plots].x=x;
+ points[no_plots].y=y;
+
+ no_plots++;
+}
+
+
+void XPutPlots(ulong c)
+{
+ FG(c);
+ XDrawPoints(display,current->pm[current->pmi],current->gc,
+ points,no_plots,CoordModeOrigin);
+}
+
+
+void XPutPlotsAsLines(ulong c)
+{
+ FG(c);
+ XDrawLines(display,current->pm[current->pmi],current->gc,
+ points,no_plots,CoordModeOrigin);
+}
+
+
+void XFillPoly(XPoint *xp,int n,int shape,ulong c)
+{
+ FG(c);
+ XFillPolygon(display,current->pm[current->pmi],current->gc,xp,n,
+ shape,CoordModeOrigin);
+}
+
+
+void XScroll(int dx,int dy)
+{
+ int destx,desty,srcx,srcy;
+ int w,h;
+
+ if (dx>=0)
+ {
+ destx=0;
+ srcx=dx;
+ w=current->pw-dx;
+ }
+
+ if (dx<0)
+ {
+ destx=-(dx);
+ srcx=0;
+ w=current->pw+dx;
+ }
+
+ if (dy>=0)
+ {
+ desty=0;
+ srcy=dy;
+ h=current->ph-dy;
+ }
+
+ if (dy<0)
+ {
+ desty=-(dy);
+ srcy=0;
+ h=current->ph+dy;
+ }
+
+ WM(GXcopy);
+ XCopyArea(display,current->pm[current->pmi],current->pm[current->pmi],
+ current->gc,srcx,srcy,current->pw-dx,current->ph,destx,desty);
+ WM(current->lastuserfunc);
+}
+
+
+void XCopy(int sx,int sy,int w,int h,int dx,int dy)
+{
+ WM(GXcopy);
+ XCopyArea(display,current->pm[current->pmi],current->pm[current->pmi],
+ current->gc,sx,sy,current->pw,current->ph,dx,dy);
+ WM(current->lastuserfunc);
+}
+
+
+void XPut(Pixmap spm,int sx,int sy,int w,int h,int dx,int dy)
+{
+ WM(GXcopy);
+ XCopyArea(display,spm,current->pm[current->pmi],
+ current->gc,sx,sy,w,h,dx,dy);
+ WM(current->lastuserfunc);
+}
+
+
+void XGet(Pixmap dpm,int sx,int sy,int w,int h,int dx,int dy)
+{
+ WM(GXcopy);
+ XCopyArea(display,dpm,current->pm[current->pmi],
+ current->gc,sx,sy,w,h,dx,dy);
+ WM(current->lastuserfunc);
+}
+
+
+void ScreenCopy(void)
+{
+ if (current->buffer)
+ {
+ WM(GXcopy);
+ XCopyArea(display,current->pm[current->pmi^1],
+ current->pm[current->pmi],current->gc,0,0,
+ current->pw,current->ph,0,0);
+ WM(current->lastuserfunc);
+ }
+}
+
+
+Display *GetDisplay(void)
+{
+ return display;
+}
+
+
+
+void XFinished(void)
+{
+ XCloseDisplay(display);
+}
+
+
+void XDoTillButtonPress(XVoidCallback func)
+{
+ XEvent event;
+ int ignore=True;
+
+ while (True)
+ if (XPending(display))
+ {
+ XNextEvent(display,&event);
+
+ switch (event.type)
+ {
+ case Expose:
+ if (event.xexpose.count)
+ break;
+ Redraw(current->ox,current->oy);
+ break;
+
+ case ButtonPress:
+ if (event.xbutton.button)
+ if (!ignore)
+ return;
+ break;
+ }
+ }
+ else
+ if (func)
+ switch (func())
+ {
+ case XFUNCCONT:
+ ignore=False;
+ break;
+
+ case XFUNCIGNORE:
+ ignore=True;
+ break;
+
+ case XFUNCSTOP:
+ return;
+ break;
+ }
+
+}
+
+
+void XDoMouse(XButtonCallback button, XMoveCallBack move, XVoidCallback process)
+{
+ XEvent event;
+
+ while (True)
+ if ((XPending(display))||(!process))
+ {
+ XNextEvent(display,&event);
+
+ switch (event.type)
+ {
+ case Expose:
+ if (event.xexpose.count)
+ break;
+ Redraw(current->ox,current->oy);
+ break;
+
+ case MotionNotify:
+ if (move)
+ switch(move(event.xmotion.window,
+ event.xmotion.x,event.xmotion.y))
+ {
+ case XFUNCSTOP:
+ return;
+ break;
+ }
+ break;
+
+ case ButtonPress:
+ if (button)
+ switch(button(event.xbutton.window,XPRESS,
+ event.xbutton.button,
+ event.xbutton.x,event.xbutton.y))
+ {
+ case XFUNCSTOP:
+ return;
+ break;
+ }
+ break;
+ }
+ }
+ else
+ if (process)
+ switch (process())
+ {
+ case XFUNCCONT:
+ case XFUNCIGNORE:
+ break;
+
+ case XFUNCSTOP:
+ return;
+ break;
+ }
+
+}
+
+
+static int IsMoveWin(Window w, XWindowMoveCallBack call[] ,int *i)
+{
+ int f;
+
+ if (!call)
+ {
+ return(False);
+ }
+
+ f=0;
+
+ while(call[f].w)
+ {
+ if (call[f].w==w)
+ {
+ *i=f;
+ return call[f].func ? True:False;
+ }
+ else
+ {
+ f++;
+ }
+ }
+
+ return False;
+}
+
+
+static int IsButtonWin(Window w, XWindowButtonCallback call[] ,int *i)
+{
+ int f;
+
+ if (!call)
+ {
+ return(False);
+ }
+
+ f=0;
+
+ while(call[f].w)
+ {
+ if (call[f].w==w)
+ {
+ *i=f;
+ return call[f].func ? True:False;
+ }
+ else
+ {
+ f++;
+ }
+ }
+
+ return False;
+}
+
+
+static int IsKeyWin(Window w, XWindowKeyCallback call[] ,int *i)
+{
+ int f;
+
+ if (!call)
+ {
+ return(False);
+ }
+
+ f=0;
+
+ while(call[f].w)
+ {
+ if (call[f].w==w)
+ {
+ *i=f;
+ return call[f].func ? True:False;
+ }
+ else
+ {
+ f++;
+ }
+ }
+
+ return False;
+}
+
+
+void XDoWindows(XWindowButtonCallback button[],
+ XWindowMoveCallBack move[],
+ XWindowKeyCallback key[],
+ XVoidCallback process)
+{
+ int i;
+ XEvent event;
+
+ while (True)
+ if ((XPending(display))||(!process))
+ {
+ XNextEvent(display,&event);
+
+ switch (event.type)
+ {
+ case Expose:
+ if (event.xexpose.count)
+ break;
+
+ PUSHW;
+ SetCurrentWin(event.xexpose.window);
+ Redraw(current->ox,current->oy);
+ POPW;
+
+ break;
+
+ case MotionNotify:
+ if (IsMoveWin(event.xmotion.window,move,&i))
+ {
+ switch(move[i].func(event.xmotion.window,
+ event.xmotion.x,
+ event.xmotion.y))
+ {
+ case XFUNCSTOP:
+ return;
+ break;
+ }
+ }
+ break;
+
+ case ButtonPress:
+ if (IsButtonWin(event.xbutton.window,button,&i))
+ {
+ switch(button[i].func
+ (event.xbutton.window,
+ XPRESS,
+ event.xbutton.button,
+ event.xbutton.x,event.xbutton.y))
+ {
+ case XFUNCSTOP:
+ return;
+ break;
+ }
+ }
+ break;
+
+ case ButtonRelease:
+ if (IsButtonWin(event.xbutton.window,button,&i))
+ {
+ switch(button[i].func
+ (event.xbutton.window,
+ XRELEASE,
+ event.xbutton.button,
+ event.xbutton.x,event.xbutton.y))
+ {
+ case XFUNCSTOP:
+ return;
+ break;
+ }
+ }
+ break;
+
+ case KeyPress:
+ if (IsKeyWin(event.xkey.window,key,&i))
+ {
+ switch(key[i].func(event.xkey.window,
+ XPRESS,
+ &event))
+ {
+ case XFUNCSTOP:
+ return;
+ break;
+ }
+ }
+ break;
+
+ case KeyRelease:
+ if (IsKeyWin(event.xkey.window,key,&i))
+ {
+ switch(key[i].func(event.xkey.window,
+ XRELEASE,
+ &event))
+ {
+ case XFUNCSTOP:
+ return;
+ break;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ else
+ if (process)
+ {
+ switch (process())
+ {
+ case XFUNCCONT:
+ case XFUNCIGNORE:
+ break;
+
+ case XFUNCSTOP:
+ return;
+ break;
+ }
+ }
+}
+
+
+/* Sprite routines */
+void LoadSprite(const char *fn, XSprite *spr, const XColor xc[256])
+{
+ Pixmap piximg,pixmask,pixsave;
+ int fd,x,y;
+ char magic[11];
+ unsigned char *data,*p;
+ unsigned short us;
+ GC gc;
+
+ if ((fd=open(fn,O_RDONLY))==-1)
+ {
+ WARN1("Couldn't open sprite file",fn);
+ return;
+ }
+
+ read(fd,magic,11);
+
+ if (strncmp(magic,"XbitSprite",10))
+ {
+ WARN1(fn,"is not a sprite file!");
+ close(fd);
+ return;
+ }
+
+ spr->x=spr->y=0;
+
+ read(fd,&us,sizeof(unsigned short));
+ spr->w=ntohs(us);
+ read(fd,&us,sizeof(unsigned short));
+ spr->h=ntohs(us);
+
+ if (!(data=malloc(spr->w*spr->h)))
+ {
+ WARN("Couldn't grab memory for sprite image");
+ close(fd);
+ return;
+ }
+
+ if (read(fd,data,spr->w*spr->h)!=spr->w*spr->h)
+ {
+ WARN("Couldn't load sprite image");
+ close(fd);
+ free(data);
+ return;
+ }
+
+ close(fd);
+
+ gc=XCreateGC(display,current->w,0,NULL);
+
+ XSetPlaneMask(display,gc,AllPlanes);
+ XSetGraphicsExposures(display,gc,False);
+
+ piximg=XCreatePixmap(display,current->w,spr->w,spr->h,vinfo.depth);
+ pixmask=XCreatePixmap(display,current->w,spr->w,spr->h,vinfo.depth);
+ pixsave=XCreatePixmap(display,current->w,spr->w,spr->h,vinfo.depth);
+
+ p=data;
+
+ for(y=0;y<spr->h;y++)
+ {
+ for(x=0;x<spr->w;x++)
+ {
+ XSetForeground(display,gc,xc[*p].pixel);
+ XDrawPoint(display,piximg,gc,x,y);
+
+ if (*p)
+ XSetForeground(display,gc,xb_white);
+ else
+ XSetForeground(display,gc,xb_black);
+
+ XDrawPoint(display,pixmask,gc,x,y);
+
+ p++;
+ }
+ }
+
+ spr->data=piximg;
+ spr->mask=pixmask;
+ spr->save=pixsave;
+
+ free(data);
+}
+
+
+void XDrawSprites(XSprite *spr[],int no, XSpriteControl ctl)
+{
+ int f;
+
+ WM(GXcopy);
+
+ if (!(ctl&XSPRNOSAVE))
+ for(f=0;f<no;f++)
+ if (current->buffer)
+ {
+ spr[f]->lx=spr[f]->x;
+ spr[f]->ly=spr[f]->y;
+ XCopyArea(display,current->pm[current->pmi^1],
+ spr[f]->save,current->gc,spr[f]->x,spr[f]->y,
+ spr[f]->w,spr[f]->h,0,0);
+ }
+ else
+ {
+ spr[f]->lx=spr[f]->x;
+ spr[f]->ly=spr[f]->y;
+ XCopyArea(display,current->pm[current->pmi],
+ spr[f]->save,current->gc,spr[f]->x,spr[f]->y,
+ spr[f]->w,spr[f]->h,0,0);
+ }
+
+ WM(GXand);
+ for(f=0;f<no;f++)
+ if (current->buffer)
+ XCopyArea(display,spr[f]->mask,current->pm[current->pmi^1],
+ current->gc,0,0,
+ spr[f]->w,spr[f]->h,spr[f]->x,spr[f]->y);
+ else
+ XCopyArea(display,spr[f]->mask,current->pm[current->pmi],
+ current->gc,0,0,
+ spr[f]->w,spr[f]->h,spr[f]->x,spr[f]->y);
+
+ WM(GXor);
+ for(f=0;f<no;f++)
+ if (current->buffer)
+ XCopyArea(display,spr[f]->data,current->pm[current->pmi^1],
+ current->gc,0,0,
+ spr[f]->w,spr[f]->h,spr[f]->x,spr[f]->y);
+ else
+ XCopyArea(display,spr[f]->data,current->pm[current->pmi],
+ current->gc,0,0,
+ spr[f]->w,spr[f]->h,spr[f]->x,spr[f]->y);
+
+ WM(current->lastuserfunc);
+}
+
+
+void XEraseSprites(XSprite *spr[],int no)
+{
+ int f;
+
+ WM(GXcopy);
+
+ for(f=0;f<no;f++)
+ if (current->buffer)
+ XCopyArea(display,spr[f]->save,current->pm[current->pmi^1],
+ current->gc,0,0,
+ spr[f]->w,spr[f]->h,spr[f]->lx,spr[f]->ly);
+ else
+ XCopyArea(display,spr[f]->save,current->pm[current->pmi],
+ current->gc,0,0,
+ spr[f]->w,spr[f]->h,spr[f]->lx,spr[f]->ly);
+
+ WM(current->lastuserfunc);
+}
+
+
+void LoadColormap(const char *fn, XColor xc[256])
+{
+ int fd,f;
+ unsigned short us;
+
+ if ((fd=open(fn,O_RDONLY))==-1)
+ {
+ WARN1("Couldn't open cmap",fn);
+ return;
+ }
+
+ for(f=0;f<256;f++)
+ {
+ xc[f].flags=DoRed|DoGreen|DoBlue;
+ read(fd,&us,sizeof(unsigned short));
+ xc[f].red=ntohs(us);
+ read(fd,&us,sizeof(unsigned short));
+ xc[f].green=ntohs(us);
+ read(fd,&us,sizeof(unsigned short));
+ xc[f].blue=ntohs(us);
+
+ XAllocColor(display,DefaultColormap(display,screen),xc + f);
+ }
+}
+
+
+void AllocColors(int no,ulong pix[],const char *name[])
+{
+ int f,col;
+ XColor xc;
+
+ for(f=0;f<no;f++)
+ {
+ if (XParseColor(display,DefaultColormap(display,screen),name[f],&xc))
+ {
+ if (XAllocColor(display,DefaultColormap(display,screen),&xc))
+ pix[f]=xc.pixel;
+ else
+ {
+ WARN1("couldn't allocate",name[f]);
+
+ col=0;
+
+ if (xc.flags&DoRed)
+ col+=xc.red;
+
+ if (xc.flags&DoBlue)
+ col+=xc.blue;
+
+ if (xc.flags&DoGreen)
+ col+=xc.green;
+
+ if (col>(0x8000*3))
+ {
+ WARN("defaulting to white");
+ pix[f]=WhitePixel(display,screen);
+ }
+ else
+ {
+ WARN("defaulting to black");
+ pix[f]=BlackPixel(display,screen);
+ }
+ }
+ }
+ else
+ {
+ WARN1("not a color ",name[f]);
+ pix[f]=WhitePixel(display,screen);
+ }
+ }
+}
+
+
+void AllocColorsRGB(int no, ulong pix[], const Colour col[])
+{
+ int f;
+ XColor xc;
+
+ for(f=0;f<no;f++)
+ {
+ xc.red=col[f].r;
+ xc.green=col[f].g;
+ xc.blue=col[f].b;
+ xc.flags=DoRed|DoBlue|DoGreen;
+
+ if (XAllocColor(display,DefaultColormap(display,screen),&xc))
+ pix[f]=xc.pixel;
+ else
+ {
+ WARN("couldn't allocate RGB color");
+
+ if ((col[f].r+col[f].g+col[f].b)>(0x8000*3))
+ {
+ WARN("defaulting to white");
+ pix[f]=WhitePixel(display,screen);
+ }
+ else
+ {
+ WARN("defaulting to black");
+ pix[f]=BlackPixel(display,screen);
+ }
+ }
+ }
+}
+
+
+void LoadSpriteDataSet (const char *cmapfn,
+ const char *sprfn[],
+ SpriteDataSet *set)
+{
+ int f,r,fd;
+ char magic[11];
+ XColor xcol[256];
+ Colour col[256];
+ SpriteData *spr;
+ int no;
+ int used[256];
+ unsigned short us;
+ unsigned char byte;
+
+
+ /* Allocate referenced table
+ */
+ for(f=0;f<256;f++)
+ used[f]=-1;
+
+ /* Count and allocate referenced sprites
+ */
+ no=0;
+ while(sprfn[no])
+ no++;
+
+ /* Load in colourmap
+ */
+ LoadColormap(cmapfn,xcol);
+
+ set->no_col=0;
+ set->no_spr=no;
+
+ /* Load in sprites and sort out colour usage
+ */
+ spr=malloc(sizeof(SpriteData)*no);
+
+ for(f=0;f<no;f++)
+ {
+ if ((fd=open(sprfn[f],O_RDONLY))==-1)
+ {
+ WARN1("Couldn't open sprite file",sprfn[f]);
+ exit(1);
+ return;
+ }
+
+ read(fd,magic,11);
+
+ if (strncmp(magic,"XbitSprite",10))
+ {
+ WARN1(sprfn[f],"is not a sprite file!");
+ exit(1);
+ return;
+ }
+
+ read(fd,&us,sizeof(unsigned short));
+ spr[f].w=ntohs(us);
+ read(fd,&us,sizeof(unsigned short));
+ spr[f].h=ntohs(us);
+
+ if (!(spr[f].data=malloc(spr[f].w*spr[f].h)))
+ {
+ WARN("Couldn't grab memory for sprite image");
+ exit(1);
+ }
+
+ /* Read through pixel values, stacking up colour definitions as neeed
+ */
+ for(r=0;r<(spr[f].w*spr[f].h);r++)
+ {
+ read(fd,&byte,1);
+
+ if (used[byte]==-1)
+ {
+ col[set->no_col].r=xcol[byte].red;
+ col[set->no_col].g=xcol[byte].green;
+ col[set->no_col].b=xcol[byte].blue;
+
+ used[byte]=set->no_col++;
+ }
+
+ spr[f].data[r]=used[byte];
+ }
+
+ close(fd);
+ }
+
+ /* Got all sprites - allocate and remap colours
+ */
+ AllocColoursRGB(set->no_col,set->pix,col);
+
+ /* Remap sprites
+ */
+ for(f=0;f<no;f++)
+ for(r=0;r<(spr[f].w*spr[f].h);r++)
+ spr[f].data[r]=set->pix[spr[f].data[r]];
+
+ /* Set up return, all done
+ */
+ set->spr=spr;
+}
+
+
+/* END OF FILE */