summaryrefslogtreecommitdiffstats
path: root/tkhtml1/src/htmlwidget.c
diff options
context:
space:
mode:
Diffstat (limited to 'tkhtml1/src/htmlwidget.c')
-rw-r--r--tkhtml1/src/htmlwidget.c2043
1 files changed, 0 insertions, 2043 deletions
diff --git a/tkhtml1/src/htmlwidget.c b/tkhtml1/src/htmlwidget.c
deleted file mode 100644
index 3d6e632..0000000
--- a/tkhtml1/src/htmlwidget.c
+++ /dev/null
@@ -1,2043 +0,0 @@
-/*
-** The main routine for the HTML widget for Tcl/Tk
-**
-** Copyright (C) 1997-2000 D. Richard Hipp
-**
-** 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., 59 Temple Place - Suite 330,
-** Boston, MA 02111-1307, USA.
-**
-** Author contact information:
-** drh@acm.org
-** http://www.hwaci.com/drh/
-*/
-#include <tk.h>
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-#include "htmlwidget.h"
-/*
-#ifdef USE_TK_STUBS
-# include <tkIntXlibDecls.h>
-#endif
-*/
-/*
-** This global variable is used for tracing the operation of
-** the Html formatter.
-*/
-int HtmlTraceMask = 0;
-
-#ifdef __WIN32__
-# define DEF_FRAME_BG_COLOR "SystemButtonFace"
-# define DEF_FRAME_BG_MONO "White"
-# define DEF_FRAME_CURSOR ""
-# define DEF_BUTTON_FG "SystemButtonText"
-# define DEF_BUTTON_HIGHLIGHT_BG "SystemButtonFace"
-# define DEF_BUTTON_HIGHLIGHT "SystemWindowFrame"
-#else
-# define DEF_FRAME_BG_COLOR "#d9d9d9"
-# define DEF_FRAME_BG_MONO "White"
-# define DEF_FRAME_CURSOR ""
-# define DEF_BUTTON_FG "Black"
-# define DEF_BUTTON_HIGHLIGHT_BG "#d9d9d9"
-# define DEF_BUTTON_HIGHLIGHT "Black"
-#endif
-
-/*
-** Information used for argv parsing.
-*/
-static Tk_ConfigSpec configSpecs[] = {
- {TK_CONFIG_STRING, "-appletcommand", "appletCommand", "HtmlCallback",
- DEF_HTML_CALLBACK, Tk_Offset(HtmlWidget, zAppletCommand), 0},
- {TK_CONFIG_BORDER, "-background", "background", "Background",
- DEF_HTML_BG_COLOR, Tk_Offset(HtmlWidget, border),
- TK_CONFIG_COLOR_ONLY},
- {TK_CONFIG_BORDER, "-background", "background", "Background",
- DEF_HTML_BG_MONO, Tk_Offset(HtmlWidget, border),
- TK_CONFIG_MONO_ONLY},
- {TK_CONFIG_STRING, "-base", "base", "Base",
- "", Tk_Offset(HtmlWidget, zBase), 0},
- {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL,
- (char *) NULL, 0, 0},
- {TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL,
- (char *) NULL, 0, 0},
- {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth",
- DEF_HTML_BORDER_WIDTH, Tk_Offset(HtmlWidget, borderWidth), 0},
- {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor",
- DEF_HTML_CURSOR, Tk_Offset(HtmlWidget, cursor), TK_CONFIG_NULL_OK},
- {TK_CONFIG_BOOLEAN, "-exportselection", "exportSelection","ExportSelection",
- DEF_HTML_EXPORT_SEL, Tk_Offset(HtmlWidget, exportSelection), 0},
- {TK_CONFIG_SYNONYM, "-fg", "foreground", (char *) NULL,
- (char *) NULL, 0, 0},
- {TK_CONFIG_STRING, "-fontcommand", "fontCommand", "FontCommand",
- DEF_HTML_CALLBACK, Tk_Offset(HtmlWidget, zFontCommand), 0},
- {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground",
- DEF_HTML_FG, Tk_Offset(HtmlWidget, fgColor), 0},
- {TK_CONFIG_STRING, "-formcommand", "formlCommand", "HtmlCallback",
- DEF_HTML_CALLBACK, Tk_Offset(HtmlWidget, zFormCommand), 0},
- {TK_CONFIG_STRING, "-framecommand", "frameCommand", "HtmlCallback",
- DEF_HTML_CALLBACK, Tk_Offset(HtmlWidget, zFrameCommand), 0},
- {TK_CONFIG_PIXELS, "-height", "height", "Height",
- DEF_HTML_HEIGHT, Tk_Offset(HtmlWidget, height), 0},
- {TK_CONFIG_COLOR, "-highlightbackground", "highlightBackground",
- "HighlightBackground", DEF_HTML_HIGHLIGHT_BG,
- Tk_Offset(HtmlWidget, highlightBgColorPtr), 0},
- {TK_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor",
- DEF_HTML_HIGHLIGHT, Tk_Offset(HtmlWidget, highlightColorPtr), 0},
- {TK_CONFIG_PIXELS, "-highlightthickness", "highlightThickness",
- "HighlightThickness",
- DEF_HTML_HIGHLIGHT_WIDTH, Tk_Offset(HtmlWidget, highlightWidth), 0},
- {TK_CONFIG_STRING, "-hyperlinkcommand", "hyperlinkCommand", "HtmlCallback",
- DEF_HTML_CALLBACK, Tk_Offset(HtmlWidget, zHyperlinkCommand), 0},
- {TK_CONFIG_STRING, "-imagecommand", "imageCommand", "HtmlCallback",
- DEF_HTML_CALLBACK, Tk_Offset(HtmlWidget, zGetImage), 0},
- {TK_CONFIG_INT, "-insertofftime", "insertOffTime", "OffTime",
- DEF_HTML_INSERT_OFF_TIME, Tk_Offset(HtmlWidget, insOffTime), 0},
- {TK_CONFIG_INT, "-insertontime", "insertOnTime", "OnTime",
- DEF_HTML_INSERT_ON_TIME, Tk_Offset(HtmlWidget, insOnTime), 0},
- {TK_CONFIG_STRING, "-isvisitedcommand", "isVisitedCommand", "HtmlCallback",
- DEF_HTML_CALLBACK, Tk_Offset(HtmlWidget, zIsVisited), 0},
- {TK_CONFIG_PIXELS, "-padx", "padX", "Pad",
- DEF_HTML_PADX, Tk_Offset(HtmlWidget, padx), 0},
- {TK_CONFIG_PIXELS, "-pady", "padY", "Pad",
- DEF_HTML_PADY, Tk_Offset(HtmlWidget, pady), 0},
- {TK_CONFIG_RELIEF, "-relief", "relief", "Relief",
- DEF_HTML_RELIEF, Tk_Offset(HtmlWidget, relief), 0},
- {TK_CONFIG_STRING, "-resolvercommand", "resolverCommand", "HtmlCallback",
- DEF_HTML_CALLBACK, Tk_Offset(HtmlWidget, zResolverCommand), 0},
- {TK_CONFIG_RELIEF, "-rulerelief", "ruleRelief","RuleRelief",
- "sunken", Tk_Offset(HtmlWidget, ruleRelief), 0},
- {TK_CONFIG_STRING, "-scriptcommand", "scriptCommand", "HtmlCallback",
- "", Tk_Offset(HtmlWidget, zScriptCommand), 0},
- {TK_CONFIG_COLOR, "-selectioncolor", "background", "Background",
- DEF_HTML_SELECTION_COLOR, Tk_Offset(HtmlWidget, selectionColor), 0},
- {TK_CONFIG_RELIEF, "-tablerelief", "tableRelief","TableRelief",
- "raised", Tk_Offset(HtmlWidget, tableRelief), 0},
- {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus",
- DEF_HTML_TAKE_FOCUS, Tk_Offset(HtmlWidget, takeFocus),
- TK_CONFIG_NULL_OK},
- {TK_CONFIG_COLOR, "-unvisitedcolor", "foreground", "Foreground",
- DEF_HTML_UNVISITED, Tk_Offset(HtmlWidget, newLinkColor), 0},
- {TK_CONFIG_BOOLEAN, "-underlinehyperlinks", "underlineHyperlinks",
- "UnderlineHyperlinks", "1", Tk_Offset(HtmlWidget, underlineLinks), 0},
- {TK_CONFIG_COLOR, "-visitedcolor", "foreground", "Foreground",
- DEF_HTML_VISITED, Tk_Offset(HtmlWidget, oldLinkColor), 0},
- {TK_CONFIG_PIXELS, "-width", "width", "Width",
- DEF_HTML_WIDTH, Tk_Offset(HtmlWidget, width), 0},
- {TK_CONFIG_STRING, "-xscrollcommand", "xScrollCommand", "ScrollCommand",
- DEF_HTML_SCROLL_COMMAND, Tk_Offset(HtmlWidget, xScrollCmd),
- TK_CONFIG_NULL_OK},
- {TK_CONFIG_STRING, "-yscrollcommand", "yScrollCommand", "ScrollCommand",
- DEF_HTML_SCROLL_COMMAND, Tk_Offset(HtmlWidget, yScrollCmd),
- TK_CONFIG_NULL_OK},
- {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
- (char *) NULL, 0, 0}
-};
-
-/*
-** Get a copy of the config specs.
-*/
-Tk_ConfigSpec *HtmlConfigSpec(void){
- return configSpecs;
-}
-
-/*
-** Find the width of the usable drawing area in pixels. If the window isn't
-** mapped, use the size requested by the user.
-**
-** The usable drawing area is the area available for displaying rendered
-** HTML. The usable drawing area does not include the 3D border or the
-** padx and pady boundry within the 3D border. The usable drawing area
-** is the size of the clipping window.
-*/
-int HtmlUsableWidth(HtmlWidget *htmlPtr){
- int w;
- Tk_Window tkwin = htmlPtr->tkwin;
- if( tkwin && Tk_IsMapped(tkwin) ){
- w = Tk_Width(tkwin) - 2*(htmlPtr->padx + htmlPtr->inset);
- TestPoint(0);
- }else{
- w = htmlPtr->width;
- TestPoint(0);
- }
- return w;
-}
-
-/*
-** Find the height of the usable drawing area in pixels. If the window isn't
-** mapped, use the size requested by the user.
-**
-** The usable drawing area is the area available for displaying rendered
-** HTML. The usable drawing area does not include the 3D border or the
-** padx and pady boundry within the 3D border. The usable drawing area
-** is the size of the clipping window.
-*/
-int HtmlUsableHeight(HtmlWidget *htmlPtr){
- int h;
- Tk_Window tkwin = htmlPtr->tkwin;
- if( tkwin && Tk_IsMapped(tkwin) ){
- h = Tk_Height(tkwin) - 2*(htmlPtr->pady + htmlPtr->inset);
- TestPoint(0);
- }else{
- h = htmlPtr->height;
- TestPoint(0);
- }
- return h;
-}
-
-/*
-** Compute a pair of floating point numbers that describe the current
-** vertical scroll position. The first number is the fraction of
-** the document that is off the top of the visible region and the second
-** number is the fraction that is beyond the end of the visible region.
-*/
-void HtmlComputeVerticalPosition(
- HtmlWidget *htmlPtr,
- char *buf /* Write the two floating point values here */
-){
- int actual; /* Size of the viewing area */
- double frac1, frac2;
-
- actual = HtmlUsableHeight(htmlPtr);
- if( htmlPtr->maxY <= 0 ){
- frac1 = 0.0;
- frac2 = 1.0;
- TestPoint(0);
- }else{
- frac1 = (double)htmlPtr->yOffset/(double)htmlPtr->maxY;
- if( frac1 > 1.0 ){
- frac1 = 1.0;
- TestPoint(0);
- }else if( frac1 < 0.0 ){
- frac1 = 0.0;
- TestPoint(0);
- }
- frac2 = (double)(htmlPtr->yOffset+actual)/(double)htmlPtr->maxY;
- if( frac2 > 1.0 ){
- frac2 = 1.0;
- TestPoint(0);
- }else if( frac2 < 0.0 ){
- frac2 = 0.0;
- TestPoint(0);
- }
- }
- sprintf(buf,"%g %g",frac1, frac2);
-}
-
-/*
-** Do the same thing for the horizontal direction
-*/
-void HtmlComputeHorizontalPosition(
- HtmlWidget *htmlPtr,
- char *buf /* Write the two floating point values here */
-){
- int actual; /* Size of the viewing area */
- double frac1, frac2;
-
- actual = HtmlUsableWidth(htmlPtr);
- if( htmlPtr->maxX <= 0 ){
- frac1 = 0.0;
- frac2 = 1.0;
- TestPoint(0);
- }else{
- frac1 = (double)htmlPtr->xOffset/(double)htmlPtr->maxX;
- if( frac1 > 1.0 ){
- frac1 = 1.0;
- TestPoint(0);
- }else if( frac1 < 0.0 ){
- frac1 = 0.0;
- TestPoint(0);
- }
- frac2 = (double)(htmlPtr->xOffset+actual)/(double)htmlPtr->maxX;
- if( frac2 > 1.0 ){
- frac2 = 1.0;
- TestPoint(0);
- }else if( frac2 < 0.0 ){
- frac2 = 0.0;
- TestPoint(0);
- }
- }
- sprintf(buf,"%g %g",frac1, frac2);
-}
-
-/*
-** Clear the cache of GCs
-*/
-static void ClearGcCache(HtmlWidget *htmlPtr){
- int i;
- for(i=0; i<N_CACHE_GC; i++){
- if( htmlPtr->aGcCache[i].index ){
- Tk_FreeGC(htmlPtr->display, htmlPtr->aGcCache[i].gc);
- htmlPtr->aGcCache[i].index = 0;
- TestPoint(0);
- }else{
- TestPoint(0);
- }
- }
-}
-
-
-/*
-** This routine is called when the widget command is deleted. If the
-** widget isn't already in the process of being destroyed, this command
-** starts that process rolling.
-**
-** This routine can be called in two ways.
-**
-** (1) The window is destroyed, which causes the command to be deleted.
-** In this case, we don't have to do anything.
-**
-** (2) The command only is deleted (ex: "rename .html {}"). In that
-** case we need to destroy the window.
-*/
-static void HtmlCmdDeletedProc(ClientData clientData){
- HtmlWidget *htmlPtr = (HtmlWidget*) clientData;
- if (htmlPtr != NULL && htmlPtr->tkwin!=NULL ) {
- Tk_Window tkwin = htmlPtr->tkwin;
- htmlPtr->tkwin = NULL;
- Tk_DestroyWindow(tkwin);
- }
-}
-
-/*
-** Reset the main layout context in the main widget. This happens
-** before we redo the layout, or just before deleting the widget.
-*/
-static void ResetLayoutContext(HtmlWidget *htmlPtr){
- htmlPtr->layoutContext.headRoom = 0;
- htmlPtr->layoutContext.top = 0;
- htmlPtr->layoutContext.bottom = 0;
- HtmlClearMarginStack(&htmlPtr->layoutContext.leftMargin);
- HtmlClearMarginStack(&htmlPtr->layoutContext.rightMargin);
-}
-
-/*
-** This routine is invoked in order to redraw all or part of the HTML
-** widget. This might happen because the display has changed, or in
-** response to an expose event. In all cases, though, this routine
-** is called by an idle callback.
-*/
-static void HtmlRedrawCallback(ClientData clientData){
- HtmlWidget *htmlPtr = (HtmlWidget*)clientData;
- Tk_Window tkwin = htmlPtr->tkwin;
- Tk_Window clipwin = htmlPtr->clipwin;
- Pixmap pixmap; /* The buffer on which to render HTML */
- int x, y, w, h; /* Virtual canvas coordinates of area to draw */
- int hw; /* highlight thickness */
- int insetX, insetY; /* Total highlight thickness, border width and
- ** padx/y */
- int clipwinH, clipwinW; /* Width and height of the clipping window */
- HtmlBlock *pBlock; /* For looping over blocks to be drawn */
- int redoSelection = 0; /* True to recompute the selection */
-
- /*
- ** Don't bother doing anything if the widget is in the process of
- ** being destroyed.
- */
- if( tkwin==0 ){
- goto redrawExit;
- }
-
- /*
- ** Recompute the layout, if necessary or requested.
- **
- ** Calling HtmlLayout() is tricky because HtmlLayout() may invoke one
- ** or more callbacks (thru the "-imagecommand" callback, for instance)
- ** and these callbacks could, in theory, do nasty things like delete
- ** or unmap this widget. So we have to take precautions:
- **
- ** * Don't remove the REDRAW_PENDING flag until after HtmlLayout()
- ** has been called, to prevent a recursive call to HtmlRedrawCallback().
- **
- ** * Call HtmlLock() on the htmlPtr structure to prevent it from
- ** being deleted out from under us.
- **
- */
- if( (htmlPtr->flags & RESIZE_ELEMENTS)!=0
- && (htmlPtr->flags & STYLER_RUNNING)==0 ){
- HtmlImage *pImage;
- for(pImage=htmlPtr->imageList; pImage; pImage=pImage->pNext){
- pImage->pList = 0;
- }
- htmlPtr->lastSized = 0;
- htmlPtr->flags &= ~RESIZE_ELEMENTS;
- htmlPtr->flags |= RELAYOUT;
- }
-
- /* We used to make a distinction between RELAYOUT and EXTEND_LAYOUT.
- ** RELAYOUT would be used when the widget was resized, but the
- ** less compute-intensive EXTEND_LAYOUT would be used when new
- ** text was appended.
- **
- ** Unfortunately, EXTEND_LAYOUT has some problem that arise when
- ** tables are used. The quick fix is to make an EXTEND_LAYOUT do
- ** a complete RELAYOUT. Someday, we need to fix EXTEND_LAYOUT so
- ** that it works right...
- */
- if( (htmlPtr->flags & (RELAYOUT|EXTEND_LAYOUT))!=0
- && (htmlPtr->flags & STYLER_RUNNING)==0 ){
- htmlPtr->nextPlaced = 0;
- htmlPtr->nInput = 0;
- htmlPtr->varId = 0;
- htmlPtr->maxX = 0;
- htmlPtr->maxY = 0;
- ResetLayoutContext(htmlPtr);
- htmlPtr->firstBlock = 0;
- htmlPtr->lastBlock = 0;
- redoSelection = 1;
- htmlPtr->flags &= ~RELAYOUT;
- htmlPtr->flags |= HSCROLL | VSCROLL | REDRAW_TEXT | EXTEND_LAYOUT;
- }
- if( (htmlPtr->flags & EXTEND_LAYOUT) && htmlPtr->pFirst!=0 ){
- HtmlLock(htmlPtr);
- HtmlLayout(htmlPtr);
- if( HtmlUnlock(htmlPtr) ) goto redrawExit;
- tkwin = htmlPtr->tkwin;
- htmlPtr->flags &= ~EXTEND_LAYOUT;
- HtmlFormBlocks(htmlPtr);
- HtmlMapControls(htmlPtr);
- if( redoSelection && htmlPtr->selBegin.p && htmlPtr->selEnd.p ){
- HtmlUpdateSelection(htmlPtr,1);
- HtmlUpdateInsert(htmlPtr);
- }
- }
- htmlPtr->flags &= ~REDRAW_PENDING;
-
- /* No need to do any actual drawing if we aren't mapped
- */
- if( !Tk_IsMapped(tkwin) ){
- goto redrawExit;
- }
-
- /* Redraw the scrollbars. Take care here, since the scrollbar
- ** update command could (in theory) delete the html widget, or
- ** even the whole interpreter. Preserve critical data structures,
- ** and check to see if we are still alive before continuing.
- */
- if( (htmlPtr->flags & (HSCROLL|VSCROLL)) != 0 ){
- Tcl_Interp *interp = htmlPtr->interp;
- int result;
- char buf[200];
-
- if( (htmlPtr->flags & HSCROLL)!=0 ){
- if( htmlPtr->xScrollCmd && htmlPtr->xScrollCmd[0] ){
- HtmlComputeHorizontalPosition(htmlPtr,buf);
- HtmlLock(htmlPtr);
- result = Tcl_VarEval(interp, htmlPtr->xScrollCmd, " ", buf, NULL);
- if( HtmlUnlock(htmlPtr) ) goto redrawExit;
- if (result != TCL_OK) {
- Tcl_AddErrorInfo(interp,
- "\n (horizontal scrolling command executed by html widget)");
- Tcl_BackgroundError(interp);
- TestPoint(0);
- }
- }
- htmlPtr->flags &= ~HSCROLL;
- }
- if( (htmlPtr->flags & VSCROLL)!=0 && tkwin && Tk_IsMapped(tkwin) ){
- if( htmlPtr->yScrollCmd && htmlPtr->yScrollCmd[0] ){
- Tcl_Interp *interp = htmlPtr->interp;
- int result;
- char buf[200];
- HtmlComputeVerticalPosition(htmlPtr,buf);
- HtmlLock(htmlPtr);
- result = Tcl_VarEval(interp, htmlPtr->yScrollCmd, " ", buf, NULL);
- if( HtmlUnlock(htmlPtr) ) goto redrawExit;
- if (result != TCL_OK) {
- Tcl_AddErrorInfo(interp,
- "\n (horizontal scrolling command executed by html widget)");
- Tcl_BackgroundError(interp);
- TestPoint(0);
- }
- }
- htmlPtr->flags &= ~VSCROLL;
- }
- tkwin = htmlPtr->tkwin;
- if( tkwin==0 || !Tk_IsMapped(tkwin) ){ goto redrawExit; }
- if( htmlPtr->flags & REDRAW_PENDING ){ return; }
- clipwin = htmlPtr->clipwin;
- if( clipwin==0 ){ TestPoint(0); goto redrawExit; }
- }
-
- /* Redraw the focus highlight, if requested */
- hw = htmlPtr->highlightWidth;
- if( htmlPtr->flags & REDRAW_FOCUS ){
- if( hw>0 ){
- GC gc;
- Tk_Window tkwin = htmlPtr->tkwin;
-
- if( htmlPtr->flags & GOT_FOCUS ){
- gc = Tk_GCForColor(htmlPtr->highlightColorPtr, Tk_WindowId(tkwin));
- TestPoint(0);
- }else{
- gc = Tk_GCForColor(htmlPtr->highlightBgColorPtr, Tk_WindowId(tkwin));
- TestPoint(0);
- }
- Tk_DrawFocusHighlight(tkwin, gc, hw, Tk_WindowId(tkwin));
- }
- htmlPtr->flags &= ~REDRAW_FOCUS;
- }
-
- /* Draw the borders around the parameter of the window. This is
- ** drawn directly -- it is not double buffered.
- */
- if( htmlPtr->flags & REDRAW_BORDER ){
- htmlPtr->flags &= ~REDRAW_BORDER;
- Tk_Fill3DRectangle(tkwin, Tk_WindowId(tkwin), htmlPtr->border,
- hw, /* x */
- hw, /* y */
- Tk_Width(tkwin) - 2*hw, /* width */
- Tk_Height(tkwin) - 2*hw, /* height */
- htmlPtr->borderWidth, htmlPtr->relief);
- }
-
- /*
- ** If the styler is in a callback, unmap the clipping window and
- ** abort further processing.
- */
- if( htmlPtr->flags & STYLER_RUNNING ){
- if( Tk_IsMapped(clipwin) ){
- Tk_UnmapWindow(clipwin);
- }
- goto earlyOut;
- }
-
- /*
- ** If we don't have a clipping window, then something is seriously
- ** wrong. We might as well give up.
- */
- if( clipwin==NULL ){ TestPoint(0); goto earlyOut; }
-
- /* Resize, reposition and map the clipping window, if necessary */
- insetX = htmlPtr->padx + htmlPtr->inset;
- insetY = htmlPtr->pady + htmlPtr->inset;
- if( htmlPtr->flags & RESIZE_CLIPWIN ){
- int h, w;
- Tk_MoveResizeWindow(clipwin, insetX, insetY,
- htmlPtr->realWidth - 2*insetX,
- htmlPtr->realHeight - 2*insetY);
- if( !Tk_IsMapped(clipwin) ){
- Tk_MapWindow(clipwin);
- }
- h = htmlPtr->realHeight - 2*insetY;
- if( htmlPtr->yOffset + h > htmlPtr->maxY ){
- htmlPtr->yOffset = htmlPtr->maxY - h;
- }
- if( htmlPtr->yOffset < 0 ){
- htmlPtr->yOffset = 0;
- }
- w = htmlPtr->realWidth - 2*insetX;
- if( htmlPtr->xOffset + h > htmlPtr->maxX ){
- htmlPtr->xOffset = htmlPtr->maxX - w;
- }
- if( htmlPtr->xOffset < 0 ){
- htmlPtr->xOffset = 0;
- }
- htmlPtr->flags &= ~RESIZE_CLIPWIN;
- }
- HtmlMapControls(htmlPtr);
-
- /*
- ** Compute the virtual canvas coordinates corresponding to the
- ** dirty region of the clipping window.
- */
- clipwinW = Tk_Width(clipwin);
- clipwinH = Tk_Height(clipwin);
- if( htmlPtr->flags & REDRAW_TEXT ){
- w = clipwinW;
- h = clipwinH;
- x = htmlPtr->xOffset;
- y = htmlPtr->yOffset;
- htmlPtr->dirtyLeft = 0;
- htmlPtr->dirtyTop = 0;
- htmlPtr->flags &= ~REDRAW_TEXT;
- }else{
- if( htmlPtr->dirtyLeft < 0 ){
- htmlPtr->dirtyLeft = 0;
- TestPoint(0);
- }
- if( htmlPtr->dirtyRight > clipwinW ){
- htmlPtr->dirtyRight = clipwinW;
- TestPoint(0);
- }
- if( htmlPtr->dirtyTop < 0 ){
- htmlPtr->dirtyTop = 0;
- TestPoint(0);
- }
- if( htmlPtr->dirtyBottom > clipwinH ){
- htmlPtr->dirtyBottom = clipwinH;
- TestPoint(0);
- }
- w = htmlPtr->dirtyRight - htmlPtr->dirtyLeft;
- h = htmlPtr->dirtyBottom - htmlPtr->dirtyTop;
- x = htmlPtr->xOffset + htmlPtr->dirtyLeft;
- y = htmlPtr->yOffset + htmlPtr->dirtyTop;
- }
-
- /* Skip the rest of the drawing process if the area to be refreshed is
- ** less than zero */
- if( w>0 && h>0 ){
- Display *display = htmlPtr->display;
- int dead;
- GC gcBg;
- XRectangle xrec;
- /* printf("Redraw %dx%d at %d,%d\n", w, h, x, y); */
-
- /* Allocate and clear a pixmap upon which to draw */
- gcBg = HtmlGetGC(htmlPtr, COLOR_Background, FONT_Any);
- pixmap = Tk_GetPixmap(display, Tk_WindowId(clipwin),w,h,Tk_Depth(clipwin));
- xrec.x = 0;
- xrec.y = 0;
- xrec.width = w;
- xrec.height = h;
- XFillRectangles(display, pixmap, gcBg, &xrec, 1);
-
- /* Render all visible HTML onto the pixmap */
- HtmlLock(htmlPtr);
- for(pBlock=htmlPtr->firstBlock; pBlock; pBlock=pBlock->pNext){
- if( pBlock->top <= y+h && pBlock->bottom >= y
- && pBlock->left <= x+w && pBlock->right >= x ){
- HtmlBlockDraw(htmlPtr,pBlock,pixmap,x,y,w,h);
- if( htmlPtr->tkwin==0 ) break;
- }
- }
- dead = HtmlUnlock(htmlPtr);
-
- /* Finally, copy the pixmap onto the window and delete the pixmap */
- if( !dead ){
- XCopyArea(display, pixmap, Tk_WindowId(clipwin),
- gcBg, 0, 0, w, h, htmlPtr->dirtyLeft, htmlPtr->dirtyTop);
- }
- Tk_FreePixmap(display, pixmap);
- if( dead ) goto redrawExit;
- /* XFlush(display); */
- }
-
- /* Redraw images, if requested */
- if( htmlPtr->flags & REDRAW_IMAGES ){
- HtmlImage *pImage;
- HtmlElement *pElem;
- int top, bottom, left, right; /* Coordinates of the clipping window */
- int imageTop; /* Top edge of image */
-
- top = htmlPtr->yOffset;
- bottom = top + HtmlUsableHeight(htmlPtr);
- left = htmlPtr->xOffset;
- right = left + HtmlUsableWidth(htmlPtr);
- for(pImage = htmlPtr->imageList; pImage; pImage=pImage->pNext){
- for(pElem = pImage->pList; pElem; pElem=pElem->image.pNext){
- if( pElem->image.redrawNeeded==0 ) continue;
- imageTop = pElem->image.y - pElem->image.ascent;
- if( imageTop > bottom
- || imageTop + pElem->image.h < top
- || pElem->image.x > right
- || pElem->image.x + pElem->image.w < left ){
- TestPoint(0);
- continue;
- }
- HtmlDrawImage(pElem, Tk_WindowId(htmlPtr->clipwin),
- left, top, right, bottom);
- }
- }
- htmlPtr->flags &= ~REDRAW_IMAGES;
- }
-
- /* Set the dirty region to the empty set. */
- earlyOut:
- htmlPtr->dirtyTop = LARGE_NUMBER;
- htmlPtr->dirtyLeft = LARGE_NUMBER;
- htmlPtr->dirtyBottom = 0;
- htmlPtr->dirtyRight = 0;
- redrawExit:
- return;
-}
-
-/*
-** Make sure that a call to the HtmlRedrawCallback() routine has been
-** queued.
-*/
-void HtmlScheduleRedraw(HtmlWidget *htmlPtr){
- if( (htmlPtr->flags & REDRAW_PENDING)==0
- && htmlPtr->tkwin!=0
- && Tk_IsMapped(htmlPtr->tkwin)
- ){
- Tcl_DoWhenIdle(HtmlRedrawCallback, (ClientData)htmlPtr);
- htmlPtr->flags |= REDRAW_PENDING;
- }
-}
-
-/*
-** If any part of the screen needs to be redrawn, Then call this routine
-** with the values of a box (in window coordinates) that needs to be
-** redrawn. This routine will make sure an idle callback is scheduled
-** to do the redraw.
-**
-** The box coordinates are relative to the clipping window (clipwin),
-** not the main window (tkwin).
-*/
-void HtmlRedrawArea(
- HtmlWidget *htmlPtr, /* The widget to be redrawn */
- int left, int top, /* Top left corner of area to redraw */
- int right, int bottom /* bottom right corner of area to redraw */
-){
- if( bottom < 0 ){ TestPoint(0); return; }
- if( top > htmlPtr->realHeight ){ TestPoint(0); return; }
- if( right < 0 ){ TestPoint(0); return; }
- if( left > htmlPtr->realWidth ){ TestPoint(0); return; }
- if( htmlPtr->dirtyTop > top ){ htmlPtr->dirtyTop = top; TestPoint(0);}
- if( htmlPtr->dirtyLeft > left ){ htmlPtr->dirtyLeft = left; TestPoint(0);}
- if( htmlPtr->dirtyBottom < bottom ){
- htmlPtr->dirtyBottom = bottom;
- TestPoint(0);
- }
- if( htmlPtr->dirtyRight < right ){ htmlPtr->dirtyRight = right; TestPoint(0);}
- HtmlScheduleRedraw(htmlPtr);
- TestPoint(0);
-}
-
-/* Redraw the HtmlBlock given.
-*/
-void HtmlRedrawBlock(HtmlWidget *htmlPtr, HtmlBlock *p){
- if( p ){
- HtmlRedrawArea(htmlPtr,
- p->left - htmlPtr->xOffset,
- p->top - htmlPtr->yOffset,
- p->right - htmlPtr->xOffset + 1,
- p->bottom - htmlPtr->yOffset
- );
- TestPoint(0);
- }else{
- TestPoint(0);
- }
-}
-
-/*
-** Call this routine to force the entire widget to be redrawn.
-*/
-void HtmlRedrawEverything(HtmlWidget *htmlPtr){
- htmlPtr->flags |= REDRAW_FOCUS | REDRAW_TEXT | REDRAW_BORDER;
- HtmlScheduleRedraw(htmlPtr);
- TestPoint(0);
-}
-
-/*
-** Do the redrawing right now. Don't wait.
-*/
-#if 0 /* NOT_USED */
-static void HtmlRedrawPush(HtmlWidget *htmlPtr){
- if( htmlPtr->flags & REDRAW_PENDING ){
- Tcl_CancelIdleCall(HtmlRedrawCallback, (ClientData)htmlPtr);
- TestPoint(0);
- }else{
- TestPoint(0);
- }
- HtmlRedrawCallback( (ClientData)htmlPtr );
-}
-#endif
-
-/*
-** Call this routine to cause all of the rendered HTML at the
-** virtual canvas coordinate of Y and beyond to be redrawn.
-*/
-void HtmlRedrawText(HtmlWidget *htmlPtr, int y){
- int yOffset; /* Top-most visible canvas coordinate */
- int clipHeight; /* Height of the clipping window */
-
- yOffset = htmlPtr->yOffset;
- clipHeight = HtmlUsableHeight(htmlPtr);
- y -= yOffset;
- if( y < clipHeight ){
- HtmlRedrawArea(htmlPtr, 0, y, LARGE_NUMBER, clipHeight);
- TestPoint(0);
- }else{
- TestPoint(0);
- }
-}
-
-/*
-** Recalculate the preferred size of the html widget and pass this
-** along to the geometry manager.
-*/
-static void HtmlRecomputeGeometry(HtmlWidget *htmlPtr){
- int w, h; /* Total width and height of the widget */
-
- htmlPtr->inset = htmlPtr->highlightWidth + htmlPtr->borderWidth;
- w = htmlPtr->width + 2*(htmlPtr->padx + htmlPtr->inset);
- h = htmlPtr->height + 2*(htmlPtr->pady + htmlPtr->inset);
- Tk_GeometryRequest(htmlPtr->tkwin, w, h);
- Tk_SetInternalBorder(htmlPtr->tkwin, htmlPtr->inset);
- TestPoint(0);
-}
-
-/*
-** This routine is called in order to process a "configure" subcommand
-** on the given html widget.
-*/
-int ConfigureHtmlWidget(
- Tcl_Interp *interp, /* Write error message to this interpreter */
- HtmlWidget *htmlPtr, /* The Html widget to be configured */
- int argc, /* Number of configuration arguments */
- const char **argv, /* Text of configuration arguments */
- int flags, /* Configuration flags */
- int realign /* Always do a redraw if set */
-){
- int rc;
- int i;
- int redraw = realign; /* True if a redraw is required. */
-
- /* Scan thru the configuration options to see if we need to redraw
- ** the widget.
- */
- for(i=0; redraw==0 && i<argc; i+=2){
- int c;
- int n;
- if( argv[i][0]!='-' ){
- redraw = 1;
- break;
- }
- c = argv[i][1];
- n = strlen(argv[i]);
- if( c=='c' && n>4 && strncmp(argv[i],"-cursor",n)==0 ){
- /* do nothing */
- }else
- /* The default case */
- {
- redraw = 1;
- }
- }
- rc = Tk_ConfigureWidget(interp, htmlPtr->tkwin, configSpecs, argc, (const char**)argv,
- (char *) htmlPtr, flags);
- if( rc!=TCL_OK || redraw==0 ){ TestPoint(0); return rc; }
- memset(htmlPtr->fontValid, 0, sizeof(htmlPtr->fontValid));
- htmlPtr->apColor[COLOR_Normal] = htmlPtr->fgColor;
- htmlPtr->apColor[COLOR_Visited] = htmlPtr->oldLinkColor;
- htmlPtr->apColor[COLOR_Unvisited] = htmlPtr->newLinkColor;
- htmlPtr->apColor[COLOR_Selection] = htmlPtr->selectionColor;
- htmlPtr->apColor[COLOR_Background] = Tk_3DBorderColor(htmlPtr->border);
- Tk_SetBackgroundFromBorder(htmlPtr->tkwin, htmlPtr->border);
- if( htmlPtr->highlightWidth < 0 ){ htmlPtr->highlightWidth = 0; TestPoint(0);}
- if (htmlPtr->padx < 0) { htmlPtr->padx = 0; TestPoint(0);}
- if (htmlPtr->pady < 0) { htmlPtr->pady = 0; TestPoint(0);}
- if (htmlPtr->width < 100) { htmlPtr->width = 100; TestPoint(0);}
- if (htmlPtr->height < 100) { htmlPtr->height = 100; TestPoint(0);}
- if (htmlPtr->borderWidth < 0) {htmlPtr->borderWidth = 0; TestPoint(0);}
- htmlPtr->flags |= RESIZE_ELEMENTS | RELAYOUT | REDRAW_BORDER | RESIZE_CLIPWIN;
- HtmlRecomputeGeometry(htmlPtr);
- HtmlRedrawEverything(htmlPtr);
- ClearGcCache(htmlPtr);
- return rc;
-}
-
-/*
-** Delete a single HtmlElement
-*/
-void HtmlDeleteElement(HtmlElement *p){
- switch( p->base.type ){
- case Html_Block:
- if( p->block.z ){
- HtmlFree(p->block.z);
- }
- break;
- default:
- break;
- }
- HtmlFree(p);
-}
-
-/*
-** Erase all data from the HTML widget. Bring it back to an
-** empty screen.
-**
-** This happens (for example) when the "clear" method is invoked
-** on the widget, or just before the widget is deleted.
-*/
-void HtmlClear(HtmlWidget *htmlPtr){
- int i;
- HtmlElement *p, *pNext;
-
- HtmlDeleteControls(htmlPtr);
- for(p=htmlPtr->pFirst; p; p=pNext){
- pNext = p->pNext;
- HtmlDeleteElement(p);
- }
- htmlPtr->pFirst = 0;
- htmlPtr->pLast = 0;
- htmlPtr->nToken = 0;
- if( htmlPtr->zText ){
- HtmlFree(htmlPtr->zText);
- }
- htmlPtr->zText = 0;
- htmlPtr->nText = 0;
- htmlPtr->nAlloc = 0;
- htmlPtr->nComplete = 0;
- htmlPtr->iPlaintext = 0;
- for(i=N_PREDEFINED_COLOR; i<N_COLOR; i++){
- if( htmlPtr->apColor[i] != 0 ){
- Tk_FreeColor(htmlPtr->apColor[i]);
- htmlPtr->apColor[i] = 0;
- }
- }
- for(i=0; i<N_COLOR; i++){
- htmlPtr->iDark[i] = 0;
- htmlPtr->iLight[i] = 0;
- }
- htmlPtr->colorUsed = 0;
- while( htmlPtr->imageList ){
- HtmlImage *p = htmlPtr->imageList;
- htmlPtr->imageList = p->pNext;
- Tk_FreeImage(p->image);
- HtmlFree(p);
- TestPoint(0);
- }
- while( htmlPtr->styleStack ){
- HtmlStyleStack *p = htmlPtr->styleStack;
- htmlPtr->styleStack = p->pNext;
- HtmlFree(p);
- }
- ClearGcCache(htmlPtr);
- ResetLayoutContext(htmlPtr);
- if( htmlPtr->zBaseHref ){
- HtmlFree(htmlPtr->zBaseHref);
- htmlPtr->zBaseHref = 0;
- }
- htmlPtr->lastSized = 0;
- htmlPtr->nextPlaced = 0;
- htmlPtr->firstBlock = 0;
- htmlPtr->lastBlock = 0;
- htmlPtr->nInput = 0;
- htmlPtr->nForm = 0;
- htmlPtr->varId = 0;
- htmlPtr->paraAlignment = ALIGN_None;
- htmlPtr->rowAlignment = ALIGN_None;
- htmlPtr->anchorFlags = 0;
- htmlPtr->inDt = 0;
- htmlPtr->anchorStart = 0;
- htmlPtr->formStart = 0;
- htmlPtr->innerList = 0;
- htmlPtr->maxX = 0;
- htmlPtr->maxY = 0;
- htmlPtr->xOffset = 0;
- htmlPtr->yOffset = 0;
- htmlPtr->pInsBlock = 0;
- htmlPtr->ins.p = 0;
- htmlPtr->selBegin.p = 0;
- htmlPtr->selEnd.p = 0;
- htmlPtr->pSelStartBlock = 0;
- htmlPtr->pSelEndBlock = 0;
-}
-
-/*
-** This routine attempts to delete the widget structure. But it won't
-** do it if the widget structure is locked. If the widget structure is
-** locked, then when HtmlUnlock() is called and the lock count reaches
-** zero, this routine will be called to finish the job.
-*/
-static void DestroyHtmlWidget(HtmlWidget *htmlPtr){
- int i;
-
- if( htmlPtr->locked>0 ) return;
- Tcl_DeleteCommand(htmlPtr->interp, htmlPtr->zCmdName);
- Tcl_DeleteCommand(htmlPtr->interp, htmlPtr->zClipwin);
- HtmlClear(htmlPtr);
- Tk_FreeOptions(configSpecs, (char*) htmlPtr, htmlPtr->display, 0);
- for(i=0; i<N_FONT; i++){
- if( htmlPtr->aFont[i] != 0 ){
- Tk_FreeFont(htmlPtr->aFont[i]);
- htmlPtr->aFont[i] = 0;
- }
- }
- for(i=0; i<Html_TypeCount; i++){
- if( htmlPtr->zHandler[i] ){
- HtmlFree(htmlPtr->zHandler[i]);
- htmlPtr->zHandler[i] = 0;
- }
- }
- if( htmlPtr->insTimer ){
- Tcl_DeleteTimerHandler(htmlPtr->insTimer);
- htmlPtr->insTimer = 0;
- }
- HtmlFree(htmlPtr->zClipwin);
- HtmlFree(htmlPtr);
-}
-
-/*
-** Remove a lock from the HTML widget. If the widget has been
-** deleted, then delete the widget structure. Return 1 if the
-** widget has been deleted. Return 0 if it still exists.
-**
-** Normal Tk code (that is to say, code in the Tk core) uses
-** Tcl_Preserve() and Tcl_Release() to accomplish what this
-** function does. But preserving and releasing are much more
-** common in this code than in regular widgets, so this routine
-** was invented to do the same thing easier and faster.
-*/
-int HtmlUnlock(HtmlWidget *htmlPtr){
- htmlPtr->locked--;
- if( htmlPtr->tkwin==0 && htmlPtr->locked<=0 ){
- Tcl_Interp *interp = htmlPtr->interp;
- Tcl_Preserve(interp);
- DestroyHtmlWidget(htmlPtr);
- Tcl_Release(interp);
- return 1;
- }
- return htmlPtr->tkwin==0;
-}
-
-/*
-** Lock the HTML widget. This prevents the widget structure from
-** being deleted even if the widget itself is destroyed. There must
-** be a call to HtmlUnlock() to release the structure.
-*/
-void HtmlLock(HtmlWidget *htmlPtr){
- htmlPtr->locked++;
-}
-
-/*
-** This routine checks to see if an HTML widget has been
-** destroyed. It is always called after calling HtmlLock().
-**
-** If the widget has been destroyed, then the structure
-** is unlocked and the function returns 1. If the widget
-** has not been destroyed, then the structure is not unlocked
-** and the routine returns 0.
-**
-** This routine is intended for use in code like the following:
-**
-** HtmlLock(htmlPtr);
-** // Do something that might destroy the widget
-** if( HtmlIsDead(htmlPtr) ) return;
-** // Do something that might destroy the widget
-** if( HtmlIsDead(htmlPtr) ) return;
-** // Do something that might destroy the widget
-** if( HtmlUnlock(htmlPtr) ) return;
-*/
-int HtmlIsDead(HtmlWidget *htmlPtr){
- if( htmlPtr->tkwin==0 ){
- HtmlUnlock(htmlPtr);
- return 1;
- }
- return 0;
-}
-
-/*
-** Flash the insertion cursor.
-*/
-void HtmlFlashCursor(ClientData clientData){
- HtmlWidget *htmlPtr = (HtmlWidget*)clientData;
- if( htmlPtr->pInsBlock==0 || htmlPtr->insOnTime<=0
- || htmlPtr->insOffTime<=0 ){
- htmlPtr->insTimer = 0;
- TestPoint(0);
- return;
- }
- HtmlRedrawBlock(htmlPtr, htmlPtr->pInsBlock);
- if( (htmlPtr->flags & GOT_FOCUS)==0 ){
- htmlPtr->insStatus = 0;
- htmlPtr->insTimer = 0;
- TestPoint(0);
- }else if( htmlPtr->insStatus ){
- htmlPtr->insTimer = Tcl_CreateTimerHandler(htmlPtr->insOffTime,
- HtmlFlashCursor, clientData);
- htmlPtr->insStatus = 0;
- TestPoint(0);
- }else{
- htmlPtr->insTimer = Tcl_CreateTimerHandler(htmlPtr->insOnTime,
- HtmlFlashCursor, clientData);
- htmlPtr->insStatus = 1;
- TestPoint(0);
- }
-}
-
-/*
-** Return a GC from the cache. As many as N_CACHE_GCs are kept valid
-** at any one time. They are replaced using an LRU algorithm.
-**
-** A value of FONT_Any (-1) for the font means "don't care".
-*/
-GC HtmlGetGC(HtmlWidget *htmlPtr, int color, int font){
- int i, j;
- GcCache *p = htmlPtr->aGcCache;
- XGCValues gcValues;
- int mask;
- Tk_Font tkfont;
-
- /*
- ** Check for an existing GC.
- */
- if( color < 0 || color >= N_COLOR ){ color = 0; TestPoint(0); }
- if( font < FONT_Any || font >= N_FONT ){ font = FONT_Default; TestPoint(0); }
- for(i=0; i<N_CACHE_GC; i++, p++){
- if( p->index==0 ){ TestPoint(0); continue; }
- if( (font<0 || p->font==font) && p->color==color ){
- if( p->index>1 ){
- for(j=0; j<N_CACHE_GC; j++){
- if( htmlPtr->aGcCache[j].index
- && htmlPtr->aGcCache[j].index < p->index ){
- htmlPtr->aGcCache[j].index++;
- }
- }
- p->index = 1;
- }
- return htmlPtr->aGcCache[i].gc;
- }
- }
-
- /*
- ** No GC matches. Find a place to allocate a new GC.
- */
- p = htmlPtr->aGcCache;
- for(i=0; i<N_CACHE_GC; i++, p++){
- if( p->index==0 || p->index==N_CACHE_GC ){ TestPoint(0); break; }
- }
- if( p->index ){
- Tk_FreeGC(htmlPtr->display, p->gc);
- }
- gcValues.foreground = htmlPtr->apColor[color]->pixel;
- gcValues.graphics_exposures = True;
- mask = GCForeground | GCGraphicsExposures;
- if( font<0 ){ font = FONT_Default; TestPoint(0); }
- tkfont = HtmlGetFont(htmlPtr, font);
- if( tkfont ){
- gcValues.font = Tk_FontId(tkfont);
- mask |= GCFont;
- }
- p->gc = Tk_GetGC(htmlPtr->tkwin, mask, &gcValues);
- if( p->index==0 ){ p->index = N_CACHE_GC + 1; TestPoint(0); }
- for(j=0; j<N_CACHE_GC; j++){
- if( htmlPtr->aGcCache[j].index && htmlPtr->aGcCache[j].index < p->index ){
- htmlPtr->aGcCache[j].index++;
- }
- }
- p->index = 1;
- p->font = font;
- p->color = color;
- return p->gc;
-}
-
-/*
-** Retrieve any valid GC. The font and color don't matter since the
-** GC will only be used for copying.
-*/
-GC HtmlGetAnyGC(HtmlWidget *htmlPtr){
- int i;
- GcCache *p = htmlPtr->aGcCache;
-
- for(i=0; i<N_CACHE_GC; i++, p++){
- if( p->index ){ TestPoint(0); return p->gc; }
- }
- TestPoint(0);
- return HtmlGetGC(htmlPtr, COLOR_Normal, FONT_Default);
-}
-
-/*
-** All window events (for both tkwin and clipwin) are
-** sent to this routine.
-*/
-static void HtmlEventProc(ClientData clientData, XEvent *eventPtr){
- HtmlWidget *htmlPtr = (HtmlWidget*) clientData;
- int redraw_needed = 0;
- XConfigureRequestEvent *p;
-
- switch( eventPtr->type ){
- case GraphicsExpose:
- case Expose:
- if( htmlPtr->tkwin==0 ){
- /* The widget is being deleted. Do nothing */
- TestPoint(0);
- }else if( eventPtr->xexpose.window!=Tk_WindowId(htmlPtr->tkwin) ){
- /* Exposure in the clipping window */
- HtmlRedrawArea(htmlPtr, eventPtr->xexpose.x - 1,
- eventPtr->xexpose.y - 1,
- eventPtr->xexpose.x + eventPtr->xexpose.width + 1,
- eventPtr->xexpose.y + eventPtr->xexpose.height + 1);
- TestPoint(0);
- }else{
- /* Exposure in the main window */
- htmlPtr->flags |= REDRAW_BORDER;
- HtmlScheduleRedraw(htmlPtr);
- TestPoint(0);
- }
- break;
- case DestroyNotify:
- if( (htmlPtr->flags & REDRAW_PENDING) ){
- Tcl_CancelIdleCall(HtmlRedrawCallback, (ClientData)htmlPtr);
- htmlPtr->flags &= ~REDRAW_PENDING;
- }
- if( htmlPtr->tkwin != 0 ){
- if( eventPtr->xany.window!=Tk_WindowId(htmlPtr->tkwin) ){
- Tk_DestroyWindow(htmlPtr->tkwin);
- htmlPtr->clipwin = 0;
- break;
- }
- htmlPtr->tkwin = 0;
- Tcl_DeleteCommand(htmlPtr->interp, htmlPtr->zCmdName);
- Tcl_DeleteCommand(htmlPtr->interp, htmlPtr->zClipwin);
- }
- HtmlUnlock(htmlPtr);
- break;
- case ConfigureNotify:
- if( htmlPtr->tkwin!=0
- && eventPtr->xconfigure.window==Tk_WindowId(htmlPtr->tkwin)
- ){
- p = (XConfigureRequestEvent*)eventPtr;
- if( p->width != htmlPtr->realWidth ){
- redraw_needed = 1;
- htmlPtr->realWidth = p->width;
- TestPoint(0);
- }else{
- TestPoint(0);
- }
- if( p->height != htmlPtr->realHeight ){
- redraw_needed = 1;
- htmlPtr->realHeight = p->height;
- TestPoint(0);
- }else{
- TestPoint(0);
- }
- if( redraw_needed ){
- htmlPtr->flags |= RELAYOUT | VSCROLL | HSCROLL | RESIZE_CLIPWIN;
- HtmlRedrawEverything(htmlPtr);
- TestPoint(0);
- }else{
- TestPoint(0);
- }
- }
- break;
- case FocusIn:
- if( htmlPtr->tkwin!=0
- && eventPtr->xfocus.window==Tk_WindowId(htmlPtr->tkwin)
- && eventPtr->xfocus.detail != NotifyInferior
- ){
- htmlPtr->flags |= GOT_FOCUS | REDRAW_FOCUS;
- HtmlScheduleRedraw(htmlPtr);
- HtmlUpdateInsert(htmlPtr);
- TestPoint(0);
- }else{
- TestPoint(0);
- }
- break;
- case FocusOut:
- if( htmlPtr->tkwin!=0
- && eventPtr->xfocus.window==Tk_WindowId(htmlPtr->tkwin)
- && eventPtr->xfocus.detail != NotifyInferior
- ){
- htmlPtr->flags &= ~GOT_FOCUS;
- htmlPtr->flags |= REDRAW_FOCUS;
- HtmlScheduleRedraw(htmlPtr);
- TestPoint(0);
- }else{
- TestPoint(0);
- }
- break;
- }
-}
-
-
-/*
-** The rendering and layout routines should call this routine in order to get
-** a font structure. The iFont parameter specifies which of the N_FONT
-** fonts should be obtained. The font is allocated if necessary.
-**
-** Because the -fontcommand callback can be invoked, this function can
-** (in theory) cause the HTML widget to be changed arbitrarily or even
-** deleted. Callers of this function much be prepared to be called
-** recursively and/or to have the HTML widget deleted out from under
-** them. This routine will return NULL if the HTML widget is deleted.
-*/
-Tk_Font HtmlGetFont(
- HtmlWidget *htmlPtr, /* The HTML widget to which the font applies */
- int iFont /* Which font to obtain */
-){
- Tk_Font toFree = 0;
-
- if( iFont<0 ){ iFont = 0; TestPoint(0); }
- if( iFont>=N_FONT ){ iFont = N_FONT - 1; CANT_HAPPEN; }
-
- /*
- ** If the font has previously been allocated, but the "fontValid" bitmap
- ** shows it is no longer valid, then mark it for freeing later. We use
- ** a policy of allocate-before-free because Tk's font cache operates
- ** much more efficiently that way.
- */
- if( !FontIsValid(htmlPtr, iFont) && htmlPtr->aFont[iFont]!=0 ){
- toFree = htmlPtr->aFont[iFont];
- htmlPtr->aFont[iFont] = 0;
- TestPoint(0);
- }
-
- /*
- ** If we need to allocate a font, first construct the font name then
- ** allocate it.
- */
- if( htmlPtr->aFont[iFont]==0 ){
- char name[200]; /* Name of the font */
-
- name[0] = 0;
-
- /* Run the -fontcommand if it is specified
- */
- if( htmlPtr->zFontCommand && htmlPtr->zFontCommand[0] ){
- int iFam; /* The font family index. Value between 0 and 7 */
- Tcl_DString str; /* The command we'll execute to get the font name */
- char *zSep = ""; /* Separator between font attributes */
- int rc; /* Return code from the font command */
- char zBuf[100]; /* Temporary buffer */
-
- Tcl_DStringInit(&str);
- Tcl_DStringAppend(&str, htmlPtr->zFontCommand, -1);
- sprintf(zBuf, " %d {", FontSize(iFont)+1);
- Tcl_DStringAppend(&str,zBuf, -1);
- iFam = iFont / N_FONT_SIZE ;
- if( iFam & 1 ){
- Tcl_DStringAppend(&str,"bold",-1);
- zSep = " ";
- }
- if( iFam & 2 ){
- Tcl_DStringAppend(&str,zSep,-1);
- Tcl_DStringAppend(&str,"italic",-1);
- zSep = " ";
- }
- if( iFam & 4 ){
- Tcl_DStringAppend(&str,zSep,-1);
- Tcl_DStringAppend(&str,"fixed",-1);
- }
- Tcl_DStringAppend(&str,"}",-1);
- HtmlLock(htmlPtr);
- rc = Tcl_GlobalEval(htmlPtr->interp, Tcl_DStringValue(&str));
- Tcl_DStringFree(&str);
- if( HtmlUnlock(htmlPtr) ){
- return NULL;
- }
- if( rc!=TCL_OK ){
- Tcl_AddErrorInfo(htmlPtr->interp,
- "\n (-fontcommand callback of HTML widget)");
- Tcl_BackgroundError(htmlPtr->interp);
- }else{
- sprintf(name,"%.100s", Tcl_GetStringResult(htmlPtr->interp));
- }
- Tcl_ResetResult(htmlPtr->interp);
- }
-
- /*
- ** If the -fontcommand failed or returned an empty string, or if
- ** there is no -fontcommand, then get the default font name.
- */
- if( name[0]==0 ){
- char *familyStr = "";
- int iFamily;
- int iSize;
- int size;
-
- iFamily = iFont / N_FONT_SIZE;
- iSize = iFont % N_FONT_SIZE + 1;
- switch( iFamily ){
- case 0: familyStr = "helvetica -%d"; break;
- case 1: familyStr = "helvetica -%d bold"; break;
- case 2: familyStr = "helvetica -%d italic"; break;
- case 3: familyStr = "helvetica -%d bold italic"; break;
- case 4: familyStr = "courier -%d"; break;
- case 5: familyStr = "courier -%d bold"; break;
- case 6: familyStr = "courier -%d italic"; break;
- case 7: familyStr = "courier -%d bold italic"; break;
- default: familyStr = "helvetica -14"; CANT_HAPPEN;
- }
- switch( iSize ){
- case 1: size = 8; break;
- case 2: size = 10; break;
- case 3: size = 12; break;
- case 4: size = 14; break;
- case 5: size = 16; break;
- case 6: size = 18; break;
- case 7: size = 24; break;
- default: size = 14; CANT_HAPPEN;
- }
- sprintf(name, familyStr, size);
- }
-
- /* Get the named font
- */
- htmlPtr->aFont[iFont] = Tk_GetFont(htmlPtr->interp, htmlPtr->tkwin, name);
- if( htmlPtr->aFont[iFont]==0 ){
- Tcl_AddErrorInfo(htmlPtr->interp,
- "\n (trying to create a font named \"");
- Tcl_AddErrorInfo(htmlPtr->interp, name);
- Tcl_AddErrorInfo(htmlPtr->interp, "\" in the HTML widget)");
- Tcl_BackgroundError(htmlPtr->interp);
- htmlPtr->aFont[iFont] =
- Tk_GetFont(htmlPtr->interp, htmlPtr->tkwin, "fixed");
- }
- if( htmlPtr->aFont[iFont]==0 ){
- Tcl_AddErrorInfo(htmlPtr->interp,
- "\n (trying to create font \"fixed\" in the HTML widget)");
- Tcl_BackgroundError(htmlPtr->interp);
- htmlPtr->aFont[iFont] =
- Tk_GetFont(htmlPtr->interp, htmlPtr->tkwin, "helvetica -12");
- }
- FontSetValid(htmlPtr, iFont);
- TestPoint(0);
- }
-
- /*
- ** Free the expired font, if any.
- */
- if( toFree!=0 ){
- Tk_FreeFont(toFree);
- }
- return htmlPtr->aFont[iFont];
-}
-
-/*
-** Compute the squared distance between two colors
-*/
-static float colorDistance(XColor *pA, XColor *pB){
- float x, y, z;
-
- x = 0.30 * (pA->red - pB->red);
- y = 0.61 * (pA->green - pB->green);
- z = 0.11 * (pA->blue - pB->blue);
- TestPoint(0);
- return x*x + y*y + z*z;
-}
-
-/*
-** This routine returns an index between 0 and N_COLOR-1 which indicates
-** which XColor structure in the apColor[] array of htmlPtr should be
-** used to describe the color specified by the given name.
-*/
-int HtmlGetColorByName(HtmlWidget *htmlPtr, char *zColor){
- XColor *pNew;
- int iColor;
- Tk_Uid name;
- int i, n;
- char zAltColor[16];
-
- /* Netscape accepts color names that are just HEX values, without
- ** the # up front. This isn't valid HTML, but we support it for
- ** compatibility.
- */
- n = strlen(zColor);
-
- /* trucate any spaces on the end */
- while (n>0 && zColor[n-1]==' ') {
- zColor[n-1] = '\0';
- n--;
- }
-
- if( n==6 || n==3 || n==9 || n==12 ){
- for(i=0; i<n; i++){
- if( !isxdigit(zColor[i]) ) break;
- }
- if( i==n ){
- sprintf(zAltColor,"#%s",zColor);
- }else{
- strcpy(zAltColor, zColor);
- }
- name = Tk_GetUid(zAltColor);
- }else{
- name = Tk_GetUid(zColor);
- }
- pNew = Tk_GetColor(htmlPtr->interp, htmlPtr->clipwin, name);
- if( pNew==0 ){
- return 0; /* Color 0 is always the default */
- }
-
- iColor = GetColorByValue(htmlPtr, pNew);
- Tk_FreeColor(pNew);
- return iColor;
-}
-
-/*
-** Macros used in the computation of appropriate shadow colors.
-*/
-#define MAX_COLOR 65535
-#define MAX(A,B) ((A)<(B)?(B):(A))
-#define MIN(A,B) ((A)<(B)?(A):(B))
-
-/*
-** Check to see if the given color is too dark to be easily distinguished
-** from black.
-*/
-static int isDarkColor(XColor *p){
- float x, y, z;
-
- x = 0.50 * p->red;
- y = 1.00 * p->green;
- z = 0.28 * p->blue;
- return (x*x + y*y + z*z)<0.05*MAX_COLOR*MAX_COLOR;
-}
-
-/*
-** Given that the background color is iBgColor, figure out an
-** appropriate color for the dark part of a 3D shadow.
-*/
-int HtmlGetDarkShadowColor(HtmlWidget *htmlPtr, int iBgColor){
- if( htmlPtr->iDark[iBgColor]==0 ){
- XColor *pRef, val;
- pRef = htmlPtr->apColor[iBgColor];
- if( isDarkColor(pRef) ){
- int t1, t2;
- t1 = MIN(MAX_COLOR,pRef->red*1.2);
- t2 = (pRef->red*3 + MAX_COLOR)/4;
- val.red = MAX(t1,t2);
- t1 = MIN(MAX_COLOR,pRef->green*1.2);
- t2 = (pRef->green*3 + MAX_COLOR)/4;
- val.green = MAX(t1,t2);
- t1 = MIN(MAX_COLOR,pRef->blue*1.2);
- t2 = (pRef->blue*3 + MAX_COLOR)/4;
- val.blue = MAX(t1,t2);
- }else{
- val.red = pRef->red*0.6;
- val.green = pRef->green*0.6;
- val.blue = pRef->blue*0.6;
- }
- htmlPtr->iDark[iBgColor] = GetColorByValue(htmlPtr, &val) + 1;
- }
- return htmlPtr->iDark[iBgColor] - 1;
-}
-
-/*
-** Check to see if the given color is too light to be easily distinguished
-** from white.
-*/
-static int isLightColor(XColor *p){
- return p->green>=0.85*MAX_COLOR;
-}
-
-/*
-** Given that the background color is iBgColor, figure out an
-** appropriate color for the bright part of the 3D shadow.
-*/
-int HtmlGetLightShadowColor(HtmlWidget *htmlPtr, int iBgColor){
- if( htmlPtr->iLight[iBgColor]==0 ){
- XColor *pRef, val;
- pRef = htmlPtr->apColor[iBgColor];
- if( isLightColor(pRef) ){
- val.red = pRef->red*0.9;
- val.green = pRef->green*0.9;
- val.blue = pRef->blue*0.9;
- }else{
- int t1, t2;
- t1 = MIN(MAX_COLOR,pRef->green*1.4);
- t2 = (pRef->green + MAX_COLOR)/2;
- val.green = MAX(t1,t2);
- t1 = MIN(MAX_COLOR,pRef->red*1.4);
- t2 = (pRef->red + MAX_COLOR)/2;
- val.red = MAX(t1,t2);
- t1 = MIN(MAX_COLOR,pRef->blue*1.4);
- t2 = (pRef->blue + MAX_COLOR)/2;
- val.blue = MAX(t1,t2);
- }
- htmlPtr->iLight[iBgColor] = GetColorByValue(htmlPtr, &val) + 1;
- }
- return htmlPtr->iLight[iBgColor] - 1;
-}
-
-/*
-** Find a color integer for the color whose color components
-** are given by pRef.
-*/
-LOCAL int GetColorByValue(HtmlWidget *htmlPtr, XColor *pRef){
- int i;
- float dist;
- float closestDist;
- int closest;
- /*
- int r, g, b;
-# define COLOR_MASK 0xf800
- */
-
- XColor* q;
- q = Tk_GetColorByValue(htmlPtr->clipwin, pRef);
-
- /* Search for an exact match */
- /*
- r = pRef->red &= COLOR_MASK;
- g = pRef->green &= COLOR_MASK;
- b = pRef->blue &= COLOR_MASK;
- */
- for(i=0; i<N_COLOR; i++){
- XColor *p = htmlPtr->apColor[i];
- /*
- if( p && (p->red & COLOR_MASK)==r && (p->green & COLOR_MASK)==g
- && (p->blue & COLOR_MASK)==b ){
- */
- if (p && (q->red == p->red)
- && (q->green == p->green)
- && (q->blue == p->blue)) {
- htmlPtr->colorUsed |= (1<<i);
- Tk_FreeColor(q);
- return i;
- }
- }
- Tk_FreeColor(q);
-
- /* No exact matches. Look for a completely unused slot */
- for(i=N_PREDEFINED_COLOR; i<N_COLOR; i++){
- if( htmlPtr->apColor[i]==0 ){
- htmlPtr->apColor[i] = Tk_GetColorByValue(htmlPtr->clipwin, pRef);
- htmlPtr->colorUsed |= (1<<i);
- return i;
- }
- }
-
- /* No empty slots. Look for a slot that contains a color that
- ** isn't currently in use. */
- for(i=N_PREDEFINED_COLOR; i<N_COLOR; i++){
- if( ((htmlPtr->colorUsed >> i) & 1) == 0 ){
- Tk_FreeColor(htmlPtr->apColor[i]);
- htmlPtr->apColor[i] = Tk_GetColorByValue(htmlPtr->clipwin, pRef);
- htmlPtr->colorUsed |= (1<<i);
- return i;
- }
- }
-
- /* Ok, find the existing color that is closest to the color requested
- ** and use it. */
- closest = 0;
- closestDist = colorDistance(pRef, htmlPtr->apColor[0]);
- for(i=1; i<N_COLOR; i++){
- dist = colorDistance(pRef, htmlPtr->apColor[i]);
- if( dist < closestDist ){
- closestDist = dist;
- closest = i;
- }
- }
- return i;
-}
-
-/*
-** This routine searchs for a hyperlink beneath the coordinates x,y
-** and returns a pointer to the HREF for that hyperlink. The text
-** is held one of the markup.argv[] fields of the <a> markup.
-*/
-char *HtmlGetHref(HtmlWidget *htmlPtr, int x, int y){
- HtmlBlock *pBlock;
- HtmlElement *pElem;
-
- for(pBlock=htmlPtr->firstBlock; pBlock; pBlock=pBlock->pNext){
- if( pBlock->top > y || pBlock->bottom < y
- || pBlock->left > x || pBlock->right < x
- ){
- TestPoint(0);
- continue;
- }
- pElem = pBlock->base.pNext;
- if( (pElem->base.style.flags & STY_Anchor)==0 ){ TestPoint(0); continue; }
- switch( pElem->base.type ){
- case Html_Text:
- case Html_Space:
- case Html_IMG:
- while( pElem && pElem->base.type!=Html_A ){
- pElem = pElem->base.pPrev;
- }
- if( pElem==0 || pElem->base.type!=Html_A ){ break; }
- return HtmlMarkupArg(pElem,"href", 0);
- default:
- break;
- }
- }
- TestPoint(0);
- return 0;
-}
-
-/*
-** Change the "yOffset" field from its current value to the value given.
-** This has the effect of scrolling the widget vertically.
-*/
-void HtmlVerticalScroll(HtmlWidget *htmlPtr, int yOffset){
- int inset; /* The 3D border plus the pady */
- int h; /* Height of the clipping window */
- int diff; /* Difference between old and new offset */
- GC gc; /* Graphics context used for copying */
- int w; /* Width of text area */
-
- if( yOffset==htmlPtr->yOffset ){ TestPoint(0); return; }
- inset = htmlPtr->pady + htmlPtr->inset;
- h = htmlPtr->realHeight - 2*inset;
- if( (htmlPtr->flags & REDRAW_TEXT)!=0
- || (htmlPtr->dirtyTop < h && htmlPtr->dirtyBottom > 0)
- || htmlPtr->yOffset > yOffset + (h - 30)
- || htmlPtr->yOffset < yOffset - (h - 30)
- ){
- htmlPtr->yOffset = yOffset;
- htmlPtr->flags |= VSCROLL | REDRAW_TEXT;
- HtmlScheduleRedraw(htmlPtr);
- TestPoint(0);
- return;
- }
- diff = htmlPtr->yOffset - yOffset;
- gc = HtmlGetAnyGC(htmlPtr);
- w = htmlPtr->realWidth - 2*(htmlPtr->inset + htmlPtr->padx);
- htmlPtr->flags |= VSCROLL;
- htmlPtr->yOffset = yOffset;
-#ifndef MAC_OSX_TK
- if( diff < 0 ){
- XCopyArea(htmlPtr->display,
- Tk_WindowId(htmlPtr->clipwin), /* source */
- Tk_WindowId(htmlPtr->clipwin), /* destination */
- gc,
- 0, -diff, /* source X, Y */
- w, h + diff, /* Width and height */
- 0, 0); /* Destination X, Y */
- HtmlRedrawArea(htmlPtr, 0, h + diff, w, h);
- TestPoint(0);
- }else{
- XCopyArea(htmlPtr->display,
- Tk_WindowId(htmlPtr->clipwin), /* source */
- Tk_WindowId(htmlPtr->clipwin), /* destination */
- gc,
- 0, 0, /* source X, Y */
- w, h - diff, /* Width and height */
- 0, diff); /* Destination X, Y */
- HtmlRedrawArea(htmlPtr, 0, 0, w, diff);
- TestPoint(0);
- }
-#else
- HtmlRedrawArea(htmlPtr, 0, 0, w, h);
-#endif
- /* HtmlMapControls(htmlPtr);*/
-}
-
-/*
-** Change the "xOffset" field from its current value to the value given.
-** This has the effect of scrolling the widget horizontally.
-*/
-void HtmlHorizontalScroll(HtmlWidget *htmlPtr, int xOffset){
- if( xOffset==htmlPtr->xOffset ){ TestPoint(0); return; }
- htmlPtr->xOffset = xOffset;
- HtmlMapControls(htmlPtr);
- htmlPtr->flags |= HSCROLL | REDRAW_TEXT;
- HtmlScheduleRedraw(htmlPtr);
- TestPoint(0);
-}
-
-/*
-** The following array defines all possible widget command. The main
-** widget command function just parses up the command line, then vectors
-** control to one of the command service routines defined in the
-** following array:
-*/
-static struct HtmlSubcommand {
- char *zCmd1; /* First-level subcommand. Required */
- char *zCmd2; /* Second-level subcommand. May be NULL */
- int minArgc; /* Minimum number of arguments */
- int maxArgc; /* Maximum number of arguments */
- char *zHelp; /* Help string if wrong number of arguments */
- int (*xFunc)(HtmlWidget*,Tcl_Interp*,int,const char**); /* Cmd service routine */
-} aSubcommand[] = {
- { "cget", 0, 3, 3, "CONFIG-OPTION", HtmlCgetCmd },
- { "clear", 0, 2, 2, 0, HtmlClearCmd },
- { "configure", 0, 2, 0, "?ARGS...?", HtmlConfigCmd },
- { "href", 0, 4, 4, "X Y", HtmlHrefCmd },
- { "index", 0, 3, 3, "INDEX", HtmlIndexCmd },
- { "insert", 0, 3, 3, "INDEX", HtmlInsertCmd },
- { "names", 0, 2, 2, 0, HtmlNamesCmd },
- { "parse", 0, 3, 3, "HTML-TEXT", HtmlParseCmd },
- { "resolve", 0, 2, 0, "?URI ...?", HtmlResolveCmd },
- { "selection", "clear", 3, 3, 0, HtmlSelectionClearCmd},
- { 0, "set", 5, 5, "START END", HtmlSelectionSetCmd },
- { "text", "ascii", 5, 5, "START END", HtmlTextAsciiCmd},
- { 0, "delete", 5, 5, "START END", 0 },
- { 0, "html", 5, 5, "START END", 0 },
- { 0, "insert", 5, 5, "INDEX TEXT", 0 },
- { "token", "append", 5, 5, "TAG ARGUMENTS", 0 },
- { 0, "delete", 4, 5, "INDEX ?INDEX?", 0 },
- { 0, "find", 4, 6, "TAG ?before|after INDEX?", 0 },
- { 0, "get", 4, 5, "INDEX ?INDEX?", 0 },
- { 0, "handler", 4, 5, "TAG ?SCRIPT?", HtmlTokenHandlerCmd },
- { 0, "insert", 6, 6, "INDEX TAG ARGUMENTS", 0 },
- { 0, "list", 5, 5, "START END", HtmlTokenListCmd },
- { "xview", 0, 2, 5, "OPTIONS...", HtmlXviewCmd },
- { "yview", 0, 2, 5, "OPTIONS...", HtmlYviewCmd },
-#ifdef DEBUG
- { "debug", "dump", 5, 5, "START END", HtmlDebugDumpCmd },
- { 0, "testpt", 4, 4, "FILENAME", HtmlDebugTestPtCmd },
-#endif
-};
-#define nSubcommand (sizeof(aSubcommand)/sizeof(aSubcommand[0]))
-
-/*
-** This routine implements the command used by individual HTML widgets.
-*/
-static int HtmlWidgetCommand(
- ClientData clientData, /* The HTML widget data structure */
- Tcl_Interp *interp, /* Current interpreter. */
- int argc, /* Number of arguments. */
- const char **argv /* Argument strings. */
-){
- HtmlWidget *htmlPtr = (HtmlWidget*) clientData;
- size_t length;
- int c;
- int i;
- struct HtmlSubcommand *pCmd;
-
- if (argc < 2) {
- Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
- " option ?arg arg ...?\"", 0);
- TestPoint(0);
- return TCL_ERROR;
- }
- c = argv[1][0];
- length = strlen(argv[1]);
- for(i=0, pCmd=aSubcommand; i<nSubcommand; i++, pCmd++){
- if( pCmd->zCmd1==0 || c!=pCmd->zCmd1[0]
- || strncmp(pCmd->zCmd1,argv[1],length)!=0 ){
- TestPoint(0);
- continue;
- }
- if( pCmd->zCmd2 ){
- int length2;
- int j;
- if( argc<3 ){
- Tcl_AppendResult(interp, "wrong # args: should be \"",
- argv[0], " ", pCmd->zCmd1, " SUBCOMMAND ?OPTIONS...?", 0);
- TestPoint(0);
- return TCL_ERROR;
- }
- length2 = strlen(argv[2]);
- for(j=i; j<nSubcommand && (j==i || pCmd->zCmd1==0); j++, pCmd++){
- if( strncmp(pCmd->zCmd2,argv[2],length2)==0 ){
- TestPoint(0);
- break;
- }
- }
- if( j>=nSubcommand || (j!=i && aSubcommand[j].zCmd1!=0) ){
- Tcl_AppendResult(interp,"unknown subcommand \"", argv[2],
- "\" -- should be one of:", 0);
- for(j=i; j<nSubcommand && (j==i || aSubcommand[j].zCmd1==0); j++){
- Tcl_AppendResult(interp, " ", aSubcommand[j].zCmd2, 0);
- TestPoint(0);
- }
- return TCL_ERROR;
- }
- }
- if( argc<pCmd->minArgc || (argc>pCmd->maxArgc && pCmd->maxArgc>0) ){
- Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0],
- " ", pCmd->zCmd1, 0);
- if( pCmd->zCmd2 ){
- Tcl_AppendResult(interp, " ", pCmd->zCmd2, 0);
- TestPoint(0);
- }
- if( pCmd->zHelp ){
- Tcl_AppendResult(interp, " ", pCmd->zHelp, 0);
- TestPoint(0);
- }
- Tcl_AppendResult(interp, "\"", 0);
- TestPoint(0);
- return TCL_ERROR;
- }
- if( pCmd->xFunc==0 ){
- Tcl_AppendResult(interp,"command not yet implemented", 0);
- TestPoint(0);
- return TCL_ERROR;
- }
- TestPoint(0);
- return (*pCmd->xFunc)(htmlPtr, interp, argc, argv);
- }
- Tcl_AppendResult(interp,"unknown command \"", argv[1], "\" -- should be "
- "one of:", 0);
- for(i=0; i<nSubcommand; i++){
- if( aSubcommand[i].zCmd1==0 || aSubcommand[i].zCmd1[0]=='_' ){
- TestPoint(0);
- continue;
- }
- Tcl_AppendResult(interp, " ", aSubcommand[i].zCmd1, 0);
- TestPoint(0);
- }
- TestPoint(0);
- return TCL_ERROR;
-}
-
-/*
-** The following routine implements the Tcl "html" command. This command
-** is used to create new HTML widgets only. After the widget has been
-** created, it is manipulated using the widget command defined above.
-*/
-static int HtmlCommand(
- ClientData clientData, /* Main window */
- Tcl_Interp *interp, /* Current interpreter. */
- int argc, /* Number of arguments. */
- const char **argv /* Argument strings. */
-){
- int n, c;
- char *z;
-
- if (argc < 2) {
- Tcl_AppendResult(interp, "wrong # args: should be \"",
- argv[0], " pathName ?options?\"", (char *) NULL);
- return TCL_ERROR;
- }
- z = (char*)argv[1];
- n = strlen(z);
- c = z[0];
-
- /* If the first argument begins with ".", then it must be the
- ** name of a new window the user wants to create.
- */
- if( argv[1][0]=='.' ){
- HtmlWidget *htmlPtr;
- Tk_Window new;
- Tk_Window clipwin;
- char *zClipwin;
- Tk_Window tkwin = (Tk_Window)clientData;
- static int varId = 1; /* Used to construct unique names */
-
- new = Tk_CreateWindowFromPath(interp, tkwin, argv[1], (char *) NULL);
- if (new == NULL) {
- return TCL_ERROR;
- }
- zClipwin = HtmlAlloc( strlen(argv[1]) + 3 );
- if( zClipwin==0 ){
- Tk_DestroyWindow(new);
- return TCL_ERROR;
- }
- sprintf(zClipwin,"%s.x",argv[1]);
- clipwin = Tk_CreateWindowFromPath(interp, new, zClipwin, 0);
- if( clipwin==0 ){
- Tk_DestroyWindow(new);
- HtmlFree(zClipwin);
- return TCL_ERROR;
- }
-
- htmlPtr = HtmlAlloc(sizeof(HtmlWidget) + strlen(argv[1]) + 1);
- memset(htmlPtr, 0, sizeof(HtmlWidget));
- htmlPtr->tkwin = new;
- htmlPtr->clipwin = clipwin;
- htmlPtr->zClipwin = zClipwin;
- htmlPtr->display = Tk_Display(new);
- htmlPtr->interp = interp;
- htmlPtr->zCmdName = (char*)&htmlPtr[1];
- strcpy(htmlPtr->zCmdName, argv[1]);
- htmlPtr->relief = TK_RELIEF_FLAT;
- htmlPtr->dirtyLeft = LARGE_NUMBER;
- htmlPtr->dirtyTop = LARGE_NUMBER;
- htmlPtr->flags = RESIZE_CLIPWIN;
- htmlPtr->varId = varId++;
- Tcl_CreateCommand(interp, htmlPtr->zCmdName,
- HtmlWidgetCommand, (ClientData)htmlPtr, HtmlCmdDeletedProc);
- Tcl_CreateCommand(interp, htmlPtr->zClipwin,
- HtmlWidgetCommand, (ClientData)htmlPtr, HtmlCmdDeletedProc);
-
- Tk_SetClass(new,"Html");
- Tk_SetClass(clipwin,"HtmlClip");
- Tk_CreateEventHandler(htmlPtr->tkwin,
- ExposureMask|StructureNotifyMask|FocusChangeMask,
- HtmlEventProc, (ClientData) htmlPtr);
- Tk_CreateEventHandler(htmlPtr->clipwin,
- ExposureMask|StructureNotifyMask,
- HtmlEventProc, (ClientData) htmlPtr);
- if (ConfigureHtmlWidget(interp, htmlPtr, argc-2, argv+2, 0, 1) != TCL_OK) {
- goto error;
- }
- Tcl_SetResult(interp,Tk_PathName(htmlPtr->tkwin),NULL);
- return TCL_OK;
-
- error:
- Tk_DestroyWindow(htmlPtr->tkwin);
- return TCL_ERROR;
- }
-
- /* html reformat $from $to $text
- **
- ** Convert the format of text.
- */
- if( c=='r' && strncmp(z,"reformat",n)==0 ){
- if( argc!=5 ){
- Tcl_AppendResult(interp, "wrong # args: should be \"",
- argv[0], " reformat FROM TO TEXT", (char *) NULL);
- return TCL_ERROR;
- }
- Tcl_AppendResult(interp, "not yet implemented", 0);
- return TCL_ERROR;
- }else
-
-
- /* html urljoin $scheme $authority $path $query $fragment
- **
- ** Merge together the parts of a URL into a single value URL.
- */
- if( c=='u' && strncmp(z,"urljoin",n)==0 ){
- if( argc!=7 ){
- Tcl_AppendResult(interp, "wrong # args: should be \"",
- argv[0], " url join SCHEME AUTHORITY PATH QUERY FRAGMENT\"", 0);
- return TCL_ERROR;
- }
- Tcl_AppendResult(interp, "not yet implemented", 0);
- return TCL_ERROR;
- }else
-
-
- /* html urlsplit $url
- **
- ** Split a URL into a list of its parts.
- */
- if( c=='u' && strncmp(z,"urlsplit",n)==0 ){
- if( argc!=3 ){
- Tcl_AppendResult(interp, "wrong # args: should be \"",
- argv[0], " url split URL\"", 0);
- return TCL_ERROR;
- }
- Tcl_AppendResult(interp, "not yet implemented", 0);
- return TCL_ERROR;
- }else
-
- /* No match. Report an error.
- */
- {
- Tcl_AppendResult(interp, "unknown command \"", z, "\": should be "
- "a window name or one of: "
- "reformat urljoin urlsplit", 0);
- return TCL_ERROR;
- }
- return TCL_OK;
-}
-
-/*
-** The following mess is used to define DLL_EXPORT. DLL_EXPORT is
-** blank except when we are building a Windows95/NT DLL from this
-** library. Some special trickery is necessary to make this wall
-** work together with makeheaders.
-*/
-#if INTERFACE
-#define DLL_EXPORT
-#endif
-#if defined(USE_TCL_STUBS) && defined(__WIN32__)
-# undef DLL_EXPORT
-# define DLL_EXPORT __declspec(dllexport)
-#endif
-
-/*
-** This routine is used to register the "html" command with the
-** Tcl interpreter. This is the only routine in this file with
-** external linkage.
-*/
-DLL_EXPORT int Tkhtml1_Init(Tcl_Interp *interp) {
-
- if (Tcl_InitStubs(interp, TCL_PATCH_LEVEL, 0) == NULL)
- return TCL_ERROR;
-
- if (Tk_InitStubs(interp, TK_PATCH_LEVEL, 0) == NULL)
- return TCL_ERROR;
-
- Tcl_CreateCommand(interp,"html", HtmlCommand, Tk_MainWindow(interp), 0);
-
-#ifdef DEBUG
- Tcl_LinkVar(interp, "HtmlTraceMask", (char*)&HtmlTraceMask, TCL_LINK_INT);
-#endif
-
- if (Tcl_PkgProvide(interp, PACKAGE_NAME, PACKAGE_VERSION) != TCL_OK)
- return TCL_ERROR;
-
- return TCL_OK;
-}