/* * Graphics support routines for T3X under Unix/X11. * Copyright (C) 1997,1998,2003 Nils M. Holm * See the file LICENSE for conditions of use. */ #include #include #include #include #include #include #include #define XLIM 16000 #define YLIM 16000 Display *Dsp; Window Win; GC Csr, Csr_set, Csr_clear, Csr_invert; int Reshaped; int Fx, Fy; int Xn, Yn; int M_shift, M_control; #define EV_X 0 #define EV_Y 1 #define EV_BUTTONS 2 #define EV_KEY 3 void adjust(width, height) { Fx = XLIM * 2 / width; Fy = YLIM * 2 / height; } XCELL gfxctl_reshaped S0() { int r = Reshaped; Reshaped = 0; return r; } error(s) char *s; { fprintf(stderr, "GFX class: %s\n", s); exit(1); } XCELL gfxctl__init S1(char *title) { XEvent e; XGCValues v; int i = -1; char *dpyname; int scrn; XSizeHints *wm_size; XWMHints *wm_hints; XClassHint *wm_class; XTextProperty wname; Xn = 500; Yn = 375; wm_size = XAllocSizeHints(); wm_hints = XAllocWMHints(); wm_class = XAllocClassHint(); if (!(wm_size && wm_hints && wm_class)) error("Not enough memory"); dpyname = getenv("DISPLAY"); Dsp = XOpenDisplay(dpyname); if (!Dsp) error("Could not open display"); scrn = DefaultScreen(Dsp); Win = XCreateSimpleWindow(Dsp, RootWindow(Dsp, scrn), 10, 10, Xn, Yn, 0, BlackPixel(Dsp, scrn), WhitePixel(Dsp, scrn)); if (!Dsp) error("Could not create window"); XSelectInput(Dsp, Win, KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | ExposureMask | PointerMotionMask); v.plane_mask = AllPlanes; v.foreground = 0; v.background = -1; v.function = GXset; Csr_set = XCreateGC(Dsp, Win, GCPlaneMask | GCForeground | GCBackground | GCFunction, &v); v.function = GXclear; Csr_clear = XCreateGC(Dsp, Win, GCPlaneMask | GCForeground | GCBackground | GCFunction, &v); v.function = GXinvert; Csr_invert = XCreateGC(Dsp, Win, GCPlaneMask | GCForeground | GCBackground | GCFunction, &v); XStringListToTextProperty(&title, 1, &wname); wm_hints->initial_state = NormalState; wm_hints->flags = StateHint; wm_class->res_name = title; wm_class->res_class = title; XSetWMProperties(Dsp, Win, &wname, &wname, &title, 1, wm_size, wm_hints, wm_class); XMapWindow(Dsp, Win); do { XNextEvent(Dsp, &e); } while (e.type != Expose); adjust(Xn, Yn); Reshaped = 1; M_shift = M_control = 0; return 0; } XCELL gfxctl_fini S0() { XFreeGC(Dsp, Csr_set); XFreeGC(Dsp, Csr_clear); XFreeGC(Dsp, Csr_invert); XDestroyWindow(Dsp, Win); XFlush(Dsp); XCloseDisplay(Dsp); return 0; } XCELL gfxctl_sync S0() { XFlush(Dsp); return 0; } void flags(f) { switch(f) { case 0: Csr = Csr_set; break; case 1: Csr = Csr_clear; break; case 2: Csr = Csr_invert; break; } } XCELL gfxctl_point S3(XCELL x, XCELL y, XCELL f) { x = (x + XLIM) / Fx; y = (y + YLIM) / Fy; flags(f); XDrawPoint(Dsp, Win, Csr, x, y); return 0; } XCELL gfxctl_line S5(XCELL x, XCELL y, XCELL dx, XCELL dy, XCELL f) { x = (x + XLIM) / Fx; y = (y + YLIM) / Fy; dx = (dx + XLIM) / Fx; dy = (dy + YLIM) / Fy; flags(f); XDrawLine(Dsp, Win, Csr, x, y, dx, dy); return 0; } #ifdef LIBRARY XCELL gfxctl_box(XCELL, XCELL, XCELL, XCELL, XCELL, XCELL); #else XCELL gfxctl_box(XCELL, XCELL, XCELL, XCELL, XCELL); #endif XCELL gfxctl_box S5(XCELL x, XCELL y, XCELL dx, XCELL dy, XCELL f) { XCELL t; x = (x + XLIM) / Fx; y = (y + YLIM) / Fy; dx = (dx + XLIM) / Fx; dy = (dy + YLIM) / Fy; if (x > dx) { t = x; x = dx; dx = t; } if (y > dy) { t = y; y = dy; dy = t; } flags(f); XFillRectangle(Dsp, Win, Csr, x, y, dx-x, dy-y); return 0; } XCELL gfxctl_clear S1(XCELL m) { #ifdef LIBRARY gfxctl_box(0, m, YLIM, XLIM, -YLIM, -XLIM); #else gfxctl_box(m, YLIM, XLIM, -YLIM, -XLIM); #endif return 0; } XCELL gfxctl_ratio S0() { XCELL r; r = (XCELL) Fx * (XCELL) 100; return r / Fy; } XCELL gfxctl_wait S1(XCELL msec) { usleep(msec*1000); return 0; } int mapkey(k) KeySym k; { switch (k) { case XK_Begin: case XK_Home: return(327); case XK_End: return(335); case XK_Left: return(331); case XK_Right: return(333); case XK_Up: return(328); case XK_Down: return(336); case XK_Prior: return(329); case XK_Next: return(337); case XK_Insert: return(338); case XK_Delete: return(339); case XK_F1: return(315); case XK_F2: return(316); case XK_F3: return(317); case XK_F4: return(318); case XK_F5: return(319); case XK_F6: return(320); case XK_F7: return(321); case XK_F8: return(322); case XK_F9: return(323); case XK_F10: return(324); } if (IsModifierKey(k)) return -1; if (k & 0xFF00) return(k&0x7f); return(k); } XCELL gfxctl_poll S2(XCELL *e, XCELL block) { static int mx = 0, my = 0; static int buttons = 0; XEvent xe; int r; KeySym k, k2; int n; Drawable d; XFlush(Dsp); e[EV_X] = mx; e[EV_Y] = my; e[EV_BUTTONS] = buttons; e[EV_KEY] = -1; if (!block && !XPending(Dsp)) return(0); r = 0; while (1) { XNextEvent(Dsp, &xe); switch (xe.type) { case MotionNotify: e[EV_X] = xe.xmotion.x; e[EV_Y] = xe.xmotion.y; break; case ButtonPress: e[EV_BUTTONS] = xe.xbutton.button == Button1? 1: xe.xbutton.button == Button2? 2: xe.xbutton.button == Button3? 4: 0; e[EV_X] = xe.xbutton.x; e[EV_Y] = xe.xbutton.y; r = -1; break; case ButtonRelease: e[EV_BUTTONS] = 0; e[EV_X] = xe.xbutton.x; e[EV_Y] = xe.xbutton.y; r = -1; break; case KeyRelease: k = XKeycodeToKeysym(Dsp, xe.xkey.keycode, 0); switch (k) { case XK_Shift_L: case XK_Shift_R: M_shift = 0; continue; case XK_Control_L: case XK_Control_R: M_control = 0; continue; default: e[EV_X] = xe.xkey.x; e[EV_Y] = xe.xkey.y; } continue; case KeyPress: k = XKeycodeToKeysym(Dsp, xe.xkey.keycode, 0); switch (k) { case XK_Shift_L: case XK_Shift_R: M_shift = 1; continue; case XK_Control_L: case XK_Control_R: M_control = 1; continue; default: if (M_control) { if (islower(k)) k -= '`'; else k -= '@'; } else if (M_shift) k = XKeycodeToKeysym(Dsp, xe.xkey.keycode, 1); e[EV_KEY] = mapkey(k); e[EV_X] = xe.xkey.x; e[EV_Y] = xe.xkey.y; r = -1; } break; case Expose: XGetGeometry(Dsp, Win, &d, &n, &n, &Xn, &Yn, &n, &n); adjust(Xn, Yn); Reshaped = 1; r = 0; e[EV_X] = xe.xexpose.x; e[EV_Y] = xe.xexpose.y; while (XCheckTypedEvent(Dsp, Expose, &xe)) ; break; } if (XPending(Dsp)) continue; if (!block || r || Reshaped) break; } mx = e[EV_X] * Fx - XLIM; my = e[EV_Y] * Fy - YLIM; e[EV_X] = mx; e[EV_Y] = my; buttons = e[EV_BUTTONS]; return(r); }