summaryrefslogtreecommitdiff
path: root/emu/port/win-x11-old.c
diff options
context:
space:
mode:
Diffstat (limited to 'emu/port/win-x11-old.c')
-rw-r--r--emu/port/win-x11-old.c847
1 files changed, 847 insertions, 0 deletions
diff --git a/emu/port/win-x11-old.c b/emu/port/win-x11-old.c
new file mode 100644
index 00000000..e06d455c
--- /dev/null
+++ b/emu/port/win-x11-old.c
@@ -0,0 +1,847 @@
+#include "dat.h"
+#include "fns.h"
+#include "cursor.h"
+#include "keyboard.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+#include <X11/Xutil.h>
+#include <X11/keysym.h>
+
+#define ABS(x) ((x) < 0 ? -(x) : (x))
+
+/*
+ * alias defs for image types to overcome name conflicts
+ */
+typedef struct ICursor ICursor;
+typedef struct IPoint IPoint;
+typedef struct IRectangle IRectangle;
+typedef struct CRemapTbl CRemapTbl;
+struct ICursor
+{
+ int w;
+ int h;
+ int hotx;
+ int hoty;
+ char *src;
+ char *mask;
+};
+
+struct IPoint
+{
+ int x;
+ int y;
+};
+
+struct IRectangle
+{
+ IPoint min;
+ IPoint max;
+};
+
+struct CRemapTbl
+{
+ ulong inferno[256]; /* The corresponding inferno colormap vals */
+ ulong openslot[256];
+ Bool cellused[256];
+ int cnt;
+ int opencnt;
+};
+
+enum
+{
+ DblTime = 300 /* double click time in msec */
+};
+
+XColor map[256]; /* Inferno colormap array */
+XColor map7[128]; /* Inferno colormap array */
+uchar map7to8[128][2];
+Colormap xcmap; /* Default shared colormap */
+int infernotox11[256]; /* Values for mapping between */
+int x11toinferno[256]; /* X11 and inferno */
+int x24bitswap = 0; /* swap endian for 24bit RGB */
+
+static int triedscreen;
+static XModifierKeymap *modmap;
+static int keypermod;
+static Drawable xdrawable;
+static Atom wm_take_focus;
+static void xexpose(XEvent*);
+static void xmouse(XEvent*);
+static void xkeyboard(XEvent*);
+static void xmapping(XEvent*);
+static void xproc(void*);
+static void xinitscreen(int, int);
+static void initmap(Window);
+static GC creategc(Drawable);
+static CRemapTbl crtbl;
+static void graphicscmap(XColor*);
+ int xscreendepth;
+ Drawable xscreenid;
+ Display* xdisplay;
+ Display* xkmcon;
+ Visual *xvis;
+ GC xgcfill, xgccopy, xgcsimplesrc, xgczero, xgcreplsrc;
+ GC xgcfill0, xgccopy0, xgcsimplesrc0, xgczero0, xgcreplsrc0;
+
+char *gkscanid = "emu_x11";
+
+
+ulong*
+attachscreen(IRectangle *r, int *ld, int *width, int *softscreen)
+{
+ extern ulong* makememones();
+
+ r->min.x = 0;
+ r->min.y = 0;
+ r->max.x = Xsize;
+ r->max.y = Ysize;
+ *ld = 3;
+ *width = Xsize/4;
+ *softscreen = 1;
+ if(!triedscreen){
+ triedscreen = 1;
+ xinitscreen(Xsize, Ysize);
+ if(kproc("xproc", xproc, nil, 0) < 0) {
+ fprint(2, "emu: win-x11 can't make X proc\n");
+ return 0;
+ }
+ }
+ return makememones();
+}
+
+void
+flushmemscreen(IRectangle r)
+{
+ if(r.min.x > r.max.x)
+ return;
+ XCopyArea(xdisplay, xscreenid, xdrawable, xgccopy,
+ r.min.x, r.min.y,
+ r.max.x-r.min.x, r.max.y-r.min.y, r.min.x, r.min.y);
+ XFlush(xdisplay);
+}
+
+static int
+revbyte(int b)
+{
+ int r;
+
+ r = 0;
+ r |= (b&0x01) << 7;
+ r |= (b&0x02) << 5;
+ r |= (b&0x04) << 3;
+ r |= (b&0x08) << 1;
+ r |= (b&0x10) >> 1;
+ r |= (b&0x20) >> 3;
+ r |= (b&0x40) >> 5;
+ r |= (b&0x80) >> 7;
+ return r;
+}
+
+static void
+gotcursor(ICursor c)
+{
+ Cursor xc;
+ XColor fg, bg;
+ Pixmap xsrc, xmask;
+ static Cursor xcursor;
+
+ if(c.src == nil){
+ if(xcursor != 0) {
+ XFreeCursor(xdisplay, xcursor);
+ xcursor = 0;
+ }
+ XUndefineCursor(xdisplay, xdrawable);
+ XFlush(xdisplay);
+ return;
+ }
+ xsrc = XCreateBitmapFromData(xdisplay, xdrawable, c.src, c.w, c.h);
+ xmask = XCreateBitmapFromData(xdisplay, xdrawable, c.mask, c.w, c.h);
+
+ fg = map[255];
+ bg = map[0];
+ fg.pixel = infernotox11[255];
+ bg.pixel = infernotox11[0];
+ xc = XCreatePixmapCursor(xdisplay, xsrc, xmask, &fg, &bg, -c.hotx, -c.hoty);
+ if(xc != 0) {
+ XDefineCursor(xdisplay, xdrawable, xc);
+ if(xcursor != 0)
+ XFreeCursor(xdisplay, xcursor);
+ xcursor = xc;
+ }
+ XFreePixmap(xdisplay, xsrc);
+ XFreePixmap(xdisplay, xmask);
+ XFlush(xdisplay);
+ free(c.src);
+}
+
+void
+setcursor(IPoint p)
+{
+ XWarpPointer(xdisplay, None, xdrawable, 0, 0, 0, 0, p.x, p.y);
+ XFlush(xdisplay);
+}
+
+void
+drawcursor(Drawcursor* c)
+{
+ ICursor ic;
+ IRectangle ir;
+ uchar *bs, *bc;
+ int i, h, j, bpl;
+ char *src, *mask, *csrc, *cmask;
+
+ /* Set the default system cursor */
+ src = nil;
+ mask = nil;
+ if(c->data != nil){
+ h = (c->maxy-c->miny)/2;
+ ir.min.x = c->minx;
+ ir.min.y = c->miny;
+ ir.max.x = c->maxx;
+ ir.max.y = c->maxy;
+ /* passing IRectangle to Rectangle is safe */
+ bpl = bytesperline(ir, 1);
+
+ i = h*bpl;
+ src = malloc(2*i);
+ if(src == nil)
+ return;
+ mask = src + i;
+
+ csrc = src;
+ cmask = mask;
+ bc = c->data;
+ bs = c->data + h*bpl;
+ for(i = 0; i < h; i++){
+ for(j = 0; j < bpl; j++) {
+ *csrc++ = revbyte(bs[j]);
+ *cmask++ = revbyte(bs[j] | bc[j]);
+ }
+ bs += bpl;
+ bc += bpl;
+ }
+ }
+ ic.w = 8*bpl;
+ ic.h = h;
+ ic.hotx = c->hotx;
+ ic.hoty = c->hoty;
+ ic.src = src;
+ ic.mask = mask;
+
+ gotcursor(ic);
+}
+
+static void
+xproc(void *arg)
+{
+ ulong mask;
+ XEvent event;
+
+ closepgrp(up->env->pgrp);
+ closefgrp(up->env->fgrp);
+ closeegrp(up->env->egrp);
+ closesigs(up->env->sigs);
+
+ mask = KeyPressMask|
+ KeyReleaseMask|
+ ButtonPressMask|
+ ButtonReleaseMask|
+ PointerMotionMask|
+ Button1MotionMask|
+ Button2MotionMask|
+ Button3MotionMask|
+ ExposureMask;
+
+ XSelectInput(xkmcon, xdrawable, mask);
+ for(;;) {
+ XWindowEvent(xkmcon, xdrawable, mask, &event);
+ switch(event.type) {
+ case KeyPress:
+ case KeyRelease:
+ xkeyboard(&event);
+ break;
+ case ButtonPress:
+ case ButtonRelease:
+ case MotionNotify:
+ xmouse(&event);
+ break;
+ case Expose:
+ xexpose(&event);
+ break;
+ case MappingNotify:
+ xmapping(&event);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+static int
+shutup(Display *d, XErrorEvent *e)
+{
+ char buf[200];
+ print("X error: error code=%d, request_code=%d, minor=%d\n", e->error_code, e->request_code, e->minor_code);
+ XGetErrorText(d, e->error_code, buf, sizeof(buf));
+ print("%s\n", buf);
+ USED(d);
+ USED(e);
+ return 0;
+}
+
+static void
+xinitscreen(int xsize, int ysize)
+{
+ int i, pmid;
+ char *argv[2];
+ char *disp_val;
+ Window rootwin;
+ XWMHints hints;
+ Screen *screen;
+ XVisualInfo xvi;
+ int rootscreennum;
+ XTextProperty name;
+ XClassHint classhints;
+ XSizeHints normalhints;
+ XSetWindowAttributes attrs;
+
+ xscreenid = 0;
+ xdrawable = 0;
+
+ xdisplay = XOpenDisplay(NULL);
+ if(xdisplay == 0){
+ disp_val = getenv("DISPLAY");
+ if(disp_val == 0)
+ disp_val = "not set";
+ fprint(2, "emu: win-x11 open %r, DISPLAY is %s\n", disp_val);
+ cleanexit(0);
+ }
+
+ rootscreennum = DefaultScreen(xdisplay);
+ rootwin = DefaultRootWindow(xdisplay);
+
+ xscreendepth = DefaultDepth(xdisplay, rootscreennum);
+ if(XMatchVisualInfo(xdisplay, rootscreennum, 24, TrueColor, &xvi)
+ || XMatchVisualInfo(xdisplay, rootscreennum, 24, DirectColor, &xvi)){
+ xvis = xvi.visual;
+ xscreendepth = 24;
+ xtblbit = 1;
+ }
+ else if(XMatchVisualInfo(xdisplay, rootscreennum, 8, PseudoColor, &xvi)
+ || XMatchVisualInfo(xdisplay, rootscreennum, 8, StaticColor, &xvi)){
+ if(xscreendepth > 8) {
+ fprint(2, "emu: win-x11 can't deal with depth %d screens\n", xscreendepth);
+ cleanexit(0);
+ }
+ xvis = xvi.visual;
+ xscreendepth = 8;
+ }
+ else{
+ if(xscreendepth != 8){
+ fprint(2, "emu: win-x11 can't deal with depth %d screens\n", xscreendepth);
+ cleanexit(0);
+ }
+ xvis = DefaultVisual(xdisplay, rootscreennum);
+ }
+
+ screen = DefaultScreenOfDisplay(xdisplay);
+ xcmap = DefaultColormapOfScreen(screen);
+
+ if(xvis->class != StaticColor){
+ graphicscmap(map);
+ initmap(rootwin);
+ }
+
+ if(modmap = XGetModifierMapping(xdisplay))
+ keypermod = modmap->max_keypermod;
+
+ attrs.colormap = xcmap;
+ attrs.background_pixel = 0;
+ attrs.border_pixel = 0;
+ /* attrs.override_redirect = 1;*/ /* WM leave me alone! |CWOverrideRedirect */
+ xdrawable = XCreateWindow(xdisplay, rootwin, 0, 0, xsize, ysize, 0, xscreendepth, InputOutput, xvis, CWBackPixel|CWBorderPixel|CWColormap, &attrs);
+
+ /*
+ * set up property as required by ICCCM
+ */
+ name.value = "inferno";
+ name.encoding = XA_STRING;
+ name.format = 8;
+ name.nitems = strlen(name.value);
+ normalhints.flags = USSize|PMaxSize;
+ normalhints.max_width = normalhints.width = xsize;
+ normalhints.max_height = normalhints.height = ysize;
+ hints.flags = InputHint|StateHint;
+ hints.input = 1;
+ hints.initial_state = NormalState;
+ classhints.res_name = "inferno";
+ classhints.res_class = "Inferno";
+ argv[0] = "inferno";
+ argv[1] = nil;
+ XSetWMProperties(xdisplay, xdrawable,
+ &name, /* XA_WM_NAME property for ICCCM */
+ &name, /* XA_WM_ICON_NAME */
+ argv, /* XA_WM_COMMAND */
+ 1, /* argc */
+ &normalhints, /* XA_WM_NORMAL_HINTS */
+ &hints, /* XA_WM_HINTS */
+ &classhints); /* XA_WM_CLASS */
+
+ /*
+ * put the window on the screen
+ */
+ XMapWindow(xdisplay, xdrawable);
+
+ xscreenid = XCreatePixmap(xdisplay, xdrawable, xsize, ysize, xscreendepth);
+ XFlush(xdisplay);
+
+ xgcfill = creategc(xscreenid);
+ XSetFillStyle(xdisplay, xgcfill, FillSolid);
+ xgccopy = creategc(xscreenid);
+ xgcsimplesrc = creategc(xscreenid);
+ XSetFillStyle(xdisplay, xgcsimplesrc, FillStippled);
+ xgczero = creategc(xscreenid);
+ xgcreplsrc = creategc(xscreenid);
+ XSetFillStyle(xdisplay, xgcreplsrc, FillTiled);
+
+ pmid = XCreatePixmap(xdisplay, xdrawable, 1, 1, 1);
+ xgcfill0 = creategc(pmid);
+ XSetFillStyle(xdisplay, xgcfill0, FillSolid);
+ xgccopy0 = creategc(pmid);
+ xgcsimplesrc0 = creategc(pmid);
+ XSetFillStyle(xdisplay, xgcsimplesrc0, FillStippled);
+ xgczero0 = creategc(pmid);
+ xgcreplsrc0 = creategc(pmid);
+ XSetFillStyle(xdisplay, xgcreplsrc0, FillTiled);
+ XFreePixmap(xdisplay, pmid);
+
+ XSetForeground(xdisplay, xgccopy, infernotox11[0]);
+ XFillRectangle(xdisplay, xscreenid, xgccopy, 0, 0, xsize, ysize);
+
+ xkmcon = XOpenDisplay(NULL);
+ if(xkmcon == 0){
+ disp_val = getenv("DISPLAY");
+ if(disp_val == 0)
+ disp_val = "not set";
+ fprint(2, "emu: win-x11 open %r, DISPLAY is %s\n", disp_val);
+ cleanexit(0);
+ }
+}
+
+static void
+graphicscmap(XColor *map)
+{
+ int r, g, b, cr, cg, cb, v, num, den, idx, v7, idx7;
+
+ for(r=0; r!=4; r++) {
+ for(g = 0; g != 4; g++) {
+ for(b = 0; b!=4; b++) {
+ for(v = 0; v!=4; v++) {
+ den=r;
+ if(g > den)
+ den=g;
+ if(b > den)
+ den=b;
+ /* divide check -- pick grey shades */
+ if(den==0)
+ cr=cg=cb=v*17;
+ else {
+ num=17*(4*den+v);
+ cr=r*num/den;
+ cg=g*num/den;
+ cb=b*num/den;
+ }
+ idx = r*64 + v*16 + ((g*4 + b + v - r) & 15);
+ idx = 255 - idx;
+ map[idx].red = cr*0x0101;
+ map[idx].green = cg*0x0101;
+ map[idx].blue = cb*0x0101;
+ map[idx].pixel = idx;
+ map[idx].flags = DoRed|DoGreen|DoBlue;
+
+ v7 = v >> 1;
+ idx7 = r*32 + v7*16 + g*4 + b;
+ if((v & 1) == v7){
+ map7to8[idx7][0] = idx;
+ if(den == 0) { /* divide check -- pick grey shades */
+ cr = ((255.0/7.0)*v7)+0.5;
+ cg = cr;
+ cb = cr;
+ }
+ else {
+ num=17*15*(4*den+v7*2)/14;
+ cr=r*num/den;
+ cg=g*num/den;
+ cb=b*num/den;
+ }
+ map7[idx7].red = cr*0x0101;
+ map7[idx7].green = cg*0x0101;
+ map7[idx7].blue = cb*0x0101;
+ map7[idx7].pixel = idx7;
+ map7[idx7].flags = DoRed|DoGreen|DoBlue;
+ }
+ else
+ map7to8[idx7][1] = idx;
+ }
+ }
+ }
+ }
+}
+
+/*
+ * Initialize and install the Inferno colormap as a private colormap for this
+ * application. Inferno gets the best colors here when it has the cursor focus.
+ */
+static void
+initmap(Window w)
+{
+ XColor c;
+ XColor xcol;
+ ulong v;
+ int i, pix, ncmaps;
+
+ if(xscreendepth <= 1)
+ return;
+
+ if(xvis->class == TrueColor || xvis->class == DirectColor) {
+ int color_order_init = 0;
+ uint pp, p;
+
+ for(i = 0; i < 256; i++) {
+ c = map[i];
+ /* find out index into colormap for our RGB */
+ if(!XAllocColor(xdisplay, xcmap, &c)) {
+ fprint(2, "emu: win-x11 can't alloc color\n");
+ cleanexit(0);
+ }
+
+ /* The pixel value returned from XGetPixel needs to
+ * be converted to RGB so we can call rgb2cmap()
+ * to translate between 24 bit X and our color. Unfortunately,
+ * the return value appears to be display server endian
+ * dependant. Therefore, we run some heuristics to later
+ * determine how to mask the int value correctly.
+ * Yeah, I know we can look at xvis->byte_order but
+ * some displays say MSB even though they run on LSB.
+ * Besides, this is more anal.
+ */
+
+ p = c.pixel;
+ pp = rgb2cmap((p>>16)&0xff,(p>>8)&0xff,p&0xff);
+ if(!color_order_init && (pp!=map[i].pixel)) {
+ /* check if endian is other way */
+ pp = rgb2cmap(p&0xff,(p>>8)&0xff,(p>>16)&0xff);
+ if(pp!=map[i].pixel) {
+ fprint(2, "emu: win-x11 can't convert 24bit colors\n");
+ cleanexit(0);
+ }
+ color_order_init = 1;
+ x24bitswap = 1;
+ }
+
+ if(color_order_init) {
+ pp = rgb2cmap(p&0xff,(p>>8)&0xff,(p>>16)&0xff);
+ if(pp!=map[i].pixel) {
+ fprint(2, "emu: win-x11 can't convert 24bit colors\n");
+ cleanexit(0);
+ }
+ /* no x11toinferno; later use rgb2cmap() */
+ infernotox11[map[i].pixel] = c.pixel;
+ }
+ else if(pp!=map[i].pixel) {
+ fprint(2, "emu: win-x11 can't convert 24bit colors\n");
+ cleanexit(0);
+ }
+ else {
+ /* no x11toinferno; later use rgb2cmap() */
+ infernotox11[map[i].pixel] = c.pixel;
+ }
+ }
+ }
+ else if(xvis->class == PseudoColor) {
+ if(xtblbit == 0){
+ xcmap = XCreateColormap(xdisplay, w, xvis, AllocAll);
+ XStoreColors(xdisplay, xcmap, map, 256);
+ for(i = 0; i < 256; i++) {
+ infernotox11[i] = i;
+ x11toinferno[i] = i;
+ }
+ }
+ else {
+ for(i = 0; i < 128; i++) {
+ c = map7[i];
+ if(!XAllocColor(xdisplay, xcmap, &c)) {
+ fprint(2, "emu: win-x11 can't alloc colors in default map, don't use -7\n");
+ cleanexit(0);
+ }
+ infernotox11[map7to8[i][0]] = c.pixel;
+ infernotox11[map7to8[i][1]] = c.pixel;
+ x11toinferno[c.pixel] = map7to8[i][0];
+ }
+ }
+ }
+ else {
+ xtblbit = 0;
+ fprint(2, "emu: win-x11 unsupported visual class %d\n", xvis->class);
+ }
+ return;
+}
+
+static void
+xmapping(XEvent *e)
+{
+ XMappingEvent *xe;
+
+ if(e->type != MappingNotify)
+ return;
+ xe = (XMappingEvent*)e;
+ if(modmap)
+ XFreeModifiermap(modmap);
+ modmap = XGetModifierMapping(xe->display);
+ if(modmap)
+ keypermod = modmap->max_keypermod;
+}
+
+
+/*
+ * Disable generation of GraphicsExpose/NoExpose events in the GC.
+ */
+static GC
+creategc(Drawable d)
+{
+ XGCValues gcv;
+
+ gcv.function = GXcopy;
+ gcv.graphics_exposures = False;
+ return XCreateGC(xdisplay, d, GCFunction|GCGraphicsExposures, &gcv);
+}
+
+static void
+xexpose(XEvent *e)
+{
+ IRectangle r;
+ XExposeEvent *xe;
+
+ if(e->type != Expose)
+ return;
+ xe = (XExposeEvent*)e;
+ r.min.x = xe->x;
+ r.min.y = xe->y;
+ r.max.x = xe->x + xe->width;
+ r.max.y = xe->y + xe->height;
+ drawqlock();
+ flushmemscreen(r);
+ drawqunlock();
+}
+
+
+static void
+xkeyboard(XEvent *e)
+{
+ int ind, n;
+ KeySym k;
+ Rune r;
+ unsigned int md;
+ char buf[1];
+
+ if(gkscanq) {
+ uchar ch = (KeyCode)e->xkey.keycode;
+ if(e->xany.type == KeyRelease)
+ ch |= 0x80;
+ qproduce(gkscanq, &ch, 1);
+ return;
+ }
+
+ /*
+ * 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;
+
+ md = e->xkey.state;
+ ind = 0;
+ if(md & ShiftMask)
+ ind = 1;
+
+ k = XKeycodeToKeysym(e->xany.display, (KeyCode)e->xkey.keycode, ind);
+
+ /* May have to try unshifted version */
+ if(k == NoSymbol && ind == 1)
+ k = XKeycodeToKeysym(e->xany.display, (KeyCode)e->xkey.keycode, 0);
+
+ if(k == XK_Multi_key || 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_Alt_L:
+ case XK_Alt_R:
+ case XK_Meta_L:
+ case XK_Meta_R:
+ k = Latin;
+ break;
+ case XK_Left:
+ case XK_KP_Left:
+ k = Left;
+ break;
+ case XK_Down:
+ case XK_KP_Down:
+ k = Down;
+ break;
+ case XK_Right:
+ case XK_KP_Right:
+ k = Right;
+ break;
+ case XK_Up:
+ case XK_KP_Up:
+ k = Up;
+ break;
+ case XK_Home:
+ case XK_KP_Home:
+ k = Home;
+ break;
+ case XK_End:
+ case XK_KP_End:
+ k = End;
+ break;
+ case XK_Page_Up:
+ case XK_KP_Page_Up:
+ k = Pgup;
+ break;
+ case XK_Page_Down:
+ case XK_KP_Page_Down:
+ k = Pgdown;
+ break;
+ default: /* not ISO-1 or tty control */
+ return;
+ }
+ }
+ /* 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(md & ControlMask)
+ k &= 0x9f;
+ if(k == '\t' && ind)
+ k = BackTab;
+
+ if(md & Mod1Mask)
+ k = APP|(k&0xff);
+ if(k == NoSymbol)
+ return;
+
+ gkbdputc(gkbdq, k);
+}
+
+static void
+xmouse(XEvent *e)
+{
+ int s, dbl;
+ XButtonEvent *be;
+ XMotionEvent *me;
+ XEvent motion;
+ Pointer m;
+ static ulong lastb, lastt;
+
+ dbl = 0;
+ switch(e->type){
+ case ButtonPress:
+ be = (XButtonEvent *)e;
+ m.x = be->x;
+ m.y = be->y;
+ s = be->state;
+ if(be->button == lastb && be->time - lastt < DblTime)
+ dbl = 1;
+ lastb = be->button;
+ lastt = be->time;
+ 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.x = be->x;
+ m.y = be->y;
+ 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;
+
+ /* remove excess MotionNotify events from queue and keep last one */
+ while(XCheckTypedWindowEvent(xkmcon, xdrawable, MotionNotify, &motion) == True)
+ me = (XMotionEvent *) &motion;
+
+ s = me->state;
+ m.x = me->x;
+ m.y = me->y;
+ break;
+ default:
+ return;
+ }
+
+ m.b = 0;
+ if(s & Button1Mask)
+ m.b |= 1;
+ if(s & Button2Mask)
+ m.b |= 2;
+ if(s & Button3Mask)
+ m.b |= 4;
+ if(dbl)
+ m.b |= 1<<4;
+
+ m.modify = 1;
+ mouseproduce(m);
+}
+