Mercurial > kinput2.yaz
diff lib/OnConv.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 | e55ccba56891 07a41a882b14 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/OnConv.c Mon Mar 08 04:44:30 2010 +0900 @@ -0,0 +1,1442 @@ +#ifndef lint +static char *rcsid = "$Id: OnConv.c,v 10.9 1999/05/19 08:52:42 ishisone Exp $"; +#endif +/* + * Copyright (c) 1990 Software Research Associates, Inc. + * Copyright (c) 1999 Kazuki YASUMATSU + * + * 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 + * Author: Kazuki YASUMATSU (Kazuki.Yasumatsu@fujixerox.co.jp) + */ + + +#include <X11/IntrinsicP.h> +#include <X11/StringDefs.h> +#include <X11/Xmu/Atoms.h> +#if XtSpecificationRelease > 4 +#include <X11/Xfuncs.h> +#endif +#include "CachedAtom.h" +#include "AsyncErr.h" +#include "OnConvP.h" +#include "InputConv.h" +#include "ConvDisp.h" +#include "CandPanel.h" +#include "AuxPanel.h" +#include "ICLabel.h" + +#define DEBUG_VAR debug_OnTheSpotConversion +#include "DebugPrint.h" + +/*- resource table -*/ +static XtResource resources[] = { +#define offset(field) XtOffset(OnTheSpotConversionWidget, onthespot.field) + { XtNpreeditStartCallback, XtCCallback, XtRCallback, sizeof(XtCallbackList), + offset(preeditstartcallback), XtRCallback, (XtPointer)NULL }, + { XtNpreeditDoneCallback, XtCCallback, XtRCallback, sizeof(XtCallbackList), + offset(preeditdonecallback), XtRCallback, (XtPointer)NULL }, + { XtNpreeditDrawCallback, XtCCallback, XtRCallback, sizeof(XtCallbackList), + offset(preeditdrawcallback), XtRCallback, (XtPointer)NULL }, + { XtNpreeditCaretCallback, XtCCallback, XtRCallback, sizeof(XtCallbackList), + offset(preeditcaretcallback), XtRCallback, (XtPointer)NULL }, + { XtNstatusStartCallback, XtCCallback, XtRCallback, sizeof(XtCallbackList), + offset(statusstartcallback), XtRCallback, (XtPointer)NULL }, + { XtNstatusDoneCallback, XtCCallback, XtRCallback, sizeof(XtCallbackList), + offset(statusdonecallback), XtRCallback, (XtPointer)NULL }, + { XtNstatusDrawCallback, XtCCallback, XtRCallback, sizeof(XtCallbackList), + offset(statusdrawcallback), XtRCallback, (XtPointer)NULL }, + { XtNfeedbackAttributes, XtCFeedbackAttributes, + XtRFeedbackAttributes, sizeof(FeedbackAttributes), + offset(feedbackattrs), XtRString, (XtPointer)"U,,R,H" }, +#undef offset +}; + +/*- default translations -*/ +static char translations[] = "<Key>: to-inputobj()"; /* same as superclass's */ + +/*- declarations of local structures -*/ +typedef struct { + int attrs_length; + int attrs_limit; + unsigned long *attrs_buffer; +} AttributeBuffer; + +/*- declarations of static functions -*/ +static void ClassInitialize(); +static void Initialize(); +static void Destroy(); +static Boolean SetValues(); + +static void ConversionStartup(); +static void ConversionFinish(); +static void ChangeAttributes(); +static void ChangeFocus(); + +static void StringToFeedbackAttrs(); + +static Widget CreateSelectionWidget(); + +static void UpdateText(); +static void CommitText(); +static void UpdateMode(); +static void SelectionControl(); + +static void SelectionStart(); +static void LocateSelectionPopup(); +static void SelectionEnd(); +static void SelectionSet(); +static void SelectionGet(); +static void SelectionMove(); + +static Widget CreateAuxWidget(); +static void AuxControl(); +static void AuxStart(); +static void AuxEnd(); +static void AuxChange(); +static void LocateAuxPopup(); + +static void SelectionSelected(); + +static Boolean SafeGetWindowAttributes(); +static void MoveShell(); +static Window getToplevelWindow(); +static void setTransientFor(); +static void allocDisplaySegments(); +static void freeDisplaySegment(); +static void clearAllDisplaySegments(); +static void copyString(); +static void freeString(); +static AttributeBuffer *allocAttributeBuffer(); +static void destroyAttributeBuffer(); +static void addAttributeBuffer(); +static unsigned long attrToFeedback(); +static void CBPreeditStart(); +static void CBPreeditDone(); +static void CBPreeditDraw(); +static void CBPreeditCaret(); +static void CBStatusStart(); +static void CBStatusDone(); +static void CBStatusDraw(); + +/*- composite-extension rec: for enabling non-widget children -*/ +static CompositeClassExtensionRec CompositeExtension = { + /* next_extension */ NULL, + /* record_type */ NULLQUARK, + /* version */ XtCompositeExtensionVersion, + /* record_size */ sizeof(CompositeClassExtensionRec), + /* accept_objects */ True, +}; + +/*- onTheSpotConversionClass record -*/ +OnTheSpotConversionClassRec onTheSpotConversionClassRec = { + { /* core fields */ + /* superclass */ (WidgetClass)&conversionControlClassRec, + /* class_name */ "OnTheSpotConversion", + /* widget_size */ sizeof(OnTheSpotConversionRec), + /* class_initialize */ ClassInitialize, + /* class_part_initialize */ NULL, + /* class_inited */ FALSE, + /* initialize */ Initialize, + /* initialize_hook */ NULL, + /* realize */ XtInheritRealize, + /* actions */ NULL, + /* num_actions */ 0, + /* resources */ resources, + /* num_resources */ XtNumber(resources), + /* xrm_class */ NULLQUARK, + /* compress_motion */ TRUE, + /* compress_exposure */ TRUE, + /* compress_enterleave */ TRUE, + /* visible_interest */ FALSE, + /* destroy */ Destroy, + /* resize */ XtInheritResize, + /* 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 */ UpdateText, + /* Fix */ CommitText, + /* ModeChange */ UpdateMode, + /* SelectionControl */ SelectionControl, + /* AuxControl */ AuxControl, + }, + { /* onTheSpotConversion fields */ + /* empty */ 0 + }, +}; + +WidgetClass onTheSpotConversionWidgetClass = (WidgetClass)&onTheSpotConversionClassRec; + +/* + *+ Core class method + */ + +/*- ClassInitialize: class initializer -*/ +/* ARGSUSED */ +static void +ClassInitialize() +{ + /* add String -> FeedbackAttributes converter */ + XtAddConverter(XtRString, XtRFeedbackAttributes, StringToFeedbackAttrs, + (XtConvertArgList)NULL, (Cardinal)0); +} + +/*- Initialize: initalize method -*/ +/* ARGSUSED */ +static void +Initialize(req, new, args, num_args) +Widget req; +Widget new; +ArgList args; +Cardinal *num_args; +{ + OnTheSpotConversionWidget ocw = (OnTheSpotConversionWidget)new; + + (void)CreateSelectionWidget(ocw); + (void)CreateAuxWidget(ocw); + + ocw->onthespot.dispsegments = NULL; + ocw->onthespot.numsegments = 0; + ocw->onthespot.dispsegmentsize = 0; + ocw->onthespot.candlist = NULL; + ocw->onthespot.numcands = 0; + ocw->onthespot.selectionpoppedup = False; + ocw->onthespot.auxpoppedup = False; + ocw->onthespot.lastcaret = 0; + ocw->onthespot.fixnotify = False; +} + +/*- Destroy: destroy method -*/ +static void +Destroy(w) +Widget w; +{ + OnTheSpotConversionWidget ocw = (OnTheSpotConversionWidget)w; + + /* $B%G%#%9%W%l%$%;%0%a%s%H$NNN0h$r2rJ|(B */ + if (ocw->onthespot.dispsegments) { + DisplaySegment *dsp = ocw->onthespot.dispsegments; + int i; + + for (i = 0; i < ocw->onthespot.numsegments; i++) { + freeString(&dsp[i].seg); + } + XtFree((char *)dsp); + } +} + +/*- SetValues: setvalues method -*/ +/* ARGSUSED */ +static Boolean +SetValues(cur, req, new, args, num_args) +Widget cur; +Widget req; +Widget new; +ArgList args; +Cardinal *num_args; +{ + /* OnTheSpotConversionWidget ocw = (OnTheSpotConversionWidget)new; */ + return False; +} + +/* + *+ ConversionControl class method + */ + +/*- ConversionStartup: class specific conversion startup -*/ +static void +ConversionStartup(widget, valuemask, value) +Widget widget; +unsigned long valuemask; +ConversionAttributes *value; +{ + OnTheSpotConversionWidget ocw = (OnTheSpotConversionWidget)widget; + Widget inputobj = ocw->ccontrol.inputobj; + Window toplevel; + + TRACE(("OnTheSpot:ConversionStartup()\n")); + + /* $BFbIt$N%P%C%U%!$r%/%j%"$9$k(B */ + clearAllDisplaySegments(ocw); + + /* WM_TRANSIENT_FOR $B%W%m%Q%F%#$r@5$7$/%;%C%H$9$k(B */ + toplevel = getToplevelWindow(XtDisplay(widget), + ocw->ccontrol.clientwindow); + setTransientFor(ocw->onthespot.selectionshell, toplevel); + setTransientFor(ocw->onthespot.auxshell, toplevel); + + /* + * OnTheSpotConvesion $B$N(B widget $B<+BN$O%]%C%W%"%C%W$5$;$J$$$,!"(B + * $B%P%C%/%(%s%I%?%$%W$N;~$K$O%/%i%$%"%s%H$,$3$N(B widget $B$N(B + * $B%&%#%s%I%&$KBP$7$F%$%Y%s%H$rAw$k$N$G(B Realize $B$@$1$7$F$*$/(B + */ + if (!XtIsRealized(widget)) { + Arg args[2]; + + XtSetArg(args[0], XtNwidth, 1); + XtSetArg(args[1], XtNheight, 1); + XtSetValues(widget, args, 2); + XtRealizeWidget(widget); + } + + ocw->onthespot.lastcaret = 0; + ocw->onthespot.fixnotify = False; + + /* $B%9%F!<%?%9$r99?7$9$k(B */ + UpdateMode(widget); + + /* $B%W%l%(%G%#%C%H$r3+;O$9$k(B */ + CBPreeditStart(widget); +} + +/*- ConversionFinish: class specific conversion finish -*/ +/* ARGSUSED */ +static void +ConversionFinish(w) +Widget w; +{ + OnTheSpotConversionWidget ocw = (OnTheSpotConversionWidget)w; + Atom encoding = XA_COMPOUND_TEXT(XtDisplayOfObject(w)); + int format = 8; + + if (!ocw->onthespot.fixnotify) { + /* $B3NDj$7$F$$$J$$(B */ + DisplaySegment *dseg = ocw->onthespot.dispsegments; + int i, len = 0; + for (i = 0; i < ocw->onthespot.numsegments; i++, dseg++) { + len += dseg->seg.nchars; + } + if (len > 0) { + /* $B%W%l%(%G%#%C%H%P%C%U%!$N>C5n(B */ + unsigned long attr = 0; + CBPreeditDraw(ocw, 0, 0, len, encoding, format, 0, (XPointer)"", + 0, &attr); + } + } + + /* $B%W%l%(%G%#%C%H$r=*N;$9$k(B */ + CBPreeditDone(w); + + /* $B%9%F!<%?%9$r99?7(B($B=i4|2=(B)$B$9$k(B */ + CBStatusDraw(ocw, encoding, format, 0, (XPointer)"", 0); + + if (ocw->onthespot.selectionpoppedup) { + XtPopdown(ocw->onthespot.selectionshell); + ocw->onthespot.selectionpoppedup = False; + } + if (ocw->onthespot.auxpoppedup) { + XtPopdown(ocw->onthespot.auxshell); + ocw->onthespot.auxpoppedup = False; + } +} + +/*- ChangeAttributes: class specific conversion attribute change routine -*/ +/* ARGSUSED */ +static void +ChangeAttributes(w, valuemask, value) +Widget w; +unsigned long valuemask; +ConversionAttributes *value; +{ + /* do nothing */ +} + +/*- ChangeFocus: class specific conversion attribute change routine -*/ +static void +ChangeFocus(w, set) +Widget w; +int set; +{ + if (set) { + UpdateMode(w); + } else { +#if 0 + /* $B%U%)!<%+%9$r<:$C$?>l9g$K$O2?$b$7$J$$(B */ + OnTheSpotConversionWidget ocw = (OnTheSpotConversionWidget)w; + Atom encoding = XA_COMPOUND_TEXT(XtDisplayOfObject(w)); + int format = 8; + + CBStatusDraw(ocw, encoding, format, 0, (XPointer)"", 0); +#endif + } +} + +/* + *+ resource converter + */ + +/*- StringToFeedbackAttrs: string to feedback attiributes converter -*/ +static void +StringToFeedbackAttrs(args, num_args, from, to) +XrmValue *args; +Cardinal *num_args; +XrmValue *from; +XrmValue *to; +{ + char *s = (char *)from->addr; + int idx; + int invalid = 0; + static FeedbackAttributes fba; + + for (idx = 0; idx < 4; idx++) fba.feedbacks[idx] = 0; + + for (idx = 0; idx < 4; idx++) { + int c; + unsigned long fb = 0; + + while ((c = *s++) != ',' && c != '\0') { + switch (c) { + case 'R': case 'r': fb |= XIMReverse; break; + case 'U': case 'u': fb |= XIMUnderline; break; + case 'H': case 'h': fb |= XIMHighlight; break; + case 'P': case 'p': fb |= XIMPrimary; break; + case 'S': case 's': fb |= XIMSecondary; break; + case 'T': case 't': fb |= XIMTertiary; break; + case ' ': case '\t': + break; + default: + invalid++; + break; + } + } + fba.feedbacks[idx] = fb; + if (c == '\0') break; + } + + if (invalid) { + XtStringConversionWarning((char *)from->addr, XtRFeedbackAttributes); + } + to->size = sizeof(fba); + to->addr = (caddr_t)&fba; +} + +/* + *+ sub-widget creation + */ + +/*- CreateSelectionWidget: create selection widget for selecting candidates -*/ +static Widget +CreateSelectionWidget(ocw) +OnTheSpotConversionWidget ocw; +{ + Widget shell, sel; + + /* set width/height so that XtRealizeWidget() doesn't cause error */ + shell = XtVaCreatePopupShell("selectionShell", + transientShellWidgetClass, + (Widget)ocw, + XtNwidth, 1, + XtNheight, 1, + NULL); + ocw->onthespot.selectionshell = shell; + + sel = XtCreateManagedWidget("selection", candidatePanelWidgetClass, + shell, NULL, 0); + (void)XtCreateWidget("display", ocw->ccontrol.displayobjclass, sel, + NULL, 0); + XtAddCallback(sel, XtNcallback, SelectionSelected, (XtPointer)ocw); + XtInstallAccelerators(sel, (Widget)ocw); + + ocw->onthespot.selectionwidget = sel; + + return shell; +} + +/*- CreateAuxWidget: create aux widget for display auxiliary data -*/ +static Widget +CreateAuxWidget(ocw) +OnTheSpotConversionWidget ocw; +{ + Widget shell, sel; + + /* set width/height so that XtRealizeWidget() doesn't cause error */ + shell = XtVaCreatePopupShell("auxShell", + transientShellWidgetClass, + (Widget)ocw, + XtNwidth, 1, + XtNheight, 1, + XtNallowShellResize, True, + NULL); + ocw->onthespot.auxshell = shell; + + sel = XtCreateManagedWidget("aux", auxPanelWidgetClass, + shell, NULL, 0); + (void)XtCreateWidget("display", ocw->ccontrol.displayobjclass, sel, + NULL, 0); + XtAddCallback(sel, XtNcallback, SelectionSelected, (XtPointer)ocw); + XtInstallAccelerators(sel, (Widget)ocw); + + ocw->onthespot.auxwidget = sel; + + return shell; +} + +/* + *+ inputobject callback + */ + +/*- UpdateText: update text -*/ +static void +UpdateText(w) +Widget w; +{ + OnTheSpotConversionWidget ocw = (OnTheSpotConversionWidget)w; + Widget inputobj = ocw->ccontrol.inputobj; + int nnew = ICNumSegments(inputobj); + int nold = ocw->onthespot.numsegments; + FeedbackAttributes *fba = &ocw->onthespot.feedbackattrs; + Cardinal cseg, caret; + ICString *newseg; + DisplaySegment *dseg; + Boolean changed; + int chgseg, chgoffset; + int oldlen; + AttributeBuffer *buffer; + int i; + int diff; + Cardinal nsame; + + TRACE(("OnTheSpotConversion:UpdateText() nnew=%d\n", nnew)); + + ocw->onthespot.fixnotify = False; + + if (!ICCursorPos(inputobj, &cseg, &caret)) { + cseg = nnew; + caret = 0; + } + + allocDisplaySegments(ocw, nnew); + + changed = False; + chgseg = chgoffset = 0; + oldlen = 0; + buffer = allocAttributeBuffer(); + for (i = 0, dseg = ocw->onthespot.dispsegments; i < nnew; i++, dseg++) { + newseg = ICGetSegment(inputobj, i); + if (i < cseg) { + caret += newseg->nchars; + } + if (i >= nold) { + copyString(newseg, &dseg->seg); + addAttributeBuffer(buffer, inputobj, newseg, 0, fba); + if (!changed) { + chgseg = i; + chgoffset = 0; + changed = True; + } + } else { + oldlen += dseg->seg.nchars; + diff = ICCompareSegment(inputobj, newseg, &dseg->seg, &nsame); + switch (diff) { + case ICSame: + if (changed) { + addAttributeBuffer(buffer, inputobj, newseg, 0, fba); + } + break; + case ICAttrChanged: + dseg->seg.attr = newseg->attr; + addAttributeBuffer(buffer, inputobj, newseg, 0, fba); + if (!changed) { + chgseg = i; + chgoffset = 0; + changed = True; + } + break; + case ICStringChanged: + freeString(&dseg->seg); + copyString(newseg, &dseg->seg); + if (!changed) { + addAttributeBuffer(buffer, inputobj, newseg, nsame, fba); + chgseg = i; + chgoffset = nsame; + changed = True; + } + else { + addAttributeBuffer(buffer, inputobj, newseg, 0, fba); + } + break; + default: /* ICAttrChanged | ICStringChanged */ + freeString(&dseg->seg); + copyString(newseg, &dseg->seg); + addAttributeBuffer(buffer, inputobj, newseg, 0, fba); + if (!changed) { + chgseg = i; + chgoffset = 0; + changed = True; + } + break; + } + } + } + + for (; i < nold; i++, dseg++) { + oldlen += dseg->seg.nchars; + if (!changed) { + chgseg = i; + chgoffset = 0; + changed = True; + } + freeDisplaySegment(dseg); + } + + ocw->onthespot.numsegments = nnew; + + if (!changed) { + if (ocw->onthespot.lastcaret != caret) { + CBPreeditCaret(ocw, caret); + } + } + else { /* changed */ + Atom encoding = ocw->ccontrol.textencoding; + int format; + int length; + XtPointer string; + + if (ICGetPreeditString(inputobj, chgseg, chgoffset, &encoding, &format, + &length, &string) == 0) { + + dseg = ocw->onthespot.dispsegments; + for (i = 0; i < chgseg; i++, dseg++) { + chgoffset += dseg->seg.nchars; + } + CBPreeditDraw(ocw, caret, chgoffset, oldlen - chgoffset, + encoding, format, length, string, + buffer->attrs_length, buffer->attrs_buffer); + + /* string $B$r(B free $B$7$F$*$/(B */ + XtFree((char *)string); + } + } + + ocw->onthespot.lastcaret = caret; + + /* buffer $B$r(B destroy $B$7$F$*$/(B */ + destroyAttributeBuffer(buffer); +} + +/*- CommitText: commit text -*/ +static void +CommitText(w, arg) +Widget w; +CCTextCallbackArg *arg; +{ + OnTheSpotConversionWidget ocw = (OnTheSpotConversionWidget)w; + DisplaySegment *dseg; + int i, len; + + dseg = ocw->onthespot.dispsegments; + len = 0; + for (i = 0; i < ocw->onthespot.numsegments; i++, dseg++) { + len += dseg->seg.nchars; + } + if (len > 0) { + /* $B%W%l%(%G%#%C%H%P%C%U%!$N>C5n(B */ + Atom encoding = XA_COMPOUND_TEXT(XtDisplayOfObject(w)); + int format = 8; + unsigned long attr = 0; + CBPreeditDraw(ocw, 0, 0, len, encoding, format, 0, (XPointer)"", + 0, &attr); + } + /* $BFbIt$N%P%C%U%!$r%/%j%"$9$k(B */ + clearAllDisplaySegments(ocw); + ocw->onthespot.lastcaret = 0; + + XtCallCallbackList((Widget)ocw, ocw->ccontrol.textcallback, + (XtPointer)arg); + + ocw->onthespot.fixnotify = True; +} + +/*- UpdateMode: update mode -*/ +static void +UpdateMode(w) +Widget w; +{ + OnTheSpotConversionWidget ocw = (OnTheSpotConversionWidget)w; + Widget inputobj = ocw->ccontrol.inputobj; + Atom encoding = ocw->ccontrol.textencoding; + int format; + int length; + XtPointer string; + int nchars; + + TRACE(("OnTheSpotConversion:UpdateMode()\n")); + + if (ICGetStatusString(inputobj, &encoding, &format, &length, &string, + &nchars) == -1) + return; + + CBStatusDraw(ocw, encoding, format, length, string, nchars); + + /* string $B$r(B free $B$7$F$*$/(B */ + XtFree((char *)string); +} + +/*- SelectionControl: selection control -*/ +static void +SelectionControl(w, arg) +Widget w; +ICSelectionControlArg *arg; +{ + OnTheSpotConversionWidget ocw = (OnTheSpotConversionWidget)w; + String params[1]; + Cardinal num_params; + + switch (arg->command) { + case ICSelectionStart: + SelectionStart(ocw, arg->u.selection_kind); + break; + case ICSelectionEnd: + SelectionEnd(ocw, &arg->u.current_item); + break; + case ICSelectionSet: + SelectionSet(ocw, arg->u.current_item); + break; + case ICSelectionMove: + SelectionMove(ocw, arg->u.dir); + break; + case ICSelectionGet: + SelectionGet(ocw, &arg->u.current_item); + break; + default: + params[0] = XtClass(w)->core_class.class_name; + num_params = 1; + XtAppWarningMsg(XtWidgetToApplicationContext(w), + "parameterError", "SelectionControl", "WidgetError", + "%s: unknown selection control command", + params, &num_params); + break; + } +} + +/*- SelectionStart: selection startup -*/ +/* ARGSUSED */ +static void +SelectionStart(ocw, kind) +OnTheSpotConversionWidget ocw; +int kind; +{ + Cardinal ncand; + + TRACE(("OnTheSpotConversion:SelectionStart()\n")); + if (ocw->onthespot.selectionpoppedup) { + TRACE(("\tselection already started -- ignored\n")); + return; + } + + ocw->onthespot.candlist = ICGetItemList(ocw->ccontrol.inputobj, &ncand); + ocw->onthespot.numcands = ncand; + + TRACE(("\tnumcands=%d\n", ocw->onthespot.numcands)); + CPanelSetList(ocw->onthespot.selectionwidget, + ocw->onthespot.candlist, + ocw->onthespot.numcands, 0, True); + + LocateSelectionPopup(ocw); + XtPopup(ocw->onthespot.selectionshell, XtGrabNone); + ocw->onthespot.selectionpoppedup = True; +} + +/*- LocateSelectionPopup: put selection popup at an appropriate position -*/ +static void +LocateSelectionPopup(ocw) +OnTheSpotConversionWidget ocw; +{ + Position x, y; + int clx, cly; + Dimension dpyWidth, dpyHeight; + Widget panel = ocw->onthespot.selectionwidget; + Widget shell = ocw->onthespot.selectionshell; + Window junk; + int barheight = ocw->ccontrol.titlebarheight; + + (void)XTranslateCoordinates(XtDisplay(ocw), + ocw->ccontrol.clientwindow, + RootWindowOfScreen(XtScreen(ocw)), + 0, 0, &clx, &cly, &junk); + + (void)SafeGetWindowAttributes(XtDisplay(ocw), ocw->ccontrol.clientwindow, + &(ocw->ccontrol.client_attr)); + + x = clx; + y = cly + ocw->ccontrol.client_attr.height; + + dpyWidth = WidthOfScreen(XtScreen(shell)); + dpyHeight = HeightOfScreen(XtScreen(shell)); + + if (x + panel->core.width > (int)dpyWidth) x = dpyWidth - panel->core.width; + if (x < 0) x = 0; +#if 0 + if (y + panel->core.height + barheight > (int)dpyHeight) { + y = cly - panel->core.height - 8 - barheight - 20; /* XXX */ + if (y < 0) y = dpyHeight - panel->core.height - barheight; + } +#endif + if (y + panel->core.height + barheight > (int)dpyHeight) + y = dpyHeight - panel->core.height - 8 - barheight - 20; /* XXX */ + if (y < 0) y = 0; + MoveShell(shell, x, y); +} + +/*- SelectionEnd: selection finish -*/ +static void +SelectionEnd(ocw, current) +OnTheSpotConversionWidget ocw; +int *current; +{ + TRACE(("OnTheSpotConversion:SelectionEnd()\n")); + + if (!ocw->onthespot.selectionpoppedup) { /* for safe */ + TRACE(("\tnot in selection mode -- ignored\n")); + return; + } + + XtVaGetValues(ocw->onthespot.selectionwidget, + XtNcurrentItem, current, + NULL); + + XtPopdown(ocw->onthespot.selectionshell); + + ocw->onthespot.selectionpoppedup = False; +} + +/*- SelectionSet: set current selection item -*/ +static void +SelectionSet(ocw, current) +OnTheSpotConversionWidget ocw; +int current; +{ + TRACE(("OnTheSpotConversion:SelectionSet()\n")); + + if (!ocw->onthespot.selectionpoppedup) { /* for safe */ + TRACE(("\tnot in selection mode -- ignored\n")); + return; + } + + XtVaSetValues(ocw->onthespot.selectionwidget, + XtNcurrentItem, current, + NULL); +} + +/*- SelectionGet: get current selection item -*/ +static void +SelectionGet(ocw, current) +OnTheSpotConversionWidget ocw; +int *current; +{ + TRACE(("OnTheSpotConversion:SelectionGet()\n")); + + if (!ocw->onthespot.selectionpoppedup) { /* for safe */ + TRACE(("\tnot in selection mode -- ignored\n")); + return; + } + + XtVaGetValues(ocw->onthespot.selectionwidget, + XtNcurrentItem, current, + NULL); +} + +/*- SelectionMove: move crrent selection to specified direction -*/ +static void +SelectionMove(ocw, dir) +OnTheSpotConversionWidget ocw; +int dir; +{ + TRACE(("OnTheSpotConversion:SelectionMove()\n")); + + if (!ocw->onthespot.selectionpoppedup) { /* for safe */ + TRACE(("\tnot in selection mode -- ignored\n")); + return; + } + + CPanelMoveCurrent(ocw->onthespot.selectionwidget, dir); +} + +/* + * Aux Callback + */ + +static void +AuxControl(w, arg) +Widget w; +ICAuxControlArg *arg; +{ + OnTheSpotConversionWidget ocw = (OnTheSpotConversionWidget)w; + String params[1]; + Cardinal num_params; + + switch (arg->command) { + case ICAuxStart: + AuxStart(ocw); + break; + case ICAuxEnd: + AuxEnd(ocw); + break; + case ICAuxChange: + AuxChange(ocw); + break; + default: + params[0] = XtClass(w)->core_class.class_name; + num_params = 1; + XtAppWarningMsg(XtWidgetToApplicationContext(w), + "parameterError", "AuxControl", "WidgetError", + "%s: unknown aux control command", + params, &num_params); + break; + } +} + +/* ARGSUSED */ +static void +AuxStart(ocw) +OnTheSpotConversionWidget ocw; +{ + ICString *auxstr; + Cardinal ncand, curseg, cursorpos; + + if (ocw->onthespot.auxpoppedup) return; + + /* $B%F%-%9%H%3!<%k%P%C%/$N;~$N$h$&$J=hM}$r$9$k(B + $B$N$O(B AuxPanel.c $B$K$^$+$;$h$&(B */ + + auxstr = ICGetAuxSegments(ocw->ccontrol.inputobj, + &ncand, &curseg, &cursorpos); + + APanelStart(ocw->onthespot.auxwidget, auxstr, ncand, curseg, cursorpos); + + /* $B%]%C%W%"%C%W$9$k>l=j$r7h$a$k(B */ + LocateAuxPopup(ocw); + + XtPopup(ocw->onthespot.auxshell, XtGrabNone); + ocw->onthespot.auxpoppedup = True; +} + +/* ARGSUSED */ +static void +AuxEnd(ocw) +OnTheSpotConversionWidget ocw; +{ + if (!ocw->onthespot.auxpoppedup) return; /* for safe */ + +/* APanelEnd(ocw->onthespot.auxwidget); */ + + XtPopdown(ocw->onthespot.auxshell); + + ocw->onthespot.auxpoppedup = False; +} + +/* ARGSUSED */ +static void +AuxChange(ocw) +OnTheSpotConversionWidget ocw; +{ + Cardinal ncand, curseg, cursorpos; + ICString *auxstr; + + if (!ocw->onthespot.auxpoppedup) return; /* for safe */ + + auxstr = ICGetAuxSegments(ocw->ccontrol.inputobj, + &ncand, &curseg, &cursorpos); + + APanelChange(ocw->onthespot.auxwidget, auxstr, ncand, curseg, cursorpos); +} + +/*- LocateAuxPopup: put aux popup at an appropriate position -*/ +static void +LocateAuxPopup(ocw) +OnTheSpotConversionWidget ocw; +{ + Position x, y; + int clx, cly; + Dimension dpyWidth, dpyHeight; + Widget panel = ocw->onthespot.auxwidget; + Widget shell = ocw->onthespot.auxshell; + Window junk; + int barheight = ocw->ccontrol.titlebarheight; + + (void)XTranslateCoordinates(XtDisplay(ocw), + ocw->ccontrol.clientwindow, + RootWindowOfScreen(XtScreen(ocw)), + 0, 0, &clx, &cly, &junk); + + (void)SafeGetWindowAttributes(XtDisplay(ocw), ocw->ccontrol.clientwindow, + &(ocw->ccontrol.client_attr)); + + x = clx; + y = cly + ocw->ccontrol.client_attr.height; + + dpyWidth = WidthOfScreen(XtScreen(shell)); + dpyHeight = HeightOfScreen(XtScreen(shell)); + + if (x + panel->core.width > (int)dpyWidth) x = dpyWidth - panel->core.width; + if (x < 0) x = 0; +#if 0 + if (y + panel->core.height + barheight > (int)dpyHeight) { + y = cly - panel->core.height - 8 - barheight - 20; /* XXX */ + if (y < 0) y = dpyHeight - panel->core.height - barheight; + } +#endif + if (y + panel->core.height + barheight > (int)dpyHeight) + y = dpyHeight - panel->core.height - 8 - barheight - 20; /* XXX */ + if (y < 0) y = 0; + MoveShell(shell, x, y); +} + +/* + *+ Selection Widget callback + */ + +/*- SelectionSelected: selection selected callback -*/ +/* ARGSUSED */ +static void +SelectionSelected(w, client_data, call_data) +Widget w; +XtPointer client_data; +XtPointer call_data; +{ + OnTheSpotConversionWidget ocw = (OnTheSpotConversionWidget)client_data; + int current = (int)call_data; + + TRACE(("OnTheSpotConversion:SelectionSelected()\n")); + XtPopdown(ocw->onthespot.selectionshell); + ocw->onthespot.selectionpoppedup = False; + ICSelectItem(ocw->ccontrol.inputobj, current); +} + +/* + *+ miscelaneous functions + */ + +/*- SafeGetWindowAttributes: get window attributes -*/ +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); +} + +/*- MoveShell: move shell widget -*/ +static void +MoveShell(w, x, y) +Widget w; +Position x; +Position y; +{ + XtWidgetGeometry req; + + /* + * calling XtMoveWidget() is NOT enough to move shell widgets. + * we must use XtMakeGeometryRequest() or XtSetValues() to + * invoke root-geometry-manager which modifies the size hint + * appropriately. + */ + req.request_mode = CWX | CWY; + req.x = x; + req.y = y; + (void)XtMakeGeometryRequest(w, &req, (XtWidgetGeometry *)NULL); +} + +/*- getToplevelWindow: get top-level window of a given window -*/ +static Window +getToplevelWindow(dpy, win) +Display *dpy; +Window win; +{ + Atom wm_state; + Atom type; + int format; + unsigned long nitems, bytesafter; + unsigned char *data; + Window root, parent; + Window *children; + unsigned int nchildren; + + /* + * find toplevel window which has WM_STATE property or if no exists, + * direct subwindow of the root window. (ie I assume that if a + * window manager is running, that is a ICCCM compliant one) + */ + wm_state = CachedInternAtom(dpy, "WM_STATE", True); + for (;;) { + type = None; + if (wm_state != None) { + data = NULL; + XGetWindowProperty(dpy, win, wm_state, 0L, 0L, False, + AnyPropertyType, &type, &format, + &nitems, &bytesafter, &data); + if (data != NULL) XtFree((char *)data); + if (type != None) break; + } + if (!XQueryTree(dpy, win, &root, &parent, &children, &nchildren)) break; + if (nchildren > 0) XtFree((char *)children); + if (root == parent) break; + win = parent; + } + return win; +} + +/*- setTransientFor: set WM_TRANSIENT_FOR property to specified widget -*/ +static void +setTransientFor(w, win) +Widget w; +Window win; +{ + if (!XtIsRealized(w)) XtRealizeWidget(w); + XSetTransientForHint(XtDisplay(w), XtWindow(w), win); +} + +/*- allocDisplaySegments: prepare specified number of display segments -*/ +static void +allocDisplaySegments(ocw, n) +OnTheSpotConversionWidget ocw; +Cardinal n; +{ + if (ocw->onthespot.dispsegmentsize > n) return; + n = ((n + 3) / 4) * 4 ; + if (ocw->onthespot.dispsegments == NULL) { + ocw->onthespot.dispsegments = (DisplaySegment *)XtMalloc(n * sizeof(DisplaySegment)); + } else { + ocw->onthespot.dispsegments = (DisplaySegment *)XtRealloc((char *)ocw->onthespot.dispsegments, n * sizeof(DisplaySegment)); + } + ocw->onthespot.dispsegmentsize = n; +} + +/*- freeDisplaySegment: free display segment's contents -*/ +static void +freeDisplaySegment(dsp) +DisplaySegment *dsp; +{ + freeString(&dsp->seg); +} + +/*- clearAllDisplaySegments: clear all display segment's -*/ +static void +clearAllDisplaySegments(ocw) +OnTheSpotConversionWidget ocw; +{ + DisplaySegment *dsp = ocw->onthespot.dispsegments; + int i; + + for (i = 0; i < ocw->onthespot.numsegments; i++) { + freeDisplaySegment(dsp++); + } + ocw->onthespot.numsegments = 0; +} + +/*- copyString: copy ICString -*/ +static void +copyString(from, to) +ICString *from; +ICString *to; +{ + *to = *from; + to->data = XtMalloc(to->nbytes); + (void)bcopy(from->data, to->data, to->nbytes); +} + +/*- freeString: free ICString -*/ +static void +freeString(seg) +ICString *seg; +{ + XtFree(seg->data); + seg->data = NULL; + seg->nbytes = 0; +} + +/*- allocAttributeBuffer: allocate attribute buffer -*/ +static AttributeBuffer * +allocAttributeBuffer() +{ + AttributeBuffer *buffer; + + buffer = (AttributeBuffer *)XtMalloc(sizeof(AttributeBuffer)); + buffer->attrs_length = 0; + buffer->attrs_limit = 64; + buffer->attrs_buffer = (unsigned long *)XtMalloc(buffer->attrs_limit * sizeof(unsigned long)); + return buffer; +} + +/*- destroyAttributeBuffer: destroy draw string buffer's contents -*/ +static void +destroyAttributeBuffer(buffer) +AttributeBuffer *buffer; +{ + XtFree((char *)buffer->attrs_buffer); + XtFree((char *)buffer); +} + +/*- addAttributeBuffer: add segment to draw string buffer's contents -*/ +static void +addAttributeBuffer(buffer, inputobj, seg, offset, fba) +AttributeBuffer *buffer; +Widget inputobj; +ICString *seg; +int offset; +FeedbackAttributes *fba; +{ + int nchars = seg->nchars - offset; + unsigned long fb; + int i; + + if (buffer->attrs_length + nchars > buffer->attrs_limit) { + unsigned long *new_attrs_buffer; + int new_limit = buffer->attrs_limit * 2; + if (new_limit < buffer->attrs_length + nchars) + new_limit = buffer->attrs_length + nchars + 8; + new_attrs_buffer = (unsigned long *)XtMalloc(new_limit * sizeof(unsigned long)); + bcopy(buffer->attrs_buffer, new_attrs_buffer, + buffer->attrs_length * sizeof(unsigned long)); + XtFree((char *)buffer->attrs_buffer); + buffer->attrs_limit = new_limit; + buffer->attrs_buffer = new_attrs_buffer; + } + fb = attrToFeedback(fba, seg->attr); + for (i = 0; i < nchars; i++) { + buffer->attrs_buffer[buffer->attrs_length + i] = fb; + } + buffer->attrs_length += nchars; +} + +/*- attrToFeedback: ICString attribute -> XIMFeedback attribute converter -*/ +static unsigned long +attrToFeedback(fba, attr) +FeedbackAttributes *fba; +int attr; +{ + int idx; + + if (attr == ICAttrNormalString) return 0; + + if (!(attr & ICAttrConverted)) { + /* Not yet converted */ + idx = FEEDBACK_NOCONV; + } else if (attr & ICAttrCurrentSegment) { + /* it's converted and the current segment */ + idx = FEEDBACK_CURRENT; + } else if (attr & ICAttrCurrentSubSegment) { + /* it's converted and the current sub segment */ + idx = FEEDBACK_CURRENTSUB; + } else { + /* converted, not current */ + idx = FEEDBACK_CONV; + } + return fba->feedbacks[idx]; +} + +/*- CBPreeditStart: callback preedit start -*/ +static void +CBPreeditStart(ocw) +OnTheSpotConversionWidget ocw; +{ + if (ocw->onthespot.preeditstartcallback == NULL || + XtHasCallbacks((Widget)ocw, XtNpreeditStartCallback) != XtCallbackHasSome) + { + /* no callback */ + return; + } + + TRACE(("OnTheSpot:CBPreeditStart()\n")); + + XtCallCallbackList((Widget)ocw, ocw->onthespot.preeditstartcallback, + (XtPointer)NULL); +} + +/*- CBPreeditDone: callback preedit done -*/ +static void +CBPreeditDone(ocw) +OnTheSpotConversionWidget ocw; +{ + if (ocw->onthespot.preeditdonecallback == NULL || + XtHasCallbacks((Widget)ocw, XtNpreeditDoneCallback) != XtCallbackHasSome) + { + /* no callback */ + return; + } + + TRACE(("OnTheSpot:CBPreeditDone()\n")); + + XtCallCallbackList((Widget)ocw, ocw->onthespot.preeditdonecallback, + (XtPointer)NULL); +} + +/*- CBPreeditDraw: callback preedit draw -*/ +static void +CBPreeditDraw(ocw, caret, chg_first, chg_length, encoding, format, text_length, text, attrs_length, attrs) +OnTheSpotConversionWidget ocw; +int caret; +int chg_first; +int chg_length; +Atom encoding; +int format; +int text_length; +XtPointer text; +int attrs_length; +unsigned long *attrs; +{ + OCCPreeditDrawArg arg; + + if (ocw->onthespot.preeditdrawcallback == NULL || + XtHasCallbacks((Widget)ocw, XtNpreeditDrawCallback) != XtCallbackHasSome) + { + /* no callback */ + return; + } + + TRACE(("OnTheSpot:CBPreeditDraw()\n")); + + arg.caret = caret; + arg.chg_first = chg_first; + arg.chg_length = chg_length; + arg.encoding = encoding; + arg.format = format; + arg.text_length = text_length; + arg.text = text; + arg.attrs_length = attrs_length; + arg.attrs = attrs; + XtCallCallbackList((Widget)ocw, ocw->onthespot.preeditdrawcallback, + (XtPointer)&arg); +} + +/*- CBPreeditCaret: callback preedit caret -*/ +static void +CBPreeditCaret(ocw, caret) +OnTheSpotConversionWidget ocw; +int caret; +{ + if (ocw->onthespot.preeditcaretcallback == NULL || + XtHasCallbacks((Widget)ocw, XtNpreeditCaretCallback) != XtCallbackHasSome) + { + /* no callback */ + return; + } + + TRACE(("OnTheSpot:CBPreeditCaret()\n")); + + XtCallCallbackList((Widget)ocw, ocw->onthespot.preeditcaretcallback, + (XtPointer)caret); +} + +/*- CBStatusStart: callback status start -*/ +static void +CBStatusStart(ocw) +OnTheSpotConversionWidget ocw; +{ + if (ocw->onthespot.statusstartcallback == NULL || + XtHasCallbacks((Widget)ocw, XtNstatusStartCallback) != XtCallbackHasSome) + { + /* no callback */ + return; + } + + TRACE(("OnTheSpot:CBStatusStart()\n")); + + XtCallCallbackList((Widget)ocw, ocw->onthespot.statusstartcallback, + (XtPointer)NULL); +} + +/*- CBStatusDone: callback status done -*/ +static void +CBStatusDone(ocw) +OnTheSpotConversionWidget ocw; +{ + if (ocw->onthespot.statusdonecallback == NULL || + XtHasCallbacks((Widget)ocw, XtNstatusDoneCallback) != XtCallbackHasSome) + { + /* no callback */ + return; + } + + TRACE(("OnTheSpot:CBStatusDone()\n")); + + XtCallCallbackList((Widget)ocw, ocw->onthespot.statusdonecallback, + (XtPointer)NULL); +} + +/*- CBStatusDraw: callback status draw -*/ +static void +CBStatusDraw(ocw, encoding, format, length, text, nchars) +OnTheSpotConversionWidget ocw; +Atom encoding; +int format; +int length; +XtPointer text; +int nchars; +{ + OCCPreeditDrawArg arg; + + if (ocw->onthespot.statusdrawcallback == NULL || + XtHasCallbacks((Widget)ocw, XtNstatusDrawCallback) != XtCallbackHasSome) + { + /* no callback */ + return; + } + + TRACE(("OnTheSpot:CBStatusDraw()\n")); + + arg.caret = 0; /* ignored */ + arg.chg_first = 0; /* ignored */ + arg.chg_length = 0; /* ignored */ + arg.encoding = encoding; + arg.format = format; + arg.text_length = length; + arg.text = text; + arg.attrs_length = nchars; + arg.attrs = NULL; /* ignored */ + XtCallCallbackList((Widget)ocw, ocw->onthespot.statusdrawcallback, + (XtPointer)&arg); +} +