diff options
Diffstat (limited to 'libXg/gwin.c')
-rw-r--r-- | libXg/gwin.c | 542 |
1 files changed, 542 insertions, 0 deletions
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); +} + |