Mercurial > kinput2.yaz
view lib/ConvCtrl.c @ 0:92745d501b9a
initial import from kinput2-v3.1
author | Yoshiki Yazawa <yaz@honeyplanet.jp> |
---|---|
date | Mon, 08 Mar 2010 04:44:30 +0900 |
parents | |
children | 7a454839a6de |
line wrap: on
line source
#ifndef lint static char *rcsid = "$Id: ConvCtrl.c,v 1.54 2001/01/10 08:51:28 ishisone Exp $"; #endif /* * Copyright (c) 1990 Software Research Associates, Inc. * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose and without fee is hereby granted, provided * that the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of Software Research Associates not be * used in advertising or publicity pertaining to distribution of the * software without specific, written prior permission. Software Research * Associates makes no representations about the suitability of this software * for any purpose. It is provided "as is" without express or implied * warranty. * * Author: Makoto Ishisone, Software Research Associates, Inc., Japan */ #include <X11/IntrinsicP.h> #include <X11/StringDefs.h> #include <X11/Xmu/CharSet.h> #include "ConvCtrlP.h" #include "InputConv.h" #include "ConvDisp.h" #include "MyDispatch.h" #include "AsyncErr.h" #define DEBUG_VAR debug_ConversionControl #include "DebugPrint.h" static XtResource resources[] = { #define offset(field) XtOffset(ConversionControlWidget, ccontrol.field) { XtNinputObject, XtCInputObject, XtRWidget, sizeof(Widget), offset(inputobj), XtRImmediate, (XtPointer)NULL }, { XtNinputObjectClass, XtCInputObjectClass, XtRPointer, sizeof(WidgetClass), offset(inputobjclass), XtRImmediate, (XtPointer)NULL }, { XtNdisplayObjectClass, XtCDisplayObjectClass, XtRPointer, sizeof(WidgetClass), offset(displayobjclass), XtRImmediate, (XtPointer)NULL }, { XtNclientWindow, XtCWindow, XtRWindow, sizeof(Window), offset(clientwindow), XtRImmediate, (XtPointer)None }, { XtNfocusWindow, XtCWindow, XtRWindow, sizeof(Window), offset(focuswindow), XtRImmediate, (XtPointer)None }, { XtNcursor, XtCCursor, XtRCursor, sizeof(Cursor), offset(cursor), XtRImmediate, (XtPointer)None }, { XtNeventSelectMethod, XtCEventSelectMethod, XtREventSelectMethod, sizeof(EventSelectMethod), offset(eventselectmethod), XtRString, (XtPointer)"none" }, { XtNtextEncoding, XtCTextEncoding, XtRAtom, sizeof(Atom), offset(textencoding), XtRString, "COMPOUND_TEXT" }, { XtNtextCallback, XtCCallback, XtRCallback, sizeof(XtCallbackList), offset(textcallback), XtRCallback, (XtPointer)NULL }, { XtNnewTextCallback, XtCCallback, XtRCallback, sizeof(XtCallbackList), offset(newtextcallback), XtRCallback, (XtPointer)NULL }, { XtNendCallback, XtCCallback, XtRCallback, sizeof(XtCallbackList), offset(endcallback), XtRCallback, (XtPointer)NULL }, { XtNunusedEventCallback, XtCCallback, XtRCallback, sizeof(XtCallbackList), offset(unusedeventcallback), XtRCallback, (XtPointer)NULL }, { XtNsendbackKeyPress, XtCSendbackEvent, XtRBoolean, sizeof(Boolean), offset(sendbackKeyPress), XtRString, (XtPointer)"False" }, { XtNtitlebarHeight, XtCTitlebarHeight, XtRDimension, sizeof(Dimension), offset(titlebarheight), XtRImmediate, (XtPointer)0 }, #undef offset }; static void EventToInputObject(); static XtActionsRec actions[] = { {"to-inputobj", EventToInputObject }, }; static char translations[] = "<Key>: to-inputobj()"; static void ClassInitialize(); static void StringToESM(); static void ClassPartInitialize(); static void Initialize(), Destroy(); static void Realize(); static void Resize(); static Boolean SetValues(); static void ConversionStartup(); static void ConversionFinish(); static void ChangeAttributes(); static void ChangeFocus(); static void TextChange(); static void Fix(); static void ModeChange(); static void SelectionControl(); static void AuxControl(); static void GetClientCoordinates(); static Widget CreateInputObject(); static Boolean ClassIsSubClassOf(); static void CaptureClientDead(); static void InterceptClientKeyEvent(); static void SelectFocusKeyEvent(); static void UnselectFocusKeyEvent(); static void ClientKey(); static void ClientDead(); static Boolean SafeGetWindowAttributes(); static void CheckAttributes(); static void CheckCoordinates(); static Boolean clipRectangle(); static void FixCallback(); static void ConversionEndCallback(); static void TextChangeCallback(); static void ModeChangeCallback(); static void SelectionControlCallback(); static void AuxControlCallback(); static void WidgetError(), WidgetWarning(); static CompositeClassExtensionRec CompositeExtension = { /* next_extension */ NULL, /* record_type */ NULLQUARK, /* version */ XtCompositeExtensionVersion, /* record_size */ sizeof(CompositeClassExtensionRec), /* accept_objects */ True, }; ConversionControlClassRec conversionControlClassRec = { { /* core fields */ /* superclass */ (WidgetClass) &transientShellClassRec, /* class_name */ "ConversionControl", /* widget_size */ sizeof(ConversionControlRec), /* class_initialize */ ClassInitialize, /* class_part_initialize */ ClassPartInitialize, /* class_inited */ FALSE, /* initialize */ Initialize, /* 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 */ TRUE, /* compress_enterleave */ TRUE, /* visible_interest */ FALSE, /* destroy */ Destroy, /* resize */ Resize, /* expose */ NULL, /* set_values */ SetValues, /* set_values_hook */ NULL, /* set_values_almost */ XtInheritSetValuesAlmost, /* get_values_hook */ NULL, /* accept_focus */ NULL, /* version */ XtVersion, /* callback_private */ NULL, /* tm_table */ translations, /* query_geometry */ XtInheritQueryGeometry, /* display_accelerator */ XtInheritDisplayAccelerator, /* extension */ NULL }, { /* composite fields */ /* geometry_manager */ XtInheritGeometryManager, /* change_managed */ XtInheritChangeManaged, /* insert_child */ XtInheritInsertChild, /* delete_child */ XtInheritDeleteChild, /* extension */ (XtPointer)&CompositeExtension, }, { /* shell fields */ /* extension */ NULL }, { /* wm_shell fields */ /* extension */ NULL }, { /* vendor_shell fields */ /* extension */ NULL }, { /* transient_shell fields */ /* extension */ NULL }, { /* conversionControl fields */ /* Startup */ ConversionStartup, /* Finish */ ConversionFinish, /* ChangeAttributes */ ChangeAttributes, /* ChangeFocus */ ChangeFocus, /* TextChange */ TextChange, /* Fix */ Fix, /* ModeChange */ ModeChange, /* SelectionControl */ SelectionControl, /* AuxControl */ AuxControl, } }; WidgetClass conversionControlWidgetClass = (WidgetClass)&conversionControlClassRec; /* ARGSUSED */ static void ClassInitialize() { /* add String -> EventSelectionMethod converter */ XtAddConverter(XtRString, XtREventSelectMethod, StringToESM, (XtConvertArgList)NULL, (Cardinal)0); } /* ARGSUSED */ static void StringToESM(args, num_args, from, to) XrmValue *args; Cardinal *num_args; XrmValue *from; XrmValue *to; { char *s = (char *)from->addr; static EventSelectMethod esm = ESMethodNone; if (!XmuCompareISOLatin1(s, "inputonly")) { esm = ESMethodInputOnly; } else if (!XmuCompareISOLatin1(s, "selectfocus")) { esm = ESMethodSelectFocus; } else if (!XmuCompareISOLatin1(s, "none")) { esm = ESMethodNone; } else { XtStringConversionWarning(s, XtREventSelectMethod); } to->size = sizeof(EventSelectMethod); to->addr = (caddr_t)&esm; } static void ClassPartInitialize(cl) WidgetClass cl; { ConversionControlWidgetClass class = (ConversionControlWidgetClass)cl; ConversionControlWidgetClass super = (ConversionControlWidgetClass)class->core_class.superclass; #define ccclass conversionControl_class if (class->ccclass.Startup == XtInheritStartup) { class->ccclass.Startup = super->ccclass.Startup; } if (class->ccclass.Finish == XtInheritFinish) { class->ccclass.Finish = super->ccclass.Finish; } if (class->ccclass.ChangeAttributes == XtInheritChangeAttributes) { class->ccclass.ChangeAttributes = super->ccclass.ChangeAttributes; } if (class->ccclass.ChangeFocus == XtInheritChangeFocus) { class->ccclass.ChangeFocus = super->ccclass.ChangeFocus; } if (class->ccclass.TextChange == XtInheritTextChange) { class->ccclass.TextChange = super->ccclass.TextChange; } if (class->ccclass.Fix == XtInheritFix) { class->ccclass.Fix = super->ccclass.Fix; } if (class->ccclass.ModeChange == XtInheritModeChange) { class->ccclass.ModeChange = super->ccclass.ModeChange; } if (class->ccclass.SelectionControl == XtInheritSelectionControl) { class->ccclass.SelectionControl = super->ccclass.SelectionControl; } if (class->ccclass.AuxControl == XtInheritAuxControl) { class->ccclass.AuxControl = super->ccclass.AuxControl; } #undef ccclass } /* ARGSUSED */ static void Initialize(req, new, args, num_args) Widget req; Widget new; ArgList args; Cardinal *num_args; { ConversionControlWidget ccw = (ConversionControlWidget)new; /* * check inputobj/inputobjclass resource */ if (ccw->ccontrol.inputobj == NULL) { /* if inputobj not specified, inputobjclass must be specified */ if (ccw->ccontrol.inputobjclass == NULL) { WidgetError(new, "noResourceError", "inputObjectClass", "either inputObject or inputObjectClass must be specified at creation time"); } else if (!ClassIsSubClassOf(ccw->ccontrol.inputobjclass, inputConvObjectClass)) { WidgetError(new, "classError", "inputObjectClass", "inputObjectClass must be subclass of inputConvObjectClass"); } (void)CreateInputObject(ccw); ccw->ccontrol.createinputobj = True; } else if (!XtIsSubclass(ccw->ccontrol.inputobj, inputConvObjectClass)) { WidgetError(new, "classError", "inputObject", "inputObject must be subclass of inputConvObjectClass"); } if (ccw->ccontrol.displayobjclass == NULL) { WidgetError(new, "noResourceError", "displayObjectClass", "displayObjectClass must be specified"); } else if (!ClassIsSubClassOf(ccw->ccontrol.displayobjclass, convDisplayObjectClass)) { WidgetError(new, "classError", "displayObjectClass", "displayObjectClass must be subclass of convDisplayObjectClass"); } ccw->ccontrol.active = False; ccw->ccontrol.oldclientwindow = None; ccw->ccontrol.probewindow = None; } static void Destroy(w) Widget w; { ConversionControlWidget ccw = (ConversionControlWidget)w; Display *dpy = XtDisplay(w); if (ccw->ccontrol.active == False) return; if (ccw->ccontrol.clientwindow != None) { MyRemoveAllEventHandler(dpy, ccw->ccontrol.clientwindow); } if (ccw->ccontrol.probewindow != None) { MyRemoveAllEventHandler(dpy, ccw->ccontrol.probewindow); XDestroyWindow(dpy, ccw->ccontrol.probewindow); } } static void Realize(w, maskp, attr) Widget w; XtValueMask *maskp; XSetWindowAttributes *attr; { ConversionControlWidget ccw = (ConversionControlWidget)w; if (ccw->ccontrol.cursor != None) { attr->cursor = ccw->ccontrol.cursor; *maskp |= CWCursor; } /* call super class's realize function */ (*conversionControlWidgetClass->core_class.superclass->core_class.realize)(w, maskp, attr); } static void Resize(w) Widget w; { ConversionControlWidget ccw = (ConversionControlWidget)w; Widget child; int i; TRACE(("ConversionControl:Resize()\n")); /* ignore non-widgets */ for (i = 0; i < ccw->composite.num_children; i++) { child = ccw->composite.children[i]; if (XtIsWidget(child) && child->core.managed) { XtResizeWidget(child, ccw->core.width, ccw->core.height, child->core.border_width); } } } /* ARGSUSED */ static Boolean SetValues(cur, req, wid, args, num_args) Widget cur; Widget req; Widget wid; ArgList args; Cardinal *num_args; { ConversionControlWidget old = (ConversionControlWidget)cur; ConversionControlWidget new = (ConversionControlWidget)wid; if (new->ccontrol.active) { if (old->ccontrol.inputobj != new->ccontrol.inputobj) { WidgetWarning(wid, "setValuesError", "inputObject", "inputObject resource can't be changed during conversion"); new->ccontrol.inputobj = old->ccontrol.inputobj; /* restore */ } if (old->ccontrol.eventselectmethod != new->ccontrol.eventselectmethod) { WidgetWarning(wid, "setValuesError", "eventSelectionMethod", "eventSelectionMethod resource can't be changed during conversion"); new->ccontrol.eventselectmethod = old->ccontrol.eventselectmethod; /* restore */ } } if (new->ccontrol.clientwindow != old->ccontrol.clientwindow || new->ccontrol.focuswindow != old->ccontrol.focuswindow) { WidgetWarning(wid, "setValuesError", "clientWindow", "clientWindow and focusWindow resources are read-only"); new->ccontrol.clientwindow = old->ccontrol.clientwindow; /* restore */ new->ccontrol.focuswindow = old->ccontrol.focuswindow; /* restore */ } if (new->ccontrol.cursor != old->ccontrol.cursor && XtIsRealized(wid)) { XDefineCursor(XtDisplay(wid), XtWindow(wid), new->ccontrol.cursor); } return False; } /* ARGSUSED */ static void ConversionStartup(w, mask, value) Widget w; unsigned long mask; ConversionAttributes *value; { /* do nothing */ } /* ARGSUSED */ static void ConversionFinish(w) Widget w; { /* do nothing */ } /* ARGSUSED */ static void ChangeAttributes(w, mask, value) Widget w; unsigned long mask; ConversionAttributes *value; { /* do nothing */ } /* ARGSUSED */ static void ChangeFocus(w, set) Widget w; int set; { /* do nothing */ } /* ARGSUSED */ static void TextChange(w) Widget w; { /* do nothing */ } /* ARGSUSED */ static void Fix(w, arg) Widget w; CCTextCallbackArg *arg; { ConversionControlWidget ccw = (ConversionControlWidget)w; XtCallCallbackList((Widget)ccw, ccw->ccontrol.textcallback, (XtPointer)arg); } /* ARGSUSED */ static void ModeChange(w) Widget w; { /* do nothing */ } /* ARGSUSED */ static void SelectionControl(w, controlarg) Widget w; ICSelectionControlArg *controlarg; { /* do nothing */ } /* ARGSUSED */ static void AuxControl(w, controlarg) Widget w; ICAuxControlArg *controlarg; { /* do nothing */ } /* * public functions */ void CControlStartConversion(w, clientwindow, valuemask, value) Widget w; Window clientwindow; unsigned long valuemask; ConversionAttributes *value; { ConversionControlWidget ccw = (ConversionControlWidget)w; ConversionControlWidgetClass class = (ConversionControlWidgetClass)w->core.widget_class; TRACE(("CControlStartConversion(clientwindow=%lx)\n", clientwindow)); if (ccw->ccontrol.active) { WidgetWarning(w, "busyError", "CControlStartConversion", "is busy. can't start conversion"); return; } if (clientwindow == None) { /* ouch */ WidgetWarning(w, "dataError", "cControlStartConversion", "clientWindow not specified. can't start conversion."); return; } /* check clientWindow's existance */ if (!SafeGetWindowAttributes(XtDisplay(w), clientwindow, &(ccw->ccontrol.client_attr))) { WidgetWarning(w, "badWindowError", "clientWindow", "clientWindow does not exist. can't start conversion."); return; } ICClearConversion(ccw->ccontrol.inputobj); ccw->ccontrol.notext = ICNumSegments(ccw->ccontrol.inputobj) == 0; ccw->ccontrol.active = True; ccw->ccontrol.clientwindow = clientwindow; /* check given attributes */ CheckAttributes(ccw, &valuemask, value); if (valuemask & CAFocusWindow) { ccw->ccontrol.focuswindow = value->focuswindow; } else { ccw->ccontrol.focuswindow = clientwindow; ccw->ccontrol.focus_attr = ccw->ccontrol.client_attr; } if (ccw->ccontrol.eventselectmethod == ESMethodInputOnly) { InterceptClientKeyEvent(ccw); } else if (ccw->ccontrol.eventselectmethod == ESMethodSelectFocus) { SelectFocusKeyEvent(ccw); } CheckCoordinates(ccw, &valuemask, value, 1); GetClientCoordinates(ccw); CaptureClientDead(ccw); XtAddCallback(ccw->ccontrol.inputobj, XtNfixNotify, FixCallback, (XtPointer)ccw); XtAddCallback(ccw->ccontrol.inputobj, XtNendNotify, ConversionEndCallback, (XtPointer)ccw); XtAddCallback(ccw->ccontrol.inputobj, XtNtextChangeNotify, TextChangeCallback, (XtPointer)ccw); XtAddCallback(ccw->ccontrol.inputobj, XtNmodeChangeNotify, ModeChangeCallback, (XtPointer)ccw); XtAddCallback(ccw->ccontrol.inputobj, XtNselectionControl, SelectionControlCallback, (XtPointer)ccw); XtAddCallback(ccw->ccontrol.inputobj, XtNauxControl, AuxControlCallback, (XtPointer)ccw); /* call input style dependent startup */ (*class->conversionControl_class.Startup)(w, valuemask, value); } void CControlEndConversion(w) Widget w; { ConversionControlWidget ccw = (ConversionControlWidget)w; ConversionControlWidgetClass class = (ConversionControlWidgetClass)w->core.widget_class; Display *dpy = XtDisplay(w); if (!ccw->ccontrol.active) { WidgetWarning(w, "busyError", "cControlEndConversion", "is not active. can't stop conversion"); return; } XtRemoveCallback(ccw->ccontrol.inputobj, XtNfixNotify, FixCallback, (XtPointer)ccw); XtRemoveCallback(ccw->ccontrol.inputobj, XtNendNotify, ConversionEndCallback, (XtPointer)ccw); XtRemoveCallback(ccw->ccontrol.inputobj, XtNtextChangeNotify, TextChangeCallback, (XtPointer)ccw); XtRemoveCallback(ccw->ccontrol.inputobj, XtNmodeChangeNotify, ModeChangeCallback, (XtPointer)ccw); XtRemoveCallback(ccw->ccontrol.inputobj, XtNselectionControl, SelectionControlCallback, (XtPointer)ccw); XtRemoveCallback(ccw->ccontrol.inputobj, XtNauxControl, AuxControlCallback, (XtPointer)ccw); ICClearConversion(ccw->ccontrol.inputobj); MyRemoveEventHandler(dpy, ccw->ccontrol.clientwindow, DestroyNotify, ClientDead, (XtPointer)ccw); if (ccw->ccontrol.probewindow != None) { MyRemoveAllEventHandler(dpy, ccw->ccontrol.probewindow); XDestroyWindow(dpy, ccw->ccontrol.probewindow); ccw->ccontrol.probewindow = None; } /* unselect focuswindow events */ if (ccw->ccontrol.eventselectmethod == ESMethodSelectFocus) { UnselectFocusKeyEvent(ccw); } ccw->ccontrol.active = False; /* call input style dependent finish */ (*class->conversionControl_class.Finish)(w); ccw->ccontrol.oldclientwindow = ccw->ccontrol.clientwindow; ccw->ccontrol.clientwindow = None; } void CControlChangeAttributes(w, valuemask, value) Widget w; unsigned long valuemask; ConversionAttributes *value; { ConversionControlWidget ccw = (ConversionControlWidget)w; ConversionControlWidgetClass class = (ConversionControlWidgetClass)w->core.widget_class; if (!ccw->ccontrol.active) { WidgetWarning(w, "busyError", "cControlChangeAttributes", "is not active. can't change attributes"); return; } CheckAttributes(ccw, &valuemask, value); CheckCoordinates(ccw, &valuemask, value, 0); if (valuemask == 0L) return; if (valuemask & CAFocusWindow) { if (ccw->ccontrol.eventselectmethod == ESMethodSelectFocus) { UnselectFocusKeyEvent(ccw); } ccw->ccontrol.focuswindow = value->focuswindow; if (ccw->ccontrol.eventselectmethod == ESMethodSelectFocus) { SelectFocusKeyEvent(ccw); } } (*class->conversionControl_class.ChangeAttributes)(w, valuemask, value); } void CControlChangeFocus(w, set) Widget w; int set; { ConversionControlWidget ccw = (ConversionControlWidget)w; ConversionControlWidgetClass class = (ConversionControlWidgetClass)w->core.widget_class; if (!ccw->ccontrol.active) { WidgetWarning(w, "busyError", "cControlChangeFocus", "is not active. can't change focus"); return; } (*class->conversionControl_class.ChangeFocus)(w, set); } static Boolean SafeGetWindowAttributes(dpy, w, attr) Display *dpy; Window w; XWindowAttributes *attr; { XAEHandle h; unsigned long errbits = 0; h = XAESetRecordErrors(dpy, &errbits); (void)XGetWindowAttributes(dpy, w, attr); XAEUnset(h); return (errbits == 0); } static void CheckAttributes(ccw, valuemaskp, value) ConversionControlWidget ccw; unsigned long *valuemaskp; ConversionAttributes *value; { Display *dpy = XtDisplay((Widget)ccw); XAEHandle h; unsigned long ebits = 0; #define CHECKATTRS (CAFocusWindow|CAColormap|CACursor|CABackgroundPixmap) if ((*valuemaskp & CHECKATTRS) == 0) return; #undef CHECKATTRS #define XERROR(e) (ebits & (1 << (e))) h = XAESetRecordErrors(dpy, &ebits); if (*valuemaskp & (CAColormap|CACursor|CABackgroundPixmap)) { XSetWindowAttributes attr; Window w; w = XCreateSimpleWindow(dpy, ccw->ccontrol.clientwindow, 0, 0, 1, 1, 0, 0L, 0L); if (*valuemaskp & CACursor) { /* BadCursor */ attr.cursor = value->cursor; XChangeWindowAttributes(dpy, w, CWCursor, &attr); } if (*valuemaskp & CAColormap) { /* BadMatch or BadColormap */ attr.colormap = value->colormap; XChangeWindowAttributes(dpy, w, CWColormap, &attr); } if (*valuemaskp & CABackgroundPixmap) { /* BadMatch or BadPixmap */ attr.background_pixmap = value->background_pixmap; XChangeWindowAttributes(dpy, w, CWBackPixmap, &attr); } XDestroyWindow(dpy, w); } if (*valuemaskp & CAFocusWindow) { (void)XGetWindowAttributes(dpy, value->focuswindow, &(ccw->ccontrol.focus_attr)); } else { XSync(dpy, False); } XAEUnset(h); if ((*valuemaskp & CAFocusWindow) && XERROR(BadWindow)) { WidgetWarning((Widget)ccw, "badWindowError", "focusWindow", "focusWindow does not exist."); *valuemaskp &= ~CAFocusWindow; } if ((*valuemaskp & CAColormap) && XERROR(BadColor)) { WidgetWarning((Widget)ccw, "badColorError", "colormap", "invalid colormap ID."); *valuemaskp &= ~CAColormap; } if ((*valuemaskp & CAColormap) && XERROR(BadMatch)) { WidgetWarning((Widget)ccw, "badMatchError", "colormap", "invalid colormap."); *valuemaskp &= ~CAColormap; } if ((*valuemaskp & CABackgroundPixmap) && XERROR(BadPixmap)) { WidgetWarning((Widget)ccw, "badPixmapError", "backgroundPixmap", "invalid pixmap ID."); *valuemaskp &= ~CABackgroundPixmap; } if ((*valuemaskp & CABackgroundPixmap) && XERROR(BadMatch)) { WidgetWarning((Widget)ccw, "badMatchError", "backgroundPixmap", "invalid pixmap for background."); *valuemaskp &= ~CABackgroundPixmap; } if ((*valuemaskp & CACursor) && XERROR(BadCursor)) { WidgetWarning((Widget)ccw, "badCursorError", "cursor", "invalid cursor ID."); *valuemaskp &= ~CACursor; } #undef XERROR } static void CheckCoordinates(ccw, valuemaskp, value, clip) ConversionControlWidget ccw; unsigned long *valuemaskp; ConversionAttributes *value; int clip; { #define INVALIDRECT(r) (r.width == 0 || r.height == 0) if ((*valuemaskp & CAClientArea) && (INVALIDRECT(value->clientarea) || (clip && !clipRectangle(&value->clientarea, &ccw->ccontrol.client_attr)))) { DPRINT(("CheckCoordinates: invalid ClientArea\n")); *valuemaskp &= ~CAClientArea; } if ((*valuemaskp & CAStatusArea) && (INVALIDRECT(value->statusarea) || (clip && !clipRectangle(&value->statusarea, &ccw->ccontrol.client_attr)))) { DPRINT(("CheckCoordinates: invalid StatusArea\n")); *valuemaskp &= ~CAStatusArea; } #undef INVALIDRECT } static Boolean clipRectangle(rectp, attrp) register XRectangle *rectp; register XWindowAttributes *attrp; { register int z0, z1, e; z0 = rectp->x; z1 = z0 + rectp->width; e = attrp->width; if (z0 == z1) z1 = e; /* if (rectp->width == 0)... */ if (z0 >= e || z1 <= 0) return False; if (z0 < 0) z0 = 0; if (z1 > e) z1 = e; rectp->x = z0; rectp->width = z1 - z0; z0 = rectp->y; z1 = z0 + rectp->height; e = attrp->height; if (z0 == z1) z1 = e; /* if (rectp->height == 0)... */ if (z0 >= e || z1 <= 0) return False; if (z0 < 0) z0 = 0; if (z1 > e) z1 = e; rectp->y = z0; rectp->height = z1 - z0; return True; } static void GetClientCoordinates(ccw) ConversionControlWidget ccw; { Display *dpy = XtDisplay(ccw); Window root = RootWindowOfScreen(XtScreen(ccw)); Window win = ccw->ccontrol.clientwindow; Window junk; int rootx, rooty; if (!XTranslateCoordinates(dpy, win, root, 0, 0, &rootx, &rooty, &junk)) { WidgetWarning((Widget)ccw, "windowError", "differentRoot", "clientWindow and conversion widget have different root. this should not happen!"); rootx = rooty = 0; } ccw->ccontrol.client_rootx = rootx; ccw->ccontrol.client_rooty = rooty; } /* ARGSUSED */ static void EventToInputObject(w, event, args, num_args) Widget w; XEvent *event; String *args; Cardinal *num_args; { ConversionControlWidget ccw = (ConversionControlWidget)w; Boolean hascallback = False; int r; #ifdef OBSOLETE_FEATURE Boolean sendback = False; #endif if (ccw->ccontrol.inputobj == NULL) return; ccw->ccontrol.endnotify = False; if (ccw->ccontrol.unusedeventcallback != NULL && XtHasCallbacks(w, XtNunusedEventCallback) == XtCallbackHasSome) { hascallback = True; } #ifdef OBSOLETE_FEATURE /* * a cheap little hack -- sending back unused events * * if user set some callback on XtNunusedEventCallback, we call * the callback functions on 'unused' KeyPress events. * * otherwise, if the resource XtNsendbackKeyPress is true, we * attempt to send 'unused' KeyPress events back to the client. * * we call callbacks or send an event back to the client when * following conditions are satisfied: * + it is a KeyPress event AND * + the number of segments is 0 before the conversion object * processes it AND * + the number of segments remains 0 after processing AND * + none of the modeChangeNotify, selectionControl, endNotify and * fixNofity callbacks are called during processing * it is intentional to exclude textChangeNotify callback from * above condition, because this callback is often called even if * the text doesn't change actually. so we use the condition that * the number of segments remains 0 instead. */ if ((hascallback ||ccw->ccontrol.sendbackKeyPress) && event->type == KeyPress && ICNumSegments(ccw->ccontrol.inputobj) == 0) { sendback = True; } ccw->ccontrol.eventused = False; if ((r = ICInputEvent(ccw->ccontrol.inputobj, event)) == 1 || (sendback && !ccw->ccontrol.eventused && ICNumSegments(ccw->ccontrol.inputobj) == 0)) { #else /* * Above feature is obsolete. Now it is the input object's * responsibility to decide whether the event should be * sent back to the client or not. */ if ((r = ICInputEvent(ccw->ccontrol.inputobj, event)) == 1) { #endif /* event isn't used */ if (hascallback) { TRACE(("call XtNunusedEventCallback\n")); XtCallCallbackList(w, ccw->ccontrol.unusedeventcallback, (XtPointer)event); } else if (ccw->ccontrol.sendbackKeyPress) { Window savewin; Window savesubwin; TRACE(("sendback event to window 0x%lx\n", ccw->ccontrol.focuswindow)); savewin = event->xkey.window; savesubwin = event->xkey.subwindow; event->xkey.window = ccw->ccontrol.focuswindow; event->xkey.subwindow = None; /* * here we use NoEventMask as the eventmask, not * KeyPressMask. that means the event will be sent only * to the client who created the destination window. */ XSendEvent(XtDisplay(w), event->xkey.window, False, NoEventMask, event); event->xkey.window = savewin; /* restore */ event->xkey.subwindow = savesubwin; /* restore */ } } if (r < 0 || ccw->ccontrol.endnotify) { CControlEndConversion(w); XtCallCallbackList(w, ccw->ccontrol.endcallback, (XtPointer)False); } } /* * sub-widget creation */ static Widget CreateInputObject(ccw) ConversionControlWidget ccw; { Widget inputobj; Arg args[1]; XtSetArg(args[0], XtNdisplayObjectClass, ccw->ccontrol.displayobjclass); inputobj = XtCreateWidget("inputObj", ccw->ccontrol.inputobjclass, (Widget)ccw, args, 1); ccw->ccontrol.inputobj = inputobj; return inputobj; } static Boolean ClassIsSubClassOf(class, reference) WidgetClass class; WidgetClass reference; { while (class != NULL) { if (class == reference) return True; class = class->core_class.superclass; } return False; } static void CaptureClientDead(ccw) ConversionControlWidget ccw; { Display *dpy = XtDisplay(ccw); Window win = ccw->ccontrol.clientwindow; MyAddEventHandler(dpy, win, DestroyNotify, StructureNotifyMask, ClientDead, (XtPointer)ccw); } static void InterceptClientKeyEvent(ccw) ConversionControlWidget ccw; { Display *dpy = XtDisplay(ccw); Window win = ccw->ccontrol.clientwindow; Window probe; TRACE(("InterceptClientKeyEvent()\n")); probe = XCreateWindow(dpy, win, 0, 0, 9999, 9999, 0, 0, InputOnly, (Visual *)CopyFromParent, 0L, (XSetWindowAttributes *)NULL); TRACE(("\tprobewindow = %lx\n", probe)); MyAddEventHandler(dpy, probe, KeyPress, KeyPressMask, ClientKey, (XtPointer)ccw); MyAddEventHandler(dpy, probe, KeyRelease, KeyReleaseMask, ClientKey, (XtPointer)ccw); ccw->ccontrol.probewindow = probe; XMapWindow(dpy, probe); } static void SelectFocusKeyEvent(ccw) ConversionControlWidget ccw; { Display *dpy = XtDisplay(ccw); Window win = ccw->ccontrol.focuswindow; MyAddEventHandler(dpy, win, KeyPress, KeyPressMask, ClientKey, (XtPointer)ccw); MyAddEventHandler(dpy, win, KeyRelease, KeyReleaseMask, ClientKey, (XtPointer)ccw); } static void UnselectFocusKeyEvent(ccw) ConversionControlWidget ccw; { Display *dpy = XtDisplay(ccw); Window win = ccw->ccontrol.focuswindow; MyRemoveEventHandler(dpy, win, KeyPress, ClientKey, (XtPointer)ccw); MyRemoveEventHandler(dpy, win, KeyRelease, ClientKey, (XtPointer)ccw); } static void ClientKey(ev, data) XEvent *ev; XtPointer data; { Widget w = (Widget)data; Cardinal num_params = 0; EventToInputObject(w, ev, (String *)NULL, &num_params); } static void ClientDead(ev, data) XEvent *ev; XtPointer data; { ConversionControlWidget ccw = (ConversionControlWidget)data; ConversionControlWidgetClass class = (ConversionControlWidgetClass)ccw->core.widget_class; if (ev->type != DestroyNotify || ev->xdestroywindow.window != ccw->ccontrol.clientwindow) return; /* * Client window is destroyed. */ /* remove all event handlers */ MyRemoveAllEventHandler(XtDisplay(ccw), ccw->ccontrol.clientwindow); if (ccw->ccontrol.probewindow != None) { /* no need to destroy probewindow. it's already destroyed. */ MyRemoveAllEventHandler(XtDisplay(ccw), ccw->ccontrol.probewindow); } if (ccw->ccontrol.eventselectmethod == ESMethodSelectFocus && ccw->ccontrol.focuswindow != ccw->ccontrol.clientwindow) { MyRemoveAllEventHandler(XtDisplay(ccw), ccw->ccontrol.focuswindow); } ccw->ccontrol.oldclientwindow = ccw->ccontrol.clientwindow; ccw->ccontrol.clientwindow = None; ccw->ccontrol.focuswindow = None; ccw->ccontrol.probewindow = None; ccw->ccontrol.active = False; XtRemoveCallback(ccw->ccontrol.inputobj, XtNfixNotify, FixCallback, (XtPointer)ccw); XtRemoveCallback(ccw->ccontrol.inputobj, XtNendNotify, ConversionEndCallback, (XtPointer)ccw); XtRemoveCallback(ccw->ccontrol.inputobj, XtNtextChangeNotify, TextChangeCallback, (XtPointer)ccw); XtRemoveCallback(ccw->ccontrol.inputobj, XtNmodeChangeNotify, ModeChangeCallback, (XtPointer)ccw); XtRemoveCallback(ccw->ccontrol.inputobj, XtNselectionControl, SelectionControlCallback, (XtPointer)ccw); XtRemoveCallback(ccw->ccontrol.inputobj, XtNauxControl, AuxControlCallback, (XtPointer)ccw); /* call input style dependent finish */ (*class->conversionControl_class.Finish)((Widget)ccw); /* clear conversion object */ ICClearConversion(ccw->ccontrol.inputobj); ccw->ccontrol.oldclientwindow = None; XtCallCallbackList((Widget)ccw, ccw->ccontrol.endcallback, (XtPointer)True); } /* ARGSUSED */ static void FixCallback(w, client_data, call_data) Widget w; XtPointer client_data; XtPointer call_data; { Widget widget = (Widget)client_data; ConversionControlWidget ccw = (ConversionControlWidget)widget; ConversionControlWidgetClass class = (ConversionControlWidgetClass)widget->core.widget_class; Atom encoding = ccw->ccontrol.textencoding; int format; int length; XtPointer text; CCTextCallbackArg arg; ccw->ccontrol.eventused = True; if (ICGetConvertedString(w, &encoding, &format, &length, &text) < 0) { return; } arg.encoding = encoding; arg.format = format; arg.length = length; arg.text = text; (*class->conversionControl_class.Fix)(widget, &arg); XtFree(text); } /* ARGSUSED */ static void ConversionEndCallback(w, client_data, call_data) Widget w; XtPointer client_data; XtPointer call_data; { ConversionControlWidget ccw = (ConversionControlWidget)client_data; ccw->ccontrol.eventused = True; ccw->ccontrol.endnotify = True; } /* ARGSUSED */ static void TextChangeCallback(w, client_data, call_data) Widget w; XtPointer client_data; XtPointer call_data; { Widget widget = (Widget)client_data; ConversionControlWidget ccw = (ConversionControlWidget)widget; ConversionControlWidgetClass class = (ConversionControlWidgetClass)widget->core.widget_class; int nsegs = ICNumSegments(ccw->ccontrol.inputobj); /* * don't do: * ccw->ccontrol.eventused = True; * because this callback is often called even if * the text didn't change actually. */ /* * when num-segments changed from 0 to 1 (or more), * call new-text calllback */ if (ccw->ccontrol.notext && nsegs > 0) { XtCallCallbackList((Widget)ccw, ccw->ccontrol.newtextcallback, (XtPointer)w); } ccw->ccontrol.notext = nsegs == 0; (*class->conversionControl_class.TextChange)(widget); } /* ARGSUSED */ static void ModeChangeCallback(w, client_data, call_data) Widget w; XtPointer client_data; XtPointer call_data; { Widget widget = (Widget)client_data; ConversionControlWidget ccw = (ConversionControlWidget)widget; ConversionControlWidgetClass class = (ConversionControlWidgetClass)widget->core.widget_class; ccw->ccontrol.eventused = True; (*class->conversionControl_class.ModeChange)(widget); } /* ARGSUSED */ static void SelectionControlCallback(w, client_data, call_data) Widget w; XtPointer client_data; XtPointer call_data; { Widget widget = (Widget)client_data; ConversionControlWidget ccw = (ConversionControlWidget)widget; ConversionControlWidgetClass class = (ConversionControlWidgetClass)widget->core.widget_class; ICSelectionControlArg *arg = (ICSelectionControlArg *)call_data; ccw->ccontrol.eventused = True; (*class->conversionControl_class.SelectionControl)(widget, arg); } /* ARGSUSED */ static void AuxControlCallback(w, client_data, call_data) Widget w; XtPointer client_data; XtPointer call_data; { Widget widget = (Widget)client_data; ConversionControlWidget ccw = (ConversionControlWidget)widget; ConversionControlWidgetClass class = (ConversionControlWidgetClass)widget->core.widget_class; ICAuxControlArg *arg = (ICAuxControlArg *)call_data; ccw->ccontrol.eventused = True; (*class->conversionControl_class.AuxControl)(widget, arg); } static void WidgetError(w, name, type, msg) Widget w; String name; String type; String msg; { char buf[512]; String params[1]; Cardinal num_params; params[0] = XtClass(w)->core_class.class_name; num_params = 1; (void)sprintf(buf, "%%s: %s", msg); XtAppErrorMsg(XtWidgetToApplicationContext(w), name, type, "WidgetError", buf, params, &num_params); } static void WidgetWarning(w, name, type, msg) Widget w; String name; String type; String msg; { char buf[512]; String params[1]; Cardinal num_params; params[0] = XtClass(w)->core_class.class_name; num_params = 1; (void)sprintf(buf, "%%s: %s", msg); XtAppWarningMsg(XtWidgetToApplicationContext(w), name, type, "WidgetError", buf, params, &num_params); }