Mercurial > kinput2.yaz
comparison 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 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:92745d501b9a |
---|---|
1 #ifndef lint | |
2 static char *rcsid = "$Id: OverConv.c,v 1.71 1999/05/06 09:07:58 ishisone Exp $"; | |
3 #endif | |
4 /*- | |
5 * Copyright (c) 1990 Software Research Associates, Inc. | |
6 * | |
7 * Permission to use, copy, modify, and distribute this software and its | |
8 * documentation for any purpose and without fee is hereby granted, provided | |
9 * that the above copyright notice appear in all copies and that both that | |
10 * copyright notice and this permission notice appear in supporting | |
11 * documentation, and that the name of Software Research Associates not be | |
12 * used in advertising or publicity pertaining to distribution of the | |
13 * software without specific, written prior permission. Software Research | |
14 * Associates makes no representations about the suitability of this software | |
15 * for any purpose. It is provided "as is" without express or implied | |
16 * warranty. | |
17 * | |
18 * Author: Makoto Ishisone, Software Research Associates, Inc., Japan | |
19 */ | |
20 | |
21 #include <X11/IntrinsicP.h> | |
22 #include <X11/StringDefs.h> | |
23 #include <X11/Xmu/CharSet.h> | |
24 #if XtSpecificationRelease > 4 | |
25 #include <X11/Xfuncs.h> | |
26 #endif | |
27 #include "CachedAtom.h" | |
28 #include "AsyncErr.h" | |
29 #include "OverConvP.h" | |
30 #include "InputConv.h" | |
31 #include "ConvDisp.h" | |
32 #include "CandPanel.h" | |
33 #include "AuxPanel.h" | |
34 #include "CanvasShel.h" | |
35 #include "ICLabel.h" | |
36 | |
37 #define DEBUG_VAR debug_OverTheSpotConversion | |
38 #include "DebugPrint.h" | |
39 | |
40 typedef enum { NeedNone, NeedRedraw, NeedReconfig } ResetStatus; | |
41 | |
42 /*- resource table -*/ | |
43 static XtResource resources[] = { | |
44 #define offset(field) XtOffset(OverTheSpotConversionWidget, overthespot.field) | |
45 { XtNspotX, XtCPosition, XtRPosition, sizeof(Position), | |
46 offset(spotx), XtRImmediate, (XtPointer)0 }, | |
47 { XtNspotY, XtCPosition, XtRPosition, sizeof(Position), | |
48 offset(spoty), XtRImmediate, (XtPointer)0 }, | |
49 { XtNautoSpotForwarding, XtCAutoSpotForwarding, XtRBoolean, sizeof(Boolean), | |
50 offset(spotforwarding), XtRImmediate, (XtPointer)False }, | |
51 { XtNlineSpacing, XtCLineSpacing, XtRDimension, sizeof(Dimension), | |
52 offset(linespacing), XtRImmediate, (XtPointer)0 }, | |
53 { XtNmodeLocation, XtCModeLocation, XtRModeLocation, sizeof(ModeLocation), | |
54 offset(modelocation), XtRString, "BottomLeft" }, | |
55 { XtNshrinkWindow, XtCShrinkWindow, XtRBoolean, sizeof(Boolean), | |
56 offset(shrinkwindow), XtRImmediate, (XtPointer)False }, | |
57 { XtNignoreStatusAreaSpec, XtCIgnoreStatusAreaSpec, | |
58 XtRBoolean, sizeof(Boolean), | |
59 offset(ignorestatusarea), XtRImmediate, (XtPointer)False }, | |
60 { XtNmodeBorderForeground, XtCModeBorderForeground, | |
61 XtRBoolean, sizeof(Boolean), | |
62 offset(borderforeground), XtRImmediate, (XtPointer)False }, | |
63 { XtNuseOverrideShellForMode, XtCUseOverrideShellForMode, | |
64 XtRBoolean, sizeof(Boolean), | |
65 offset(useoverride), XtRImmediate, (XtPointer)False }, | |
66 /* changes superclass's default */ | |
67 { XtNmappedWhenManaged, XtCMappedWhenManaged, XtRBoolean, sizeof(Boolean), | |
68 XtOffset(OverTheSpotConversionWidget, core.mapped_when_managed), | |
69 XtRImmediate, (XtPointer)False }, | |
70 #undef offset | |
71 }; | |
72 | |
73 /*- default translation table -*/ | |
74 static char translations[] = "<Key>: to-inputobj()"; /* same as superclass's */ | |
75 | |
76 /*- declarations of static functions -*/ | |
77 static void ClassInitialize(); | |
78 static void Initialize(); | |
79 static void Destroy(); | |
80 static Boolean SetValues(); | |
81 | |
82 static void ConversionStartup(); | |
83 static void ChangeAttributes(); | |
84 static void ChangeFocus(); | |
85 static void ConversionFinish(); | |
86 | |
87 static void CreateDisplayObject(); | |
88 static void CreateSelectionWidget(); | |
89 static void CreateModeWidget(); | |
90 static TextCanvas * CreateTextCanvas(); | |
91 | |
92 static void setupTextCanvas(); | |
93 static ResetStatus resetTextCanvas(); | |
94 static void setupDisplayObject(); | |
95 static ResetStatus resetDisplayObject(); | |
96 static void setupModeWidget(); | |
97 static ResetStatus resetModeWidget(); | |
98 static void locateTextCanvasInitial(); | |
99 static void locateModeWidget(); | |
100 static void locateTrackingModeWidget(); | |
101 static void redrawAndReconfigureTextCanvas(); | |
102 | |
103 static void UpdateText(); | |
104 static void UpdateMode(); | |
105 static void SelectionControl(); | |
106 | |
107 static void SelectionStart(); | |
108 static void locateSelectionPopup(); | |
109 static void SelectionEnd(); | |
110 static void SelectionSet(); | |
111 static void SelectionGet(); | |
112 static void SelectionMove(); | |
113 static void ForwardSpot(); | |
114 | |
115 static void CreateAuxWidget(); | |
116 static void AuxControl(); | |
117 static void AuxStart(); | |
118 static void locateAuxPopup(); | |
119 static void AuxEnd(); | |
120 static void AuxChange(); | |
121 | |
122 | |
123 static void TextRedisplay(); | |
124 | |
125 static void SelectionSelected(); | |
126 | |
127 static void computeDisplaySegments(); | |
128 static void recomputeDisplaySegments(); | |
129 static void computeLastPosition(); | |
130 static DisplayFragment *computeDisplayFragments(); | |
131 static int computeWidthAvailable(); | |
132 static void nextLocation(); | |
133 static DisplayLocation *findLocation(); | |
134 static void reconfigureDisplay(); | |
135 static void updateDisplay(); | |
136 static void updateDisplaySegment(); | |
137 static void redrawSegments(); | |
138 | |
139 static void adjustDisplay(); | |
140 static Boolean getAttributeSegmentRange(); | |
141 static Boolean getInsertingSegmentRange(); | |
142 static void adjustOffset(); | |
143 | |
144 static void eraseCursor(); | |
145 static void showCursor(); | |
146 static Boolean exposeCursor(); | |
147 static void computeCursor(); | |
148 | |
149 static void StringToModeLocation(); | |
150 | |
151 static void MoveShell(); | |
152 static Window getToplevelWindow(); | |
153 static void setTransientFor(); | |
154 static void setMwmHints(); | |
155 static void getFocusOffset(); | |
156 static Boolean intersectRect(); | |
157 static void unionRect(); | |
158 static int enoughSpaceForStatus(); | |
159 static DisplayFragment *allocDisplayFragment(); | |
160 static void freeDisplayFragments(); | |
161 static void destroyDisplayFragments(); | |
162 static void allocDisplaySegments(); | |
163 static void freeDisplaySegment(); | |
164 static void clearAllDisplaySegments(); | |
165 static void copyString(); | |
166 static void freeString(); | |
167 | |
168 /*- composite-extension rec: for enabling non-widget children -*/ | |
169 static CompositeClassExtensionRec CompositeExtension = { | |
170 /* next_extension */ NULL, | |
171 /* record_type */ NULLQUARK, | |
172 /* version */ XtCompositeExtensionVersion, | |
173 /* record_size */ sizeof(CompositeClassExtensionRec), | |
174 /* accept_objects */ True, | |
175 }; | |
176 | |
177 /*- overTheSpotConversionClass record -*/ | |
178 OverTheSpotConversionClassRec overTheSpotConversionClassRec = { | |
179 { /* core fields */ | |
180 /* superclass */ (WidgetClass)&conversionControlClassRec, | |
181 /* class_name */ "OverTheSpotConversion", | |
182 /* widget_size */ sizeof(OverTheSpotConversionRec), | |
183 /* class_initialize */ ClassInitialize, | |
184 /* class_part_initialize */ NULL, | |
185 /* class_inited */ FALSE, | |
186 /* initialize */ Initialize, | |
187 /* initialize_hook */ NULL, | |
188 /* realize */ XtInheritRealize, | |
189 /* actions */ NULL, | |
190 /* num_actions */ 0, | |
191 /* resources */ resources, | |
192 /* num_resources */ XtNumber(resources), | |
193 /* xrm_class */ NULLQUARK, | |
194 /* compress_motion */ TRUE, | |
195 /* compress_exposure */ TRUE, | |
196 /* compress_enterleave */ TRUE, | |
197 /* visible_interest */ FALSE, | |
198 /* destroy */ Destroy, | |
199 /* resize */ XtInheritResize, | |
200 /* expose */ NULL, | |
201 /* set_values */ SetValues, | |
202 /* set_values_hook */ NULL, | |
203 /* set_values_almost */ XtInheritSetValuesAlmost, | |
204 /* get_values_hook */ NULL, | |
205 /* accept_focus */ NULL, | |
206 /* version */ XtVersion, | |
207 /* callback_private */ NULL, | |
208 /* tm_table */ translations, | |
209 /* query_geometry */ XtInheritQueryGeometry, | |
210 /* display_accelerator */ XtInheritDisplayAccelerator, | |
211 /* extension */ NULL | |
212 }, | |
213 { /* composite fields */ | |
214 /* geometry_manager */ XtInheritGeometryManager, | |
215 /* change_managed */ XtInheritChangeManaged, | |
216 /* insert_child */ XtInheritInsertChild, | |
217 /* delete_child */ XtInheritDeleteChild, | |
218 /* extension */ (XtPointer)&CompositeExtension, | |
219 }, | |
220 { /* shell fields */ | |
221 /* extension */ NULL | |
222 }, | |
223 { /* wm_shell fields */ | |
224 /* extension */ NULL | |
225 }, | |
226 { /* vendor_shell fields */ | |
227 /* extension */ NULL | |
228 }, | |
229 { /* transient_shell fields */ | |
230 /* extension */ NULL | |
231 }, | |
232 { /* conversionControl fields */ | |
233 /* Startup */ ConversionStartup, | |
234 /* Finish */ ConversionFinish, | |
235 /* ChangeAttributes */ ChangeAttributes, | |
236 /* ChangeFocus */ ChangeFocus, | |
237 /* TextChange */ UpdateText, | |
238 /* Fix */ XtInheritFix, | |
239 /* ModeChange */ UpdateMode, | |
240 /* SelectionControl */ SelectionControl, | |
241 /* SelectionControl */ AuxControl, | |
242 }, | |
243 { /* overTheSpotConversion fields */ | |
244 /* empty */ 0 | |
245 }, | |
246 }; | |
247 | |
248 WidgetClass overTheSpotConversionWidgetClass = (WidgetClass)&overTheSpotConversionClassRec; | |
249 | |
250 /* | |
251 *+ Convenience macros | |
252 */ | |
253 #define SPOTX(w) ((w)->overthespot.spotx) | |
254 #define SPOTY(w) ((w)->overthespot.spoty) | |
255 #define CLAREA(w) ((w)->overthespot.clientarea) | |
256 #define FOCUSOFFX(w) ((w)->overthespot.focusoffsetx) | |
257 #define FOCUSOFFY(w) ((w)->overthespot.focusoffsety) | |
258 | |
259 /* | |
260 *+ Core class methods | |
261 */ | |
262 | |
263 /*- ClassInitialize: add resource converter (string->modelocation) -*/ | |
264 /* ARGSUSED */ | |
265 static void | |
266 ClassInitialize() | |
267 { | |
268 XtAddConverter(XtRString, XtRModeLocation, StringToModeLocation, | |
269 NULL, 0); | |
270 } | |
271 | |
272 /*- Initialize: initialize method -*/ | |
273 /* ARGSUSED */ | |
274 static void | |
275 Initialize(req, new, args, num_args) | |
276 Widget req; | |
277 Widget new; | |
278 ArgList args; | |
279 Cardinal *num_args; | |
280 { | |
281 OverTheSpotConversionWidget ocw = (OverTheSpotConversionWidget)new; | |
282 | |
283 ocw->overthespot.background = ocw->core.background_pixel; | |
284 ocw->overthespot.canvaslist = NULL; | |
285 ocw->overthespot.overflowcanvas = NULL; | |
286 ocw->overthespot.dispsegments = NULL; | |
287 ocw->overthespot.numsegments = 0; | |
288 ocw->overthespot.dispsegmentsize = 0; | |
289 ocw->overthespot.candlist = NULL; | |
290 ocw->overthespot.numcands = 0; | |
291 ocw->overthespot.selectionpoppedup = False; | |
292 ocw->overthespot.cursorvisible = False; | |
293 ocw->overthespot.canvascursor = None; | |
294 ocw->overthespot.auxpoppedup = False; | |
295 | |
296 ocw->overthespot.wm_state = | |
297 CachedInternAtom(XtDisplay(new), "WM_STATE", False); | |
298 | |
299 /* $B%F%-%9%HI=<($N(B widget $B$O:G=i$NJQ493+;O;~$K:n$k(B */ | |
300 CreateDisplayObject(ocw); | |
301 CreateSelectionWidget(ocw); | |
302 CreateAuxWidget(ocw); | |
303 CreateModeWidget(ocw); | |
304 } | |
305 | |
306 /*- Destroy: destroy method -*/ | |
307 static void | |
308 Destroy(w) | |
309 Widget w; | |
310 { | |
311 OverTheSpotConversionWidget ocw = (OverTheSpotConversionWidget)w; | |
312 | |
313 /* $B%G%#%9%W%l%$%;%0%a%s%H$NNN0h$r2rJ|(B */ | |
314 if (ocw->overthespot.dispsegments) { | |
315 DisplaySegment *dsp = ocw->overthespot.dispsegments; | |
316 int i; | |
317 | |
318 for (i = 0; i < ocw->overthespot.numsegments; i++) { | |
319 freeString(&dsp[i].seg); | |
320 destroyDisplayFragments(dsp->fragments); | |
321 } | |
322 XtFree((char *)dsp); | |
323 } | |
324 | |
325 /* canvaslist $B$NNN0h$r2rJ|(B (canvas widget $B$O(B $B<+F0E*$K(B destroy $B$5$l$k(B */ | |
326 if (ocw->overthespot.canvaslist) { | |
327 TextCanvas *p = ocw->overthespot.canvaslist; | |
328 while (p) { | |
329 TextCanvas *q = p->next; | |
330 XtFree((char *)p); | |
331 p = q; | |
332 } | |
333 } | |
334 } | |
335 | |
336 /*- SetValues: setvalues method -*/ | |
337 /* ARGSUSED */ | |
338 static Boolean | |
339 SetValues(cur, req, new, args, num_args) | |
340 Widget cur; | |
341 Widget req; | |
342 Widget new; | |
343 ArgList args; | |
344 Cardinal *num_args; | |
345 { | |
346 /* OverTheSpotConversionWidget ocw = (OverTheSpotConversionWidget)new; */ | |
347 return False; | |
348 } | |
349 | |
350 /* | |
351 *+ ConversionControl cass methods | |
352 */ | |
353 | |
354 /*- ConversionStartup: class specific conversion startup -*/ | |
355 static void | |
356 ConversionStartup(w, mask, value) | |
357 Widget w; | |
358 unsigned long mask; | |
359 ConversionAttributes *value; | |
360 { | |
361 OverTheSpotConversionWidget ocw = (OverTheSpotConversionWidget)w; | |
362 Widget inputobj = ocw->ccontrol.inputobj; | |
363 Window toplevel; | |
364 | |
365 TRACE(("OverTheSpot:ConversionStartup()\n")); | |
366 | |
367 /* $BFbIt$N%P%C%U%!$r%/%j%"$9$k(B */ | |
368 clearAllDisplaySegments(ocw); | |
369 | |
370 /* $BJQ49%*%V%8%'%/%H$K%3!<%k%P%C%/$r@_Dj$9$k(B */ | |
371 XtAddCallback(inputobj, XtNfixNotify, ForwardSpot, (XtPointer)w); | |
372 | |
373 if (ocw->overthespot.ignorestatusarea) mask &= ~CAStatusArea; | |
374 | |
375 setupDisplayObject(ocw, mask, value); | |
376 setupTextCanvas(ocw, mask, value); | |
377 setupModeWidget(ocw, mask, value); | |
378 | |
379 /* WM_TRANSIENT_FOR $B%W%m%Q%F%#$r@5$7$/%;%C%H$9$k(B */ | |
380 toplevel = getToplevelWindow(XtDisplay(w), | |
381 ocw->ccontrol.clientwindow, | |
382 ocw->overthespot.wm_state); | |
383 setTransientFor(ocw->overthespot.modeshell, toplevel); | |
384 setTransientFor(ocw->overthespot.selectionshell, toplevel); | |
385 setTransientFor(ocw->overthespot.auxshell, toplevel); | |
386 | |
387 /* $B%F%-%9%H%-%c%s%P%9$NI=<(0LCV$r7h$a$k(B */ | |
388 locateTextCanvasInitial(ocw); | |
389 | |
390 /* $B%b!<%I$NI=<(0LCV$r7h$a$k(B */ | |
391 if (!ocw->overthespot.modelocationspecified) locateModeWidget(ocw); | |
392 | |
393 /* | |
394 * OverTheSpotConvesion $B$N>l9g!"<+J,<+?H$O%]%C%W%"%C%W$7$J$$$,!"(B | |
395 * $B%P%C%/%(%s%I%?%$%W$N;~$K$O%/%i%$%"%s%H$,$3$N(B widget $B$N(B | |
396 * $B%&%#%s%I%&$KBP$7$F%$%Y%s%H$rAw$k$N$G!"(BRealize $B$@$1$7$F$*$/(B | |
397 * $B$=$N:]!"Bg$-$5$r;XDj$7$J$$$H%5%$%:$,(B 0 $B$K$J$C$F$7$^$&$N$GCm0U$9$k(B | |
398 */ | |
399 if (!XtIsRealized(w)) { | |
400 Arg args[2]; | |
401 | |
402 XtSetArg(args[0], XtNwidth, 1); | |
403 XtSetArg(args[1], XtNheight, 1); | |
404 XtSetValues(w, args, 2); | |
405 XtRealizeWidget(w); | |
406 } | |
407 | |
408 /* $B%b!<%II=<(%-%c%s%P%9$r%]%C%W%"%C%W$9$k(B */ | |
409 if (ocw->overthespot.modeshell != NULL) { | |
410 XtPopup(ocw->overthespot.modeshell, XtGrabNone); | |
411 } | |
412 } | |
413 | |
414 /*- ChangeAttributes: class specific conversion attribute change routine -*/ | |
415 /* ARGSUSED */ | |
416 static void | |
417 ChangeAttributes(w, mask, value) | |
418 Widget w; | |
419 unsigned long mask; | |
420 ConversionAttributes *value; | |
421 { | |
422 OverTheSpotConversionWidget ocw = (OverTheSpotConversionWidget)w; | |
423 ResetStatus dispres, tcres; | |
424 | |
425 TRACE(("OverTheSpot:ChangeAttributes()\n")); | |
426 | |
427 if (ocw->overthespot.ignorestatusarea) mask &= ~CAStatusArea; | |
428 | |
429 dispres = resetDisplayObject(ocw, mask, value); | |
430 tcres = resetTextCanvas(ocw, mask, value); | |
431 if (dispres == NeedReconfig || tcres == NeedReconfig) { | |
432 redrawAndReconfigureTextCanvas(ocw); | |
433 } else if (dispres == NeedRedraw || tcres == NeedRedraw) { | |
434 TextCanvas *tcp = ocw->overthespot.canvaslist; | |
435 | |
436 while (tcp != NULL) { | |
437 if (XtIsRealized(tcp->canvas)) { | |
438 XClearArea(XtDisplay(tcp->canvas), XtWindow(tcp->canvas), | |
439 0, 0, 0, 0, True); | |
440 } | |
441 tcp = tcp->next; | |
442 } | |
443 } | |
444 | |
445 if (resetModeWidget(ocw, mask, value) != NeedNone && | |
446 XtIsRealized(ocw->overthespot.modewidget)) { | |
447 XClearArea(XtDisplay(w), XtWindow((Widget)ocw->overthespot.modewidget), | |
448 0, 0, 0, 0, True); | |
449 } | |
450 } | |
451 | |
452 /*- ChangeFocus: class specific conversion attribute change routine -*/ | |
453 static void | |
454 ChangeFocus(w, set) | |
455 Widget w; | |
456 int set; | |
457 { | |
458 OverTheSpotConversionWidget ocw = (OverTheSpotConversionWidget)w; | |
459 | |
460 TRACE(("OverTheSpot:ChangeFocus()\n")); | |
461 | |
462 if (ocw->overthespot.modeshell == NULL) return; | |
463 if (set) { | |
464 XtPopup(ocw->overthespot.modeshell, XtGrabNone); | |
465 } else { | |
466 XtPopdown(ocw->overthespot.modeshell); | |
467 } | |
468 } | |
469 | |
470 /*- ConversionFinish: class specific conversion finish -*/ | |
471 /* ARGSUSED */ | |
472 static void | |
473 ConversionFinish(w) | |
474 Widget w; | |
475 { | |
476 OverTheSpotConversionWidget ocw = (OverTheSpotConversionWidget)w; | |
477 Widget inputobj = ocw->ccontrol.inputobj; | |
478 TextCanvas *tcp = ocw->overthespot.canvaslist; | |
479 XAEHandle h; | |
480 | |
481 /* $BJQ49%*%V%8%'%/%H$N%3!<%k%P%C%/$r>C$9(B */ | |
482 XtRemoveCallback(inputobj, XtNfixNotify, ForwardSpot, (XtPointer)w); | |
483 | |
484 /* Popdown and unrealize textcanvases | |
485 * we must be careful here. if clientwindow are destroyed, | |
486 * the text canvases are also destroyed. | |
487 * we have to popdown and unrealize canvas widgets, but if | |
488 * they are destroyed, BadWindow error will be generated. | |
489 * so we must set own error handler that ignores errors. | |
490 */ | |
491 h = XAESetIgnoreErrors(XtDisplay(w)); | |
492 while (tcp != NULL) { | |
493 if (tcp->poppedup) XtPopdown(tcp->canvas); | |
494 XtUnrealizeWidget(tcp->canvas); | |
495 /* XtVaSetValues(tcp->canvas, XtNcursor, None, NULL); */ | |
496 tcp->poppedup = False; | |
497 tcp = tcp->next; | |
498 } | |
499 /* Popdown mode widget */ | |
500 if (ocw->overthespot.modeshell != NULL) { | |
501 XtPopdown(ocw->overthespot.modeshell); | |
502 } | |
503 if (ocw->overthespot.modeshell == ocw->overthespot.modeshell_fix) { | |
504 XtUnrealizeWidget(ocw->overthespot.modeshell); | |
505 } | |
506 XAEUnset(h); | |
507 | |
508 /* Popdown selection popup (if popped-up) */ | |
509 if (ocw->overthespot.selectionpoppedup) { | |
510 XtPopdown(ocw->overthespot.selectionshell); | |
511 ocw->overthespot.selectionpoppedup = False; | |
512 } | |
513 if (ocw->overthespot.auxpoppedup) { | |
514 XtPopdown(ocw->overthespot.auxshell); | |
515 ocw->overthespot.auxpoppedup = False; | |
516 } | |
517 } | |
518 | |
519 /* | |
520 *+ sub-widget creation | |
521 */ | |
522 | |
523 /*- CreateDisplayObject: create display object for text drawing -*/ | |
524 static void | |
525 CreateDisplayObject(ocw) | |
526 OverTheSpotConversionWidget ocw; | |
527 { | |
528 Widget dispobj; | |
529 | |
530 dispobj = XtCreateWidget("displayObj", ocw->ccontrol.displayobjclass, | |
531 (Widget)ocw, NULL, 0); | |
532 | |
533 ocw->overthespot.displayobj = dispobj; | |
534 ocw->overthespot.lineheight = CDLineHeight(dispobj, | |
535 &ocw->overthespot.ascent); | |
536 | |
537 } | |
538 | |
539 /*- CreateSelectionWidget: create selection widget for selecting candidates -*/ | |
540 static void | |
541 CreateSelectionWidget(ocw) | |
542 OverTheSpotConversionWidget ocw; | |
543 { | |
544 Widget shell, sel, obj; | |
545 | |
546 shell = XtVaCreatePopupShell("selectionShell", | |
547 transientShellWidgetClass, | |
548 (Widget)ocw, | |
549 XtNwidth, 1, XtNheight, 1, | |
550 NULL); | |
551 ocw->overthespot.selectionshell = shell; | |
552 | |
553 sel = XtCreateManagedWidget("selection", candidatePanelWidgetClass, | |
554 shell, NULL, 0); | |
555 obj = XtCreateWidget("display", ocw->ccontrol.displayobjclass, | |
556 sel, NULL, 0); | |
557 XtAddCallback(sel, XtNcallback, SelectionSelected, (Widget)ocw); | |
558 XtInstallAccelerators(sel, (Widget)ocw); | |
559 | |
560 ocw->overthespot.selectionwidget = sel; | |
561 ocw->overthespot.selectiondisplayobj = obj; | |
562 } | |
563 | |
564 /*- CreateAuxWidget: create auxiliary widget for displaying auxiliary data -*/ | |
565 static void | |
566 CreateAuxWidget(ocw) | |
567 OverTheSpotConversionWidget ocw; | |
568 { | |
569 Widget shell, sel, obj; | |
570 | |
571 shell = XtVaCreatePopupShell("auxShell", | |
572 transientShellWidgetClass, | |
573 (Widget)ocw, | |
574 XtNwidth, 1, XtNheight, 1, | |
575 XtNallowShellResize, True, | |
576 NULL); | |
577 ocw->overthespot.auxshell = shell; | |
578 | |
579 sel = XtCreateManagedWidget("aux", auxPanelWidgetClass, | |
580 shell, NULL, 0); | |
581 obj = XtCreateWidget("display", ocw->ccontrol.displayobjclass, | |
582 sel, NULL, 0); | |
583 XtAddCallback(sel, XtNcallback, SelectionSelected, (Widget)ocw); | |
584 XtInstallAccelerators(sel, (Widget)ocw); | |
585 | |
586 ocw->overthespot.auxwidget = sel; | |
587 ocw->overthespot.auxdisplayobj = obj; | |
588 } | |
589 | |
590 /*- CreateModeWidget: create mode displaying widget -*/ | |
591 static void | |
592 CreateModeWidget(ocw) | |
593 OverTheSpotConversionWidget ocw; | |
594 { | |
595 Widget shell, w, obj; | |
596 | |
597 TRACE(("CreateModeWidget()\n")); | |
598 | |
599 /* create fixed widget */ | |
600 shell = XtCreatePopupShell("modeShell", adoptedShellWidgetClass, | |
601 (Widget)ocw, NULL, 0); | |
602 XtVaGetValues(shell, XtNborderWidth, &ocw->overthespot.saved_bw, NULL); | |
603 w = XtCreateManagedWidget("mode", icLabelWidgetClass, shell, NULL, 0); | |
604 obj = XtCreateWidget("display", ocw->ccontrol.displayobjclass, w, | |
605 NULL, 0); | |
606 XtInstallAccelerators(shell, (Widget)ocw); | |
607 XtInstallAccelerators(w, (Widget)ocw); | |
608 ocw->overthespot.modeshell_fix = shell; | |
609 ocw->overthespot.modewidget_fix = w; | |
610 ocw->overthespot.modedisplayobj_fix = obj; | |
611 | |
612 /* create floating widget */ | |
613 if (ocw->overthespot.useoverride) { | |
614 shell = XtCreatePopupShell("modeShell", overrideShellWidgetClass, | |
615 (Widget)ocw, NULL, 0); | |
616 } else { | |
617 shell = XtCreatePopupShell("modeShell", transientShellWidgetClass, | |
618 (Widget)ocw, NULL, 0); | |
619 } | |
620 w = XtCreateManagedWidget("mode", icLabelWidgetClass, shell, NULL, 0); | |
621 obj = XtCreateWidget("display", ocw->ccontrol.displayobjclass, w, | |
622 NULL, 0); | |
623 XtInstallAccelerators(shell, (Widget)ocw); | |
624 XtInstallAccelerators(w, (Widget)ocw); | |
625 ocw->overthespot.modeshell_float = shell; | |
626 ocw->overthespot.modewidget_float = w; | |
627 ocw->overthespot.modedisplayobj_float = obj; | |
628 | |
629 /* set mwm hints for the shell */ | |
630 setMwmHints(shell); | |
631 } | |
632 | |
633 /*- CreateTextCanvas: create a text canvas -*/ | |
634 static TextCanvas * | |
635 CreateTextCanvas(ocw) | |
636 OverTheSpotConversionWidget ocw; | |
637 { | |
638 TextCanvas *tcp; | |
639 | |
640 tcp = XtNew(TextCanvas); | |
641 tcp->x = 0; | |
642 tcp->y = 0; | |
643 tcp->poppedup = False; | |
644 tcp->next = NULL; | |
645 tcp->canvas = XtVaCreatePopupShell("text", | |
646 canvasShellWidgetClass, | |
647 (Widget)ocw, | |
648 XtNcolormap, | |
649 ocw->overthespot.colormap, | |
650 XtNbackground, | |
651 ocw->overthespot.background, | |
652 XtNparentWindow, | |
653 ocw->ccontrol.clientwindow, | |
654 XtNoverrideRedirect, True, | |
655 NULL); /* XXX for now XXX */ | |
656 XtAddCallback(tcp->canvas, XtNexposeCallback, TextRedisplay, (XtPointer)ocw); | |
657 XtInstallAccelerators(tcp->canvas, (Widget)ocw); | |
658 | |
659 return tcp; | |
660 } | |
661 | |
662 | |
663 /* | |
664 *+ subwidget configuration | |
665 */ | |
666 | |
667 /*- setupTextCanvas: do text canvas configuration on conversion startup -*/ | |
668 static void | |
669 setupTextCanvas(ocw, mask, value) | |
670 OverTheSpotConversionWidget ocw; | |
671 unsigned long mask; | |
672 ConversionAttributes *value; | |
673 { | |
674 TRACE(("setupTextCanvas(mask=0x%lx)\n", mask)); | |
675 | |
676 getFocusOffset(ocw); | |
677 | |
678 if (mask & CAClientArea) { | |
679 CLAREA(ocw) = value->clientarea; | |
680 } else { | |
681 /* default */ | |
682 CLAREA(ocw).x = 0; | |
683 CLAREA(ocw).y = 0; | |
684 CLAREA(ocw).width = ocw->ccontrol.focus_attr.width; | |
685 CLAREA(ocw).height = ocw->ccontrol.focus_attr.height; | |
686 } | |
687 CLAREA(ocw).x += FOCUSOFFX(ocw); | |
688 CLAREA(ocw).y += FOCUSOFFY(ocw); | |
689 | |
690 TRACE(("\tclientarea: (%d,%d)-(%d,%d)\n",CLAREA(ocw).x,CLAREA(ocw).y,CLAREA(ocw).width,CLAREA(ocw).height)); | |
691 if (mask & CASpotLocation) { | |
692 SPOTX(ocw) = value->spotx + FOCUSOFFX(ocw); | |
693 SPOTY(ocw) = value->spoty + FOCUSOFFY(ocw); | |
694 } else { | |
695 /* default */ | |
696 SPOTX(ocw) = CLAREA(ocw).x; | |
697 SPOTY(ocw) = CLAREA(ocw).y + ocw->overthespot.ascent; | |
698 } | |
699 TRACE(("\tspotlocation: (%d,%d)\n",SPOTX(ocw),SPOTY(ocw))); | |
700 | |
701 if (mask & CALineSpacing) { | |
702 ocw->overthespot.linespacing = value->linespacing; | |
703 if (ocw->overthespot.linespacing == 0) { | |
704 DPRINT(("\tspecified linespacing is 0. reset to default\n")); | |
705 ocw->overthespot.linespacing = ocw->overthespot.lineheight; | |
706 } | |
707 } else { | |
708 ocw->overthespot.linespacing = ocw->overthespot.lineheight; | |
709 } | |
710 if (mask & CAColormap) { | |
711 ocw->overthespot.colormap = value->colormap; | |
712 } else { | |
713 ocw->overthespot.colormap = DefaultColormapOfScreen(XtScreen((Widget)ocw)); | |
714 } | |
715 if (mask & CAColor) { | |
716 ocw->overthespot.background = value->background; | |
717 } else { | |
718 /* default */ | |
719 ocw->overthespot.background = ocw->core.background_pixel; | |
720 } | |
721 if (mask & CACursor) { | |
722 ocw->overthespot.canvascursor = value->cursor; | |
723 } else { | |
724 ocw->overthespot.canvascursor = None; | |
725 } | |
726 | |
727 if (ocw->overthespot.canvaslist == NULL) { | |
728 ocw->overthespot.canvaslist = CreateTextCanvas(ocw); | |
729 } else { | |
730 TextCanvas *tcp = ocw->overthespot.canvaslist; | |
731 while (tcp != NULL) { | |
732 XtVaSetValues(tcp->canvas, | |
733 XtNcolormap, ocw->overthespot.colormap, | |
734 XtNbackground, ocw->overthespot.background, | |
735 XtNparentWindow, ocw->ccontrol.clientwindow, | |
736 XtNcursor, ocw->overthespot.canvascursor, | |
737 NULL); | |
738 tcp = tcp->next; | |
739 } | |
740 } | |
741 } | |
742 | |
743 /*- resetTextCanvas: do text canvas reconfiguration on attribute change -*/ | |
744 static ResetStatus | |
745 resetTextCanvas(ocw, mask, value) | |
746 OverTheSpotConversionWidget ocw; | |
747 unsigned long mask; | |
748 ConversionAttributes *value; | |
749 { | |
750 ResetStatus redraw = NeedNone; | |
751 | |
752 if (mask & (CAColormap|CAColor|CACursor)) { | |
753 Arg args[3]; | |
754 Cardinal i = 0; | |
755 if (mask & CAColormap && | |
756 value->colormap != ocw->overthespot.colormap) { | |
757 ocw->overthespot.colormap = value->colormap; | |
758 XtSetArg(args[i], XtNcolormap, value->colormap); i++; | |
759 } | |
760 if (mask & CAColor && | |
761 value->background != ocw->overthespot.background) { | |
762 ocw->overthespot.background = value->background; | |
763 XtSetArg(args[i], XtNbackground, value->background); i++; | |
764 } | |
765 if (mask & CACursor && | |
766 value->cursor != ocw->overthespot.canvascursor) { | |
767 ocw->overthespot.canvascursor = value->cursor; | |
768 XtSetArg(args[i], XtNcursor, value->cursor); i++; | |
769 } | |
770 if (i > 0) { | |
771 TextCanvas *tcp = ocw->overthespot.canvaslist; | |
772 | |
773 while (tcp != NULL) { | |
774 XtSetValues(tcp->canvas, args, i); | |
775 tcp = tcp->next; | |
776 } | |
777 redraw = NeedRedraw; | |
778 } | |
779 } | |
780 if (mask & CAFocusWindow) { | |
781 getFocusOffset(ocw); | |
782 redraw = NeedReconfig; | |
783 } | |
784 if (mask & CAClientArea) { | |
785 if (value->clientarea.x + FOCUSOFFX(ocw) != CLAREA(ocw).x || | |
786 value->clientarea.y + FOCUSOFFY(ocw) != CLAREA(ocw).y || | |
787 value->clientarea.width != CLAREA(ocw).width || | |
788 value->clientarea.height != CLAREA(ocw).height) { | |
789 CLAREA(ocw) = value->clientarea; | |
790 CLAREA(ocw).x += FOCUSOFFX(ocw); | |
791 CLAREA(ocw).y += FOCUSOFFY(ocw); | |
792 redraw = NeedReconfig; | |
793 } | |
794 } else if (mask & CAFocusWindow) { | |
795 CLAREA(ocw).x = FOCUSOFFX(ocw); | |
796 CLAREA(ocw).y = FOCUSOFFY(ocw); | |
797 CLAREA(ocw).width = ocw->ccontrol.focus_attr.width; | |
798 CLAREA(ocw).height = ocw->ccontrol.focus_attr.height; | |
799 } | |
800 if (mask & CASpotLocation) { | |
801 if (value->spotx + FOCUSOFFX(ocw) != SPOTX(ocw) || | |
802 value->spoty + FOCUSOFFY(ocw) != SPOTY(ocw)) { | |
803 SPOTX(ocw) = value->spotx + FOCUSOFFX(ocw); | |
804 SPOTY(ocw) = value->spoty + FOCUSOFFY(ocw); | |
805 redraw = NeedReconfig; | |
806 } | |
807 } else if (mask & CAFocusWindow) { | |
808 SPOTX(ocw) = CLAREA(ocw).x; | |
809 SPOTY(ocw) = CLAREA(ocw).y + ocw->overthespot.ascent; | |
810 } | |
811 if (mask & CALineSpacing) { | |
812 if (value->linespacing != ocw->overthespot.linespacing && | |
813 value->linespacing != 0) { | |
814 ocw->overthespot.linespacing = value->linespacing; | |
815 redraw = NeedReconfig; | |
816 } | |
817 } else if (mask & CAFonts) { | |
818 ocw->overthespot.linespacing = ocw->overthespot.lineheight; | |
819 redraw = NeedReconfig; | |
820 } | |
821 | |
822 return redraw; | |
823 } | |
824 | |
825 /*- setupDisplayObject: do displayobj configuration on conversion startup -*/ | |
826 static void | |
827 setupDisplayObject(ocw, mask, value) | |
828 OverTheSpotConversionWidget ocw; | |
829 unsigned long mask; | |
830 ConversionAttributes *value; | |
831 { | |
832 Widget dispobj = ocw->overthespot.displayobj; | |
833 | |
834 TRACE(("setupDisplayObject()\n")); | |
835 | |
836 /* | |
837 * order is important. we must set fonts BEFORE anything else, | |
838 * because it is possible that the fonts previously set in the | |
839 * display object no longer exist, and if so, that causes BadFont | |
840 * error when changing GCs. | |
841 */ | |
842 | |
843 if (mask & CAFonts) { | |
844 TRACE(("\tchanging fonts...\n")); | |
845 CDSetFonts(dispobj, value->fonts, value->num_fonts); | |
846 } else { | |
847 /* reset to default */ | |
848 CDSetFonts(dispobj, (XFontStruct **)NULL, 0); | |
849 } | |
850 if (mask & CAColor) { | |
851 TRACE(("\tchanging colors...\n")); | |
852 XtVaSetValues(dispobj, | |
853 XtNforeground, value->foreground, | |
854 XtNbackground, value->background, | |
855 NULL); | |
856 } | |
857 ocw->overthespot.lineheight = CDLineHeight(dispobj, | |
858 &ocw->overthespot.ascent); | |
859 } | |
860 | |
861 /*- resetDisplayObject: do displayobj reconfiguration on attribute change -*/ | |
862 static ResetStatus | |
863 resetDisplayObject(ocw, mask, value) | |
864 OverTheSpotConversionWidget ocw; | |
865 unsigned long mask; | |
866 ConversionAttributes *value; | |
867 { | |
868 Widget dispobj = ocw->overthespot.displayobj; | |
869 ResetStatus redraw = NeedNone; | |
870 | |
871 TRACE(("resetDisplayObject()\n")); | |
872 | |
873 if (mask & CAColor) { | |
874 TRACE(("\tchanging colors...\n")); | |
875 XtVaSetValues(dispobj, | |
876 XtNforeground, value->foreground, | |
877 XtNbackground, value->background, | |
878 NULL); | |
879 redraw = NeedRedraw; | |
880 } | |
881 if (mask & CAFonts) { | |
882 TRACE(("\tchanging fonts...\n")); | |
883 CDSetFonts(dispobj, value->fonts, value->num_fonts); | |
884 ocw->overthespot.lineheight = CDLineHeight(dispobj, | |
885 &ocw->overthespot.ascent); | |
886 redraw = NeedReconfig; | |
887 } | |
888 | |
889 return redraw; | |
890 } | |
891 | |
892 /*- setupModeWidget: do mode widget configuration on conversion startup -*/ | |
893 static void | |
894 setupModeWidget(ocw, mask, value) | |
895 OverTheSpotConversionWidget ocw; | |
896 unsigned long mask; | |
897 ConversionAttributes *value; | |
898 { | |
899 Widget inputobj = ocw->ccontrol.inputobj; | |
900 Widget dispobj; | |
901 Widget mode; | |
902 Arg modeargs[10]; | |
903 Arg shellargs[15]; | |
904 Cardinal i = 0, j = 0; | |
905 | |
906 TRACE(("setupModeWidget()\n")); | |
907 | |
908 /* choose appropriate widgets */ | |
909 if (mask & CAStatusArea) { | |
910 /* use fixed modedisplay */ | |
911 ocw->overthespot.modeshell = ocw->overthespot.modeshell_fix; | |
912 ocw->overthespot.modewidget = ocw->overthespot.modewidget_fix; | |
913 ocw->overthespot.modedisplayobj = ocw->overthespot.modedisplayobj_fix; | |
914 XtSetArg(shellargs[j], XtNparentWindow, ocw->ccontrol.clientwindow); j++; | |
915 XtSetArg(shellargs[j], XtNborderWidth, 0); j++; | |
916 XtSetArg(shellargs[j], XtNallowShellResize, False); j++; | |
917 XtSetArg(shellargs[j], XtNx, value->statusarea.x); j++; | |
918 XtSetArg(shellargs[j], XtNy, value->statusarea.y); j++; | |
919 XtSetArg(shellargs[j], XtNwidth, value->statusarea.width); j++; | |
920 XtSetArg(shellargs[j], XtNheight, value->statusarea.height); j++; | |
921 ocw->overthespot.modelocationspecified = True; | |
922 } else if (ocw->overthespot.modelocation == ModeTrackText && | |
923 enoughSpaceForStatus(ocw)) { | |
924 ocw->overthespot.modeshell = ocw->overthespot.modeshell_fix; | |
925 ocw->overthespot.modewidget = ocw->overthespot.modewidget_fix; | |
926 ocw->overthespot.modedisplayobj = ocw->overthespot.modedisplayobj_fix; | |
927 ocw->overthespot.modelocationspecified = False; | |
928 XtSetArg(shellargs[j], XtNparentWindow, ocw->ccontrol.clientwindow); j++; | |
929 XtSetArg(shellargs[j], XtNallowShellResize, True); j++; | |
930 XtSetArg(shellargs[j], XtNborderWidth, ocw->overthespot.saved_bw); j++; | |
931 } else if (ocw->overthespot.modelocation == ModeNone) { | |
932 ocw->overthespot.modeshell = NULL; | |
933 ocw->overthespot.modewidget = NULL; | |
934 ocw->overthespot.modedisplayobj = NULL; | |
935 ocw->overthespot.modelocationspecified = False; | |
936 return; | |
937 } else { | |
938 /* use floating modedisplay */ | |
939 ocw->overthespot.modeshell = ocw->overthespot.modeshell_float; | |
940 ocw->overthespot.modewidget = ocw->overthespot.modewidget_float; | |
941 ocw->overthespot.modedisplayobj = ocw->overthespot.modedisplayobj_float; | |
942 ocw->overthespot.modelocationspecified = False; | |
943 } | |
944 | |
945 mode = ocw->overthespot.modewidget; | |
946 dispobj = ocw->overthespot.modedisplayobj; | |
947 | |
948 XtSetArg(modeargs[i], XtNlabel, ICGetMode(inputobj)); i++; | |
949 if (mask & CAColormap) { | |
950 XtSetArg(modeargs[i], XtNcolormap, value->colormap); i++; | |
951 } | |
952 /* ignore background_pixmap... */ | |
953 | |
954 /* | |
955 * order of changing display object resources is important. | |
956 * see comment in setupDisplayObject() for details. | |
957 */ | |
958 if (mask & CAStatusFonts) { | |
959 TRACE(("\tchanging fonts...\n")); | |
960 CDSetFonts(dispobj, value->status_fonts, value->num_status_fonts); | |
961 } else { | |
962 /* reset to default */ | |
963 CDSetFonts(dispobj, (XFontStruct **)NULL, 0); | |
964 } | |
965 if (mask & CAColor) { | |
966 TRACE(("\tchanging colors...\n")); | |
967 XtVaSetValues(dispobj, | |
968 XtNforeground, value->foreground, | |
969 XtNbackground, value->background, | |
970 NULL); | |
971 XtSetArg(modeargs[i], XtNbackground, value->background); i++; | |
972 if (ocw->overthespot.borderforeground) { | |
973 XtSetArg(shellargs[j], XtNborderColor, value->foreground); j++; | |
974 } | |
975 } else { | |
976 XtSetArg(modeargs[i], XtNbackground, ocw->overthespot.background); i++; | |
977 } | |
978 | |
979 XtSetValues(mode, modeargs, i); | |
980 ICLRecomputeSize(mode); | |
981 | |
982 if (!(mask & CAStatusArea)) { | |
983 /* | |
984 * force shell to resize. | |
985 * it is because Shell doesn't honor its child's dimension | |
986 * at second (or later) realization. | |
987 */ | |
988 XtSetArg(shellargs[j], XtNwidth, mode->core.width); j++; | |
989 XtSetArg(shellargs[j], XtNheight, mode->core.height); j++; | |
990 } | |
991 XtSetValues(ocw->overthespot.modeshell, shellargs, j); | |
992 } | |
993 | |
994 /*- resetModeWidget: do mode widget reconfiguration on attribute change -*/ | |
995 static ResetStatus | |
996 resetModeWidget(ocw, mask, value) | |
997 OverTheSpotConversionWidget ocw; | |
998 unsigned long mask; | |
999 ConversionAttributes *value; | |
1000 { | |
1001 Widget mode = ocw->overthespot.modewidget; | |
1002 Widget dispobj = ocw->overthespot.modedisplayobj; | |
1003 ResetStatus redraw = NeedNone; | |
1004 | |
1005 TRACE(("resetModeWidget()\n")); | |
1006 | |
1007 if (ocw->overthespot.modeshell == NULL) return NeedNone; | |
1008 | |
1009 if (mask & CAStatusArea) { | |
1010 if (ocw->overthespot.modelocationspecified && | |
1011 ocw->overthespot.modeshell == ocw->overthespot.modeshell_fix) { | |
1012 XtVaSetValues(ocw->overthespot.modeshell, | |
1013 XtNx, value->statusarea.x, | |
1014 XtNy, value->statusarea.y, | |
1015 XtNwidth, value->statusarea.width, | |
1016 XtNheight, value->statusarea.height, | |
1017 NULL); | |
1018 } /* else ignore... */ | |
1019 } | |
1020 | |
1021 if (mask & CAColormap) { | |
1022 XtVaSetValues(mode, XtNcolormap, value->colormap, NULL); | |
1023 } | |
1024 | |
1025 if (mask & CAColor) { | |
1026 TRACE(("\tchanging colors...\n")); | |
1027 XtVaSetValues(dispobj, | |
1028 XtNforeground, value->foreground, | |
1029 XtNbackground, value->background, | |
1030 NULL); | |
1031 XtVaSetValues(mode, XtNbackground, value->background, NULL); | |
1032 if (ocw->overthespot.borderforeground) { | |
1033 XtVaSetValues(ocw->overthespot.modeshell, | |
1034 XtNborderColor, value->foreground, | |
1035 NULL); | |
1036 } | |
1037 redraw = NeedRedraw; | |
1038 } | |
1039 if (mask & CAStatusFonts) { | |
1040 TRACE(("\tchanging fonts...\n")); | |
1041 CDSetFonts(dispobj, value->status_fonts, value->num_status_fonts); | |
1042 ICLRecomputeSize(mode); | |
1043 redraw = NeedRedraw; | |
1044 } | |
1045 | |
1046 return redraw; | |
1047 } | |
1048 | |
1049 /*- locateTextCanvasInitial: put the text canvas at the initial position -*/ | |
1050 static void | |
1051 locateTextCanvasInitial(ocw) | |
1052 OverTheSpotConversionWidget ocw; | |
1053 { | |
1054 TextCanvas *tcp = ocw->overthespot.canvaslist; | |
1055 | |
1056 tcp->x = SPOTX(ocw); | |
1057 tcp->y = SPOTY(ocw) - ocw->overthespot.ascent; | |
1058 } | |
1059 | |
1060 /*- locateModeWidget: put the mode widget at the initial position -*/ | |
1061 static void | |
1062 locateModeWidget(ocw) | |
1063 OverTheSpotConversionWidget ocw; | |
1064 { | |
1065 Position x, y; | |
1066 Widget modewidget = ocw->overthespot.modewidget; | |
1067 Widget modeshell = ocw->overthespot.modeshell; | |
1068 int rootx, rooty; | |
1069 Window child; | |
1070 | |
1071 if (modeshell == ocw->overthespot.modeshell_fix) { | |
1072 /* must be tracking text type */ | |
1073 locateTrackingModeWidget(ocw, True, 0, 0); | |
1074 return; | |
1075 } | |
1076 | |
1077 switch (ocw->overthespot.modelocation) { | |
1078 case ModeTopLeft: | |
1079 x = 0; | |
1080 y = -(modewidget->core.height + modeshell->core.border_width * 2); | |
1081 y -= ocw->ccontrol.titlebarheight; | |
1082 break; | |
1083 case ModeTopRight: | |
1084 x = ocw->ccontrol.client_attr.width - modewidget->core.width + modeshell->core.border_width * 2; | |
1085 y = -(modewidget->core.height + modeshell->core.border_width * 2); | |
1086 y -= ocw->ccontrol.titlebarheight; | |
1087 break; | |
1088 case ModeBottomRight: | |
1089 x = ocw->ccontrol.client_attr.width - modewidget->core.width + modeshell->core.border_width * 2; | |
1090 y = ocw->ccontrol.client_attr.height; | |
1091 break; | |
1092 case ModeTrackText: /* in case of insufficient space in the client area */ | |
1093 x = CLAREA(ocw).x; | |
1094 y = CLAREA(ocw).y + CLAREA(ocw).height + 2; | |
1095 break; | |
1096 case ModeBottomLeft: | |
1097 x = 0; | |
1098 y = ocw->ccontrol.client_attr.height; | |
1099 break; | |
1100 default: | |
1101 /* ModeNone */ | |
1102 return; | |
1103 } | |
1104 | |
1105 (void)XTranslateCoordinates(XtDisplay(ocw), ocw->ccontrol.clientwindow, | |
1106 RootWindowOfScreen(XtScreen(ocw)), | |
1107 x, y, &rootx, &rooty, &child); | |
1108 MoveShell(ocw->overthespot.modeshell, rootx, rooty); | |
1109 } | |
1110 | |
1111 /*- locateTrackingModeWidget: put the tracking text type mode widget at appropriate position */ | |
1112 static void | |
1113 locateTrackingModeWidget(ocw, initial, x, y) | |
1114 OverTheSpotConversionWidget ocw; | |
1115 Boolean initial; | |
1116 Position x; | |
1117 Position y; | |
1118 { | |
1119 Widget modewidget = ocw->overthespot.modewidget; | |
1120 Widget modeshell = ocw->overthespot.modeshell; | |
1121 Dimension width, height; | |
1122 XRectangle *clarea = &CLAREA(ocw); | |
1123 static Position lastx, lasty; | |
1124 | |
1125 if (initial) { | |
1126 x = SPOTX(ocw); | |
1127 y = SPOTY(ocw) - ocw->overthespot.ascent | |
1128 + ocw->overthespot.lineheight; | |
1129 } else if (x == lastx && y == lasty) { | |
1130 return; | |
1131 } | |
1132 | |
1133 lastx = x; | |
1134 lasty = y; | |
1135 | |
1136 width = modewidget->core.width + modeshell->core.border_width * 2; | |
1137 height = modewidget->core.height + modeshell->core.border_width * 2; | |
1138 | |
1139 /* adjust x */ | |
1140 if (x + width > clarea->x + clarea->width) { | |
1141 x = clarea->x + clarea->width - width; | |
1142 } | |
1143 if (x < clarea->x) x = clarea->x; | |
1144 | |
1145 /* adjust y */ | |
1146 if (y + height + 2 <= clarea->y + clarea->height) { | |
1147 y += 2; /* make some (2pixels high) space between text and mode */ | |
1148 } else if (y + height > clarea->y + clarea->height) { | |
1149 Position initx, inity; | |
1150 | |
1151 if (initial) { | |
1152 initx = SPOTX(ocw); | |
1153 inity = SPOTY(ocw) - ocw->overthespot.ascent; | |
1154 } else { | |
1155 TextCanvas *tcp = ocw->overthespot.canvaslist; | |
1156 initx = tcp->x; | |
1157 inity = tcp->y; | |
1158 } | |
1159 if (inity - height > clarea->y) { | |
1160 y = inity - height; | |
1161 } else if (x + width < initx) { | |
1162 y = inity - modeshell->core.border_width * 2; | |
1163 } else if (clarea->x + width < initx) { | |
1164 x = initx - width; | |
1165 y = inity - modeshell->core.border_width * 2; | |
1166 } else { | |
1167 x = initx - width; | |
1168 y = inity - height; | |
1169 } | |
1170 if (y < clarea->y) y = clarea->y; | |
1171 } | |
1172 XtMoveWidget(modeshell, x, y); | |
1173 } | |
1174 | |
1175 /*- redrawAndReconfigureTextCanvas: redraw & reconfigure text canvas -*/ | |
1176 static void | |
1177 redrawAndReconfigureTextCanvas(ocw) | |
1178 OverTheSpotConversionWidget ocw; | |
1179 { | |
1180 TextCanvas *tcp = ocw->overthespot.canvaslist; | |
1181 | |
1182 TRACE(("OverTheSpotConversion:redrawAndReconfigureTextCanvas()\n")); | |
1183 | |
1184 /* popdown and clear all canvases */ | |
1185 while (tcp != NULL) { | |
1186 if (tcp->poppedup) XtPopdown(tcp->canvas); | |
1187 tcp->poppedup = False; | |
1188 if (XtIsRealized(tcp->canvas)) { | |
1189 XClearArea(XtDisplay(tcp->canvas), XtWindow(tcp->canvas), | |
1190 0, 0, 0, 0, True); | |
1191 } | |
1192 tcp = tcp->next; | |
1193 } | |
1194 locateTextCanvasInitial(ocw); | |
1195 recomputeDisplaySegments(ocw); | |
1196 computeCursor(ocw); | |
1197 reconfigureDisplay(ocw); | |
1198 } | |
1199 | |
1200 /* | |
1201 *+ inputobject callback | |
1202 */ | |
1203 | |
1204 /*- UpdateText: update text -*/ | |
1205 static void | |
1206 UpdateText(w) | |
1207 Widget w; | |
1208 { | |
1209 OverTheSpotConversionWidget ocw = (OverTheSpotConversionWidget)w; | |
1210 | |
1211 TRACE(("OverTheSpotConversion:UpdateText()\n")); | |
1212 eraseCursor(ocw); | |
1213 computeDisplaySegments(ocw); | |
1214 computeCursor(ocw); | |
1215 reconfigureDisplay(ocw); | |
1216 updateDisplay(ocw); | |
1217 showCursor(ocw); | |
1218 } | |
1219 | |
1220 /*- UpdateMode: update mode -*/ | |
1221 static void | |
1222 UpdateMode(w) | |
1223 Widget w; | |
1224 { | |
1225 OverTheSpotConversionWidget ocw = (OverTheSpotConversionWidget)w; | |
1226 | |
1227 if (ocw->overthespot.modewidget == NULL) return; | |
1228 | |
1229 XtVaSetValues(ocw->overthespot.modewidget, | |
1230 XtNlabel, ICGetMode(ocw->ccontrol.inputobj), | |
1231 NULL); | |
1232 #ifdef notdef | |
1233 /* a hack... */ | |
1234 if (ocw->overthespot.modeshell == ocw->overthespot.modeshell_float && | |
1235 XtIsRealized(ocw->overthespot.modeshell)) { | |
1236 XRaiseWindow(XtDisplay(ocw->overthespot.modeshell), | |
1237 XtWindow(ocw->overthespot.modeshell)); | |
1238 } | |
1239 #endif | |
1240 } | |
1241 | |
1242 /*- SelectionControl: selection control -*/ | |
1243 static void | |
1244 SelectionControl(w, arg) | |
1245 Widget w; | |
1246 ICSelectionControlArg *arg; | |
1247 { | |
1248 OverTheSpotConversionWidget ocw = (OverTheSpotConversionWidget)w; | |
1249 | |
1250 switch (arg->command) { | |
1251 case ICSelectionStart: | |
1252 SelectionStart(ocw, arg->u.selection_kind); | |
1253 break; | |
1254 case ICSelectionEnd: | |
1255 SelectionEnd(ocw, &arg->u.current_item); | |
1256 break; | |
1257 case ICSelectionSet: | |
1258 SelectionSet(ocw, arg->u.current_item); | |
1259 break; | |
1260 case ICSelectionMove: | |
1261 SelectionMove(ocw, arg->u.dir); | |
1262 break; | |
1263 case ICSelectionGet: | |
1264 SelectionGet(ocw, &arg->u.current_item); | |
1265 break; | |
1266 default: | |
1267 XtAppWarning(XtWidgetToApplicationContext(w), | |
1268 "OverTheSpotConversion: unknown selection control command"); | |
1269 break; | |
1270 } | |
1271 } | |
1272 | |
1273 /*- SelectionStart: selection startup -*/ | |
1274 /* ARGSUSED */ | |
1275 static void | |
1276 SelectionStart(ocw, kind) | |
1277 OverTheSpotConversionWidget ocw; | |
1278 int kind; | |
1279 { | |
1280 Cardinal ncand; | |
1281 | |
1282 TRACE(("OverTheSpotConversion:SelectionStart()\n")); | |
1283 if (ocw->overthespot.selectionpoppedup) { | |
1284 DPRINT(("\tselection already started -- ignored\n")); | |
1285 return; | |
1286 } | |
1287 | |
1288 ocw->overthespot.candlist = ICGetItemList(ocw->ccontrol.inputobj, &ncand); | |
1289 ocw->overthespot.numcands = ncand; | |
1290 | |
1291 TRACE(("\tnumcands=%d\n", ocw->overthespot.numcands)); | |
1292 CPanelSetList(ocw->overthespot.selectionwidget, | |
1293 ocw->overthespot.candlist, | |
1294 ocw->overthespot.numcands, 0, True); | |
1295 | |
1296 locateSelectionPopup(ocw); | |
1297 XtPopup(ocw->overthespot.selectionshell, XtGrabNone); | |
1298 ocw->overthespot.selectionpoppedup = True; | |
1299 } | |
1300 | |
1301 /*- locateSelectionPopup: put selection popup at an appropriate position -*/ | |
1302 static void | |
1303 locateSelectionPopup(ocw) | |
1304 OverTheSpotConversionWidget ocw; | |
1305 { | |
1306 Position x, y; | |
1307 int clx, cly; | |
1308 Dimension dpyWidth, dpyHeight; | |
1309 Widget panel = ocw->overthespot.selectionwidget; | |
1310 Widget shell = ocw->overthespot.selectionshell; | |
1311 Window junk; | |
1312 int barheight = ocw->ccontrol.titlebarheight; | |
1313 | |
1314 (void)XTranslateCoordinates(XtDisplay(ocw), | |
1315 ocw->ccontrol.clientwindow, | |
1316 RootWindowOfScreen(XtScreen(ocw)), | |
1317 0, 0, &clx, &cly, &junk); | |
1318 | |
1319 if (ocw->overthespot.numsegments > 0) { | |
1320 DisplayLocation lastp; | |
1321 DisplaySegment *dsp = ocw->overthespot.dispsegments; | |
1322 int i; | |
1323 int offset = 0; | |
1324 | |
1325 /* find current segment. if not found, use last segment */ | |
1326 for (i = 0; i < ocw->overthespot.numsegments - 1; i++) { | |
1327 if (dsp[i].seg.attr & ICAttrCurrentSegment) break; | |
1328 } | |
1329 | |
1330 computeLastPosition(dsp[i].fragments, &lastp); | |
1331 if (lastp.canvas == ocw->overthespot.overflowcanvas) { | |
1332 offset = ocw->overthespot.overflowoffset; | |
1333 } | |
1334 x = clx + lastp.canvas->x + lastp.x | |
1335 - panel->core.width / 2 + offset; | |
1336 y = cly + lastp.canvas->y + lastp.y + ocw->overthespot.lineheight; | |
1337 } else { | |
1338 x = clx + SPOTX(ocw) - panel->core.width / 2; | |
1339 y = cly + SPOTY(ocw); | |
1340 } | |
1341 | |
1342 dpyWidth = WidthOfScreen(XtScreen(shell)); | |
1343 dpyHeight = HeightOfScreen(XtScreen(shell)); | |
1344 | |
1345 if (x + panel->core.width > (int)dpyWidth) x = dpyWidth - panel->core.width; | |
1346 if (x < 0) x = 0; | |
1347 if (y + panel->core.height + barheight > (int)dpyHeight) { | |
1348 y = cly + SPOTY(ocw) - panel->core.height - barheight; | |
1349 if (y < 0) y = dpyHeight - panel->core.height - barheight; | |
1350 } | |
1351 MoveShell(shell, x, y); | |
1352 } | |
1353 | |
1354 /*- SelectionEnd: selection finish -*/ | |
1355 static void | |
1356 SelectionEnd(ocw, current) | |
1357 OverTheSpotConversionWidget ocw; | |
1358 int *current; | |
1359 { | |
1360 TRACE(("OverTheSpotConversion:SelectionEnd()\n")); | |
1361 | |
1362 if (!ocw->overthespot.selectionpoppedup) { /* for safe */ | |
1363 TRACE(("\tnot in selection mode -- ignored\n")); | |
1364 return; | |
1365 } | |
1366 | |
1367 XtVaGetValues(ocw->overthespot.selectionwidget, | |
1368 XtNcurrentItem, current, | |
1369 NULL); | |
1370 | |
1371 XtPopdown(ocw->overthespot.selectionshell); | |
1372 | |
1373 ocw->overthespot.selectionpoppedup = False; | |
1374 } | |
1375 | |
1376 /*- SelectionSet: set current selection item -*/ | |
1377 static void | |
1378 SelectionSet(ocw, current) | |
1379 OverTheSpotConversionWidget ocw; | |
1380 int current; | |
1381 { | |
1382 TRACE(("OverTheSpotConversion:SelectionSet()\n")); | |
1383 | |
1384 if (!ocw->overthespot.selectionpoppedup) { /* for safe */ | |
1385 TRACE(("\tnot in selection mode -- ignored\n")); | |
1386 return; | |
1387 } | |
1388 | |
1389 XtVaSetValues(ocw->overthespot.selectionwidget, | |
1390 XtNcurrentItem, current, | |
1391 NULL); | |
1392 } | |
1393 | |
1394 /*- SelectionGet: get current selection item -*/ | |
1395 static void | |
1396 SelectionGet(ocw, current) | |
1397 OverTheSpotConversionWidget ocw; | |
1398 int *current; | |
1399 { | |
1400 TRACE(("OverTheSpotConversion:SelectionGet()\n")); | |
1401 | |
1402 if (!ocw->overthespot.selectionpoppedup) { /* for safe */ | |
1403 TRACE(("\tnot in selection mode -- ignored\n")); | |
1404 return; | |
1405 } | |
1406 | |
1407 XtVaGetValues(ocw->overthespot.selectionwidget, | |
1408 XtNcurrentItem, current, | |
1409 NULL); | |
1410 } | |
1411 | |
1412 /*- SelectionMove: move crrent selection to specified direction -*/ | |
1413 static void | |
1414 SelectionMove(ocw, dir) | |
1415 OverTheSpotConversionWidget ocw; | |
1416 int dir; | |
1417 { | |
1418 TRACE(("OverTheSpotConversion:SelectionMove()\n")); | |
1419 | |
1420 if (!ocw->overthespot.selectionpoppedup) { /* for safe */ | |
1421 TRACE(("\tnot in selection mode -- ignored\n")); | |
1422 return; | |
1423 } | |
1424 | |
1425 CPanelMoveCurrent(ocw->overthespot.selectionwidget, dir); | |
1426 } | |
1427 | |
1428 /*- ForwardSpot: forward spot location when text is fixed -*/ | |
1429 /* ARGSUSED */ | |
1430 static void | |
1431 ForwardSpot(w, client_data, call_data) | |
1432 Widget w; | |
1433 XtPointer client_data; | |
1434 XtPointer call_data; | |
1435 { | |
1436 OverTheSpotConversionWidget ocw = (OverTheSpotConversionWidget)client_data; | |
1437 DisplaySegment *dsp = ocw->overthespot.dispsegments; | |
1438 Cardinal nsegs = ocw->overthespot.numsegments; | |
1439 DisplayLocation disploc; | |
1440 | |
1441 if (!ocw->overthespot.spotforwarding || nsegs == 0) return; | |
1442 | |
1443 /* get next spot location */ | |
1444 computeLastPosition(dsp[nsegs - 1].fragments, &disploc); | |
1445 | |
1446 SPOTX(ocw) = disploc.canvas->x + disploc.x; | |
1447 SPOTY(ocw) = disploc.canvas->y + disploc.y + ocw->overthespot.ascent; | |
1448 locateTextCanvasInitial(ocw); | |
1449 } | |
1450 | |
1451 /* | |
1452 * Aux Callback | |
1453 */ | |
1454 | |
1455 static void | |
1456 AuxControl(w, arg) | |
1457 Widget w; | |
1458 ICAuxControlArg *arg; | |
1459 { | |
1460 OverTheSpotConversionWidget ocw = (OverTheSpotConversionWidget)w; | |
1461 String params[1]; | |
1462 Cardinal num_params; | |
1463 | |
1464 switch (arg->command) { | |
1465 case ICAuxStart: | |
1466 AuxStart(ocw); | |
1467 break; | |
1468 case ICAuxEnd: | |
1469 AuxEnd(ocw); | |
1470 break; | |
1471 case ICAuxChange: | |
1472 AuxChange(ocw); | |
1473 break; | |
1474 default: | |
1475 params[0] = XtClass(w)->core_class.class_name; | |
1476 num_params = 1; | |
1477 XtAppWarningMsg(XtWidgetToApplicationContext(w), | |
1478 "parameterError", "AuxControl", "WidgetError", | |
1479 "%s: unknown aux control command", | |
1480 params, &num_params); | |
1481 break; | |
1482 } | |
1483 } | |
1484 | |
1485 /* ARGSUSED */ | |
1486 static void | |
1487 AuxStart(ocw) | |
1488 OverTheSpotConversionWidget ocw; | |
1489 { | |
1490 ICString *auxstr; | |
1491 Cardinal ncand, curseg, cursorpos; | |
1492 | |
1493 if (ocw->overthespot.auxpoppedup) return; | |
1494 | |
1495 /* $B%F%-%9%H%3!<%k%P%C%/$N;~$N$h$&$J=hM}$r$9$k(B | |
1496 $B$N$O(B AuxPanel.c $B$K$^$+$;$h$&(B */ | |
1497 | |
1498 auxstr = ICGetAuxSegments(ocw->ccontrol.inputobj, | |
1499 &ncand, &curseg, &cursorpos); | |
1500 | |
1501 APanelStart(ocw->overthespot.auxwidget, auxstr, ncand, curseg, cursorpos); | |
1502 | |
1503 /* $B%]%C%W%"%C%W$9$k>l=j$r7h$a$k(B */ | |
1504 locateAuxPopup(ocw, False); | |
1505 | |
1506 XtPopup(ocw->overthespot.auxshell, XtGrabNone); | |
1507 ocw->overthespot.auxpoppedup = True; | |
1508 } | |
1509 | |
1510 /* ARGSUSED */ | |
1511 static void | |
1512 AuxEnd(ocw) | |
1513 OverTheSpotConversionWidget ocw; | |
1514 { | |
1515 if (!ocw->overthespot.auxpoppedup) return; /* for safe */ | |
1516 | |
1517 /* APanelEnd(ocw->overthespot.auxwidget); */ | |
1518 | |
1519 XtPopdown(ocw->overthespot.auxshell); | |
1520 | |
1521 ocw->overthespot.auxpoppedup = False; | |
1522 } | |
1523 | |
1524 /* ARGSUSED */ | |
1525 static void | |
1526 AuxChange(ocw) | |
1527 OverTheSpotConversionWidget ocw; | |
1528 { | |
1529 Cardinal ncand, curseg, cursorpos; | |
1530 ICString *auxstr; | |
1531 | |
1532 if (!ocw->overthespot.auxpoppedup) return; /* for safe */ | |
1533 | |
1534 auxstr = ICGetAuxSegments(ocw->ccontrol.inputobj, | |
1535 &ncand, &curseg, &cursorpos); | |
1536 | |
1537 APanelChange(ocw->overthespot.auxwidget, auxstr, ncand, curseg, cursorpos); | |
1538 | |
1539 /* reposition popup shell */ | |
1540 locateAuxPopup(ocw, True); | |
1541 } | |
1542 | |
1543 /*- locateAuxPopup: put aux popup at an appropriate position -*/ | |
1544 static void | |
1545 locateAuxPopup(ocw, usecurloc) | |
1546 OverTheSpotConversionWidget ocw; | |
1547 Boolean usecurloc; /* use the current location as the default */ | |
1548 { | |
1549 int x, y; | |
1550 int clx, cly; | |
1551 int dpyWidth, dpyHeight; | |
1552 Widget panel = ocw->overthespot.auxwidget; | |
1553 Widget shell = ocw->overthespot.auxshell; | |
1554 Window junk; | |
1555 int barheight = ocw->ccontrol.titlebarheight; | |
1556 | |
1557 (void)XTranslateCoordinates(XtDisplay(ocw), | |
1558 ocw->ccontrol.clientwindow, | |
1559 RootWindowOfScreen(XtScreen(ocw)), | |
1560 0, 0, &clx, &cly, &junk); | |
1561 | |
1562 if (usecurloc) { | |
1563 x = shell->core.x; | |
1564 y = shell->core.y; | |
1565 } else { | |
1566 if (ocw->overthespot.numsegments > 0) { | |
1567 DisplayLocation lastp; | |
1568 DisplaySegment *dsp = ocw->overthespot.dispsegments; | |
1569 int i; | |
1570 int offset; | |
1571 | |
1572 /* find current segment. if not found, use last segment */ | |
1573 for (i = 0; i < ocw->overthespot.numsegments - 1; i++) { | |
1574 if (dsp[i].seg.attr & ICAttrCurrentSegment) break; | |
1575 } | |
1576 | |
1577 computeLastPosition(dsp[i].fragments, &lastp); | |
1578 if (lastp.canvas == ocw->overthespot.overflowcanvas) | |
1579 offset = ocw->overthespot.overflowoffset; | |
1580 else | |
1581 offset = 0; | |
1582 x = clx + lastp.canvas->x + lastp.x | |
1583 - panel->core.width / 2 + offset; | |
1584 y = cly + lastp.canvas->y + lastp.y + ocw->overthespot.lineheight; | |
1585 } else { | |
1586 x = clx + ocw->overthespot.spotx - panel->core.width / 2; | |
1587 y = cly + ocw->overthespot.spoty; | |
1588 } | |
1589 } | |
1590 | |
1591 dpyWidth = (int)WidthOfScreen(XtScreen(shell)); | |
1592 dpyHeight = (int)HeightOfScreen(XtScreen(shell)); | |
1593 | |
1594 if ((int)(x + panel->core.width) > dpyWidth) x = dpyWidth - panel->core.width; | |
1595 if (x < 0) x = 0; | |
1596 if ((int)(y + panel->core.height + barheight) > dpyHeight) { | |
1597 y = cly + ocw->overthespot.spoty - panel->core.height - barheight; | |
1598 if (y < 0) y = dpyHeight - panel->core.height - barheight; | |
1599 } | |
1600 MoveShell(shell, x, y); | |
1601 } | |
1602 | |
1603 | |
1604 /* | |
1605 *+ TextCanvas callback | |
1606 */ | |
1607 | |
1608 /*- TextRedisplay: redraw text canvas -*/ | |
1609 static void | |
1610 TextRedisplay(w, client_data, call_data) | |
1611 Widget w; | |
1612 XtPointer client_data; | |
1613 XtPointer call_data; | |
1614 { | |
1615 OverTheSpotConversionWidget ocw = (OverTheSpotConversionWidget)client_data; | |
1616 XExposeEvent *event = (XExposeEvent *)call_data; | |
1617 XRectangle region; | |
1618 Boolean cursorredraw; | |
1619 | |
1620 TRACE(("OverTheSpotConversion:TextRedisplay()\n")); | |
1621 region.x = event->x; | |
1622 region.y = event->y; | |
1623 region.width = event->width; | |
1624 region.height = event->height; | |
1625 | |
1626 cursorredraw = exposeCursor(ocw, w, ®ion); | |
1627 redrawSegments(ocw, w, ®ion); | |
1628 if (cursorredraw) showCursor(ocw); | |
1629 } | |
1630 | |
1631 | |
1632 /* | |
1633 *+ Selection Widget callback | |
1634 */ | |
1635 | |
1636 /*- SelectionSelected: selection selected callback -*/ | |
1637 /* ARGSUSED */ | |
1638 static void | |
1639 SelectionSelected(w, client_data, call_data) | |
1640 Widget w; | |
1641 XtPointer client_data; | |
1642 XtPointer call_data; | |
1643 { | |
1644 OverTheSpotConversionWidget ocw = (OverTheSpotConversionWidget)client_data; | |
1645 int current = (int)call_data; | |
1646 | |
1647 TRACE(("OverTheSpotConversion:SelectionSelected()\n")); | |
1648 XtPopdown(ocw->overthespot.selectionshell); | |
1649 ocw->overthespot.selectionpoppedup = False; | |
1650 ICSelectItem(ocw->ccontrol.inputobj, current); | |
1651 } | |
1652 | |
1653 | |
1654 /* | |
1655 *+ text drawing functions | |
1656 */ | |
1657 | |
1658 /*- computeDisplaySegments: compare old&new text and update segments/fragments -*/ | |
1659 static void | |
1660 computeDisplaySegments(ocw) | |
1661 OverTheSpotConversionWidget ocw; | |
1662 { | |
1663 Widget inputobj = ocw->ccontrol.inputobj; | |
1664 int nnew = ICNumSegments(inputobj); | |
1665 int nold = ocw->overthespot.numsegments; | |
1666 ICString *newseg; | |
1667 DisplaySegment *dseg; | |
1668 DisplayLocation disploc; | |
1669 Cardinal nsame; | |
1670 int diff; | |
1671 int i; | |
1672 | |
1673 TRACE(("OverTheSpotConversion:computeDisplaySegments() nnew=%d\n", nnew)); | |
1674 allocDisplaySegments(ocw, nnew); | |
1675 | |
1676 ocw->overthespot.overflowcanvas = NULL; | |
1677 | |
1678 disploc.x = disploc.y = 0; | |
1679 if (ocw->overthespot.canvaslist == NULL) { | |
1680 ocw->overthespot.canvaslist = CreateTextCanvas(ocw); | |
1681 } | |
1682 disploc.canvas = ocw->overthespot.canvaslist; | |
1683 | |
1684 for (i = 0, dseg = ocw->overthespot.dispsegments; i < nnew; i++, dseg++) { | |
1685 newseg = ICGetSegment(ocw->ccontrol.inputobj, i); | |
1686 if (i >= nold) { | |
1687 copyString(newseg, &dseg->seg); | |
1688 dseg->redrawpos = 0; | |
1689 dseg->fragments = computeDisplayFragments(ocw, newseg, &disploc); | |
1690 } else { | |
1691 DisplayFragment *oldfragments, *newfragments; | |
1692 | |
1693 dseg->redrawpos = -1; | |
1694 diff = ICCompareSegment(inputobj, newseg, &dseg->seg, &nsame); | |
1695 if (diff != ICSame || | |
1696 disploc.canvas != dseg->fragments->canvas || | |
1697 disploc.x != dseg->fragments->region.x || | |
1698 disploc.y != dseg->fragments->region.y) { | |
1699 oldfragments = dseg->fragments; | |
1700 newfragments = computeDisplayFragments(ocw, newseg, &disploc); | |
1701 dseg->fragments = newfragments; | |
1702 } else { | |
1703 oldfragments = NULL; | |
1704 newfragments = dseg->fragments; | |
1705 computeLastPosition(newfragments, &disploc); | |
1706 } | |
1707 | |
1708 switch (diff) { | |
1709 case ICSame: | |
1710 if (oldfragments == NULL || | |
1711 oldfragments->canvas == newfragments->canvas && | |
1712 oldfragments->region.x == newfragments->region.x && | |
1713 oldfragments->region.y == newfragments->region.y) { | |
1714 dseg->redrawpos = -1; | |
1715 } else { | |
1716 dseg->redrawpos = 0; | |
1717 } | |
1718 break; | |
1719 case ICAttrChanged: | |
1720 dseg->redrawpos = 0; | |
1721 dseg->seg.attr = newseg->attr; | |
1722 break; | |
1723 case ICStringChanged: | |
1724 if (oldfragments == NULL || | |
1725 oldfragments->canvas == newfragments->canvas && | |
1726 oldfragments->region.x == newfragments->region.x && | |
1727 oldfragments->region.y == newfragments->region.y) { | |
1728 dseg->redrawpos = nsame; | |
1729 } else { | |
1730 dseg->redrawpos = 0; | |
1731 } | |
1732 freeString(&dseg->seg); | |
1733 copyString(newseg, &dseg->seg); | |
1734 break; | |
1735 default: | |
1736 dseg->redrawpos = 0; | |
1737 freeString(&dseg->seg); | |
1738 copyString(newseg, &dseg->seg); | |
1739 break; | |
1740 } | |
1741 if (oldfragments) freeDisplayFragments(oldfragments); | |
1742 } | |
1743 } | |
1744 | |
1745 for (; i < nold; i++, dseg++) freeDisplaySegment(dseg); | |
1746 | |
1747 ocw->overthespot.numsegments = nnew; | |
1748 } | |
1749 | |
1750 /*- recomputeDisplaySegments: recompute segments/fragments -*/ | |
1751 static void | |
1752 recomputeDisplaySegments(ocw) | |
1753 OverTheSpotConversionWidget ocw; | |
1754 { | |
1755 int nseg = ocw->overthespot.numsegments; | |
1756 DisplaySegment *dseg; | |
1757 DisplayLocation disploc; | |
1758 int i; | |
1759 | |
1760 ocw->overthespot.overflowcanvas = NULL; | |
1761 | |
1762 disploc.x = disploc.y = 0; | |
1763 if (ocw->overthespot.canvaslist == NULL) { | |
1764 ocw->overthespot.canvaslist = CreateTextCanvas(ocw); | |
1765 } | |
1766 disploc.canvas = ocw->overthespot.canvaslist; | |
1767 | |
1768 for (i = 0, dseg = ocw->overthespot.dispsegments; i < nseg; i++, dseg++) { | |
1769 freeDisplayFragments(dseg->fragments); | |
1770 dseg->redrawpos = 0; | |
1771 dseg->fragments = computeDisplayFragments(ocw, &dseg->seg, &disploc); | |
1772 } | |
1773 } | |
1774 | |
1775 /*- computeLastPosition: get last position of the specified fragment -*/ | |
1776 static void | |
1777 computeLastPosition(fragments, disploc) | |
1778 DisplayFragment *fragments; | |
1779 DisplayLocation *disploc; | |
1780 { | |
1781 while (fragments->next != NULL) fragments = fragments->next; | |
1782 disploc->canvas = fragments->canvas; | |
1783 disploc->x = fragments->region.x + fragments->region.width; | |
1784 disploc->y = fragments->region.y; | |
1785 } | |
1786 | |
1787 /*- computeDisplayFragments: compute fragment(s) of the specified segment -*/ | |
1788 static DisplayFragment * | |
1789 computeDisplayFragments(ocw, newseg, disploc) | |
1790 OverTheSpotConversionWidget ocw; | |
1791 ICString *newseg; | |
1792 DisplayLocation *disploc; | |
1793 { | |
1794 int start; | |
1795 int nchars; | |
1796 Widget dispobj = ocw->overthespot.displayobj; | |
1797 DisplayFragment *fragments, *dfp; | |
1798 int widthavailable; | |
1799 | |
1800 TRACE(("computeDisplayFragments()\n")); | |
1801 start = 0; | |
1802 fragments = NULL; | |
1803 while (start < newseg->nchars) { | |
1804 widthavailable = computeWidthAvailable(ocw, disploc); | |
1805 nchars = CDMaxChar(dispobj, newseg, start, widthavailable); | |
1806 if (nchars == 0) { | |
1807 if (disploc->canvas->x <= CLAREA(ocw).x && | |
1808 disploc->x == 0) { | |
1809 /* | |
1810 * specified width is too narrow to display a character. | |
1811 * we force to display at least one character per line. | |
1812 */ | |
1813 nchars = 1; | |
1814 } | |
1815 } | |
1816 TRACE(("\twidthavailable=%d, start=%d, maxchar=%d\n", widthavailable, start, nchars)); | |
1817 if (nchars > 0) { | |
1818 if (fragments == NULL) { | |
1819 fragments = dfp = allocDisplayFragment(); | |
1820 } else { | |
1821 dfp->next = allocDisplayFragment(); | |
1822 dfp = dfp->next; | |
1823 } | |
1824 dfp->from = start; | |
1825 dfp->nchars = nchars; | |
1826 dfp->canvas = disploc->canvas; | |
1827 dfp->region.x = disploc->x; | |
1828 dfp->region.y = disploc->y; | |
1829 dfp->region.width = CDStringWidth(dispobj, newseg, start, | |
1830 start + nchars); | |
1831 dfp->region.height = ocw->overthespot.lineheight; | |
1832 dfp->next = NULL; | |
1833 | |
1834 disploc->x += dfp->region.width; | |
1835 } | |
1836 start += nchars; | |
1837 if (start < newseg->nchars) nextLocation(ocw, disploc); | |
1838 } | |
1839 | |
1840 return fragments; | |
1841 } | |
1842 | |
1843 /*- computeWidthAvailable: return the width of the current line left for drawing -*/ | |
1844 /* ARGSUSED */ | |
1845 static int | |
1846 computeWidthAvailable(ocw, disploc) | |
1847 OverTheSpotConversionWidget ocw; | |
1848 DisplayLocation *disploc; | |
1849 { | |
1850 XRectangle *cregion = &CLAREA(ocw); | |
1851 | |
1852 if (disploc->canvas == ocw->overthespot.overflowcanvas) { | |
1853 /* we pretend this canvas is veeeeeeery wide */ | |
1854 return 9999; | |
1855 } | |
1856 return (cregion->x + cregion->width) - (disploc->canvas->x + disploc->x); | |
1857 } | |
1858 | |
1859 /*- nextLocation: return the position of the next line -*/ | |
1860 /* ARGSUSED */ | |
1861 static void | |
1862 nextLocation(ocw, disploc) | |
1863 OverTheSpotConversionWidget ocw; | |
1864 DisplayLocation *disploc; | |
1865 { | |
1866 XRectangle *cregion = &CLAREA(ocw); | |
1867 Position x, y; | |
1868 | |
1869 if (disploc->canvas->y + ocw->overthespot.linespacing * 2 > | |
1870 cregion->y + cregion->height) { | |
1871 /* no new canvas can create underneath this canvas */ | |
1872 ocw->overthespot.overflowcanvas = disploc->canvas; | |
1873 return; | |
1874 } | |
1875 | |
1876 if (disploc->canvas->next == NULL) { | |
1877 disploc->canvas->next = CreateTextCanvas(ocw); | |
1878 } | |
1879 x = CLAREA(ocw).x; | |
1880 y = disploc->canvas->y + ocw->overthespot.linespacing; | |
1881 disploc->canvas = disploc->canvas->next; | |
1882 disploc->x = disploc->y = 0; | |
1883 | |
1884 disploc->canvas->x = x; | |
1885 disploc->canvas->y = y; | |
1886 } | |
1887 | |
1888 /*- findLocation: compute the display position of specified char -*/ | |
1889 static DisplayLocation * | |
1890 findLocation(ocw, dsp, offset, disploc) | |
1891 OverTheSpotConversionWidget ocw; | |
1892 DisplaySegment *dsp; | |
1893 Cardinal offset; | |
1894 DisplayLocation *disploc; | |
1895 { | |
1896 DisplayFragment *dfp = dsp->fragments; | |
1897 | |
1898 while (dfp != NULL) { | |
1899 if (dfp->nchars > offset || | |
1900 dfp->next == NULL && dfp->nchars == offset) { | |
1901 break; | |
1902 } | |
1903 offset -= dfp->nchars; | |
1904 dfp = dfp->next; | |
1905 } | |
1906 if (dfp == NULL) return NULL; | |
1907 | |
1908 disploc->canvas = dfp->canvas; | |
1909 disploc->x = dfp->region.x + CDStringWidth(ocw->overthespot.displayobj, | |
1910 &dsp->seg, dfp->from, | |
1911 dfp->from + offset); | |
1912 disploc->y = dfp->region.y; | |
1913 | |
1914 return disploc; | |
1915 } | |
1916 | |
1917 /*- reconfigureDisplay: do reconfiguration of text canvas (resize/popup/popdown) -*/ | |
1918 static void | |
1919 reconfigureDisplay(ocw) | |
1920 OverTheSpotConversionWidget ocw; | |
1921 { | |
1922 DisplaySegment *dsp; | |
1923 DisplayFragment *dfp; | |
1924 TextCanvas *tcp, *lasttcp; | |
1925 Boolean shrink = ocw->overthespot.shrinkwindow; | |
1926 XRectangle *areap = &CLAREA(ocw); | |
1927 int i; | |
1928 | |
1929 for (tcp = ocw->overthespot.canvaslist; tcp != NULL; tcp = tcp->next) { | |
1930 tcp->maxx = tcp->maxy = 0; | |
1931 tcp->shouldpopup = False; | |
1932 } | |
1933 | |
1934 for (i = 0, dsp = ocw->overthespot.dispsegments; i < ocw->overthespot.numsegments; i++, dsp++) { | |
1935 for (dfp = dsp->fragments; dfp != NULL; dfp = dfp->next) { | |
1936 tcp = dfp->canvas; | |
1937 tcp->maxx = dfp->region.x + dfp->region.width; | |
1938 tcp->maxy = dfp->region.y + dfp->region.height; | |
1939 tcp->shouldpopup = True; | |
1940 } | |
1941 } | |
1942 | |
1943 lasttcp = NULL; | |
1944 for (tcp = ocw->overthespot.canvaslist; tcp != NULL; tcp = tcp->next) { | |
1945 if (tcp->maxx < tcp->canvas->core.width && XtIsRealized(tcp->canvas)) { | |
1946 XClearArea(XtDisplay(tcp->canvas), XtWindow(tcp->canvas), | |
1947 tcp->maxx, 0, 0, 0, False); | |
1948 } | |
1949 if (tcp->shouldpopup) lasttcp = tcp; | |
1950 } | |
1951 | |
1952 if (!ocw->overthespot.modelocationspecified && | |
1953 ocw->overthespot.modeshell == ocw->overthespot.modeshell_fix) { | |
1954 /* ModeTrackText */ | |
1955 if (lasttcp == NULL) { | |
1956 locateTrackingModeWidget(ocw, True, 0, 0); | |
1957 } else { | |
1958 locateTrackingModeWidget(ocw, False, lasttcp->x, | |
1959 lasttcp->y + lasttcp->maxy); | |
1960 } | |
1961 } | |
1962 | |
1963 if (ocw->overthespot.cursorvisible) { | |
1964 DisplayLocation *dlp = &ocw->overthespot.cursorlocation; | |
1965 XRectangle cbounds; | |
1966 int x; | |
1967 | |
1968 tcp = dlp->canvas; | |
1969 CDGetCursorBounds(ocw->overthespot.displayobj, &cbounds); | |
1970 x = dlp->x + cbounds.x + cbounds.width; | |
1971 if (x > tcp->maxx) tcp->maxx = x; | |
1972 } | |
1973 | |
1974 if (lasttcp != NULL && | |
1975 lasttcp->x + lasttcp->maxx > areap->x + areap->width) { | |
1976 ocw->overthespot.overflowcanvas = lasttcp; | |
1977 adjustDisplay(ocw); | |
1978 } | |
1979 | |
1980 for (tcp = ocw->overthespot.canvaslist; tcp != NULL; tcp = tcp->next) { | |
1981 Arg args[2]; | |
1982 int nargs = 0; | |
1983 if (tcp->shouldpopup && tcp->maxx > 0 && tcp->maxy > 0) { | |
1984 if (tcp == ocw->overthespot.overflowcanvas) { | |
1985 XtMoveWidget(tcp->canvas, | |
1986 tcp->x + ocw->overthespot.overflowoffset, tcp->y); | |
1987 } else if (tcp->x != tcp->canvas->core.x || | |
1988 tcp->y != tcp->canvas->core.y) { | |
1989 XtMoveWidget(tcp->canvas, tcp->x, tcp->y); | |
1990 } | |
1991 if (shrink || !tcp->poppedup || | |
1992 tcp->maxx > tcp->canvas->core.width) { | |
1993 XtSetArg(args[nargs], XtNwidth, tcp->maxx); nargs++; | |
1994 } | |
1995 if (!tcp->poppedup || tcp->maxy > tcp->canvas->core.height) { | |
1996 XtSetArg(args[nargs], XtNheight, tcp->maxy); nargs++; | |
1997 } | |
1998 if (nargs > 0) XtSetValues(tcp->canvas, args, nargs); | |
1999 | |
2000 if (!tcp->poppedup) { | |
2001 TRACE(("reconfigureDisplay(): canvas popup\n")); | |
2002 XtPopup(tcp->canvas, XtGrabNone); | |
2003 tcp->poppedup = True; | |
2004 } | |
2005 } else { | |
2006 if (tcp->poppedup) { | |
2007 TRACE(("reconfigureDisplay(): canvas popdown\n")); | |
2008 XtPopdown(tcp->canvas); | |
2009 tcp->poppedup = False; | |
2010 } | |
2011 } | |
2012 } | |
2013 } | |
2014 | |
2015 /*- updateDisplay: redraw text (if needed) -*/ | |
2016 static void | |
2017 updateDisplay(ocw) | |
2018 OverTheSpotConversionWidget ocw; | |
2019 { | |
2020 Widget dispobj = ocw->overthespot.displayobj; | |
2021 DisplaySegment *dsp = ocw->overthespot.dispsegments; | |
2022 int i; | |
2023 | |
2024 for (i = 0; i < ocw->overthespot.numsegments; i++, dsp++) { | |
2025 if (dsp->redrawpos >= 0) { | |
2026 TRACE(("updateDisplaySegment(seg#=%d)\n", i)); | |
2027 updateDisplaySegment(dispobj, dsp); | |
2028 } | |
2029 } | |
2030 } | |
2031 | |
2032 /*- updateDisplaySegment: redraw specified segment (if needed) -*/ | |
2033 static void | |
2034 updateDisplaySegment(dispobj, dsp) | |
2035 Widget dispobj; | |
2036 DisplaySegment *dsp; | |
2037 { | |
2038 DisplayFragment *dfp = dsp->fragments; | |
2039 int from; | |
2040 int x; | |
2041 | |
2042 while (dfp != NULL) { | |
2043 if (dsp->redrawpos < dfp->from + dfp->nchars) { | |
2044 from = (dsp->redrawpos > dfp->from) ? dsp->redrawpos : dfp->from; | |
2045 x = dfp->region.x; | |
2046 if (from > dfp->from) { | |
2047 x += CDStringWidth(dispobj, &dsp->seg, dfp->from, from); | |
2048 } | |
2049 CDDrawString(dispobj, dfp->canvas->canvas, &dsp->seg, | |
2050 from, dfp->from + dfp->nchars, | |
2051 x, dfp->region.y); | |
2052 } | |
2053 dfp = dfp->next; | |
2054 } | |
2055 } | |
2056 | |
2057 /*- redrawSegments: redraw segments in specified area -*/ | |
2058 static void | |
2059 redrawSegments(ocw, canvas, region) | |
2060 OverTheSpotConversionWidget ocw; | |
2061 Widget canvas; | |
2062 XRectangle *region; | |
2063 { | |
2064 DisplaySegment *dsp = ocw->overthespot.dispsegments; | |
2065 DisplayFragment *dfp; | |
2066 Widget dispobj = ocw->overthespot.displayobj; | |
2067 int i; | |
2068 | |
2069 for (i = 0; i < ocw->overthespot.numsegments; i++, dsp++) { | |
2070 for (dfp = dsp->fragments; dfp != NULL; dfp = dfp->next) { | |
2071 if (dfp->canvas->canvas == canvas && | |
2072 intersectRect(&dfp->region, region)) { | |
2073 CDDrawString(dispobj, canvas, &dsp->seg, | |
2074 dfp->from, dfp->from + dfp->nchars, | |
2075 dfp->region.x, dfp->region.y); | |
2076 } | |
2077 } | |
2078 } | |
2079 } | |
2080 | |
2081 /* | |
2082 *+ handle overflow canvas functions | |
2083 */ | |
2084 | |
2085 /*- adjustDisplay: compute appropriate offset for the overflow canvas -*/ | |
2086 static void | |
2087 adjustDisplay(ocw) | |
2088 OverTheSpotConversionWidget ocw; | |
2089 { | |
2090 Position outerleft, outerright, innerleft, innerright; | |
2091 TextCanvas *overflowcanvas = ocw->overthespot.overflowcanvas; | |
2092 Cardinal curseg; | |
2093 Cardinal curoffset; | |
2094 XRectangle *areap; | |
2095 Position offset; | |
2096 | |
2097 TRACE(("adjustDisplay()\n")); | |
2098 ocw->overthespot.overflowoffset = 0; | |
2099 | |
2100 /* | |
2101 * $B%9%H%i%F%8$H$7$F$O(B | |
2102 * $B%+%l%s%H%;%0%a%s%H!&%+%l%s%H%5%V%;%0%a%s%H!&%$%s%5!<%H%+!<%=%k$N$"$k(B | |
2103 * $B%;%0%a%s%H$N$I$l$b$J$1$l$P5$$K$7$J$$(B | |
2104 * $B%$%s%5!<%H%+!<%=%k$,$"$l$P$=$l$r:GM%@h$9$k!#$D$^$j%$%s%5!<%H%+!<%=%k(B | |
2105 * $B$O2?$,$"$C$F$bI=<($9$k$h$&$K$9$k!#(B | |
2106 * $B$G$-$l$P%$%s%5!<%H%+!<%=%k$N$"$k%;%0%a%s%H$O$9$Y$FI=<($9$k!#(B | |
2107 */ | |
2108 | |
2109 outerleft = innerleft = 9999; | |
2110 outerright = innerright = 0; | |
2111 | |
2112 if (ICCursorPos(ocw->ccontrol.inputobj, &curseg, &curoffset) == 1) { | |
2113 (void)getInsertingSegmentRange(ocw, overflowcanvas, | |
2114 curseg, curoffset, | |
2115 &outerleft, &outerright, &innerleft); | |
2116 if (outerleft <= outerright) innerright = innerleft + 2; /* XXX */ | |
2117 } else { | |
2118 (void)getAttributeSegmentRange(ocw, overflowcanvas, | |
2119 ICAttrCurrentSegment, | |
2120 &innerleft, &innerright); | |
2121 (void)getAttributeSegmentRange(ocw, overflowcanvas, | |
2122 ICAttrCurrentSubSegment, | |
2123 &outerleft, &outerright); | |
2124 } | |
2125 | |
2126 if (outerleft > outerright && innerleft > innerright) { | |
2127 /* no important segments is on the overflow canvas */ | |
2128 TRACE(("\tno important segments on the canvas\n")); | |
2129 return; | |
2130 } | |
2131 | |
2132 if (outerleft > innerleft) outerleft = innerleft; | |
2133 if (outerright < innerright) outerright = innerright; | |
2134 | |
2135 areap = &CLAREA(ocw); | |
2136 | |
2137 if (areap->x <= outerleft && outerright <= areap->x + areap->width) { | |
2138 /* important part fits in the visible area */ | |
2139 TRACE(("\timportant segments are visible\n")); | |
2140 return; | |
2141 } | |
2142 | |
2143 offset = 0; | |
2144 adjustOffset(areap, outerleft, outerright, &offset, False); | |
2145 adjustOffset(areap, innerleft, innerright, &offset, True); | |
2146 TRACE(("\toffset = %d\n", offset)); | |
2147 ocw->overthespot.overflowoffset = offset; | |
2148 } | |
2149 | |
2150 /*- getAttributeSegmentRange: compute span of segments which has the specified attributes -*/ | |
2151 static Boolean | |
2152 getAttributeSegmentRange(ocw, canvas, attr, leftp, rightp) | |
2153 OverTheSpotConversionWidget ocw; | |
2154 TextCanvas *canvas; | |
2155 int attr; | |
2156 Position *leftp; | |
2157 Position *rightp; | |
2158 { | |
2159 int nsegs = ocw->overthespot.numsegments; | |
2160 DisplaySegment *dseg = ocw->overthespot.dispsegments; | |
2161 DisplayFragment *dfp; | |
2162 Position left, right; | |
2163 | |
2164 left = 32767; | |
2165 right = 0; | |
2166 | |
2167 while (nsegs-- > 0) { | |
2168 if (dseg->seg.attr & attr) { | |
2169 dfp = dseg->fragments; | |
2170 | |
2171 while (dfp != NULL) { | |
2172 if (dfp->canvas == canvas) { | |
2173 if (dfp->region.x < left) left = dfp->region.x; | |
2174 if (right < dfp->region.x + dfp->region.width) { | |
2175 right = dfp->region.x + dfp->region.width; | |
2176 } | |
2177 } | |
2178 dfp = dfp->next; | |
2179 } | |
2180 } | |
2181 dseg++; | |
2182 } | |
2183 | |
2184 if (left > right) return False; | |
2185 | |
2186 *leftp = left + canvas->x; | |
2187 *rightp = right + canvas->x; | |
2188 return True; | |
2189 } | |
2190 | |
2191 /*- getInsertingSegmentRange: compute span of segments which has insert cursor -*/ | |
2192 static Boolean | |
2193 getInsertingSegmentRange(ocw, canvas, curseg, offset, leftp, rightp, posp) | |
2194 OverTheSpotConversionWidget ocw; | |
2195 TextCanvas *canvas; | |
2196 Cardinal curseg; | |
2197 Cardinal offset; | |
2198 Position *leftp; | |
2199 Position *rightp; | |
2200 Position *posp; | |
2201 { | |
2202 DisplaySegment *dseg = ocw->overthespot.dispsegments + curseg; | |
2203 DisplayFragment *dfp; | |
2204 Position left, right, insert; | |
2205 | |
2206 left = 32767; | |
2207 right = 0; | |
2208 | |
2209 dfp = dseg->fragments; | |
2210 | |
2211 while (dfp != NULL) { | |
2212 if (dfp->canvas == canvas && | |
2213 dfp->from <= offset && offset <= dfp->from + dfp->nchars) { | |
2214 if (dfp->region.x < left) left = dfp->region.x; | |
2215 if (right < dfp->region.x + dfp->region.width) { | |
2216 right = dfp->region.x + dfp->region.width; | |
2217 } | |
2218 | |
2219 if (offset == dfp->from) { | |
2220 insert = dfp->region.x; | |
2221 } else if (offset == dfp->from + dfp->nchars) { | |
2222 insert = dfp->region.x + dfp->region.width; | |
2223 } else { | |
2224 insert = dfp->region.x + | |
2225 CDStringWidth(ocw->overthespot.displayobj, | |
2226 &dseg->seg, dfp->from, | |
2227 offset); | |
2228 } | |
2229 break; | |
2230 } | |
2231 dfp = dfp->next; | |
2232 } | |
2233 | |
2234 if (left > right) return False; | |
2235 | |
2236 *leftp = left + canvas->x; | |
2237 *rightp = right + canvas->x; | |
2238 *posp = insert + canvas->x; | |
2239 return True; | |
2240 } | |
2241 | |
2242 /*- adjustOffset: make the span fit within the specified area -*/ | |
2243 static void | |
2244 adjustOffset(rectp, left, right, offsetp, force) | |
2245 XRectangle *rectp; | |
2246 Position left; | |
2247 Position right; | |
2248 Position *offsetp; | |
2249 Boolean force; | |
2250 { | |
2251 Position offset = *offsetp; | |
2252 | |
2253 if (rectp->x <= left + offset && | |
2254 right + offset <= rectp->x + rectp->width) return; | |
2255 | |
2256 if (right - left > rectp->width) { | |
2257 if (!force) return; | |
2258 /* centering */ | |
2259 offset = (rectp->x + rectp->width / 2) - (right + left) / 2; | |
2260 } else { | |
2261 if (left + offset < rectp->x) { | |
2262 offset = rectp->x - left; | |
2263 } else if (rectp->x + rectp->width < right + offset) { | |
2264 offset = rectp->x + rectp->width - right; | |
2265 } | |
2266 } | |
2267 *offsetp = offset; | |
2268 return; | |
2269 } | |
2270 | |
2271 | |
2272 /* | |
2273 *+ insert cursor handling functions | |
2274 */ | |
2275 | |
2276 /*- eraseCursor: erase insert cursor -*/ | |
2277 static void | |
2278 eraseCursor(ocw) | |
2279 OverTheSpotConversionWidget ocw; | |
2280 { | |
2281 if (!ocw->overthespot.cursorvisible) return; | |
2282 | |
2283 TRACE(("eraseCursor() at (%d,%d)\n", | |
2284 ocw->overthespot.cursorlocation.x, | |
2285 ocw->overthespot.cursorlocation.y)); | |
2286 CDDrawCursor(ocw->overthespot.displayobj, | |
2287 ocw->overthespot.cursorlocation.canvas->canvas, | |
2288 ocw->overthespot.cursorlocation.x, | |
2289 ocw->overthespot.cursorlocation.y, | |
2290 False); | |
2291 ocw->overthespot.cursorvisible = False; | |
2292 } | |
2293 | |
2294 /*- showCursor: draw insert cursor -*/ | |
2295 static void | |
2296 showCursor(ocw) | |
2297 OverTheSpotConversionWidget ocw; | |
2298 { | |
2299 if (!ocw->overthespot.cursorvisible) return; | |
2300 | |
2301 TRACE(("showCursor at (%d,%d)\n", | |
2302 ocw->overthespot.cursorlocation.x, | |
2303 ocw->overthespot.cursorlocation.y)); | |
2304 CDDrawCursor(ocw->overthespot.displayobj, | |
2305 ocw->overthespot.cursorlocation.canvas->canvas, | |
2306 ocw->overthespot.cursorlocation.x, | |
2307 ocw->overthespot.cursorlocation.y, | |
2308 True); | |
2309 } | |
2310 | |
2311 /*- exposeCursor: make the insert cursor redraw correctly when exposing -*/ | |
2312 static Boolean | |
2313 exposeCursor(ocw, w, region) | |
2314 OverTheSpotConversionWidget ocw; | |
2315 Widget w; | |
2316 XRectangle *region; | |
2317 { | |
2318 XRectangle bounds; | |
2319 | |
2320 if (!ocw->overthespot.cursorvisible || | |
2321 w != ocw->overthespot.cursorlocation.canvas->canvas) return False; | |
2322 | |
2323 TRACE(("exposeCursor(region=%d,%d-%d,%d)\n", | |
2324 region->x, region->y, region->width, region->height)); | |
2325 /* | |
2326 * if a part of the insert cursor is in the exposing region, | |
2327 * clear the entire cursor before redraw, since the cursor is | |
2328 * drawn with xor mode. | |
2329 */ | |
2330 CDGetCursorBounds(ocw->overthespot.displayobj, &bounds); | |
2331 bounds.x += ocw->overthespot.cursorlocation.x; | |
2332 bounds.y += ocw->overthespot.cursorlocation.y; | |
2333 if (intersectRect(region, &bounds)) { | |
2334 eraseCursor(ocw); | |
2335 XClearArea(XtDisplay(w), XtWindow(w), | |
2336 bounds.x, bounds.y, bounds.width, bounds.height, False); | |
2337 unionRect(region, &bounds, region); | |
2338 } | |
2339 ocw->overthespot.cursorvisible = True; | |
2340 return True; | |
2341 } | |
2342 | |
2343 /*- computeCursor: compute insert cursor position if visible -*/ | |
2344 static void | |
2345 computeCursor(ocw) | |
2346 OverTheSpotConversionWidget ocw; | |
2347 { | |
2348 DisplaySegment *dsp; | |
2349 DisplayLocation disploc; | |
2350 Cardinal seg, offset; | |
2351 | |
2352 if (!ICCursorPos(ocw->ccontrol.inputobj, &seg, &offset)) { | |
2353 ocw->overthespot.cursorvisible = False; | |
2354 return; | |
2355 } | |
2356 | |
2357 /* sanity check */ | |
2358 if (seg >= ocw->overthespot.numsegments) return; | |
2359 dsp = ocw->overthespot.dispsegments + seg; | |
2360 if (offset > dsp->seg.nchars) return; | |
2361 | |
2362 if (findLocation(ocw, dsp, offset, &disploc) == NULL) return; | |
2363 | |
2364 disploc.y += ocw->overthespot.ascent; | |
2365 | |
2366 ocw->overthespot.cursorvisible = True; | |
2367 ocw->overthespot.cursorlocation = disploc; | |
2368 } | |
2369 | |
2370 /* | |
2371 *+ resource converter | |
2372 */ | |
2373 | |
2374 /*- StringToModeLocation: string->mode-location resource converter -*/ | |
2375 /* ARGSUSED */ | |
2376 static void | |
2377 StringToModeLocation(args, num_args, from, to) | |
2378 XrmValue *args; | |
2379 Cardinal *num_args; | |
2380 XrmValue *from; | |
2381 XrmValue *to; | |
2382 { | |
2383 char *s = (char *)from->addr; | |
2384 static ModeLocation ml = ModeBottomLeft; | |
2385 | |
2386 if (!XmuCompareISOLatin1(s, "topleft")) ml = ModeTopLeft; | |
2387 else if (!XmuCompareISOLatin1(s, "topright")) ml = ModeTopRight; | |
2388 else if (!XmuCompareISOLatin1(s, "bottomleft")) ml = ModeBottomLeft; | |
2389 else if (!XmuCompareISOLatin1(s, "bottomright")) ml = ModeBottomRight; | |
2390 else if (!XmuCompareISOLatin1(s, "tracktext")) ml = ModeTrackText; | |
2391 else if (!XmuCompareISOLatin1(s, "none")) ml = ModeNone; | |
2392 else { | |
2393 XtStringConversionWarning(s, XtRModeLocation); | |
2394 } | |
2395 | |
2396 to->size = sizeof(ModeLocation); | |
2397 to->addr = (caddr_t)&ml; | |
2398 } | |
2399 | |
2400 /* | |
2401 *+ miscellaneous functions | |
2402 */ | |
2403 | |
2404 /*- MoveShell: move shell widget -*/ | |
2405 static void | |
2406 MoveShell(w, x, y) | |
2407 Widget w; | |
2408 Position x; | |
2409 Position y; | |
2410 { | |
2411 ShellWidget shell = (ShellWidget)w; | |
2412 | |
2413 TRACE(("MoveShell(%s,x=%d,y=%d,core.x=%d,core.y=%d)\n",XtName(w),x,y,w->core.x,w->core.y)); | |
2414 XtCheckSubclass(w, shellWidgetClass, | |
2415 "MoveShell: specified widget is not a shell"); | |
2416 /* | |
2417 * calling XtMoveWidget() is NOT enough to move shell widgets when | |
2418 * they are not mapped. we must use XtMakeGeometryRequest() or | |
2419 * XtSetValues() to invoke root-geometry-manager which modifies | |
2420 * the size hint appropriately. | |
2421 */ | |
2422 if (shell->shell.popped_up) { | |
2423 XtMoveWidget(w, x, y); | |
2424 } else { | |
2425 XtWidgetGeometry req; | |
2426 | |
2427 req.request_mode = CWX | CWY; | |
2428 req.x = x; | |
2429 req.y = y; | |
2430 (void)XtMakeGeometryRequest(w, &req, (XtWidgetGeometry *)NULL); | |
2431 } | |
2432 } | |
2433 | |
2434 /*- getToplevelWindow: get top-level window of a given window -*/ | |
2435 static Window | |
2436 getToplevelWindow(dpy, win, wm_state) | |
2437 Display *dpy; | |
2438 Window win; | |
2439 Atom wm_state; | |
2440 { | |
2441 Atom type; | |
2442 int format; | |
2443 unsigned long nitems, bytesafter; | |
2444 unsigned char *data; | |
2445 Window root, parent; | |
2446 Window *children; | |
2447 unsigned int nchildren; | |
2448 | |
2449 /* | |
2450 * find toplevel window which has WM_STATE property or if no exists, | |
2451 * direct subwindow of the root window. (ie I assume that if a | |
2452 * window manager is running, that is a ICCCM compliant one) | |
2453 */ | |
2454 for (;;) { | |
2455 type = None; | |
2456 if (wm_state != None) { | |
2457 data = NULL; | |
2458 XGetWindowProperty(dpy, win, wm_state, 0L, 0L, False, | |
2459 AnyPropertyType, &type, &format, | |
2460 &nitems, &bytesafter, &data); | |
2461 if (data != NULL) XtFree((char *)data); | |
2462 if (type != None) break; | |
2463 } | |
2464 if (!XQueryTree(dpy, win, &root, &parent, &children, &nchildren)) break; | |
2465 if (nchildren > 0) XtFree((char *)children); | |
2466 if (root == parent) break; | |
2467 win = parent; | |
2468 } | |
2469 return win; | |
2470 } | |
2471 | |
2472 /*- setTransientFor: set WM_TRANSIENT_FOR property to specified widget -*/ | |
2473 static void | |
2474 setTransientFor(w, win) | |
2475 Widget w; | |
2476 Window win; | |
2477 { | |
2478 if (w == NULL) return; | |
2479 if (!XtIsRealized(w)) XtRealizeWidget(w); | |
2480 XSetTransientForHint(XtDisplay(w), XtWindow(w), win); | |
2481 } | |
2482 | |
2483 /*-setMwmHints: set _MOTIF_WM_HINTS for mode shell -*/ | |
2484 static void | |
2485 setMwmHints(w) | |
2486 Widget w; | |
2487 { | |
2488 #define MWM_HINTS_ATOM "_MOTIF_WM_HINTS" | |
2489 #define MWM_HINTS_DECOR (1 << 1) | |
2490 #define MWM_DECOR_BORDER (1 << 1) | |
2491 Atom mwm_hints; | |
2492 unsigned long hints[5]; | |
2493 | |
2494 if (w == NULL) return; | |
2495 if (!XtIsRealized(w)) XtRealizeWidget(w); | |
2496 | |
2497 mwm_hints = CachedInternAtom(XtDisplay(w), MWM_HINTS_ATOM, False); | |
2498 if (mwm_hints == None) return; /* just in case.. */ | |
2499 | |
2500 hints[0] = MWM_HINTS_DECOR; /* flags */ | |
2501 hints[2] = MWM_DECOR_BORDER; /* decorations */ | |
2502 hints[1] = hints[3] = hints[4] = 0; /* functions, input mode and status */ | |
2503 | |
2504 XChangeProperty(XtDisplay(w), XtWindow(w), | |
2505 mwm_hints, mwm_hints, 32, PropModeReplace, | |
2506 (unsigned char *)hints, 5); | |
2507 } | |
2508 | |
2509 /*- getFocusOffset: get the focus window's position relative to the client window -*/ | |
2510 static void | |
2511 getFocusOffset(ocw) | |
2512 OverTheSpotConversionWidget ocw; | |
2513 { | |
2514 int offx, offy; | |
2515 Window junkw; | |
2516 | |
2517 if (ocw->ccontrol.focuswindow == ocw->ccontrol.clientwindow) { | |
2518 FOCUSOFFX(ocw) = 0; | |
2519 FOCUSOFFY(ocw) = 0; | |
2520 return; | |
2521 } | |
2522 XTranslateCoordinates(XtDisplay((Widget)ocw), | |
2523 ocw->ccontrol.focuswindow, | |
2524 ocw->ccontrol.clientwindow, | |
2525 0, 0, &offx, &offy, &junkw); | |
2526 FOCUSOFFX(ocw) = offx; | |
2527 FOCUSOFFY(ocw) = offy; | |
2528 } | |
2529 | |
2530 /*- intersectRect: returns given rectangles have a intersection -*/ | |
2531 static Boolean | |
2532 intersectRect(rect1, rect2) | |
2533 register XRectangle *rect1; | |
2534 register XRectangle *rect2; | |
2535 { | |
2536 return (rect1->x + rect1->width <= rect2->x || | |
2537 rect1->x >= rect2->x + rect2->width || | |
2538 rect1->y + rect1->height <= rect2->y || | |
2539 rect1->y >= rect2->y + rect2->height) ? False : True; | |
2540 } | |
2541 | |
2542 /*- unionRect: returns minimum rectangle that covers given rectangles -*/ | |
2543 static void | |
2544 unionRect(rect1, rect2, rect_ret) | |
2545 register XRectangle *rect1; | |
2546 register XRectangle *rect2; | |
2547 XRectangle *rect_ret; | |
2548 { | |
2549 int x0, x1, y0, y1; | |
2550 | |
2551 x0 = (rect1->x > rect2->x) ? rect2->x : rect1->x; | |
2552 y0 = (rect1->y > rect2->y) ? rect2->y : rect1->y; | |
2553 x1 = (rect1->x + rect1->width > rect2->x + rect2->width) ? | |
2554 rect1->x + rect1->width : rect2->x + rect2->width; | |
2555 y1 = (rect1->y + rect1->height > rect2->y + rect2->height) ? | |
2556 rect1->y + rect1->height : rect2->y + rect2->height; | |
2557 | |
2558 rect_ret->x = x0; | |
2559 rect_ret->y = y0; | |
2560 rect_ret->width = x1 - x0; | |
2561 rect_ret->height = y1 - y0; | |
2562 } | |
2563 | |
2564 /*- enoughSpaceForStatus: checks if there's enough space for the status display -*/ | |
2565 static int | |
2566 enoughSpaceForStatus(ocw) | |
2567 OverTheSpotConversionWidget ocw; | |
2568 { | |
2569 Widget modew = ocw->overthespot.modewidget_fix; | |
2570 int modespace; | |
2571 int ascent = ocw->overthespot.ascent; | |
2572 int descent = ocw->overthespot.lineheight - ascent; | |
2573 int lspace = ocw->overthespot.linespacing; | |
2574 int areatop = CLAREA(ocw).y; | |
2575 int areabottom = CLAREA(ocw).y + CLAREA(ocw).height; | |
2576 int top, bottom, y; | |
2577 | |
2578 if (lspace == 0) lspace = 1; /* avoid "divide by zero" error */ | |
2579 | |
2580 /* | |
2581 * tracking $B%9%F!<%?%9$,I=<($G$-$k$+$I$&$+%A%'%C%/$9$k$K$O!"%/%i%$(B | |
2582 * $B%"%s%H%(%j%"$KI=<($G$-$k:G=i$H:G8e$N9T$K$D$$$F$=$N>e$+2<$K%9%F!<(B | |
2583 * $B%?%9$,I=<($G$-$k$3$H$rD4$Y$l$P$h$$!#(B | |
2584 */ | |
2585 | |
2586 modespace = modew->core.height + modew->core.border_width * 2 + 2; | |
2587 | |
2588 /* $B:G=i$N9T$N>e2<$N(B Y $B:BI8$r7W;;$7$F%9%F!<%?%9$,I=<($G$-$k$+D4$Y$k(B */ | |
2589 y = SPOTY(ocw) - ascent; | |
2590 top = y - ((y - areatop) / lspace) * lspace; | |
2591 bottom = top + ascent + descent; | |
2592 if (top - areatop < modespace && areabottom - bottom < modespace) { | |
2593 return 0; | |
2594 } | |
2595 | |
2596 /* $B:G8e$N9T$N>e2<$N(B Y $B:BI8$r7W;;$7$F%9%F!<%?%9$,I=<($G$-$k$+D4$Y$k(B */ | |
2597 y = SPOTY(ocw) + descent; | |
2598 bottom = y + ((areabottom - y) / lspace) * lspace; | |
2599 top = bottom - (ascent + descent); | |
2600 if (top - areatop < modespace && areabottom - bottom < modespace) { | |
2601 return 0; | |
2602 } | |
2603 | |
2604 return 1; | |
2605 } | |
2606 | |
2607 static DisplayFragment *free_fragments = NULL; | |
2608 | |
2609 /*- allocDisplayFragment: get new fragment -*/ | |
2610 static DisplayFragment * | |
2611 allocDisplayFragment() | |
2612 { | |
2613 if (free_fragments == NULL) { | |
2614 return XtNew(DisplayFragment); | |
2615 } else { | |
2616 DisplayFragment *dfp = free_fragments; | |
2617 free_fragments = dfp->next; | |
2618 return dfp; | |
2619 } | |
2620 } | |
2621 | |
2622 /*- freeDisplayFragments: add specified fragment list to free-list -*/ | |
2623 static void | |
2624 freeDisplayFragments(fragments) | |
2625 DisplayFragment *fragments; | |
2626 { | |
2627 DisplayFragment *dfp = fragments; | |
2628 | |
2629 if (dfp == NULL) return; | |
2630 while (dfp->next != NULL) dfp = dfp->next; | |
2631 dfp->next = free_fragments; | |
2632 free_fragments = fragments; | |
2633 } | |
2634 | |
2635 /*- destroyDisplayFragments: free specified fragment list -*/ | |
2636 static void | |
2637 destroyDisplayFragments(fragments) | |
2638 DisplayFragment *fragments; | |
2639 { | |
2640 DisplayFragment *dfp; | |
2641 | |
2642 while (fragments != NULL) { | |
2643 dfp = fragments->next; | |
2644 XtFree((char *)fragments); | |
2645 fragments = dfp; | |
2646 } | |
2647 } | |
2648 | |
2649 /*- allocDisplaySegments: prepare specified number of display segments -*/ | |
2650 static void | |
2651 allocDisplaySegments(ocw, n) | |
2652 OverTheSpotConversionWidget ocw; | |
2653 int n; | |
2654 { | |
2655 if (ocw->overthespot.dispsegmentsize > n) return; | |
2656 n = ((n + 3) / 4) * 4 ; | |
2657 if (ocw->overthespot.dispsegments == NULL) { | |
2658 ocw->overthespot.dispsegments = (DisplaySegment *)XtMalloc(n * sizeof(DisplaySegment)); | |
2659 } else { | |
2660 ocw->overthespot.dispsegments = (DisplaySegment *)XtRealloc((char *)ocw->overthespot.dispsegments, n * sizeof(DisplaySegment)); | |
2661 } | |
2662 ocw->overthespot.dispsegmentsize = n; | |
2663 } | |
2664 | |
2665 /*- freeDisplaySegment: free display segment's contents -*/ | |
2666 static void | |
2667 freeDisplaySegment(dsp) | |
2668 DisplaySegment *dsp; | |
2669 { | |
2670 freeString(&dsp->seg); | |
2671 freeDisplayFragments(dsp->fragments); | |
2672 dsp->fragments = NULL; | |
2673 } | |
2674 | |
2675 /*- clearAllDisplaySegments: clear all display segment's -*/ | |
2676 static void | |
2677 clearAllDisplaySegments(ocw) | |
2678 OverTheSpotConversionWidget ocw; | |
2679 { | |
2680 DisplaySegment *dsp = ocw->overthespot.dispsegments; | |
2681 int i; | |
2682 | |
2683 for (i = 0; i < ocw->overthespot.numsegments; i++) { | |
2684 freeDisplaySegment(dsp++); | |
2685 } | |
2686 ocw->overthespot.numsegments = 0; | |
2687 } | |
2688 | |
2689 /*- copyString: copy ICString -*/ | |
2690 static void | |
2691 copyString(from, to) | |
2692 ICString *from; | |
2693 ICString *to; | |
2694 { | |
2695 *to = *from; | |
2696 to->data = XtMalloc(to->nbytes); | |
2697 (void)bcopy(from->data, to->data, to->nbytes); | |
2698 } | |
2699 | |
2700 /*- freeString: free ICString -*/ | |
2701 static void | |
2702 freeString(seg) | |
2703 ICString *seg; | |
2704 { | |
2705 XtFree(seg->data); | |
2706 seg->data = NULL; | |
2707 seg->nbytes = 0; | |
2708 } |