home *** CD-ROM | disk | FTP | other *** search
/ Aminet 18 / aminetcdnumber181997.iso / Aminet / misc / emu / AROSdev.lha / AROS / config / linux / graphics_driver.c next >
Encoding:
C/C++ Source or Header  |  1997-01-27  |  13.5 KB  |  675 lines

  1. #include <X11/Xlib.h>
  2. #include <X11/Xutil.h>
  3. #include <X11/cursorfont.h>
  4.  
  5. #define DEBUG_FreeMem 1
  6.  
  7. #include <stdlib.h>
  8. #include <stdio.h>
  9. #include <string.h>
  10. #include <exec/memory.h>
  11. #include <clib/exec_protos.h>
  12. #include <graphics/rastport.h>
  13. #include <graphics/gfxbase.h>
  14. #include <graphics/text.h>
  15. #include <proto/graphics.h>
  16. #include <proto/aros.h>
  17. #include "graphics_intern.h"
  18.  
  19. #define static    /* nothing */
  20.  
  21. static Display         * sysDisplay;
  22. static int           sysScreen;
  23. static Cursor           sysCursor;
  24.  
  25. /* Table which links TextAttr with X11 font names */
  26. struct FontTable
  27. {
  28.     struct TextAttr ta;
  29.     char      * name;
  30. }
  31. AROSFontTable[] =
  32. {
  33.     { { "topaz.font",      8, FS_NORMAL, FPF_ROMFONT  }, "8x13bold" },
  34.     { { "topaz.font",     13, FS_NORMAL, FPF_ROMFONT  }, "8x13bold" },
  35.     { { "helvetica.font", 11, FS_NORMAL, FPF_DISKFONT }, "-adobe-helvetica-medium-r-normal--11-*-100-100-*-*-iso8859-1" },
  36.     { { "helvetica.font", 12, FS_NORMAL, FPF_DISKFONT }, "-adobe-helvetica-medium-r-normal--12-*-100-100-*-*-iso8859-1" },
  37.     { { "helvetica.font", 14, FS_NORMAL, FPF_DISKFONT }, "-adobe-helvetica-medium-r-normal--14-*-100-100-*-*-iso8859-1" },
  38. };
  39.  
  40. #define PEN_BITS    4
  41. #define NUM_COLORS  (1L << PEN_BITS)
  42. #define PEN_MASK    (NUM_COLORS - 1)
  43.  
  44. static const char * sysColName[NUM_COLORS] =
  45. {
  46.     "grey70",
  47.     "black",
  48.     "white",
  49.     "orange",
  50.  
  51.     "blue",
  52.     "green",
  53.     "red",
  54.     "cyan",
  55.  
  56.     "magenta",
  57.     "violet",
  58.     "brown",
  59.     "bisque",
  60.  
  61.     "lavender",
  62.     "navy",
  63.     "khaki",
  64.     "sienna",
  65. };
  66.  
  67. static long sysCMap[NUM_COLORS];
  68. static unsigned long sysPlaneMask;
  69.  
  70. struct ETextFont
  71. {
  72.     struct TextFont etf_Font;
  73.     XFontStruct     etf_XFS;
  74. };
  75.  
  76. #define ETF(tf)         ((struct ETextFont *)tf)
  77.  
  78. int driver_init (struct GfxBase * GfxBase)
  79. {
  80.     char * displayName;
  81.     Colormap cm;
  82.     XColor xc;
  83.     XColor fg, bg;
  84.     short t;
  85.     short depth;
  86.  
  87.     if (!(displayName = getenv ("DISPLAY")) )
  88.     displayName = ":0.0";
  89.  
  90.     if (!(sysDisplay = XOpenDisplay (displayName)) )
  91.     {
  92.     fprintf (stderr, "Cannot open display %s\n", displayName);
  93.     return False;
  94.     }
  95.  
  96.     sysScreen = DefaultScreen (sysDisplay);
  97.  
  98.     depth = DisplayPlanes (sysDisplay, sysScreen);
  99.     cm = DefaultColormap (sysDisplay, sysScreen);
  100.  
  101.     sysPlaneMask = 0;
  102.  
  103.     for (t=0; t < NUM_COLORS; t++)
  104.     {
  105.     if (depth == 1)
  106.     {
  107.         sysCMap[t] = !(t & 1) ?
  108.             WhitePixel(sysDisplay, sysScreen) :
  109.             BlackPixel(sysDisplay, sysScreen);
  110.     }
  111.     else
  112.     {
  113.         if (XParseColor (sysDisplay, cm, sysColName[t], &xc))
  114.         {
  115.         if (!XAllocColor (sysDisplay, cm, &xc))
  116.         {
  117.             fprintf (stderr, "Couldn't allocate color %s\n",
  118.                 sysColName[t]);
  119.             sysCMap[t] = !(t & 1) ?
  120.                 WhitePixel(sysDisplay, sysScreen) :
  121.                 BlackPixel(sysDisplay, sysScreen);
  122.         }
  123.  
  124.         sysCMap[t] = xc.pixel;
  125.  
  126.         if (t == 0)
  127.             bg = xc;
  128.         else if (t == 1)
  129.             fg = xc;
  130.         }
  131.         else
  132.         {
  133.         fprintf (stderr, "Couldn't get color %s\n", sysColName[t]);
  134.         }
  135.     }
  136.  
  137.     sysPlaneMask |= sysCMap[t];
  138.     }
  139.  
  140.     sysCursor = XCreateFontCursor (sysDisplay, XC_top_left_arrow);
  141.     XRecolorCursor (sysDisplay, sysCursor, &fg, &bg);
  142.  
  143.     return True;
  144. }
  145.  
  146. int driver_open (struct GfxBase * GfxBase)
  147. {
  148.     return True;
  149. }
  150.  
  151. void driver_close (struct GfxBase * GfxBase)
  152. {
  153.     return;
  154. }
  155.  
  156. void driver_expunge (struct GfxBase * GfxBase)
  157. {
  158.     return;
  159. }
  160.  
  161. GC GetGC (struct RastPort * rp)
  162. {
  163.     return (GC) rp->longreserved[0];
  164. }
  165.  
  166. int GetXWindow (struct RastPort * rp)
  167. {
  168.     return (int) rp->longreserved[1];
  169. }
  170.  
  171. void SetGC (struct RastPort * rp, GC gc)
  172. {
  173.     rp->longreserved[0] = (IPTR)gc;
  174. }
  175.  
  176. void SetXWindow (struct RastPort * rp, int win)
  177. {
  178.     rp->longreserved[1] = (IPTR)win;
  179. }
  180.  
  181. Display * GetSysDisplay (void)
  182. {
  183.     return sysDisplay;
  184. }
  185.  
  186. int GetSysScreen (void)
  187. {
  188.     return sysScreen;
  189. }
  190.  
  191. void UpdateLinePtrn (struct RastPort * rp)
  192. {
  193.     XGCValues gcval;
  194.  
  195.     if (!(rp->Flags & 0x10) )
  196.     return;
  197.  
  198.     if (rp->LinePtrn != 0xFFFF)
  199.     {
  200.     char dash_list[16];
  201.     int  n;
  202.     int  mode;
  203.     UWORD bit;
  204.  
  205.     bit=0x8000;
  206.     mode = (rp->LinePtrn & bit) != 0;
  207.     dash_list[0] = 0;
  208.  
  209.     for (n=0; bit; bit>>=1)
  210.     {
  211.         if (((rp->LinePtrn & bit) != 0) != mode)
  212.         {
  213.         mode = !mode;
  214.         n ++;
  215.         dash_list[n] = 0;
  216.         }
  217.  
  218.         dash_list[n] ++;
  219.     }
  220.  
  221.     gcval.line_style = LineOnOffDash;
  222.  
  223.     XChangeGC (sysDisplay
  224.         , GetGC(rp)
  225.         , GCLineStyle
  226.         , &gcval
  227.     );
  228.  
  229.     XSetDashes (sysDisplay
  230.         , GetGC(rp)
  231.         , 0
  232.         , dash_list
  233.         , n+1
  234.     );
  235.     }
  236.     else
  237.     {
  238.     gcval.line_style = LineSolid;
  239.  
  240.     XChangeGC (sysDisplay
  241.         , GetGC(rp)
  242.         , GCLineStyle
  243.         , &gcval
  244.     );
  245.  
  246.     }
  247.  
  248.     rp->Flags &= ~0x10;
  249. }
  250.  
  251. void driver_SetABPenDrMd (struct RastPort * rp, ULONG apen, ULONG bpen,
  252.     ULONG drmd, struct GfxBase * GfxBase)
  253. {
  254.     apen &= PEN_MASK;
  255.     bpen &= PEN_MASK;
  256.  
  257.     XSetForeground (sysDisplay, GetGC (rp), sysCMap[apen]);
  258.     XSetBackground (sysDisplay, GetGC (rp), sysCMap[bpen]);
  259.  
  260.     if (drmd & COMPLEMENT)
  261.     XSetFunction (sysDisplay, GetGC(rp), GXxor);
  262.     else
  263.     XSetFunction (sysDisplay, GetGC(rp), GXcopy);
  264. }
  265.  
  266. void driver_SetAPen (struct RastPort * rp, ULONG pen,
  267.             struct GfxBase * GfxBase)
  268. {
  269.     pen &= PEN_MASK;
  270.  
  271.     XSetForeground (sysDisplay, GetGC (rp), sysCMap[pen]);
  272. }
  273.  
  274. void driver_SetBPen (struct RastPort * rp, ULONG pen,
  275.             struct GfxBase * GfxBase)
  276. {
  277.     pen &= PEN_MASK;
  278.  
  279.     XSetBackground (sysDisplay, GetGC (rp), sysCMap[pen]);
  280. }
  281.  
  282. void driver_SetOutlinePen (struct RastPort * rp, ULONG pen,
  283.             struct GfxBase * GfxBase)
  284. {
  285. }
  286.  
  287. void driver_SetDrMd (struct RastPort * rp, ULONG mode,
  288.             struct GfxBase * GfxBase)
  289. {
  290.     if (mode & COMPLEMENT)
  291.     XSetFunction (sysDisplay, GetGC(rp), GXxor);
  292.     else
  293.     XSetFunction (sysDisplay, GetGC(rp), GXcopy);
  294. }
  295.  
  296. void driver_EraseRect (struct RastPort * rp, LONG x1, LONG y1, LONG x2, LONG y2,
  297.             struct GfxBase * GfxBase)
  298. {
  299.     XClearArea (sysDisplay, GetXWindow (rp),
  300.         x1, y1, x2-x1+1, y2-y1+1, False);
  301. }
  302.  
  303. void driver_RectFill (struct RastPort * rp, LONG x1, LONG y1, LONG x2, LONG y2,
  304.             struct GfxBase * GfxBase)
  305. {
  306.     if (rp->DrawMode & COMPLEMENT)
  307.     {
  308.     ULONG pen;
  309.  
  310.     pen = ((ULONG)(rp->FgPen)) & PEN_MASK;
  311.  
  312.     XSetForeground (sysDisplay, GetGC (rp), sysPlaneMask);
  313.  
  314.     XFillRectangle (sysDisplay, GetXWindow (rp), GetGC (rp),
  315.         x1, y1, x2-x1+1, y2-y1+1);
  316.  
  317.     XSetForeground (sysDisplay, GetGC (rp), sysCMap[pen]);
  318.     }
  319.     else
  320.     XFillRectangle (sysDisplay, GetXWindow (rp), GetGC (rp),
  321.         x1, y1, x2-x1+1, y2-y1+1);
  322. }
  323.  
  324. #define SWAP(a,b)       { a ^= b; b ^= a; a ^= b; }
  325. #define ABS(x)          ((x) < 0 ? -(x) : (x))
  326.  
  327. void driver_ScrollRaster (struct RastPort * rp, LONG dx, LONG dy,
  328.     LONG x1, LONG y1, LONG x2, LONG y2, struct GfxBase * GfxBase)
  329. {
  330.     LONG w, h, x3, y3, x4, y4, _dx_, _dy_;
  331.     ULONG apen = GetAPen (rp);
  332.  
  333.     if (!dx && !dy) return;
  334.  
  335.     if (x2 < x1) SWAP (x1,x2)
  336.     if (y2 < y1) SWAP (y1,y2)
  337.  
  338.     _dx_ = ABS(dx);
  339.     _dy_ = ABS(dy);
  340.  
  341.     x3 = x1 + _dx_;
  342.     y3 = y1 + _dy_;
  343.  
  344.     x4 = x2 - _dx_ +1;
  345.     y4 = y2 - _dy_ +1;
  346.  
  347.     w = x2 - x3 +1;
  348.     h = y2 - y3 +1;
  349.  
  350.     SetAPen (rp, rp->BgPen);
  351.  
  352.     if (dx <= 0) {
  353.     if (dy <= 0) {
  354.         XCopyArea (sysDisplay,GetXWindow(rp),GetXWindow(rp),GetGC(rp),
  355.             x1, y1, w, h, x3, y3);
  356.  
  357.         if (_dy_) XClearArea (sysDisplay,GetXWindow(rp),
  358.             x1, y1, w+_dx_, _dy_, FALSE);
  359.  
  360.         if (_dx_) XClearArea (sysDisplay,GetXWindow(rp),
  361.             x1, y1, _dx_, h, FALSE);
  362.  
  363.     } else { /* dy > 0 */
  364.         XCopyArea (sysDisplay,GetXWindow(rp),GetXWindow(rp),GetGC(rp),
  365.             x1, y3, w, h, x3, y1);
  366.  
  367.         XClearArea (sysDisplay,GetXWindow(rp),
  368.             x1, y4, w+_dx_, _dy_, FALSE);
  369.  
  370.         if (_dx_) XClearArea (sysDisplay,GetXWindow(rp),
  371.             x1, y1, _dx_, h, FALSE);
  372.     }
  373.     } else { /* dx > 0 */
  374.     if (dy <= 0) {
  375.         XCopyArea (sysDisplay,GetXWindow(rp),GetXWindow(rp),GetGC(rp),
  376.             x3, y1, w, h, x1, y3);
  377.  
  378.         if (_dy_) XClearArea (sysDisplay,GetXWindow(rp),
  379.             x1, y1, w+_dx_, _dy_, FALSE);
  380.  
  381.         XClearArea (sysDisplay,GetXWindow(rp),
  382.             x4, y3, _dx_, h, FALSE);
  383.     } else { /* dy > 0 */
  384.         XCopyArea (sysDisplay,GetXWindow(rp),GetXWindow(rp),GetGC(rp),
  385.             x3, y3, w, h, x1, y1);
  386.  
  387.         XClearArea (sysDisplay,GetXWindow(rp),
  388.             x1, y4, w+_dx_, _dy_, FALSE);
  389.  
  390.         XClearArea (sysDisplay,GetXWindow(rp),
  391.             x4, y1, _dx_, h, FALSE);
  392.     }
  393.     }
  394.  
  395.     SetAPen (rp, apen);
  396. }
  397.  
  398. void driver_DrawEllipse (struct RastPort * rp, LONG x, LONG y, LONG rx, LONG ry,
  399.         struct GfxBase * GfxBase)
  400. {
  401.     UpdateLinePtrn (rp);
  402.  
  403.     XDrawArc (sysDisplay, GetXWindow(rp), GetGC(rp),
  404.         x-rx, y-ry, rx*2, ry*2,
  405.         0, 360*64);
  406. }
  407.  
  408. void driver_Text (struct RastPort * rp, STRPTR string, LONG len,
  409.         struct GfxBase * GfxBase)
  410. {
  411.     if (rp->DrawMode & JAM2)
  412.     XDrawImageString (sysDisplay, GetXWindow(rp), GetGC(rp), rp->cp_x,
  413.         rp->cp_y, string, len);
  414.     else
  415.     XDrawString (sysDisplay, GetXWindow(rp), GetGC(rp), rp->cp_x,
  416.         rp->cp_y, string, len);
  417.  
  418.     rp->cp_x += TextLength (rp, string, len);
  419. }
  420.  
  421. WORD driver_TextLength (struct RastPort * rp, STRPTR string, ULONG len,
  422.             struct GfxBase * GfxBase)
  423. {
  424.     struct ETextFont * etf;
  425.  
  426.     etf = (struct ETextFont *)rp->Font;
  427.  
  428.     return XTextWidth (&etf->etf_XFS, string, len);
  429. }
  430.  
  431. void driver_Move (struct RastPort * rp, LONG x, LONG y,
  432.             struct GfxBase * GfxBase)
  433. {
  434.     return;
  435. }
  436.  
  437. void driver_Draw (struct RastPort * rp, LONG x, LONG y,
  438.             struct GfxBase * GfxBase)
  439. {
  440.     UpdateLinePtrn (rp);
  441.  
  442.     XDrawLine (sysDisplay, GetXWindow(rp), GetGC(rp),
  443.         rp->cp_x, rp->cp_y,
  444.         x, y);
  445. }
  446.  
  447. ULONG driver_ReadPixel (struct RastPort * rp, LONG x, LONG y,
  448.             struct GfxBase * GfxBase)
  449. {
  450.     XImage * image;
  451.     unsigned long pixel;
  452.     ULONG t;
  453.  
  454.     XSync(sysDisplay, False);
  455.  
  456.     image = XGetImage (sysDisplay
  457.     , GetXWindow(rp)
  458.     , x, y
  459.     , 1, 1
  460.     , AllPlanes
  461.     , ZPixmap
  462.     );
  463.  
  464.     if (!image)
  465.     return ((ULONG)-1L);
  466.  
  467.     pixel = XGetPixel (image, 0, 0);
  468.  
  469.     XDestroyImage (image);
  470.  
  471.     for (t=0; t<NUM_COLORS; t++)
  472.     if (pixel == sysCMap[t])
  473.         return t;
  474.  
  475.     return ((ULONG)-1L);
  476. }
  477.  
  478. LONG driver_WritePixel (struct RastPort * rp, LONG x, LONG y,
  479.             struct GfxBase * GfxBase)
  480. {
  481.     XDrawPoint (sysDisplay, GetXWindow(rp), GetGC(rp),
  482.         x, y);
  483.  
  484.     return 0;
  485. }
  486.  
  487. void driver_PolyDraw (struct RastPort * rp, LONG count, WORD * coords,
  488.             struct GfxBase * GfxBase)
  489. {
  490.     UpdateLinePtrn (rp);
  491.  
  492.     XDrawLines (sysDisplay, GetXWindow(rp), GetGC(rp),
  493.         (XPoint *)coords, count,
  494.         CoordModeOrigin
  495.     );
  496. }
  497.  
  498. void driver_SetRast (struct RastPort * rp, ULONG color,
  499.             struct GfxBase * GfxBase)
  500. {
  501.     XClearArea (sysDisplay, GetXWindow(rp),
  502.         0, 0,
  503.         1000, 1000,
  504.         FALSE);
  505. }
  506.  
  507. void driver_SetFont (struct RastPort * rp, struct TextFont * font,
  508.             struct GfxBase * GfxBase)
  509. {
  510.     if (GetGC(rp))
  511.     XSetFont (sysDisplay, GetGC(rp), ETF(font)->etf_XFS.fid);
  512.  
  513.     rp->Font       = font;
  514.     rp->TxWidth    = ETF(font)->etf_Font.tf_XSize;
  515.     rp->TxHeight   = ETF(font)->etf_Font.tf_YSize;
  516.     rp->TxBaseline = ETF(font)->etf_Font.tf_Baseline;
  517. }
  518.  
  519. struct TextFont * driver_OpenFont (struct TextAttr * ta,
  520.     struct GfxBase * GfxBase)
  521. {
  522.     struct ETextFont * tf;
  523.     XFontStruct      * xfs;
  524.     int t;
  525.     char * name;
  526.  
  527.     if (!ta->ta_Name)
  528.     return NULL;
  529.  
  530.     if (!(tf = AllocMem (sizeof (struct ETextFont), MEMF_ANY)) )
  531.     return (NULL);
  532.  
  533.     xfs = NULL;
  534.  
  535.     for (t=0; t<sizeof(AROSFontTable)/sizeof(AROSFontTable[0]); t++)
  536.     {
  537.     if (AROSFontTable[t].ta.ta_YSize == ta->ta_YSize
  538.         && !strcasecmp (AROSFontTable[t].ta.ta_Name, ta->ta_Name)
  539.     )
  540.     {
  541.         xfs = XLoadQueryFont (sysDisplay, AROSFontTable[t].name);
  542.         break;
  543.     }
  544.     }
  545.  
  546.     if (!xfs)
  547.     {
  548.     FreeMem (tf, sizeof (struct ETextFont));
  549.     return (NULL);
  550.     }
  551.  
  552.     tf->etf_XFS = *xfs;
  553.  
  554.     t = strlen (ta->ta_Name);
  555.  
  556.     name = AllocVec (t+1, MEMF_ANY);
  557.  
  558.     if (name)
  559.     strcpy (name, ta->ta_Name);
  560.     else
  561.     {
  562.     FreeMem (tf, sizeof (struct ETextFont));
  563.     return (NULL);
  564.     }
  565.  
  566.     tf->etf_Font.tf_Message.mn_Node.ln_Name = name;
  567.     tf->etf_Font.tf_YSize = tf->etf_XFS.max_bounds.ascent +
  568.             tf->etf_XFS.max_bounds.descent;
  569.     tf->etf_Font.tf_XSize = tf->etf_XFS.max_bounds.rbearing -
  570.             tf->etf_XFS.min_bounds.lbearing;
  571.     tf->etf_Font.tf_Baseline = tf->etf_XFS.ascent;
  572.     tf->etf_Font.tf_LoChar = tf->etf_XFS.min_char_or_byte2;
  573.     tf->etf_Font.tf_HiChar = tf->etf_XFS.max_char_or_byte2;
  574.  
  575.     if (!tf->etf_Font.tf_XSize || !tf->etf_Font.tf_YSize)
  576.     {
  577.     XUnloadFont (sysDisplay, tf->etf_XFS.fid);
  578.     FreeMem (tf, sizeof (struct ETextFont));
  579.     return (NULL);
  580.     }
  581.  
  582.     tf->etf_Font.tf_Accessors ++;
  583.  
  584.     return (struct TextFont *)tf;
  585. }
  586.  
  587. void driver_CloseFont (struct TextFont * tf, struct GfxBase * GfxBase)
  588. {
  589.     if (!ETF(tf)->etf_Font.tf_Accessors)
  590.     {
  591.     XUnloadFont (sysDisplay, ETF(tf)->etf_XFS.fid);
  592.     FreeVec (ETF(tf)->etf_Font.tf_Message.mn_Node.ln_Name);
  593.     FreeMem (tf, sizeof (struct ETextFont));
  594.     }
  595.     else
  596.     ETF(tf)->etf_Font.tf_Accessors --;
  597. }
  598.  
  599. int driver_InitRastPort (struct RastPort * rp, struct GfxBase * GfxBase)
  600. {
  601.     XGCValues gcval;
  602.     GC gc;
  603.  
  604.     gcval.plane_mask = sysPlaneMask;
  605.     gcval.graphics_exposures = True;
  606.  
  607.     gc = XCreateGC (sysDisplay
  608.     , DefaultRootWindow (sysDisplay)
  609.     , GCPlaneMask
  610.         | GCGraphicsExposures
  611.     , &gcval
  612.     );
  613.  
  614.     if (!gc)
  615.     return FALSE;
  616.  
  617.     SetGC (rp, gc);
  618.  
  619.     return TRUE;
  620. }
  621.  
  622. int driver_CloneRastPort (struct RastPort * newRP, struct RastPort * oldRP,
  623.             struct GfxBase * GfxBase)
  624. {
  625.     GC gc;
  626.  
  627.     gc = XCreateGC (sysDisplay
  628.     , GetXWindow (oldRP)
  629.     , 0L
  630.     , NULL
  631.     );
  632.  
  633.     if (!gc)
  634.     return FALSE;
  635.  
  636.     XCopyGC (sysDisplay, GetGC(oldRP), (1L<<(GCLastBit+1))-1, gc);
  637.     SetGC (newRP, gc);
  638.  
  639.     return TRUE;
  640. }
  641.  
  642. void driver_DeinitRastPort (struct RastPort * rp, struct GfxBase * GfxBase)
  643. {
  644.     GC gc;
  645.  
  646.     if ((gc = GetGC (rp)))
  647.     {
  648.     XFreeGC (sysDisplay, gc);
  649.  
  650.     SetGC (rp, NULL);
  651.     }
  652. }
  653.  
  654. ULONG driver_SetWriteMask (struct RastPort * rp, ULONG mask,
  655.             struct GfxBase * GfxBase)
  656. {
  657.     XGCValues gcval;
  658.     GC gc;
  659.  
  660.     if ((gc = GetGC (rp)))
  661.     {
  662.     gcval.plane_mask = sysPlaneMask;
  663.  
  664.     XChangeGC (sysDisplay
  665.         , gc
  666.         , GCPlaneMask
  667.         , &gcval
  668.     );
  669.  
  670.     return TRUE;
  671.     }
  672.  
  673.     return FALSE;
  674. }
  675.