Mercurial > kinput2.yaz
diff lib/OffConv.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/OffConv.c Mon Mar 08 04:44:30 2010 +0900 @@ -0,0 +1,2045 @@ +#ifndef lint +static char *rcsid = "$Id: OffConv.c,v 1.44 2001/07/01 13:47:00 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 + */ + +/* + * Note: This file contains TWO widget classes, OffTheSpotConversionWidget + * and its subclass SeparateConversionWidget. + */ + +#include <X11/IntrinsicP.h> +#include <X11/StringDefs.h> +#if XtSpecificationRelease > 4 +#include <X11/Xfuncs.h> +#endif +#include "CachedAtom.h" +#include "AsyncErr.h" +#include "OffConvP.h" +#include <X11/Xaw/Form.h> +#include "InputConv.h" +#include "ConvDisp.h" +#include "CandPanel.h" +#include "AuxPanel.h" +#include "Canvas.h" +#include "AdoptedShe.h" +#include "CanvasShel.h" +#include "ICLabel.h" + +#define DEBUG_VAR debug_OffTheSpotConversion +#include "DebugPrint.h" + +/*- resource table for OffTheSpotConversion (SeparateConversion has no resources -*/ +static XtResource off_resources[] = { +#define offset(field) XtOffset(OffTheSpotConversionWidget, offthespot.field) + { XtNleftMargin, XtCMargin, XtRDimension, sizeof(Dimension), + offset(leftmargin), XtRImmediate, (XtPointer)2 }, + { XtNrightMargin, XtCMargin, XtRDimension, sizeof(Dimension), + offset(rightmargin), XtRImmediate, (XtPointer)2 }, +#undef offset +}; + +/*- default translations -- same as superclass's -*/ +static char off_translations[] = "<Key>: to-inputobj()"; +static char sep_translations[] = "<Key>: to-inputobj()"; + +/*- declarations of static functions -*/ +static void OffTheSpot_Initialize(); +static void OffTheSpot_Destroy(); +static Boolean OffTheSpot_SetValues(); +static void OffTheSpot_Startup(); +static void OffTheSpot_ConversionFinish(); +static void OffTheSpot_ChangeAttributes(); +static void OffTheSpot_ChangeFocus(); + +static void Separate_Initialize(); +static void Separate_Startup(); +static void Separate_ConversionFinish(); +static void Separate_ChangeAttributes(); +static void Separate_ChangeFocus(); + +static Widget CreateDisplayObject(); +static Widget CreateSelectionWidget(); + +static void SetupDisplayObject(); +static Boolean ResetDisplayObject(); +static void SetupModeWidget(); +static Boolean ResetModeWidget(); +static void SetupCanvasWidget(); +static Boolean ResetCanvasWidget(); + +static void UpdateText(); +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 TextRedisplay(); +static void TextResize(); + +static void SelectionSelected(); + +static void computeDisplaySegments(); +static void recomputeDisplaySegments(); +static void computeLastPosition(); +static DisplayFragment * computeDisplayFragments(); +static int widthAvailable(); +static void initialLocation(); +static void nextLocation(); +static DisplayLocation * findLocation(); +static void reconfigureDisplay(); +static void updateDisplay(); +static void updateDisplaySegment(); +static void redrawSegments(); + +static void eraseCursor(); +static void showCursor(); +static Boolean exposeCursor(); +static void computeCursor(); + +static void MoveShell(); +static Window getToplevelWindow(); +static void setTransientFor(); +static Boolean intersectRect(); +static void unionRect(); +static DisplayFragment * allocDisplayFragment(); +static void freeDisplayFragments(); +static void destroyDisplayFragments(); +static void allocDisplaySegments(); +static void freeDisplaySegment(); +static void clearAllDisplaySegments(); +static void copyString(); +static void freeString(); + +/*- 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, +}; + +/*- offTheSpotConversionClass record -*/ +OffTheSpotConversionClassRec offTheSpotConversionClassRec = { + { /* core fields */ + /* superclass */ (WidgetClass)&conversionControlClassRec, + /* class_name */ "OffTheSpotConversion", + /* widget_size */ sizeof(OffTheSpotConversionRec), + /* class_initialize */ NULL, + /* class_part_initialize */ NULL, + /* class_inited */ FALSE, + /* initialize */ OffTheSpot_Initialize, + /* initialize_hook */ NULL, + /* realize */ XtInheritRealize, + /* actions */ NULL, + /* num_actions */ 0, + /* resources */ off_resources, + /* num_resources */ XtNumber(off_resources), + /* xrm_class */ NULLQUARK, + /* compress_motion */ TRUE, + /* compress_exposure */ TRUE, + /* compress_enterleave */ TRUE, + /* visible_interest */ FALSE, + /* destroy */ OffTheSpot_Destroy, + /* resize */ XtInheritResize, + /* expose */ NULL, + /* set_values */ OffTheSpot_SetValues, + /* set_values_hook */ NULL, + /* set_values_almost */ XtInheritSetValuesAlmost, + /* get_values_hook */ NULL, + /* accept_focus */ NULL, + /* version */ XtVersion, + /* callback_private */ NULL, + /* tm_table */ off_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 */ OffTheSpot_Startup, + /* Finish */ OffTheSpot_ConversionFinish, + /* ChangeAttributes */ OffTheSpot_ChangeAttributes, + /* ChangeFocus */ OffTheSpot_ChangeFocus, + /* TextChange */ UpdateText, + /* Fix */ XtInheritFix, + /* ModeChange */ UpdateMode, + /* SelectionControl */ SelectionControl, + /* AuxControl */ AuxControl, + }, + { /* offTheSpotConversion fields */ + /* empty */ 0 + }, +}; + +WidgetClass offTheSpotConversionWidgetClass = (WidgetClass)&offTheSpotConversionClassRec; + +/*- separateConversionClass record -*/ +SeparateConversionClassRec separateConversionClassRec = { + { /* core fields */ + /* superclass */ (WidgetClass)&offTheSpotConversionClassRec, + /* class_name */ "SeparateConversion", + /* widget_size */ sizeof(SeparateConversionRec), + /* class_initialize */ NULL, + /* class_part_initialize */ NULL, + /* class_inited */ FALSE, + /* initialize */ Separate_Initialize, + /* initialize_hook */ NULL, + /* realize */ XtInheritRealize, + /* actions */ NULL, + /* num_actions */ 0, + /* resources */ NULL, + /* num_resources */ 0, + /* xrm_class */ NULLQUARK, + /* compress_motion */ TRUE, + /* compress_exposure */ TRUE, + /* compress_enterleave */ TRUE, + /* visible_interest */ FALSE, + /* destroy */ NULL, + /* resize */ XtInheritResize, + /* expose */ NULL, + /* set_values */ NULL, + /* set_values_hook */ NULL, + /* set_values_almost */ XtInheritSetValuesAlmost, + /* get_values_hook */ NULL, + /* accept_focus */ NULL, + /* version */ XtVersion, + /* callback_private */ NULL, + /* tm_table */ sep_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 */ Separate_Startup, + /* Finish */ Separate_ConversionFinish, + /* ChangeAttributes */ Separate_ChangeAttributes, + /* ChangeFocus */ Separate_ChangeFocus, + /* TextChange */ XtInheritTextChange, + /* Fix */ XtInheritFix, + /* ModeChange */ XtInheritModeChange, + /* SelectionControl */ XtInheritSelectionControl, + /* AuxControl */ XtInheritAuxControl, + }, + { /* offTheSpotConversion fields */ + /* empty */ 0 + }, + { /* separateConversion fields */ + /* empty */ 0 + }, +}; + +WidgetClass separateConversionWidgetClass = (WidgetClass)&separateConversionClassRec; + +/* + *+ OffTheSpot -- Core class method + */ + +/*- OffTheSpot_Initialize: initalize method for OffTheSpotCoversion -*/ +/* ARGSUSED */ +static void +OffTheSpot_Initialize(req, new, args, num_args) +Widget req; +Widget new; +ArgList args; +Cardinal *num_args; +{ + OffTheSpotConversionWidget ocw = (OffTheSpotConversionWidget)new; + + (void)CreateDisplayObject(ocw); + (void)CreateSelectionWidget(ocw); + (void)CreateAuxWidget(ocw); + + ocw->offthespot.canvaswidget = NULL; + ocw->offthespot.modewidget = NULL; + ocw->offthespot.modeshell = NULL; + + ocw->offthespot.dispsegments = NULL; + ocw->offthespot.numsegments = 0; + ocw->offthespot.dispsegmentsize = 0; + ocw->offthespot.candlist = NULL; + ocw->offthespot.numcands = 0; + ocw->offthespot.selectionpoppedup = False; + ocw->offthespot.auxpoppedup = False; +} + +/*- OffTheSpot_Destroy: destroy method for OffTheSpotCoversion -*/ +static void +OffTheSpot_Destroy(w) +Widget w; +{ + OffTheSpotConversionWidget ocw = (OffTheSpotConversionWidget)w; + + /* $B%G%#%9%W%l%$%;%0%a%s%H$NNN0h$r2rJ|(B */ + if (ocw->offthespot.dispsegments) { + DisplaySegment *dsp = ocw->offthespot.dispsegments; + int i; + + for (i = 0; i < ocw->offthespot.numsegments; i++) { + freeString(&dsp[i].seg); + destroyDisplayFragments(dsp->fragments); + } + XtFree((char *)dsp); + } +} + +/*- OffTheSpot_SetValues: setvalues method for OffTheSpotCoversion -*/ +/* ARGSUSED */ +static Boolean +OffTheSpot_SetValues(cur, req, new, args, num_args) +Widget cur; +Widget req; +Widget new; +ArgList args; +Cardinal *num_args; +{ + /* OffTheSpotConversionWidget ocw = (OffTheSpotConversionWidget)new; */ + return False; +} + +/* + *+ OffTheSpot -- ConversionControl class method + */ + +/*- OffTheSpot_Startup: OffTheSpot conversion startup -*/ +static void +OffTheSpot_Startup(widget, valuemask, value) +Widget widget; +unsigned long valuemask; +ConversionAttributes *value; +{ + OffTheSpotConversionWidget ocw = (OffTheSpotConversionWidget)widget; + Window toplevel; + + if (!(valuemask & CAStatusArea)) { + String params[1]; + Cardinal num_params = 1; + + params[0] = XtClass(widget)->core_class.class_name; + XtAppErrorMsg(XtWidgetToApplicationContext(widget), + "conversionAttributeError", "statusArea", "WidgetError", + "%s: status area must be specified", + params, &num_params); + } + + SetupDisplayObject(ocw, valuemask, value); + SetupModeWidget(ocw, valuemask, value); + SetupCanvasWidget(ocw, valuemask, value); + + /* $BFbIt$N%P%C%U%!$r%/%j%"$9$k(B */ + clearAllDisplaySegments(ocw); + + /* $B%+!<%=%k$N@_Dj(B */ + ocw->offthespot.cursorvisible = True; + eraseCursor(ocw); + ocw->offthespot.cursorvisible = True; + initialLocation(ocw, &(ocw->offthespot.cursorlocation)); + ocw->offthespot.cursorlocation.y += ocw->offthespot.ascent; + + /* 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->offthespot.selectionshell, toplevel); + setTransientFor(ocw->offthespot.auxshell, toplevel); + + /* + * OffTheSpotConvesion $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); + } + + /* $B%]%C%W%"%C%W$9$k(B */ + XtPopup(ocw->offthespot.modeshell, XtGrabNone); + XtPopup(ocw->offthespot.canvaswidget, XtGrabNone); +} + +/*- OffTheSpot_ConversionFinish: OffTheSpot conversion finish -*/ +/* ARGSUSED */ +static void +OffTheSpot_ConversionFinish(w) +Widget w; +{ + OffTheSpotConversionWidget ocw = (OffTheSpotConversionWidget)w; + XAEHandle h; + + /* Popdown and unrealize textcanvas and mode widget + * we must be careful here. if clientwindow are destroyed, + * the text canvas and mode widget are also destroyed. + * we have to popdown and unrealize those widgets, but if + * they are destroyed, BadWindow error will be generated. + * so we must set own error handler that ignores errors. + */ + h = XAESetIgnoreErrors(XtDisplay(w)); + XtPopdown(ocw->offthespot.modeshell); + XtUnrealizeWidget(ocw->offthespot.modeshell); + XtPopdown(ocw->offthespot.canvaswidget); + XtUnrealizeWidget(ocw->offthespot.canvaswidget); + XAEUnset(h); + + if (ocw->offthespot.selectionpoppedup) { + XtPopdown(ocw->offthespot.selectionshell); + ocw->offthespot.selectionpoppedup = False; + } + if (ocw->offthespot.auxpoppedup) { + XtPopdown(ocw->offthespot.auxshell); + ocw->offthespot.auxpoppedup = False; + } +} + +/*- OffTheSpot_ChangeAttributes: OffTheSpot conversion attribute change -*/ +/* ARGSUSED */ +static void +OffTheSpot_ChangeAttributes(w, valuemask, value) +Widget w; +unsigned long valuemask; +ConversionAttributes *value; +{ + OffTheSpotConversionWidget ocw = (OffTheSpotConversionWidget)w; + Boolean redraw, reconfig; + + if (ResetModeWidget(ocw, valuemask, value) && + XtIsRealized(ocw->offthespot.modewidget)) { + XClearArea(XtDisplay(w), XtWindow((Widget)ocw->offthespot.modewidget), + 0, 0, 0, 0, True); + } + + redraw = ResetDisplayObject(ocw, valuemask, value); + reconfig = ResetCanvasWidget(ocw, valuemask, value); + + if (reconfig) { + TextResize(ocw->offthespot.canvaswidget, (XtPointer)w, (XtPointer)NULL); + } else if (redraw && XtIsRealized(ocw->offthespot.canvaswidget)) { + XClearArea(XtDisplay(w), XtWindow(ocw->offthespot.canvaswidget), + 0, 0, 0, 0, True); + } +} + +/*- OffTheSpot_ChangeFocus: OffTheSpot focus change -*/ +static void +OffTheSpot_ChangeFocus(w, set) +Widget w; +int set; +{ + OffTheSpotConversionWidget ocw = (OffTheSpotConversionWidget)w; + + if (set) { + XtPopup(ocw->offthespot.modeshell, XtGrabNone); + XtPopup(ocw->offthespot.canvaswidget, XtGrabNone); + } else { + XtPopdown(ocw->offthespot.modeshell); + XtPopdown(ocw->offthespot.canvaswidget); + } +} + +/* + *+ Separate -- Core class method + */ + +/*- Separate_Initialize: initialize method for SeparateConversion -*/ +/* ARGSUSED */ +static void +Separate_Initialize(req, new, args, num_args) +Widget req; +Widget new; +ArgList args; +Cardinal *num_args; +{ + SeparateConversionWidget scw = (SeparateConversionWidget)new; + Widget inputobj = scw->ccontrol.inputobj; + Widget form, canvas, mode, tmp[2]; + + form = XtCreateManagedWidget("form", formWidgetClass, (Widget)scw, + NULL, 0); + tmp[0] = mode = XtVaCreateWidget("mode", icLabelWidgetClass, form, + XtNlabel, ICGetMode(inputobj), + NULL); + (void)XtCreateWidget("display", scw->ccontrol.displayobjclass, mode, + NULL, 0); + + tmp[1] = canvas = XtCreateWidget("text", canvasWidgetClass, form, NULL, 0); + XtManageChildren(tmp, 2); + + XtAddCallback(canvas, XtNexposeCallback, TextRedisplay, (XtPointer)scw); + XtAddCallback(canvas, XtNresizeCallback, TextResize, (XtPointer)scw); + + XtInstallAccelerators(canvas, (Widget)scw); + XtInstallAccelerators(mode, (Widget)scw); + XtInstallAccelerators(form, (Widget)scw); + + scw->separate.formwidget = form; + scw->offthespot.canvaswidget = canvas; + scw->offthespot.modewidget = mode; + +} + +/* + *+ Separate -- ConversionControl class method + */ + +/*- Separate_Startup: Separate conversion startup -*/ +/* ARGSUSED */ +static void +Separate_Startup(widget, valuemask, value) +Widget widget; +unsigned long valuemask; +ConversionAttributes *value; +{ + SeparateConversionWidget scw = (SeparateConversionWidget)widget; + Position clx, cly; + Dimension clw, clh; + Position x, y; + Dimension w, h; + Dimension dpyWidth, dpyHeight; + Window toplevel; + + /* $BFbIt$N%P%C%U%!$r%/%j%"$9$k(B */ + clearAllDisplaySegments((OffTheSpotConversionWidget)scw); + + /* $B%+!<%=%k$N@_Dj(B */ + scw->offthespot.cursorvisible = True; + eraseCursor((OffTheSpotConversionWidget)scw); + scw->offthespot.cursorvisible = True; + initialLocation((OffTheSpotConversionWidget)scw, + &(scw->offthespot.cursorlocation)); + scw->offthespot.cursorlocation.y += scw->offthespot.ascent; + + /* $B=i4|%b!<%I$r@_Dj$9$k(B */ + XtVaSetValues(scw->offthespot.modewidget, + XtNlabel, ICGetMode(scw->ccontrol.inputobj), + NULL); + + /* $BI=<(0LCV$r7h$a$k(B */ + clx = scw->ccontrol.client_rootx; + cly = scw->ccontrol.client_rooty; + clw = scw->ccontrol.client_attr.width; + clh = scw->ccontrol.client_attr.height; + + XtRealizeWidget((Widget)scw); + w = scw->core.width; + h = scw->core.height; + DPRINT(("Off_the_spot_Startup(): widget size = %dx%d\n", w, h)); + x = clx + clw / 2 - w / 2; + y = cly + clh + 8; + + dpyWidth = WidthOfScreen(XtScreen(widget)); + dpyHeight = HeightOfScreen(XtScreen(widget)); + + if (x + w > dpyWidth) x = dpyWidth - w; + if (x < 0) x = 0; + if (y + h > dpyHeight) { + y = cly - h; + if (y < 0) y = dpyHeight - h; + } + MoveShell(widget, x, y); + + /* WM_TRANSIENT_FOR $B%W%m%Q%F%#$r@5$7$/%;%C%H$9$k(B */ + toplevel = getToplevelWindow(XtDisplay(widget), + scw->ccontrol.clientwindow); + setTransientFor((Widget)scw, toplevel); + + /* + * This is a kind of a magic word... I don't know why, but without this + * the selection popup will appear in wrong size (1x1) at the first time. + */ + XtRealizeWidget(scw->offthespot.selectionshell); + XtRealizeWidget(scw->offthespot.auxshell); + + /* $B%]%C%W%"%C%W$9$k(B */ + XtPopup(widget, XtGrabNone); +} + +/*- Separate_ConversionFinish: Separate conversion finish -*/ +/* ARGSUSED */ +static void +Separate_ConversionFinish(w) +Widget w; +{ + SeparateConversionWidget scw = (SeparateConversionWidget)w; + + if (scw->offthespot.selectionpoppedup) { + XtPopdown(scw->offthespot.selectionshell); + scw->offthespot.selectionpoppedup = False; + } + if (scw->offthespot.auxpoppedup) { + XtPopdown(scw->offthespot.auxshell); + scw->offthespot.auxpoppedup = False; + } + XtPopdown(w); +} + +/*- Separate_ChangeAttributes: Separate conversion attribute change -*/ +/* ARGSUSED */ +static void +Separate_ChangeAttributes(w, mask, value) +Widget w; +unsigned long mask; +ConversionAttributes *value; +{ + /* do nothing */ +} + +/*- Separate_ChangeFocus: Separate focus change -*/ +/* ARGSUSED */ +static void +Separate_ChangeFocus(w, set) +Widget w; +int set; +{ + /* do nothing */ +} + +/* + *+ sub-widget creation + */ + +/*- CreateDisplayObject: create display object for text drawing -*/ +static Widget +CreateDisplayObject(ocw) +OffTheSpotConversionWidget ocw; +{ + Widget dispobj; + + dispobj = XtCreateWidget("displayObj", ocw->ccontrol.displayobjclass, + (Widget)ocw, NULL, 0); + + ocw->offthespot.displayobj = dispobj; + ocw->offthespot.lineheight = CDLineHeight(dispobj, &ocw->offthespot.ascent); + + return dispobj; +} + +/*- CreateSelectionWidget: create selection widget for selecting candidates -*/ +static Widget +CreateSelectionWidget(ocw) +OffTheSpotConversionWidget 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->offthespot.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->offthespot.selectionwidget = sel; + + return shell; +} + +/*- CreateAuxWidget: create aux widget for display auxiliary data -*/ +static Widget +CreateAuxWidget(ocw) +OffTheSpotConversionWidget 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->offthespot.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->offthespot.auxwidget = sel; + + return shell; +} + +/* + *+ subwidget configuration + */ + +/*- SetupDisplayObject: do display objetct configuration on conversion startup -*/ +static void +SetupDisplayObject(ocw, mask, value) +OffTheSpotConversionWidget ocw; +unsigned long mask; +ConversionAttributes *value; +{ + /* + * order is important. we must set fonts BEFORE anything else, + * because it is possible that the fonts previously set in the + * display object no longer exist, and if so, that causes BadFont + * error when changing GCs. + */ + + if (mask & CAFonts) { + CDSetFonts(ocw->offthespot.displayobj, + value->fonts, value->num_fonts); + } else { + CDSetFonts(ocw->offthespot.displayobj, (XFontStruct **)NULL, 0); + } + if (mask & CAColor) { + XtVaSetValues(ocw->offthespot.displayobj, + XtNforeground, value->foreground, + XtNbackground, value->background, + NULL); + } + + ocw->offthespot.lineheight = CDLineHeight(ocw->offthespot.displayobj, + &ocw->offthespot.ascent); +} + +/*- ResetDisplayObject: do display objetct reconfiguration on attribute change -*/ +static Boolean +ResetDisplayObject(ocw, mask, value) +OffTheSpotConversionWidget ocw; +unsigned long mask; +ConversionAttributes *value; +{ + Boolean redraw = False; + + if (mask & CAColor) { + XtVaSetValues(ocw->offthespot.displayobj, + XtNforeground, value->foreground, + XtNbackground, value->background, + NULL); + redraw = True; + } + if (mask & CAFonts) { + CDSetFonts(ocw->offthespot.displayobj, + value->fonts, value->num_fonts); + redraw = True; + ocw->offthespot.lineheight = CDLineHeight(ocw->offthespot.displayobj, + &ocw->offthespot.ascent); + } + return redraw; +} + +/*- SetupModeWidget: do mode widget configuration (OffTheSpot only) -*/ +static void +SetupModeWidget(ocw, mask, value) +OffTheSpotConversionWidget ocw; +unsigned long mask; +ConversionAttributes *value; +{ + Window clwin = ocw->ccontrol.clientwindow; + Widget inputobj = ocw->ccontrol.inputobj; + Arg shellarg[10], modearg[10], objarg[10]; + Cardinal i = 0, j = 0, k = 0; + + XtSetArg(shellarg[i], XtNparentWindow, clwin); i++; + XtSetArg(shellarg[i], XtNx, value->statusarea.x); i++; + XtSetArg(shellarg[i], XtNy, value->statusarea.y); i++; + XtSetArg(shellarg[i], XtNwidth, value->statusarea.width); i++; + XtSetArg(shellarg[i], XtNheight, value->statusarea.height); i++; + + XtSetArg(modearg[j], XtNlabel, ICGetMode(inputobj)); j++; + + if (mask & CAColormap) { + XtSetArg(modearg[j], XtNcolormap, value->colormap); j++; + } else { + XtSetArg(modearg[j], XtNcolormap, + DefaultColormapOfScreen(XtScreen((Widget)ocw))); j++; + } + if (mask & CAColor) { + XtSetArg(modearg[j], XtNbackground, value->background); j++; + XtSetArg(objarg[k], XtNforeground, value->foreground); k++; + XtSetArg(objarg[k], XtNbackground, value->background); k++; + } else { + XtSetArg(modearg[j], XtNbackground, ocw->core.background_pixel); j++; + } + + if (ocw->offthespot.modewidget == NULL) { + Widget shell, mode, disp; + shell = XtCreatePopupShell("modeShell", adoptedShellWidgetClass, + (Widget)ocw, shellarg, i); + mode = XtCreateManagedWidget("mode", icLabelWidgetClass, shell, + modearg, j); + disp = XtCreateWidget("display", ocw->ccontrol.displayobjclass, mode, + objarg, k); + if (mask & CAStatusFonts) { + CDSetFonts(disp, value->status_fonts, value->num_status_fonts); + } + + ocw->offthespot.modeshell = shell; + ocw->offthespot.modewidget = mode; + ocw->offthespot.modedisplayobj = disp; + XtInstallAccelerators(mode, (Widget)ocw); + } else { + if (mask & CAStatusFonts) { + CDSetFonts(ocw->offthespot.modedisplayobj, + value->status_fonts, value->num_status_fonts); + } else { + CDSetFonts(ocw->offthespot.modedisplayobj, + (XFontStruct **)NULL, 0); + } + XtSetValues(ocw->offthespot.modeshell, shellarg, i); + XtSetValues(ocw->offthespot.modewidget, modearg, j); + XtSetValues(ocw->offthespot.modedisplayobj, objarg, k); + } + + ICLRecomputeSize(ocw->offthespot.modewidget); +} + +/*- ResetModeWidget: do mode widget reconfiguration (OffTheSpot only) -*/ +static Boolean +ResetModeWidget(ocw, mask, value) +OffTheSpotConversionWidget ocw; +unsigned long mask; +ConversionAttributes *value; +{ + Arg shellarg[10], modearg[10], objarg[10]; + Cardinal i = 0, j = 0, k = 0; + Boolean redraw = False; + + if (mask & CAStatusArea) { + XtSetArg(shellarg[i], XtNx, value->statusarea.x); i++; + XtSetArg(shellarg[i], XtNy, value->statusarea.y); i++; + XtSetArg(shellarg[i], XtNwidth, value->statusarea.width); i++; + XtSetArg(shellarg[i], XtNheight, value->statusarea.height); i++; + } + + if (mask & CAColormap) { + XtSetArg(modearg[j], XtNcolormap, value->colormap); j++; + redraw = True; + } + if (mask & CAColor) { + XtSetArg(modearg[j], XtNbackground, value->background); j++; + XtSetArg(objarg[k], XtNforeground, value->foreground); k++; + XtSetArg(objarg[k], XtNbackground, value->background); k++; + redraw = True; + } + XtSetValues(ocw->offthespot.modeshell, shellarg, i); + XtSetValues(ocw->offthespot.modewidget, modearg, j); + XtSetValues(ocw->offthespot.modedisplayobj, objarg, k); + + if (mask & CAStatusFonts) { + CDSetFonts(ocw->offthespot.modedisplayobj, + value->status_fonts, value->num_status_fonts); + ICLRecomputeSize(ocw->offthespot.modewidget); + redraw = True; + } + + return redraw; +} + +/*- SetupCanvasWidget: do text canvas configuration on conversion startup -*/ +static void +SetupCanvasWidget(ocw, mask, value) +OffTheSpotConversionWidget ocw; +unsigned long mask; +ConversionAttributes *value; +{ + Window clwin = ocw->ccontrol.clientwindow; + Arg arg[10]; + Cardinal i = 0; + + XtSetArg(arg[i], XtNparentWindow, clwin); i++; + + if (mask & CAClientArea) { + XtSetArg(arg[i], XtNx, value->clientarea.x); i++; + XtSetArg(arg[i], XtNy, value->clientarea.y); i++; + XtSetArg(arg[i], XtNwidth, value->clientarea.width); i++; + XtSetArg(arg[i], XtNheight, value->clientarea.height); i++; + } else { + XtSetArg(arg[i], XtNx, 0); i++; + XtSetArg(arg[i], XtNy, 0); i++; + XtSetArg(arg[i], XtNwidth, ocw->ccontrol.client_attr.width); i++; + XtSetArg(arg[i], XtNheight, ocw->ccontrol.client_attr.height); i++; + } + + /* if (mask & CALineSpacing) ... */ + if (mask & CAColormap) { + XtSetArg(arg[i], XtNcolormap, value->colormap); i++; + } else { + XtSetArg(arg[i], XtNcolormap, + DefaultColormapOfScreen(XtScreen((Widget)ocw))); i++; + } + if (mask & CAColor) { + XtSetArg(arg[i], XtNbackground, value->background); i++; + } else { + XtSetArg(arg[i], XtNbackground, ocw->core.background_pixel); i++; + } + if (mask & CACursor) { + XtSetArg(arg[i], XtNcursor, value->cursor); i++; + } else { + XtSetArg(arg[i], XtNcursor, None); i++; + } + + if (ocw->offthespot.canvaswidget == NULL) { + Widget canvas; + canvas = XtCreatePopupShell("text", canvasShellWidgetClass, + (Widget)ocw, arg, i); + XtAddCallback(canvas, XtNexposeCallback, TextRedisplay, (XtPointer)ocw); + XtAddCallback(canvas, XtNresizeCallback, TextResize, (XtPointer)ocw); + XtInstallAccelerators(canvas, (Widget)ocw); + ocw->offthespot.canvaswidget = canvas; + } else { + XtSetValues(ocw->offthespot.canvaswidget, arg, i); + } +} + +/*- ResetCanvasWidget: do text canvas reconfiguration on attribute change (OfftheSpot only) -*/ +static Boolean +ResetCanvasWidget(ocw, mask, value) +OffTheSpotConversionWidget ocw; +unsigned long mask; +ConversionAttributes *value; +{ + Arg arg[10]; + Cardinal i = 0; + Boolean redraw = False; + + if (mask & CAClientArea) { + XtSetArg(arg[i], XtNx, value->clientarea.x); i++; + XtSetArg(arg[i], XtNy, value->clientarea.y); i++; + XtSetArg(arg[i], XtNwidth, value->clientarea.width); i++; + XtSetArg(arg[i], XtNheight, value->clientarea.height); i++; + redraw = True; + } + + if (mask & CAColormap) { + XtSetArg(arg[i], XtNcolormap, value->colormap); i++; + redraw = True; + } + if (mask & CAColor) { + XtSetArg(arg[i], XtNbackground, value->background); i++; + redraw = True; + } + if (mask & CACursor) { + XtSetArg(arg[i], XtNcursor, value->cursor); i++; + } + + XtSetValues(ocw->offthespot.canvaswidget, arg, i); + + return redraw; +} + +static void +UpdateText(w) +Widget w; +{ + OffTheSpotConversionWidget ocw = (OffTheSpotConversionWidget)w; + + TRACE(("OffTheSpotConversion:UpdateText()\n")); + eraseCursor(ocw); + computeDisplaySegments(ocw); + computeCursor(ocw); + reconfigureDisplay(ocw); + updateDisplay(ocw); + showCursor(ocw); +} + +static void +UpdateMode(w) +Widget w; +{ + OffTheSpotConversionWidget ocw = (OffTheSpotConversionWidget)w; + + TRACE(("OffTheSpotConversion:UpdateMode()\n")); + XtVaSetValues(ocw->offthespot.modewidget, + XtNlabel, ICGetMode(ocw->ccontrol.inputobj), + NULL); +} + +static void +SelectionControl(w, arg) +Widget w; +ICSelectionControlArg *arg; +{ + OffTheSpotConversionWidget ocw = (OffTheSpotConversionWidget)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; + } +} + +/* ARGSUSED */ +static void +SelectionStart(ocw, kind) +OffTheSpotConversionWidget ocw; +int kind; +{ + Cardinal ncand; + + TRACE(("OffTheSpotConversion:SelectionStart()\n")); + if (ocw->offthespot.selectionpoppedup) { + TRACE(("\tselection already started -- ignored\n")); + return; + } + + ocw->offthespot.candlist = ICGetItemList(ocw->ccontrol.inputobj, &ncand); + ocw->offthespot.numcands = ncand; + + TRACE(("\tnumcands=%d\n", ocw->offthespot.numcands)); + CPanelSetList(ocw->offthespot.selectionwidget, + ocw->offthespot.candlist, + ocw->offthespot.numcands, 0, True); + + /* $B%]%C%W%"%C%W$9$k>l=j$r7h$a$k(B */ + LocateSelectionPopup(ocw); + + XtPopup(ocw->offthespot.selectionshell, XtGrabNone); + ocw->offthespot.selectionpoppedup = True; +} + +static void +LocateSelectionPopup(ocw) +OffTheSpotConversionWidget ocw; +{ + Position x, y; + DisplayLocation lastp; + Dimension dpyWidth, dpyHeight; + Widget canvas = ocw->offthespot.canvaswidget; + Widget panel = ocw->offthespot.selectionwidget; + Widget shell = ocw->offthespot.selectionshell; + int clx, cly; + Window junk; + int barheight = ocw->ccontrol.titlebarheight; + + if (ocw->offthespot.numsegments > 0) { + computeLastPosition(ocw->offthespot.dispsegments[ocw->offthespot.numsegments - 1].fragments, &lastp); + } else { + lastp.y = 0; + } + lastp.x = canvas->core.width / 2; + lastp.y += ocw->offthespot.lineheight; + (void)XTranslateCoordinates(XtDisplay(canvas), XtWindow(canvas), + RootWindowOfScreen(XtScreen(canvas)), + 0, 0, &clx, &cly, &junk); + + x = clx + lastp.x - panel->core.width / 2; + y = cly + lastp.y + 8; /* XXX */ + + dpyWidth = WidthOfScreen(XtScreen(canvas)); + dpyHeight = HeightOfScreen(XtScreen(canvas)); + + if (x + panel->core.width > dpyWidth) x = dpyWidth - panel->core.width; + if (x < 0) x = 0; + if (y + panel->core.height + barheight > dpyHeight) { + y = cly - panel->core.height - 8 - barheight; + if (y < 0) y = dpyHeight - panel->core.height - barheight; + } + MoveShell(shell, x, y); +} + +static void +SelectionEnd(ocw, current) +OffTheSpotConversionWidget ocw; +int *current; +{ + TRACE(("OffTheSpotConversion:SelectionEnd()\n")); + if (!ocw->offthespot.selectionpoppedup) { /* for safe */ + TRACE(("\tnot in selection mode -- ignored\n")); + return; + } + + XtVaGetValues(ocw->offthespot.selectionwidget, + XtNcurrentItem, current, + NULL); + + XtPopdown(ocw->offthespot.selectionshell); + + ocw->offthespot.selectionpoppedup = False; +} + +static void +SelectionSet(ocw, current) +OffTheSpotConversionWidget ocw; +int current; +{ + TRACE(("OffTheSpotConversion:SelectionSet()\n")); + if (!ocw->offthespot.selectionpoppedup) { /* for safe */ + TRACE(("\tnot in selection mode -- ignored\n")); + return; + } + + XtVaSetValues(ocw->offthespot.selectionwidget, + XtNcurrentItem, current, + NULL); +} + +static void +SelectionGet(ocw, current) +OffTheSpotConversionWidget ocw; +int *current; +{ + TRACE(("OffTheSpotConversion:SelectionGet()\n")); + if (!ocw->offthespot.selectionpoppedup) { /* for safe */ + TRACE(("\tnot in selection mode -- ignored\n")); + return; + } + + XtVaGetValues(ocw->offthespot.selectionwidget, + XtNcurrentItem, current, + NULL); +} + +static void +SelectionMove(ocw, dir) +OffTheSpotConversionWidget ocw; +int dir; +{ + TRACE(("OffTheSpotConversion:SelectionMove()\n")); + if (!ocw->offthespot.selectionpoppedup) { /* for safe */ + TRACE(("\tnot in selection mode -- ignored\n")); + return; + } + + CPanelMoveCurrent(ocw->offthespot.selectionwidget, dir); +} + +/* + * Aux Callback + */ + +static void +AuxControl(w, arg) +Widget w; +ICAuxControlArg *arg; +{ + OffTheSpotConversionWidget ocw = (OffTheSpotConversionWidget)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) +OffTheSpotConversionWidget ocw; +{ + ICString *auxstr; + Cardinal ncand, curseg, cursorpos; + + if (ocw->offthespot.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->offthespot.auxwidget, auxstr, ncand, curseg, cursorpos); + + /* $B%]%C%W%"%C%W$9$k>l=j$r7h$a$k(B */ + LocateAuxPopup(ocw); + + XtPopup(ocw->offthespot.auxshell, XtGrabNone); + ocw->offthespot.auxpoppedup = True; +} + +/* ARGSUSED */ +static void +AuxEnd(ocw) +OffTheSpotConversionWidget ocw; +{ + if (!ocw->offthespot.auxpoppedup) return; /* for safe */ + +/* APanelEnd(ocw->offthespot.auxwidget); */ + + XtPopdown(ocw->offthespot.auxshell); + + ocw->offthespot.auxpoppedup = False; +} + +/* ARGSUSED */ +static void +AuxChange(ocw) +OffTheSpotConversionWidget ocw; +{ + Cardinal ncand, curseg, cursorpos; + ICString *auxstr; + + if (!ocw->offthespot.auxpoppedup) return; /* for safe */ + + auxstr = ICGetAuxSegments(ocw->ccontrol.inputobj, + &ncand, &curseg, &cursorpos); + + APanelChange(ocw->offthespot.auxwidget, auxstr, ncand, curseg, cursorpos); +} + +static void +LocateAuxPopup(ocw) +OffTheSpotConversionWidget ocw; +{ + Position x, y; + DisplayLocation lastp; + Dimension dpyWidth, dpyHeight; + Widget canvas = ocw->offthespot.canvaswidget; + Widget panel = ocw->offthespot.auxwidget; + Widget shell = ocw->offthespot.auxshell; + int clx, cly; + Window junk; + int barheight = ocw->ccontrol.titlebarheight; + + if (ocw->offthespot.numsegments > 0) { + computeLastPosition(ocw->offthespot.dispsegments[ocw->offthespot.numsegments - 1].fragments, &lastp); + } else { + lastp.y = 0; + } + lastp.x = canvas->core.width / 2; + lastp.y += ocw->offthespot.lineheight; + (void)XTranslateCoordinates(XtDisplay(canvas), XtWindow(canvas), + RootWindowOfScreen(XtScreen(canvas)), + 0, 0, &clx, &cly, &junk); + + x = clx + lastp.x - panel->core.width / 2; + y = cly + lastp.y + 8; /* XXX */ + + dpyWidth = WidthOfScreen(XtScreen(canvas)); + dpyHeight = HeightOfScreen(XtScreen(canvas)); + + if (x + panel->core.width > dpyWidth) x = dpyWidth - panel->core.width; + if (x < 0) x = 0; + if (y + panel->core.height + barheight > dpyHeight) { + y = cly - panel->core.height - 8 - barheight; + if (y < 0) y = dpyHeight - panel->core.height - barheight; + } + MoveShell(shell, x, y); +} + + +/* + *+ TextCanvas callback + */ + +/*- TextRedisplay: redraw text canvas -*/ +static void +TextRedisplay(w, client_data, call_data) +Widget w; +XtPointer client_data; +XtPointer call_data; +{ + OffTheSpotConversionWidget ocw = (OffTheSpotConversionWidget)client_data; + XExposeEvent *event = (XExposeEvent *)call_data; + XRectangle region; + Boolean cursorredraw; + + TRACE(("OffTheSpotConversion:TextRedisplay()\n")); + region.x = event->x; + region.y = event->y; + region.width = event->width; + region.height = event->height; + + cursorredraw = exposeCursor(ocw, w, ®ion); + redrawSegments(ocw, ®ion); + if (cursorredraw) showCursor(ocw); +} + +/*- TextResize: do reconfiguration (and redraw) of text canvas when resized -*/ +/* ARGSUSED */ +static void +TextResize(w, client_data, call_data) +Widget w; +XtPointer client_data; +XtPointer call_data; /* unused */ +{ + OffTheSpotConversionWidget ocw = (OffTheSpotConversionWidget)client_data; + + TRACE(("OffTheSpotConversion:TextResize()\n")); + recomputeDisplaySegments(ocw); + computeCursor(ocw); + if (XtIsRealized(w)) { + /* redraw it */ + XClearArea(XtDisplay(w), XtWindow(w), 0, 0, 0, 0, True); + } +} + + +/* + *+ Selection Widget callback + */ + +/*- SelectionSelected: selection selected callback -*/ +/* ARGSUSED */ +static void +SelectionSelected(w, client_data, call_data) +Widget w; +XtPointer client_data; +XtPointer call_data; +{ + OffTheSpotConversionWidget ocw = (OffTheSpotConversionWidget)client_data; + int current = (int)call_data; + + TRACE(("OffTheSpotConversion:SelectionSelected()\n")); + XtPopdown(ocw->offthespot.selectionshell); + ocw->offthespot.selectionpoppedup = False; + ICSelectItem(ocw->ccontrol.inputobj, current); +} + + +/* + *+ text drawing functions + */ + +/*- computeDisplaySegments: compare old&new text and update segments/fragments -*/ +static void +computeDisplaySegments(ocw) +OffTheSpotConversionWidget ocw; +{ + Widget inputobj = ocw->ccontrol.inputobj; + Cardinal nnew = ICNumSegments(inputobj); + Cardinal nold = ocw->offthespot.numsegments; + ICString *newseg; + DisplaySegment *dseg; + DisplayLocation disploc; + Cardinal nsame; + int diff; + Cardinal i; + + TRACE(("OffTheSpotConversion:computeDisplaySegments() nnew=%d\n", nnew)); + allocDisplaySegments(ocw, nnew); + + initialLocation(ocw, &disploc); + + for (i = 0, dseg = ocw->offthespot.dispsegments; i < nnew; i++, dseg++) { + newseg = ICGetSegment(ocw->ccontrol.inputobj, i); + if (i >= nold) { + copyString(newseg, &dseg->seg); + dseg->redrawpos = 0; + dseg->fragments = computeDisplayFragments(ocw, newseg, &disploc); + } else { + DisplayFragment *oldfragments, *newfragments; + + dseg->redrawpos = -1; + diff = ICCompareSegment(inputobj, newseg, &dseg->seg, &nsame); + if (diff != ICSame || + disploc.x != dseg->fragments->region.x || + disploc.y != dseg->fragments->region.y) { + oldfragments = dseg->fragments; + newfragments = computeDisplayFragments(ocw, newseg, &disploc); + dseg->fragments = newfragments; + } else { + oldfragments = NULL; + newfragments = dseg->fragments; + computeLastPosition(newfragments, &disploc); + } + + switch (diff) { + case ICSame: + if (oldfragments == NULL || + oldfragments->region.x == newfragments->region.x && + oldfragments->region.y == newfragments->region.y) { + dseg->redrawpos = -1; + } else { + dseg->redrawpos = 0; + } + break; + case ICAttrChanged: + dseg->redrawpos = 0; + dseg->seg.attr = newseg->attr; + break; + case ICStringChanged: + if (oldfragments == NULL || + oldfragments->region.x == newfragments->region.x && + oldfragments->region.y == newfragments->region.y) { + dseg->redrawpos = nsame; + } else { + dseg->redrawpos = 0; + } + freeString(&dseg->seg); + copyString(newseg, &dseg->seg); + break; + default: + dseg->redrawpos = 0; + freeString(&dseg->seg); + copyString(newseg, &dseg->seg); + break; + } + if (oldfragments) freeDisplayFragments(oldfragments); + } + } + + for (; i < nold; i++, dseg++) freeDisplaySegment(dseg); + + ocw->offthespot.numsegments = nnew; +} + +/*- recomputeDisplaySegments: recompute segments/fragments -*/ +static void +recomputeDisplaySegments(ocw) +OffTheSpotConversionWidget ocw; +{ + Cardinal nsegs = ocw->offthespot.numsegments; + DisplaySegment *dseg; + DisplayLocation disploc; + Cardinal i; + + initialLocation(ocw, &disploc); + + for (i = 0, dseg = ocw->offthespot.dispsegments; i < nsegs; i++, dseg++) { + freeDisplayFragments(dseg->fragments); + dseg->redrawpos = 0; + dseg->fragments = computeDisplayFragments(ocw, &dseg->seg, &disploc); + } +} + +/*- computeLastPosition: get last position of the specified fragment list -*/ +static void +computeLastPosition(fragments, disploc) +DisplayFragment *fragments; +DisplayLocation *disploc; +{ + while (fragments->next != NULL) fragments = fragments->next; + disploc->x = fragments->region.x + fragments->region.width; + disploc->y = fragments->region.y; +} + +/*- computeDisplayFragments: compute fragment(s) of the specified segment -*/ +static DisplayFragment * +computeDisplayFragments(ocw, newseg, disploc) +OffTheSpotConversionWidget ocw; +ICString *newseg; +DisplayLocation *disploc; +{ + int start; + int nchars; + Widget dispobj = ocw->offthespot.displayobj; + DisplayFragment *fragments, *dfp; + int widthavailable; + + TRACE(("computeDisplayFragments()\n")); + start = 0; + fragments = NULL; + while (start < newseg->nchars) { + widthavailable = widthAvailable(ocw, disploc); + nchars = CDMaxChar(dispobj, newseg, start, widthavailable); + if (nchars == 0 && disploc->x <= ocw->offthespot.leftmargin) { + /* + * avoiding infinite loop + * we display at least one character per line + */ + nchars = 1; + } + TRACE(("\twidthavailable=%d, start=%d, maxchar=%d\n", widthavailable, start, nchars)); + if (nchars > 0) { + if (fragments == NULL) { + fragments = dfp = allocDisplayFragment(); + } else { + dfp->next = allocDisplayFragment(); + dfp = dfp->next; + } + dfp->from = start; + dfp->nchars = nchars; + dfp->region.x = disploc->x; + dfp->region.y = disploc->y; + dfp->region.width = CDStringWidth(dispobj, newseg, start, + start + nchars); + dfp->region.height = ocw->offthespot.lineheight; + dfp->next = NULL; + + disploc->x += dfp->region.width; + } + start += nchars; + + if (start < newseg->nchars) nextLocation(ocw, disploc); + } + + return fragments; +} + +/*- widthAvailable: return the width of the current line left for drawing -*/ +static int +widthAvailable(ocw, disploc) +OffTheSpotConversionWidget ocw; +DisplayLocation *disploc; +{ + return ocw->offthespot.canvaswidget->core.width - + ocw->offthespot.rightmargin - disploc->x; +} + +/*- initialLocation: return the initial text drawing position -*/ +static void +initialLocation(ocw, disploc) +OffTheSpotConversionWidget ocw; +DisplayLocation *disploc; +{ + int cheight = ocw->offthespot.canvaswidget->core.height; + int lheight = ocw->offthespot.lineheight; + + disploc->x = ocw->offthespot.leftmargin; + if (cheight / lheight == 1) { + /* if there's space for a single line, locate it in the center */ + disploc->y = (cheight - lheight) / 2; + } else { + disploc->y = 0; + } +} + +/*- nextLocation: return the position of the next line -*/ +static void +nextLocation(ocw, disploc) +OffTheSpotConversionWidget ocw; +DisplayLocation *disploc; +{ + disploc->x = ocw->offthespot.leftmargin; + disploc->y += ocw->offthespot.lineheight; +} + +/*- findLocation: compute the display position of specific character -*/ +static DisplayLocation * +findLocation(ocw, dsp, offset, disploc) +OffTheSpotConversionWidget ocw; +DisplaySegment *dsp; +Cardinal offset; +DisplayLocation *disploc; +{ + DisplayFragment *dfp = dsp->fragments; + + while (dfp != NULL) { + if (dfp->nchars > offset || + dfp->next == NULL && dfp->nchars == offset) { + break; + } + offset -= dfp->nchars; + dfp = dfp->next; + } + if (dfp == NULL) return NULL; + + disploc->x = dfp->region.x + CDStringWidth(ocw->offthespot.displayobj, + &dsp->seg, dfp->from, + dfp->from + offset); + disploc->y = dfp->region.y; + + return disploc; +} + +/*- reconfigureDisplay: do reconfiguration of text canvas (resize/popup/popdown) -*/ +static void +reconfigureDisplay(ocw) +OffTheSpotConversionWidget ocw; +{ + DisplaySegment *dsp; + DisplayFragment *dfp; + Widget canvas = ocw->offthespot.canvaswidget; + Position lastx, lasty; + Dimension height = ocw->offthespot.lineheight; + int i; + + lastx = 0; + dsp = ocw->offthespot.dispsegments; + if (ocw->offthespot.numsegments > 0 && dsp->fragments != NULL) { + lasty = dsp->fragments->region.y; + } else { + lasty = 0; + } + for (i = 0, dsp = ocw->offthespot.dispsegments; i < ocw->offthespot.numsegments; i++, dsp++) { + for (dfp = dsp->fragments; dfp != NULL; dfp = dfp->next) { + if (lasty != dfp->region.y) { + XClearArea(XtDisplay(canvas), XtWindow(canvas), + lastx, lasty, 0, height, False); + } + lastx = dfp->region.x + dfp->region.width; + lasty = dfp->region.y; + } + } + + XClearArea(XtDisplay(canvas), XtWindow(canvas), + lastx, lasty, 0, 0, False); + if (lasty + height < canvas->core.height) { + XClearArea(XtDisplay(canvas), XtWindow(canvas), + 0, lasty + height, 0, 0, False); + } +} + +/*- updateDisplay: redraw text (if needed) -*/ +static void +updateDisplay(ocw) +OffTheSpotConversionWidget ocw; +{ + DisplaySegment *dsp = ocw->offthespot.dispsegments; + int i; + + for (i = 0; i < ocw->offthespot.numsegments; i++, dsp++) { + if (dsp->redrawpos >= 0) { + TRACE(("updateDisplaySegment(seg#=%d)\n", i)); + updateDisplaySegment(ocw, dsp); + } + } +} + +/*- updateDisplaySegment: redraw specified segment (if needed) -*/ +static void +updateDisplaySegment(ocw, dsp) +OffTheSpotConversionWidget ocw; +DisplaySegment *dsp; +{ + DisplayFragment *dfp = dsp->fragments; + Widget dispobj = ocw->offthespot.displayobj; + Widget canvas = ocw->offthespot.canvaswidget; + int from; + int x; + + while (dfp != NULL) { + if (dsp->redrawpos < dfp->from + dfp->nchars) { + from = (dsp->redrawpos > dfp->from) ? dsp->redrawpos : dfp->from; + x = dfp->region.x; + if (from > dfp->from) { + x += CDStringWidth(dispobj, &dsp->seg, dfp->from, from); + } + CDDrawString(dispobj, canvas, &dsp->seg, + from, dfp->from + dfp->nchars, + x, dfp->region.y); + } + dfp = dfp->next; + } +} + +/*- redrawSegments: redraw segments in specified area -*/ +static void +redrawSegments(ocw, region) +OffTheSpotConversionWidget ocw; +XRectangle *region; +{ + DisplaySegment *dsp = ocw->offthespot.dispsegments; + DisplayFragment *dfp; + Widget dispobj = ocw->offthespot.displayobj; + Widget canvas = ocw->offthespot.canvaswidget; + int i; + + for (i = 0; i < ocw->offthespot.numsegments; i++, dsp++) { + for (dfp = dsp->fragments; dfp != NULL; dfp = dfp->next) { + if (intersectRect(&dfp->region, region)) { + CDDrawString(dispobj, canvas, &dsp->seg, + dfp->from, dfp->from + dfp->nchars, + dfp->region.x, dfp->region.y); + } + } + } +} + +/* + *+ insert cursor handling + */ + +/*- eraseCursor: erase insert cursor -*/ +static void +eraseCursor(ocw) +OffTheSpotConversionWidget ocw; +{ + if (!ocw->offthespot.cursorvisible) return; + + TRACE(("eraseCursor() at (%d,%d)\n", + ocw->offthespot.cursorlocation.x, + ocw->offthespot.cursorlocation.y)); + CDDrawCursor(ocw->offthespot.displayobj, + ocw->offthespot.canvaswidget, + ocw->offthespot.cursorlocation.x, + ocw->offthespot.cursorlocation.y, + False); + ocw->offthespot.cursorvisible = False; +} + +/*- showCursor: draw insert cursor -*/ +static void +showCursor(ocw) +OffTheSpotConversionWidget ocw; +{ + if (!ocw->offthespot.cursorvisible) return; + + TRACE(("showCursor at (%d,%d)\n", + ocw->offthespot.cursorlocation.x, + ocw->offthespot.cursorlocation.y)); + CDDrawCursor(ocw->offthespot.displayobj, + ocw->offthespot.canvaswidget, + ocw->offthespot.cursorlocation.x, + ocw->offthespot.cursorlocation.y, + True); +} + +/*- exposeCursor: make the insert cursor redraw correctly when exposing -*/ +static Boolean +exposeCursor(ocw, w, region) +OffTheSpotConversionWidget ocw; +Widget w; +XRectangle *region; +{ + XRectangle bounds; + + if (!ocw->offthespot.cursorvisible) return False; + + TRACE(("exposeCursor(region=%d,%d-%d,%d)\n", + region->x, region->y, region->width, region->height)); + CDGetCursorBounds(ocw->offthespot.displayobj, &bounds); + bounds.x += ocw->offthespot.cursorlocation.x; + bounds.y += ocw->offthespot.cursorlocation.y; + if (intersectRect(region, &bounds)) { + eraseCursor(ocw); + XClearArea(XtDisplay(w), XtWindow(w), + bounds.x, bounds.y, bounds.width, bounds.height, False); + unionRect(region, &bounds, region); + } + ocw->offthespot.cursorvisible = True; + return True; +} + +/*- computeCursor: compute cursor position -*/ +static void +computeCursor(ocw) +OffTheSpotConversionWidget ocw; +{ + DisplaySegment *dsp; + DisplayLocation disploc; + Cardinal seg, offset; + + if (ocw->offthespot.numsegments == 0) { + /* special case */ + initialLocation(ocw, &(ocw->offthespot.cursorlocation)); + ocw->offthespot.cursorlocation.y += ocw->offthespot.ascent; + ocw->offthespot.cursorvisible = True; + return; + } + + if (!ICCursorPos(ocw->ccontrol.inputobj, &seg, &offset)) return; + + /* sanity check */ + if (seg >= ocw->offthespot.numsegments) return; + dsp = ocw->offthespot.dispsegments + seg; + if (offset > dsp->seg.nchars) return; + + if (findLocation(ocw, dsp, offset, &disploc) == NULL) return; + + disploc.y += ocw->offthespot.ascent; + + ocw->offthespot.cursorvisible = True; + ocw->offthespot.cursorlocation = disploc; +} + +/* + *+ miscelaneous functions + */ + +/*- 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); +} + +/*- intersectRect: return whether given two rectangles have a intersection -*/ +static Boolean +intersectRect(rect1, rect2) +register XRectangle *rect1; +register XRectangle *rect2; +{ + return (rect1->x + rect1->width <= rect2->x || + rect1->x >= rect2->x + rect2->width || + rect1->y + rect1->height <= rect2->y || + rect1->y >= rect2->y + rect2->height) ? False : True; +} + +/*- unionRect: returns a minimum rectangle that covers given two rectangles -*/ +static void +unionRect(rect1, rect2, rect_ret) +register XRectangle *rect1; +register XRectangle *rect2; +XRectangle *rect_ret; +{ + int x0, x1, y0, y1; + + x0 = (rect1->x > rect2->x) ? rect2->x : rect1->x; + y0 = (rect1->y > rect2->y) ? rect2->y : rect1->y; + x1 = (rect1->x + rect1->width > rect2->x + rect2->width) ? + rect1->x + rect1->width : rect2->x + rect2->width; + y1 = (rect1->y + rect1->height > rect2->y + rect2->height) ? + rect1->y + rect1->height : rect2->y + rect2->height; + + rect_ret->x = x0; + rect_ret->y = y0; + rect_ret->width = x1 - x0; + rect_ret->height = y1 - y0; +} + +static DisplayFragment *free_fragments = NULL; + +/*- allocDisplayFragment: get a new fragment -*/ +static DisplayFragment * +allocDisplayFragment() +{ + if (free_fragments == NULL) { + return XtNew(DisplayFragment); + } else { + DisplayFragment *dfp = free_fragments; + free_fragments = dfp->next; + return dfp; + } +} + +/*- freeDisplayFragments: add specified fragment list to the free-list -*/ +static void +freeDisplayFragments(fragments) +DisplayFragment *fragments; +{ + DisplayFragment *dfp = fragments; + + if (dfp == NULL) return; + while (dfp->next != NULL) dfp = dfp->next; + dfp->next = free_fragments; + free_fragments = fragments; +} + +/*- destroyDisplayFragments: do 'free()' specified fragment list -*/ +static void +destroyDisplayFragments(fragments) +DisplayFragment *fragments; +{ + DisplayFragment *dfp; + + while (fragments != NULL) { + dfp = fragments->next; + XtFree((char *)fragments); + fragments = dfp; + } +} + +/*- allocDisplaySegments: prepare specified number of display segments -*/ +static void +allocDisplaySegments(ocw, n) +OffTheSpotConversionWidget ocw; +Cardinal n; +{ + if (ocw->offthespot.dispsegmentsize > n) return; + n = ((n + 3) / 4) * 4 ; + if (ocw->offthespot.dispsegments == NULL) { + ocw->offthespot.dispsegments = (DisplaySegment *)XtMalloc(n * sizeof(DisplaySegment)); + } else { + ocw->offthespot.dispsegments = (DisplaySegment *)XtRealloc((char *)ocw->offthespot.dispsegments, n * sizeof(DisplaySegment)); + } + ocw->offthespot.dispsegmentsize = n; +} + +/*- freeDisplaySegment: free display segment's contents -*/ +static void +freeDisplaySegment(dsp) +DisplaySegment *dsp; +{ + freeString(&dsp->seg); + freeDisplayFragments(dsp->fragments); + dsp->fragments = NULL; +} + +/*- clearAllDisplaySegments: clear all display segment's -*/ +static void +clearAllDisplaySegments(ocw) +OffTheSpotConversionWidget ocw; +{ + DisplaySegment *dsp = ocw->offthespot.dispsegments; + int i; + + for (i = 0; i < ocw->offthespot.numsegments; i++) { + freeDisplaySegment(dsp++); + } + ocw->offthespot.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; +}