/** * * $Header: /cvsroot/lesstif/lesstif/lib/Xm-2.1/TextOut.c,v 1.9 2006/04/19 18:42:22 dannybackx Exp $ * * Copyright (C) 1995 Free Software Foundation, Inc. * Copyright © 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 LessTif Development Team * * This file is part of the GNU LessTif Library. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * **/ static const char rcsid[] = "$Header: /cvsroot/lesstif/lesstif/lib/Xm-2.1/TextOut.c,v 1.9 2006/04/19 18:42:22 dannybackx Exp $"; /* Do NOT use this (USE_XT_GC) : * it requires setting all the dynamic GC fields before every use of * the GC. As we have too many GC fields that can change, this is * really a bad idea. * Setting this macro leads to use of XtAllocateGC and XtGetGC, * and similar for the free operations. * This path has been explored more than once, by different * developers. Please keep the comments here so it gets * remembered. */ #undef USE_XT_GC /* * End of the USE_XT_GC blurb. */ #include #include #include /* for INT_MAX */ #include #include #include #include #include #include #include #include #include #include #include #undef VERBOSE static void Draw(XmTextWidget w, LineNum num, XmTextPosition start, XmTextPosition end, XmHighlightMode highlight); #define Offset(field) XtOffsetOf(XmTextInnerRec, inner.out.field) #define USE_AVERAGE_WIDTH 1 #undef Out_FontTextWidth #define Out_FontTextWidth(o,s,l) (int)_XmOut_FontTextWidth(o, s, l) #define Out_FontMaxWidth(o) (int)_XmOut_FontMaxWidth(o) static void _XmTextOutSetRenderTable(Widget w, int o, XrmValue *v); /* Resources for the TextInner class */ static XtResource output_resources[] = { { XmNblinkRate, XmCBlinkRate, XmRInt, sizeof(int), Offset(blinkrate), XmRImmediate, (XtPointer)500 }, { XmNcolumns, XmCColumns, XmRShort, sizeof(short), Offset(columns), XmRImmediate, (XtPointer)20 }, { XmNcursorPositionVisible, XmCCursorPositionVisible, XmRBoolean, sizeof(Boolean), Offset(cursor_position_visible), XmRImmediate, (XtPointer)True }, /* * FontList and RenderTable resources : * Note that the right order is important here ! */ { "keep.off", "Keep.off", XmRBoolean, sizeof(Boolean), Offset(check_set_render_table), XmRImmediate, (XtPointer)NULL }, { XmNfontList, XmCFontList, XmRFontList, sizeof(XmFontList), Offset(fontlist), XmRCallProc, (XtPointer)_XmTextOutSetRenderTable }, { XmNrenderTable, XmCRenderTable, XmRRenderTable, sizeof(XmFontList), Offset(fontlist), XmRCallProc, (XtPointer)_XmTextOutSetRenderTable }, /* * End of the fontList and renderTable resources */ { XmNresizeHeight, XmCResizeHeight, XmRBoolean, sizeof(Boolean), Offset(resizeheight), XmRImmediate, (XtPointer)False }, { XmNresizeWidth, XmCResizeWidth, XmRBoolean, sizeof(Boolean), Offset(resizewidth), XmRImmediate, (XtPointer)False }, { XmNrows, XmCRows, XmRShort, sizeof(short), Offset(rows), XmRImmediate, (XtPointer)1 }, { XmNwordWrap, XmCWordWrap, XmRBoolean, sizeof(Boolean), Offset(wordwrap), XmRImmediate, (XtPointer)False }, /* ScrolledText resources */ { XmNscrollHorizontal, XmCScroll, XmRBoolean, sizeof(Boolean), Offset(scrollhorizontal), XmRImmediate, (XtPointer)True }, { XmNscrollLeftSide, XmCScrollSide, XmRBoolean, sizeof(Boolean), Offset(scrollleftside), XmRImmediate, (XtPointer)False }, { XmNscrollTopSide, XmCScrollSide, XmRBoolean, sizeof(Boolean), Offset(scrolltopside), XmRImmediate, (XtPointer)False }, { XmNscrollVertical, XmCScroll, XmRBoolean, sizeof(Boolean), Offset(scrollvertical), XmRImmediate, (XtPointer)True }, }; /* * Common initialization procedures ------------------------------------------- */ extern int _XmFontCalculateAverageCharacterWidth(Widget w, XFontStruct *fs) { unsigned long width; Atom atom; if (fs == NULL) { /* Especially important in Xft case */ return 0; } /* this is copied from a similar function in Screen.c */ if ((atom = XmInternAtom(XtDisplay(w), _XA_AVERAGE_WIDTH, True)) && XGetFontProperty(fs, atom, &width) && width) { width = (width + 5) / 10; /*CP: just to round it up slightly */ } else if ((! XGetFontProperty(fs, XA_QUAD_WIDTH, &width)) || width == 0) { /* * Use the width of '0' if that's available, otherwise the maximum width * like the manual page of XmText says. */ if (fs->per_char && fs->min_char_or_byte2 <= '0' && fs->max_char_or_byte2 >= '0') width = fs->per_char['0' - fs->min_char_or_byte2].width; else width = fs->max_bounds.width ; } return width; } /* FIX ME - this thing is clearly overly simplistic. */ /* I think it should : * - grab a fontset whenever it can (bypassing fonts) * - make sure you pick any fontset (preferably) or font (if all else * fails) from the list if nothing matches the tag we want */ /* * Note : never *ever* use XmFONTLIST_DEFAULT_TAG without checking * XmSTRING_DEFAULT_CHARSET as well. Pre-1.2 docs use the latter everywhere. */ static void FontInit(XmTextWidget w) { OutputData o = Text_OutputData(w); XmFontListEntry entry = NULL; XmFontList oldlist = Out_FontList(o); XFontStruct *fs; int i; DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "FontInit(fontlist %p)\n", oldlist)); DEBUGOUT(_LtDebugPrintRenderTable(__FILE__, (Widget)w, "FontInit(): ", oldlist)); /* This part is probably all wrong ... FIX ME */ for (i = 0; Out_FontList(o)->renditions[i]->tag != NULL; i++) { if (strcmp(XmFONTLIST_DEFAULT_TAG, Out_FontList(o)->renditions[i]->tag) == 0 || strcmp(XmSTRING_DEFAULT_CHARSET, Out_FontList(o)->renditions[i]->tag) == 0) { entry = Out_FontList(o)->renditions[i]; if (entry->font == NULL) { entry = NULL; continue; } break; } } if (!entry) { for (i = 0; Out_FontList(o)->renditions[i]->tag != NULL; i++) { if (Out_FontList(o)->renditions[i]->type == XmFONT_IS_FONTSET) { entry = Out_FontList(o)->renditions[i]; if (entry->font == NULL) { entry = NULL; continue; } break; } } } if (!entry) { for (i = 0; Out_FontList(o)->renditions[i]->tag != NULL; i++) { if (Out_FontList(o)->renditions[i]->type == XmFONT_IS_FONT) { entry = Out_FontList(o)->renditions[i]; if (entry->font == NULL) { entry = NULL; continue; } break; } } } /* (Hopefully) end of the all wrong part */ #if USE_XFT Out_FontType(o) = XmFONT_IS_FONT; o->xft_font = NULL; /* * We need a hack to get Xft fonts accepted. * The current (initial hack) is to use Xft for fonts if * the first item in the fontList is an Xft font. */ if (Out_FontList(o) && Out_FontList(o)->renditions[0] && Out_FontList(o)->renditions[0]->type == XmFONT_IS_XFT) { Out_FontType(o) = XmFONT_IS_XFT; entry = Out_FontList(o)->renditions[0]; o->xft_font = entry->xft_font; Out_Font(o) = NULL; } #endif /* This should only be the very very last resort. */ #ifdef USE_XFT if (entry == NULL || (entry->font == NULL && entry->type != XmFONT_IS_XFT)) #else if (entry == NULL || entry->font == NULL) #endif { Out_FontList(o) = _XmFontListCreateDefault(XtDisplay((Widget)w)); entry = Out_FontList(o)->renditions[0]; } else { /* Make copy. Original will be free */ /* amai, 20010313: * I do not understand why this is necessary, but * it seems to be ... * Why does copying the list affect behaviour?! * Try to omit the copying step and run test/Xm/text/test17! * The original will _not_ be freed, or at least it won't be * always freed, see test/Xm/text/test11, the leak check! */ Out_FontList(o) = XmFontListAppendEntry(NULL, entry); if (Out_FontListCreated(o)) XmFontListFree(oldlist); entry = Out_FontList(o)->renditions[0]; Out_FontListCreated(o) = True; } /* We may get a font or a fontset here */ if (entry->type == XmFONT_IS_FONT) { fs = (XFontStruct *)entry->font; Out_FontAverageWidth(o) = (fs->max_bounds.width + fs->min_bounds.width) / 2; Out_UseFontSet(o) = False; Out_Font(o) = fs; Out_Font_Ascent(o) = Out_FontAscent(o); Out_Font_Descent(o) = Out_FontDescent(o); #ifdef USE_XFT } else if (entry->type == XmFONT_IS_XFT) { Out_FontAverageWidth(o) = Out_XftFont(o)->max_advance_width; Out_FontAverageWidth(o) = entry->font_average_width; /* FIX ME HACK */ Out_UseFontSet(o) = False; /* FIX ME now sure what this means now */ Out_Font_Ascent(o) = Out_FontAscent(o); Out_Font_Descent(o) = Out_FontDescent(o); #endif } else if (entry->type == XmFONT_IS_FONTSET) { XFontStruct **fsl; char **nl; int r, i, max, min, ma, md; r = XFontsOfFontSet((XFontSet)entry->font, &fsl, &nl); DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "XFontsOfFontSet : %d\n", r)); for (i = 0; i < r; i++) { DEBUGOUT(_LtDebug0(__FILE__, NULL, "\t%s\n", nl[i])); } if (r == 0) { DEBUGOUT(_LtDebug(__FILE__, NULL, "No font in fontset\n")); abort(); } /* correct calculation */ ma = md = max = 0; min = INT_MAX; for(i=0; imax_bounds.width > max) max = fsl[i]->max_bounds.width; if (fsl[i]->min_bounds.width < min) min = fsl[i]->min_bounds.width; if (fsl[i]->max_bounds.ascent > ma) ma = fsl[i]->max_bounds.ascent; if (fsl[i]->max_bounds.descent > md) md = fsl[i]->max_bounds.descent; } Out_FontAverageWidth(o) = (max + min) / 2; Out_Font_Ascent(o) = ma; Out_Font_Descent(o) = md; /* Just pick the first one */ Out_Font(o) = fsl[0]; Out_UseFontSet(o) = True; } else { /* This is not supposed to happen. */ _XmWarning((Widget)w, "XmText FontInit: untreated rendition type\n"); } if (Out_FontAverageWidth(o) <= 0) { Out_FontAverageWidth(o) = _XmFontCalculateAverageCharacterWidth((Widget)w, fs); } Out_TabWidth(o) = 8 * Out_FontAverageWidth(o); #ifdef USE_XFT if (Out_XftFont(o)) Out_XftFont(o)->height = Out_Font_Ascent(o) + Out_Font_Descent(o); else o->lineheight = Out_Font_Ascent(o) + Out_Font_Descent(o); #else Out_FontHeight(o) = Out_Font_Ascent(o) + Out_Font_Descent(o); #endif Out_CursorHeight(o) = Out_FontHeight(o); DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "FontInit - fl %p font %p : ascent=%d descent=%d height=%d avewidth=%d\n", Out_FontList(o), Out_Font(o), Out_Font_Ascent(o), Out_Font_Descent(o), Out_FontHeight(o), Out_FontAverageWidth(o))); } /* * This thing still creates GC's the anti-social way - with XCreateGC. * * By using XtGetGC or XtAllocateGC, Xt will allow us to share GC's * with other widgets. We'd just have to be sure about what we want to be * the properties of the thing. * * Note: the explanation for this is in comments at the top of this file. */ static void GCInitialize(XmTextWidget w) { OutputData o = Text_OutputData(w); XGCValues values; XtGCMask mask, dynamic, dontcare; /* * DrawGC * Need to change : ClipRectangles * GCFillStyle | GCStipple */ values.line_style = LineSolid; values.line_width = 0; values.fill_style = FillSolid; mask = GCLineStyle | GCLineWidth | GCForeground | GCBackground | GCClipXOrigin | GCClipYOrigin; if (Out_FontType(o) == XmFONT_IS_FONT) { values.font = Out_Font(o)->fid; mask |= GCFont; } else #ifdef USE_XFT if (Out_FontType(o) == XmFONT_IS_XFT) { /* FIX ME XmFONT_IS_XFT */ } #endif #ifdef USE_BIDI else if (Out_FontType(o) == XmFONT_IS_XOC) { /* FIX ME XmFONT_IS_BIDI */ } #endif values.foreground = Prim_Foreground(w); values.background = XtBackground(w); values.clip_x_origin = 0; values.clip_y_origin = 0; dynamic = 0; dontcare = 0; if (! w->core.sensitive) { Screen *s = XtScreen((Widget)w); mask |= GCStipple; values.fill_style = FillStippled; values.stipple = XmGetPixmapByDepth(s, "50_foreground", 1, 0, 1); } #ifdef USE_XT_GC Out_DrawGC(o) = XtAllocateGC((Widget)w, w->core.depth, mask, &values, dynamic, dontcare); #else Out_DrawGC(o) = XCreateGC(XtDisplay((Widget)w), XtWindow(w), mask, &values); #endif Out_DrawGCInverted(o) = False; /* * Cursor GC * Need to change : Tile/Stipple Origin, Stipple */ values.line_style = LineSolid; values.line_width = 0; values.fill_style = FillStippled; values.foreground = Prim_Foreground(w); values.background = XtBackground(w); mask = GCLineStyle | GCLineWidth | GCFillStyle | GCForeground | GCBackground; dynamic = GCTileStipXOrigin | GCTileStipYOrigin | GCStipple; dontcare = 0; #ifdef USE_XT_GC Out_CursorGC(o) = XtAllocateGC((Widget)w, w->core.depth, mask, &values, dynamic, dontcare); #else Out_CursorGC(o) = XCreateGC(XtDisplay((Widget)w), XtWindow(w), mask, &values); #endif /* * CopyGC * At least this one is not changed anywhere :-) */ values.line_style = LineSolid; values.line_width = 0; values.fill_style = FillSolid; values.foreground = XtBackground(w); values.background = Prim_Foreground(w); mask = GCLineStyle | GCLineWidth | GCFillStyle | GCForeground | GCBackground; Out_CopyGC(o) = XtGetGC((Widget)w, mask, &values); } static void GCPixmap(XmTextWidget tw) { OutputData o = Text_OutputData(tw); Widget w = (Widget)tw; static char dots[] = {2, 1, 1}; GC gc; int width=0, width_erase=0, height=0; Display *display; XGCValues values; XtGCMask mask; values.line_style = LineSolid; values.line_width = 0; values.fill_style = FillSolid; values.foreground = 0; values.background = 0; display = XtDisplay(w); width = Out_CursorWidth(o) ; if (Out_FontType(o) == XmFONT_IS_FONT) { width_erase = 2 * Out_Font(o)->max_bounds.width; height = Out_CursorHeight(o) = Out_FontHeight(o); } else #ifdef USE_XFT if (Out_FontType(o) == XmFONT_IS_XFT) { width_erase = 2 * ((XftFont *)o->xft_font)->max_advance_width; width_erase = 2 * Out_FontAverageWidth(o); /* FIX ME HACK */ height = Out_CursorHeight(o) = Out_XftFont(o)->height; } #endif if (Out_CursorIBeam(o)) { XFreePixmap(XtDisplay(w), Out_CursorIBeam(o)); } Out_CursorIBeam(o) = (Pixmap)NULL; if (Out_CursorStipple(o)) { XFreePixmap(XtDisplay(w), Out_CursorStipple(o)); } Out_CursorStipple(o) = (Pixmap)NULL; if (Out_CursorSave(o)) { XFreePixmap(XtDisplay(w), Out_CursorSave(o)); } Out_CursorSave(o) = (Pixmap)NULL; Out_CursorSaveValid(o) = False; if (height > 0) { Out_CursorIBeam(o) = XCreatePixmap(display, RootWindowOfScreen(XtScreen(w)), width, height, 1); Out_CursorStipple(o) = XCreatePixmap(display, RootWindowOfScreen(XtScreen(w)), width, height, 1); Out_CursorSave(o) = XCreatePixmap(display, RootWindowOfScreen(XtScreen(w)), width_erase, height, w->core.depth); values.line_style = LineSolid; values.line_width = 0; values.fill_style = FillSolid; values.foreground = 0; values.background = 0; mask = GCLineStyle | GCLineWidth | GCFillStyle | GCForeground | GCBackground; gc = XCreateGC(display, Out_CursorIBeam(o), mask, &values); XFillRectangle(display, Out_CursorIBeam(o), gc, 0, 0, width, height); XFillRectangle(display, Out_CursorStipple(o), gc, 0, 0, width, height); XSetForeground(display, gc, 1); if (Text_InputData(w)->overstrike) { /* Overwrite cursor */ XDrawLine(display, Out_CursorIBeam(o), gc, 0, 0, 0, height - 1); XDrawLine(display, Out_CursorIBeam(o), gc, 0, height - 1, width - 1, height - 1); XDrawLine(display, Out_CursorIBeam(o), gc, width - 1, height - 1, width - 1, 0); XDrawLine(display, Out_CursorIBeam(o), gc, width - 1, 0, 0, 0); } else { /* I-beam */ XDrawLine(display, Out_CursorIBeam(o), gc, 2, 1, 2, height - 2); XDrawLine(display, Out_CursorIBeam(o), gc, 0, 0, 4, 0); XDrawLine(display, Out_CursorIBeam(o), gc, 0, height - 1, 4, height - 1); } XSetLineAttributes(display, gc, 0, LineOnOffDash, CapRound, JoinRound); XSetDashes(display, gc, 0, &dots[1], (int)dots[0]); XDrawLine(display, Out_CursorStipple(o), gc, 2, 1, 2, height - 2); XDrawLine(display, Out_CursorStipple(o), gc, 1, 0, 3, 0); XDrawLine(display, Out_CursorStipple(o), gc, 1, height - 1, 3, height - 1); XFreeGC(display, gc); } } static void GCClip(XmTextWidget w) { OutputData o = Text_OutputData(w); XRectangle clip; clip.x = 0; clip.y = 0; clip.width = XtWidth(w) - ( Out_RightMargin(o) + Out_LeftMargin(o) ); clip.height = XtHeight(w) - ( Out_TopMargin(o) + Out_BottomMargin(o) ); DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "XmText GCClip gc %p wid %d ht %d (%d - %d - %d, %d - %d - %d)\n", Out_DrawGC(o), clip.width, clip.height, XtWidth(w), Out_RightMargin(o), Out_LeftMargin(o), XtHeight(w), Out_TopMargin(o), Out_BottomMargin(o))); /* These calls change the GCs */ XSetClipRectangles(XtDisplay((Widget)w), Out_DrawGC(o), Out_LeftMargin(o), Out_TopMargin(o), &clip, 1, Unsorted); GCPixmap(w); } /* Take current dimensions, calculate #rows, #columns from it */ static void SizeRecalc(XmTextWidget w) { OutputData o = Text_OutputData(w); int previousColumns = Out_Columns(o); Out_XDraw(o) = Out_LeftMargin(o); #ifdef USE_XFT /* HACK */ if (Out_XftFont(o) && Out_XftFont(o)->height < 0) Out_XftFont(o)->height = Out_XftFont(o)->ascent + Out_XftFont(o)->descent; if (Out_XftFont(o)) { Out_Columns(o) = (XtWidth(w) - (Out_LeftMargin(o) + Out_RightMargin(o))) / Out_XftFont(o)->max_advance_width; Out_Columns(o) = (XtWidth(w) - (Out_LeftMargin(o) + Out_RightMargin(o))) / Out_FontAverageWidth(o); /* FIX ME HACK */ DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "SizeRecalc: xft cols %d = (wid %d - lm %d - rm %d) / fw %d, " "ht %d = %d + %d\n", Out_Columns(o), XtWidth(w), Out_LeftMargin(o), Out_RightMargin(o), Out_XftFont(o)->max_advance_width, Out_XftFont(o)->height, Out_XftFont(o)->ascent, Out_XftFont(o)->descent)); } else #endif { #ifdef USE_AVERAGE_WIDTH Out_Columns(o) = (XtWidth(w) - ( Out_LeftMargin(o) + Out_RightMargin(o) ) ) / Out_FontAverageWidth(o); DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "SizeRecalc: cols %d = (wid %d - lm %d - rm %d) / fw %d\n", Out_Columns(o), XtWidth(w), Out_LeftMargin(o), Out_RightMargin(o), Out_FontAverageWidth(o))); #else Out_Columns(o) = (XtWidth(w) - ( Out_LeftMargin(o) + Out_RightMargin(o) ) ) / Out_FontMaxWidth(o); DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "SizeRecalc: cols %d = (wid %d - lm %d - rm %d) / fw %d\n", Out_Columns(o), XtWidth(w), Out_LeftMargin(o), Out_RightMargin(o), Out_FontMaxWidth(o))); #endif } /* Y offset for a row R is calculated as Out_YDraw(o) - R*fontHeight, * and I add FontAscent here because y positions for fonts are * measured from the baseline of the font. */ Out_YDraw(o) = Out_TopMargin(o) + Out_Font_Ascent(o); if (Text_EditMode(w) == XmSINGLE_LINE_EDIT) { Out_Rows(o) = 1; } else { Out_Rows(o) = (XtHeight(w) - ( Out_TopMargin(o) + Out_BottomMargin(o) ) ) / Out_FontHeight(o); if ( Out_Rows(o) < 1 ) { Out_Rows(o) = 1; } } if (Out_ResizeHeight(o) && XtHeight(w) < (Out_TopMargin(o) + Out_BottomMargin(o) + Out_FontHeight(o) * Out_Rows(o))) { XtHeight(w) = Out_TopMargin(o) + Out_BottomMargin(o) + Out_FontHeight(o) * Out_Rows(o); } Out_NumberLines(o) = Out_Rows(o); if (Out_Columns(o) != previousColumns && Out_WordWrap(o)) { _XmTextUpdateLineTable((Widget)w, 0, 0, NULL, False); } DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "SizeRecalc wid %d ht %d -> rows %d cols %d\n", XtWidth(w), XtHeight(w), Out_Rows(o), Out_Columns(o))); } /* Text Drawing functions ------------------------------------------------ */ /* * This thing calls "Draw" which in turn calls "DrawText". * Both expect their last argument to be a flag indicating which type * of highlighting is to be used : * - XmHIGHLIGHT_NORMAL (no highlighting) * - XmHIGHLIGHT_SELECTED (reversed colours) * - XmHIGHLIGHT_SECONDARY_SELECTED (underlined) * * This means that this function should break up those parts of text that * are indicated as selected and/or highlighted. * * Highlighted stuff is recorded in an array. The array size is * Text_Highlight(w).number * Each element in the array has a mode and a position, e.g. * Text_Highlight(w).list[n].position */ static void DrawAll(XmTextWidget w) { Cardinal i; int resty, mh, hi; int highlight = XmHIGHLIGHT_NORMAL; /* initial value */ XmTextPosition np, first; OutputData o = Text_OutputData(w); #ifdef DANNY fprintf(stderr, "XmText DrawAll(%s dpy %p)\n", XtName(w), XtDisplay(w)); #endif /* * Without this, the area under the cursor is saved before it * is actually drawn; I can't figure out how that can happen but * it does. Registering when you redraw that the saved image is * invalid helps because we no longer restore invalid images... */ Out_CursorSaveValid(o) = False; mh = Text_Highlight(w).number; hi = 0; np = -1; if (mh) { if (Text_Highlight(w).list[0].position == 0) { highlight = Text_Highlight(w).list[0].mode; hi++; } if (hi < mh) { np = Text_Highlight(w).list[hi].position; } else { np = -1; } } while ( np != -1 && Text_Line(w)[0].start > np ) { highlight = Text_Highlight(w).list[hi].mode; hi++; if (hi < mh) { np = Text_Highlight(w).list[hi].position; } else { np = -1; } } if ( np < Text_Line(w)[0].start ) { np = -1; } for (i = 0; i < (Text_LineCount(w) < Out_Rows(o) ? Text_LineCount(w) : Out_Rows(o)); i++) { Line line = &Text_Line(w)[i]; Line next = &Text_Line(w)[i + 1]; #ifdef VERBOSE DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "DrawAll: line[%d]: start=%d end=%d, highlight change %d\n", i, line->start, next->start - 1, np)); #endif /* Cleaning part of widget */ XClearArea(XtDisplay(w), XtWindow(w), Prim_HighlightThickness(w) + Prim_ShadowThickness(w), Out_TopMargin(o) + i * Out_FontHeight(o), XtWidth(w) - 2 * (Prim_HighlightThickness(w) + Prim_ShadowThickness(w)), Out_FontHeight(o), False); /* Does highlighting change in this range of text ?? */ if (np >= line->start && np <= next->start - 1) { /* Yes */ /* Often highlight changes more than once per line */ /* Draw the first part */ first = line->start; /* Check whether a change is due right now */ if (first == np) { if (hi < mh) { if (Text_Highlight(w).list[hi].position == first) { highlight = Text_Highlight(w).list[hi].mode; hi++; if (hi < mh) { np = Text_Highlight(w).list[hi].position; } else { np = -1; } } } } while (np != -1 && np <= next->start - 1) { XmTextPosition drawTo = np; #if 0 if ( np < next->start - 1 ) { /*CP:16 May 1999: basically do not include the return char ** if the next highlight position is not past the end of the line. */ drawTo ++; } #endif (*Text_Output(w)->Draw)(w, i, first, drawTo, highlight); first = np; /* Find the next change */ highlight = Text_Highlight(w).list[hi].mode; hi++; if (hi == mh - 1) { np = -1; } else if (hi < mh) { np = Text_Highlight(w).list[hi].position; } } /* Draw the last part */ if (np != next->start - 1) { XmTextPosition endPos = next->start - 1; if ( np > endPos ) { /*CP:16 May 1999: basically include the return char ** if the next highlight position is past the end of the line. */ endPos ++; } (*Text_Output(w)->Draw)(w, i, first, endPos, highlight); } } else { /* Sanity checks */ if (next->start > 0 && line->start < next->start - 1) { /*CP:16 May 1999: this point is reached only for lines which ** are inside a selection area, so also include the newline. */ (*Text_Output(w)->Draw)(w, i, line->start, next->start, highlight); } else if ( ( line->start == next->start - 1 ) && highlight != XmHIGHLIGHT_NORMAL ) { (*Text_Output(w)->Draw)(w, i, line->start, next->start, highlight); } } } /* Cleaning rest of widget */ resty = Out_TopMargin(o) + i * Out_FontHeight(o) ; XClearArea(XtDisplay(w), XtWindow(w), Prim_HighlightThickness(w) + Prim_ShadowThickness(w), resty, XtWidth(w) - 2 * (Prim_HighlightThickness(w) + Prim_ShadowThickness(w)), XtHeight(w) - resty - (Prim_HighlightThickness(w) + Prim_ShadowThickness(w)), False); } /* Utilities ------------------------------------------------------------- */ #define Out_NextTabStop(o,x) \ (Out_TabWidth(o)*((x+Out_TabWidth(o))/Out_TabWidth(o))) /* XTextWidth clone, but taking TABS into account. * FIX ME: Must start from col 0 (or a tab boundary) for tab position to be * accurate. */ static int _XmTextNextX(XmTextWidget w, int x, char *ptr, int len) { OutputData o = Text_OutputData(w); XFontStruct *fs = Out_Font(o); XRectangle ink, log; while (len > 0) { unsigned int c; c = (unsigned char)*ptr; if (c == '\t') { x = Out_NextTabStop(o, x); } else if (c == '\0') { x = 0; } else { if (Out_FontList(o)->renditions[0]->type == XmFONT_IS_FONT) { x += XTextWidth(fs, ptr, 1); } else if (Out_FontList(o)->renditions[0]->type == XmFONT_IS_FONTSET) { XmbTextExtents((XFontSet)Out_FontList(o)->renditions[0]->font, ptr, 1, &ink, &log); x += log.width; #ifdef USE_XFT } else if (Out_XftFont(o)) { XGlyphInfo ext; XftTextExtents8(XtDisplay((Widget)w), Out_XftFont(o), (unsigned char*)ptr, 1, &ext); x += ext.width; #endif } else { /* ??? */ } #if 0 break; if (c < fs->min_char_or_byte2 || c > fs->max_char_or_byte2) { c = fs->default_char; /* * Hack by vogt@kvi.nl * Updated 8 nov 2000 by Tom Pollard pollard@schrodinger.com */ if (c < fs->min_char_or_byte2 || c > fs->max_char_or_byte2) { DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "_XmTextNextX: fs->default_char %d -> 32\n", c)); c = 32; } /* end hack */ } if (fs->per_char) { c -= fs->min_char_or_byte2; x += fs->per_char[c].width; } else x += fs->max_bounds.width; #endif } ptr++; len--; } return x; } static Dimension FontTextWidth(XmTextWidget w, XmTextPosition pos, XmTextPosition end) { XmTextBlockRec block; Dimension width; if (Text_Source(w) == NULL) { _XmWarning((Widget)w, "FontTextWidth: no source\n"); return 1; } (*Text_Source(w)->ReadSource) (Text_Source(w), pos, end, &block); width = _XmTextNextX(w, 0, block.ptr, block.length); #ifdef VERBOSE DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "FontTextWidth(%s) => %d\n", block.ptr, width)); #endif XtFree(block.ptr); return width; } static XmTextPosition XToPos(XmTextWidget w, LineNum row, int x) { OutputData o = Text_OutputData(w); Line line = &Text_Line(w)[row]; Line next = &Text_Line(w)[row + 1]; XmTextPosition start, end, pos; XmTextBlockRec block; DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "XToPos(row %d, x %d) TotalLines %d\n", row, x, Text_TotalLines(w))); /* Just guessing - Is this right ?? Danny */ if (row >= Text_TotalLines(w) - 0) { next = &Text_Line(w)[Text_TotalLines(w) - 1]; end = next->start - 1; if (end < 0) { end = 0; } return end; } start = line->start; if (next->start == (XmTextPosition)PASTENDPOS) { end = Text_LastPos(w); /* Avoid PASTENDPOS */ } #if 0 else if (next->past_end) /* There's nothing there ... */ { end = start; /* FIXME - this is probably wrong */ } #endif else { end = next->start - 1; } /* x is now the width from the start of the line to the pixel pos */ x -= Out_LeftMargin(o) - Out_XOffset(o); (*Text_Source(w)->ReadSource) (Text_Source(w), start, end, &block); /* check if the cursor is before the 1st character */ if (x <= 0) { pos = start; } /* OK, how 'bout after the last character */ else if (x > _XmTextNextX(w, 0, block.ptr, block.length)) { pos = end; } /* must be in between somewhere... */ else { int count, prevTot, tot, i, diff, mb; prevTot = tot = 0; count = end - start; pos = -1; diff = x; mb = 0; for (i = 0; i < count; i++) { tot = Out_FontTextWidth(o, block.ptr, i); if (x < tot) { pos = start + i; if (tot - x > diff) pos = pos - 1 - mb; break; } if (i && prevTot == tot) /* Fix at 1k2.2 */ mb++; else mb = 0; prevTot = tot; diff = x - tot; } if (pos < 0) { pos = end; } } XtFree(block.ptr); DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "XToPos: x=%d start=%d end=%d pos=%d\n", x, start, end, pos)); return pos; } static LineNum YToLineNum(XmTextWidget w, Position y) { OutputData o = Text_OutputData(w); LineNum line, l; l = line = (LineNum)((y - Out_TopMargin(o)) / Out_FontHeight(o)); if (line >= Text_LineCount(w)) { line = Text_LineCount(w); } DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "YToLineNum: y=%d line=%d (l %d Text_LineCount %d)\n", y, line, l, Text_LineCount(w))); return line; } static void DrawText(XmTextWidget w, int x, int y, char *ptr, int len, XmHighlightMode highlight) { OutputData o = Text_OutputData(w); int xoff, xstart = x, xend; Pixel fg, bg; #ifdef VERBOSE DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "DrawText: x %d y %d '%s' len %d hl %d\n", x, y, (ptr == 0) ? "(NULL)" : ptr, len, highlight)); #endif xoff = Out_LeftMargin(o) - Out_XOffset(o); #if 1 DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "XmText DrawText x %d y %d '%s' len %d hl %d, fh %d\n", x + xoff, y, (ptr == 0) ? "(NULL)" : ptr, len, highlight, Out_FontHeight(o))); #endif fg = Prim_Foreground(w); bg = XtBackground(w); /* Only change the GC if we need to */ if (highlight == XmHIGHLIGHT_SELECTED) { fg = XtBackground(w); bg = Prim_Foreground(w); } else { fg = Prim_Foreground(w); bg = XtBackground(w); } while (len > 0 && *ptr) { char *start; Dimension piecewidth, pieceheight; int count; start = ptr; count = 0; while (len > 0 && *ptr && *ptr != '\t' && *ptr != '\n' ) { ptr++, count++, len--; } if (count > 0) { piecewidth = _XmTextNextX(w, 0, start, count); pieceheight = 10; /* FIX ME */ if (count > 0) { /* This is for bug #558840. * Can be tested in test/Xm/text/test1 by double-clicking. */ unsigned long mask = GCForeground | GCBackground; XGCValues v; v.foreground = bg; v.background = fg; XChangeGC(XtDisplay(w), Out_DrawGC(o), mask, &v); XFillRectangle(XtDisplay(w), XtWindow(w), Out_DrawGC(o), x + xoff, y - Out_Font_Ascent(o), piecewidth, y + Out_Font_Descent(o)); v.background = bg; v.foreground = fg; XChangeGC(XtDisplay(w), Out_DrawGC(o), mask, &v); if (Out_FontList(o)->renditions[0]->type == XmFONT_IS_FONT) { XDrawString(XtDisplay(w), XtWindow(w), Out_DrawGC(o), x + xoff, y, start, count); } else if (Out_FontList(o)->renditions[0]->type == XmFONT_IS_FONTSET) { XmbDrawString(XtDisplay(w), XtWindow(w), (XFontSet)Out_FontList(o)->renditions[0]->font, Out_DrawGC(o), x + xoff, y, start, count); #ifdef USE_XFT } else if (Out_XftFont(o)) { _XmXftDrawString(XtDisplay(w), XtWindow(w), Out_FontList(o)->renditions[0], 1, x + xoff, y, start, count); #endif } else { /* ??? */ } } #ifdef VERBOSE if (_LtDebugInDebug(__FILE__, (Widget)w)) { char temp[256]; strncpy(temp, start, count); temp[count] = '\0'; DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "Draw: x=%d y=%d -->%s<--\n", x, y, temp)); } #endif x += piecewidth; } if (len > 0 && *ptr == '\t') { int left = x; x = Out_NextTabStop(o, x); if (highlight == XmHIGHLIGHT_SELECTED) { XSetForeground(XtDisplay(w), Out_DrawGC(o), Prim_Foreground(w)); XFillRectangle(XtDisplay(w), XtWindow(w), Out_DrawGC(o), left + xoff, y - Out_Font_Ascent(o), x - left, Out_FontHeight(o)); XSetForeground(XtDisplay(w), Out_DrawGC(o), XtBackground(w)); } ptr++, len--; } if (len > 0 && *ptr == '\n') { int left = x; x = Out_NextTabStop(o, x); if (highlight == XmHIGHLIGHT_SELECTED) { XSetForeground(XtDisplay(w), Out_DrawGC(o), Prim_Foreground(w)); XFillRectangle(XtDisplay(w), XtWindow(w), Out_DrawGC(o), left + xoff, y - Out_Font_Ascent(o), Out_ScrollWidth(o) - ( left + xoff ), Out_FontHeight(o)); XSetForeground(XtDisplay(w), Out_DrawGC(o), XtBackground(w)); } ptr++, len--; } } xend = x; if (highlight == XmHIGHLIGHT_SECONDARY_SELECTED) { XDrawLine(XtDisplay(w), XtWindow(w), Out_DrawGC(o), xoff + xstart, y + 1, xoff + xend, y + 1); } } static void ChangeHOffset(XmTextWidget w, int offset) { OutputData o = Text_OutputData(w); DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "ChangeHOffset(%d)\n", offset)); if (Out_XOffset(o) == offset) { return; } Out_XOffset(o) = offset; Out_CursorSaveValid(o) = False; (*Text_Output(w)->expose) ((Widget)w, NULL, (Region)NULL); } extern void _XmRedisplayHBar(XmTextWidget w, int offset) { OutputData o = Text_OutputData(w); Dimension displayWidth, maxWidth; int oldMin, oldMax, oldSize, oldValue; int newValue; int i; Out_ScrollWidth(o) = XtWidth(w) - ( Out_RightMargin(o) + Out_LeftMargin(o) ); if (Out_Hbar(o) == NULL) { return; } ChangeHOffset(w, offset); if (!Out_ScrollHorizontal(o)) { return; } maxWidth = 0; for (i = 0; i < (Text_LineCount(w) < Out_Rows(o) ? Text_LineCount(w) : Out_Rows(o)); i++) { if (maxWidth < Text_Line(w)[i].extra->width) { maxWidth = Text_Line(w)[i].extra->width; } } displayWidth = XtWidth(w) - ( Out_RightMargin(o) + Out_LeftMargin(o) ); if (maxWidth < displayWidth) { maxWidth = displayWidth; } Out_ScrollWidth(o) = maxWidth; XtVaGetValues(Out_Hbar(o), XmNmaximum, &oldMax, XmNminimum, &oldMin, XmNsliderSize, &oldSize, XmNvalue, &oldValue, NULL); newValue = _XmMin(Out_XOffset(o), maxWidth - displayWidth); if (oldMax != maxWidth || oldMin != 0 || oldSize != displayWidth || oldValue != newValue) { XtVaSetValues(Out_Hbar(o), XmNmaximum, maxWidth, XmNminimum, 0, XmNsliderSize, displayWidth, XmNvalue, newValue, NULL); } DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "_XmRedisplayHBar: oldmax=%d newmax=%d oldsize=%d newsize=%d\n", oldMax, maxWidth, oldSize, displayWidth)); DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "_XmRedisplayHBar: oldvalue=%d newvalue=%d\n", oldValue, newValue)); } extern void _XmChangeVSB(XmTextWidget w, XmTextPosition pos) { OutputData o = Text_OutputData(w); int top_index, pos_index, newValue; int oldMin = 0, oldMax = 0, oldSize = 0, oldValue = 0, newMax; DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "_XmChangeVSB: pos=%d\n", pos)); top_index = _XmTextGetTableIndex(w, Text_TopPos(w)); pos_index = _XmTextGetTableIndex(w, pos); DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "_XmChangeVSB: top_index=%d pos_index=%d\n", top_index, pos_index)); if (Out_Vbar(o)) { XtVaGetValues(Out_Vbar(o), XmNmaximum, &oldMax, XmNminimum, &oldMin, XmNsliderSize, &oldSize, XmNvalue, &oldValue, NULL); } /* SG (15/08/1998) newMax = _XmMax(Text_TotalLines(w) - 1, Out_Rows(o)); with the original code it was not possible to use the scrollbar to scroll down to the last line. Most obviously if out_rows is 1 (hence the slider size is 1) and there are 2 lines of text, setting scrollbar max to 1 with a slider size of 1 means you cannot move the scroll bar at all ! */ newMax = _XmMax(Text_TotalLines(w) , Out_Rows(o)); if (newMax == 0) { newMax = 1; /* Avoid another warning message ?? */ } /* Setting XmNminimum == XmNmaximum is not a good idea */ #if 0 /* rws 16 Jan 1999 What does this do???? The scrollbar value should be the index of the first visible line, right?? */ newValue = pos_index > (newMax - Out_Rows(o)) ? (newMax - Out_Rows(o)) : pos_index; #else newValue = top_index; #endif if (Out_Vbar(o) && (oldMax != newMax || oldMin != 0 || oldSize != Out_Rows(o) || oldValue != newValue)) { XmScrollBarCallbackStruct cbs; XtVaSetValues(Out_Vbar(o), XmNmaximum, newMax, XmNminimum, 0, XmNvalue, newValue, XmNsliderSize, Out_Rows(o), XmNpageIncrement, Out_Rows(o), NULL); cbs.event = NULL; cbs.value = newValue; cbs.reason = XmCR_VALUE_CHANGED; cbs.pixel = 0; XtCallCallbacks(Out_Vbar(o), XmNvalueChangedCallback, &cbs); } DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "_XmChangeVSB: oldmax=%d newmax=%d oldsize=%d newsize=%d\n", oldMax, newMax, oldSize, Out_Rows(o))); DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "_XmChangeVSB: oldvalue=%d newvalue=%d\n", oldValue, newValue)); } /* Cursor functions -------------------------------------------------------- */ static void CursorInit(XmTextWidget w) { OutputData o = Text_OutputData(w); Out_CursorIBeam(o) = (Pixmap)NULL; Out_CursorStipple(o) = (Pixmap)NULL; Out_CursorSave(o) = (Pixmap)NULL; /* Out_CursorPositionVisible(o) = True; */ Out_CursorSaveValid(o) = False; } void _XmCursorOverstrike(Widget w) { OutputData o = Text_OutputData(w); /* These change the GC !! (Danny) */ if (Out_HasFocus(o)) { GCPixmap((XmTextWidget)w); if (Text_InputData(w)->overstrike) { XSetStipple(XtDisplay((Widget)w), Out_CursorGC(o), Out_CursorIBeam(o)); } else { XSetStipple(XtDisplay((Widget)w), Out_CursorGC(o), Out_CursorIBeam(o)); } } else { XSetStipple(XtDisplay((Widget)w), Out_CursorGC(o), Out_CursorStipple(o)); } } static void CursorSet(XmTextWidget w, Boolean focus) { OutputData o = Text_OutputData(w); Out_HasFocus(o) = focus; /* These change the GC !! (Danny) */ if (focus) { XSetStipple(XtDisplay((Widget)w), Out_CursorGC(o), Out_CursorIBeam(o)); } else { XSetStipple(XtDisplay((Widget)w), Out_CursorGC(o), Out_CursorStipple(o)); } } static void CursorSaveUnderIBeam(XmTextWidget w, Position x, Position y) { OutputData o = Text_OutputData(w); if (!XtIsRealized((Widget)w)) { return; } #ifdef VERBOSE DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "CursorSaveUnderIBeam\n")); #endif /* Make sure that the text is drawn before saving the cursor */ XFlush(XtDisplay((Widget)w)); /* save the area under the cursor */ XFillRectangle(XtDisplay((Widget)w), Out_CursorSave(o), Out_CopyGC(o), 0, 0, Out_CursorWidth(o), Out_CursorHeight(o) ); XCopyArea(XtDisplay((Widget)w), XtWindow((Widget)w), Out_CursorSave(o), Out_CursorGC(o), x - 2, y, Out_CursorWidth(o), Out_CursorHeight(o), 0, 0); Out_CursorSaveValid(o) = True; } static void CursorRestoreUnderIBeam(XmTextWidget w, Position x, Position y) { OutputData o = Text_OutputData(w); if (!XtIsRealized((Widget)w)) { return; } #ifdef VERBOSE DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "CursorRestoreUnderIBeam\n")); #endif /* Make sure that the text is drawn before erasing the cursor */ XFlush(XtDisplay((Widget)w)); XCopyArea(XtDisplay((Widget)w), Out_CursorSave(o), XtWindow((Widget)w), Out_CursorGC(o), 0, 0, 5, Out_FontHeight(o), x - 2, y); Out_CursorSaveValid(o) = False; /* Huh ?? FIX ME */ } static void CursorDrawIBeam(XmTextWidget w, int x, int y) { OutputData o = Text_OutputData(w); /* save the area under the cursor */ CursorSaveUnderIBeam(w, x, y); /* Bail if the GC's don't exist yet. */ if (!XtIsRealized((Widget)w)) { DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "CursorDrawIBeam: no GC\n")); return; } /* These change the GC !! (Danny) */ XSetTSOrigin(XtDisplay((Widget)w), Out_CursorGC(o), x - 2, y); if (Text_InputData(w)->overstrike) { } else { } XFillRectangle(XtDisplay((Widget)w), XtWindow((Widget)w), Out_CursorGC(o), x - 2, y, Out_CursorWidth(o), Out_CursorHeight(o)); } static void CursorDraw(XmTextWidget w) { OutputData o = Text_OutputData(w); if (Out_CursorPositionVisible(o)) { CursorDrawIBeam(w, Out_CursorX(o), ( Out_CursorY(o) - Out_CursorHeight(o) ) + Out_Font_Descent(o) ); Out_BlinkOn(o) = True; } } static void CursorErase(XmTextWidget w) { OutputData o = Text_OutputData(w); if (Out_CursorSaveValid(o)) { CursorRestoreUnderIBeam(w, Out_CursorX(o), ( Out_CursorY(o) - Out_CursorHeight(o) ) + Out_Font_Descent(o) ); } Out_BlinkOn(o) = False; } /* Callbacks --------------------------------------------------------------- */ static void HandleTimer(XtPointer client_data, XtIntervalId *timer) { XmTextWidget w = (XmTextWidget)client_data; OutputData o = Text_OutputData(w); OnOrOff nextBlinkState = Out_BlinkState(o) == on ? off : on; (*Text_Output(w)->DrawInsertionPoint) (w, Text_CursorPos(w), nextBlinkState ); Out_BlinkState(o) = nextBlinkState; Out_TimerId(o) = XtAppAddTimeOut(XtWidgetToApplicationContext((Widget)w), Out_BlinkRate(o), HandleTimer, (XtPointer)w); } static void HandleHBar(Widget sw, XtPointer client_data, XtPointer call_data) { XmTextWidget w = (XmTextWidget)client_data; OutputData o = Text_OutputData(w); XmScrollBarCallbackStruct *cbs = (XmScrollBarCallbackStruct *)call_data; Dimension displayWidth, newOffset = 0; switch (cbs->reason) { case XmCR_DECREMENT: DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "HandleHbar reason=XmCR_DECREMENT value= %d\n", cbs->value)); newOffset = Out_XOffset(o) > Out_FontAverageWidth(o) ? Out_XOffset(o) - Out_FontAverageWidth(o) : 0; break; case XmCR_DRAG: DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "HandleHbar reason=XmCR_DRAG value=%d\n", cbs->value)); newOffset = cbs->value / Out_FontAverageWidth(o) * Out_FontAverageWidth(o); break; case XmCR_INCREMENT: DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "HandleHbar reason=XmCR_INCREMENT value=%d\n", cbs->value)); displayWidth = XtWidth(w) - ( Out_RightMargin(o) + Out_LeftMargin(o) ); if (Out_XOffset(o) < Out_ScrollWidth(o) - displayWidth - Out_FontAverageWidth(o)) { newOffset = Out_XOffset(o) + Out_FontAverageWidth(o); } else { newOffset = Out_ScrollWidth(o) - displayWidth; } break; case XmCR_PAGE_DECREMENT: DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "HandleHbar reason=XmCR_PAGE_DECREMENT value=%d\n", cbs->value)); #ifdef USE_AVERAGE_WIDTH newOffset = Out_XOffset(o) > Out_Columns(o) * Out_FontAverageWidth(o) ? Out_XOffset(o) - Out_Columns(o) * Out_FontAverageWidth(o) : 0; #else newOffset = Out_XOffset(o) > Out_Columns(o) * Out_FontMaxWidth(o) ? Out_XOffset(o) - Out_Columns(o) * Out_FontMaxWidth(o) : 0; #endif break; case XmCR_PAGE_INCREMENT: DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "HandleHbar reason=XmCR_PAGE_INCREMENT value=%d\n", cbs->value)); displayWidth = XtWidth(w) - 2 * (Prim_HighlightThickness(w) + Prim_ShadowThickness(w) + Text_MarginWidth(w)); #ifdef USE_AVERAGE_WIDTH if (Out_XOffset(o) < Out_ScrollWidth(o) - displayWidth - Out_Columns(o) * Out_FontAverageWidth(o)) { newOffset = Out_XOffset(o) + Out_Columns(o) * Out_FontAverageWidth(o); #else if (Out_XOffset(o) < Out_ScrollWidth(o) - displayWidth - Out_Columns(o) * Out_FontMaxWidth(o)) { newOffset = Out_XOffset(o) + Out_Columns(o) * Out_FontMaxWidth(o); #endif } else { newOffset = Out_ScrollWidth(o) - displayWidth; } break; case XmCR_TO_BOTTOM: DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "HandleHbar reason=XmCR_TO_BOTTOM value=%d pixel=%d\n", cbs->value, cbs->pixel)); newOffset = 0; break; case XmCR_TO_TOP: DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "HandleHbar reason=XmCR_TO_TOP value=%d pixel=%d\n", cbs->value, cbs->pixel)); displayWidth = XtWidth(w) - 2 * (Prim_HighlightThickness(w) + Prim_ShadowThickness(w) + Text_MarginWidth(w)); newOffset = Out_ScrollWidth(o) - displayWidth; break; case XmCR_VALUE_CHANGED: DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "HandleHbar reason=XmCR_VALUE_CHANGED value=%d\n", cbs->value)); newOffset = cbs->value / Out_FontAverageWidth(o) * Out_FontAverageWidth(o); break; default: newOffset = Out_XOffset(o); break; } ChangeHOffset(w, newOffset); XtVaSetValues(Out_Hbar(o), XmNvalue, Out_XOffset(o), NULL); } static void HandleVBar(Widget sw, XtPointer client_data, XtPointer call_data) { XmTextWidget w = (XmTextWidget)client_data; OutputData o = Text_OutputData(w); XmScrollBarCallbackStruct *cbs = (XmScrollBarCallbackStruct *)call_data; Dimension index; switch (cbs->reason) { case XmCR_DECREMENT: DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "HandleVbar reason=XmCR_DECREMENT\n")); XmTextScroll((Widget)w, -1); break; case XmCR_DRAG: DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "HandleVbar reason=XmCR_DRAG value=%d\n", cbs->value)); index = cbs->value; Text_TopPos(w) = Text_LineTable(w)[index].start_pos; Text_NeedsRefigureLines(w) = True; break; case XmCR_INCREMENT: DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "HandleVbar reason=XmCR_INCREMENT\n")); XmTextScroll((Widget)w, 1); break; case XmCR_PAGE_DECREMENT: DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "HandleVbar reason=XmCR_PAGE_DECREMENT\n")); XmTextScroll((Widget)w, -Out_Rows(o)); break; case XmCR_PAGE_INCREMENT: DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "HandleVbar reason=XmCR_PAGE_INCREMENT\n")); XmTextScroll((Widget)w, Out_Rows(o)); break; case XmCR_TO_BOTTOM: DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "HandleVbar reason=XmCR_TO_BOTTOM\n")); index = Text_TotalLines(w) - 1 - Out_Rows(o); Text_TopPos(w) = Text_LineTable(w)[index].start_pos; Text_NeedsRefigureLines(w) = True; break; case XmCR_TO_TOP: DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "HandleVbar reason=XmCR_TO_TOP\n")); Text_TopPos(w) = Text_FirstPos(w); Text_NeedsRefigureLines(w) = True; break; case XmCR_VALUE_CHANGED: DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "HandleVbar reason=XmVALUE_CHANGED\n")); index = cbs->value; Text_TopPos(w) = Text_LineTable(w)[index].start_pos; Text_NeedsRefigureLines(w) = True; break; default: DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "HandleVbar reason=UNKNOWN\n %d", cbs->reason)); break; } _XmRedisplayHBar(w, Out_XOffset(o)); /*CP : I do not think this is needed here Text_NeedsRefigureLines(w) = True; */ (*w->core.widget_class->core_class.expose) ((Widget)w, NULL, (Region)NULL); } static void HandleFocusEvents(Widget aw, XtPointer client_data, XEvent* event, Boolean* continueToDispatch ) { XmTextWidget w = (XmTextWidget)aw; OutputData o = Text_OutputData(w); DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "HandleFocusEvent event=%s\n", event->type == FocusIn ? "FocusIn" : "FocusOut")); if ( event->type == FocusIn && event->xany.send_event && !Out_HasFocus(o) ) { if (Text_FocusCallback(w) ) { XmAnyCallbackStruct cbs; cbs.reason = XmCR_FOCUS; cbs.event = event; XtCallCallbackList((Widget)w, Text_FocusCallback(w), &cbs); } Out_HasFocus(o) = True; XSetStipple(XtDisplay(aw), Out_CursorGC(o), Out_CursorIBeam(o)); if (Out_BlinkRate(o) > 0) { /*CP:Handle timer will do all this Out_TimerId(o) = XtAppAddTimeOut(XtWidgetToApplicationContext(aw), Out_BlinkRate(o), HandleTimer, (XtPointer)w); */ HandleTimer((XtPointer)w, 0); } (*Text_Output(w)->DrawInsertionPoint) (w, Text_CursorPos(w), on); } else if ( event->type == FocusOut && Out_HasFocus(o) ) { if (Text_LosingFocusCallback(w)) { XmTextVerifyCallbackStruct cbs; cbs.reason = XmCR_LOSING_FOCUS; cbs.event = event; cbs.currInsert = cbs.newInsert = Text_CursorPos(w); cbs.startPos = cbs.endPos = 0; cbs.text = NULL; XtCallCallbackList((Widget)w, Text_LosingFocusCallback(w), &cbs); } Out_HasFocus(o) = False; XSetStipple(XtDisplay(aw), Out_CursorGC(o), Out_CursorStipple(o)); (*Text_Output(w)->DrawInsertionPoint) (w, Text_CursorPos(w), on); if (Out_TimerId(o)) { XtRemoveTimeOut(Out_TimerId(o)); Out_TimerId(o) = 0; } } } /* Output Methods --------------------------------------------------------- */ static XmTextPosition XYToPos(XmTextWidget w, Position x, Position y) { LineNum row = YToLineNum(w, y); if ( row == Text_LineCount(w)) return Text_LastPos(w); return XToPos(w, row, x); } /* * Returns whether the cursor is in an area that's currently visible. */ static Boolean PosToXY(XmTextWidget w, XmTextPosition pos, Position *x, Position *y) { OutputData o = Text_OutputData(w); Cardinal i; *x = *y = -1; /* On purpose ! */ if (pos < Text_TopPos(w)) { return False; } for (i = 0; i < Text_LineCount(w); i++) { Line line = &Text_Line(w)[i]; Line next = &Text_Line(w)[i + 1]; if (pos >= line->start && pos < next->start) { *y = Out_YDraw(o) + i * Out_FontHeight(o); *x = Out_XDraw(o) - Out_XOffset(o) + FontTextWidth(w, line->start, pos); return True; } } return False; } static void MakePositionVisible(XmTextWidget w, XmTextPosition pos) { OutputData o = Text_OutputData(w); unsigned int line, newTopLine; int start, offset; Dimension xpos, last_xpos; Boolean UpdateVSB = False; DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "MakePositionVisible pos=%d\n", pos)); line = _XmTextGetTableIndex(w, pos); DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "\tline=%d, top_line=%d, line_count=%d, rows=%d redisplay=%s refigure=%s\n", line, Text_TopLine(w), Text_LineCount(w), Out_Rows(o), Text_NeedsRedisplay(w) ? "True" : "False", Text_NeedsRefigureLines(w) ? "True" : "False" )); if (line < Text_TopLine(w)) { newTopLine = line; } else if (line > Text_TopLine(w) + Out_Rows(o) - 1) { newTopLine = line - Out_Rows(o) + 1; } else { newTopLine = Text_TopLine(w); } if (newTopLine != Text_TopLine(w)) { Text_TopPos(w) = Text_LineTable(w)[newTopLine].start_pos; Text_NeedsRedisplay(w) = True; Text_NeedsRefigureLines(w) = True; UpdateVSB = True; } start = Text_LineTable(w)[line].start_pos; xpos = FontTextWidth(w, start, pos); last_xpos = XtWidth(w) - ( Out_RightMargin(o) + Out_LeftMargin(o) ); if (xpos - Out_XOffset(o) > last_xpos) { offset = xpos - last_xpos; } else if (xpos < Out_XOffset(o)) { offset = xpos; } else { offset = Out_XOffset(o); } /* FIX ME should Out_ScrollHorizontal and Out_ScrollVertical be False if * Text is not child of scrolledwindow */ if (offset != Out_XOffset(o)) { if (Out_ScrollHorizontal(o) && Out_Hbar(o)) { _XmRedisplayHBar(w, offset); } else { ChangeHOffset(w, offset); } } if (Out_ScrollVertical(o) && Out_Vbar(o) && UpdateVSB) { _XmChangeVSB(w, pos); } } static Boolean MoveLines(XmTextWidget w, LineNum from, LineNum to, LineNum dest) { return False; } static Boolean MeasureLine(XmTextWidget w, LineNum num, XmTextPosition pos, XmTextPosition *next, LineTableExtraRec **extra) { OutputData o = Text_OutputData(w); Dimension width = 0; XmTextPosition start, end; LineTableExtra e; #ifdef VERBOSE DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "MeasureLine: line=%d pos=%d %s %s\n", num, pos, next ? "wants next" : "", extra ? "wants width": "")); #endif start = pos < Text_LastPos(w) ? pos : Text_LastPos(w); if (start < Text_LastPos(w)) { end = (*Text_Source(w)->Scan) (Text_Source(w), pos, XmSELECT_LINE, XmsdRight, 1, False); } else { end = Text_LastPos(w); } #ifdef VERBOSE DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "\tmeasure from %d to %d\n", start, end)); #endif if (next) { if (end >= Text_LastPos(w)) { *next = (XmTextPosition)PASTENDPOS; #ifdef VERBOSE DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "\tnext PASTENDPOS\n")); #endif } else { *next = end + 1; #ifdef VERBOSE DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "\tnext %d\n", *next)); #endif } width = FontTextWidth(w, start, end); if (extra) { e = (LineTableExtra)XtMalloc(sizeof(LineTableExtraRec)); e->width = width; e->wrappedbychar = False; *extra = e; } } #if VERBOSE /* This is incredibly verbose; besides it seems to work. */ if (_LtDebugInDebug(__FILE__, (Widget)w)) { if (next) DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "MeasureLine: line=%d pos=%d next=%d width=%d\n", num, pos, *next, width)); else DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "MeasureLine: line=%d pos=%d next=NULL width=%d\n", num, pos, width)); } #endif if (num <= Out_Rows(o) - 1) { return True; } else { _XmRedisplayHBar(w, Out_XOffset(o)); return False; } } /* * DrawInsertionPoint() gets called all the time from TextIn.c, which doesn't * keep track of whether the insertion point should be visible at all. * We should therefore implement XmNcursorPositionVisible here. * * Between calls of DrawInsertionPoint() we should keep track of whether and * where the cursor is with Out_CursorX(o) and Out_CursorY(o); set them * to -1 for no cursor. */ static void DrawInsertionPoint(XmTextWidget w, XmTextPosition pos, OnOrOff state) { OutputData o = Text_OutputData(w); Position x, y; #if 1 /* rws 1 Apr 2000 WRT the disappearing cursor.... HandleTimer seems to be getting called when it should. This takes care of setting Out_BlinkState, then calls DrawInsertionPoint, which is also messing with Out_BlinkState. I'm not sure what Out_BlinkOn is keeping track of, but I would expect the two if clauses near the start of DrawInsertionPoint to be a little more symetrical wrt Out_BlinkOn and Out_BlinkState. Commenting out the two lines messing with the BlinkState seems to keep my cursor from disappearing. I've bracketted the section in question with #if 1, it needs a little more investigation..... */ if ( state == off ) { if ( Out_BlinkOn(o) == 0 ) { Out_BlinkState(o) = off; } Out_BlinkOn(o) -- ; } if ( state == on ) { if ( Out_BlinkOn(o) < 0 ) { Out_BlinkOn(o)++ ; } Out_BlinkState(o) = on; } #endif if ( Out_BlinkOn(o) != 0 ) { return; } if (pos == PASTENDPOS) /* No No No : don't want this */ { pos = Text_LastPos(w); /* ??? Danny 6/7/97 */ } #ifdef VERBOSE DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "DrawInsertionPoint Cursor : Pos %d, Save %sValid, %s Visible\n", pos, Out_CursorSaveValid(o) ? "" : "not ", Out_CursorPositionVisible(o) ? "" : "not")); #endif #if 0 /* Experimental */ /* Figure out what to do with the cursor here, before actually showing it. */ if (!Out_CursorPositionVisible(o)) { if (state == off) CursorErase(w); return; } #endif if (!XtIsRealized((Widget)w)) { return; } /* Force to get forcus to display strings quickly. */ XmImSetFocusValues((Widget)w, NULL, 0); /* erase previously visible cursor */ if (Out_CursorX(o) >= 0 && Out_CursorY(o) >= 0) { CursorErase(w); } if (state == on) { /* draw new cursor * PosToXY returns whether the position is in the area currently * shown */ if ((*Text_Output(w)->PosToXY) (w, pos, &x, &y)) { Out_CursorX(o) = x; Out_CursorY(o) = y; #if 0 /* * This shouldn't be necessary 'cause CursorDraw calls CursorDrawIBeam * which already takes care of this. */ if (!Out_CursorSaveValid(o)) { CursorSaveUnderIBeam(w, Out_CursorX(o), Out_CursorY(o)); } #endif #ifdef VERBOSE DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "Draw cursor at %d %d\n", Out_CursorX(o), Out_CursorY(o))); #endif CursorDraw(w); } } #if VERBOSE if (_LtDebugInDebug(__FILE__, (Widget)w)) { DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "DrawInsertionPoint: x=%d pos=%d state=%s\n", Out_CursorX(o), pos, (state == on ? "on" : "off"))); } #endif } static void Draw(XmTextWidget w, LineNum num, XmTextPosition start, XmTextPosition end, XmHighlightMode highlight) { OutputData o = Text_OutputData(w); XmTextBlockRec block; Line line = &Text_Line(w)[num]; #ifdef DANNY fprintf(stderr, "XmText Draw(%s dpy %p)\n", XtName(w), XtDisplay(w)); #endif if (start > Text_LastPos(w)) { return; } if (end > Text_LastPos(w)) { end = Text_LastPos(w); if (line->start > end) { return; } } (*Text_Source(w)->ReadSource) (Text_Source(w), line->start, end, &block); if (block.length > 0) { int x, y; char *ptr; int len; ptr = block.ptr + start - line->start; len = end - start; if (start > line->start) { x = _XmTextNextX(w, 0, block.ptr, start - line->start); } else { x = 0; } y = Out_YDraw(o) + num * Out_FontHeight(o); DrawText(w, x, y, ptr, len, highlight); } XtFree(block.ptr); } static void OutputInvalidate(XmTextWidget w, XmTextPosition start, XmTextPosition end, long delta) { OutputData o = Text_OutputData(w); Out_CursorSaveValid(o) = False; } static void GetPreferredSize(Widget aw, Dimension *width, Dimension *height) { XmTextWidget w = (XmTextWidget)aw; OutputData o = Text_OutputData(w); *height = Out_TopMargin(o) + Out_BottomMargin(o) + Out_Rows(o) * Out_FontHeight(o); #ifdef USE_XFT if (Out_XftFont(o)) { *width = Out_LeftMargin(o) + Out_RightMargin(o) + Out_Columns(o) * Out_FontAverageWidth(o); DEBUGOUT(_LtDebug(__FILE__, aw, "GetPreferredSize (fw %d )-> wid %d ht %d\n", Out_FontAverageWidth(o), *width, *height)); } else #endif { #ifdef USE_AVERAGE_WIDTH *width = Out_LeftMargin(o) + Out_RightMargin(o) + Out_Columns(o) * Out_FontAverageWidth(o) ; DEBUGOUT(_LtDebug(__FILE__, aw, "GetPreferredSize (fw %d )-> wid %d ht %d\n", Out_FontAverageWidth(o), *width, *height)); #else *width = Out_LeftMargin(o) + Out_RightMargin(o) + Out_Columns(o) * Out_FontMaxWidth(o) ; DEBUGOUT(_LtDebug(__FILE__, aw, "GetPreferredSize (fw %d )-> wid %d ht %d\n", Out_FontMaxWidth(o), *width, *height)); #endif } } static void OutputGetValues(Widget w, ArgList args, Cardinal num_args) { XmTextInnerWidget iw = Text_InnerWidget(w); #if VERBOSE /* Just print a list of resources requested */ DEBUGOUT(_LtDebug(__FILE__, w, "OutputGetValues")); if (_LtDebugInDebug(__FILE__, w) && num_args != 0) { int i; DEBUGOUT(_LtDebug0(__FILE__, w, "(")); for (i = 0; i < num_args - 1; i++) { DEBUGOUT(_LtDebug0(__FILE__, w, "%s, ", args[i].name)); } DEBUGOUT(_LtDebug0(__FILE__, w, "%s)", args[num_args - 1].name)); } DEBUGOUT(_LtDebug0(__FILE__, w, "\n")); #endif XtGetSubvalues(iw, output_resources, XtNumber(output_resources), args, num_args); if (_LtDebugInDebug(__FILE__, w)) { DEBUGOUT(_LtDebug(__FILE__, w, "OutputGetValues :\n")); _LtDebugPrintArgList(__FILE__, w, args, num_args, True); } } /* * Oh boy. We're getting called directly, not through Xt. Therefore, we * have different old, new widgets (XmText), but they all point to the * same OutputData. * * So, enter the hack of the month : we'll have to take care of this. :-( * The trouble is all the stuff that's underneath... we'll see how far this * leads us. We may have to find another way to solve this. * * Note we're replacing the *old* variables by temp variables; so the functions * we call from here all get the real stuff and change things in the right * places. * * 19/5/97 : already on two levels (OutputRec and OutputDataRec). */ static Boolean OutputSetValues(Widget old, Widget request, Widget new_w, ArgList args, Cardinal *num_args) { OutputRec oldOutput; OutputDataRec oldData; OutputData nd = Text_OutputData(new_w), od = &oldData; XmTextInnerWidget iw = Text_InnerWidget(new_w); Boolean redraw = False; DEBUGOUT(_LtDebug(__FILE__, new_w, "OutputSetValues: %i args\n" "\t old X %5i Y %5i W %5i H %5i\n" "\trequest X %5i Y %5i W %5i H %5i\n" "\t new X %5i Y %5i W %5i H %5i\n", *num_args, XtX(old), XtY(old), XtWidth(old), XtHeight(old), XtX(request), XtY(request), XtWidth(request), XtHeight(request), XtX(new_w), XtY(new_w), XtWidth(new_w), XtHeight(new_w))); DEBUGOUT(_LtDebugPrintArgList(__FILE__, new_w, args, *num_args, False)); /* Insert new variables */ oldOutput = *Text_Output(old); /* Copy old values */ Text_Output(old) = &oldOutput; *od = *nd; /* Copy old values */ Text_OutputData(old) = od; /* Ready */ /* Copy whatever we get passed into our data structures */ XtSetSubvalues(iw, output_resources, XtNumber(output_resources), args, *num_args); Out_RightMargin(nd) = Out_LeftMargin(nd) = Prim_ShadowThickness(new_w) + Prim_HighlightThickness(new_w) + Text_MarginWidth(new_w) ; Out_TopMargin(nd) = Out_BottomMargin(nd) = Prim_ShadowThickness(new_w) + Prim_HighlightThickness(new_w) + Text_MarginHeight(new_w) ; if (Out_RightMargin(od) != Out_RightMargin(nd) || Out_LeftMargin(nd) != Out_LeftMargin(od) || Out_TopMargin(nd) != Out_TopMargin(od) || Out_BottomMargin(nd) != Out_BottomMargin(od)) { (*Text_Output(old)->resize) (new_w, True); redraw = True; } /* Check if we need to act */ if (Out_FontList(od) != Out_FontList(nd)) { DEBUGOUT(_LtDebug(__FILE__, new_w, "OutputSetValues: FontList change.\n")); /* T. Straumann: make a copy of the font list and free the old one */ Out_FontList(nd) = XmFontListCopy(Out_FontList(nd)); /* rws 17 Jul 1999 But only free it if we created it.... xmgrace Data->Results */ if (Out_FontListCreated(od) && Out_FontList(od)) { XmFontListFree(Out_FontList(od)); } FontInit((XmTextWidget)new_w); /* From OutputCreate : */ XtHeight(new_w) = Out_FontHeight(nd) + 2 * (Prim_ShadowThickness(new_w) + Text_MarginHeight(new_w)); #ifdef USE_AVERAGE_WIDTH XtWidth(new_w) = Out_Columns(nd) * Out_FontAverageWidth(nd) + Out_LeftMargin(nd) + Out_RightMargin(nd) ; #else XtWidth(new_w) = Out_Columns(nd) * Out_FontMaxWidth(nd) + Out_LeftMargin(nd) + Out_RightMargin(nd) ; #endif if (Out_DrawGC(nd)) { /* * We need to change the font id in the DrawGC, * not the other GC's. * * Note we can only do this because the mask used when * we got this GC specifies that we can change the font. */ XGCValues values; if (Out_FontType(nd) == XmFONT_IS_FONT) { values.font = Out_Font(nd)->fid; XChangeGC(XtDisplay(new_w), Out_DrawGC(nd), GCFont, &values); } else #ifdef USE_XFT if (Out_FontType(nd) == XmFONT_IS_XFT) { /* Probably nothing to do here */ } #endif { /* * Need braces here to provide an 'else' statement * in case that USE_XFT is not defined. */ /* We may still need to do things here. * CP Hennessy suggest calling GCClip((XmTextWidget)new_w); */ } } redraw = True; } if (Out_WordWrap(od) != Out_WordWrap(nd)) { DEBUGOUT(_LtDebug(__FILE__, new_w, "OutputSetValues: WordWrap change.\n")); /*CP:15 May 1999:rebuild the line table */ _XmTextUpdateLineTable(new_w, 0, 0, NULL, False); redraw = True; } if (Out_CursorPositionVisible(od) != Out_CursorPositionVisible(nd)) { DEBUGOUT(_LtDebug(__FILE__, new_w, "OutputSetValues: CursorPosVis change.\n")); /* FIX ME ?? */ DrawInsertionPoint((XmTextWidget)new_w, Text_CursorPos(new_w), off); redraw = True; } if (Out_Rows(od) != Out_Rows(nd)) { DEBUGOUT(_LtDebug(__FILE__, new_w, "OutputSetValues: Rows change.\n")); /* FIX ME ? */ XtHeight(new_w) = Out_Rows(nd) * Out_FontHeight(nd) + Out_TopMargin(nd) + Out_BottomMargin(nd) ; redraw = True; } if (Out_Columns(od) != Out_Columns(nd)) { DEBUGOUT(_LtDebug(__FILE__, new_w, "OutputSetValues: Columns change.\n")); /* FIX ME ? */ #ifdef USE_XFT if (Out_XftFont(nd)) { XtWidth(new_w) = Out_Columns(nd) * Out_XftFont(nd)->max_advance_width + Out_LeftMargin(nd) + Out_RightMargin(nd); XtWidth(new_w) = Out_Columns(nd) * Out_FontAverageWidth(nd) + Out_LeftMargin(nd) + Out_RightMargin(nd); /* FIX ME HACK */ } else #endif { #ifdef USE_AVERAGE_WIDTH XtWidth(new_w) = Out_Columns(nd) * Out_FontAverageWidth(nd) + Out_LeftMargin(nd) + Out_RightMargin(nd); #else XtWidth(new_w) = Out_Columns(nd) * Out_FontMaxWidth(nd) + Out_LeftMargin(nd) + Out_RightMargin(nd); #endif } redraw = True; } if ( XtBackground(old) != XtBackground(new_w) ) { if (Out_DrawGC(nd)) { XGCValues values; values.background = XtBackground(new_w); XChangeGC(XtDisplay(new_w), Out_DrawGC(nd), GCBackground, &values ); } } if ( Prim_Foreground(old) != Prim_Foreground(new_w) ) { if (Out_DrawGC(nd)) { XGCValues values; values.foreground = Prim_Foreground(new_w); XChangeGC(XtDisplay(new_w), Out_DrawGC(nd), GCForeground, &values ); } } if (Out_BlinkRate(od) != Out_BlinkRate(nd)) { /* FIX ME */ } if (Out_ResizeHeight(od) != Out_ResizeHeight(nd)) { /* FIX ME */ } if (Out_ResizeWidth(od) != Out_ResizeWidth(nd)) { /* FIX ME */ } if (Out_ScrollHorizontal(od) != Out_ScrollHorizontal(nd)) { /* FIX ME */ } if (Out_ScrollVertical(od) != Out_ScrollVertical(nd)) { /* FIX ME */ } if (Out_ScrollLeftSide(od) != Out_ScrollLeftSide(nd)) { /* FIX ME */ } if (Out_ScrollTopSide(od) != Out_ScrollTopSide(nd)) { /* FIX ME */ } /* Done, restore old stuff */ Text_Output(old) = Text_Output(new_w); Text_OutputData(old) = nd; return redraw; } static void destroy(Widget aw) { XmTextWidget w = (XmTextWidget)aw; OutputData o = Text_OutputData(w); DEBUGOUT(_LtDebug(__FILE__, aw, "destroy\n")); if (o && Out_TimerId(o)) { XtRemoveTimeOut(Out_TimerId(o)); Out_TimerId(o) = 0; } if (o && Out_DrawGC(o)) { #ifdef USE_XT_GC XtReleaseGC(aw, Out_DrawGC(o)); #else XFreeGC(XtDisplay(w), Out_DrawGC(o)); #endif } if (o && Out_CursorGC(o)) { #ifdef USE_XT_GC XtReleaseGC(aw, Out_CursorGC(o)); #else XFreeGC(XtDisplay(w), Out_CursorGC(o)); #endif } if (o && Out_CopyGC(o)) { XtReleaseGC((Widget)w, Out_CopyGC(o)); } if (Out_CursorIBeam(o)) { XFreePixmap(XtDisplay((Widget)w), Out_CursorIBeam(o)); } if (Out_CursorStipple(o)) { XFreePixmap(XtDisplay((Widget)w), Out_CursorStipple(o)); } if (Out_CursorSave(o)) { XFreePixmap(XtDisplay((Widget)w), Out_CursorSave(o)); } if (Out_FontListCreated(o) && Out_FontList(o)) { XmFontListFree(Out_FontList(o)); } #ifdef USE_XFT /* FIX ME */ #endif XtFree((char *)Text_Output(w)); } static void OutputExpose(Widget aw, XEvent *event, Region region) { XmTextWidget w = (XmTextWidget)aw; DEBUGOUT(_LtDebug(__FILE__, aw, "OutputExpose: cursor pos: %d\n", Text_CursorPos(w))); if (!XtIsRealized(aw)) { return; } /* XClearArea(XtDisplay(w), XtWindow(w), Prim_HighlightThickness(w) + Prim_ShadowThickness(w), Prim_HighlightThickness(w) + Prim_ShadowThickness(w), XtWidth(w) - 2 * (Prim_HighlightThickness(w) + Prim_ShadowThickness(w)), XtHeight(w) - 2 * (Prim_HighlightThickness(w) + Prim_ShadowThickness(w)), False); */ DrawAll(w); if (Prim_Highlighted(aw)) { (*PrimC_BorderHighlight(XtClass(aw))) (aw); } else { (*PrimC_BorderUnhighlight(XtClass(aw))) (aw); } _XmDrawShadows(XtDisplay(w), XtWindow(w), Prim_TopShadowGC(w), Prim_BottomShadowGC(w), Prim_HighlightThickness(w), Prim_HighlightThickness(w), XtWidth(w) - 2 * Prim_HighlightThickness(w), XtHeight(w) - 2 * Prim_HighlightThickness(w), Prim_ShadowThickness(w), XmSHADOW_IN); (*Text_Output(w)->DrawInsertionPoint) (w, Text_CursorPos(w), on); } static void OutputRealize(Widget aw, XtValueMask *value_mask, XSetWindowAttributes *attributes) { XmTextWidget w = (XmTextWidget)aw; DEBUGOUT(_LtDebug(__FILE__, aw, "OutputRealize (fl %p)\n", Out_FontList(Text_OutputData(aw)))); GCInitialize(w); GCClip(w); CursorSet(w, False); #if 0 CursorSaveUnderIBeam(w, 0, 0); #endif } static void resize(Widget aw, Boolean state) { XmTextWidget w = (XmTextWidget)aw; OutputData o = Text_OutputData(w); SizeRecalc(w); /* SG (15/08/1998) Update scrollbars immediately on resize * to give the correct visual feedback to the user and keep * scroll bars in sync with any keyboard actions after this resize */ _XmChangeVSB(w, Text_TopPos(w)); _XmRedisplayHBar(w, Out_XOffset(o)); /* Only adjust the GCs if they have already been created! */ if (Out_DrawGC(o)) { GCClip(w); } } static OutputRec outputRec = { /* _OutputDataRec */ NULL, /* XYToPosProc */ XYToPos, /* PosToXYProc */ PosToXY, /* MeasureLineProc */ MeasureLine, /* DrawProc */ Draw, /* DrawInsertionPointProc */ DrawInsertionPoint, /* MakePositionVisibleProc */ MakePositionVisible, /* MoveLinesProc */ MoveLines, /* InvalidateProc */ OutputInvalidate, /* GetPreferredSizeProc */ GetPreferredSize, /* GetValuesProc */ OutputGetValues, /* SetValuesProc */ OutputSetValues, /* XmRealizeOutProc */ OutputRealize, /* XtWidgetProc */ destroy, /* XmResizeFlagProc */ resize, /* XtExposeProc */ OutputExpose }; extern void _XmTextOutputCreate(Widget aw, ArgList args, Cardinal num_args) { XmTextWidget w = (XmTextWidget)aw; OutputData o; XmTextInnerWidget iw = (XmTextInnerWidget)w->text.inner_widget; Dimension width, height; DEBUGOUT(_LtDebug(__FILE__, aw, "_XmTextOutputCreate(")); DEBUGOUT(_LtDebugPrintArgList(__FILE__, aw, args, num_args, False)); DEBUGOUT(_LtDebug0(__FILE__, aw, ")\n")); Text_Output(w) = (Output)XtMalloc(sizeof(OutputRec)); memcpy(Text_Output(w), &outputRec, sizeof(OutputRec)); Text_OutputData(w) = o = &iw->inner.out; XtGetSubresources(aw, iw, aw->core.name, aw->core.widget_class->core_class.class_name, output_resources, XtNumber(output_resources), args, num_args); Out_XOffset(o) = 0; /*CP: debugging */ XtAddEventHandler(aw, FocusChangeMask, False, HandleFocusEvents, NULL); CursorInit(w); /* Use DrawGC as a flag to see if the GCs have been created */ Out_DrawGC(o) = NULL; Out_RightMargin(o) = Out_LeftMargin(o) = Prim_ShadowThickness(w) + Prim_HighlightThickness(w) + Text_MarginWidth(w) ; Out_TopMargin(o) = Out_BottomMargin(o) = Prim_ShadowThickness(w) + Prim_HighlightThickness(w) + Text_MarginHeight(w) ; Out_CursorWidth(o) = 5; /*CP: M*tif seems to use 5, but why ?? */ /* Get the font information */ if ( !Out_FontList(o) || (Out_FontList(o) == (XmFontList)XmUNSPECIFIED) ) { Out_FontList(o) = _XmGetDefaultFontList((Widget)w, XmTEXT_FONTLIST); /* T. Straumann: changed this to 'true'; XmGetDefaultFontList() seems * to make a copy. */ Out_FontListCreated(o) = True; } else { /* Out_FontListCreated(o) = True; */ Out_FontListCreated(o) = False; /* we created this, so free it when the time comes */ /* rws 12 Apr 1999 If we created this, where???? A True value here is causing ml to segfault in FontListFree whenever the message window is destroyed. */ } FontInit(w); DEBUGOUT(_LtDebug(__FILE__, aw, "OutputCreate (initially) : rows %d cols %d\n", Out_Rows(o), Out_Columns(o))); /* Check window dimensions */ if (XtWidth(w) == (Dimension)0) { if (Out_Columns(o) <= 0) { Out_Columns(o) = 20; } } else { /* Reverse of this thing also copied into OutputSetValues */ #ifdef USE_XFT if (Out_XftFont(o)) { Out_Columns(o) = (XtWidth(w) - (Out_LeftMargin(o) + Out_RightMargin(o))) / Out_XftFont(o)->max_advance_width; Out_Columns(o) = (XtWidth(w) - (Out_LeftMargin(o) + Out_RightMargin(o))) / Out_FontAverageWidth(o); /* FIX ME HACK */ } else #endif { #ifdef USE_AVERAGE_WIDTH Out_Columns(o) = (XtWidth(w) - ( Out_LeftMargin(o) + Out_RightMargin(o) ) ) / Out_FontAverageWidth(o); #else Out_Columns(o) = (XtWidth(w) - ( Out_LeftMargin(o) + Out_RightMargin(o) ) ) / Out_FontMaxWidth(o); #endif } } if (XtHeight(w) == (Dimension)0) { if (Out_Rows(o) <= 0) { Out_Rows(o) = 10; } } else { Out_Rows(o) = (XtHeight(w) - ( Out_TopMargin(o) + Out_BottomMargin(o) ) ) / Out_FontHeight(o); } if (Text_EditMode(w) == XmSINGLE_LINE_EDIT) { Out_Rows(o) = 1; if (XtHeight(w) != 0 && (XtHeight(w) < Out_FontHeight(o) + Out_TopMargin(o) + Out_BottomMargin(o) ) ) { /* Statement below also copied into OutputSetValues */ XtHeight(w) = Out_FontHeight(o) + Out_TopMargin(o) + Out_BottomMargin(o); } } DEBUGOUT(_LtDebug(__FILE__, aw, "OutputCreate: rows %d cols %d\n", Out_Rows(o), Out_Columns(o))); Out_ColumnsSet(o) = Out_Columns(o); Out_RowsSet(o) = Out_Rows(o); if (XtWidth(w) == 0 || XtHeight(w) == 0) { (*Text_Output(w)->GetPreferredSize) (aw, &width, &height); XtWidth(w) = width; XtHeight(w) = height; } SizeRecalc(w); /* Create scrollbars if child of scrolledwindow */ if (XmIsScrolledWindow(XtParent(w))) { Widget sw = XtParent(w); Boolean scrollingPolicy; XtVaGetValues(sw, XmNscrollingPolicy, &scrollingPolicy, NULL); if (scrollingPolicy == XmAUTOMATIC) { Out_ScrollVertical(o) = False; Out_ScrollHorizontal(o) = False; } if (Out_ScrollHorizontal(o)) { if (SW_HSB(sw) != NULL) { Out_Hbar(o) = (Widget)SW_HSB(sw); } else { Out_Hbar(o) = XtVaCreateWidget("HorScrollBar", xmScrollBarWidgetClass, sw, XmNorientation, XmHORIZONTAL, NULL); } XtAddCallback((Widget)Out_Hbar(o), XmNdecrementCallback, HandleHBar, (XtPointer)w); XtAddCallback((Widget)Out_Hbar(o), XmNdragCallback, HandleHBar, (XtPointer)w); XtAddCallback((Widget)Out_Hbar(o), XmNincrementCallback, HandleHBar, (XtPointer)w); XtAddCallback((Widget)Out_Hbar(o), XmNpageDecrementCallback, HandleHBar, (XtPointer)w); XtAddCallback((Widget)Out_Hbar(o), XmNpageIncrementCallback, HandleHBar, (XtPointer)w); XtAddCallback((Widget)Out_Hbar(o), XmNtoBottomCallback, HandleHBar, (XtPointer)w); XtAddCallback((Widget)Out_Hbar(o), XmNtoTopCallback, HandleHBar, (XtPointer)w); XtAddCallback((Widget)Out_Hbar(o), XmNvalueChangedCallback, HandleHBar, (XtPointer)w); XtManageChild(Out_Hbar(o)); /*CP:Friday 14 May 1999: Set HBar resources to initially sane values */ XtVaSetValues(Out_Hbar(o), XmNincrement, 1, XmNpageIncrement, 1, XmNsliderSize, 1, XmNmaximum, 1, XmNminimum, 0, NULL); } else { Out_Hbar(o) = NULL; } if (Out_ScrollVertical(o) && Text_EditMode(w) != XmSINGLE_LINE_EDIT) { if (SW_VSB(sw) != NULL) { Out_Vbar(o) = (Widget)SW_VSB(sw); } else { Out_Vbar(o) = XtVaCreateWidget("VertScrollBar", xmScrollBarWidgetClass, sw, NULL); } XtAddCallback((Widget)Out_Vbar(o), XmNdecrementCallback, HandleVBar, (XtPointer)w); XtAddCallback((Widget)Out_Vbar(o), XmNdragCallback, HandleVBar, (XtPointer)w); XtAddCallback((Widget)Out_Vbar(o), XmNincrementCallback, HandleVBar, (XtPointer)w); XtAddCallback((Widget)Out_Vbar(o), XmNpageDecrementCallback, HandleVBar, (XtPointer)w); XtAddCallback((Widget)Out_Vbar(o), XmNpageIncrementCallback, HandleVBar, (XtPointer)w); XtAddCallback((Widget)Out_Vbar(o), XmNtoBottomCallback, HandleVBar, (XtPointer)w); XtAddCallback((Widget)Out_Vbar(o), XmNtoTopCallback, HandleVBar, (XtPointer)w); XtAddCallback((Widget)Out_Vbar(o), XmNvalueChangedCallback, HandleVBar, (XtPointer)w); XtManageChild(Out_Vbar(o)); /* Set VSB resources to initially sane values */ XtVaSetValues(Out_Vbar(o), XmNincrement, 1, XmNpageIncrement, Out_Rows(o), XmNsliderSize, Out_Rows(o), XmNmaximum, Out_Rows(o), /*CP:Friday 14 May 1999 a reasonable initial value */ NULL); } else { Out_Vbar(o) = NULL; } XmScrolledWindowSetAreas(sw, Out_Hbar(o), Out_Vbar(o), aw); if (Out_ScrollLeftSide(o) && Out_ScrollTopSide(o)) { XtVaSetValues(sw, XmNscrollBarPlacement, XmTOP_LEFT, NULL); } else if (!Out_ScrollLeftSide(o) && Out_ScrollTopSide(o)) { XtVaSetValues(sw, XmNscrollBarPlacement, XmTOP_RIGHT, NULL); } else if (Out_ScrollLeftSide(o) && !Out_ScrollTopSide(o)) { XtVaSetValues(sw, XmNscrollBarPlacement, XmBOTTOM_LEFT, NULL); } else if (!Out_ScrollLeftSide(o) && !Out_ScrollTopSide(o)) { XtVaSetValues(sw, XmNscrollBarPlacement, XmBOTTOM_RIGHT, NULL); } } } /* * Quasi-Public functions ----------------------------------------------------- */ extern void _XmTextDrawDestination(XmTextWidget widget) { } extern void _XmTextClearDestination(XmTextWidget widget, Boolean ignore_sens) { } extern void _XmTextDestinationVisible(Widget w, Boolean turn_on) { } extern void _XmTextChangeBlinkBehavior(XmTextWidget widget, Boolean newvalue) { } extern void _XmTextAdjustGC(XmTextWidget w) { } extern Boolean _XmTextShouldWordWrap(XmTextWidget w) { OutputData o = Text_OutputData(w); if (! Out_WordWrap(o) ) { return False; } if (Text_EditMode(w) == XmSINGLE_LINE_EDIT) { return False; } if ( Out_ScrollHorizontal(o) && XtClass(XtParent(w)) == xmScrolledWindowWidgetClass) { return False; } if ( Out_ResizeWidth(o) ) { return False; } return True; } extern Boolean _XmTextScrollable(XmTextWidget w) { OutputData o = Text_OutputData(w); return o->scrollvertical; } extern void _XmTextOutputGetSecResData(XmSecondaryResourceData *secResDataRtn) { } extern int _XmTextGetNumberLines(XmTextWidget w) { return w->text.total_lines - 1; } extern Boolean _XmTextGetDisplayRect(Widget w, XRectangle *display_rect) { return False; } extern void _XmTextMarginsProc(Widget w, XmBaselineMargins *margins_rec) { } extern void _XmTextChangeHOffset(XmTextWidget widget, int length) { } extern void _XmTextToggleCursorGC(Widget widget) { } extern void _XmTextFreeContextData(Widget w, XtPointer clientData, XtPointer callData) { } extern void _XmTextResetClipOrigin(XmTextWidget tw, XmTextPosition position, Boolean clip_mask_reset) { } /* * Return the position of the end of this line, to implement wrapping. * FIX ME (currently quite simplistic) * FIX ME (should "extra" be filled up ?) */ XmTextPosition _XmTextFindLineEnd(XmTextWidget w, XmTextPosition pos, LineTableExtra *extra) { Dimension avail, width, oldwidth; XmTextPosition wordend, last, end; OutputData o = Text_OutputData(w); avail = XtWidth(w) - (Out_RightMargin(o) + Out_LeftMargin(o)); /* What's our line ? */ end = (*Text_Source(w)->Scan) (Text_Source(w), pos, XmSELECT_LINE, XmsdRight, 1, False); /* Do we need to spend time on this; the line may be short enough */ width = FontTextWidth(w, pos, end); if (width < avail) { DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "_XmTextFindLineEnd(%d) => %d [avail %d width %d]\n", pos, end, avail, width)); return end; } /* Unfortunately, we need to investigate */ wordend = pos; do { last = wordend; wordend = (*Text_Source(w)->Scan) (Text_Source(w), last + 1, XmSELECT_WORD, XmsdRight, 1, False); oldwidth = width; width = FontTextWidth(w, pos, wordend); } while (width <= avail && wordend < end); if (last == pos){ int i; /* In this case, we need to clip at non_word_boundary. */ width = 0; for(i=pos+1; i= avail){ last = i - 1; break; } last = i; } } width = oldwidth; if (extra) { LineTableExtra e = (LineTableExtra)XtMalloc(sizeof(LineTableExtraRec)); e->width = width; e->wrappedbychar = False; *extra = e; } /* Take the previous position */ if (last < end) { DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "_XmTextFindLineEnd(%d) => %d [avail %d width %d]\n", pos, last, avail, width)); return last; } else { DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "_XmTextFindLineEnd(%d) => %d [avail %d width %d]\n", pos, PASTENDPOS, avail, width)); return PASTENDPOS; } } extern void _XmTextMovingCursorPosition(XmTextWidget tw, XmTextPosition position) { XmTextShowPosition((Widget)tw, position); } extern Boolean _XmTextGetBaselines(Widget widget, Dimension **baselines, int *line_count) { return False; } /* XTextWidth clone for TextFieldWidget. */ extern int _XmOut_FontTextWidth(OutputData o, char *s, int l) { if (Out_FontList(o)->renditions[0]->type == XmFONT_IS_FONT) { return XTextWidth(Out_Font(o), s, l); #ifdef USE_XFT } else if (Out_XftFont(o)) { XGlyphInfo ext; XftTextExtents8(Out_FontList(o)->renditions[0]->dpy, Out_XftFont(o), (unsigned char*)s, l, &ext); return ext.width; #endif } else { return XmbTextEscapement((XFontSet)Out_FontList(o)->renditions[0]->font, s, l); } } /* Calculate FontMaxWidth from fontList */ extern int _XmOut_FontMaxWidth(OutputData o) { if (Out_FontList(o)->renditions[0]->type == XmFONT_IS_FONT) { return Out_Font(o)->max_bounds.width; } else #ifdef USE_XFT if (Out_FontList(o)->renditions[0]->type == XmFONT_IS_XFT) { return Out_FontAverageWidth(o); /* FIX ME HACK */ return Out_XftFont(o)->max_advance_width; } else #endif { XFontStruct **fsl; char **nl; int i, num, max; num = XFontsOfFontSet((XFontSet)Out_FontList(o)->renditions[0]->font, &fsl, &nl); max = 0; for(i=0; imax_bounds.width > max) max = fsl[i]->max_bounds.width; } return max; } } static void _XmTextOutSetRenderTable(Widget w, int ofs, XrmValue *v) { OutputData o = Text_OutputData(w); DEBUGOUT(_LtDebug(__FILE__, w, "_XmTextOutSetRenderTable (%d)\n", o->check_set_render_table)); if (o->check_set_render_table) { /* * This is the second time we're getting called. * Therefore the result is undefined. */ v->addr = NULL; /* FIX ME or should we pass nothing ? */ } else { v->addr = (char *)&(o->fontlist); o->check_set_render_table = True; DEBUGOUT(_LtDebug(__FILE__, w, "_XmTextOutSetRenderTable rt %p\n", o->fontlist)); } }