One more check on valid display which is known to be in the startup
[xcircuit.git] / Xw / Display.c
bloba77c87798562abefe3ca9098bbdbcabe278af37d
1 /*************************************<+>*************************************
2 *****************************************************************************
3 **
4 ** File: Display.c
5 **
6 ** Project: X Widgets
7 **
8 ** Description: Code for TextEdit widget ascii sink
9 **
10 *****************************************************************************
11 **
12 ** Copyright (c) 1988 by Hewlett-Packard Company
13 ** Copyright (c) 1987, 1988 by Digital Equipment Corporation, Maynard,
14 ** Massachusetts, and the Massachusetts Institute of Technology,
15 ** Cambridge, Massachusetts
16 **
17 ** Permission to use, copy, modify, and distribute this software
18 ** and its documentation for any purpose and without fee is hereby
19 ** granted, provided that the above copyright notice appear in all
20 ** copies and that both that copyright notice and this permission
21 ** notice appear in supporting documentation, and that the names of
22 ** Hewlett-Packard, Digital or M.I.T. not be used in advertising or
23 ** publicity pertaining to distribution of the software without
24 ** written prior permission.
25 **
26 ** DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
27 ** ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
28 ** DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
29 ** ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
30 ** WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
31 ** ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
32 ** SOFTWARE.
33 **
34 *****************************************************************************
35 *************************************<+>*************************************/
38 #include <X11/Xlib.h>
39 #include <X11/Xutil.h>
40 #include <X11/Xatom.h>
41 #include <X11/Intrinsic.h>
42 #include <X11/IntrinsicP.h>
43 #include <X11/StringDefs.h>
44 #include <Xw/Xw.h>
45 #include <Xw/XwP.h>
47 #include <Xw/TextEditP.h>
49 #ifdef DEBUG
50 #include <stdio.h>
51 #endif
54 #define GETLASTPOS (*(source->scan))(source, 0, XwstLast, XwsdRight, 1, TRUE)
55 /* Private Ascii TextSink Definitions */
57 static unsigned bufferSize = 200;
59 typedef struct _AsciiSinkData {
60 Pixel foreground;
61 GC normgc, invgc, xorgc;
62 XFontStruct *font;
63 int tabwidth;
64 Pixmap insertCursorOn;
65 XwInsertState laststate;
66 } AsciiSinkData, *AsciiSinkPtr;
68 static unsigned char *buf;
70 /* XXX foreground default should be XtDefaultFGPixel. How do i do that?? */
72 static XtResource SinkResources[] = {
73 {XtNfont, XtCFont, XtRFontStruct, sizeof (XFontStruct *),
74 XtOffset(AsciiSinkPtr, font), XtRString, "Fixed"},
75 {XtNforeground, XtCForeground, XtRPixel, sizeof (int),
76 XtOffset(AsciiSinkPtr, foreground), XtRString, "XtDefaultForeground"},
79 /* Utilities */
81 /*--------------------------------------------------------------------------+*/
82 static int CharWidth (data, x, margin, c)
83 /*--------------------------------------------------------------------------+*/
84 AsciiSinkData *data;
85 int x;
86 int margin ;
87 unsigned char c;
89 int width, nonPrinting;
90 XFontStruct *font = data->font;
92 if (c == '\t')
93 /* This is totally bogus!! need to know tab settings etc.. */
94 return data->tabwidth - ((x-margin) % data->tabwidth);
95 if (c == LF)
96 c = SP;
97 nonPrinting = (c < SP);
98 if (nonPrinting) c += '@';
100 if (font->per_char &&
101 (c >= font->min_char_or_byte2 && c <= font->max_char_or_byte2))
102 width = font->per_char[c - font->min_char_or_byte2].width;
103 else
104 width = font->min_bounds.width;
106 if (nonPrinting)
107 width += CharWidth(data, x, margin, '^');
109 return width;
112 /* Sink Object Functions */
114 #define LBEARING(x) \
115 ((font->per_char != NULL && \
116 ((x) >= font->min_char_or_byte2 && (x) <= font->max_char_or_byte2)) \
117 ? font->per_char[(x) - font->min_char_or_byte2].lbearing \
118 : font->min_bounds.lbearing)
120 /*--------------------------------------------------------------------------+*/
121 static int AsciiDisplayText (w, x, y, pos1, pos2, highlight)
122 /*--------------------------------------------------------------------------+*/
123 Widget w;
124 Position x, y;
125 int highlight;
126 XwTextPosition pos1, pos2;
128 XwTextSink *sink = ((XwTextEditWidget)w)->text.sink;
129 XwTextSource *source = ((XwTextEditWidget)w)->text.source;
130 AsciiSinkData *data = (AsciiSinkData *) sink->data ;
131 int margin = ((XwTextEditWidget)w)->text.leftmargin ;
133 XFontStruct *font = data->font;
134 int j, k;
135 Dimension width;
136 XwTextBlock blk;
137 GC gc = highlight ? data->invgc : data->normgc;
138 GC invgc = highlight ? data->normgc : data->invgc;
140 y += font->ascent;
141 j = 0;
142 while (pos1 < pos2) {
143 pos1 = (*(source->read))(source, pos1, &blk, pos2 - pos1);
144 for (k = 0; k < blk.length; k++) {
145 if (j >= bufferSize - 5) {
146 bufferSize *= 2;
147 buf = (unsigned char *) XtRealloc(buf, bufferSize);
149 buf[j] = blk.ptr[k];
150 if (buf[j] == LF)
151 buf[j] = ' ';
152 else if (buf[j] == '\t') {
153 XDrawImageString(XtDisplay(w), XtWindow(w),
154 gc, x - LBEARING(*buf), y, buf, j);
155 buf[j] = 0;
156 x += XTextWidth(data->font, buf, j);
157 width = CharWidth(data, x, margin, '\t');
158 XFillRectangle(XtDisplay(w), XtWindow(w), invgc, x,
159 y - font->ascent, width,
160 (Dimension) (data->font->ascent +
161 data->font->descent));
162 x += width;
163 j = -1;
165 else
166 if (buf[j] < ' ') {
167 buf[j + 1] = buf[j] + '@';
168 buf[j] = '^';
169 j++;
171 j++;
174 XDrawImageString(XtDisplay(w), XtWindow(w), gc, x - LBEARING(*buf), y,
175 buf, j);
179 # define insertCursor_width 6
180 # define insertCursor_height 3
181 static char insertCursor_bits[] = {0x0c, 0x1e, 0x33};
183 /*--------------------------------------------------------------------------+*/
184 static Pixmap CreateInsertCursor(s)
185 /*--------------------------------------------------------------------------+*/
186 Screen *s;
189 return (XCreateBitmapFromData (DisplayOfScreen(s), RootWindowOfScreen(s),
190 insertCursor_bits, insertCursor_width, insertCursor_height));
194 * The following procedure manages the "insert" cursor.
197 /*--------------------------------------------------------------------------+*/
198 static AsciiInsertCursor (w, x, y, state)
199 /*--------------------------------------------------------------------------+*/
200 Widget w;
201 Position x, y;
202 XwInsertState state;
204 XwTextSink *sink = ((XwTextEditWidget)w)->text.sink;
205 AsciiSinkData *data = (AsciiSinkData *) sink->data;
208 XCopyArea(sink->dpy,
209 (state == XwisOn) ? data->insertCursorOn : data->insertCursorOff, w,
210 data->normgc, 0, 0, insertCursor_width, insertCursor_height,
211 x - (insertCursor_width >> 1), y - (insertCursor_height));
213 if (state != data->laststate && XtIsRealized(w))
214 XCopyPlane(XtDisplay(w),
215 data->insertCursorOn, XtWindow(w),
216 data->xorgc, 0, 0, insertCursor_width, insertCursor_height,
217 x - (insertCursor_width >> 1), y - (insertCursor_height), 1);
219 /* This change goes with the cursor hack for the broken server */
220 XCopyArea (XtDisplay(w), data->insertCursorOn, XtWindow (w),
221 data->xorgc, 0, 0, insertCursor_width, insertCursor_height,
222 x - (insertCursor_width >> 1), y - (insertCursor_height));
224 data->laststate = state;
228 * Clear the passed region to the background color.
231 /*--------------------------------------------------------------------------+*/
232 static AsciiClearToBackground (w, x, y, width, height)
233 /*--------------------------------------------------------------------------+*/
234 Widget w;
235 Position x, y;
236 Dimension width, height;
238 XwTextSink *sink = ((XwTextEditWidget)w)->text.sink;
239 AsciiSinkData *data = (AsciiSinkData *) sink->data;
240 XFillRectangle(XtDisplay(w), XtWindow(w), data->invgc, x, y, width, height);
244 * Given two positions, find the distance between them.
247 /*--------------------------------------------------------------------------+*/
248 static AsciiFindDistance (w, fromPos, fromx, toPos,
249 resWidth, resPos, resHeight)
250 /*--------------------------------------------------------------------------+*/
251 Widget w;
252 XwTextPosition fromPos; /* First position. */
253 int fromx; /* Horizontal location of first position. */
254 XwTextPosition toPos; /* Second position. */
255 int *resWidth; /* Distance between fromPos and resPos. */
256 int *resPos; /* Actual second position used. */
257 int *resHeight; /* Height required. */
259 XwTextSink *sink = ((XwTextEditWidget)w)->text.sink;
260 XwTextSource *source = ((XwTextEditWidget)w)->text.source;
261 int margin = ((XwTextEditWidget)w)->text.leftmargin ;
263 AsciiSinkData *data;
264 register XwTextPosition index, lastPos;
265 register unsigned char c;
266 XwTextBlock blk;
268 data = (AsciiSinkData *) sink->data;
269 /* we may not need this */
270 lastPos = GETLASTPOS;
271 (*(source->read))(source, fromPos, &blk, toPos - fromPos);
272 *resWidth = 0;
273 for (index = fromPos; index != toPos && index < lastPos; index++) {
274 if (index - blk.firstPos >= blk.length)
275 (*(source->read))(source, index, &blk, toPos - fromPos);
276 c = blk.ptr[index - blk.firstPos];
277 if (c == LF) {
278 *resWidth += CharWidth(data, fromx + *resWidth, margin, SP);
279 index++;
280 break;
282 *resWidth += CharWidth(data, fromx + *resWidth, margin, c);
284 *resPos = index;
285 *resHeight = data->font->ascent + data->font->descent;
289 /*--------------------------------------------------------------------------+*/
290 static TextFit AsciiTextFit (w, fromPos, fromx, width, wrap, wrapWhiteSpace,
291 fitPos, drawPos, nextPos, resWidth, resHeight)
292 /*--------------------------------------------------------------------------+*/
293 Widget w;
294 XwTextPosition fromPos; /* Starting position. */
295 int fromx; /* Horizontal location of starting position. */
296 int width; /* Desired width. */
297 int wrap; /* Whether line should wrap at all */
298 int wrapWhiteSpace; /* Whether line should wrap at white space */
300 XwTextPosition *fitPos ; /* pos of last char which fits in specified
301 width */
302 XwTextPosition *drawPos ; /* pos of last char to draw in specified
303 width based on wrap model */
304 XwTextPosition *nextPos ; /* pos of next char to draw outside specified
305 width based on wrap model */
306 int *resWidth; /* Actual width used. */
307 int *resHeight; /* Height required. */
309 XwTextSink *sink = ((XwTextEditWidget)w)->text.sink;
310 XwTextSource *source = ((XwTextEditWidget)w)->text.source;
311 int margin = ((XwTextEditWidget)w)->text.leftmargin ;
312 AsciiSinkData *data;
313 XwTextPosition lastPos, pos, whiteSpacePosition;
314 XwTextPosition fitL, drawL ;
315 /* local equivalents of fitPos, drawPos, nextPos */
316 int lastWidth, whiteSpaceWidth, whiteSpaceSeen ;
317 int useAll ;
318 TextFit fit ;
319 unsigned char c;
320 XwTextBlock blk;
322 data = (AsciiSinkData *) sink->data;
323 lastPos = GETLASTPOS;
325 *resWidth = 0;
326 *fitPos = fromPos ;
327 *drawPos = -1 ;
328 c = 0;
329 useAll = whiteSpaceSeen = FALSE ;
331 pos = fromPos ;
332 fitL = pos - 1 ;
333 (*(source->read))(source, fromPos, &blk, bufferSize);
335 while (*resWidth <= width)
336 { lastWidth = *resWidth;
337 fitL = pos - 1 ;
338 if (pos >= lastPos)
339 { pos = lastPos ;
340 fit = tfEndText ;
341 useAll = TRUE ;
342 break ;
344 if (pos - blk.firstPos >= blk.length)
345 (*(source->read))(source, pos, &blk, bufferSize);
346 c = blk.ptr[pos - blk.firstPos];
348 if (isNewline(c))
349 { fit = tfNewline ;
350 useAll = TRUE ;
351 break ;
354 if (wrapWhiteSpace && isWhiteSpace(c))
355 { whiteSpaceSeen = TRUE ;
356 drawL = pos - 1 ;
357 whiteSpaceWidth = *resWidth;
360 *resWidth += CharWidth(data, fromx + *resWidth, margin, c);
361 pos++ ;
362 } /* end while */
364 *fitPos = fitL ;
365 *drawPos = fitL ;
366 if (useAll)
368 *nextPos = pos + 1 ;
369 *resWidth = lastWidth ;
371 else if (wrapWhiteSpace && whiteSpaceSeen)
372 { *drawPos = drawL ;
373 *nextPos = drawL + 2 ;
374 *resWidth = whiteSpaceWidth ;
375 fit = tfWrapWhiteSpace ;
377 else if (wrap)
379 *nextPos = fitL + 1 ;
380 *resWidth = lastWidth ;
381 fit = tfWrapAny ;
383 else
385 /* scan source for newline or end */
386 *nextPos =
387 (*(source->scan)) (source, pos, XwstEOL, XwsdRight, 1, TRUE) + 1 ;
388 *resWidth = lastWidth ;
389 fit = tfNoFit ;
391 *resHeight = data->font->ascent + data->font->descent;
392 return (fit) ;
395 /*--------------------------------------------------------------------------+*/
396 static AsciiFindPosition(w, fromPos, fromx, width, stopAtWordBreak,
397 resPos, resWidth, resHeight)
398 /*--------------------------------------------------------------------------+*/
399 Widget w;
400 XwTextPosition fromPos; /* Starting position. */
401 int fromx; /* Horizontal location of starting position. */
402 int width; /* Desired width. */
403 int stopAtWordBreak; /* Whether the resulting position should be at
404 a word break. */
405 XwTextPosition *resPos; /* Resulting position. */
406 int *resWidth; /* Actual width used. */
407 int *resHeight; /* Height required. */
409 XwTextSink *sink = ((XwTextEditWidget)w)->text.sink;
410 XwTextSource *source = ((XwTextEditWidget)w)->text.source;
411 int margin = ((XwTextEditWidget)w)->text.leftmargin ;
412 AsciiSinkData *data;
413 XwTextPosition lastPos, index, whiteSpacePosition;
414 int lastWidth, whiteSpaceWidth;
415 Boolean whiteSpaceSeen;
416 unsigned char c;
417 XwTextBlock blk;
418 data = (AsciiSinkData *) sink->data;
419 lastPos = GETLASTPOS;
421 (*(source->read))(source, fromPos, &blk, bufferSize);
422 *resWidth = 0;
423 whiteSpaceSeen = FALSE;
424 c = 0;
425 for (index = fromPos; *resWidth <= width && index < lastPos; index++) {
426 lastWidth = *resWidth;
427 if (index - blk.firstPos >= blk.length)
428 (*(source->read))(source, index, &blk, bufferSize);
429 c = blk.ptr[index - blk.firstPos];
430 if (c == LF) {
431 *resWidth += CharWidth(data, fromx + *resWidth, margin, SP);
432 index++;
433 break;
435 *resWidth += CharWidth(data, fromx + *resWidth, margin, c);
436 if ((c == SP || c == TAB) && *resWidth <= width) {
437 whiteSpaceSeen = TRUE;
438 whiteSpacePosition = index;
439 whiteSpaceWidth = *resWidth;
442 if (*resWidth > width && index > fromPos) {
443 *resWidth = lastWidth;
444 index--;
445 if (stopAtWordBreak && whiteSpaceSeen) {
446 index = whiteSpacePosition + 1;
447 *resWidth = whiteSpaceWidth;
450 if (index == lastPos && c != LF) index = lastPos + 1;
451 *resPos = index;
452 *resHeight = data->font->ascent + data->font->descent;
456 /*--------------------------------------------------------------------------+*/
457 static int AsciiResolveToPosition (w, pos, fromx, width,
458 leftPos, rightPos)
459 /*--------------------------------------------------------------------------+*/
460 Widget w;
461 XwTextPosition pos;
462 int fromx,width;
463 XwTextPosition *leftPos, *rightPos;
465 int resWidth, resHeight;
466 XwTextSink *sink = ((XwTextEditWidget)w)->text.sink;
467 XwTextSource *source = ((XwTextEditWidget)w)->text.source;
469 AsciiFindPosition(w, pos, fromx, width, FALSE,
470 leftPos, &resWidth, &resHeight);
471 if (*leftPos > GETLASTPOS)
472 *leftPos = GETLASTPOS;
473 *rightPos = *leftPos;
477 /*--------------------------------------------------------------------------+*/
478 static int AsciiMaxLinesForHeight (w)
479 /*--------------------------------------------------------------------------+*/
480 Widget w;
482 AsciiSinkData *data;
483 XwTextSink *sink = ((XwTextEditWidget)w)->text.sink;
485 data = (AsciiSinkData *) sink->data;
486 return (int) ((w->core.height
487 - ((XwTextEditWidget) w)->text.topmargin
488 - ((XwTextEditWidget) w)->text.bottommargin
490 / (data->font->ascent + data->font->descent)
495 /*--------------------------------------------------------------------------+*/
496 static int AsciiMaxHeightForLines (w, lines)
497 /*--------------------------------------------------------------------------+*/
498 Widget w;
499 int lines;
501 AsciiSinkData *data;
502 XwTextSink *sink = ((XwTextEditWidget)w)->text.sink;
504 data = (AsciiSinkData *) sink->data;
505 return(lines * (data->font->ascent + data->font->descent));
509 /***** Public routines *****/
511 static Boolean initialized = FALSE;
512 static XContext asciiSinkContext;
514 /*--------------------------------------------------------------------------+*/
515 void AsciiSinkInitialize()
516 /*--------------------------------------------------------------------------+*/
518 if (initialized)
519 return;
520 initialized = TRUE;
522 asciiSinkContext = XUniqueContext();
524 buf = (unsigned char *) XtMalloc(bufferSize);
527 /*--------------------------------------------------------------------------+*/
528 static Boolean XwAsciiSinkCheckData(self)
529 /*--------------------------------------------------------------------------+*/
530 XwTextSink *self ;
532 XwTextEditWidget tew = self->parent ;
534 /* make sure margins are big enough to keep traversal highlight
535 from obscuring text or cursor.
537 { int minBorder ;
538 minBorder = (tew->primitive.traversal_type == XwHIGHLIGHT_OFF)
539 ? RequiredCursorMargin
540 : RequiredCursorMargin + tew->primitive.highlight_thickness ;
542 if (tew->text.topmargin < minBorder)
543 tew->text.topmargin = minBorder ;
544 if (tew->text.bottommargin < minBorder)
545 tew->text.bottommargin = minBorder ;
546 if (tew->text.rightmargin < minBorder)
547 tew->text.rightmargin = minBorder ;
548 if (tew->text.leftmargin < minBorder)
549 tew->text.leftmargin = minBorder ;
552 if ((*(self->maxLines))(tew) < 1)
553 XtWarning("TextEdit window too small to display a single line of text.");
557 /*--------------------------------------------------------------------------+*/
558 void XwAsciiSinkDestroy (sink)
559 /*--------------------------------------------------------------------------+*/
560 XwTextSink *sink;
562 AsciiSinkData *data;
563 data = (AsciiSinkData *) sink->data;
564 XtFree((char *) data);
565 XtFree((char *) sink);
568 /*--------------------------------------------------------------------------+*/
569 XwTextSink *XwAsciiSinkCreate (w, args, num_args)
570 /*--------------------------------------------------------------------------+*/
571 Widget w;
572 ArgList args;
573 Cardinal num_args;
575 XwTextSink *sink;
576 AsciiSinkData *data;
577 unsigned long valuemask = (GCFont | GCGraphicsExposures |
578 GCForeground | GCBackground | GCFunction);
579 XGCValues values;
580 unsigned long wid;
581 XFontStruct *font;
583 if (!initialized)
584 AsciiSinkInitialize();
586 sink = XtNew(XwTextSink);
587 sink->parent = (XwTextEditWidget) w ;
588 sink->parent->text.sink = sink ; /* disgusting */
589 sink->display = AsciiDisplayText;
590 sink->insertCursor = AsciiInsertCursor;
591 sink->clearToBackground = AsciiClearToBackground;
592 sink->findPosition = AsciiFindPosition;
593 sink->textFitFn = AsciiTextFit;
594 sink->findDistance = AsciiFindDistance;
595 sink->resolve = AsciiResolveToPosition;
596 sink->maxLines = AsciiMaxLinesForHeight;
597 sink->maxHeight = AsciiMaxHeightForLines;
598 sink->resources = SinkResources;
599 sink->resource_num = XtNumber(SinkResources);
600 sink->check_data = XwAsciiSinkCheckData;
601 sink->destroy = XwAsciiSinkDestroy;
602 sink->LineLastWidth = 0 ;
603 sink->LineLastPosition = 0 ;
604 data = XtNew(AsciiSinkData);
605 sink->data = (int *)data;
607 XtGetSubresources (w, (caddr_t)data, "display", "Display",
608 SinkResources, XtNumber(SinkResources),
609 args, num_args);
611 /* XXX do i have to XLoadQueryFont or does the resource guy do it for me */
613 font = data->font;
614 values.function = GXcopy;
615 values.font = font->fid;
616 values.graphics_exposures = (Bool) FALSE;
617 values.foreground = data->foreground;
618 values.background = w->core.background_pixel;
619 data->normgc = XtGetGC(w, valuemask, &values);
620 values.foreground = w->core.background_pixel;
621 values.background = data->foreground;
622 data->invgc = XtGetGC(w, valuemask, &values);
623 values.function = GXxor;
624 values.foreground = data->foreground ^ w->core.background_pixel;
625 values.background = 0;
626 data->xorgc = XtGetGC(w, valuemask, &values);
628 wid = -1;
629 if ((!XGetFontProperty(font, XA_QUAD_WIDTH, &wid)) || wid <= 0) {
630 if (font->per_char && font->min_char_or_byte2 <= '0' &&
631 font->max_char_or_byte2 >= '0')
632 wid = font->per_char['0' - font->min_char_or_byte2].width;
633 else
634 wid = font->max_bounds.width;
636 if (wid <= 0) wid = 1;
637 data->tabwidth = 8 * wid;
638 data->font = font;
640 /* data->insertCursorOn = CreateInsertCursor(XtScreen(w)); */
642 {/* Correction from AsciiSink.c on R2 tape */
643 Screen *screen = XtScreen(w);
644 Display *dpy = XtDisplay(w);
645 Window root = RootWindowOfScreen(screen);
646 Pixmap bitmap = XCreateBitmapFromData(dpy, root, insertCursor_bits,
647 insertCursor_width,
648 insertCursor_height);
649 Pixmap pixmap = XCreatePixmap(dpy, root,insertCursor_width,
650 insertCursor_height,
651 DefaultDepthOfScreen(screen));
652 XGCValues gcv;
653 GC gc;
655 gcv.function = GXcopy;
656 gcv.foreground = data->foreground ^ w->core.background_pixel;
657 gcv.background = 0;
658 gcv.graphics_exposures = False;
659 gc = XtGetGC(w, (GCFunction | GCForeground | GCBackground |
660 GCGraphicsExposures), &gcv);
661 XCopyPlane(dpy, bitmap, pixmap, gc, 0, 0, insertCursor_width,
662 insertCursor_height, 0, 0, 1);
663 XtDestroyGC(gc);
664 data->insertCursorOn = pixmap;
667 data->laststate = XwisOff;
668 (*(sink->check_data))(sink);
670 return sink;