summaryrefslogtreecommitdiff
path: root/libXg
diff options
context:
space:
mode:
authorJosip Rodin <jrodin@jagor.srce.hr>1999-06-15 14:49:16 -0700
committerJosip Rodin <jrodin@jagor.srce.hr>1999-06-15 14:49:16 -0700
commitb4340e99efb5486fb66c0d4d9348b967dc039a3a (patch)
tree9f87c02bf18a1a4bcad920d6c488e8523b667ba3 /libXg
Import wily_0.13.41.orig.tar.gz
[dgit import orig wily_0.13.41.orig.tar.gz]
Diffstat (limited to 'libXg')
-rw-r--r--libXg/Gwin.h47
-rw-r--r--libXg/GwinP.h48
-rw-r--r--libXg/Makefile.in15
-rw-r--r--libXg/arc.c44
-rw-r--r--libXg/arith.c190
-rw-r--r--libXg/balloc.c59
-rw-r--r--libXg/bitblt.c58
-rw-r--r--libXg/bitbltclip.c67
-rw-r--r--libXg/border.c27
-rw-r--r--libXg/bscreenrect.c17
-rw-r--r--libXg/circle.c22
-rw-r--r--libXg/clipline.c224
-rw-r--r--libXg/clipr.c20
-rw-r--r--libXg/copymasked.c47
-rw-r--r--libXg/cursorset.c15
-rw-r--r--libXg/cursorswitch.c65
-rw-r--r--libXg/disc.c22
-rw-r--r--libXg/ellipse.c22
-rw-r--r--libXg/font.c91
-rw-r--r--libXg/gcs.c400
-rw-r--r--libXg/getrect.c72
-rw-r--r--libXg/gwin.c542
-rw-r--r--libXg/latin1.c247
-rw-r--r--libXg/ldconvert.c54
-rw-r--r--libXg/libgint.h94
-rw-r--r--libXg/menuhit.c236
-rw-r--r--libXg/mkfont.c47
-rw-r--r--libXg/point.c20
-rw-r--r--libXg/polysegment.c26
-rw-r--r--libXg/rdbitmap.c62
-rw-r--r--libXg/rdbitmapfile.c64
-rw-r--r--libXg/rdfontfile.c135
-rw-r--r--libXg/rectclip.c24
-rw-r--r--libXg/rune.c194
-rw-r--r--libXg/segment.c24
-rw-r--r--libXg/string.c54
-rw-r--r--libXg/strwidth.c30
-rw-r--r--libXg/test.c237
-rw-r--r--libXg/texture.c41
-rw-r--r--libXg/wrbitmap.c54
-rw-r--r--libXg/wrbitmapfile.c49
-rw-r--r--libXg/xtbinit.c955
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
+