diff options
author | Josip Rodin <jrodin@jagor.srce.hr> | 1999-06-15 14:49:16 -0700 |
---|---|---|
committer | Josip Rodin <jrodin@jagor.srce.hr> | 1999-06-15 14:49:16 -0700 |
commit | b4340e99efb5486fb66c0d4d9348b967dc039a3a (patch) | |
tree | 9f87c02bf18a1a4bcad920d6c488e8523b667ba3 /libXg |
Import wily_0.13.41.orig.tar.gz
[dgit import orig wily_0.13.41.orig.tar.gz]
Diffstat (limited to 'libXg')
42 files changed, 4761 insertions, 0 deletions
diff --git a/libXg/Gwin.h b/libXg/Gwin.h new file mode 100644 index 0000000..416d868 --- /dev/null +++ b/libXg/Gwin.h @@ -0,0 +1,47 @@ +/* Copyright (c) 1992 AT&T - All rights reserved. */ +#ifndef GWIN_H +#define GWIN_H + +/* New resource names */ + +#define XtNscrollForwardR "scrollForwardR" +#define XtCScrollForwardR "ScrollForwardR" +#define XtNreshaped "reshaped" +#define XtCReshaped "Reshaped" +#define XtNgotchar "gotchar" +#define XtCGotchar "Gotchar" +#define XtNgotmouse "gotmouse" +#define XtCGotmouse "Gotmouse" +#define XtNp9font "p9font" +#define XtCP9font "P9font" +#define XtNp9fixed "p9fixed" +#define XtCP9fixed "P9fixed" +#define XtNcomposeMod "composeMod" +#define XtCComposeMod "ComposeMod" + +/* External reference to the class record pointer */ +extern WidgetClass gwinWidgetClass; + +/* Type definition for gwin widgets */ +typedef struct _GwinRec *GwinWidget; + +/* Type definition for gwin resources */ +typedef struct { + int buttons; + struct { + int x; + int y; + } xy; + unsigned long msec; + } Gwinmouse; + +typedef void (*Reshapefunc)(int, int, int, int); +typedef void (*Charfunc)(int); +typedef void (*Mousefunc)(Gwinmouse*); + +/* Method declarations */ +extern String GwinSelectionSwap(Widget, String); +extern char* Gwinselect_get(Widget w); +extern void Gwinselect_put(Widget w,char*s); + +#endif /* GWIN_H */ diff --git a/libXg/GwinP.h b/libXg/GwinP.h new file mode 100644 index 0000000..e664c0d --- /dev/null +++ b/libXg/GwinP.h @@ -0,0 +1,48 @@ +/* Copyright (c) 1992 AT&T - All rights reserved. */ +#ifndef GWINP_H +#define GWINP_H + +#include "Gwin.h" + +/* Gwin is derived from Core */ + +/* Gwin instance part */ +typedef struct { + /* New resource fields */ + Pixel foreground; + Font font; + Boolean forwardr; /* does right button scroll forward? */ + Reshapefunc reshaped; /* Notify app of reshape */ + Charfunc gotchar; /* Notify app of char arrival */ + Mousefunc gotmouse; /* Notify app of mouse change */ + String selection; /* Current selection */ + String p9font; + String p9fixed; + int compose; +} GwinPart; + +/* Full instance record */ +typedef struct _GwinRec { + CorePart core; + GwinPart gwin; +} GwinRec; + +/* New type for class methods */ +typedef String (*SelSwapProc)(Widget, String); + +/* Class part */ +typedef struct { + SelSwapProc select_swap; + XtPointer extension; +} GwinClassPart; + +/* Full class record */ +typedef struct _GwinClassRec { + CoreClassPart core_class; + GwinClassPart gwin_class; +} GwinClassRec, *GwinWidgetClass; + +/* External definition for class record */ +extern GwinClassRec gwinClassRec; + +#endif /* GWINP_H */ diff --git a/libXg/Makefile.in b/libXg/Makefile.in new file mode 100644 index 0000000..1a6c27b --- /dev/null +++ b/libXg/Makefile.in @@ -0,0 +1,15 @@ +srcdir=@srcdir@ +VPATH=@srcdir@ +CC=@CC@ +RANLIB=@RANLIB@ +INCLUDES=$(srcdir)/../include +CFLAGS=@CFLAGS@ -I.. -I$(INCLUDES) @X_CFLAGS@ +LIB=libXg.a +OBJS=arc.o arith.o balloc.o bitblt.o bitbltclip.o border.o bscreenrect.o\ + circle.o clipline.o clipr.o copymasked.o cursorset.o cursorswitch.o\ + disc.o ellipse.o font.o gcs.o getrect.o gwin.o ldconvert.o latin1.o\ + mkfont.o menuhit.o point.o polysegment.o rdbitmap.o rdbitmapfile.o\ + rdfontfile.o rectclip.o rune.o segment.o string.o strwidth.o texture.o\ + wrbitmap.o wrbitmapfile.o xtbinit.o +include $(INCLUDES)/Makelib +$(OBJS): $(INCLUDES)/u.h $(INCLUDES)/libc.h $(INCLUDES)/libg.h diff --git a/libXg/arc.c b/libXg/arc.c new file mode 100644 index 0000000..44a8282 --- /dev/null +++ b/libXg/arc.c @@ -0,0 +1,44 @@ +/* Copyright (c) 1992 AT&T - All rights reserved. */ +#include <libc.h> +#include <libg.h> +#include "libgint.h" +#include <math.h> + +#define rad2deg(x) 180*((x)/3.1415926535897932384626433832795028841971693993751) + +void +arc(Bitmap *b, Point p0, Point p1, Point p2, int v, Fcode f) +{ + unsigned int d; + int x, y, r, start, end, delta; + GC g; + + p1.x -= p0.x; + p1.y -= p0.y; + p2.x -= p0.x; + p2.y -= p0.y; + r = (int)sqrt((double)(p1.x*p1.x + p1.y*p1.y)); + start = (int)(64*rad2deg(atan2(-p2.y, p2.x))); + end = (int)(64*rad2deg(atan2(-p1.y, p1.x))); + if(start < 0) + start += 64*360; + if(end < 0) + end += 64*360; + delta = end - start; + if(delta < 0) + delta += 64*360; + x = p0.x - r; + y = p0.y - r; + if(b->flag&SHIFT){ + x -= b->r.min.x; + y -= b->r.min.y; + } + d = 2*r; + g = _getfillgc(f, b, v); + /* + * delta is positive, so this draws counterclockwise arc + * from start to start+delta + */ + XDrawArc(_dpy, (Drawable)b->id, g, x, y, d, d, start, delta); +} + diff --git a/libXg/arith.c b/libXg/arith.c new file mode 100644 index 0000000..5cf6f65 --- /dev/null +++ b/libXg/arith.c @@ -0,0 +1,190 @@ +/* Copyright (c) 1992 AT&T - All rights reserved. */ +#include <libc.h> +#include <libg.h> + +Point +add(Point a, Point b) +{ + a.x += b.x; + a.y += b.y; + return a; +} + +Point +sub(Point a, Point b) +{ + a.x -= b.x; + a.y -= b.y; + return a; +} + +Rectangle +inset(Rectangle r, int n) +{ + r.min.x += n; + r.min.y += n; + r.max.x -= n; + r.max.y -= n; + return r; +} + +Point +divpt(Point a, int b) +{ + a.x /= b; + a.y /= b; + return a; +} + +Point +mul(Point a, int b) +{ + a.x *= b; + a.y *= b; + return a; +} + +Rectangle +rsubp(Rectangle r, Point p) +{ + r.min.x -= p.x; + r.min.y -= p.y; + r.max.x -= p.x; + r.max.y -= p.y; + return r; +} + +Rectangle +raddp(Rectangle r, Point p) +{ + r.min.x += p.x; + r.min.y += p.y; + r.max.x += p.x; + r.max.y += p.y; + return r; +} + +Rectangle +rmul(Rectangle r, int a) +{ + if (a != 1) { + r.min.x *= a; + r.min.y *= a; + r.max.x *= a; + r.max.y *= a; + } + return r; +} + +Rectangle +rdiv(Rectangle r, int a) +{ + if (a != 1) { + r.min.x /= a; + r.min.y /= a; + r.max.x /= a; + r.max.y /= a; + } + return r; +} + +Rectangle +rshift(Rectangle r, int a) +{ + if (a > 0) { + r.min.x <<= a; + r.min.y <<= a; + r.max.x <<= a; + r.max.y <<= a; + } + else if (a < 0) { + a = -a; + r.min.x >>= a; + r.min.y >>= a; + r.max.x >>= a; + r.max.y >>= a; + } + return r; +} + +eqpt(Point p, Point q) +{ + return p.x==q.x && p.y==q.y; +} + +eqrect(Rectangle r, Rectangle s) +{ + return r.min.x==s.min.x && r.max.x==s.max.x && + r.min.y==s.min.y && r.max.y==s.max.y; +} + +rectXrect(Rectangle r, Rectangle s) +{ + return r.min.x<s.max.x && s.min.x<r.max.x && + r.min.y<s.max.y && s.min.y<r.max.y; +} + +int +rectinrect(Rectangle r, Rectangle s) +{ + /* !ptinrect(r.min, s) in line for speed */ + if(!(r.min.x>=s.min.x && r.min.x<s.max.x && + r.min.y>=s.min.y && r.min.y<s.max.y)) + return 0; + return r.max.x<=s.max.x && r.max.y<=s.max.y; +} + +ptinrect(Point p, Rectangle r) +{ + return p.x>=r.min.x && p.x<r.max.x && + p.y>=r.min.y && p.y<r.max.y; +} + +Rectangle +rcanon(Rectangle r) +{ + int t; + if (r.max.x < r.min.x) { + t = r.min.x; + r.min.x = r.max.x; + r.max.x = t; + } + if (r.max.y < r.min.y) { + t = r.min.y; + r.min.y = r.max.y; + r.max.y = t; + } + return r; +} + +Rectangle +Rect(int x1, int y1, int x2, int y2) +{ + Rectangle r; + + r.min.x = x1; + r.min.y = y1; + r.max.x = x2; + r.max.y = y2; + return r; +} + +Rectangle +Rpt(Point p1, Point p2) +{ + Rectangle r; + + r.min = p1; + r.max = p2; + return r; +} + +Point +Pt(int x, int y) +{ + Point p; + + p.x = x; + p.y = y; + return p; +} diff --git a/libXg/balloc.c b/libXg/balloc.c new file mode 100644 index 0000000..a9d243e --- /dev/null +++ b/libXg/balloc.c @@ -0,0 +1,59 @@ +/* Copyright (c) 1992 AT&T - All rights reserved. */ +#include <libc.h> +#include <libg.h> +#include "libgint.h" + +Bitmap* +balloc(Rectangle r, int ldepth) +{ + Bitmap *b; + + b = _balloc(r, ldepth); + bitblt(b, r.min, b, r, Zero); + return b; +} + +Bitmap* +_balloc(Rectangle r, int ldepth) +{ + int id; + Bitmap *b; + int ld; + Rectangle rx; + + b = (Bitmap *)malloc(sizeof(Bitmap)); + if(b == 0) + berror("balloc malloc"); + if (ldepth == 0) + ld = 0; + else + ld = screen.ldepth; + rx = r; + if (Dx(rx) == 0) + rx.max.x++; + if (Dy(rx) == 0) + rx.max.y++; + id = (int) XCreatePixmap(_dpy, (Drawable)screen.id, + Dx(rx), Dy(rx), _ld2d[ld]); + b->ldepth = ldepth; + b->r = r; + b->clipr = r; + b->id = id; + b->cache = 0; + if(ldepth == 0) + b->flag = DP1|BL1; + else + b->flag = screen.flag&BL1; + if(r.min.x==0 && r.min.y ==0) + b->flag |= ZORG; + else + b->flag |= SHIFT; + return b; +} + +void +bfree(Bitmap *b) +{ + XFreePixmap(_dpy, (Pixmap)b->id); + free(b); +} diff --git a/libXg/bitblt.c b/libXg/bitblt.c new file mode 100644 index 0000000..c9de4e4 --- /dev/null +++ b/libXg/bitblt.c @@ -0,0 +1,58 @@ +/* Copyright (c) 1992 AT&T - All rights reserved. */ +#include <libc.h> +#include <libg.h> +#include "libgint.h" + +void +bitblt(Bitmap *d, Point p, Bitmap *s, Rectangle r, Fcode f) +{ + int sx, sy, dx, dy, bfunc; + GC g; + unsigned long plane; + Bitmap *btmp; + + if(Dx(r)<=0 || Dy(r)<=0) + return; + sx = r.min.x; + sy = r.min.y; + if(s->flag&SHIFT){ + sx -= s->r.min.x; + sy -= s->r.min.y; + } + dx = p.x; + dy = p.y; + if(d->flag&SHIFT){ + dx -= d->r.min.x; + dy -= d->r.min.y; + } + g = _getcopygc(f, d, s, &bfunc); + if(bfunc == UseCopyArea) + XCopyArea(_dpy, (Drawable)s->id, (Drawable)d->id, g, + sx, sy, Dx(r), Dy(r), dx, dy); + else if(bfunc == UseFillRectangle){ + XFillRectangle(_dpy, (Drawable)d->id, g, + dx, dy, Dx(r), Dy(r)); + }else{ + /* bfunc == UseCopyPlane */ + plane = _ld2dmask[s->ldepth]; + plane &= ~(plane>>1); + if(0/*f == S*/) + XCopyPlane(_dpy, (Drawable)s->id, (Drawable)d->id, g, + sx, sy, Dx(r), Dy(r), dx, dy, plane); + else { + /* + * CopyPlane can only do func code S, + * so copy src rect into a bitmap with the same depth + * as the dest, then do the bitblt from the tmp. + * This won't recurse again because we only get + * UseCopyPlane with differing bitmap depths + */ + btmp = _balloc(Rect(0,0,Dx(r),Dy(r)), d->ldepth); + XCopyPlane(_dpy, (Drawable)s->id, (Drawable)btmp->id, g, + sx, sy, Dx(r), Dy(r), 0, 0, plane); + bitblt(d, p, btmp, btmp->r, f); + bfree(btmp); + } + } + +} diff --git a/libXg/bitbltclip.c b/libXg/bitbltclip.c new file mode 100644 index 0000000..4d25621 --- /dev/null +++ b/libXg/bitbltclip.c @@ -0,0 +1,67 @@ +/* Copyright (c) 1992 AT&T - All rights reserved. */ +#include <libc.h> +#include <libg.h> +#include "libgint.h" + +int +bitbltclip(void *vp) +{ + int dx, dy; + int i; + struct bbcarg{ + Bitmap *dm; + Point p; + Bitmap *sm; + Rectangle r; + Fcode f; + }*bp; + + bp = (struct bbcarg *)vp; + dx = Dx(bp->r); + dy = Dy(bp->r); + if(bp->p.x < bp->dm->clipr.min.x){ + i = bp->dm->clipr.min.x-bp->p.x; + bp->r.min.x += i; + bp->p.x += i; + dx -= i; + } + if(bp->p.y < bp->dm->clipr.min.y){ + i = bp->dm->clipr.min.y-bp->p.y; + bp->r.min.y += i; + bp->p.y += i; + dy -= i; + } + if(bp->p.x+dx > bp->dm->clipr.max.x){ + i = bp->p.x+dx-bp->dm->clipr.max.x; + bp->r.max.x -= i; + dx -= i; + } + if(bp->p.y+dy > bp->dm->clipr.max.y){ + i = bp->p.y+dy-bp->dm->clipr.max.y; + bp->r.max.y -= i; + dy -= i; + } + if(bp->r.min.x < bp->sm->clipr.min.x){ + i = bp->sm->clipr.min.x-bp->r.min.x; + bp->p.x += i; + bp->r.min.x += i; + dx -= i; + } + if(bp->r.min.y < bp->sm->clipr.min.y){ + i = bp->sm->clipr.min.y-bp->r.min.y; + bp->p.y += i; + bp->r.min.y += i; + dy -= i; + } + if(bp->r.max.x > bp->sm->clipr.max.x){ + i = bp->r.max.x-bp->sm->clipr.max.x; + bp->r.max.x -= i; + dx -= i; + } + if(bp->r.max.y > bp->sm->clipr.max.y){ + i = bp->r.max.y-bp->sm->clipr.max.y; + bp->r.max.y -= i; + dy -= i; + } + return dx>0 && dy>0; +} diff --git a/libXg/border.c b/libXg/border.c new file mode 100644 index 0000000..7294225 --- /dev/null +++ b/libXg/border.c @@ -0,0 +1,27 @@ +/* Copyright (c) 1992 AT&T - All rights reserved. */ +#include <libc.h> +#include <libg.h> + +void +border(Bitmap *l, Rectangle r, int i, Fcode c) +{ + if(i > 0){ + bitblt(l, r.min, + l, Rect(r.min.x, r.min.y, r.max.x, r.min.y+i), c); + bitblt(l, Pt(r.min.x, r.max.y-i), + l, Rect(r.min.x, r.max.y-i, r.max.x, r.max.y), c); + bitblt(l, Pt(r.min.x, r.min.y+i), + l, Rect(r.min.x, r.min.y+i, r.min.x+i, r.max.y-i), c); + bitblt(l, Pt(r.max.x-i, r.min.y+i), + l, Rect(r.max.x-i, r.min.y+i, r.max.x, r.max.y-i), c); + }else if(i < 0){ + bitblt(l, Pt(r.min.x, r.min.y+i), + l, Rect(r.min.x, r.min.y+i, r.max.x, r.min.y), c); + bitblt(l, Pt(r.min.x, r.max.y), + l, Rect(r.min.x, r.max.y, r.max.x, r.max.y-i), c); + bitblt(l, Pt(r.min.x+i, r.min.y+i), + l, Rect(r.min.x+i, r.min.y+i, r.min.x, r.max.y-i), c); + bitblt(l, Pt(r.max.x, r.min.y+i), + l, Rect(r.max.x, r.min.y+i, r.max.x-i, r.max.y-i), c); + } +} diff --git a/libXg/bscreenrect.c b/libXg/bscreenrect.c new file mode 100644 index 0000000..67185ec --- /dev/null +++ b/libXg/bscreenrect.c @@ -0,0 +1,17 @@ +/* Copyright (c) 1992 AT&T - All rights reserved. */ +#include <libc.h> +#include <libg.h> +#include "libgint.h" + +/* + * The screen data structure should always be up to date + * (Not true in the Plan 9 library, which is why this + * function exists). + */ +Rectangle +bscreenrect(Rectangle *clipr) +{ + if(clipr) + *clipr = screen.clipr; + return screen.r; +} diff --git a/libXg/circle.c b/libXg/circle.c new file mode 100644 index 0000000..050de4f --- /dev/null +++ b/libXg/circle.c @@ -0,0 +1,22 @@ +/* Copyright (c) 1992 AT&T - All rights reserved. */ +#include <libc.h> +#include <libg.h> +#include "libgint.h" + +void +circle(Bitmap *b, Point p, int r, int v, Fcode f) +{ + unsigned int d; + int x, y; + GC g; + + x = p.x - r; + y = p.y - r; + if (b->flag&SHIFT){ + x -= b->r.min.x; + y -= b->r.min.y; + } + d = 2*r; + g = _getfillgc(f, b, v); + XDrawArc(_dpy, (Drawable)b->id, g, x, y, d, d, 0, 23040/* 360 deg */); +} diff --git a/libXg/clipline.c b/libXg/clipline.c new file mode 100644 index 0000000..b8bbaad --- /dev/null +++ b/libXg/clipline.c @@ -0,0 +1,224 @@ +/* Copyright (c) 1992 AT&T - All rights reserved. */ +#include <libc.h> +#include <libg.h> +#include "libgint.h" + +typedef struct Linedesc +{ + int x0; + int y0; + char xmajor; + char slopeneg; + long dminor; + long dmajor; +} Linedesc; + +int _clipline(Rectangle, Point*, Point*, Linedesc*); + +#define XYswap(p) t=(p)->x, (p)->x=(p)->y, (p)->y=t +#define Swap(x, y) t=x, x=y, y=t + +static long +lfloor(long x, long y) /* first integer <= x/y */ +{ + if(y <= 0){ + if(y == 0) + return x; + y = -y; + x = -x; + } + if(x < 0){ /* be careful; C div. is undefined */ + x = -x; + x += y-1; + return -(x/y); + } + return x/y; +} + +static long +lceil(long x, long y) /* first integer >= x/y */ +{ + if(y <= 0){ + if(y == 0) + return x; + y = -y; + x = -x; + } + if(x < 0){ + x = -x; + return -(x/y); + } + x += y-1; + return x/y; +} + +int +_gminor(long x, Linedesc *l) +{ + long y; + + y = 2*(x-l->x0)*l->dminor + l->dmajor; + y = lfloor(y, 2*l->dmajor) + l->y0; + return l->slopeneg? -y : y; +} + +int +_gmajor(long y, Linedesc *l) +{ + long x; + + x = 2*((l->slopeneg? -y : y)-l->y0)*l->dmajor - l->dminor; + x = lceil(x, 2*l->dminor) + l->x0; + if(l->dminor) + while(_gminor(x-1, l) == y) + x--; + return x; +} + +void +gsetline(Point *pp0, Point *pp1, Linedesc *l) +{ + long dx, dy, t; + Point endpt; + int swapped; + Point p0, p1; + + swapped = 0; + p0 = *pp0; + p1 = *pp1; + l->xmajor = 1; + l->slopeneg = 0; + dx = p1.x - p0.x; + dy = p1.y - p0.y; + if(abs(dy) > abs(dx)){ /* Steep */ + l->xmajor = 0; + XYswap(&p0); + XYswap(&p1); + Swap(dx, dy); + } + if(dx < 0){ + swapped++; + Swap(p0.x, p1.x); + Swap(p0.y, p1.y); + dx = -dx; + dy = -dy; + } + if(dy < 0){ + l->slopeneg = 1; + dy = -dy; + p0.y = -p0.y; + } + l->dminor = dy; + l->dmajor = dx; + l->x0 = p0.x; + l->y0 = p0.y; + p1.x = swapped? p0.x+1 : p1.x-1; + p1.y = _gminor(p1.x, l); + if(l->xmajor == 0){ + XYswap(&p0); + XYswap(&p1); + } + if(pp0->x > pp1->x){ + *pp1 = *pp0; + *pp0 = p1; + }else + *pp1 = p1; +} +/* + * Modified clip-to-rectangle algorithm + * works in bitmaps + * Everything in SCREEN coordinates. + * + * Newman & Sproull 124 (1st edition) + */ + +static +code(Point *p, Rectangle *r) +{ + return( (p->x<r->min.x? 1 : p->x>=r->max.x? 2 : 0) | + (p->y<r->min.y? 4 : p->y>=r->max.y? 8 : 0)); +} + +int +clipline(Rectangle r, Point *p0, Point *p1) +{ + Linedesc l; + + return _clipline(r, p0, p1, &l); +} + +int +_clipline(Rectangle r, Point *p0, Point *p1, Linedesc *l) +{ + int c0, c1, n; + long t, ret; + Point temp; + int swapped; + + if(p0->x==p1->x && p0->y==p1->y) + return 0; + gsetline(p0, p1, l); + /* line is now closed */ + if(l->xmajor == 0){ + XYswap(p0); + XYswap(p1); + XYswap(&r.min); + XYswap(&r.max); + } + c0 = code(p0, &r); + c1 = code(p1, &r); + ret = 1; + swapped = 0; + n = 0; + while(c0 | c1){ + if(c0 & c1){ /* no point of line in r */ + ret = 0; + goto Return; + } + if(++n > 10){ /* horrible points; overflow etc. etc. */ + ret = 0; + goto Return; + } + if(c0 == 0){ /* swap points */ + temp = *p0; + *p0 = *p1; + *p1 = temp; + Swap(c0, c1); + swapped ^= 1; + } + if(c0 == 0) + break; + if(c0 & 1){ /* push towards left edge */ + p0->x = r.min.x; + p0->y = _gminor(p0->x, l); + }else if(c0 & 2){ /* push towards right edge */ + p0->x = r.max.x-1; + p0->y = _gminor(p0->x, l); + }else if(c0 & 4){ /* push towards top edge */ + p0->y = r.min.y; + if(l->slopeneg) + p0->x = _gmajor(p0->y-1, l)-1; + else + p0->x = _gmajor(p0->y, l); + }else if(c0 & 8){ /* push towards bottom edge */ + p0->y = r.max.y-1; + if(l->slopeneg) + p0->x = _gmajor(p0->y, l); + else + p0->x = _gmajor(p0->y+1, l)-1; + } + c0 = code(p0, &r); + } + + Return: + if(l->xmajor == 0){ + XYswap(p0); + XYswap(p1); + } + if(swapped){ + temp = *p0; + *p0 = *p1; + *p1 = temp; + } + return ret; +} diff --git a/libXg/clipr.c b/libXg/clipr.c new file mode 100644 index 0000000..6aab528 --- /dev/null +++ b/libXg/clipr.c @@ -0,0 +1,20 @@ +/* Copyright (c) 1992 AT&T - All rights reserved. */ +#include <libc.h> +#include <libg.h> +#include "libgint.h" + +int +clipr(Bitmap *d, Rectangle r) +{ + if(rectclip(&r, d->r) == 0) + return 0; + d->clipr = r; + if(r.min.x != d->r.min.x || + r.min.y != d->r.min.y || + r.max.x != d->r.max.x || + r.max.y != d->r.max.y) + d->flag |= CLIP; + else + d->flag &= ~CLIP; + return 1; +} diff --git a/libXg/copymasked.c b/libXg/copymasked.c new file mode 100644 index 0000000..17931f3 --- /dev/null +++ b/libXg/copymasked.c @@ -0,0 +1,47 @@ +#include <libc.h> +#include <libg.h> +#include "libgint.h" + +/* + * m should be a 1-bit-deep bitmap with origin (0,0) and the + * same extents as r. s should have the same depth as d. + * Rectangle r of s is copied to d wherever corresponding + * bits of m are 1 + */ +void +copymasked(Bitmap *d, Point p, Bitmap *s, Bitmap *m, Rectangle r) +{ + int sx, sy, dx, dy; + XGCValues gcv; + GC g; + + if(Dx(r)<=0 || Dy(r)<=0) + return; + sx = r.min.x; + sy = r.min.y; + if(s->flag&SHIFT){ + sx -= s->r.min.x; + sy -= s->r.min.y; + } + dx = p.x; + dy = p.y; + if(d->flag&SHIFT){ + dx -= d->r.min.x; + dy -= d->r.min.y; + } + gcv.fill_style = FillStippled; + gcv.stipple = (Pixmap)m->id; + gcv.function = GXclear; + gcv.ts_x_origin = dx; + gcv.ts_y_origin = dy; + gcv.fill_style = FillStippled; + g = _getgc(d, GCFunction|GCStipple|GCTileStipXOrigin + |GCTileStipYOrigin|GCFillStyle, &gcv); + XFillRectangle(_dpy, (Drawable)d->id, g, + dx, dy, Dx(r), Dy(r)); + gcv.function = GXor; + gcv.fill_style = FillSolid; + g = _getgc(d, GCFunction|GCFillStyle, &gcv); + XCopyArea(_dpy, (Drawable)s->id, (Drawable)d->id, g, + sx, sy, Dx(r), Dy(r), dx, dy); +} diff --git a/libXg/cursorset.c b/libXg/cursorset.c new file mode 100644 index 0000000..40b744b --- /dev/null +++ b/libXg/cursorset.c @@ -0,0 +1,15 @@ +/* Copyright (c) 1992 AT&T - All rights reserved. */ +#include <libc.h> +#include <libg.h> +#include "libgint.h" + +/* + * Only allow cursor to move within screen Bitmap + */ +void +cursorset(Point p) +{ + /* motion will be relative to window origin */ + p = sub(p, screen.r.min); + XWarpPointer(_dpy, None, (Window)screen.id, 0, 0, 0, 0, p.x, p.y); +} diff --git a/libXg/cursorswitch.c b/libXg/cursorswitch.c new file mode 100644 index 0000000..e7759eb --- /dev/null +++ b/libXg/cursorswitch.c @@ -0,0 +1,65 @@ +/* Copyright (c) 1992 AT&T - All rights reserved. */ +#include <libc.h> +#include <libg.h> +#include "libgint.h" + +/* + * Use the id field in Cursor to hold the X id corresponding + * to the cursor, so that it doesn't have to be recreated on + * each cursorswitch. This doesn't quite match the semantics + * of Plan9 libg, since the user could create a cursor (say + * with malloc) with garbage in the id field; or the user + * could change the contents of the other fields and we + * wouldn't know about it. Neither of these happen in + * existing uses of libg. + */ +static Cursor arrow = +{ + {-1, -1}, + {0xFF, 0xE0, 0xFF, 0xE0, 0xFF, 0xC0, 0xFF, 0x00, + 0xFF, 0x00, 0xFF, 0x80, 0xFF, 0xC0, 0xFF, 0xE0, + 0xE7, 0xF0, 0xE3, 0xF8, 0xC1, 0xFC, 0x00, 0xFE, + 0x00, 0x7F, 0x00, 0x3E, 0x00, 0x1C, 0x00, 0x08, + }, + {0x00, 0x00, 0x7F, 0xC0, 0x7F, 0x00, 0x7C, 0x00, + 0x7E, 0x00, 0x7F, 0x00, 0x6F, 0x80, 0x67, 0xC0, + 0x43, 0xE0, 0x41, 0xF0, 0x00, 0xF8, 0x00, 0x7C, + 0x00, 0x3E, 0x00, 0x1C, 0x00, 0x08, 0x00, 0x00, + } +}; + +static Bitmap *bsrc, *bmask; +static Rectangle crect = { 0, 0, 16, 16 }; + +void +cursorswitch(Cursor *c) +{ + if(c == 0) + c = &arrow; + if(c->id == 0){ + if(bsrc == 0){ + bsrc = balloc(crect, 0); + bmask = balloc(crect, 0); + } + /* + * Cursor should have fg where "set" is 1, + * and bg where "clr" is 1 and "set" is 0, + * and should leave places alone where "set" and "clr" are both 0 + */ + wrbitmap(bsrc, 0, 16, c->set); +#ifdef CURSORBUG + /* + * Some X servers (e.g., Sun X-on-news for some color + * monitors) don't do XCreatePixmapCursor properly: + * only the mask gets displayed, all black + */ + wrbitmap(bmask, 0, 16, c->set); +#else + wrbitmap(bmask, 0, 16, c->clr); + bitblt(bmask, Pt(0,0), bsrc, crect, S|D); +#endif + c->id = (int) XCreatePixmapCursor(_dpy, (Pixmap)bsrc->id, (Pixmap)bmask->id, + &_fgcolor, &_bgcolor, -c->offset.x, -c->offset.y); + } + XDefineCursor(_dpy, (Window)screen.id, (xCursor)c->id); +} diff --git a/libXg/disc.c b/libXg/disc.c new file mode 100644 index 0000000..5968f9d --- /dev/null +++ b/libXg/disc.c @@ -0,0 +1,22 @@ +/* Copyright (c) 1992 AT&T - All rights reserved. */ +#include <libc.h> +#include <libg.h> +#include "libgint.h" + +void +disc(Bitmap *b, Point p, int r, int v, Fcode f) +{ + unsigned int d; + int x, y; + GC g; + + x = p.x - r; + y = p.y - r; + if (b->flag&SHIFT){ + x -= b->r.min.x; + y -= b->r.min.y; + } + d = 2*r; + g = _getfillgc(f, b, v); + XFillArc(_dpy, (Drawable)b->id, g, x, y, d, d, 0, 23040/* 360 deg */); +} diff --git a/libXg/ellipse.c b/libXg/ellipse.c new file mode 100644 index 0000000..89d19cf --- /dev/null +++ b/libXg/ellipse.c @@ -0,0 +1,22 @@ +/* Copyright (c) 1992 AT&T - All rights reserved. */ +#include <libc.h> +#include <libg.h> +#include "libgint.h" + +/* e(x,y) = b*b*x*x + a*a*y*y - a*a*b*b */ + +void +ellipse(Bitmap *bp, Point p, int a, int b, int v, Fcode f) +{ + int x, y; + GC g; + + x = p.x - a; + y = p.y - b; + if (bp->flag&SHIFT){ + x -= bp->r.min.x; + y -= bp->r.min.y; + } + g = _getfillgc(f, bp, v); + XDrawArc(_dpy, (Drawable)bp->id, g, x, y, 2*a, 2*b, 0, 23040/* 360 deg */); +} diff --git a/libXg/font.c b/libXg/font.c new file mode 100644 index 0000000..1d3cd37 --- /dev/null +++ b/libXg/font.c @@ -0,0 +1,91 @@ +/* Copyright (c) 1992 AT&T - All rights reserved. */ +#include <libc.h> +#include <libg.h> +#include "libgint.h" + +#define PJW 0 /* use NUL==pjw for invisible characters */ + +static Cachesubf +*findsubfont(Font *f, Rune r, int *cn) +{ + int n, i, c; + Rune rx; + Cachesubf *csf; + Subfont *sf; + + for (i = 0, rx = r; i < 2; i++, rx = PJW) + for (n=0, csf=f->subf; n < f->nsubf; n++, csf++) + if (csf->min <= rx && rx <= csf->max) { + if (!csf->f) { + csf->f = getsubfont(csf->name); + if (!csf->f) + return 0; + } + sf = csf->f; + c = rx-csf->min+sf->minchar; + c = ((c>>8)-sf->minrow)*sf->width+(c&0xff)-sf->mincol; + if (c < 0) + break; + /* ignore zero width characters */ + if (sf->info[c].cwidth == 0 && sf->info[c].width == 0) + break; + *cn = c; + return csf; + } + return 0; +} + +int +cachechars(Font *f, char **s, void *cp, int max, int *wp, unsigned short *fp) +{ + int i, w, wid, charnum; + Rune r; + char *sp; + Cachesubf *csf; + + sp = *s; + wid = 0; + + for (i=0; *sp && i<max; sp+=w) { + r = *(unsigned char *)sp; + if (r < Runeself) + w = 1; + else + w = chartorune(&r, sp); + csf = findsubfont(f, r, &charnum); + if (!csf) + break; + wid += csf->f->info[charnum].width; + fp[i] = csf-f->subf; /* subfont number */ + ((XChar2b*)cp)[i].byte1 = charnum/csf->f->width+csf->f->minrow; + ((XChar2b*)cp)[i].byte2 = charnum%csf->f->width+csf->f->mincol; + i++; + } + *s = sp; + *wp = wid; + return i; +} + +long +charwidth(Font *f, Rune r) +{ + Cachesubf *csf; + int charnum; + + if (r == 0) + berror("NUL in charwidth"); /* difficult BUG */ + + csf = findsubfont(f, r, &charnum); + if (!csf) + return 0; + else + return csf->f->info[charnum].width; +} + +void +subffree(Subfont *f) +{ + if (f->info) + free(f->info); /* note: f->info must have been malloc'ed! */ + free(f); +} diff --git a/libXg/gcs.c b/libXg/gcs.c new file mode 100644 index 0000000..4d7d3d6 --- /dev/null +++ b/libXg/gcs.c @@ -0,0 +1,400 @@ +/* Copyright (c) 1992 AT&T - All rights reserved. */ +#include <libc.h> +#include <libg.h> +#include "libgint.h" + +/* + * Libg applications are written assuming that black is ~0 + * and white is 0. Some screens use the reverse convention. + * We get the effect the application desired by seeing what + * happens if both the source and dest are converted to the + * black==~0 convention, and then converting the dest back + * to whatever convention it uses. + * + * Offscreen bitmaps of depth 1 use the black==~0 convention. + * + * Bitmaps of depth > 1 are probably in color. Libg operations that + * would produce a 1 should produce the foreground color, and + * libg operations that would produce a 0 should produce the background + * color. Operations that use bitmaps of depth > 1 as source + * should interpret the foreground pixel as "black" (1) and the + * background pixel as "white" (0). It is hard to make this work, + * but the important cases are Fcodes Zero, F, S, and S^D, so + * we make sure that those work. When a fill value is given for + * a bitmap of depth > 1, assume ~0 means foreground, but otherwise + * take any other value literally (assume it came from rgbpix). + * This may be wrong for the case of 0, but libg programmers + * usually use Fcode Zero instead of passing 0 with Fcode S. + * + * We assume there are at most two depths of bitmaps: depth 1 + * and depth of the screen. + */ + +/* + * gx func code corresponding to libg func code when both + * source and dest use 1 for black. This is a straight translation. + */ +static int gx[16] = { + GXclear, /* Zero */ + GXnor, /* DnorS */ + GXandInverted, /* DandnotS */ + GXcopyInverted, /* notS */ + GXandReverse, /* notDandS */ + GXinvert, /* notD */ + GXxor, /* DxorS */ + GXnand, /* DnandS */ + GXand, /* DandS */ + GXequiv, /* DxnorS */ + GXnoop, /* D */ + GXorInverted, /* DornotS */ + GXcopy, /* S */ + GXorReverse, /* notDorS */ + GXor, /* DorS */ + GXset, /* F */ +}; + +/* + * gx func code corresponding to libg func code when 0 means black + * in dst and 1 means black in src. These means the table has op' + * where dst <- dst op' src == not ( not(dst) op src ). + * The comment on each line is op, in Fcode terms. + */ +static int d0s1gx[16] = { + GXset, /* Zero */ + GXorReverse, /* DnorS */ + GXor, /* DandnotS */ + GXcopy, /* notS */ + GXnand, /* notDandS */ + GXinvert, /* notD */ + GXxor, /* DxorS */ + GXandReverse, /* DnandS */ + GXorInverted, /* DandS */ + GXequiv, /* DxnorS */ + GXnoop, /* D */ + GXand, /* DornotS */ + GXcopyInverted, /* S */ + GXnor, /* notDorS */ + GXandInverted, /* DorS */ + GXclear, /* F */ +}; +/* + * gx func code corresponding to libg func code when 1 means black + * in dst and 0 means black in src. These means the table has op' + * where dst <- dst op' src == dst op not(src) ) + * The comment on each line is op, in Fcode terms. + */ +static int d1s0gx[16] = { + GXclear, /* Zero */ + GXandReverse, /* DnorS */ + GXand, /* DandnotS */ + GXcopy, /* notS */ + GXnor, /* notDandS */ + GXinvert, /* notD */ + GXequiv, /* DxorS */ + GXorReverse, /* DnandS */ + GXandInverted, /* DandS */ + GXxor, /* DxnorS */ + GXnoop, /* D */ + GXor, /* DornotS */ + GXcopyInverted, /* S */ + GXnand, /* notDorS */ + GXorInverted, /* DorS */ + GXset, /* F */ +}; + +/* + * gx func code corresponding to libg func code when 0 means black + * in both the src and the dst. These means the table has op' + * where dst <- dst op' src == not (not(dst) op not(src)) ) + * The comment on each line is op, in Fcode terms. + */ +static int d0s0gx[16] = { + GXset, /* Zero */ + GXnand, /* DnorS */ + GXorInverted, /* DandnotS */ + GXcopyInverted, /* notS */ + GXorReverse, /* notDandS */ + GXinvert, /* notD */ + GXequiv, /* DxorS */ + GXnor, /* DnandS */ + GXor, /* DandS */ + GXxor, /* DxnorS */ + GXnoop, /* D */ + GXandInverted, /* DornotS */ + GXcopy, /* S */ + GXandReverse, /* notDorS */ + GXand, /* DorS */ + GXclear, /* F */ +}; + +/* + * 1 for those Fcodes that are degenerate (don't involve src) + */ +static int degengc[16] = { + 1, /* Zero */ + 0, /* DnorS */ + 0, /* DandnotS */ + 0, /* notS */ + 0, /* notDandS */ + 1, /* notD */ + 0, /* DxorS */ + 0, /* DnandS */ + 0, /* DandS */ + 0, /* DxnorS */ + 1, /* D */ + 0, /* DornotS */ + 0, /* S */ + 0, /* notDorS */ + 0, /* DorS */ + 1, /* F */ +}; + +/* + * GCs are all for same screen, and depth is either 1 or screen depth. + * Return a GC for the depth of b, with values as specified by gcv. + * + * Also, set (or unset) the clip rectangle if necessary. + * (This implementation should be improved if setting a clip rectangle is not rare). + */ +GC +_getgc(Bitmap *b, unsigned long gcvm, XGCValues *pgcv) +{ + static GC gc0, gcn; + static clipset = 0; + GC g; + XRectangle xr; + + g = (b->ldepth==0)? gc0 : gcn; + if(!g){ + g = XCreateGC(_dpy, (Drawable)b->id, gcvm, pgcv); + if(b->ldepth==0) + gc0 = g; + else + gcn = g; + } else + XChangeGC(_dpy, g, gcvm, pgcv); + if(b->flag&CLIP){ + xr.x = b->clipr.min.x; + xr.y = b->clipr.min.y; + xr.width = Dx(b->clipr); + xr.height = Dy(b->clipr); + if(b->flag&SHIFT){ + xr.x -= b->r.min.x; + xr.y -= b->r.min.y; + } + XSetClipRectangles(_dpy, g, 0, 0, &xr, 1, YXBanded); + clipset = 1; + }else if(clipset){ + pgcv->clip_mask = None; + XChangeGC(_dpy, g, GCClipMask, pgcv); + clipset = 0; + } + return g; +} + +/* + * Return a GC that will fill bitmap b using a pixel value v and Fcode f. + * Pixel value v is according to libg convention, so 0 means + * white (or background) and ~0 means black (or foreground). + */ +GC +_getfillgc(Fcode f, Bitmap *b, unsigned long val) +{ + int xf, m; + unsigned long v, fg, bg, spix, vmax; + XGCValues gcv; + + f &= F; + vmax = _ld2dmask[b->ldepth]; + v = val & vmax; + spix = v; + xf = GXcopy; + m = b->flag; + if(m & DP1){ + xf = (m&BL1)? gx[f] : d0s1gx[f]; + }else{ + fg = _fgpixel; + bg = _bgpixel; + switch(f){ + case Zero: + labZero: + spix = bg; + break; + case F: + labF: + spix = fg; + break; + case D: + labD: + xf = GXnoop; + break; + case notD: + labnotD: + xf = GXxor; + spix = fg^bg; + break; + case S: + if(val == ~0) + spix = fg; + else + spix = v; + break; + case notS: + if(val == ~0) + spix = bg; + else + spix = v; + break; + case DxorS: + xf = GXxor; + if(val == ~0) + spix = fg^bg; + else + spix = v; + break; + case DxnorS: + xf = GXxor; + if(val == 0) + spix = fg^bg; + else + spix = v; + break; + default: + /* hard to do anything other than v==0 or v==~0 case */ + if(v < vmax-v){ + /* v is closer to 0 than vmax */ + switch(f&~S){ + case D&~S: goto labD; + case notD&~S: goto labnotD; + case Zero&~S: goto labZero; + case F&~S: goto labF; + } + }else{ + /* v is closer to vmax than 0 */ + switch(f&S){ + case D&S: goto labD; + case notD&S: goto labnotD; + case Zero&S: goto labZero; + case F&S: goto labF; + } + } + + } + } + gcv.foreground = spix; + gcv.function = xf; + return _getgc(b, GCForeground|GCFunction, &gcv); +} + +/* + * Return a GC to be used to copy an area from bitmap sb to + * bitmap db. Sometimes the calling function shouldn't use + * XCopyArea, but instead should use XCopyPlane or XFillRectangle. + * The *bltfunc arg is set to one of UseCopyArea, UseCopyPlane, + * UseFillRectangle. + */ +GC +_getcopygc(Fcode f, Bitmap *db, Bitmap *sb, int *bltfunc) +{ + unsigned long spix, bg, fg, df, sf; + int xf, c; + XGCValues gcv; + unsigned long gcvm; + + f &= F; + gcvm = 0; + df = db->flag; + if(degengc[f]){ + *bltfunc = UseFillRectangle; + if(df&SCR || !(df&DP1)){ + fg = _fgpixel; + bg = _bgpixel; + }else{ + /* must be DP1 and BL1 */ + fg = 1; + bg = 0; + } + switch(f){ + case Zero: + xf = GXcopy; + spix = bg; + break; + case F: + xf = GXcopy; + spix = fg; + break; + case D: + xf = GXnoop; + spix = fg; + break; + case notD: + xf = GXxor; + spix = fg^bg; + break; + } + gcv.function = xf; + gcv.foreground = spix; + gcvm = GCFunction|GCForeground; + }else{ + /* src is involved in f */ + +#define code(f1,f2) ((((f1)&(DP1|BL1))<<2)|((f2)&(DP1|BL1))) + + sf = sb->flag; + c = code(df,sf); + *bltfunc = UseCopyArea; + switch(code(df,sf)){ + case code(DP1|BL1,DP1|BL1): + case code(BL1,BL1): + xf = gx[f]; + break; + case code(DP1|BL1,DP1): + xf = d1s0gx[f]; + break; + case code(DP1,DP1|BL1): + xf = d0s1gx[f]; + break; + case code(DP1,DP1): + case code(0,0): + xf = d0s0gx[f]; + break; + default: + /* + * One bitmap has depth 1, the other has screen depth. + * We know the bitmap must have BL1. + * CopyPlane must be used; it won't really work + * for more than fcode==S. + */ + + *bltfunc = UseCopyPlane; + xf = GXcopy; + switch(c){ + + case code(0,DP1|BL1): + case code(BL1,DP1|BL1): + fg = _fgpixel; + bg = _bgpixel; + break; + case code(DP1|BL1,0): + fg = 0; + bg = 1; + break; + case code(DP1|BL1,BL1): + fg = 1; + bg = 0; + break; + default: + berror("bad combination of copy bitmaps"); + } + gcv.foreground = fg; + gcv.background = bg; + gcvm |= GCForeground|GCBackground; + } + gcv.function = xf; + gcvm |= GCFunction; + +#undef code + } + + return _getgc(db, gcvm, &gcv); +} diff --git a/libXg/getrect.c b/libXg/getrect.c new file mode 100644 index 0000000..2205a69 --- /dev/null +++ b/libXg/getrect.c @@ -0,0 +1,72 @@ +/* Copyright (c) 1992 AT&T - All rights reserved. */ +#include <libc.h> +#include <libg.h> +#include "libgint.h" + +static Cursor sweep={ + {-7, -7}, + {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x07, + 0xE0, 0x07, 0xE0, 0x07, 0xE3, 0xF7, 0xE3, 0xF7, + 0xE3, 0xE7, 0xE3, 0xF7, 0xE3, 0xFF, 0xE3, 0x7F, + 0xE0, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,}, + {0x00, 0x00, 0x7F, 0xFE, 0x40, 0x02, 0x40, 0x02, + 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x41, 0xE2, + 0x41, 0xC2, 0x41, 0xE2, 0x41, 0x72, 0x40, 0x38, + 0x40, 0x1C, 0x40, 0x0E, 0x7F, 0xE6, 0x00, 0x00,} +}; + +static void +grabcursor(void) +{ + /* Grab X server with an limp wrist. */ + while (XGrabPointer(_dpy, screen.id, False, + ButtonPressMask|ButtonReleaseMask| + ButtonMotionMask|StructureNotifyMask, + GrabModeAsync, GrabModeAsync, None, None, CurrentTime) + != GrabSuccess) + sleep(2); + /* Grab the keyboard too */ + XSetInputFocus(_dpy, screen.id, RevertToParent, CurrentTime); +} + +static void +ungrabcursor(void) +{ + XUngrabPointer(_dpy, CurrentTime); +} + +Rectangle +getrect(int but, Mouse *m){ + Rectangle r, rc; + + but = 1<<(but-1); + cursorswitch(&sweep); + while(m->buttons) + *m = emouse(); + grabcursor(); + while(!(m->buttons & but)){ + *m = emouse(); + if(m->buttons & (7^but)) + goto Return; + } + r.min = m->xy; + r.max = m->xy; + do{ + rc = rcanon(r); + border(&screen, rc, 2, F&~D); + *m = emouse(); + border(&screen, rc, 2, F&~D); + r.max = m->xy; + }while(m->buttons & but); + + Return: + cursorswitch((Cursor *)0); + if(m->buttons & (7^but)){ + rc.min.x = rc.max.x = 0; + rc.min.y = rc.max.y = 0; + while(m->buttons) + *m = emouse(); + } + ungrabcursor(); + return rc; +} diff --git a/libXg/gwin.c b/libXg/gwin.c new file mode 100644 index 0000000..ded8a0f --- /dev/null +++ b/libXg/gwin.c @@ -0,0 +1,542 @@ +/* Copyright (c) 1992 AT&T - All rights reserved. */ +#include <u.h> +#include <libc.h> +#include <stdio.h> +#include <X11/IntrinsicP.h> +#include <X11/StringDefs.h> +#include <X11/Xatom.h> +#include <X11/keysym.h> + +#ifndef XtSpecificationRelease +#define R3 +#define XtPointer caddr_t +#define XtOffsetOf(s_type,field) XtOffset(s_type*,field) +#define XtExposeCompressMultiple TRUE +#endif + +#include "GwinP.h" + +/* Forward declarations */ +static void Realize(Widget, XtValueMask *, XSetWindowAttributes *); +static void Resize(Widget); +static void Redraw(Widget, XEvent *, Region); +static void Mappingaction(Widget, XEvent *, String *, Cardinal*); +static void Keyaction(Widget, XEvent *, String *, Cardinal*); +static void Mouseaction(Widget, XEvent *, String *, Cardinal*); +static String SelectSwap(Widget, String); + +/* Data */ + +#define Offset(field) XtOffsetOf(GwinRec, gwin.field) + +static XtResource resources[] = { + {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel), + Offset(foreground), XtRString, (XtPointer)XtDefaultForeground}, + {XtNfont, XtCFont, XtRFontStruct, sizeof(XFontStruct *), + Offset(font),XtRString, (XtPointer)XtDefaultFont}, + {XtNscrollForwardR, XtCScrollForwardR, XtRBoolean, sizeof(Boolean), + Offset(forwardr), XtRImmediate, (XtPointer)TRUE}, + {XtNreshaped, XtCReshaped, XtRFunction, sizeof(Reshapefunc), + Offset(reshaped), XtRFunction, (XtPointer) NULL}, + {XtNgotchar, XtCGotchar, XtRFunction, sizeof(Charfunc), + Offset(gotchar), XtRFunction, (XtPointer) NULL}, + {XtNgotmouse, XtCGotmouse, XtRFunction, sizeof(Mousefunc), + Offset(gotmouse), XtRFunction, (XtPointer) NULL}, + {XtNselection, XtCSelection, XtRString, sizeof(String), + Offset(selection), XtRString, (XtPointer) NULL}, + {XtNp9font, XtCP9font, XtRString, sizeof(String), + Offset(p9font), XtRString, (XtPointer) NULL}, + {XtNp9fixed, XtCP9fixed, XtRString, sizeof(String), + Offset(p9fixed), XtRString, (XtPointer) NULL}, + {XtNcomposeMod, XtCComposeMod, XtRInt, sizeof(int), + Offset(compose), XtRImmediate, (XtPointer) 0} +}; +#undef Offset + +static XtActionsRec actions[] = { + {"key", Keyaction}, + {"mouse", Mouseaction}, + {"mapping", Mappingaction} +}; + +static char tms[] = + "<Key> : key() \n\ + <Motion> : mouse() \n\ + <BtnDown> : mouse() \n\ + <BtnUp> : mouse() \n\ + <Mapping> : mapping() \n"; + +/* Class record declaration */ + +GwinClassRec gwinClassRec = { + /* Core class part */ + { + /* superclass */ (WidgetClass)&widgetClassRec, + /* class_name */ "Gwin", + /* widget_size */ sizeof(GwinRec), + /* class_initialize */ NULL, + /* class_part_initialize*/ NULL, + /* class_inited */ FALSE, + /* initialize */ NULL, + /* initialize_hook */ NULL, + /* realize */ Realize, + /* actions */ actions, + /* num_actions */ XtNumber(actions), + /* resources */ resources, + /* num_resources */ XtNumber(resources), + /* xrm_class */ NULLQUARK, + /* compress_motion */ TRUE, + /* compress_exposure */ XtExposeCompressMultiple, + /* compress_enterleave*/ TRUE, + /* visible_interest */ FALSE, + /* destroy */ NULL, + /* resize */ Resize, + /* expose */ Redraw, + /* set_values */ NULL, + /* set_values_hook */ NULL, + /* set_values_almost */ XtInheritSetValuesAlmost, + /* get_values_hook */ NULL, + /* accept_focus */ XtInheritAcceptFocus, + /* version */ XtVersion, + /* callback_offsets */ NULL, + /* tm_table */ tms, + /* query_geometry */ XtInheritQueryGeometry, + /* display_accelerator */ NULL, + /* extension */ NULL + }, + /* Gwin class part */ + { + /* select_swap */ SelectSwap, + } +}; + +/* Class record pointer */ +WidgetClass gwinWidgetClass = (WidgetClass) &gwinClassRec; + +static XModifierKeymap *modmap; +static int keypermod; + +static void +Realize(Widget w, XtValueMask *valueMask, XSetWindowAttributes *attrs) +{ + XtValueMask mask; + + *valueMask |= CWBackingStore; + attrs->backing_store = Always; + + XtCreateWindow(w, InputOutput, (Visual *)0, *valueMask, attrs); + XtSetKeyboardFocus(w->core.parent, w); + if (modmap = XGetModifierMapping(XtDisplay(w))) + keypermod = modmap->max_keypermod; + + Resize(w); +} + +static void +Resize(Widget w) +{ + if(XtIsRealized(w)) + (*(XtClass(w)->core_class.expose))(w, (XEvent *)NULL, (Region)NULL); +} + +static void +Redraw(Widget w, XEvent *e, Region r) +{ + Reshapefunc f; + + f = ((GwinWidget)w)->gwin.reshaped; + if(f) + (*f)(w->core.x, w->core.y, + w->core.x+w->core.width, w->core.y+w->core.height); +} + +static void +Mappingaction(Widget w, XEvent *e, String *p, Cardinal *np) +{ + if (modmap) + XFreeModifiermap(modmap); + modmap = XGetModifierMapping(e->xany.display); + if (modmap) + keypermod = modmap->max_keypermod; +} + +#define STUFFCOMPOSE() \ + f = ((GwinWidget)w)->gwin.gotchar; \ + if (f) \ + for (c = 0; c < composing; c++) \ + (*f)(compose[c]) + +static void +Keyaction(Widget w, XEvent *e, String *p, Cardinal *np) +{ + static unsigned char compose[5]; + static int composing = -2; + + int c, minmod; + KeySym k, mk; + Charfunc f; + Modifiers md; + + /* + * I tried using XtGetActionKeysym, but it didn't seem to + * do case conversion properly + * (at least, with Xterminal servers and R4 intrinsics) + */ + if(e->xany.type != KeyPress) + return; + XtTranslateKeycode(e->xany.display, (KeyCode)e->xkey.keycode, + e->xkey.state, &md, &k); + /* + * The following song and dance is so we can have our chosen + * modifier key behave like a compose key, i.e, press and release + * and then type the compose sequence, like Plan 9. We have + * to find out which key is the compose key first 'though. + */ + if (IsModifierKey(k) && ((GwinWidget)w)->gwin.compose + && composing == -2 && modmap) { + minmod = (((GwinWidget)w)->gwin.compose+2)*keypermod; + for (c = minmod; c < minmod+keypermod; c++) { + XtTranslateKeycode(e->xany.display, + modmap->modifiermap[c], + e->xkey.state, &md, &mk); + if (k == mk) { + composing = -1; + break; + } + } + return; + } + /* Handle Multi_key separately, since it isn't a modifier */ + if(k == XK_Multi_key) { + composing = -1; + return; + } + if(k == NoSymbol) + return; + if(k&0xFF00){ + switch(k){ + case XK_BackSpace: + case XK_Tab: + case XK_Escape: + case XK_Delete: + case XK_KP_0: + case XK_KP_1: + case XK_KP_2: + case XK_KP_3: + case XK_KP_4: + case XK_KP_5: + case XK_KP_6: + case XK_KP_7: + case XK_KP_8: + case XK_KP_9: + case XK_KP_Divide: + case XK_KP_Multiply: + case XK_KP_Subtract: + case XK_KP_Add: + case XK_KP_Decimal: + k &= 0x7F; + break; + case XK_Linefeed: + k = '\r'; + break; + case XK_KP_Enter: + case XK_Return: + k = '\n'; + break; + case XK_Next: + k = 0x80; /* (VIEW- scroll down)*/ + break; + case XK_Prior: + k = 0x81; /* PREVIEW -- "Scroll back" */ + break; + case XK_Left: + k = 0x82; /* LeftArrow */ + break; + case XK_Right: + k = 0x83; /* RightArrow */ + break; + case XK_Down: + k = 0x84; /* LeftArrow */ + break; + case XK_Up: + k = 0x85; /* LeftArrow */ + break; + case XK_Home: + k = 0x86; /* Home */ + break; + case XK_End: + k = 0x87; /* End */ + break; + default: + return; /* not ISO-1 or tty control */ + } + } + /* Compensate for servers that call a minus a hyphen */ + if(k == XK_hyphen) + k = XK_minus; + /* Do control mapping ourselves if translator doesn't */ + if((e->xkey.state&ControlMask) && !(md&ControlMask)) + k &= 0x9f; + if(k == NoSymbol) + return; + /* Check to see if we are in a composition sequence */ + if (!((GwinWidget)w)->gwin.compose && (e->xkey.state & Mod1Mask) + && composing == -2) + composing = -1; + if (composing > -2) { + compose[++composing] = k; + if ((*compose == 'X') && (composing > 0)) { + if ((k < '0') || (k > 'f') || + ((k > '9') && (k < 'a'))) { + STUFFCOMPOSE(); + c = (unsigned short)k; + composing = -2; + } else if (composing == 4) { + c = (int)unicode(compose); + if (c == -1) { + STUFFCOMPOSE(); + c = (unsigned short)compose[4]; + } + composing = -2; + } + } else if (composing == 1) { + c = (int)latin1(compose); + if (c == -1) { + STUFFCOMPOSE(); + c = (unsigned short)compose[1]; + } + composing = -2; + } + } else { + if (composing >= 0) { + composing++; + STUFFCOMPOSE(); + } + c = (unsigned short)k; + composing = -2; + } + + if (composing >= -1) + return; + + f = ((GwinWidget)w)->gwin.gotchar; + if(f) + (*f)(c); +} + +static void +LoseSel(Widget w, Atom *sel) +{ + GwinWidget gw = (GwinWidget)w; + + if(gw->gwin.selection){ + XtFree(gw->gwin.selection); + gw->gwin.selection = 0; + } +} + +static void +Mouseaction(Widget w, XEvent *e, String *p, Cardinal *np) +{ + int s; + XButtonEvent *be; + XMotionEvent *me; + Gwinmouse m; + Mousefunc f; + + switch(e->type){ + case ButtonPress: + be = (XButtonEvent *)e; + m.xy.x = be->x; + m.xy.y = be->y; + m.msec = be->time; + s = be->state; /* the previous state */ + switch(be->button){ + case 1: s |= Button1Mask; break; + case 2: s |= Button2Mask; break; + case 3: s |= Button3Mask; break; + } + break; + case ButtonRelease: + be = (XButtonEvent *)e; + m.xy.x = be->x; + m.xy.y = be->y; + m.msec = be->time; + s = be->state; + switch(be->button){ + case 1: s &= ~Button1Mask; break; + case 2: s &= ~Button2Mask; break; + case 3: s &= ~Button3Mask; break; + } + break; + case MotionNotify: + me = (XMotionEvent *)e; + s = me->state; + m.xy.x = me->x; + m.xy.y = me->y; + m.msec = me->time; + break; + default: + return; + } + m.buttons = 0; + if(s & Button1Mask) m.buttons |= 1; + if(s & Button2Mask) m.buttons |= 2; + if(s & Button3Mask) m.buttons |= 4; + f = ((GwinWidget)w)->gwin.gotmouse; + if(f) + (*f)(&m); +} + +static void +SelCallback(Widget w, XtPointer cldata, Atom *sel, Atom *seltype, + XtPointer val, unsigned long *len, int *fmt) +{ + String s; + int n; + GwinWidget gw = (GwinWidget)w; + + if(gw->gwin.selection) + XtFree(gw->gwin.selection); + if(*seltype != XA_STRING) + n = 0; + else + n = (*len) * (*fmt/8); + s = (String)XtMalloc(n+1); + if(n > 0) + memcpy(s, (char *)val, n); + s[n] = 0; + gw->gwin.selection = s; + XtFree(val); +} + +static Boolean +SendSel(Widget w, Atom *sel, Atom *target, Atom *rtype, XtPointer *ans, + unsigned long *anslen, int *ansfmt) +{ + GwinWidget gw = (GwinWidget)w; + static Atom targets = 0; + XrmValue src, dst; + char *s; + + if(*target == XA_STRING){ + s = gw->gwin.selection; + if(!s) + s = ""; + *rtype = XA_STRING; + *ans = (XtPointer) XtNewString(s); + *anslen = strlen(*ans); + *ansfmt = 8; + return TRUE; + } +#ifndef R3 + if(targets == 0){ + src.addr = "TARGETS"; + src.size = strlen(src.addr)+1; + dst.size = sizeof(Atom); + dst.addr = (XtPointer) &targets; + XtConvertAndStore(w, XtRString, &src, XtRAtom, &dst); + } + if(*target == targets){ + *rtype = XA_ATOM; + *ans = (XtPointer) XtNew(Atom); + *(Atom*) *ans = XA_STRING; + *anslen = 1; + *ansfmt = 32; + return TRUE; + } +#endif + return FALSE; +} + +static String +SelectSwap(Widget w, String s) +{ + GwinWidget gw; + String ans; + + gw = (GwinWidget)w; + + if(!gw->gwin.selection){ +#ifdef R3 + XtGetSelectionValue(w, XA_PRIMARY, XA_STRING, SelCallback, 0, + CurrentTime); +#else + XtGetSelectionValue(w, XA_PRIMARY, XA_STRING, SelCallback, 0, + XtLastTimestampProcessed(XtDisplay(w))); +#endif + while(gw->gwin.selection == 0) + XtAppProcessEvent(XtWidgetToApplicationContext(w) , XtIMAll); + } + ans = gw->gwin.selection; + gw->gwin.selection = XtMalloc(strlen(s)+1); + strcpy(gw->gwin.selection, s); +#ifdef R3 + XtOwnSelection(w, XA_PRIMARY, CurrentTime, SendSel, LoseSel, NULL); +#else + XtOwnSelection(w, XA_PRIMARY, XtLastTimestampProcessed(XtDisplay(w)), + SendSel, LoseSel, NULL); +#endif + return ans; +} + +/* The returned answer should be free()ed when no longer needed */ +String +GwinSelectionSwap(Widget w, String s) +{ + XtCheckSubclass(w, gwinWidgetClass, NULL); + return (*((GwinWidgetClass) XtClass(w))->gwin_class.select_swap)(w, s); +} + +static void +own_selection(Widget w) +{ +#ifdef R3 + XtOwnSelection(w, XA_PRIMARY, CurrentTime, SendSel, LoseSel, NULL); +#else + XtOwnSelection(w, XA_PRIMARY, XtLastTimestampProcessed(XtDisplay(w)), + SendSel, LoseSel, NULL); +#endif +} + +static void +get_selection(Widget w) +{ +#ifdef R3 + XtGetSelectionValue(w, XA_PRIMARY, XA_STRING, SelCallback, 0, + CurrentTime); +#else + XtGetSelectionValue(w, XA_PRIMARY, XA_STRING, SelCallback, 0, + XtLastTimestampProcessed(XtDisplay(w))); +#endif +} + +/* Get current selection. Returned string isn't yours to free or + * keep - copy it and forget it. + */ +char* +Gwinselect_get(Widget w) +{ + GwinWidget gw = (GwinWidget)w; + + if(!gw->gwin.selection){ + get_selection(w); + while(gw->gwin.selection == 0) + XtAppProcessEvent(XtWidgetToApplicationContext(w) , XtIMAll); + } + own_selection(w); + return gw->gwin.selection; +} + +/* Set current selection to 's' */ +void +Gwinselect_put(Widget w,char*s) +{ + GwinWidget gw = (GwinWidget)w; + if(gw->gwin.selection) + XtFree(gw->gwin.selection); + gw->gwin.selection = XtMalloc(strlen(s)+1); + strcpy(gw->gwin.selection, s); + own_selection(w); +} + diff --git a/libXg/latin1.c b/libXg/latin1.c new file mode 100644 index 0000000..bfc6418 --- /dev/null +++ b/libXg/latin1.c @@ -0,0 +1,247 @@ +/* Copyright (c) 1992 AT&T - All rights reserved. */ + +struct latin +{ + unsigned short l; + unsigned char c[2]; +}latintab[] = { + 0x00a1, '!','!', /* spanish initial ! */ + 0x00a2, 'c','$', /* cent */ + 0x00a3, 'l','$', /* pound sterling */ + 0x00a4, 'g','$', /* general currency */ + 0x00a5, 'y','$', /* yen */ + 0x00a6, '|','|', /* broken vertical bar */ + 0x00a7, 'S','S', /* section symbol */ + 0x00a8, '\"','\"', /* dieresis */ + 0x00a9, 'c','O', /* copyright */ + 0x00aa, 's','a', /* super a, feminine ordinal */ + 0x00ab, '<','<', /* left angle quotation */ + 0x00ac, 'n','o', /* not sign, hooked overbar */ + 0x00ad, '-','-', /* soft hyphen */ + 0x00ae, 'r','O', /* registered trademark */ + 0x00af, '_','_', /* macron */ + 0x00b0, 'd','e', /* degree */ + 0x00b1, '+','-', /* plus-minus */ + 0x00b2, 's','2', /* sup 2 */ + 0x00b3, 's','3', /* sup 3 */ + 0x00b4, '\'','\'', /* acute accent */ + 0x00b5, 'm','i', /* micron */ + 0x00b6, 'p','g', /* paragraph (pilcrow) */ + 0x00b7, '.','.', /* centered . */ + 0x00b8, ',',',', /* cedilla */ + 0x00b9, 's','1', /* sup 1 */ + 0x00ba, 's','o', /* super o, masculine ordinal */ + 0x00bb, '>','>', /* right angle quotation */ + 0x00bc, '1','4', /* 1/4 */ + 0x00bd, '1','2', /* 1/2 */ + 0x00be, '3','4', /* 3/4 */ + 0x00bf, '?','?', /* spanish initial ? */ + 0x00c0, '`','A', /* A grave */ + 0x00c1, '\'','A', /* A acute */ + 0x00c2, '^','A', /* A circumflex */ + 0x00c3, '~','A', /* A tilde */ + 0x00c4, '\"','A', /* A dieresis */ + 0x00c5, 'o','A', /* A circle */ + 0x00c6, 'A','E', /* AE ligature */ + 0x00c7, ',','C', /* C cedilla */ + 0x00c8, '`','E', /* E grave */ + 0x00c9, '\'','E', /* E acute */ + 0x00ca, '^','E', /* E circumflex */ + 0x00cb, '\"','E', /* E dieresis */ + 0x00cc, '`','I', /* I grave */ + 0x00cd, '\'','I', /* I acute */ + 0x00ce, '^','I', /* I circumflex */ + 0x00cf, '\"','I', /* I dieresis */ + 0x00d0, 'D','-', /* Eth */ + 0x00d1, '~','N', /* N tilde */ + 0x00d2, '`','O', /* O grave */ + 0x00d3, '\'','O', /* O acute */ + 0x00d4, '^','O', /* O circumflex */ + 0x00d5, '~','O', /* O tilde */ + 0x00d6, '\"','O', /* O dieresis */ + 0x00d7, 'm','u', /* times sign */ + 0x00d8, '/','O', /* O slash */ + 0x00d9, '`','U', /* U grave */ + 0x00da, '\'','U', /* U acute */ + 0x00db, '^','U', /* U circumflex */ + 0x00dc, '\"','U', /* U dieresis */ + 0x00dd, '\'','Y', /* Y acute */ + 0x00de, '|','P', /* Thorn */ + 0x00df, 's','s', /* sharp s */ + 0x00e0, '`','a', /* a grave */ + 0x00e1, '\'','a', /* a acute */ + 0x00e2, '^','a', /* a circumflex */ + 0x00e3, '~','a', /* a tilde */ + 0x00e4, '\"','a', /* a dieresis */ + 0x00e5, 'o','a', /* a circle */ + 0x00e6, 'a','e', /* ae ligature */ + 0x00e7, ',','c', /* c cedilla */ + 0x00e8, '`','e', /* e grave */ + 0x00e9, '\'','e', /* e acute */ + 0x00ea, '^','e', /* e circumflex */ + 0x00eb, '\"','e', /* e dieresis */ + 0x00ec, '`','i', /* i grave */ + 0x00ed, '\'','i', /* i acute */ + 0x00ee, '^','i', /* i circumflex */ + 0x00ef, '\"','i', /* i dieresis */ + 0x00f0, 'd','-', /* eth */ + 0x00f1, '~','n', /* n tilde */ + 0x00f2, '`','o', /* o grave */ + 0x00f3, '\'','o', /* o acute */ + 0x00f4, '^','o', /* o circumflex */ + 0x00f5, '~','o', /* o tilde */ + 0x00f6, '\"','o', /* o dieresis */ + 0x00f7, '-',':', /* divide sign */ + 0x00f8, '/','o', /* o slash */ + 0x00f9, '`','u', /* u grave */ + 0x00fa, '\'','u', /* u acute */ + 0x00fb, '^','u', /* u circumflex */ + 0x00fc, '\"','u', /* u dieresis */ + 0x00fd, '\'','y', /* y acute */ + 0x00fe, '|','p', /* thorn */ + 0x00ff, '\"','y', /* y dieresis */ + 0x2654, 'w','k', /* chess white king */ + 0x2655, 'w','q', /* chess white queen */ + 0x2656, 'w','r', /* chess white rook */ + 0x2657, 'w','b', /* chess white bishop */ + 0x2658, 'w','n', /* chess white knight */ + 0x2659, 'w','p', /* chess white pawn */ + 0x265a, 'b','k', /* chess black king */ + 0x265b, 'b','q', /* chess black queen */ + 0x265c, 'b','r', /* chess black rook */ + 0x265d, 'b','b', /* chess black bishop */ + 0x265e, 'b','n', /* chess black knight */ + 0x265f, 'b','p', /* chess black pawn */ + 0x03b1, '*','a', /* alpha */ + 0x03b2, '*','b', /* beta */ + 0x03b3, '*','g', /* gamma */ + 0x03b4, '*','d', /* delta */ + 0x03b5, '*','e', /* epsilon */ + 0x03b6, '*','z', /* zeta */ + 0x03b7, '*','y', /* eta */ + 0x03b8, '*','h', /* theta */ + 0x03b9, '*','i', /* iota */ + 0x03ba, '*','k', /* kappa */ + 0x03bb, '*','l', /* lambda */ + 0x03bc, '*','m', /* mu */ + 0x03bd, '*','n', /* nu */ + 0x03be, '*','c', /* xsi */ + 0x03bf, '*','o', /* omicron */ + 0x03c0, '*','p', /* pi */ + 0x03c1, '*','r', /* rho */ + 0x03c2, 't','s', /* terminal sigma */ + 0x03c3, '*','s', /* sigma */ + 0x03c4, '*','t', /* tau */ + 0x03c5, '*','u', /* upsilon */ + 0x03c6, '*','f', /* phi */ + 0x03c7, '*','x', /* chi */ + 0x03c8, '*','q', /* psi */ + 0x03c9, '*','w', /* omega */ + 0x0391, '*','A', /* Alpha */ + 0x0392, '*','B', /* Beta */ + 0x0393, '*','G', /* Gamma */ + 0x0394, '*','D', /* Delta */ + 0x0395, '*','E', /* Epsilon */ + 0x0396, '*','Z', /* Zeta */ + 0x0397, '*','Y', /* Eta */ + 0x0398, '*','H', /* Theta */ + 0x0399, '*','I', /* Iota */ + 0x039a, '*','K', /* Kappa */ + 0x039b, '*','L', /* Lambda */ + 0x039c, '*','M', /* Mu */ + 0x039d, '*','N', /* Nu */ + 0x039e, '*','C', /* Xsi */ + 0x039f, '*','O', /* Omicron */ + 0x03a0, '*','P', /* Pi */ + 0x03a1, '*','R', /* Rho */ + 0x03a3, '*','S', /* Sigma */ + 0x03a4, '*','T', /* Tau */ + 0x03a5, '*','U', /* Upsilon */ + 0x03a6, '*','F', /* Phi */ + 0x03a7, '*','X', /* Chi */ + 0x03a8, '*','Q', /* Psi */ + 0x03a9, '*','W', /* Omega */ + 0x2190, '<','-', /* left arrow */ + 0x2191, 'u','a', /* up arrow */ + 0x2192, '-','>', /* right arrow */ + 0x2193, 'd','a', /* down arrow */ + 0x2194, 'a','b', /* arrow both */ + 0x21d0, 'V','=', /* left double-line arrow */ + 0x21d2, '=','V', /* right double-line arrow */ + 0x2200, 'f','a', /* forall */ + 0x2203, 't','e', /* there exists */ + 0x2202, 'p','d', /* partial differential */ + 0x2205, 'e','s', /* empty set */ + 0x2206, 'D','e', /* delta */ + 0x2207, 'g','r', /* gradient */ + 0x2208, 'm','o', /* element of */ + 0x2209, '!','m', /* not element of */ + 0x220d, 's','t', /* such that */ + 0x2217, '*','*', /* math asterisk */ + 0x2219, 'b','u', /* bullet */ + 0x221a, 's','r', /* radical */ + 0x221d, 'p','t', /* proportional */ + 0x221e, 'i','f', /* infinity */ + 0x2220, 'a','n', /* angle */ + 0x2227, 'l','&', /* logical and */ + 0x2228, 'l','|', /* logical or */ + 0x2229, 'c','a', /* intersection */ + 0x222a, 'c','u', /* union */ + 0x222b, 'i','s', /* integral */ + 0x2234, 't','f', /* therefore */ + 0x2243, '~','=', /* asymptotically equal */ + 0x2245, 'c','g', /* congruent */ + 0x2248, '~','~', /* almost equal */ + 0x2260, '!','=', /* not equal */ + 0x2261, '=','=', /* equivalent */ + 0x2266, '<','=', /* less than or equal */ + 0x2267, '>','=', /* greater than or equal */ + 0x2282, 's','b', /* proper subset */ + 0x2283, 's','p', /* proper superset */ + 0x2284, '!','b', /* not subset */ + 0x2286, 'i','b', /* reflexive subset */ + 0x2287, 'i','p', /* reflexive superset */ + 0x2295, 'O','+', /* circle plus */ + 0x2296, 'O','-', /* circle minus */ + 0x2297, 'O','x', /* circle multiply */ + 0x22a2, 't','u', /* turnstile */ + 0x22a8, 'T','u', /* valid */ + 0x22c4, 'l','z', /* lozenge */ + 0x22ef, 'e','l', /* ellipses */ + 0x2639, ':','(', /* saddy */ + 0x263a, ':',')', /* white-face smiley */ + 0x263b, ';',')', /* dark-face smiley */ + 0, 0, +}; + +long +latin1(unsigned char *k) +{ + struct latin *l; + + for(l=latintab; l->l; l++) + if(k[0]==l->c[0] && k[1]==l->c[1]) + return l->l; + return -1; +} + +long +unicode(unsigned char *k) +{ + long i, c; + + k++; /* skip 'X' */ + c = 0; + for(i=0; i<4; i++,k++){ + c <<= 4; + if('0'<=*k && *k<='9') + c += *k-'0'; + else if('a'<=*k && *k<='f') + c += 10 + *k-'a'; + else if('A'<=*k && *k<='F') + c += 10 + *k-'A'; + else + return -1; + } + return c; +} diff --git a/libXg/ldconvert.c b/libXg/ldconvert.c new file mode 100644 index 0000000..7f2d931 --- /dev/null +++ b/libXg/ldconvert.c @@ -0,0 +1,54 @@ +/* Copyright (c) 1992 AT&T - All rights reserved. */ +#include <libc.h> +#include <libg.h> +#include "libgint.h" + +void +_ldconvert(char *in, int inld, char *out, int outld, int w, int h) +{ + int a, b, i, j, i1, j1, j2, mask; + int ind, inl, outd, outl; + int hh, ww; + char *p, *q; + + i1 = 8 >> inld; + j1 = 8 >> outld; + ind = 1 << inld; + outd = 1 << outld; + inl = ((w << inld) + 7)/8; + outl = ((w << outld) + 7)/8; + b = 0; + + if (ind > outd) { + mask = 256 - (256 >> outd); + for (hh = 0; hh < h; hh++, in += inl, out += outl) + for (p = in, q = out, ww = 0; ww < w; ww++) { + for (j = j1; j > 0; ) { + a = *p++; + for (i = i1; i > 0; i--, j--) { + b |= a & mask; + a <<= ind; + b <<= outd; + } + } + *q++ = (b >> 8); + } + } else { + j2 = 1 << (outld - inld); + mask = 256 - (256 >> ind); + for (hh = 0; hh < h; hh++, in += inl, out += outl) + for (p = in, q = out, ww = 0; ww < w; ww++) { + a = *p++; + for (i = i1; i > 0; ) { + for (j = j1; j > 0; j--, i--) { + b |= a & mask; + a <<= ind; + b <<= outd; + } + for (j = j2; j > 0; j--) + b |= (b << ind); + *q++ = (b >> 8); + } + } + } +} diff --git a/libXg/libgint.h b/libXg/libgint.h new file mode 100644 index 0000000..86bb5de --- /dev/null +++ b/libXg/libgint.h @@ -0,0 +1,94 @@ +/* Copyright (c) 1992 AT&T - All rights reserved. */ +/* internal libg implementation file - include after libg */ + +/* + * include defs of standard library routines, if possible, + * and string routines + */ +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif +#ifdef STDC_HEADERS +#include <string.h> +#endif /* STDC_HEADERS */ + +/* + * use defines to rename X11 types Cursor, Font, Event + */ + +#define Cursor xCursor +#define Font xFont +#define Event xEvent + +#if defined(v10) || defined(HPUX) +typedef char* caddr_t; +#endif + +#include <X11/Xlib.h> +#include <X11/Xatom.h> +#include <X11/Xutil.h> + +#undef Cursor +#undef Font +#undef Event + +/* Return a GCs for solid filling/strings/etc., segments/points, and tiling */ +extern GC _getfillgc(Fcode, Bitmap*, unsigned long); +extern GC _getcopygc(Fcode, Bitmap*, Bitmap*, int*); +extern GC _getgc(Bitmap*, unsigned long, XGCValues *); + +/* convert between different bitmap depths */ +extern void _ldconvert(char *, int, char *, int, int, int); + +/* balloc without zero init (which uses a gc!) */ +extern Bitmap *_balloc(Rectangle, int); + +/* X Display for this application's connection */ +extern Display *_dpy; + +/* screen depth foreground and background for this application */ +extern unsigned long _fgpixel, _bgpixel; +extern XColor _fgcolor, _bgcolor; + +/* indexed by log depth (0 <= ld <= 5), to give depth and planemask */ +extern int _ld2d[]; +extern unsigned long _ld2dmask[]; + +/* libg.h defines: + * extern Bitmap screen; -- Bitmap for application Window after xbinit() + * extern Font *font; -- Font for application default font after xbinit() + */ + +/* + * Conventions: + * The .id field of a Bitmap is an X Pixmap unless the Bitmap is screen, + * in which case it is a Window. + * The .id field of a Cursor is set to the X xCursor the first time the + * cursor is used. + * The .id field of a Font is set to the X xFont. + * + * Coordinate conventions: libg bitmaps can have non (0,0) origins, + * but not X Pixmaps, so we have to subtract the min point of a Bitmap + * from coords in the Bitmap before using the point in the corresponding Pixmap. + * The screen Bitmap, however, contains the rectangle in X coords of the + * widget in which the application is started, relative to the window. + * The origin may or may not be (0,0), but in any case, coordinates should + * NOT be translated before using in X calls on the Window. + */ + +/* values for bitmap flag field (see _getcopygc if change first two vals) */ +enum { + DP1= 0x1, /* depth == 1 (ldepth == 0) */ + BL1= 0x2, /* black == 1 model */ + SCR= 0x4, /* on screen */ + ZORG= 0x8, /* r.min == Pt(0,0) */ + SHIFT= 0x20, /* !SCR & !ZORG */ + CLIP= 0x40 /* r != clipr */ +}; + +/* values for return bltfunc arg of _getcopygc */ +enum { + UseCopyArea, + UseCopyPlane, + UseFillRectangle +}; diff --git a/libXg/menuhit.c b/libXg/menuhit.c new file mode 100644 index 0000000..f51547c --- /dev/null +++ b/libXg/menuhit.c @@ -0,0 +1,236 @@ +/* Copyright (c) 1992 AT&T - All rights reserved. */ +#include <u.h> +#include <libc.h> +#include <libg.h> +#include "libgint.h" + +enum +{ + Margin = 3, /* outside to text */ + Border = 2, /* outside to selection boxes */ + Blackborder = 1, /* width of outlining border */ + Vspacing = 1, /* extra spacing between lines of text */ + Maxunscroll = 25, /* maximum #entries before scrolling turns on */ + Nscroll = 20, /* number entries in scrolling part */ + Scrollwid = 14, /* width of scroll bar */ + Gap = 4 /* between text and scroll bar */ +}; + +static Bitmap *menutxt; + +static uchar menutxtbits[] = { + 0x22, 0x22, 0x88, 0x88, 0x22, 0x22, 0x88, 0x88, + 0x22, 0x22, 0x88, 0x88, 0x22, 0x22, 0x88, 0x88, + 0x22, 0x22, 0x88, 0x88, 0x22, 0x22, 0x88, 0x88, + 0x22, 0x22, 0x88, 0x88, 0x22, 0x22, 0x88, 0x88, +}; + +/* + * r is a rectangle holding the text elements. + * return the rectangle, including its black edge, holding element i. + */ +static Rectangle +menurect(Rectangle r, int i) +{ + if(i < 0) + return Rect(0, 0, 0, 0); + r.min.y += (font->height+Vspacing)*i; + r.max.y = r.min.y+font->height+Vspacing; + return inset(r, Border-Margin); +} + +/* + * r is a rectangle holding the text elements. + * return the element number containing p. + */ +static int +menusel(Rectangle r, Point p) +{ + if(!ptinrect(p, r)) + return -1; + return (p.y-r.min.y)/(font->height+Vspacing); +} + +/* + * menur is a rectangle holding all the highlightable text elements. + * track mouse while inside the box, return what's selected when button + * is raised, -1 as soon as it leaves box. + * invariant: nothing is highlighted on entry or exit. + */ +static int +menuscan(int but, Mouse *m, Rectangle menur, int lasti) +{ + int i; + Rectangle r; + + r = menurect(menur, lasti); + bitblt(&screen, r.min, &screen, r, F&~D); + *m = emouse(); + while(m->buttons & (1<<(but-1))){ + *m = emouse(); + i = menusel(menur, m->xy); + if(i == lasti) + continue; + bitblt(&screen, r.min, &screen, r, F&~D); + if(i == -1) + return i; + r = menurect(menur, i); + bitblt(&screen, r.min, &screen, r, F&~D); + lasti = i; + } + return lasti; +} + +void +menupaint(Menu *menu, Rectangle textr, int off, int nitemdrawn) +{ + int i; + Point pt; + Rectangle r; + char *item; + + r = inset(textr, Border-Margin); + bitblt(&screen, r.min, &screen, r, 0); + pt = Pt(textr.min.x+textr.max.x, textr.min.y); + for(i = 0; i<nitemdrawn; i++, pt.y += font->height+Vspacing){ + item = menu->item? menu->item[i+off] : (*menu->gen)(i+off); + string(&screen, + Pt((pt.x-strwidth(font, item))/2, pt.y), + font, item, S); + } +} + +static void +menuscrollpaint(Rectangle scrollr, int off, int nitem, int nitemdrawn) +{ + Rectangle r; + + bitblt(&screen, scrollr.min, &screen, scrollr, 0); + r.min.x = scrollr.min.x; + r.max.x = scrollr.max.x; + r.min.y = scrollr.min.y + (Dy(scrollr)*off)/nitem; + r.max.y = scrollr.min.y + (Dy(scrollr)*(off+nitemdrawn))/nitem; + if(r.max.y < r.min.y+2) + r.max.y = r.min.y+2; + border(&screen, r, 1, F); + if(menutxt == 0){ + menutxt = balloc(Rect(0, 0, 16, 16), 0); + if(menutxt) + wrbitmap(menutxt, 0, 16, menutxtbits); + } + if(menutxt) + texture(&screen, inset(r, 1), menutxt, S); +} + +int +menuhit(int but, Mouse *m, Menu *menu) +{ + int i, nitem, nitemdrawn, maxwid, lasti, off, noff, wid, screenitem; + int scrolling; + Rectangle r, menur, sc, textr, scrollr; + Bitmap *b; + Point pt; + char *item; + + sc = screen.clipr; + clipr(&screen, screen.r); + maxwid = 0; + for(nitem = 0; + item = menu->item? menu->item[nitem] : (*menu->gen)(nitem); + nitem++){ + i = strwidth(font, item); + if(i > maxwid) + maxwid = i; + } + if(menu->lasthit<0 || menu->lasthit>=nitem) + menu->lasthit = 0; + screenitem = (Dy(screen.r)-10)/(font->height+Vspacing); + if(nitem>Maxunscroll || nitem>screenitem){ + scrolling = 1; + nitemdrawn = Nscroll; + if(nitemdrawn > screenitem) + nitemdrawn = screenitem; + wid = maxwid + Gap + Scrollwid; + off = menu->lasthit - nitemdrawn/2; + if(off < 0) + off = 0; + if(off > nitem-nitemdrawn) + off = nitem-nitemdrawn; + lasti = menu->lasthit-off; + }else{ + scrolling = 0; + nitemdrawn = nitem; + wid = maxwid; + off = 0; + lasti = menu->lasthit; + } + r = inset(Rect(0, 0, wid, nitemdrawn*(font->height+Vspacing)), -Margin); + r = rsubp(r, Pt(wid/2, lasti*(font->height+Vspacing)+font->height/2)); + r = raddp(r, m->xy); + pt = Pt(0, 0); + if(r.max.x>screen.r.max.x) + pt.x = screen.r.max.x-r.max.x; + if(r.max.y>screen.r.max.y) + pt.y = screen.r.max.y-r.max.y; + if(r.min.x<screen.r.min.x) + pt.x = screen.r.min.x-r.min.x; + if(r.min.y<screen.r.min.y) + pt.y = screen.r.min.y-r.min.y; + menur = raddp(r, pt); + textr.max.x = menur.max.x-Margin; + textr.min.x = textr.max.x-maxwid; + textr.min.y = menur.min.y+Margin; + textr.max.y = textr.min.y + nitemdrawn*(font->height+Vspacing); + if(scrolling){ + scrollr = inset(menur, Border); + scrollr.max.x = scrollr.min.x+Scrollwid; + }else + scrollr = Rect(0, 0, 0, 0); + + b = balloc(menur, screen.ldepth); + if(b == 0) + b = &screen; + bitblt(b, menur.min, &screen, menur, S); + bitblt(&screen, menur.min, &screen, menur, 0); + border(&screen, menur, Blackborder, F); + r = menurect(textr, lasti); + cursorset(divpt(add(r.min, r.max), 2)); + menupaint(menu, textr, off, nitemdrawn); + if(scrolling) + menuscrollpaint(scrollr, off, nitem, nitemdrawn); + r = menurect(textr, lasti); + cursorset(divpt(add(r.min, r.max), 2)); + menupaint(menu, textr, off, nitemdrawn); + if(scrolling) + menuscrollpaint(scrollr, off, nitem, nitemdrawn); + while(m->buttons & (1<<(but-1))){ + lasti = menuscan(but, m, textr, lasti); + if(lasti >= 0) + break; + while(!ptinrect(m->xy, textr) && (m->buttons & (1<<(but-1)))){ + if(scrolling && ptinrect(m->xy, scrollr)){ + noff = ((m->xy.y-scrollr.min.y)*nitem)/Dy(scrollr); + noff -= nitemdrawn/2; + if(noff < 0) + noff = 0; + if(noff > nitem-nitemdrawn) + noff = nitem-nitemdrawn; + if(noff != off){ + off = noff; + menupaint(menu, textr, off, nitemdrawn); + menuscrollpaint(scrollr, off, nitem, nitemdrawn); + } + } + *m = emouse(); + } + } + bitblt(&screen, menur.min, b, menur, S); + if(b != &screen) + bfree(b); + clipr(&screen, sc); + if(lasti >= 0){ + menu->lasthit = lasti+off; + return menu->lasthit; + } + return -1; +} diff --git a/libXg/mkfont.c b/libXg/mkfont.c new file mode 100644 index 0000000..c555ecf --- /dev/null +++ b/libXg/mkfont.c @@ -0,0 +1,47 @@ +/* Copyright (c) 1992 AT&T - All rights reserved. */ +#include <libc.h> +#include <libg.h> +#include <string.h> + +/* + * Cobble fake font using existing subfont + */ +Font* +mkfont(Subfont *subfont) +{ + Font *font; + unsigned char *gbuf; + Cachesubf *c; + char *cp; + + font = (Font *)malloc(sizeof(Font)); + if(font == 0) + return 0; + memset((void*)font, 0, sizeof(Font)); + cp = "<synthetic>"; + font->name = (char *)malloc(strlen(cp)+1); + if (font->name == 0) { + free(font); + return 0; + } + strcpy(font->name, cp); + font->nsubf = 1; + font->subf = (Cachesubf *)malloc(font->nsubf * sizeof(Cachesubf)); + if(font->subf == 0) + { + free(font->name); + free(font); + return 0; + } + memset((void*)font->subf, 0, font->nsubf*sizeof(Cachesubf)); + font->height = subfont->height; + font->ascent = subfont->ascent; + font->ldepth = screen.ldepth; + c = font->subf; + subfont->minchar = subfont->mincol; /* base font at first char */ + c->min = subfont->minchar; + c->max = subfont->maxchar; + c->name = 0; /* noticed by freeup() */ + font->subf[0].f = subfont; + return font; +} diff --git a/libXg/point.c b/libXg/point.c new file mode 100644 index 0000000..1c1d26a --- /dev/null +++ b/libXg/point.c @@ -0,0 +1,20 @@ +/* Copyright (c) 1992 AT&T - All rights reserved. */ +#include <libc.h> +#include <libg.h> +#include "libgint.h" + +void +point(Bitmap *b, Point p, int v, Fcode f) +{ + int x, y; + GC g; + + x = p.x; + y = p.y; + if(b->flag&SHIFT){ + x -= b->r.min.x; + y -= b->r.min.y; + } + g = _getfillgc(f, b, v); + XDrawPoint(_dpy, (Drawable)b->id, g, x, y); +} diff --git a/libXg/polysegment.c b/libXg/polysegment.c new file mode 100644 index 0000000..72cbe6f --- /dev/null +++ b/libXg/polysegment.c @@ -0,0 +1,26 @@ +/* Copyright (c) 1992 AT&T - All rights reserved. */ +#include <libc.h> +#include <libg.h> +#include "libgint.h" + +void +polysegment(Bitmap *d, int n, Point *pp, int v, Fcode f) +{ + XPoint *xp; + int i; + GC g; + + if (!(xp = (XPoint *)calloc(n, sizeof(XPoint)))) + berror("polysegment: could not allocate XPoints"); + for (i = 0; i < n; i++, pp++) + if(d->flag&SHIFT){ + xp[i].x = pp->x - d->r.min.x; + xp[i].y = pp->y - d->r.min.y; + } else { + xp[i].x = pp->x; + xp[i].y = pp->y; + } + g = _getfillgc(f, d, v); + XDrawLines(_dpy, (Drawable)d->id, g, xp, n, CoordModeOrigin); + free(xp); +} diff --git a/libXg/rdbitmap.c b/libXg/rdbitmap.c new file mode 100644 index 0000000..63c508f --- /dev/null +++ b/libXg/rdbitmap.c @@ -0,0 +1,62 @@ +/* Copyright (c) 1992 AT&T - All rights reserved. */ +#include <libc.h> +#include <libg.h> +#include "libgint.h" + +void +rdbitmap(Bitmap *b, int miny, int maxy, unsigned char *data) +{ + XImage *gim, *eim; + int x, y, w, h, pix, l, offset, px; + int inld, outld; + char *tdata; + + /* + * The XGetImage returned image may be wrong in a number of ways: + * wrong bit order, byte order, bit pad, scanline pad, + * and constant shift. + * So use a SLOW loop, for now + */ + w = Dx(b->r); + h = maxy - miny; + outld = b->ldepth; + inld = (b->ldepth == 0) ? 0 : screen.ldepth; + gim = XGetImage(_dpy, (Drawable)b->id, 0, miny - b->r.min.y, + w, h, ~0, ZPixmap); + px = 1<<(3-outld); /* pixels per byte */ + /* set l to number of bytes of data per scan line */ + if(b->r.min.x >= 0) + offset = b->r.min.x % px; + else + offset = px - b->r.min.x % px; + l = (-b->r.min.x+px-1)/px; + if(b->r.max.x >= 0) + l += (b->r.max.x+px-1)/px; + else + l -= b->r.max.x/px; + l *= h; + if(l <= 0) + return; + tdata = (char *)malloc(l); + if (tdata == (char *) 0) + berror("rdbitmap malloc"); + eim = XCreateImage(_dpy, 0, 1 << inld, ZPixmap, 0, tdata, + w+offset, h, 8, 0); + eim->bitmap_pad = 8; + eim->bitmap_bit_order = MSBFirst; + eim->byte_order = MSBFirst; + + for(y = 0; y < h; y++) + for(x = 0; x < w; x++) { + pix = XGetPixel(gim, x, y); + XPutPixel(eim, x+offset, y, pix); + } + + if (inld == outld) + memcpy((char *)data, tdata, l); + else + _ldconvert(tdata, inld, (char*)data, outld, w, h); + + XDestroyImage(gim); + XDestroyImage(eim); +} diff --git a/libXg/rdbitmapfile.c b/libXg/rdbitmapfile.c new file mode 100644 index 0000000..ae8ec52 --- /dev/null +++ b/libXg/rdbitmapfile.c @@ -0,0 +1,64 @@ +/* Copyright (c) 1992 AT&T - All rights reserved. */ +#include <libc.h> +#include <libg.h> +#include "libgint.h" + +#define CHUNK 6000 + +Bitmap* +rdbitmapfile(int fd) +{ + char hdr[5*12+1]; + unsigned char *data; + long dy, px; + unsigned long l, t, n; + long miny, maxy; + Rectangle r; + int ld; + Bitmap *b; + + if(read(fd, hdr, 5*12)!=5*12) + berror("rdbitmapfile read"); + ld = atoi(hdr+0*12); + r.min.x = atoi(hdr+1*12); + r.min.y = atoi(hdr+2*12); + r.max.x = atoi(hdr+3*12); + r.max.y = atoi(hdr+4*12); + if(ld<0 || ld>1) + berror("rdbitmapfile ldepth"); + if(r.min.x>r.max.x || r.min.y>r.max.y) + berror("rdbitmapfile rectangle"); + + miny = r.min.y; + maxy = r.max.y; + px = 1<<(3-ld); /* pixels per byte */ + /* set l to number of bytes of data per scan line */ + if(r.min.x >= 0) + l = (r.max.x+px-1)/px - r.min.x/px; + else{ /* make positive before divide */ + t = (-r.min.x)+px-1; + t = (t/px)*px; + l = (t+r.max.x+px-1)/px; + } + b = balloc(r, ld); + if(b == 0) + return 0; + data = (unsigned char *)malloc(CHUNK); + if(data == 0) + berror("rdbitmapfile malloc"); + while(maxy > miny){ + dy = maxy - miny; + if(dy*l > CHUNK) + dy = CHUNK/l; + n = dy*l; + if(read(fd, data, n) != n){ + free(data); + bfree(b); + berror("rdbitmapfile read"); + } + wrbitmap(b, miny, miny+dy, data); + miny += dy; + } + free(data); + return b; +} diff --git a/libXg/rdfontfile.c b/libXg/rdfontfile.c new file mode 100644 index 0000000..7206e9b --- /dev/null +++ b/libXg/rdfontfile.c @@ -0,0 +1,135 @@ +#include <u.h> +#include <libc.h> +#include <libg.h> +#include "libgint.h" +#include <string.h> +#include <fcntl.h> +#include <sys/stat.h> + +static char* +skip(char *s) +{ + while (*s==' ' || *s=='\n' || *s=='\t') + s++; + return s; +} + +Font * +rdfontfile(char *name, int ldepth) +{ + Font *fnt; + Cachesubf *c; + int fd, i; + char *buf, *s, *t; + struct stat sbuf; + unsigned long min, max; + + fd = open(name, O_RDONLY); + if (fd < 0) + return 0; + if (fstat(fd, &sbuf) < 0) + { + Err0: + close(fd); + return 0; + } + buf = (char *)malloc(sbuf.st_size+1); + if (buf == 0) + goto Err0; + buf[sbuf.st_size] = 0; + i = read(fd, buf, sbuf.st_size); + close(fd); + if (i != sbuf.st_size) + { + Err1: + free(buf); + return 0; + } + + s = buf; + fnt = (Font *)malloc(sizeof(Font)); + if (fnt == 0) + goto Err1; + memset((void*)fnt, 0, sizeof(Font)); + fnt->name = (char *)malloc(strlen(name)+1); + if (fnt->name==0) + { + Err2: + free(fnt->name); + free(fnt); + goto Err1; + } + strcpy(fnt->name, name); + fnt->height = strtol(s, &s, 0); + s = skip(s); + fnt->ascent = strtol(s, &s, 0); + s = skip(s); + if (fnt->height<=0 || fnt->ascent<=0) + goto Err2; + fnt->width = 0; + fnt->ldepth = ldepth; + + fnt->id = 0; + fnt->nsubf = 0; + fnt->subf = 0; + + do { + min = strtol(s, &s, 0); + s = skip(s); + max = strtol(s, &s, 0); + s = skip(s); + if(*s==0 || min>=65536 || max>=65536 || min>max) + { + Err3: + ffree(fnt); + return 0; + } + if (fnt->subf) + fnt->subf = (Cachesubf *)realloc(fnt->subf, (fnt->nsubf+1)*sizeof(Cachesubf)); + else + fnt->subf = (Cachesubf *)malloc(sizeof(Cachesubf)); + if (fnt->subf == 0) + { + /* realloc manual says fnt->subf may have been destroyed */ + fnt->nsubf = 0; + goto Err3; + } + c = &fnt->subf[fnt->nsubf]; + c->min = min; + c->max = max; + t = s; + while (*s && *s!=' ' && *s!='\n' && *s!='\t') + s++; + *s++ = 0; + c->f = (Subfont *)0; + c->name = (char *)malloc(strlen(t)+1); + if (c->name == 0) + { + free(c); + goto Err3; + } + strcpy(c->name, t); + s = skip(s); + fnt->nsubf++; + } while(*s); + free(buf); + return fnt; +} + +void +ffree(Font *f) +{ + int i; + Cachesubf *c; + unsigned char *b; + + for (i=0; i<f->nsubf; i++){ + c = f->subf+i; + if (c->f) + subffree(c->f); + free(c->name); + free(c); + } + free(f->subf); + free(f); +} diff --git a/libXg/rectclip.c b/libXg/rectclip.c new file mode 100644 index 0000000..9e03614 --- /dev/null +++ b/libXg/rectclip.c @@ -0,0 +1,24 @@ +/* Copyright (c) 1992 AT&T - All rights reserved. */ +#include <libc.h> +#include <libg.h> + +rectclip(Rectangle *rp, Rectangle b) /* first by reference, second by value */ +{ + Rectangle *bp = &b; + /* + * Expand rectXrect() in line for speed + */ + if((rp->min.x<bp->max.x && bp->min.x<rp->max.x && + rp->min.y<bp->max.y && bp->min.y<rp->max.y)==0) + return 0; + /* They must overlap */ + if(rp->min.x < bp->min.x) + rp->min.x = bp->min.x; + if(rp->min.y < bp->min.y) + rp->min.y = bp->min.y; + if(rp->max.x > bp->max.x) + rp->max.x = bp->max.x; + if(rp->max.y > bp->max.y) + rp->max.y = bp->max.y; + return 1; +} diff --git a/libXg/rune.c b/libXg/rune.c new file mode 100644 index 0000000..0b90560 --- /dev/null +++ b/libXg/rune.c @@ -0,0 +1,194 @@ +/* Copyright (c) 1992 AT&T - All rights reserved. */ +#include <u.h> +#include <string.h> +#include <libc.h> + +enum +{ + Bit1 = 7, + Bitx = 6, + Bit2 = 5, + Bit3 = 4, + Bit4 = 3, + + T1 = ((1<<(Bit1+1))-1) ^ 0xFF, /* 0000 0000 */ + Tx = ((1<<(Bitx+1))-1) ^ 0xFF, /* 1000 0000 */ + T2 = ((1<<(Bit2+1))-1) ^ 0xFF, /* 1100 0000 */ + T3 = ((1<<(Bit3+1))-1) ^ 0xFF, /* 1110 0000 */ + T4 = ((1<<(Bit4+1))-1) ^ 0xFF, /* 1111 0000 */ + + Rune1 = (1<<(Bit1+0*Bitx))-1, /* 0000 0000 0111 1111 */ + Rune2 = (1<<(Bit2+1*Bitx))-1, /* 0000 0111 1111 1111 */ + Rune3 = (1<<(Bit3+2*Bitx))-1, /* 1111 1111 1111 1111 */ + + Maskx = (1<<Bitx)-1, /* 0011 1111 */ + Testx = Maskx ^ 0xFF, /* 1100 0000 */ + + Bad = Runeerror +}; + +int +chartorune(Rune *rune, char *str) +{ + int c, c1, c2; + long l; + + /* + * one character sequence + * 00000-0007F => T1 + */ + c = *(uchar*)str; + if(c < Tx) { + *rune = c; + return 1; + } + + /* + * two character sequence + * 0080-07FF => T2 Tx + */ + c1 = *(uchar*)(str+1) ^ Tx; + if(c1 & Testx) + goto bad; + if(c < T3) { + if(c < T2) + goto bad; + l = ((c << Bitx) | c1) & Rune2; + if(l <= Rune1) + goto bad; + *rune = l; + return 2; + } + + /* + * three character sequence + * 0800-FFFF => T3 Tx Tx + */ + c2 = *(uchar*)(str+2) ^ Tx; + if(c2 & Testx) + goto bad; + if(c < T4) { + l = ((((c << Bitx) | c1) << Bitx) | c2) & Rune3; + if(l <= Rune2) + goto bad; + *rune = l; + return 3; + } + + /* + * bad decoding + */ +bad: + *rune = Bad; + return 1; +} + +int +runetochar(char *str, Rune *rune) +{ + long c; + + /* + * one character sequence + * 00000-0007F => 00-7F + */ + c = *rune; + if(c <= Rune1) { + str[0] = c; + return 1; + } + + /* + * two character sequence + * 0080-07FF => T2 Tx + */ + if(c <= Rune2) { + str[0] = T2 | (c >> 1*Bitx); + str[1] = Tx | (c & Maskx); + return 2; + } + + /* + * three character sequence + * 0800-FFFF => T3 Tx Tx + */ + str[0] = T3 | (c >> 2*Bitx); + str[1] = Tx | ((c >> 1*Bitx) & Maskx); + str[2] = Tx | (c & Maskx); + return 3; +} + +int +runelen(long c) +{ + Rune rune; + char str[10]; + + rune = c; + return runetochar(str, &rune); +} + +int +fullrune(char *str, int n) +{ + int c; + + if(n > 0) { + c = *(uchar*)str; + if(c < Tx) + return 1; + if(n > 1) + if(c < T3 || n > 2) + return 1; + } + return 0; +} + +char* +utfrune(char *s, long c) +{ + long c1; + Rune r; + int n; + + if(c < Runesync) /* not part of utf sequence */ + return strchr(s, c); + + for(;;) { + c1 = *(uchar*)s; + if(c1 < Runeself) { /* one byte rune */ + if(c1 == 0) + return 0; + if(c1 == c) + return s; + s++; + continue; + } + n = chartorune(&r, s); + if(r == c) + return s; + s += n; + } + return 0; +} + +long +utflen(char *s) +{ + int c; + long n; + Rune rune; + + n = 0; + for(;;) { + c = *(uchar*)s; + if(c < Runeself) { + if(c == 0) + return n; + s++; + } else + s += chartorune(&rune, s); + n++; + } + return 0; +} diff --git a/libXg/segment.c b/libXg/segment.c new file mode 100644 index 0000000..1c90a49 --- /dev/null +++ b/libXg/segment.c @@ -0,0 +1,24 @@ +/* Copyright (c) 1992 AT&T - All rights reserved. */ +#include <libc.h> +#include <libg.h> +#include "libgint.h" + +void +segment(Bitmap *d, Point p1, Point p2, int v, Fcode f) +{ + int x1, y1, x2, y2; + GC g; + + x1 = p1.x; + y1 = p1.y; + x2 = p2.x; + y2 = p2.y; + if(d->flag&SHIFT){ + x1 -= d->r.min.x; + y1 -= d->r.min.y; + x2 -= d->r.min.x; + y2 -= d->r.min.y; + } + g = _getfillgc(f, d, v); + XDrawLine(_dpy, (Drawable)d->id, g, x1, y1, x2, y2); +} diff --git a/libXg/string.c b/libXg/string.c new file mode 100644 index 0000000..13bc810 --- /dev/null +++ b/libXg/string.c @@ -0,0 +1,54 @@ +/* Copyright (c) 1992 AT&T - All rights reserved. */ +#include <libc.h> +#include <libg.h> +#include "libgint.h" + +enum { Max = 128 }; + +Point +string(Bitmap *b, Point p, Font *ft, char *s, Fcode f) +{ + int x, y, wid, i, j, n, nti, cf; + XChar2b cbuf[Max]; + unsigned short fbuf[Max]; + XTextItem16 ti[Max]; + Rune r; + GC g; + + x = p.x; + y = p.y; + if (b->flag&SHIFT){ + x -= b->r.min.x; + y -= b->r.min.y; + } + y += ft->ascent; + g = _getfillgc(f, b, ~0); + + while (*s) { + n = cachechars(ft, &s, cbuf, Max, &wid, fbuf); + if (n <= 0) { + s += chartorune(&r, s); + continue; + } + nti = 0; + cf = fbuf[0]; /* first font */ + ti[0].chars = cbuf; + ti[0].delta = 0; + ti[0].font = (xFont)ft->subf[cf].f->id; + for (i = 1, j = 1; i < n; i++, j++) { + if (fbuf[i] != cf) { /* font change */ + cf = fbuf[i]; + ti[nti++].nchars = j; + ti[nti].chars = &cbuf[i]; + ti[nti].delta = 0; + ti[nti].font = (xFont)ft->subf[cf].f->id; + j = 0; + } + } + ti[nti++].nchars = j; + XDrawText16(_dpy, (Drawable)b->id, g, x, y, ti, nti); + x += wid; + } + p.x = (b->flag&SHIFT) ? x + b->r.min.x : x; + return p; +} diff --git a/libXg/strwidth.c b/libXg/strwidth.c new file mode 100644 index 0000000..854b31d --- /dev/null +++ b/libXg/strwidth.c @@ -0,0 +1,30 @@ +/* Copyright (c) 1992 AT&T - All rights reserved. */ +#include <libc.h> +#include <libg.h> +#include "libgint.h" + +long +strwidth(Font *f, char *s) +{ + int wid, twid; + enum { Max = 128 }; + Rune cbuf[Max]; + unsigned short fbuf[Max]; + Rune r; + + twid = 0; + while (*s) + { + if (cachechars(f, &s, cbuf, Max, &wid, fbuf) <= 0) + s += chartorune(&r, s); + else + twid += wid; + } + return twid; +} + +Point +strsize(Font *f, char *s) +{ + return Pt(strwidth(f, s), f->height); +} diff --git a/libXg/test.c b/libXg/test.c new file mode 100644 index 0000000..bcf4cca --- /dev/null +++ b/libXg/test.c @@ -0,0 +1,237 @@ +/* Copyright (c) 1992 AT&T - All rights reserved. */ +#include <libc.h> +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif +#include <libg.h> +#include <stdio.h> + +void cont(char *); +void putstring(char *); +void colorinit(void); +void printcolmap(void); +void invertcolmap(void); + +unsigned char arrowset[] = + {0x00, 0x00, 0x7F, 0xC0, 0x7F, 0x00, 0x7C, 0x00, + 0x7E, 0x00, 0x7F, 0x00, 0x6F, 0x80, 0x67, 0xC0, + 0x43, 0xE0, 0x41, 0xF0, 0x00, 0xF8, 0x00, 0x7C, + 0x00, 0x3E, 0x00, 0x1C, 0x00, 0x08, 0x00, 0x00}; + +char *colors[] = { "Black", "Red", "Green", "Yellow", + "Cyan", "Magenta", "Blue", "White" }; +RGB colordefs[] = { + { 0,0,0 }, /* black */ + {0xFFFFFFFF, 0x00000000, 0x00000000}, /* red */ + {0x00000000, 0xFFFFFFFF, 0x00000000}, /* green */ + {0xFFFFFFFF, 0xFFFFFFFF, 0x00000000}, /* yellow */ + {0x00000000, 0xFFFFFFFF, 0xFFFFFFFF}, /* cyan */ + {0xFFFFFFFF, 0x00000000, 0xFFFFFFFF}, /* magenta */ + {0x00000000, 0x00000000, 0xFFFFFFFF}, /* blue */ + {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}, /* white */ +}; +#define Ncol (sizeof(colordefs)/sizeof(colordefs[0])) +unsigned long rgbval[Ncol]; +Bitmap *rgbbitmap[Ncol]; + +main(int argc, char **argv) +{ + Point p1,p2,p3; + Mouse m; + int r,rx,ry; + int n, i; + char *m3gen(int); + static Menu menu3 = { (char **) 0, m3gen, 0 }; + char *p, buf[200]; + Bitmap *bm, *bm2; + RGB cmap[256]; + + xtbinit(0,0,&argc,argv,0); + einit(Ekeyboard|Emouse); + p1 = add(screen.r.min, Pt(15,15)); + p2 = sub(screen.r.max, Pt(15,15)); + p3 = divpt(add(p1,p2),2); + fprintf(stderr, "segment(&screen, (%d,%d), (%d,%d), ~0, S)\n", + p1.x,p1.y,p2.x,p2.y); + segment(&screen, p1, p2, ~0, S); + cont("point"); + fprintf(stderr, "point(&screen, (%d,%d), ~0, S)\n", p1.x,p1.y); + point(&screen, p1, ~0, S); + cont("circle"); + rx = p3.x - p1.x; + ry = p3.y - p1.y; + r = (rx < ry)? rx : ry; + fprintf(stderr, "circle(&screen, (%d,%d), %d, ~0, S)\n", + p3.x,p3.y,r); + circle(&screen, p3, r, ~0, S); + cont("disc"); + fprintf(stderr, "disc(&screen, (%d,%d), %d, ~0, S)\n", + p3.x,p3.y,r); + disc(&screen, p3, r, ~0, S); + cont("clipped disc"); + fprintf(stderr, "clipr(&screen, ((%d,%d)(%d,%d))\n", + p1.x+30, p1.y+5, p3.x-30, p3.y-5); + clipr(&screen, Rect(p1.x+30, p1.y+5, p3.x-30, p3.y-5)); + fprintf(stderr, "disc(&screen, (%d,%d), %d, ~0, S)\n", + p3.x,p3.y,r); + disc(&screen, p3, r, ~0, S); + clipr(&screen, screen.r); + cont("ellipse"); + fprintf(stderr, "ellipse(&screen, (%d,%d), %d, %d, ~0, S)\n", + p3.x,p3.y,r,r/2); + ellipse(&screen, p3, r, r/2, ~0, S); + cont("arc"); + fprintf(stderr, "arc(&screen, (%d,%d), (%d,%d), (%d,%d), ~0, S)\n", + p3.x,p3.y, p3.x+r,p3.y, p3.x+r/2,p3.x-(int)(r*.866)); + arc(&screen, p3, Pt(p3.x+r,p3.y), Pt(p3.x+r/2,p3.x-(int)(r*.866)), ~0, S); + if(screen.ldepth > 1){ + cont("color"); + colorinit(); + p3 = p1; + rx *= 2; + ry *= 2; + for(i = 0; i<Ncol; i++) { + texture(&screen, Rpt(p3,add(p3,Pt(rx,ry/Ncol))), + rgbbitmap[i], S); + string(&screen, add(p3,Pt(15,15)), font, colors[i], DxorS); + p3.y += ry/Ncol; + } + printcolmap(); + cont("invert colmap"); + invertcolmap(); + printcolmap(); + p3 = p1; + for(i = 0; i<Ncol; i++) { + texture(&screen, Rpt(p3,add(p3,Pt(rx,ry/Ncol))), + rgbbitmap[i], S); + string(&screen, add(p3,Pt(15,15)), font, colors[i], DxorS); + p3.y += ry/Ncol; + } + cont("restore colmap"); + invertcolmap(); + } + cont("wrbitmap, border, and bitblt(S)"); + bm = balloc(Rect(0,0,16,16), 0); + fprintf(stderr, "border (%d,%d,%d,%d), -2, F)\n", + p1.x, p1.y, p1.x+16, p1.y+16); + border(&screen, Rpt(p1, add(p1,Pt(16,16))), -2, F); + wrbitmap(bm, 0, 16, arrowset); + fprintf(stderr, "bitblt(&screen, (%d,%d), bm, (0,0,16,16), S)\n", + p1.x,p1.y); + bitblt(&screen, p1, bm, Rect(0,0,16,16), S); + cont("mouse track (button 1)"); + do{ + m = emouse(); + } while(!(m.buttons&1)); + fprintf(stderr,"test tracking\n"); + while(m.buttons&1){ + point(&screen, m.xy, ~0, S); + m = emouse(); + } + cursorswitch(0); + cont("menuhit (button 3)"); + do { + do{ + m = emouse(); + } while(!(m.buttons&4)); + n = menuhit(3, &m, &menu3); + fprintf(stderr, "button %d\n", n); + } while (n != 0); + cont("keyboard (end with \\n)"); + fprintf(stderr, "type something\n"); + for (p = buf; (*p = ekbd()) != '\n' && *p != '\r'; p++) { + fprintf(stderr, "%c", *p); + if (*p == '\b') + p -= 2; + if (p < buf-1) + p = buf-1; + p[1] = 0; + putstring(buf); + } + cont("done"); + exit(0); +} + +void colorinit(void) /* set up color definitions */ +{ + int i; + + for (i = 0; i < Ncol; i++) { + rgbval[i] = rgbpix(&screen, colordefs[i]); + rgbbitmap[i] = balloc(Rect(0,0,1,1), screen.ldepth); + point(rgbbitmap[i], Pt(0,0), rgbval[i], S); + } +} + +void printcolmap(void) +{ + int i, n; + RGB cmap[256]; + + rdcolmap(&screen, cmap); + n = 1 << (1 << screen.ldepth); + fprintf(stderr, "colormap, %d entries\n", n); + for(i = 0; i < n; i++) + fprintf(stderr, "%d:\t%.8x\t%.8x\t%.8x\n", + i, cmap[i].red, cmap[i].green, cmap[i].blue); +} + +void invertcolmap(void) +{ + int i, n; + RGB cmap[256]; + + rdcolmap(&screen, cmap); + n = 1 << (1 << screen.ldepth); + for(i = 0; i < n; i++) { + cmap[i].red = ~cmap[i].red; + cmap[i].green = ~cmap[i].green; + cmap[i].blue = ~cmap[i].blue; + } + wrcolmap(&screen, cmap); +} + +void +putstring(char *buf) +{ + Point p; + static int jmax = 0, l; + + p = add(screen.r.min, Pt(20,20)); + bitblt(&screen, p, &screen, Rect(p.x, p.y, p.x+jmax, p.y+font->height), Zero); + string(&screen, p, font, buf, F); + if ((l = strwidth(font, buf)) > jmax) + jmax = l; +} + +void +cont(char *msg) +{ + Event ev; + Point mp; + + while(event(&ev) != Ekeyboard) + continue; + bitblt(&screen, Pt(0,0), &screen, screen.r, Zero); + mp = add(screen.r.min, Pt(20,20)); + string(&screen, mp, font, msg, S); + while(event(&ev) != Ekeyboard) + continue; + bitblt(&screen, Pt(0,0), &screen, screen.r, Zero); +} + +char * +m3gen(int n) +{ + static char *m3[] ={ "quit", "thing1", "thing2" }; + + if (n < 0 || n > 2) + return 0; + else + return m3[n]; +} + +void +ereshaped(Rectangle r) +{ +} diff --git a/libXg/texture.c b/libXg/texture.c new file mode 100644 index 0000000..24e427e --- /dev/null +++ b/libXg/texture.c @@ -0,0 +1,41 @@ +/* Copyright (c) 1992 AT&T - All rights reserved. */ +#include <libc.h> +#include <libg.h> +#include "libgint.h" + +void +texture(Bitmap *d, Rectangle r, Bitmap *s, Fcode f) +{ + int x, y, w, h, bfunc; + GC g; + + x = r.min.x; + y = r.min.y; + if(d->flag&SHIFT){ + x -= d->r.min.x; + y -= d->r.min.y; + } + g = _getcopygc(f, d, s, &bfunc); + if(d->flag&SHIFT){ + XSetTSOrigin(_dpy, g, -d->r.min.x, -d->r.min.y); + }else + XSetTSOrigin(_dpy, g, 0, 0); + w = Dx(r); + h = Dy(r); + if(bfunc == UseFillRectangle){ + /* source isn't involved at all */ + XFillRectangle(_dpy, (Drawable)d->id, g, x, y, w, h); + }else if(bfunc == UseCopyArea){ + XSetTile(_dpy, g, (Drawable)s->id); + XSetFillStyle(_dpy, g, FillTiled); + XFillRectangle(_dpy, (Drawable)d->id, g, x, y, w, h); + XSetFillStyle(_dpy, g, FillSolid); + }else{ + if(s->ldepth != 0) + berror("unsupported texture"); + XSetStipple(_dpy, g, (Drawable)s->id); + XSetFillStyle(_dpy, g, FillOpaqueStippled); + XFillRectangle(_dpy, (Drawable)d->id, g, x, y, w, h); + XSetFillStyle(_dpy, g, FillSolid); + } +} diff --git a/libXg/wrbitmap.c b/libXg/wrbitmap.c new file mode 100644 index 0000000..e1f43cd --- /dev/null +++ b/libXg/wrbitmap.c @@ -0,0 +1,54 @@ +/* Copyright (c) 1992 AT&T - All rights reserved. */ +#include <libc.h> +#include <libg.h> +#include "libgint.h" +#include <X11/Intrinsic.h> +#ifndef XtSpecificationRelease +#define R3 +#endif + +#include <stdio.h> +void +wrbitmap(Bitmap *b, int miny, int maxy, unsigned char *data) +{ + XImage *im; + int w, h, inld, outld, l, offset, px; + GC g; + char *tdata; + + w = Dx(b->r); + h = maxy - miny; + inld = b->ldepth; + outld = (b->ldepth == 0) ? 0 : screen.ldepth; + px = 1<<(3-outld); /* pixels per byte */ + /* set l to number of bytes of data per scan line */ + if(b->r.min.x >= 0) + offset = b->r.min.x % px; + else + offset = px - b->r.min.x % px; + l = (-b->r.min.x+px-1)/px; + if(b->r.max.x >= 0) + l += (b->r.max.x+px-1)/px; + else + l -= b->r.max.x/px; + l *= h; + + tdata = (char *)malloc(l); + if (tdata == (char *) 0) + berror("wrbitmap malloc"); + if (inld == outld) + memcpy((void*)tdata, (void*)data, l); + else + _ldconvert((char*)data, inld, tdata, outld, w, h); + + im = XCreateImage(_dpy, 0, 1 << outld, ZPixmap, 0, tdata, w, h, 8, 0); + + /* Botched interface to XCreateImage doesn't let you set these: */ + im->bitmap_bit_order = MSBFirst; + im->byte_order = MSBFirst; + + g = _getfillgc(S, b, ~0); + XSetBackground(_dpy, g, b->flag&DP1 ? 0 : _bgpixel); + XPutImage(_dpy, (Drawable)b->id, g, im, offset, 0, 0, miny - b->r.min.y, w-offset, h); + XDestroyImage(im); +} diff --git a/libXg/wrbitmapfile.c b/libXg/wrbitmapfile.c new file mode 100644 index 0000000..eb1237a --- /dev/null +++ b/libXg/wrbitmapfile.c @@ -0,0 +1,49 @@ +/* Copyright (c) 1992 AT&T - All rights reserved. */ +#include <libc.h> +#include <libg.h> +#include "libgint.h" + +#define CHUNK 4096 + +void +wrbitmapfile(int fd, Bitmap *b) +{ + char hdr[5*12+1]; + unsigned char *data; + long dy, px; + unsigned long l, t, n; + long miny, maxy; + + sprint(hdr, "%11d %11d %11d %11d %11d ", + b->ldepth, b->r.min.x, b->r.min.y, b->r.max.x, b->r.max.y); + if(write(fd, hdr, 5*12) != 5*12) + berror("wrbitmapfile write"); + + px = 1<<(3-b->ldepth); /* pixels per byte */ + /* set l to number of bytes of data per scan line */ + if(b->r.min.x >= 0) + l = (b->r.max.x+px-1)/px - b->r.min.x/px; + else{ /* make positive before divide */ + t = (-b->r.min.x)+px-1; + t = (t/px)*px; + l = (t+b->r.max.x+px-1)/px; + } + miny = b->r.min.y; + maxy = b->r.max.y; + data = (unsigned char *)malloc(CHUNK); + if(data == 0) + berror("wrbitmapfile malloc"); + while(maxy > miny){ + dy = maxy - miny; + if(dy*l > CHUNK) + dy = CHUNK/l; + rdbitmap(b, miny, miny+dy, data); + n = dy*l; + if(write(fd, data, n) != n){ + free(data); + berror("wrbitmapfile write"); + } + miny += dy; + } + free(data); +} diff --git a/libXg/xtbinit.c b/libXg/xtbinit.c new file mode 100644 index 0000000..b707f14 --- /dev/null +++ b/libXg/xtbinit.c @@ -0,0 +1,955 @@ +/* Copyright (c) 1992 AT&T - All rights reserved. */ +#include <libc.h> +#include <libg.h> +#include <stdio.h> +#include "libgint.h" + +#define COMPRESSMOUSE + +#define Cursor xCursor +#define Font xFont +#define Event xEvent + +#include <X11/Intrinsic.h> +#include <X11/StringDefs.h> +#include <X11/Shell.h> +#include "Gwin.h" + +#ifndef XtSpecificationRelease +#define R3 +#define XtAppInitialize(a,b,c,d,e,f,g,h,i) XtInitialize(0,b,c,d,e,f) +#define XtConvertAndStore(a,b,c,d,e) (XtConvert(a,b,c,d,e),1) +#define XtAppPending(a) XtPending() +#define XtAppProcessEvent(a,b) XtProcessEvent(b) +#define XtAppAddTimeOut(a,b,c,d) XtAddTimeOut(b,c,d) +#define XtAppAddInput(a,b,c,d,e) XtAddInput(b,c,d,e) +#define XtPointer caddr_t +#endif + +#undef Cursor +#undef Font +#undef Event + +/* libg globals */ +Bitmap screen; +Font *font, *fixed; + +/* implementation globals */ +Display *_dpy; +Widget _toplevel; +unsigned long _fgpixel, _bgpixel; +XColor _fgcolor, _bgcolor; +int _ld2d[6] = { 1, 2, 4, 8, 16, 24 }; +unsigned long _ld2dmask[6] = { 0x1, 0x3, 0xF, 0xFF, 0xFFFF, 0x00FFFFFF }; +Colormap _libg_cmap; +int _cmap_installed; + +/* xbinit implementation globals */ +#ifndef R3 +static XtAppContext app; +#endif +static Widget widg; +static int exposed = 0; +static Atom wm_take_focus; +static Mouse lastmouse; + +typedef struct Ebuf { + struct Ebuf *next; + int n; + unsigned char buf[2]; +} Ebuf; + +typedef struct Esrc { + int inuse; + int size; + int count; + Ebuf *head; + Ebuf *tail; + XtInputId id; +} Esrc; + +#define MAXINPUT 1024 /* number of queued input events */ +#define MAXSRC 10 + +static Esrc esrc[MAXSRC]; +static int nsrc; + + +static int einitcalled = 0; +static int Smouse = -1; +static int Skeyboard = -1; +static int Stimer = -1; +static XtIntervalId timerid; + +static Font * initfont(char *, XFontStruct *, char *); +static void reshaped(int, int, int, int); +static void gotchar(int); +static void gotmouse(Gwinmouse *); +static int log2(int); +static void pixtocolor(Pixel, XColor *); +static Subfont *XFontStructtoSubfont(XFontStruct *); +static Ebuf *ebread(Esrc *); +static Ebuf *ebadd(Esrc *); +static void focinit(Widget); +static void wmproto(Widget, XEvent *, String *, Cardinal *); +static void waitevent(void); + +static Errfunc onerr; + +String _fallbacks[] = { + "*gwin.width: 800", + "*gwin.height: 600", + NULL +}; + +#ifndef R3 +static char *shelltrans = + "<ClientMessage> WM_PROTOCOLS : WMProtocolAction()"; +static XtActionsRec wmpactions[] = { + {"WMProtocolAction", wmproto} +}; +#endif + + /* too many X options */ +static XrmOptionDescRec optable[] = { + {"-p9fn", "*p9font", XrmoptionSepArg, (caddr_t)NULL}, + {"-p9font", "*p9font", XrmoptionSepArg, (caddr_t)NULL}, + {"-p9fixed", "*p9fixed", XrmoptionSepArg, (caddr_t)NULL}, +}; + +static int +ioerr(Display *d) +{ + if(onerr) + (*onerr)("ioerr"); + else + exit(1); + return 0; +} + +void +xtbinit(Errfunc f, char *class, int *pargc, char **argv, char **fallbacks) +{ + int n; + unsigned int depth; + XFontStruct *xf; + String fontname; + String fixedname; + Arg args[10]; + char *p; + XSetWindowAttributes attr; + int compose; + + if(!class && argv[0]){ + p = strrchr(argv[0], '/'); + if(p) + class = XtNewString(p+1); + else + class = XtNewString(argv[0]); + if(class[0] >= 'a' && class[0] <= 'z') + class[0] += 'A' - 'a'; + } + onerr = f; + if (!fallbacks) + fallbacks = _fallbacks; + n = 0; + XtSetArg(args[n], XtNinput, TRUE); n++; + _toplevel = XtAppInitialize(&app, class, + optable, sizeof(optable)/sizeof(optable[0]), + pargc, argv, fallbacks, args, n); + + n = 0; + XtSetArg(args[n], XtNreshaped, reshaped); n++; + XtSetArg(args[n], XtNgotchar, gotchar); n++; + XtSetArg(args[n], XtNgotmouse, gotmouse); n++; + widg = XtCreateManagedWidget("gwin", gwinWidgetClass, _toplevel, args, n); + + n = 0; + XtSetArg(args[n], XtNforeground, &_fgpixel); n++; + XtSetArg(args[n], XtNbackground, &_bgpixel); n++; + XtSetArg(args[n], XtNdepth, &depth); n++; + XtSetArg(args[n], XtNfont, &xf); n++; + XtSetArg(args[n], XtNp9font, &fontname); n++; + XtSetArg(args[n], XtNp9fixed, &fixedname); n++; + XtSetArg(args[n], XtNcomposeMod, &compose); n++; + XtGetValues(widg, args, n); + XSetIOErrorHandler(ioerr); + XSetErrorHandler(ioerr); + + if (compose < 0 || compose > 5) { + n = 0; + XtSetArg(args[n], XtNcomposeMod, 0); n++; + XtSetValues(widg, args, n); + } + + _dpy = XtDisplay(widg); + screen.id = 0; + XtRealizeWidget(_toplevel); + pixtocolor(_fgpixel, &_fgcolor); + pixtocolor(_bgpixel, &_bgcolor); + screen.id = (int) XtWindow(widg); + screen.ldepth = log2(depth); + screen.flag = SCR; + if(_fgpixel != 0) + screen.flag |= BL1; + if(depth == 1) + screen.flag |= DP1; + font = initfont(fontname, xf, "variable"); + fixed = initfont(fixedname, 0, "fixed"); + /* leave screen rect at all zeros until reshaped() sets it */ + while(!exposed) { + XFlush(_dpy); + XtAppProcessEvent(app, XtIMXEvent); + } + XFlush(_dpy); + focinit(_toplevel); +} + +static Font * +initfont(char *name, XFontStruct *xf, char *backupname) +{ + /* Given (in order of preference) + * 'name' which may be the name of a font file, + * 'backupfont' which may be an XFontStruct, + * and 'backupname', which is the name of an X font. + */ + Font *f; + + if (name) { + f = rdfontfile(name, screen.ldepth); + if (f && charwidth(f, (Rune) ' ') != 0) + return f; + } + if (xf) + return mkfont(XFontStructtoSubfont(xf)); + return mkfont(getsubfont(backupname)); /* just has to work */ +} + +static void +focinit(Widget w) +{ +#ifndef R3 + XrmValue src, dst; + + src.addr = "WM_TAKE_FOCUS"; + src.size = strlen((char *)src.addr)+1; + dst.addr = (XtPointer) &wm_take_focus; + dst.size = sizeof(Atom); + XtConvertAndStore(w, XtRString, &src, XtRAtom, &dst); + XSetWMProtocols(XtDisplay(w), XtWindow(w), &wm_take_focus, 1); + XtAppAddActions(app, wmpactions, XtNumber(wmpactions)); + XtAugmentTranslations(w, XtParseTranslationTable(shelltrans)); +#endif +} + +#ifndef R3 +static void +wmproto(Widget w, XEvent *e , String *p, Cardinal *np) +{ + Time t; + + if(e->type == ClientMessage && + (Atom)(e->xclient.data.l[0]) == wm_take_focus) { + t = (Time) e->xclient.data.l[1]; + XtCallAcceptFocus(widg, &t); + } +} +#endif + +static void +reshaped(int minx, int miny, int maxx, int maxy) +{ + Ebuf *eb; + Mouse m; + + screen.r = Rect(minx, miny, maxx, maxy); + screen.clipr = screen.r; + if (screen.id) { + exposed = 1; + ereshaped(screen.r); + } + if(einitcalled){ + /* + * Cause a mouse event, so programs like sam + * will get out of eread and REALLY do the reshape + */ + eb = ebadd(&esrc[Smouse]); + if (eb == 0) + berror("eballoc can't malloc"); + memcpy((void*)eb->buf, (void*)&lastmouse, sizeof lastmouse); + esrc[Smouse].count++; + } +} + +static void +gotchar(int c) +{ + Ebuf *eb; + + if(!einitcalled || Skeyboard == -1) + return; + eb = ebadd(&esrc[Skeyboard]); + if (eb == 0) + berror("eballoc can't malloc"); + BPSHORT(eb->buf, (unsigned short)(c & 0xffff)); + esrc[Skeyboard].count++; +} + +static void +gotmouse(Gwinmouse *gm) +{ + Ebuf *eb; + Mouse m; + + if(!einitcalled || Smouse == -1) + return; + m.buttons = gm->buttons; + m.xy.x = gm->xy.x; + m.xy.y = gm->xy.y; + m.msec = gm->msec; + lastmouse = m; + eb = ebadd(&esrc[Smouse]); + if (eb == 0) + berror("eballoc can't malloc"); + memcpy((void*)eb->buf, (void*)&m, sizeof m); + esrc[Smouse].count++; +} + +static void +gotinput(XtPointer cldata, int *pfd, XtInputId *id) +{ + Ebuf *eb, *lasttail, *newe; + Esrc *es; + int n; + + if(!einitcalled) + return; + es = (Esrc *)cldata; + if (es->count >= MAXINPUT) + return; + lasttail = es->tail; + eb = ebadd(es); + if (eb == 0) + return; + if(es->size){ + n = read(*pfd, (char *)eb->buf, es->size); + if (n < 0) + n = 0; + if(n < es->size) { + newe = realloc(eb, sizeof(Ebuf)+n); + newe->n = n; + if (es->head == eb) + es->head = newe; + else + lasttail->next = newe; + es->tail = newe; + } + } + es->count++; +} + +static void +gottimeout(XtPointer cldata, XtIntervalId *id) +{ + if(!einitcalled || Stimer == -1) + return; + /* + * Don't queue up timeouts, because there's + * too big a danger that they might pile up + * too quickly. + */ + esrc[Stimer].head = (Ebuf *)1; + esrc[Stimer].count = 1; + XtAppAddTimeOut(app, (long)cldata, gottimeout, cldata); +} + +static int +log2(int n) +{ + int i, v; + + for(i=0, v=1; i < 32; i++, v<<=1) + if(n <= v) + break; + return i; +} + +static void +pixtocolor(Pixel p, XColor *pc) +{ +#ifdef R3 + Colormap cmap; + Arg args[2]; + int n; + + n = 0; + XtSetArg(args[n], XtNcolormap, &cmap); n++; + XtGetValues(_toplevel, args, n); + pc->pixel = p; + XQueryColor(_dpy, cmap, pc); +#else + XrmValue xvf, xvt; + + xvf.size = sizeof(Pixel); + xvf.addr = (XtPointer)&p; + xvt.size = sizeof(XColor); + xvt.addr = (XtPointer)pc; + if(!XtConvertAndStore(_toplevel, XtRPixel, &xvf, XtRColor, &xvt)) + pc->pixel = p; /* maybe that's enough */ +#endif +} + +unsigned long +rgbpix(Bitmap *b, RGB col) +{ + XColor c; + Colormap cmap; + Arg args[2]; + int n, depth, dr, dg, db; + RGB map[256], *m; + unsigned long d, max, pixel; + + if (!_cmap_installed) { + n = 0; + XtSetArg(args[n], XtNcolormap, &cmap); n++; + XtGetValues(_toplevel, args, n); + c.red = col.red>>16; + c.green = col.green>>16; + c.blue = col.blue>>16; + c.flags = DoRed|DoGreen|DoBlue; + if(XAllocColor(_dpy, cmap, &c)) + return (unsigned long)(c.pixel); + } + depth = _ld2d[screen.ldepth]; + rdcolmap(&screen, map); + max = -1; + for (n = 0, m = map; n < (1 << depth); n++, m++) + { + dr = m->red - col.red; + dg = m->green - col.green; + db = m->blue - col.blue; + d = dr*dr+dg*dg+db*db; + if (d < max || max == -1) + { + max = d; + pixel = n; + } + } + return pixel; +} + +void +rdcolmap(Bitmap *b, RGB *map) +{ + XColor cols[256]; + int i, n, depth; + Colormap cmap; + Arg args[2]; + + if (_cmap_installed) { + cmap = _libg_cmap; + } else { + i = 0; + XtSetArg(args[i], XtNcolormap, &cmap); i++; + XtGetValues(_toplevel, args, i); + } + + depth = _ld2d[screen.ldepth]; + n = 1 << depth; + if (depth == 1) { + map[0].red = map[0].green = map[0].blue = ~0; + map[1].red = map[1].green = map[1].blue = 0; + } + else { + if (n > 256) { + berror("rdcolmap bitmap too deep"); + return; + } + for (i = 0; i < n; i++) + cols[i].pixel = i; + XQueryColors(_dpy, cmap, cols, n); + for (i = 0; i < n; i++) { + map[i].red = (cols[i].red << 16) | cols[i].red; + map[i].green = (cols[i].green << 16) | cols[i].green; + map[i].blue = (cols[i].blue << 16) | cols[i].blue; + } + } +} + +void +wrcolmap(Bitmap *b, RGB *map) +{ + int i, n, depth; + Screen *scr; + XColor cols[256]; + Arg args[2]; + XVisualInfo vi; + Window w; + + scr = XtScreen(_toplevel); + depth = _ld2d[screen.ldepth]; + n = 1 << depth; + if (n > 256) { + berror("wrcolmap bitmap too deep"); + return; + } else if (depth > 1) { + for (i = 0; i < n; i++) { + cols[i].red = map[i].red >> 16; + cols[i].green = map[i].green >> 16; + cols[i].blue = map[i].blue >> 16; + cols[i].pixel = i; + cols[i].flags = DoRed|DoGreen|DoBlue; + } + if (!XMatchVisualInfo(_dpy, XScreenNumberOfScreen(scr), + depth, PseudoColor, &vi)) { + berror("wrcolmap can't get visual"); + return; + } + w = XtWindow(_toplevel); + _libg_cmap = XCreateColormap(_dpy, w, vi.visual, AllocAll); + XStoreColors(_dpy, _libg_cmap, cols, n); + + i = 0; + XtSetArg(args[i], XtNcolormap, _libg_cmap); i++; + XtSetValues(_toplevel, args, i); + _cmap_installed = 1; + } +} + +Subfont * +getsubfont(char *s) +{ + XFontStruct *fp; + + if(!s) + return 0; + fp = XLoadQueryFont(_dpy, s); + if(!fp) + return 0; + return XFontStructtoSubfont(fp); +} + +static Subfont * +XFontStructtoSubfont(XFontStruct *fp) +{ + XCharStruct *cp; + Subfont *f; + int min, max; + int i; + + if(!fp) + berror("no font"); + f = (Subfont *)malloc(sizeof(Subfont)); + if(!f) + berror("XFontStructtoSubfont malloc"); + min = fp->min_byte1; + max = fp->max_byte1; + f->minrow = min; + f->mincol = fp->min_char_or_byte2; + f->width = fp->max_char_or_byte2-fp->min_char_or_byte2+1; + f->n = f->width; + f->minchar = 0; + f->maxchar = fp->max_char_or_byte2; + if (min || max) { + f->maxchar |= (max<<8); + f->n *= (max-min+1); + } + f->id = fp->fid; + f->height = fp->max_bounds.ascent + fp->max_bounds.descent; + f->ascent = fp->max_bounds.ascent; + f->info = (Fontchar *)malloc((f->n+1)*sizeof(Fontchar)); + if(!f->info) + berror("getsubfont malloc"); + memset((void*)f->info, 0, (f->n+1)*sizeof(Fontchar)); + for(i = 0; i < f->n; i++){ + if(fp->per_char) + cp = fp->per_char + i; + else + cp = &fp->max_bounds; + f->info[i].left = cp->lbearing; + f->info[i].cwidth = cp->rbearing - cp->lbearing; + f->info[i].width = cp->width; + f->info[i].top = 0; + f->info[i].bottom = f->height; + } + XFreeFontInfo(0, fp, 0); + return f; +} + +int +scrollfwdbut(void) +{ + Arg arg; + Boolean v; + String s; + + XtSetArg(arg, XtNscrollForwardR, &v); + XtGetValues(widg, &arg, 1); + return v ? 3 : 1; +} + +void +einit(unsigned long keys) +{ + /* + * Make sure Smouse = log2(Emouse) and Skeyboard == log2(Ekeyboard) + */ + nsrc = 0; + if(keys&Emouse){ + Smouse = 0; + esrc[Smouse].inuse = 1; + esrc[Smouse].size = sizeof(Mouse); + esrc[Smouse].count = 0; + nsrc = Smouse+1; + } + if(keys&Ekeyboard){ + Skeyboard = 1; + esrc[Skeyboard].inuse = 1; + esrc[Skeyboard].size = 1; + esrc[Skeyboard].count = 0; + if(Skeyboard >= nsrc) + nsrc = Skeyboard+1; + } + einitcalled = 1; +} + +unsigned long +estart(unsigned long key, int fd, int n) +{ + int i; + + if(fd < 0) + berror("bad fd to estart"); + if(n <= 0 || n > EMAXMSG) + n = EMAXMSG; + for(i=0; i<MAXSRC; i++) + if((key & ~(1<<i)) == 0 && !esrc[i].inuse){ + if(nsrc <= i) + nsrc = i+1; + esrc[i].inuse = 1; + esrc[i].size = n; + esrc[i].count = 0; + esrc[i].id = XtAppAddInput(app, fd, (XtPointer)XtInputReadMask, + gotinput, (XtPointer) &esrc[i]); + return 1<<i; + } + return 0; +} + +static void +rmsource(int s) +{ + /* nsrc not updated. This will impact efficiency but not + * correctness, I think. + */ + esrc[s].inuse = 0; + esrc[s].size = 0; + esrc[s].count = 0; + esrc[s].head = esrc[s].tail = 0; +} + +void +estop(unsigned long key) +{ + int s; + + s = log2(key); + if (!esrc[s].inuse){ + berror("key not in use"); + } + XtRemoveInput(esrc[s].id); + rmsource(s); +} + +void +estoptimer(unsigned long key) +{ + int s; + + s = log2(key); + if (!esrc[s].inuse){ + berror("key not in use"); + } + if(Stimer != s) + berror("this key is not the timer"); + XtRemoveTimeOut( (XtIntervalId) esrc[s].id ); + Stimer = -1; + rmsource(s); +} + +unsigned long +etimer(unsigned long key, long n) +{ + int i; + + if(Stimer != -1) + berror("timer started twice"); + if(n <= 0) + n = 1000; + for(i=0; i<MAXSRC; i++) + if((key & ~(1<<i)) == 0 && !esrc[i].inuse){ + if(nsrc <= i) + nsrc = i+1; + esrc[i].inuse = 1; + esrc[i].size = 0; + esrc[i].count = 0; + esrc[i].head = 0; /* bugfix by gary */ + /* Assume an XtInputId can hold an XtIntervalId */ + esrc[i].id = (XtInputId) XtAppAddTimeOut( + app, n, gottimeout, (XtPointer)n); + Stimer = i; + return 1<<i; + } + return 0; +} + +unsigned long +event(Event *e) +{ + return eread(~0L, e); +} + +unsigned long +eread(unsigned long keys, Event *e) +{ + Ebuf *eb; + int i; + + if(keys == 0) + return 0; + /* Give Priority to X events */ + if (XtAppPending(app) & XtIMXEvent) + XtAppProcessEvent(app, XtIMXEvent); + + for(;;){ + for(i=0; i<nsrc; i++) + if((keys & (1<<i)) && esrc[i].head){ + if(i == Smouse) + e->mouse = emouse(); + else if(i == Skeyboard) + e->kbdc = ekbd(); + else if(i == Stimer) { + esrc[i].head = 0; + esrc[i].count = 0; + } else { + eb = ebread(&esrc[i]); + e->n = eb->n; + if(e->n > 0) + memcpy((void*)e->data, (void*)eb->buf, e->n); + free(eb); + } + return 1<<i; + } + waitevent(); + } +} + +void +eflush(unsigned long keys) +{ + int i; + Ebuf *eb, *enext; + + if(keys == 0) + return; + + for(i=0; i<nsrc; i++) + if((keys & (1<<i))){ + for (eb = esrc[i].head; eb; eb = enext) { + enext = eb->next; + free(eb); + } + esrc[i].count = 0; + esrc[i].head = 0; + esrc[i].tail = 0; + } +} + +Mouse +emouse(void) +{ + Mouse m; + Ebuf *eb; + + if(!esrc[Smouse].inuse) + berror("mouse events not selected"); + eb = ebread(&esrc[Smouse]); + memcpy((void*)&m, (void*)eb->buf, sizeof(Mouse)); + free(eb); + return m; +} + +int +ekbd(void) +{ + Ebuf *eb; + int c; + + if(!esrc[Skeyboard].inuse) + berror("keyboard events not selected"); + eb = ebread(&esrc[Skeyboard]); + c = BGSHORT(eb->buf); + free(eb); + return c; +} + +int +ecanread(unsigned long keys) +{ + int i; + + for(;;){ + for(i=0; i<nsrc; i++){ + if((keys & (1<<i)) && esrc[i].head) + return 1<<i; + } + if(XtAppPending(app)) + waitevent(); + else + return 0; + } +} + +int +ecanmouse(void) +{ + if(Smouse == -1) + berror("mouse events not selected"); + return ecanread(Emouse); +} + +int +ecankbd(void) +{ + if(Skeyboard == -1) + berror("keyboard events not selected"); + return ecanread(Ekeyboard); +} + +static Ebuf* +ebread(Esrc *s) +{ + Ebuf *eb; + + while(s->head == 0) + waitevent(); + eb = s->head; +#ifdef COMPRESSMOUSE + if(s == &esrc[Smouse]) { + while(eb->next) { + s->head = eb->next; + s->count--; + free(eb); + eb = s->head; + } + } +#endif + s->head = s->head->next; + if(s->head == 0) { + s->tail = 0; + s->count = 0; + } else + s->count--; + return eb; +} + +static Ebuf* +ebadd(Esrc *s) +{ + Ebuf *eb; + int m; + + m = sizeof(Ebuf); + if(s->size > 1) + m += (s->size-1); /* overestimate, because of alignment */ + eb = (Ebuf *)malloc(m); + if(eb) { + eb->next = 0; + eb->n = s->size; + if(s->tail){ + s->tail->next = eb; + s->tail = eb; + }else + s->head = s->tail = eb; + } + return eb; +} + +void +berror(char *s) +{ + if(onerr) + (*onerr)(s); + else{ + fprintf(stderr, "libg error: %s:\n", s); + exit(1); + } +} + +void +bflush(void) +{ + while(XtAppPending(app) & XtIMXEvent) + waitevent(); +} + +static void +waitevent(void) +{ + XtInputMask mask; + + XFlush(_dpy); + + mask = XtAppPending(app); + + if (mask & XtIMXEvent) + XtAppProcessEvent(app, XtIMXEvent); + else + XtAppProcessEvent(app, XtIMAll); +} + +int +snarfswap(char *s, int n, char **t) +{ + *t = GwinSelectionSwap(widg, s); + if (*t) + return strlen(*t); + return 0; +} + +char* +select_get(void) +{ + return Gwinselect_get(widg); +} + +void +select_put(char*s) +{ + Gwinselect_put(widg,s); +} + +int scrpix(int *w, int *h) +{ + if (w) + *w = WidthOfScreen(XtScreen(_toplevel)); + if (h) + *h = HeightOfScreen(XtScreen(_toplevel)); + return 1; +} + +#ifdef DEBUG +/* for debugging */ +printgc(char *msg, GC g) +{ + XGCValues v; + + XGetGCValues(_dpy, g, GCFunction|GCForeground|GCBackground|GCFont| + GCTile|GCFillStyle|GCStipple, &v); + fprintf(stderr, "%s: gc %x\n", msg, g); + fprintf(stderr, " fg %d bg %d func %d fillstyle %d font %x tile %x stipple %x\n", + v.foreground, v.background, v.function, v.fill_style, + v.font, v.tile, v.stipple); +} +#endif + |