1 #if (!defined(lint) && !defined(SABER))
2 static char Xrcsid
[] = "$XConsortium: AsciiSink.c,v 1.49 89/12/14 19:15:55 converse Exp $";
3 #endif /* lint && SABER */
5 /***********************************************************
6 Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts,
7 and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
11 Permission to use, copy, modify, and distribute this software and its
12 documentation for any purpose and without fee is hereby granted,
13 provided that the above copyright notice appear in all copies and that
14 both that copyright notice and this permission notice appear in
15 supporting documentation, and that the names of Digital or MIT not be
16 used in advertising or publicity pertaining to distribution of the
17 software without specific, written prior permission.
19 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
20 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
21 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
22 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
23 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
24 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
27 ******************************************************************/
32 #include <X11/Xutil.h>
33 #include <X11/Xatom.h>
34 #include <X11/IntrinsicP.h>
35 #include <X11/StringDefs.h>
36 #include <./Xaw3_1XawInit.h>
37 #include <./Xaw3_1AsciiSinkP.h>
38 #include <./Xaw3_1AsciiSrcP.h> /* For source function defs. */
39 #include <./Xaw3_1TextP.h> /* I also reach into the text widget. */
42 #undef GETLASTPOS /* We will use our own GETLASTPOS. */
45 #define GETLASTPOS XawTextSourceScan(source, 0, XawstAll, XawsdRight, 1, TRUE)
47 static void Initialize(), Destroy();
48 static Boolean
SetValues();
50 static void DisplayText(), InsertCursor(), FindPosition();
51 static void FindDistance(), Resolve(), GetCursorBounds();
53 #define offset(field) XtOffset(AsciiSinkObject, ascii_sink.field)
55 static XtResource resources
[] = {
56 {XtNecho
, XtCOutput
, XtRBoolean
, sizeof(Boolean
),
57 offset(echo
), XtRImmediate
, (caddr_t
) True
},
58 {XtNdisplayNonprinting
, XtCOutput
, XtRBoolean
, sizeof(Boolean
),
59 offset(display_nonprinting
), XtRImmediate
, (caddr_t
) True
},
63 #define SuperClass (&textSinkClassRec)
64 AsciiSinkClassRec asciiSinkClassRec
= {
66 /* core_class fields */
67 /* superclass */ (WidgetClass
) SuperClass
,
68 /* class_name */ "AsciiSink",
69 /* widget_size */ sizeof(AsciiSinkRec
),
70 /* class_initialize */ XawInitializeWidgetSet
,
71 /* class_part_initialize */ NULL
,
72 /* class_inited */ FALSE
,
73 /* initialize */ Initialize
,
74 /* initialize_hook */ NULL
,
78 /* resources */ resources
,
79 /* num_resources */ XtNumber(resources
),
80 /* xrm_class */ NULLQUARK
,
85 /* destroy */ Destroy
,
88 /* set_values */ SetValues
,
89 /* set_values_hook */ NULL
,
91 /* get_values_hook */ NULL
,
93 /* version */ XtVersion
,
94 /* callback_private */ NULL
,
100 /* text_sink_class fields */
102 /* DisplayText */ DisplayText
,
103 /* InsertCursor */ InsertCursor
,
104 /* ClearToBackground */ XtInheritClearToBackground
,
105 /* FindPosition */ FindPosition
,
106 /* FindDistance */ FindDistance
,
107 /* Resolve */ Resolve
,
108 /* MaxLines */ XtInheritMaxLines
,
109 /* MaxHeight */ XtInheritMaxHeight
,
110 /* SetTabs */ XtInheritSetTabs
,
111 /* GetCursorBounds */ GetCursorBounds
113 /* ascii_sink_class fields. */
115 /* Keep Compiler happy. */ NULL
119 WidgetClass asciiSinkObjectClass
= (WidgetClass
)&asciiSinkClassRec
;
129 register int i
, width
, nonPrinting
;
130 AsciiSinkObject sink
= (AsciiSinkObject
) w
;
131 XFontStruct
*font
= sink
->text_sink
.font
;
134 if ( c
== LF
) return(0);
137 /* Adjust for Left Margin. */
138 x
-= ((TextWidget
) XtParent(w
))->text
.margin
.left
;
140 if (x
>= XtParent(w
)->core
.width
) return 0;
141 for (i
= 0, tab
= sink
->text_sink
.tabs
;
142 i
< sink
->text_sink
.tab_count
; i
++, tab
++) {
144 if (*tab
< XtParent(w
)->core
.width
)
153 if ( (nonPrinting
= (c
< (unsigned char) SP
)) )
154 if (sink
->ascii_sink
.display_nonprinting
)
161 if (font
->per_char
&&
162 (c
>= font
->min_char_or_byte2
&& c
<= font
->max_char_or_byte2
))
163 width
= font
->per_char
[c
- font
->min_char_or_byte2
].width
;
165 width
= font
->min_bounds
.width
;
168 width
+= CharWidth(w
, x
, (unsigned char) '^');
173 /* Function Name: PaintText
174 * Description: Actually paints the text into the windoe.
175 * Arguments: w - the text widget.
176 * gc - gc to paint text with.
177 * x, y - location to paint the text.
178 * buf, len - buffer and length of text to paint.
179 * Returns: the width of the text painted, or 0.
181 * NOTE: If this string attempts to paint past the end of the window
182 * then this function will return zero.
186 PaintText(w
, gc
, x
, y
, buf
, len
)
193 AsciiSinkObject sink
= (AsciiSinkObject
) w
;
194 TextWidget ctx
= (TextWidget
) XtParent(w
);
197 Dimension width
= XTextWidth(sink
->text_sink
.font
, (char *) buf
, len
);
198 max_x
= (Position
) ctx
->core
.width
;
200 if ( ((int) width
) <= -x
) /* Don't draw if we can't see it. */
203 XDrawImageString(XtDisplay(ctx
), XtWindow(ctx
), gc
,
204 (int) x
, (int) y
, (char *) buf
, len
);
205 if ( (((Position
) width
+ x
) > max_x
) && (ctx
->text
.margin
.right
!= 0) ) {
206 x
= ctx
->core
.width
- ctx
->text
.margin
.right
;
207 width
= ctx
->text
.margin
.right
;
208 XFillRectangle(XtDisplay((Widget
) ctx
), XtWindow( (Widget
) ctx
),
209 sink
->ascii_sink
.normgc
, (int) x
,
210 (int) y
- sink
->text_sink
.font
->ascent
,
211 (unsigned int) width
,
212 (unsigned int) (sink
->text_sink
.font
->ascent
+
213 sink
->text_sink
.font
->descent
));
219 /* Sink Object Functions */
222 * This function does not know about drawing more than one line of text.
226 DisplayText(w
, x
, y
, pos1
, pos2
, highlight
)
230 XawTextPosition pos1
, pos2
;
232 AsciiSinkObject sink
= (AsciiSinkObject
) w
;
233 Widget source
= XawTextGetSource(XtParent(w
));
234 unsigned char buf
[BUFSIZ
];
238 GC gc
= highlight
? sink
->ascii_sink
.invgc
: sink
->ascii_sink
.normgc
;
239 GC invgc
= highlight
? sink
->ascii_sink
.normgc
: sink
->ascii_sink
.invgc
;
241 if (!sink
->ascii_sink
.echo
) return;
243 y
+= sink
->text_sink
.font
->ascent
;
244 for ( j
= 0 ; pos1
< pos2
; ) {
245 pos1
= XawTextSourceRead(source
, pos1
, &blk
, pos2
- pos1
);
246 for (k
= 0; k
< blk
.length
; k
++) {
247 if (j
>= BUFSIZ
) { /* buffer full, dump the text. */
248 x
+= PaintText(w
, gc
, x
, y
, buf
, j
);
252 if (buf
[j
] == LF
) /* line feeds ('\n') are not printed. */
255 else if (buf
[j
] == '\t') {
259 if ((j
!= 0) && ((temp
= PaintText(w
, gc
, x
, y
, buf
, j
)) == 0))
263 width
= CharWidth(w
, x
, (unsigned char) '\t');
264 XFillRectangle(XtDisplayOfObject(w
), XtWindowOfObject(w
),
266 (int) y
- sink
->text_sink
.font
->ascent
,
267 (unsigned int) width
,
268 (unsigned int) (sink
->text_sink
.font
->ascent
+
269 sink
->text_sink
.font
->descent
));
273 else if ( buf
[j
] < (unsigned char) ' ' ) {
274 if (sink
->ascii_sink
.display_nonprinting
) {
275 buf
[j
+ 1] = buf
[j
] + '@';
286 (void) PaintText(w
, gc
, x
, y
, buf
, j
);
289 #define insertCursor_width 6
290 #define insertCursor_height 3
291 static char insertCursor_bits
[] = {0x0c, 0x1e, 0x33};
294 CreateInsertCursor(s
)
297 return (XCreateBitmapFromData (DisplayOfScreen(s
), RootWindowOfScreen(s
),
298 insertCursor_bits
, insertCursor_width
, insertCursor_height
));
301 /* Function Name: GetCursorBounds
302 * Description: Returns the size and location of the cursor.
303 * Arguments: w - the text object.
304 * RETURNED rect - an X rectangle to return the cursor bounds in.
309 GetCursorBounds(w
, rect
)
313 AsciiSinkObject sink
= (AsciiSinkObject
) w
;
315 rect
->width
= (unsigned short) insertCursor_width
;
316 rect
->height
= (unsigned short) insertCursor_height
;
317 rect
->x
= sink
->ascii_sink
.cursor_x
- (short) (rect
->width
/ 2);
318 rect
->y
= sink
->ascii_sink
.cursor_y
- (short) rect
->height
;
322 * The following procedure manages the "insert" cursor.
326 InsertCursor (w
, x
, y
, state
)
329 XawTextInsertState state
;
331 AsciiSinkObject sink
= (AsciiSinkObject
) w
;
332 Widget text_widget
= XtParent(w
);
335 sink
->ascii_sink
.cursor_x
= x
;
336 sink
->ascii_sink
.cursor_y
= y
;
338 GetCursorBounds(w
, &rect
);
339 if (state
!= sink
->ascii_sink
.laststate
&& XtIsRealized(text_widget
))
340 XCopyPlane(XtDisplay(text_widget
),
341 sink
->ascii_sink
.insertCursorOn
,
342 XtWindow(text_widget
), sink
->ascii_sink
.xorgc
,
343 0, 0, (unsigned int) rect
.width
, (unsigned int) rect
.height
,
344 (int) rect
.x
, (int) rect
.y
, 1);
345 sink
->ascii_sink
.laststate
= state
;
349 * Given two positions, find the distance between them.
353 FindDistance (w
, fromPos
, fromx
, toPos
, resWidth
, resPos
, resHeight
)
355 XawTextPosition fromPos
; /* First position. */
356 int fromx
; /* Horizontal location of first position. */
357 XawTextPosition toPos
; /* Second position. */
358 int *resWidth
; /* Distance between fromPos and resPos. */
359 XawTextPosition
*resPos
; /* Actual second position used. */
360 int *resHeight
; /* Height required. */
362 AsciiSinkObject sink
= (AsciiSinkObject
) w
;
363 Widget source
= XawTextGetSource(XtParent(w
));
365 register XawTextPosition index
, lastPos
;
366 register unsigned char c
;
369 /* we may not need this */
370 lastPos
= GETLASTPOS
;
371 XawTextSourceRead(source
, fromPos
, &blk
, toPos
- fromPos
);
373 for (index
= fromPos
; index
!= toPos
&& index
< lastPos
; index
++) {
374 if (index
- blk
.firstPos
>= blk
.length
)
375 XawTextSourceRead(source
, index
, &blk
, toPos
- fromPos
);
376 c
= blk
.ptr
[index
- blk
.firstPos
];
377 *resWidth
+= CharWidth(w
, fromx
+ *resWidth
, c
);
384 *resHeight
= sink
->text_sink
.font
->ascent
+sink
->text_sink
.font
->descent
;
389 FindPosition(w
, fromPos
, fromx
, width
, stopAtWordBreak
,
390 resPos
, resWidth
, resHeight
)
392 XawTextPosition fromPos
; /* Starting position. */
393 int fromx
; /* Horizontal location of starting position.*/
394 int width
; /* Desired width. */
395 int stopAtWordBreak
; /* Whether the resulting position should be at
397 XawTextPosition
*resPos
; /* Resulting position. */
398 int *resWidth
; /* Actual width used. */
399 int *resHeight
; /* Height required. */
401 AsciiSinkObject sink
= (AsciiSinkObject
) w
;
402 Widget source
= XawTextGetSource(XtParent(w
));
404 XawTextPosition lastPos
, index
, whiteSpacePosition
;
405 int lastWidth
, whiteSpaceWidth
;
406 Boolean whiteSpaceSeen
;
410 lastPos
= GETLASTPOS
;
412 XawTextSourceRead(source
, fromPos
, &blk
, BUFSIZ
);
414 whiteSpaceSeen
= FALSE
;
416 for (index
= fromPos
; *resWidth
<= width
&& index
< lastPos
; index
++) {
417 lastWidth
= *resWidth
;
418 if (index
- blk
.firstPos
>= blk
.length
)
419 XawTextSourceRead(source
, index
, &blk
, BUFSIZ
);
420 c
= blk
.ptr
[index
- blk
.firstPos
];
421 *resWidth
+= CharWidth(w
, fromx
+ *resWidth
, c
);
423 if ((c
== SP
|| c
== TAB
) && *resWidth
<= width
) {
424 whiteSpaceSeen
= TRUE
;
425 whiteSpacePosition
= index
;
426 whiteSpaceWidth
= *resWidth
;
433 if (*resWidth
> width
&& index
> fromPos
) {
434 *resWidth
= lastWidth
;
436 if (stopAtWordBreak
&& whiteSpaceSeen
) {
437 index
= whiteSpacePosition
+ 1;
438 *resWidth
= whiteSpaceWidth
;
441 if (index
== lastPos
&& c
!= LF
) index
= lastPos
+ 1;
443 *resHeight
= sink
->text_sink
.font
->ascent
+sink
->text_sink
.font
->descent
;
447 Resolve (w
, pos
, fromx
, width
, leftPos
, rightPos
)
451 XawTextPosition
*leftPos
, *rightPos
;
453 int resWidth
, resHeight
;
454 Widget source
= XawTextGetSource(XtParent(w
));
456 FindPosition(w
, pos
, fromx
, width
, FALSE
, leftPos
, &resWidth
, &resHeight
);
457 if (*leftPos
> GETLASTPOS
)
458 *leftPos
= GETLASTPOS
;
459 *rightPos
= *leftPos
;
464 AsciiSinkObject sink
;
466 XtGCMask valuemask
= (GCFont
|
467 GCGraphicsExposures
| GCForeground
| GCBackground
);
470 values
.font
= sink
->text_sink
.font
->fid
;
471 values
.graphics_exposures
= (Bool
) FALSE
;
473 values
.foreground
= sink
->text_sink
.foreground
;
474 values
.background
= sink
->text_sink
.background
;
475 sink
->ascii_sink
.normgc
= XtGetGC((Widget
)sink
, valuemask
, &values
);
477 values
.foreground
= sink
->text_sink
.background
;
478 values
.background
= sink
->text_sink
.foreground
;
479 sink
->ascii_sink
.invgc
= XtGetGC((Widget
)sink
, valuemask
, &values
);
481 values
.function
= GXxor
;
482 values
.background
= (unsigned long) 0L; /* (pix ^ 0) = pix */
483 values
.foreground
= (sink
->text_sink
.background
^
484 sink
->text_sink
.foreground
);
485 valuemask
= GCFunction
| GCForeground
| GCBackground
;
487 sink
->ascii_sink
.xorgc
= XtGetGC((Widget
)sink
, valuemask
, &values
);
491 /***** Public routines *****/
493 /* Function Name: Initialize
494 * Description: Initializes the TextSink Object.
495 * Arguments: request, new - the requested and new values for the object
503 Initialize(request
, new)
506 AsciiSinkObject sink
= (AsciiSinkObject
) new;
510 sink
->ascii_sink
.insertCursorOn
= CreateInsertCursor(XtScreenOfObject(new));
511 sink
->ascii_sink
.laststate
= XawisOff
;
512 sink
->ascii_sink
.cursor_x
= sink
->ascii_sink
.cursor_y
= 0;
515 /* Function Name: Destroy
516 * Description: This function cleans up when the object is
518 * Arguments: w - the AsciiSink Object.
526 AsciiSinkObject sink
= (AsciiSinkObject
) w
;
528 XtReleaseGC(w
, sink
->ascii_sink
.normgc
);
529 XtReleaseGC(w
, sink
->ascii_sink
.invgc
);
530 XtReleaseGC(w
, sink
->ascii_sink
.xorgc
);
531 XFreePixmap(XtDisplayOfObject(w
), sink
->ascii_sink
.insertCursorOn
);
534 /* Function Name: SetValues
535 * Description: Sets the values for the AsciiSink
536 * Arguments: current - current state of the object.
537 * request - what was requested.
538 * new - what the object will become.
539 * Returns: True if redisplay is needed.
544 SetValues(current
, request
, new)
545 Widget current
, request
, new;
547 AsciiSinkObject w
= (AsciiSinkObject
) new;
548 AsciiSinkObject old_w
= (AsciiSinkObject
) current
;
550 if (w
->text_sink
.font
!= old_w
->text_sink
.font
) {
551 XtReleaseGC((Widget
)w
, w
->ascii_sink
.normgc
);
552 XtReleaseGC((Widget
)w
, w
->ascii_sink
.invgc
);
554 ((TextWidget
)XtParent(new))->text
.redisplay_needed
= True
;
556 if ( (w
->ascii_sink
.echo
!= old_w
->ascii_sink
.echo
) ||
557 (w
->ascii_sink
.display_nonprinting
!=
558 old_w
->ascii_sink
.display_nonprinting
) )
559 ((TextWidget
)XtParent(new))->text
.redisplay_needed
= True
;