Mercurial > kinput2.yaz
diff lib/OverConv.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/OverConv.c Mon Mar 08 04:44:30 2010 +0900 @@ -0,0 +1,2708 @@ +#ifndef lint +static char *rcsid = "$Id: OverConv.c,v 1.71 1999/05/06 09:07:58 ishisone Exp $"; +#endif +/*- + * Copyright (c) 1990 Software Research Associates, Inc. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Software Research Associates not be + * used in advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. Software Research + * Associates makes no representations about the suitability of this software + * for any purpose. It is provided "as is" without express or implied + * warranty. + * + * Author: Makoto Ishisone, Software Research Associates, Inc., Japan + */ + +#include <X11/IntrinsicP.h> +#include <X11/StringDefs.h> +#include <X11/Xmu/CharSet.h> +#if XtSpecificationRelease > 4 +#include <X11/Xfuncs.h> +#endif +#include "CachedAtom.h" +#include "AsyncErr.h" +#include "OverConvP.h" +#include "InputConv.h" +#include "ConvDisp.h" +#include "CandPanel.h" +#include "AuxPanel.h" +#include "CanvasShel.h" +#include "ICLabel.h" + +#define DEBUG_VAR debug_OverTheSpotConversion +#include "DebugPrint.h" + +typedef enum { NeedNone, NeedRedraw, NeedReconfig } ResetStatus; + +/*- resource table -*/ +static XtResource resources[] = { +#define offset(field) XtOffset(OverTheSpotConversionWidget, overthespot.field) + { XtNspotX, XtCPosition, XtRPosition, sizeof(Position), + offset(spotx), XtRImmediate, (XtPointer)0 }, + { XtNspotY, XtCPosition, XtRPosition, sizeof(Position), + offset(spoty), XtRImmediate, (XtPointer)0 }, + { XtNautoSpotForwarding, XtCAutoSpotForwarding, XtRBoolean, sizeof(Boolean), + offset(spotforwarding), XtRImmediate, (XtPointer)False }, + { XtNlineSpacing, XtCLineSpacing, XtRDimension, sizeof(Dimension), + offset(linespacing), XtRImmediate, (XtPointer)0 }, + { XtNmodeLocation, XtCModeLocation, XtRModeLocation, sizeof(ModeLocation), + offset(modelocation), XtRString, "BottomLeft" }, + { XtNshrinkWindow, XtCShrinkWindow, XtRBoolean, sizeof(Boolean), + offset(shrinkwindow), XtRImmediate, (XtPointer)False }, + { XtNignoreStatusAreaSpec, XtCIgnoreStatusAreaSpec, + XtRBoolean, sizeof(Boolean), + offset(ignorestatusarea), XtRImmediate, (XtPointer)False }, + { XtNmodeBorderForeground, XtCModeBorderForeground, + XtRBoolean, sizeof(Boolean), + offset(borderforeground), XtRImmediate, (XtPointer)False }, + { XtNuseOverrideShellForMode, XtCUseOverrideShellForMode, + XtRBoolean, sizeof(Boolean), + offset(useoverride), XtRImmediate, (XtPointer)False }, + /* changes superclass's default */ + { XtNmappedWhenManaged, XtCMappedWhenManaged, XtRBoolean, sizeof(Boolean), + XtOffset(OverTheSpotConversionWidget, core.mapped_when_managed), + XtRImmediate, (XtPointer)False }, +#undef offset +}; + +/*- default translation table -*/ +static char translations[] = "<Key>: to-inputobj()"; /* same as superclass's */ + +/*- declarations of static functions -*/ +static void ClassInitialize(); +static void Initialize(); +static void Destroy(); +static Boolean SetValues(); + +static void ConversionStartup(); +static void ChangeAttributes(); +static void ChangeFocus(); +static void ConversionFinish(); + +static void CreateDisplayObject(); +static void CreateSelectionWidget(); +static void CreateModeWidget(); +static TextCanvas * CreateTextCanvas(); + +static void setupTextCanvas(); +static ResetStatus resetTextCanvas(); +static void setupDisplayObject(); +static ResetStatus resetDisplayObject(); +static void setupModeWidget(); +static ResetStatus resetModeWidget(); +static void locateTextCanvasInitial(); +static void locateModeWidget(); +static void locateTrackingModeWidget(); +static void redrawAndReconfigureTextCanvas(); + +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 void ForwardSpot(); + +static void CreateAuxWidget(); +static void AuxControl(); +static void AuxStart(); +static void locateAuxPopup(); +static void AuxEnd(); +static void AuxChange(); + + +static void TextRedisplay(); + +static void SelectionSelected(); + +static void computeDisplaySegments(); +static void recomputeDisplaySegments(); +static void computeLastPosition(); +static DisplayFragment *computeDisplayFragments(); +static int computeWidthAvailable(); +static void nextLocation(); +static DisplayLocation *findLocation(); +static void reconfigureDisplay(); +static void updateDisplay(); +static void updateDisplaySegment(); +static void redrawSegments(); + +static void adjustDisplay(); +static Boolean getAttributeSegmentRange(); +static Boolean getInsertingSegmentRange(); +static void adjustOffset(); + +static void eraseCursor(); +static void showCursor(); +static Boolean exposeCursor(); +static void computeCursor(); + +static void StringToModeLocation(); + +static void MoveShell(); +static Window getToplevelWindow(); +static void setTransientFor(); +static void setMwmHints(); +static void getFocusOffset(); +static Boolean intersectRect(); +static void unionRect(); +static int enoughSpaceForStatus(); +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, +}; + +/*- overTheSpotConversionClass record -*/ +OverTheSpotConversionClassRec overTheSpotConversionClassRec = { + { /* core fields */ + /* superclass */ (WidgetClass)&conversionControlClassRec, + /* class_name */ "OverTheSpotConversion", + /* widget_size */ sizeof(OverTheSpotConversionRec), + /* 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 */ XtInheritFix, + /* ModeChange */ UpdateMode, + /* SelectionControl */ SelectionControl, + /* SelectionControl */ AuxControl, + }, + { /* overTheSpotConversion fields */ + /* empty */ 0 + }, +}; + +WidgetClass overTheSpotConversionWidgetClass = (WidgetClass)&overTheSpotConversionClassRec; + +/* + *+ Convenience macros + */ +#define SPOTX(w) ((w)->overthespot.spotx) +#define SPOTY(w) ((w)->overthespot.spoty) +#define CLAREA(w) ((w)->overthespot.clientarea) +#define FOCUSOFFX(w) ((w)->overthespot.focusoffsetx) +#define FOCUSOFFY(w) ((w)->overthespot.focusoffsety) + +/* + *+ Core class methods + */ + +/*- ClassInitialize: add resource converter (string->modelocation) -*/ +/* ARGSUSED */ +static void +ClassInitialize() +{ + XtAddConverter(XtRString, XtRModeLocation, StringToModeLocation, + NULL, 0); +} + +/*- Initialize: initialize method -*/ +/* ARGSUSED */ +static void +Initialize(req, new, args, num_args) +Widget req; +Widget new; +ArgList args; +Cardinal *num_args; +{ + OverTheSpotConversionWidget ocw = (OverTheSpotConversionWidget)new; + + ocw->overthespot.background = ocw->core.background_pixel; + ocw->overthespot.canvaslist = NULL; + ocw->overthespot.overflowcanvas = NULL; + ocw->overthespot.dispsegments = NULL; + ocw->overthespot.numsegments = 0; + ocw->overthespot.dispsegmentsize = 0; + ocw->overthespot.candlist = NULL; + ocw->overthespot.numcands = 0; + ocw->overthespot.selectionpoppedup = False; + ocw->overthespot.cursorvisible = False; + ocw->overthespot.canvascursor = None; + ocw->overthespot.auxpoppedup = False; + + ocw->overthespot.wm_state = + CachedInternAtom(XtDisplay(new), "WM_STATE", False); + + /* $B%F%-%9%HI=<($N(B widget $B$O:G=i$NJQ493+;O;~$K:n$k(B */ + CreateDisplayObject(ocw); + CreateSelectionWidget(ocw); + CreateAuxWidget(ocw); + CreateModeWidget(ocw); +} + +/*- Destroy: destroy method -*/ +static void +Destroy(w) +Widget w; +{ + OverTheSpotConversionWidget ocw = (OverTheSpotConversionWidget)w; + + /* $B%G%#%9%W%l%$%;%0%a%s%H$NNN0h$r2rJ|(B */ + if (ocw->overthespot.dispsegments) { + DisplaySegment *dsp = ocw->overthespot.dispsegments; + int i; + + for (i = 0; i < ocw->overthespot.numsegments; i++) { + freeString(&dsp[i].seg); + destroyDisplayFragments(dsp->fragments); + } + XtFree((char *)dsp); + } + + /* canvaslist $B$NNN0h$r2rJ|(B (canvas widget $B$O(B $B<+F0E*$K(B destroy $B$5$l$k(B */ + if (ocw->overthespot.canvaslist) { + TextCanvas *p = ocw->overthespot.canvaslist; + while (p) { + TextCanvas *q = p->next; + XtFree((char *)p); + p = q; + } + } +} + +/*- SetValues: setvalues method -*/ +/* ARGSUSED */ +static Boolean +SetValues(cur, req, new, args, num_args) +Widget cur; +Widget req; +Widget new; +ArgList args; +Cardinal *num_args; +{ + /* OverTheSpotConversionWidget ocw = (OverTheSpotConversionWidget)new; */ + return False; +} + +/* + *+ ConversionControl cass methods + */ + +/*- ConversionStartup: class specific conversion startup -*/ +static void +ConversionStartup(w, mask, value) +Widget w; +unsigned long mask; +ConversionAttributes *value; +{ + OverTheSpotConversionWidget ocw = (OverTheSpotConversionWidget)w; + Widget inputobj = ocw->ccontrol.inputobj; + Window toplevel; + + TRACE(("OverTheSpot:ConversionStartup()\n")); + + /* $BFbIt$N%P%C%U%!$r%/%j%"$9$k(B */ + clearAllDisplaySegments(ocw); + + /* $BJQ49%*%V%8%'%/%H$K%3!<%k%P%C%/$r@_Dj$9$k(B */ + XtAddCallback(inputobj, XtNfixNotify, ForwardSpot, (XtPointer)w); + + if (ocw->overthespot.ignorestatusarea) mask &= ~CAStatusArea; + + setupDisplayObject(ocw, mask, value); + setupTextCanvas(ocw, mask, value); + setupModeWidget(ocw, mask, value); + + /* WM_TRANSIENT_FOR $B%W%m%Q%F%#$r@5$7$/%;%C%H$9$k(B */ + toplevel = getToplevelWindow(XtDisplay(w), + ocw->ccontrol.clientwindow, + ocw->overthespot.wm_state); + setTransientFor(ocw->overthespot.modeshell, toplevel); + setTransientFor(ocw->overthespot.selectionshell, toplevel); + setTransientFor(ocw->overthespot.auxshell, toplevel); + + /* $B%F%-%9%H%-%c%s%P%9$NI=<(0LCV$r7h$a$k(B */ + locateTextCanvasInitial(ocw); + + /* $B%b!<%I$NI=<(0LCV$r7h$a$k(B */ + if (!ocw->overthespot.modelocationspecified) locateModeWidget(ocw); + + /* + * OverTheSpotConvesion $B$N>l9g!"<+J,<+?H$O%]%C%W%"%C%W$7$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!"(BRealize $B$@$1$7$F$*$/(B + * $B$=$N:]!"Bg$-$5$r;XDj$7$J$$$H%5%$%:$,(B 0 $B$K$J$C$F$7$^$&$N$GCm0U$9$k(B + */ + if (!XtIsRealized(w)) { + Arg args[2]; + + XtSetArg(args[0], XtNwidth, 1); + XtSetArg(args[1], XtNheight, 1); + XtSetValues(w, args, 2); + XtRealizeWidget(w); + } + + /* $B%b!<%II=<(%-%c%s%P%9$r%]%C%W%"%C%W$9$k(B */ + if (ocw->overthespot.modeshell != NULL) { + XtPopup(ocw->overthespot.modeshell, XtGrabNone); + } +} + +/*- ChangeAttributes: class specific conversion attribute change routine -*/ +/* ARGSUSED */ +static void +ChangeAttributes(w, mask, value) +Widget w; +unsigned long mask; +ConversionAttributes *value; +{ + OverTheSpotConversionWidget ocw = (OverTheSpotConversionWidget)w; + ResetStatus dispres, tcres; + + TRACE(("OverTheSpot:ChangeAttributes()\n")); + + if (ocw->overthespot.ignorestatusarea) mask &= ~CAStatusArea; + + dispres = resetDisplayObject(ocw, mask, value); + tcres = resetTextCanvas(ocw, mask, value); + if (dispres == NeedReconfig || tcres == NeedReconfig) { + redrawAndReconfigureTextCanvas(ocw); + } else if (dispres == NeedRedraw || tcres == NeedRedraw) { + TextCanvas *tcp = ocw->overthespot.canvaslist; + + while (tcp != NULL) { + if (XtIsRealized(tcp->canvas)) { + XClearArea(XtDisplay(tcp->canvas), XtWindow(tcp->canvas), + 0, 0, 0, 0, True); + } + tcp = tcp->next; + } + } + + if (resetModeWidget(ocw, mask, value) != NeedNone && + XtIsRealized(ocw->overthespot.modewidget)) { + XClearArea(XtDisplay(w), XtWindow((Widget)ocw->overthespot.modewidget), + 0, 0, 0, 0, True); + } +} + +/*- ChangeFocus: class specific conversion attribute change routine -*/ +static void +ChangeFocus(w, set) +Widget w; +int set; +{ + OverTheSpotConversionWidget ocw = (OverTheSpotConversionWidget)w; + + TRACE(("OverTheSpot:ChangeFocus()\n")); + + if (ocw->overthespot.modeshell == NULL) return; + if (set) { + XtPopup(ocw->overthespot.modeshell, XtGrabNone); + } else { + XtPopdown(ocw->overthespot.modeshell); + } +} + +/*- ConversionFinish: class specific conversion finish -*/ +/* ARGSUSED */ +static void +ConversionFinish(w) +Widget w; +{ + OverTheSpotConversionWidget ocw = (OverTheSpotConversionWidget)w; + Widget inputobj = ocw->ccontrol.inputobj; + TextCanvas *tcp = ocw->overthespot.canvaslist; + XAEHandle h; + + /* $BJQ49%*%V%8%'%/%H$N%3!<%k%P%C%/$r>C$9(B */ + XtRemoveCallback(inputobj, XtNfixNotify, ForwardSpot, (XtPointer)w); + + /* Popdown and unrealize textcanvases + * we must be careful here. if clientwindow are destroyed, + * the text canvases are also destroyed. + * we have to popdown and unrealize canvas 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)); + while (tcp != NULL) { + if (tcp->poppedup) XtPopdown(tcp->canvas); + XtUnrealizeWidget(tcp->canvas); + /* XtVaSetValues(tcp->canvas, XtNcursor, None, NULL); */ + tcp->poppedup = False; + tcp = tcp->next; + } + /* Popdown mode widget */ + if (ocw->overthespot.modeshell != NULL) { + XtPopdown(ocw->overthespot.modeshell); + } + if (ocw->overthespot.modeshell == ocw->overthespot.modeshell_fix) { + XtUnrealizeWidget(ocw->overthespot.modeshell); + } + XAEUnset(h); + + /* Popdown selection popup (if popped-up) */ + if (ocw->overthespot.selectionpoppedup) { + XtPopdown(ocw->overthespot.selectionshell); + ocw->overthespot.selectionpoppedup = False; + } + if (ocw->overthespot.auxpoppedup) { + XtPopdown(ocw->overthespot.auxshell); + ocw->overthespot.auxpoppedup = False; + } +} + +/* + *+ sub-widget creation + */ + +/*- CreateDisplayObject: create display object for text drawing -*/ +static void +CreateDisplayObject(ocw) +OverTheSpotConversionWidget ocw; +{ + Widget dispobj; + + dispobj = XtCreateWidget("displayObj", ocw->ccontrol.displayobjclass, + (Widget)ocw, NULL, 0); + + ocw->overthespot.displayobj = dispobj; + ocw->overthespot.lineheight = CDLineHeight(dispobj, + &ocw->overthespot.ascent); + +} + +/*- CreateSelectionWidget: create selection widget for selecting candidates -*/ +static void +CreateSelectionWidget(ocw) +OverTheSpotConversionWidget ocw; +{ + Widget shell, sel, obj; + + shell = XtVaCreatePopupShell("selectionShell", + transientShellWidgetClass, + (Widget)ocw, + XtNwidth, 1, XtNheight, 1, + NULL); + ocw->overthespot.selectionshell = shell; + + sel = XtCreateManagedWidget("selection", candidatePanelWidgetClass, + shell, NULL, 0); + obj = XtCreateWidget("display", ocw->ccontrol.displayobjclass, + sel, NULL, 0); + XtAddCallback(sel, XtNcallback, SelectionSelected, (Widget)ocw); + XtInstallAccelerators(sel, (Widget)ocw); + + ocw->overthespot.selectionwidget = sel; + ocw->overthespot.selectiondisplayobj = obj; +} + +/*- CreateAuxWidget: create auxiliary widget for displaying auxiliary data -*/ +static void +CreateAuxWidget(ocw) +OverTheSpotConversionWidget ocw; +{ + Widget shell, sel, obj; + + shell = XtVaCreatePopupShell("auxShell", + transientShellWidgetClass, + (Widget)ocw, + XtNwidth, 1, XtNheight, 1, + XtNallowShellResize, True, + NULL); + ocw->overthespot.auxshell = shell; + + sel = XtCreateManagedWidget("aux", auxPanelWidgetClass, + shell, NULL, 0); + obj = XtCreateWidget("display", ocw->ccontrol.displayobjclass, + sel, NULL, 0); + XtAddCallback(sel, XtNcallback, SelectionSelected, (Widget)ocw); + XtInstallAccelerators(sel, (Widget)ocw); + + ocw->overthespot.auxwidget = sel; + ocw->overthespot.auxdisplayobj = obj; +} + +/*- CreateModeWidget: create mode displaying widget -*/ +static void +CreateModeWidget(ocw) +OverTheSpotConversionWidget ocw; +{ + Widget shell, w, obj; + + TRACE(("CreateModeWidget()\n")); + + /* create fixed widget */ + shell = XtCreatePopupShell("modeShell", adoptedShellWidgetClass, + (Widget)ocw, NULL, 0); + XtVaGetValues(shell, XtNborderWidth, &ocw->overthespot.saved_bw, NULL); + w = XtCreateManagedWidget("mode", icLabelWidgetClass, shell, NULL, 0); + obj = XtCreateWidget("display", ocw->ccontrol.displayobjclass, w, + NULL, 0); + XtInstallAccelerators(shell, (Widget)ocw); + XtInstallAccelerators(w, (Widget)ocw); + ocw->overthespot.modeshell_fix = shell; + ocw->overthespot.modewidget_fix = w; + ocw->overthespot.modedisplayobj_fix = obj; + + /* create floating widget */ + if (ocw->overthespot.useoverride) { + shell = XtCreatePopupShell("modeShell", overrideShellWidgetClass, + (Widget)ocw, NULL, 0); + } else { + shell = XtCreatePopupShell("modeShell", transientShellWidgetClass, + (Widget)ocw, NULL, 0); + } + w = XtCreateManagedWidget("mode", icLabelWidgetClass, shell, NULL, 0); + obj = XtCreateWidget("display", ocw->ccontrol.displayobjclass, w, + NULL, 0); + XtInstallAccelerators(shell, (Widget)ocw); + XtInstallAccelerators(w, (Widget)ocw); + ocw->overthespot.modeshell_float = shell; + ocw->overthespot.modewidget_float = w; + ocw->overthespot.modedisplayobj_float = obj; + + /* set mwm hints for the shell */ + setMwmHints(shell); +} + +/*- CreateTextCanvas: create a text canvas -*/ +static TextCanvas * +CreateTextCanvas(ocw) +OverTheSpotConversionWidget ocw; +{ + TextCanvas *tcp; + + tcp = XtNew(TextCanvas); + tcp->x = 0; + tcp->y = 0; + tcp->poppedup = False; + tcp->next = NULL; + tcp->canvas = XtVaCreatePopupShell("text", + canvasShellWidgetClass, + (Widget)ocw, + XtNcolormap, + ocw->overthespot.colormap, + XtNbackground, + ocw->overthespot.background, + XtNparentWindow, + ocw->ccontrol.clientwindow, + XtNoverrideRedirect, True, + NULL); /* XXX for now XXX */ + XtAddCallback(tcp->canvas, XtNexposeCallback, TextRedisplay, (XtPointer)ocw); + XtInstallAccelerators(tcp->canvas, (Widget)ocw); + + return tcp; +} + + +/* + *+ subwidget configuration + */ + +/*- setupTextCanvas: do text canvas configuration on conversion startup -*/ +static void +setupTextCanvas(ocw, mask, value) +OverTheSpotConversionWidget ocw; +unsigned long mask; +ConversionAttributes *value; +{ + TRACE(("setupTextCanvas(mask=0x%lx)\n", mask)); + + getFocusOffset(ocw); + + if (mask & CAClientArea) { + CLAREA(ocw) = value->clientarea; + } else { + /* default */ + CLAREA(ocw).x = 0; + CLAREA(ocw).y = 0; + CLAREA(ocw).width = ocw->ccontrol.focus_attr.width; + CLAREA(ocw).height = ocw->ccontrol.focus_attr.height; + } + CLAREA(ocw).x += FOCUSOFFX(ocw); + CLAREA(ocw).y += FOCUSOFFY(ocw); + + TRACE(("\tclientarea: (%d,%d)-(%d,%d)\n",CLAREA(ocw).x,CLAREA(ocw).y,CLAREA(ocw).width,CLAREA(ocw).height)); + if (mask & CASpotLocation) { + SPOTX(ocw) = value->spotx + FOCUSOFFX(ocw); + SPOTY(ocw) = value->spoty + FOCUSOFFY(ocw); + } else { + /* default */ + SPOTX(ocw) = CLAREA(ocw).x; + SPOTY(ocw) = CLAREA(ocw).y + ocw->overthespot.ascent; + } + TRACE(("\tspotlocation: (%d,%d)\n",SPOTX(ocw),SPOTY(ocw))); + + if (mask & CALineSpacing) { + ocw->overthespot.linespacing = value->linespacing; + if (ocw->overthespot.linespacing == 0) { + DPRINT(("\tspecified linespacing is 0. reset to default\n")); + ocw->overthespot.linespacing = ocw->overthespot.lineheight; + } + } else { + ocw->overthespot.linespacing = ocw->overthespot.lineheight; + } + if (mask & CAColormap) { + ocw->overthespot.colormap = value->colormap; + } else { + ocw->overthespot.colormap = DefaultColormapOfScreen(XtScreen((Widget)ocw)); + } + if (mask & CAColor) { + ocw->overthespot.background = value->background; + } else { + /* default */ + ocw->overthespot.background = ocw->core.background_pixel; + } + if (mask & CACursor) { + ocw->overthespot.canvascursor = value->cursor; + } else { + ocw->overthespot.canvascursor = None; + } + + if (ocw->overthespot.canvaslist == NULL) { + ocw->overthespot.canvaslist = CreateTextCanvas(ocw); + } else { + TextCanvas *tcp = ocw->overthespot.canvaslist; + while (tcp != NULL) { + XtVaSetValues(tcp->canvas, + XtNcolormap, ocw->overthespot.colormap, + XtNbackground, ocw->overthespot.background, + XtNparentWindow, ocw->ccontrol.clientwindow, + XtNcursor, ocw->overthespot.canvascursor, + NULL); + tcp = tcp->next; + } + } +} + +/*- resetTextCanvas: do text canvas reconfiguration on attribute change -*/ +static ResetStatus +resetTextCanvas(ocw, mask, value) +OverTheSpotConversionWidget ocw; +unsigned long mask; +ConversionAttributes *value; +{ + ResetStatus redraw = NeedNone; + + if (mask & (CAColormap|CAColor|CACursor)) { + Arg args[3]; + Cardinal i = 0; + if (mask & CAColormap && + value->colormap != ocw->overthespot.colormap) { + ocw->overthespot.colormap = value->colormap; + XtSetArg(args[i], XtNcolormap, value->colormap); i++; + } + if (mask & CAColor && + value->background != ocw->overthespot.background) { + ocw->overthespot.background = value->background; + XtSetArg(args[i], XtNbackground, value->background); i++; + } + if (mask & CACursor && + value->cursor != ocw->overthespot.canvascursor) { + ocw->overthespot.canvascursor = value->cursor; + XtSetArg(args[i], XtNcursor, value->cursor); i++; + } + if (i > 0) { + TextCanvas *tcp = ocw->overthespot.canvaslist; + + while (tcp != NULL) { + XtSetValues(tcp->canvas, args, i); + tcp = tcp->next; + } + redraw = NeedRedraw; + } + } + if (mask & CAFocusWindow) { + getFocusOffset(ocw); + redraw = NeedReconfig; + } + if (mask & CAClientArea) { + if (value->clientarea.x + FOCUSOFFX(ocw) != CLAREA(ocw).x || + value->clientarea.y + FOCUSOFFY(ocw) != CLAREA(ocw).y || + value->clientarea.width != CLAREA(ocw).width || + value->clientarea.height != CLAREA(ocw).height) { + CLAREA(ocw) = value->clientarea; + CLAREA(ocw).x += FOCUSOFFX(ocw); + CLAREA(ocw).y += FOCUSOFFY(ocw); + redraw = NeedReconfig; + } + } else if (mask & CAFocusWindow) { + CLAREA(ocw).x = FOCUSOFFX(ocw); + CLAREA(ocw).y = FOCUSOFFY(ocw); + CLAREA(ocw).width = ocw->ccontrol.focus_attr.width; + CLAREA(ocw).height = ocw->ccontrol.focus_attr.height; + } + if (mask & CASpotLocation) { + if (value->spotx + FOCUSOFFX(ocw) != SPOTX(ocw) || + value->spoty + FOCUSOFFY(ocw) != SPOTY(ocw)) { + SPOTX(ocw) = value->spotx + FOCUSOFFX(ocw); + SPOTY(ocw) = value->spoty + FOCUSOFFY(ocw); + redraw = NeedReconfig; + } + } else if (mask & CAFocusWindow) { + SPOTX(ocw) = CLAREA(ocw).x; + SPOTY(ocw) = CLAREA(ocw).y + ocw->overthespot.ascent; + } + if (mask & CALineSpacing) { + if (value->linespacing != ocw->overthespot.linespacing && + value->linespacing != 0) { + ocw->overthespot.linespacing = value->linespacing; + redraw = NeedReconfig; + } + } else if (mask & CAFonts) { + ocw->overthespot.linespacing = ocw->overthespot.lineheight; + redraw = NeedReconfig; + } + + return redraw; +} + +/*- setupDisplayObject: do displayobj configuration on conversion startup -*/ +static void +setupDisplayObject(ocw, mask, value) +OverTheSpotConversionWidget ocw; +unsigned long mask; +ConversionAttributes *value; +{ + Widget dispobj = ocw->overthespot.displayobj; + + TRACE(("setupDisplayObject()\n")); + + /* + * 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) { + TRACE(("\tchanging fonts...\n")); + CDSetFonts(dispobj, value->fonts, value->num_fonts); + } else { + /* reset to default */ + CDSetFonts(dispobj, (XFontStruct **)NULL, 0); + } + if (mask & CAColor) { + TRACE(("\tchanging colors...\n")); + XtVaSetValues(dispobj, + XtNforeground, value->foreground, + XtNbackground, value->background, + NULL); + } + ocw->overthespot.lineheight = CDLineHeight(dispobj, + &ocw->overthespot.ascent); +} + +/*- resetDisplayObject: do displayobj reconfiguration on attribute change -*/ +static ResetStatus +resetDisplayObject(ocw, mask, value) +OverTheSpotConversionWidget ocw; +unsigned long mask; +ConversionAttributes *value; +{ + Widget dispobj = ocw->overthespot.displayobj; + ResetStatus redraw = NeedNone; + + TRACE(("resetDisplayObject()\n")); + + if (mask & CAColor) { + TRACE(("\tchanging colors...\n")); + XtVaSetValues(dispobj, + XtNforeground, value->foreground, + XtNbackground, value->background, + NULL); + redraw = NeedRedraw; + } + if (mask & CAFonts) { + TRACE(("\tchanging fonts...\n")); + CDSetFonts(dispobj, value->fonts, value->num_fonts); + ocw->overthespot.lineheight = CDLineHeight(dispobj, + &ocw->overthespot.ascent); + redraw = NeedReconfig; + } + + return redraw; +} + +/*- setupModeWidget: do mode widget configuration on conversion startup -*/ +static void +setupModeWidget(ocw, mask, value) +OverTheSpotConversionWidget ocw; +unsigned long mask; +ConversionAttributes *value; +{ + Widget inputobj = ocw->ccontrol.inputobj; + Widget dispobj; + Widget mode; + Arg modeargs[10]; + Arg shellargs[15]; + Cardinal i = 0, j = 0; + + TRACE(("setupModeWidget()\n")); + + /* choose appropriate widgets */ + if (mask & CAStatusArea) { + /* use fixed modedisplay */ + ocw->overthespot.modeshell = ocw->overthespot.modeshell_fix; + ocw->overthespot.modewidget = ocw->overthespot.modewidget_fix; + ocw->overthespot.modedisplayobj = ocw->overthespot.modedisplayobj_fix; + XtSetArg(shellargs[j], XtNparentWindow, ocw->ccontrol.clientwindow); j++; + XtSetArg(shellargs[j], XtNborderWidth, 0); j++; + XtSetArg(shellargs[j], XtNallowShellResize, False); j++; + XtSetArg(shellargs[j], XtNx, value->statusarea.x); j++; + XtSetArg(shellargs[j], XtNy, value->statusarea.y); j++; + XtSetArg(shellargs[j], XtNwidth, value->statusarea.width); j++; + XtSetArg(shellargs[j], XtNheight, value->statusarea.height); j++; + ocw->overthespot.modelocationspecified = True; + } else if (ocw->overthespot.modelocation == ModeTrackText && + enoughSpaceForStatus(ocw)) { + ocw->overthespot.modeshell = ocw->overthespot.modeshell_fix; + ocw->overthespot.modewidget = ocw->overthespot.modewidget_fix; + ocw->overthespot.modedisplayobj = ocw->overthespot.modedisplayobj_fix; + ocw->overthespot.modelocationspecified = False; + XtSetArg(shellargs[j], XtNparentWindow, ocw->ccontrol.clientwindow); j++; + XtSetArg(shellargs[j], XtNallowShellResize, True); j++; + XtSetArg(shellargs[j], XtNborderWidth, ocw->overthespot.saved_bw); j++; + } else if (ocw->overthespot.modelocation == ModeNone) { + ocw->overthespot.modeshell = NULL; + ocw->overthespot.modewidget = NULL; + ocw->overthespot.modedisplayobj = NULL; + ocw->overthespot.modelocationspecified = False; + return; + } else { + /* use floating modedisplay */ + ocw->overthespot.modeshell = ocw->overthespot.modeshell_float; + ocw->overthespot.modewidget = ocw->overthespot.modewidget_float; + ocw->overthespot.modedisplayobj = ocw->overthespot.modedisplayobj_float; + ocw->overthespot.modelocationspecified = False; + } + + mode = ocw->overthespot.modewidget; + dispobj = ocw->overthespot.modedisplayobj; + + XtSetArg(modeargs[i], XtNlabel, ICGetMode(inputobj)); i++; + if (mask & CAColormap) { + XtSetArg(modeargs[i], XtNcolormap, value->colormap); i++; + } + /* ignore background_pixmap... */ + + /* + * order of changing display object resources is important. + * see comment in setupDisplayObject() for details. + */ + if (mask & CAStatusFonts) { + TRACE(("\tchanging fonts...\n")); + CDSetFonts(dispobj, value->status_fonts, value->num_status_fonts); + } else { + /* reset to default */ + CDSetFonts(dispobj, (XFontStruct **)NULL, 0); + } + if (mask & CAColor) { + TRACE(("\tchanging colors...\n")); + XtVaSetValues(dispobj, + XtNforeground, value->foreground, + XtNbackground, value->background, + NULL); + XtSetArg(modeargs[i], XtNbackground, value->background); i++; + if (ocw->overthespot.borderforeground) { + XtSetArg(shellargs[j], XtNborderColor, value->foreground); j++; + } + } else { + XtSetArg(modeargs[i], XtNbackground, ocw->overthespot.background); i++; + } + + XtSetValues(mode, modeargs, i); + ICLRecomputeSize(mode); + + if (!(mask & CAStatusArea)) { + /* + * force shell to resize. + * it is because Shell doesn't honor its child's dimension + * at second (or later) realization. + */ + XtSetArg(shellargs[j], XtNwidth, mode->core.width); j++; + XtSetArg(shellargs[j], XtNheight, mode->core.height); j++; + } + XtSetValues(ocw->overthespot.modeshell, shellargs, j); +} + +/*- resetModeWidget: do mode widget reconfiguration on attribute change -*/ +static ResetStatus +resetModeWidget(ocw, mask, value) +OverTheSpotConversionWidget ocw; +unsigned long mask; +ConversionAttributes *value; +{ + Widget mode = ocw->overthespot.modewidget; + Widget dispobj = ocw->overthespot.modedisplayobj; + ResetStatus redraw = NeedNone; + + TRACE(("resetModeWidget()\n")); + + if (ocw->overthespot.modeshell == NULL) return NeedNone; + + if (mask & CAStatusArea) { + if (ocw->overthespot.modelocationspecified && + ocw->overthespot.modeshell == ocw->overthespot.modeshell_fix) { + XtVaSetValues(ocw->overthespot.modeshell, + XtNx, value->statusarea.x, + XtNy, value->statusarea.y, + XtNwidth, value->statusarea.width, + XtNheight, value->statusarea.height, + NULL); + } /* else ignore... */ + } + + if (mask & CAColormap) { + XtVaSetValues(mode, XtNcolormap, value->colormap, NULL); + } + + if (mask & CAColor) { + TRACE(("\tchanging colors...\n")); + XtVaSetValues(dispobj, + XtNforeground, value->foreground, + XtNbackground, value->background, + NULL); + XtVaSetValues(mode, XtNbackground, value->background, NULL); + if (ocw->overthespot.borderforeground) { + XtVaSetValues(ocw->overthespot.modeshell, + XtNborderColor, value->foreground, + NULL); + } + redraw = NeedRedraw; + } + if (mask & CAStatusFonts) { + TRACE(("\tchanging fonts...\n")); + CDSetFonts(dispobj, value->status_fonts, value->num_status_fonts); + ICLRecomputeSize(mode); + redraw = NeedRedraw; + } + + return redraw; +} + +/*- locateTextCanvasInitial: put the text canvas at the initial position -*/ +static void +locateTextCanvasInitial(ocw) +OverTheSpotConversionWidget ocw; +{ + TextCanvas *tcp = ocw->overthespot.canvaslist; + + tcp->x = SPOTX(ocw); + tcp->y = SPOTY(ocw) - ocw->overthespot.ascent; +} + +/*- locateModeWidget: put the mode widget at the initial position -*/ +static void +locateModeWidget(ocw) +OverTheSpotConversionWidget ocw; +{ + Position x, y; + Widget modewidget = ocw->overthespot.modewidget; + Widget modeshell = ocw->overthespot.modeshell; + int rootx, rooty; + Window child; + + if (modeshell == ocw->overthespot.modeshell_fix) { + /* must be tracking text type */ + locateTrackingModeWidget(ocw, True, 0, 0); + return; + } + + switch (ocw->overthespot.modelocation) { + case ModeTopLeft: + x = 0; + y = -(modewidget->core.height + modeshell->core.border_width * 2); + y -= ocw->ccontrol.titlebarheight; + break; + case ModeTopRight: + x = ocw->ccontrol.client_attr.width - modewidget->core.width + modeshell->core.border_width * 2; + y = -(modewidget->core.height + modeshell->core.border_width * 2); + y -= ocw->ccontrol.titlebarheight; + break; + case ModeBottomRight: + x = ocw->ccontrol.client_attr.width - modewidget->core.width + modeshell->core.border_width * 2; + y = ocw->ccontrol.client_attr.height; + break; + case ModeTrackText: /* in case of insufficient space in the client area */ + x = CLAREA(ocw).x; + y = CLAREA(ocw).y + CLAREA(ocw).height + 2; + break; + case ModeBottomLeft: + x = 0; + y = ocw->ccontrol.client_attr.height; + break; + default: + /* ModeNone */ + return; + } + + (void)XTranslateCoordinates(XtDisplay(ocw), ocw->ccontrol.clientwindow, + RootWindowOfScreen(XtScreen(ocw)), + x, y, &rootx, &rooty, &child); + MoveShell(ocw->overthespot.modeshell, rootx, rooty); +} + +/*- locateTrackingModeWidget: put the tracking text type mode widget at appropriate position */ +static void +locateTrackingModeWidget(ocw, initial, x, y) +OverTheSpotConversionWidget ocw; +Boolean initial; +Position x; +Position y; +{ + Widget modewidget = ocw->overthespot.modewidget; + Widget modeshell = ocw->overthespot.modeshell; + Dimension width, height; + XRectangle *clarea = &CLAREA(ocw); + static Position lastx, lasty; + + if (initial) { + x = SPOTX(ocw); + y = SPOTY(ocw) - ocw->overthespot.ascent + + ocw->overthespot.lineheight; + } else if (x == lastx && y == lasty) { + return; + } + + lastx = x; + lasty = y; + + width = modewidget->core.width + modeshell->core.border_width * 2; + height = modewidget->core.height + modeshell->core.border_width * 2; + + /* adjust x */ + if (x + width > clarea->x + clarea->width) { + x = clarea->x + clarea->width - width; + } + if (x < clarea->x) x = clarea->x; + + /* adjust y */ + if (y + height + 2 <= clarea->y + clarea->height) { + y += 2; /* make some (2pixels high) space between text and mode */ + } else if (y + height > clarea->y + clarea->height) { + Position initx, inity; + + if (initial) { + initx = SPOTX(ocw); + inity = SPOTY(ocw) - ocw->overthespot.ascent; + } else { + TextCanvas *tcp = ocw->overthespot.canvaslist; + initx = tcp->x; + inity = tcp->y; + } + if (inity - height > clarea->y) { + y = inity - height; + } else if (x + width < initx) { + y = inity - modeshell->core.border_width * 2; + } else if (clarea->x + width < initx) { + x = initx - width; + y = inity - modeshell->core.border_width * 2; + } else { + x = initx - width; + y = inity - height; + } + if (y < clarea->y) y = clarea->y; + } + XtMoveWidget(modeshell, x, y); +} + +/*- redrawAndReconfigureTextCanvas: redraw & reconfigure text canvas -*/ +static void +redrawAndReconfigureTextCanvas(ocw) +OverTheSpotConversionWidget ocw; +{ + TextCanvas *tcp = ocw->overthespot.canvaslist; + + TRACE(("OverTheSpotConversion:redrawAndReconfigureTextCanvas()\n")); + + /* popdown and clear all canvases */ + while (tcp != NULL) { + if (tcp->poppedup) XtPopdown(tcp->canvas); + tcp->poppedup = False; + if (XtIsRealized(tcp->canvas)) { + XClearArea(XtDisplay(tcp->canvas), XtWindow(tcp->canvas), + 0, 0, 0, 0, True); + } + tcp = tcp->next; + } + locateTextCanvasInitial(ocw); + recomputeDisplaySegments(ocw); + computeCursor(ocw); + reconfigureDisplay(ocw); +} + +/* + *+ inputobject callback + */ + +/*- UpdateText: update text -*/ +static void +UpdateText(w) +Widget w; +{ + OverTheSpotConversionWidget ocw = (OverTheSpotConversionWidget)w; + + TRACE(("OverTheSpotConversion:UpdateText()\n")); + eraseCursor(ocw); + computeDisplaySegments(ocw); + computeCursor(ocw); + reconfigureDisplay(ocw); + updateDisplay(ocw); + showCursor(ocw); +} + +/*- UpdateMode: update mode -*/ +static void +UpdateMode(w) +Widget w; +{ + OverTheSpotConversionWidget ocw = (OverTheSpotConversionWidget)w; + + if (ocw->overthespot.modewidget == NULL) return; + + XtVaSetValues(ocw->overthespot.modewidget, + XtNlabel, ICGetMode(ocw->ccontrol.inputobj), + NULL); +#ifdef notdef + /* a hack... */ + if (ocw->overthespot.modeshell == ocw->overthespot.modeshell_float && + XtIsRealized(ocw->overthespot.modeshell)) { + XRaiseWindow(XtDisplay(ocw->overthespot.modeshell), + XtWindow(ocw->overthespot.modeshell)); + } +#endif +} + +/*- SelectionControl: selection control -*/ +static void +SelectionControl(w, arg) +Widget w; +ICSelectionControlArg *arg; +{ + OverTheSpotConversionWidget ocw = (OverTheSpotConversionWidget)w; + + 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: + XtAppWarning(XtWidgetToApplicationContext(w), + "OverTheSpotConversion: unknown selection control command"); + break; + } +} + +/*- SelectionStart: selection startup -*/ +/* ARGSUSED */ +static void +SelectionStart(ocw, kind) +OverTheSpotConversionWidget ocw; +int kind; +{ + Cardinal ncand; + + TRACE(("OverTheSpotConversion:SelectionStart()\n")); + if (ocw->overthespot.selectionpoppedup) { + DPRINT(("\tselection already started -- ignored\n")); + return; + } + + ocw->overthespot.candlist = ICGetItemList(ocw->ccontrol.inputobj, &ncand); + ocw->overthespot.numcands = ncand; + + TRACE(("\tnumcands=%d\n", ocw->overthespot.numcands)); + CPanelSetList(ocw->overthespot.selectionwidget, + ocw->overthespot.candlist, + ocw->overthespot.numcands, 0, True); + + locateSelectionPopup(ocw); + XtPopup(ocw->overthespot.selectionshell, XtGrabNone); + ocw->overthespot.selectionpoppedup = True; +} + +/*- locateSelectionPopup: put selection popup at an appropriate position -*/ +static void +locateSelectionPopup(ocw) +OverTheSpotConversionWidget ocw; +{ + Position x, y; + int clx, cly; + Dimension dpyWidth, dpyHeight; + Widget panel = ocw->overthespot.selectionwidget; + Widget shell = ocw->overthespot.selectionshell; + Window junk; + int barheight = ocw->ccontrol.titlebarheight; + + (void)XTranslateCoordinates(XtDisplay(ocw), + ocw->ccontrol.clientwindow, + RootWindowOfScreen(XtScreen(ocw)), + 0, 0, &clx, &cly, &junk); + + if (ocw->overthespot.numsegments > 0) { + DisplayLocation lastp; + DisplaySegment *dsp = ocw->overthespot.dispsegments; + int i; + int offset = 0; + + /* find current segment. if not found, use last segment */ + for (i = 0; i < ocw->overthespot.numsegments - 1; i++) { + if (dsp[i].seg.attr & ICAttrCurrentSegment) break; + } + + computeLastPosition(dsp[i].fragments, &lastp); + if (lastp.canvas == ocw->overthespot.overflowcanvas) { + offset = ocw->overthespot.overflowoffset; + } + x = clx + lastp.canvas->x + lastp.x + - panel->core.width / 2 + offset; + y = cly + lastp.canvas->y + lastp.y + ocw->overthespot.lineheight; + } else { + x = clx + SPOTX(ocw) - panel->core.width / 2; + y = cly + SPOTY(ocw); + } + + 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 (y + panel->core.height + barheight > (int)dpyHeight) { + y = cly + SPOTY(ocw) - panel->core.height - barheight; + if (y < 0) y = dpyHeight - panel->core.height - barheight; + } + MoveShell(shell, x, y); +} + +/*- SelectionEnd: selection finish -*/ +static void +SelectionEnd(ocw, current) +OverTheSpotConversionWidget ocw; +int *current; +{ + TRACE(("OverTheSpotConversion:SelectionEnd()\n")); + + if (!ocw->overthespot.selectionpoppedup) { /* for safe */ + TRACE(("\tnot in selection mode -- ignored\n")); + return; + } + + XtVaGetValues(ocw->overthespot.selectionwidget, + XtNcurrentItem, current, + NULL); + + XtPopdown(ocw->overthespot.selectionshell); + + ocw->overthespot.selectionpoppedup = False; +} + +/*- SelectionSet: set current selection item -*/ +static void +SelectionSet(ocw, current) +OverTheSpotConversionWidget ocw; +int current; +{ + TRACE(("OverTheSpotConversion:SelectionSet()\n")); + + if (!ocw->overthespot.selectionpoppedup) { /* for safe */ + TRACE(("\tnot in selection mode -- ignored\n")); + return; + } + + XtVaSetValues(ocw->overthespot.selectionwidget, + XtNcurrentItem, current, + NULL); +} + +/*- SelectionGet: get current selection item -*/ +static void +SelectionGet(ocw, current) +OverTheSpotConversionWidget ocw; +int *current; +{ + TRACE(("OverTheSpotConversion:SelectionGet()\n")); + + if (!ocw->overthespot.selectionpoppedup) { /* for safe */ + TRACE(("\tnot in selection mode -- ignored\n")); + return; + } + + XtVaGetValues(ocw->overthespot.selectionwidget, + XtNcurrentItem, current, + NULL); +} + +/*- SelectionMove: move crrent selection to specified direction -*/ +static void +SelectionMove(ocw, dir) +OverTheSpotConversionWidget ocw; +int dir; +{ + TRACE(("OverTheSpotConversion:SelectionMove()\n")); + + if (!ocw->overthespot.selectionpoppedup) { /* for safe */ + TRACE(("\tnot in selection mode -- ignored\n")); + return; + } + + CPanelMoveCurrent(ocw->overthespot.selectionwidget, dir); +} + +/*- ForwardSpot: forward spot location when text is fixed -*/ +/* ARGSUSED */ +static void +ForwardSpot(w, client_data, call_data) +Widget w; +XtPointer client_data; +XtPointer call_data; +{ + OverTheSpotConversionWidget ocw = (OverTheSpotConversionWidget)client_data; + DisplaySegment *dsp = ocw->overthespot.dispsegments; + Cardinal nsegs = ocw->overthespot.numsegments; + DisplayLocation disploc; + + if (!ocw->overthespot.spotforwarding || nsegs == 0) return; + + /* get next spot location */ + computeLastPosition(dsp[nsegs - 1].fragments, &disploc); + + SPOTX(ocw) = disploc.canvas->x + disploc.x; + SPOTY(ocw) = disploc.canvas->y + disploc.y + ocw->overthespot.ascent; + locateTextCanvasInitial(ocw); +} + +/* + * Aux Callback + */ + +static void +AuxControl(w, arg) +Widget w; +ICAuxControlArg *arg; +{ + OverTheSpotConversionWidget ocw = (OverTheSpotConversionWidget)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) +OverTheSpotConversionWidget ocw; +{ + ICString *auxstr; + Cardinal ncand, curseg, cursorpos; + + if (ocw->overthespot.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->overthespot.auxwidget, auxstr, ncand, curseg, cursorpos); + + /* $B%]%C%W%"%C%W$9$k>l=j$r7h$a$k(B */ + locateAuxPopup(ocw, False); + + XtPopup(ocw->overthespot.auxshell, XtGrabNone); + ocw->overthespot.auxpoppedup = True; +} + +/* ARGSUSED */ +static void +AuxEnd(ocw) +OverTheSpotConversionWidget ocw; +{ + if (!ocw->overthespot.auxpoppedup) return; /* for safe */ + +/* APanelEnd(ocw->overthespot.auxwidget); */ + + XtPopdown(ocw->overthespot.auxshell); + + ocw->overthespot.auxpoppedup = False; +} + +/* ARGSUSED */ +static void +AuxChange(ocw) +OverTheSpotConversionWidget ocw; +{ + Cardinal ncand, curseg, cursorpos; + ICString *auxstr; + + if (!ocw->overthespot.auxpoppedup) return; /* for safe */ + + auxstr = ICGetAuxSegments(ocw->ccontrol.inputobj, + &ncand, &curseg, &cursorpos); + + APanelChange(ocw->overthespot.auxwidget, auxstr, ncand, curseg, cursorpos); + + /* reposition popup shell */ + locateAuxPopup(ocw, True); +} + +/*- locateAuxPopup: put aux popup at an appropriate position -*/ +static void +locateAuxPopup(ocw, usecurloc) +OverTheSpotConversionWidget ocw; +Boolean usecurloc; /* use the current location as the default */ +{ + int x, y; + int clx, cly; + int dpyWidth, dpyHeight; + Widget panel = ocw->overthespot.auxwidget; + Widget shell = ocw->overthespot.auxshell; + Window junk; + int barheight = ocw->ccontrol.titlebarheight; + + (void)XTranslateCoordinates(XtDisplay(ocw), + ocw->ccontrol.clientwindow, + RootWindowOfScreen(XtScreen(ocw)), + 0, 0, &clx, &cly, &junk); + + if (usecurloc) { + x = shell->core.x; + y = shell->core.y; + } else { + if (ocw->overthespot.numsegments > 0) { + DisplayLocation lastp; + DisplaySegment *dsp = ocw->overthespot.dispsegments; + int i; + int offset; + + /* find current segment. if not found, use last segment */ + for (i = 0; i < ocw->overthespot.numsegments - 1; i++) { + if (dsp[i].seg.attr & ICAttrCurrentSegment) break; + } + + computeLastPosition(dsp[i].fragments, &lastp); + if (lastp.canvas == ocw->overthespot.overflowcanvas) + offset = ocw->overthespot.overflowoffset; + else + offset = 0; + x = clx + lastp.canvas->x + lastp.x + - panel->core.width / 2 + offset; + y = cly + lastp.canvas->y + lastp.y + ocw->overthespot.lineheight; + } else { + x = clx + ocw->overthespot.spotx - panel->core.width / 2; + y = cly + ocw->overthespot.spoty; + } + } + + dpyWidth = (int)WidthOfScreen(XtScreen(shell)); + dpyHeight = (int)HeightOfScreen(XtScreen(shell)); + + if ((int)(x + panel->core.width) > dpyWidth) x = dpyWidth - panel->core.width; + if (x < 0) x = 0; + if ((int)(y + panel->core.height + barheight) > dpyHeight) { + y = cly + ocw->overthespot.spoty - panel->core.height - 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; +{ + OverTheSpotConversionWidget ocw = (OverTheSpotConversionWidget)client_data; + XExposeEvent *event = (XExposeEvent *)call_data; + XRectangle region; + Boolean cursorredraw; + + TRACE(("OverTheSpotConversion: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, w, ®ion); + if (cursorredraw) showCursor(ocw); +} + + +/* + *+ Selection Widget callback + */ + +/*- SelectionSelected: selection selected callback -*/ +/* ARGSUSED */ +static void +SelectionSelected(w, client_data, call_data) +Widget w; +XtPointer client_data; +XtPointer call_data; +{ + OverTheSpotConversionWidget ocw = (OverTheSpotConversionWidget)client_data; + int current = (int)call_data; + + TRACE(("OverTheSpotConversion:SelectionSelected()\n")); + XtPopdown(ocw->overthespot.selectionshell); + ocw->overthespot.selectionpoppedup = False; + ICSelectItem(ocw->ccontrol.inputobj, current); +} + + +/* + *+ text drawing functions + */ + +/*- computeDisplaySegments: compare old&new text and update segments/fragments -*/ +static void +computeDisplaySegments(ocw) +OverTheSpotConversionWidget ocw; +{ + Widget inputobj = ocw->ccontrol.inputobj; + int nnew = ICNumSegments(inputobj); + int nold = ocw->overthespot.numsegments; + ICString *newseg; + DisplaySegment *dseg; + DisplayLocation disploc; + Cardinal nsame; + int diff; + int i; + + TRACE(("OverTheSpotConversion:computeDisplaySegments() nnew=%d\n", nnew)); + allocDisplaySegments(ocw, nnew); + + ocw->overthespot.overflowcanvas = NULL; + + disploc.x = disploc.y = 0; + if (ocw->overthespot.canvaslist == NULL) { + ocw->overthespot.canvaslist = CreateTextCanvas(ocw); + } + disploc.canvas = ocw->overthespot.canvaslist; + + for (i = 0, dseg = ocw->overthespot.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.canvas != dseg->fragments->canvas || + 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->canvas == newfragments->canvas && + 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->canvas == newfragments->canvas && + 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->overthespot.numsegments = nnew; +} + +/*- recomputeDisplaySegments: recompute segments/fragments -*/ +static void +recomputeDisplaySegments(ocw) +OverTheSpotConversionWidget ocw; +{ + int nseg = ocw->overthespot.numsegments; + DisplaySegment *dseg; + DisplayLocation disploc; + int i; + + ocw->overthespot.overflowcanvas = NULL; + + disploc.x = disploc.y = 0; + if (ocw->overthespot.canvaslist == NULL) { + ocw->overthespot.canvaslist = CreateTextCanvas(ocw); + } + disploc.canvas = ocw->overthespot.canvaslist; + + for (i = 0, dseg = ocw->overthespot.dispsegments; i < nseg; i++, dseg++) { + freeDisplayFragments(dseg->fragments); + dseg->redrawpos = 0; + dseg->fragments = computeDisplayFragments(ocw, &dseg->seg, &disploc); + } +} + +/*- computeLastPosition: get last position of the specified fragment -*/ +static void +computeLastPosition(fragments, disploc) +DisplayFragment *fragments; +DisplayLocation *disploc; +{ + while (fragments->next != NULL) fragments = fragments->next; + disploc->canvas = fragments->canvas; + 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) +OverTheSpotConversionWidget ocw; +ICString *newseg; +DisplayLocation *disploc; +{ + int start; + int nchars; + Widget dispobj = ocw->overthespot.displayobj; + DisplayFragment *fragments, *dfp; + int widthavailable; + + TRACE(("computeDisplayFragments()\n")); + start = 0; + fragments = NULL; + while (start < newseg->nchars) { + widthavailable = computeWidthAvailable(ocw, disploc); + nchars = CDMaxChar(dispobj, newseg, start, widthavailable); + if (nchars == 0) { + if (disploc->canvas->x <= CLAREA(ocw).x && + disploc->x == 0) { + /* + * specified width is too narrow to display a character. + * we force to 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->canvas = disploc->canvas; + dfp->region.x = disploc->x; + dfp->region.y = disploc->y; + dfp->region.width = CDStringWidth(dispobj, newseg, start, + start + nchars); + dfp->region.height = ocw->overthespot.lineheight; + dfp->next = NULL; + + disploc->x += dfp->region.width; + } + start += nchars; + if (start < newseg->nchars) nextLocation(ocw, disploc); + } + + return fragments; +} + +/*- computeWidthAvailable: return the width of the current line left for drawing -*/ +/* ARGSUSED */ +static int +computeWidthAvailable(ocw, disploc) +OverTheSpotConversionWidget ocw; +DisplayLocation *disploc; +{ + XRectangle *cregion = &CLAREA(ocw); + + if (disploc->canvas == ocw->overthespot.overflowcanvas) { + /* we pretend this canvas is veeeeeeery wide */ + return 9999; + } + return (cregion->x + cregion->width) - (disploc->canvas->x + disploc->x); +} + +/*- nextLocation: return the position of the next line -*/ +/* ARGSUSED */ +static void +nextLocation(ocw, disploc) +OverTheSpotConversionWidget ocw; +DisplayLocation *disploc; +{ + XRectangle *cregion = &CLAREA(ocw); + Position x, y; + + if (disploc->canvas->y + ocw->overthespot.linespacing * 2 > + cregion->y + cregion->height) { + /* no new canvas can create underneath this canvas */ + ocw->overthespot.overflowcanvas = disploc->canvas; + return; + } + + if (disploc->canvas->next == NULL) { + disploc->canvas->next = CreateTextCanvas(ocw); + } + x = CLAREA(ocw).x; + y = disploc->canvas->y + ocw->overthespot.linespacing; + disploc->canvas = disploc->canvas->next; + disploc->x = disploc->y = 0; + + disploc->canvas->x = x; + disploc->canvas->y = y; +} + +/*- findLocation: compute the display position of specified char -*/ +static DisplayLocation * +findLocation(ocw, dsp, offset, disploc) +OverTheSpotConversionWidget 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->canvas = dfp->canvas; + disploc->x = dfp->region.x + CDStringWidth(ocw->overthespot.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) +OverTheSpotConversionWidget ocw; +{ + DisplaySegment *dsp; + DisplayFragment *dfp; + TextCanvas *tcp, *lasttcp; + Boolean shrink = ocw->overthespot.shrinkwindow; + XRectangle *areap = &CLAREA(ocw); + int i; + + for (tcp = ocw->overthespot.canvaslist; tcp != NULL; tcp = tcp->next) { + tcp->maxx = tcp->maxy = 0; + tcp->shouldpopup = False; + } + + for (i = 0, dsp = ocw->overthespot.dispsegments; i < ocw->overthespot.numsegments; i++, dsp++) { + for (dfp = dsp->fragments; dfp != NULL; dfp = dfp->next) { + tcp = dfp->canvas; + tcp->maxx = dfp->region.x + dfp->region.width; + tcp->maxy = dfp->region.y + dfp->region.height; + tcp->shouldpopup = True; + } + } + + lasttcp = NULL; + for (tcp = ocw->overthespot.canvaslist; tcp != NULL; tcp = tcp->next) { + if (tcp->maxx < tcp->canvas->core.width && XtIsRealized(tcp->canvas)) { + XClearArea(XtDisplay(tcp->canvas), XtWindow(tcp->canvas), + tcp->maxx, 0, 0, 0, False); + } + if (tcp->shouldpopup) lasttcp = tcp; + } + + if (!ocw->overthespot.modelocationspecified && + ocw->overthespot.modeshell == ocw->overthespot.modeshell_fix) { + /* ModeTrackText */ + if (lasttcp == NULL) { + locateTrackingModeWidget(ocw, True, 0, 0); + } else { + locateTrackingModeWidget(ocw, False, lasttcp->x, + lasttcp->y + lasttcp->maxy); + } + } + + if (ocw->overthespot.cursorvisible) { + DisplayLocation *dlp = &ocw->overthespot.cursorlocation; + XRectangle cbounds; + int x; + + tcp = dlp->canvas; + CDGetCursorBounds(ocw->overthespot.displayobj, &cbounds); + x = dlp->x + cbounds.x + cbounds.width; + if (x > tcp->maxx) tcp->maxx = x; + } + + if (lasttcp != NULL && + lasttcp->x + lasttcp->maxx > areap->x + areap->width) { + ocw->overthespot.overflowcanvas = lasttcp; + adjustDisplay(ocw); + } + + for (tcp = ocw->overthespot.canvaslist; tcp != NULL; tcp = tcp->next) { + Arg args[2]; + int nargs = 0; + if (tcp->shouldpopup && tcp->maxx > 0 && tcp->maxy > 0) { + if (tcp == ocw->overthespot.overflowcanvas) { + XtMoveWidget(tcp->canvas, + tcp->x + ocw->overthespot.overflowoffset, tcp->y); + } else if (tcp->x != tcp->canvas->core.x || + tcp->y != tcp->canvas->core.y) { + XtMoveWidget(tcp->canvas, tcp->x, tcp->y); + } + if (shrink || !tcp->poppedup || + tcp->maxx > tcp->canvas->core.width) { + XtSetArg(args[nargs], XtNwidth, tcp->maxx); nargs++; + } + if (!tcp->poppedup || tcp->maxy > tcp->canvas->core.height) { + XtSetArg(args[nargs], XtNheight, tcp->maxy); nargs++; + } + if (nargs > 0) XtSetValues(tcp->canvas, args, nargs); + + if (!tcp->poppedup) { + TRACE(("reconfigureDisplay(): canvas popup\n")); + XtPopup(tcp->canvas, XtGrabNone); + tcp->poppedup = True; + } + } else { + if (tcp->poppedup) { + TRACE(("reconfigureDisplay(): canvas popdown\n")); + XtPopdown(tcp->canvas); + tcp->poppedup = False; + } + } + } +} + +/*- updateDisplay: redraw text (if needed) -*/ +static void +updateDisplay(ocw) +OverTheSpotConversionWidget ocw; +{ + Widget dispobj = ocw->overthespot.displayobj; + DisplaySegment *dsp = ocw->overthespot.dispsegments; + int i; + + for (i = 0; i < ocw->overthespot.numsegments; i++, dsp++) { + if (dsp->redrawpos >= 0) { + TRACE(("updateDisplaySegment(seg#=%d)\n", i)); + updateDisplaySegment(dispobj, dsp); + } + } +} + +/*- updateDisplaySegment: redraw specified segment (if needed) -*/ +static void +updateDisplaySegment(dispobj, dsp) +Widget dispobj; +DisplaySegment *dsp; +{ + DisplayFragment *dfp = dsp->fragments; + 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, dfp->canvas->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, canvas, region) +OverTheSpotConversionWidget ocw; +Widget canvas; +XRectangle *region; +{ + DisplaySegment *dsp = ocw->overthespot.dispsegments; + DisplayFragment *dfp; + Widget dispobj = ocw->overthespot.displayobj; + int i; + + for (i = 0; i < ocw->overthespot.numsegments; i++, dsp++) { + for (dfp = dsp->fragments; dfp != NULL; dfp = dfp->next) { + if (dfp->canvas->canvas == canvas && + intersectRect(&dfp->region, region)) { + CDDrawString(dispobj, canvas, &dsp->seg, + dfp->from, dfp->from + dfp->nchars, + dfp->region.x, dfp->region.y); + } + } + } +} + +/* + *+ handle overflow canvas functions + */ + +/*- adjustDisplay: compute appropriate offset for the overflow canvas -*/ +static void +adjustDisplay(ocw) +OverTheSpotConversionWidget ocw; +{ + Position outerleft, outerright, innerleft, innerright; + TextCanvas *overflowcanvas = ocw->overthespot.overflowcanvas; + Cardinal curseg; + Cardinal curoffset; + XRectangle *areap; + Position offset; + + TRACE(("adjustDisplay()\n")); + ocw->overthespot.overflowoffset = 0; + + /* + * $B%9%H%i%F%8$H$7$F$O(B + * $B%+%l%s%H%;%0%a%s%H!&%+%l%s%H%5%V%;%0%a%s%H!&%$%s%5!<%H%+!<%=%k$N$"$k(B + * $B%;%0%a%s%H$N$I$l$b$J$1$l$P5$$K$7$J$$(B + * $B%$%s%5!<%H%+!<%=%k$,$"$l$P$=$l$r:GM%@h$9$k!#$D$^$j%$%s%5!<%H%+!<%=%k(B + * $B$O2?$,$"$C$F$bI=<($9$k$h$&$K$9$k!#(B + * $B$G$-$l$P%$%s%5!<%H%+!<%=%k$N$"$k%;%0%a%s%H$O$9$Y$FI=<($9$k!#(B + */ + + outerleft = innerleft = 9999; + outerright = innerright = 0; + + if (ICCursorPos(ocw->ccontrol.inputobj, &curseg, &curoffset) == 1) { + (void)getInsertingSegmentRange(ocw, overflowcanvas, + curseg, curoffset, + &outerleft, &outerright, &innerleft); + if (outerleft <= outerright) innerright = innerleft + 2; /* XXX */ + } else { + (void)getAttributeSegmentRange(ocw, overflowcanvas, + ICAttrCurrentSegment, + &innerleft, &innerright); + (void)getAttributeSegmentRange(ocw, overflowcanvas, + ICAttrCurrentSubSegment, + &outerleft, &outerright); + } + + if (outerleft > outerright && innerleft > innerright) { + /* no important segments is on the overflow canvas */ + TRACE(("\tno important segments on the canvas\n")); + return; + } + + if (outerleft > innerleft) outerleft = innerleft; + if (outerright < innerright) outerright = innerright; + + areap = &CLAREA(ocw); + + if (areap->x <= outerleft && outerright <= areap->x + areap->width) { + /* important part fits in the visible area */ + TRACE(("\timportant segments are visible\n")); + return; + } + + offset = 0; + adjustOffset(areap, outerleft, outerright, &offset, False); + adjustOffset(areap, innerleft, innerright, &offset, True); + TRACE(("\toffset = %d\n", offset)); + ocw->overthespot.overflowoffset = offset; +} + +/*- getAttributeSegmentRange: compute span of segments which has the specified attributes -*/ +static Boolean +getAttributeSegmentRange(ocw, canvas, attr, leftp, rightp) +OverTheSpotConversionWidget ocw; +TextCanvas *canvas; +int attr; +Position *leftp; +Position *rightp; +{ + int nsegs = ocw->overthespot.numsegments; + DisplaySegment *dseg = ocw->overthespot.dispsegments; + DisplayFragment *dfp; + Position left, right; + + left = 32767; + right = 0; + + while (nsegs-- > 0) { + if (dseg->seg.attr & attr) { + dfp = dseg->fragments; + + while (dfp != NULL) { + if (dfp->canvas == canvas) { + if (dfp->region.x < left) left = dfp->region.x; + if (right < dfp->region.x + dfp->region.width) { + right = dfp->region.x + dfp->region.width; + } + } + dfp = dfp->next; + } + } + dseg++; + } + + if (left > right) return False; + + *leftp = left + canvas->x; + *rightp = right + canvas->x; + return True; +} + +/*- getInsertingSegmentRange: compute span of segments which has insert cursor -*/ +static Boolean +getInsertingSegmentRange(ocw, canvas, curseg, offset, leftp, rightp, posp) +OverTheSpotConversionWidget ocw; +TextCanvas *canvas; +Cardinal curseg; +Cardinal offset; +Position *leftp; +Position *rightp; +Position *posp; +{ + DisplaySegment *dseg = ocw->overthespot.dispsegments + curseg; + DisplayFragment *dfp; + Position left, right, insert; + + left = 32767; + right = 0; + + dfp = dseg->fragments; + + while (dfp != NULL) { + if (dfp->canvas == canvas && + dfp->from <= offset && offset <= dfp->from + dfp->nchars) { + if (dfp->region.x < left) left = dfp->region.x; + if (right < dfp->region.x + dfp->region.width) { + right = dfp->region.x + dfp->region.width; + } + + if (offset == dfp->from) { + insert = dfp->region.x; + } else if (offset == dfp->from + dfp->nchars) { + insert = dfp->region.x + dfp->region.width; + } else { + insert = dfp->region.x + + CDStringWidth(ocw->overthespot.displayobj, + &dseg->seg, dfp->from, + offset); + } + break; + } + dfp = dfp->next; + } + + if (left > right) return False; + + *leftp = left + canvas->x; + *rightp = right + canvas->x; + *posp = insert + canvas->x; + return True; +} + +/*- adjustOffset: make the span fit within the specified area -*/ +static void +adjustOffset(rectp, left, right, offsetp, force) +XRectangle *rectp; +Position left; +Position right; +Position *offsetp; +Boolean force; +{ + Position offset = *offsetp; + + if (rectp->x <= left + offset && + right + offset <= rectp->x + rectp->width) return; + + if (right - left > rectp->width) { + if (!force) return; + /* centering */ + offset = (rectp->x + rectp->width / 2) - (right + left) / 2; + } else { + if (left + offset < rectp->x) { + offset = rectp->x - left; + } else if (rectp->x + rectp->width < right + offset) { + offset = rectp->x + rectp->width - right; + } + } + *offsetp = offset; + return; +} + + +/* + *+ insert cursor handling functions + */ + +/*- eraseCursor: erase insert cursor -*/ +static void +eraseCursor(ocw) +OverTheSpotConversionWidget ocw; +{ + if (!ocw->overthespot.cursorvisible) return; + + TRACE(("eraseCursor() at (%d,%d)\n", + ocw->overthespot.cursorlocation.x, + ocw->overthespot.cursorlocation.y)); + CDDrawCursor(ocw->overthespot.displayobj, + ocw->overthespot.cursorlocation.canvas->canvas, + ocw->overthespot.cursorlocation.x, + ocw->overthespot.cursorlocation.y, + False); + ocw->overthespot.cursorvisible = False; +} + +/*- showCursor: draw insert cursor -*/ +static void +showCursor(ocw) +OverTheSpotConversionWidget ocw; +{ + if (!ocw->overthespot.cursorvisible) return; + + TRACE(("showCursor at (%d,%d)\n", + ocw->overthespot.cursorlocation.x, + ocw->overthespot.cursorlocation.y)); + CDDrawCursor(ocw->overthespot.displayobj, + ocw->overthespot.cursorlocation.canvas->canvas, + ocw->overthespot.cursorlocation.x, + ocw->overthespot.cursorlocation.y, + True); +} + +/*- exposeCursor: make the insert cursor redraw correctly when exposing -*/ +static Boolean +exposeCursor(ocw, w, region) +OverTheSpotConversionWidget ocw; +Widget w; +XRectangle *region; +{ + XRectangle bounds; + + if (!ocw->overthespot.cursorvisible || + w != ocw->overthespot.cursorlocation.canvas->canvas) return False; + + TRACE(("exposeCursor(region=%d,%d-%d,%d)\n", + region->x, region->y, region->width, region->height)); + /* + * if a part of the insert cursor is in the exposing region, + * clear the entire cursor before redraw, since the cursor is + * drawn with xor mode. + */ + CDGetCursorBounds(ocw->overthespot.displayobj, &bounds); + bounds.x += ocw->overthespot.cursorlocation.x; + bounds.y += ocw->overthespot.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->overthespot.cursorvisible = True; + return True; +} + +/*- computeCursor: compute insert cursor position if visible -*/ +static void +computeCursor(ocw) +OverTheSpotConversionWidget ocw; +{ + DisplaySegment *dsp; + DisplayLocation disploc; + Cardinal seg, offset; + + if (!ICCursorPos(ocw->ccontrol.inputobj, &seg, &offset)) { + ocw->overthespot.cursorvisible = False; + return; + } + + /* sanity check */ + if (seg >= ocw->overthespot.numsegments) return; + dsp = ocw->overthespot.dispsegments + seg; + if (offset > dsp->seg.nchars) return; + + if (findLocation(ocw, dsp, offset, &disploc) == NULL) return; + + disploc.y += ocw->overthespot.ascent; + + ocw->overthespot.cursorvisible = True; + ocw->overthespot.cursorlocation = disploc; +} + +/* + *+ resource converter + */ + +/*- StringToModeLocation: string->mode-location resource converter -*/ +/* ARGSUSED */ +static void +StringToModeLocation(args, num_args, from, to) +XrmValue *args; +Cardinal *num_args; +XrmValue *from; +XrmValue *to; +{ + char *s = (char *)from->addr; + static ModeLocation ml = ModeBottomLeft; + + if (!XmuCompareISOLatin1(s, "topleft")) ml = ModeTopLeft; + else if (!XmuCompareISOLatin1(s, "topright")) ml = ModeTopRight; + else if (!XmuCompareISOLatin1(s, "bottomleft")) ml = ModeBottomLeft; + else if (!XmuCompareISOLatin1(s, "bottomright")) ml = ModeBottomRight; + else if (!XmuCompareISOLatin1(s, "tracktext")) ml = ModeTrackText; + else if (!XmuCompareISOLatin1(s, "none")) ml = ModeNone; + else { + XtStringConversionWarning(s, XtRModeLocation); + } + + to->size = sizeof(ModeLocation); + to->addr = (caddr_t)&ml; +} + +/* + *+ miscellaneous functions + */ + +/*- MoveShell: move shell widget -*/ +static void +MoveShell(w, x, y) +Widget w; +Position x; +Position y; +{ + ShellWidget shell = (ShellWidget)w; + + TRACE(("MoveShell(%s,x=%d,y=%d,core.x=%d,core.y=%d)\n",XtName(w),x,y,w->core.x,w->core.y)); + XtCheckSubclass(w, shellWidgetClass, + "MoveShell: specified widget is not a shell"); + /* + * calling XtMoveWidget() is NOT enough to move shell widgets when + * they are not mapped. we must use XtMakeGeometryRequest() or + * XtSetValues() to invoke root-geometry-manager which modifies + * the size hint appropriately. + */ + if (shell->shell.popped_up) { + XtMoveWidget(w, x, y); + } else { + XtWidgetGeometry req; + + 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, wm_state) +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) + */ + 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 (w == NULL) return; + if (!XtIsRealized(w)) XtRealizeWidget(w); + XSetTransientForHint(XtDisplay(w), XtWindow(w), win); +} + +/*-setMwmHints: set _MOTIF_WM_HINTS for mode shell -*/ +static void +setMwmHints(w) +Widget w; +{ +#define MWM_HINTS_ATOM "_MOTIF_WM_HINTS" +#define MWM_HINTS_DECOR (1 << 1) +#define MWM_DECOR_BORDER (1 << 1) + Atom mwm_hints; + unsigned long hints[5]; + + if (w == NULL) return; + if (!XtIsRealized(w)) XtRealizeWidget(w); + + mwm_hints = CachedInternAtom(XtDisplay(w), MWM_HINTS_ATOM, False); + if (mwm_hints == None) return; /* just in case.. */ + + hints[0] = MWM_HINTS_DECOR; /* flags */ + hints[2] = MWM_DECOR_BORDER; /* decorations */ + hints[1] = hints[3] = hints[4] = 0; /* functions, input mode and status */ + + XChangeProperty(XtDisplay(w), XtWindow(w), + mwm_hints, mwm_hints, 32, PropModeReplace, + (unsigned char *)hints, 5); +} + +/*- getFocusOffset: get the focus window's position relative to the client window -*/ +static void +getFocusOffset(ocw) +OverTheSpotConversionWidget ocw; +{ + int offx, offy; + Window junkw; + + if (ocw->ccontrol.focuswindow == ocw->ccontrol.clientwindow) { + FOCUSOFFX(ocw) = 0; + FOCUSOFFY(ocw) = 0; + return; + } + XTranslateCoordinates(XtDisplay((Widget)ocw), + ocw->ccontrol.focuswindow, + ocw->ccontrol.clientwindow, + 0, 0, &offx, &offy, &junkw); + FOCUSOFFX(ocw) = offx; + FOCUSOFFY(ocw) = offy; +} + +/*- intersectRect: returns given 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 minimum rectangle that covers given 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; +} + +/*- enoughSpaceForStatus: checks if there's enough space for the status display -*/ +static int +enoughSpaceForStatus(ocw) +OverTheSpotConversionWidget ocw; +{ + Widget modew = ocw->overthespot.modewidget_fix; + int modespace; + int ascent = ocw->overthespot.ascent; + int descent = ocw->overthespot.lineheight - ascent; + int lspace = ocw->overthespot.linespacing; + int areatop = CLAREA(ocw).y; + int areabottom = CLAREA(ocw).y + CLAREA(ocw).height; + int top, bottom, y; + + if (lspace == 0) lspace = 1; /* avoid "divide by zero" error */ + + /* + * tracking $B%9%F!<%?%9$,I=<($G$-$k$+$I$&$+%A%'%C%/$9$k$K$O!"%/%i%$(B + * $B%"%s%H%(%j%"$KI=<($G$-$k:G=i$H:G8e$N9T$K$D$$$F$=$N>e$+2<$K%9%F!<(B + * $B%?%9$,I=<($G$-$k$3$H$rD4$Y$l$P$h$$!#(B + */ + + modespace = modew->core.height + modew->core.border_width * 2 + 2; + + /* $B:G=i$N9T$N>e2<$N(B Y $B:BI8$r7W;;$7$F%9%F!<%?%9$,I=<($G$-$k$+D4$Y$k(B */ + y = SPOTY(ocw) - ascent; + top = y - ((y - areatop) / lspace) * lspace; + bottom = top + ascent + descent; + if (top - areatop < modespace && areabottom - bottom < modespace) { + return 0; + } + + /* $B:G8e$N9T$N>e2<$N(B Y $B:BI8$r7W;;$7$F%9%F!<%?%9$,I=<($G$-$k$+D4$Y$k(B */ + y = SPOTY(ocw) + descent; + bottom = y + ((areabottom - y) / lspace) * lspace; + top = bottom - (ascent + descent); + if (top - areatop < modespace && areabottom - bottom < modespace) { + return 0; + } + + return 1; +} + +static DisplayFragment *free_fragments = NULL; + +/*- allocDisplayFragment: get 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 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: 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) +OverTheSpotConversionWidget ocw; +int n; +{ + if (ocw->overthespot.dispsegmentsize > n) return; + n = ((n + 3) / 4) * 4 ; + if (ocw->overthespot.dispsegments == NULL) { + ocw->overthespot.dispsegments = (DisplaySegment *)XtMalloc(n * sizeof(DisplaySegment)); + } else { + ocw->overthespot.dispsegments = (DisplaySegment *)XtRealloc((char *)ocw->overthespot.dispsegments, n * sizeof(DisplaySegment)); + } + ocw->overthespot.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) +OverTheSpotConversionWidget ocw; +{ + DisplaySegment *dsp = ocw->overthespot.dispsegments; + int i; + + for (i = 0; i < ocw->overthespot.numsegments; i++) { + freeDisplaySegment(dsp++); + } + ocw->overthespot.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; +}