home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / xfe / Microline3.0 / XmL / XmL.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  37.0 KB  |  1,537 lines

  1. /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. /*
  20.  * The following source code is part of the Microline Widget Library.
  21.  * The Microline widget library is made available to Mozilla developers
  22.  * under the Netscape Public License (NPL) by Neuron Data.  To learn
  23.  * more about Neuron Data, please visit the Neuron Data Home Page at
  24.  * http://www.neurondata.com.
  25.  */
  26.  
  27. #include <XmL/XmL.h>
  28. #include <Xm/XmP.h>
  29. #include <Xm/LabelP.h>
  30. #include <Xm/DrawnBP.h>
  31. #include <Xm/MessageB.h>
  32. #include <Xm/Protocols.h>
  33. #include <Xm/AtomMgr.h>
  34. #ifdef MOTIF11
  35. #include <Xm/VendorE.h>
  36. #else
  37. #include <Xm/VendorS.h>
  38. #endif
  39. #include <Xm/BulletinB.h>
  40. #include <Xm/MenuShell.h>
  41.  
  42. #include <stdlib.h>
  43. #include <stdio.h>
  44.  
  45. #ifdef SUNOS4
  46. int fprintf(FILE *, char *, ...);
  47. #endif
  48.  
  49. static void XmLDrawnBDestroyCB(Widget w, XtPointer clientData, XtPointer);
  50. static void XmLDrawnBDrawCB(Widget, XtPointer, XtPointer);
  51. static void XmLDrawnBDrawStringCB(Widget, XtPointer, XtPointer);
  52. static int XmLDrawCalc(Widget w, Dimension width, Dimension height,
  53.     unsigned char alignment, XRectangle *rect, XRectangle *clipRect,
  54.     int *x, int *y);
  55. static void XmLFontGetAverageWidth(XFontStruct *fs, short *width);
  56. static void XmLMessageBoxResponse(Widget, XtPointer, XtPointer);
  57. static void XmLMessageBoxWMDelete(Widget, XtPointer, XtPointer);
  58. static void XmLSortFunc(char *lvec, char *rvec);
  59.  
  60. struct _XmLArrayRec
  61.     {
  62.     char _autonumber, _growFast;
  63.     int _count, _size;
  64.     void **_items;
  65.     };
  66.  
  67. XmLArray
  68. XmLArrayNew(char autonumber,
  69.         char growFast)
  70.     {
  71.     XmLArray array;
  72.  
  73.     array = (XmLArray)malloc(sizeof(struct _XmLArrayRec));
  74.     array->_count = 0;
  75.     array->_size = 0;
  76.     array->_items = 0;
  77.     array->_autonumber = autonumber;
  78.     array->_growFast = growFast;
  79.     return array;
  80.     }
  81.  
  82. void
  83. XmLArrayFree(XmLArray array)
  84.     {
  85.     if (array->_items)
  86.         free((char *)array->_items);
  87.     free((char *)array);
  88.     }
  89.  
  90. void
  91. XmLArrayAdd(XmLArray array,
  92.         int pos,
  93.         int count)
  94.     {
  95.     int i;
  96.     void **items;
  97.  
  98.     if (count < 1)
  99.         return;
  100.     if (pos < 0 || pos > array->_count)
  101.         pos = array->_count;
  102.     if (array->_count + count >= array->_size)
  103.         {
  104.         if (array->_growFast)
  105.             {
  106.             if (!array->_size)
  107.                 array->_size = count + 256;
  108.             else
  109.                 array->_size = (array->_count + count) * 2;
  110.             }
  111.         else
  112.             array->_size = array->_count + count;
  113.         items = (void **)malloc(sizeof(void *) * array->_size);
  114.         if (array->_items)
  115.             {
  116.             for (i = 0; i < array->_count; i++)
  117.                 items[i] = array->_items[i];
  118.             free((char *)array->_items);
  119.             }
  120.         array->_items = items;
  121.         }
  122.     for (i = array->_count + count - 1; i >= pos + count; i--)
  123.         {
  124.         array->_items[i] = array->_items[i - count];
  125.         if (array->_autonumber)
  126.             ((XmLArrayItem *)array->_items[i])->pos = i;
  127.         }
  128.     for (i = pos; i < pos + count; i++)
  129.         array->_items[i] = 0;
  130.     array->_count += count;
  131.     }
  132.  
  133. int
  134. XmLArrayDel(XmLArray array,
  135.         int pos,
  136.         int count)
  137.     {
  138.     int i;
  139.  
  140.     if (pos < 0 || pos + count > array->_count)
  141.         return -1;
  142.     for (i = pos; i < array->_count - count; i++)
  143.         {
  144.         array->_items[i] = array->_items[i + count];
  145.         if (array->_autonumber)
  146.             ((XmLArrayItem *)array->_items[i])->pos = i;
  147.         }
  148.     array->_count -= count;
  149.     if (!array->_count)
  150.         {
  151.         if (array->_items)
  152.             free((char *)array->_items);
  153.         array->_items = 0;
  154.         array->_size = 0;
  155.         }
  156.     return 0;
  157.     }
  158.  
  159. int
  160. XmLArraySet(XmLArray array,
  161.         int pos,
  162.         void *item)
  163.     {
  164.     if (pos < 0 || pos >= array->_count)
  165.         return -1;
  166.     if (array->_items[pos])
  167.         fprintf(stderr, "XmLArraySet: warning: overwriting pointer\n");
  168.     array->_items[pos] = item;
  169.     if (array->_autonumber)
  170.         ((XmLArrayItem *)array->_items[pos])->pos = pos;
  171.     return 0;
  172.     }
  173.  
  174. void *
  175. XmLArrayGet(XmLArray array,
  176.         int pos)
  177.     {
  178.     if (pos < 0 || pos >= array->_count)
  179.         return 0;
  180.     return array->_items[pos];
  181.     }
  182.  
  183. int
  184. XmLArrayGetCount(XmLArray array)
  185.     {
  186.     return array->_count;
  187.     }
  188.  
  189. int
  190. XmLArrayMove(XmLArray array,
  191.          int newPos,
  192.          int pos,
  193.          int count)
  194.     {
  195.     void **items;
  196.     int i;
  197.  
  198.     if (count <= 0)
  199.         return -1;
  200.     if (newPos < 0 || newPos + count > array->_count)
  201.         return -1;
  202.     if (pos < 0 || pos + count > array->_count)
  203.         return -1;
  204.     if (pos == newPos)
  205.         return 0;
  206.     /* copy items to move */
  207.     items = (void **)malloc(sizeof(void *) * count);
  208.     for (i = 0; i < count; i++)
  209.         items[i] = array->_items[pos + i];
  210.     /* move real items around */
  211.     if (newPos < pos)
  212.         for (i = pos + count - 1; i >= newPos + count; i--)
  213.             {
  214.             array->_items[i] = array->_items[i - count];
  215.             if (array->_autonumber)
  216.                 ((XmLArrayItem *)array->_items[i])->pos = i;
  217.             }
  218.     else
  219.         for (i = pos; i < newPos; i++)
  220.             {
  221.             array->_items[i] = array->_items[i + count];
  222.             if (array->_autonumber)
  223.                 ((XmLArrayItem *)array->_items[i])->pos = i;
  224.             }
  225.     /* move items copy back */
  226.     for (i = 0; i < count; i++)
  227.         {
  228.         array->_items[newPos + i] = items[i];
  229.         if (array->_autonumber)
  230.             ((XmLArrayItem *)array->_items[newPos + i])->pos = newPos + i;
  231.         }
  232.     free((char *)items);
  233.     return 0;
  234.     }
  235.  
  236. int
  237. XmLArrayReorder(XmLArray array,
  238.         int *newPositions,
  239.         int pos,
  240.         int count)
  241.     {
  242.     int i;
  243.     void **items;
  244.  
  245.     if (count <= 0)
  246.         return -1;
  247.     if (pos < 0 || pos + count > array->_count)
  248.         return -1;
  249.     for (i = 0; i < count; i++)
  250.         {
  251.         if (newPositions[i] < pos || newPositions[i] >= pos + count)
  252.             return -1;
  253.         }
  254.     items = (void **)malloc(sizeof(void *) * count);
  255.     for (i = 0; i < count; i++)
  256.         items[i] = array->_items[newPositions[i]];
  257.     for (i = 0; i < count; i++)
  258.         {
  259.         array->_items[pos + i] = items[i];
  260.         if (array->_autonumber)
  261.             ((XmLArrayItem *)array->_items[pos + i])->pos = pos + i;
  262.         }
  263.     free((char *)items);
  264.     return 0;
  265.     }
  266.  
  267. int
  268. XmLArraySort(XmLArray array,
  269.          XmLArrayCompareFunc compare,
  270.          void *userData,
  271.          int pos,
  272.          int count)
  273.     {
  274.     int i;
  275.  
  276.     if (pos < 0 || pos + count > array->_count)
  277.         return -1;
  278.     XmLSort(&array->_items[pos], count, sizeof(void *),
  279.         (XmLSortCompareFunc)compare, userData);
  280.     if (array->_autonumber)
  281.         for (i = pos; i < pos + count; i++)
  282.             ((XmLArrayItem *)array->_items[i])->pos = i;
  283.     return 0;
  284.     }
  285.  
  286.  
  287. Boolean
  288. XmLCvtStringToUChar(Display *dpy,
  289.             char *resname,
  290.             XmLStringToUCharMap *map,
  291.             XrmValuePtr fromVal,
  292.             XrmValuePtr toVal)
  293. {
  294.     char *from;
  295.     int i, /*num,*/ valid;
  296.  
  297.     from = (char *)fromVal->addr;
  298.     valid = 0;
  299.     i = 0;
  300.     while (map[i].name)
  301.         {
  302.         if (!strcmp(from, map[i].name))
  303.             {
  304.             valid = 1;
  305.             break;
  306.             }
  307.         i++;
  308.         }
  309.     if (!valid)
  310.         {
  311.         XtDisplayStringConversionWarning(dpy, from, resname);
  312.         toVal->size = 0;
  313.         toVal->addr = 0;
  314.         return False;
  315.         }
  316.     if (toVal->addr)
  317.         {
  318.         if (toVal->size < sizeof(unsigned char))
  319.             {
  320.             toVal->size = sizeof(unsigned char);
  321.             return False;
  322.             }
  323.         *(unsigned char *)(toVal->addr) = map[i].value;
  324.         }
  325.     else
  326.         toVal->addr = (caddr_t)&map[i].value;
  327.     toVal->size = sizeof(unsigned char);
  328.     return True;
  329.     }
  330.  
  331. int
  332. XmLDateDaysInMonth(int m,
  333.            int y)
  334. {
  335.     static int d[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
  336.  
  337.     if (m < 1 || m > 12 || y < 1753 || y > 9999)
  338.         return -1;
  339.     if (m == 2 && (!((y % 4) && (y % 100)) || !(y % 400)))
  340.         return 29;
  341.     return d[m - 1];
  342. }
  343.  
  344. /* Calculation from Communications Of The ACM, Vol 6, No 8, p 444 */
  345. /* sun is 0, sat is 6 */
  346. int
  347. XmLDateWeekDay(int m,
  348.            int d,
  349.            int y)
  350. {
  351.     long jd, j1, j2;
  352.  
  353.     if (m < 1 || m > 12 || d < 1 || d > XmLDateDaysInMonth(m, y) ||
  354.         y < 1753 || y > 9999)
  355.         return -1;
  356.     if (m > 2)
  357.         m -= 3;
  358.     else
  359.         {
  360.         m += 9;
  361.         y--;
  362.         }
  363.     j1 = y / 100;
  364.     j2 = y - 100 * j1;
  365.     jd = (146097 * j1) / 4 + (1461 * j2) / 4 + (153 * m + 2) / 5 +
  366.         1721119 + d;
  367.         return (jd + 1) % 7;
  368. }
  369.  
  370. typedef struct
  371.     {
  372.     GC gc;
  373.     int type;
  374.     int dir;
  375.     XFontStruct *fontStruct;
  376.     } XmLDrawnBData;
  377.  
  378. void
  379. XmLDrawnButtonSetType(Widget w,
  380.               int drawnType,
  381.               int drawnDir)
  382.     {
  383.     XmLDrawnBData *dd;
  384.     XmDrawnButtonWidget b;
  385.     XmString str;
  386.     XmFontList fontlist;
  387.     XGCValues values;
  388.     XtGCMask mask;
  389.     Dimension width, height, dim;
  390.     Dimension highlightThickness, shadowThickness;
  391.     Dimension marginWidth, marginHeight;
  392.     Dimension marginTop, marginBottom, marginLeft, marginRight;
  393.  
  394.     if (!XtIsSubclass(w, xmDrawnButtonWidgetClass))
  395.         {
  396.         XmLWarning(w, "DrawnButtonSetType() - not an XmDrawnButton");
  397.         return;
  398.         }
  399.     XtVaSetValues(w,
  400.         XmNpushButtonEnabled, True,
  401.         NULL);
  402.     XtRemoveAllCallbacks(w, XmNexposeCallback);
  403.     XtRemoveAllCallbacks(w, XmNresizeCallback);
  404.     if (drawnType == XmDRAWNB_STRING && drawnDir == XmDRAWNB_RIGHT)
  405.         {
  406.         XtVaSetValues(w,
  407.             XmNlabelType, XmSTRING,
  408.             NULL);
  409.         return;
  410.         }
  411.     b = (XmDrawnButtonWidget)w;
  412.     dd = (XmLDrawnBData *)malloc(sizeof(XmLDrawnBData));
  413.     dd->type = drawnType;
  414.     dd->dir = drawnDir;
  415.     dd->gc = 0;
  416.     if (dd->type == XmDRAWNB_STRING)
  417.         {
  418.         XtVaGetValues(w,
  419.             XmNlabelString, &str,
  420.             XmNfontList, &fontlist,
  421.             XmNhighlightThickness, &highlightThickness,
  422.             XmNshadowThickness, &shadowThickness,
  423.             XmNmarginHeight, &marginHeight,
  424.             XmNmarginWidth, &marginWidth,
  425.             XmNmarginTop, &marginTop,
  426.             XmNmarginBottom, &marginBottom,
  427.             XmNmarginLeft, &marginLeft,
  428.             XmNmarginRight, &marginRight,
  429.             NULL);
  430.         if (!str && XtName(w))
  431.             str = XmStringCreateSimple(XtName(w));
  432.         if (!str)
  433.             str = XmStringCreateSimple("");
  434.         XmStringExtent(fontlist, str, &width, &height);
  435.         XmStringFree(str);
  436.         if (drawnDir == XmDRAWNB_UP || drawnDir == XmDRAWNB_DOWN)
  437.             {
  438.             dim = width;
  439.             width = height;
  440.             height = dim;
  441.             }
  442.         height += (highlightThickness + shadowThickness +
  443.             marginHeight) * 2 + marginTop + marginBottom;
  444.         width += (highlightThickness + shadowThickness +
  445.             marginWidth) * 2 + marginLeft + marginRight;
  446.         /* change to pixmap type so label string isnt drawn */
  447.         XtVaSetValues(w,
  448.             XmNlabelType, XmPIXMAP,
  449.             NULL);
  450.         XtVaSetValues(w,
  451.             XmNwidth, width,
  452.             XmNheight, height,
  453.             NULL);
  454.         XtAddCallback(w, XmNexposeCallback, XmLDrawnBDrawStringCB,
  455.             (XtPointer)dd);
  456.         XtAddCallback(w, XmNresizeCallback, XmLDrawnBDrawStringCB,
  457.             (XtPointer)dd);
  458.         }
  459.     else
  460.         {
  461.         mask = GCForeground;
  462.         values.foreground = b->primitive.foreground;
  463.         dd->gc = XtGetGC(w, mask, &values);
  464.         XtAddCallback(w, XmNexposeCallback, XmLDrawnBDrawCB, (XtPointer)dd);
  465.         XtAddCallback(w, XmNresizeCallback, XmLDrawnBDrawCB, (XtPointer)dd);
  466.         }
  467.     XtAddCallback(w, XmNdestroyCallback, XmLDrawnBDestroyCB, (XtPointer)dd);
  468.     }
  469.  
  470. static void
  471. XmLDrawnBDestroyCB(Widget w,
  472.            XtPointer clientData,
  473.            XtPointer callData)
  474.     {
  475.     XmLDrawnBData *dd;
  476.  
  477.     dd = (XmLDrawnBData *)clientData;
  478.     if (dd->type == XmDRAWNB_STRING)
  479.         {
  480.         if (dd->gc)
  481.             {
  482.             XFreeGC(XtDisplay(w), dd->gc);
  483.             XFreeFont(XtDisplay(w), dd->fontStruct);
  484.             }
  485.         }
  486.     else
  487.         XtReleaseGC(w, dd->gc);
  488.     free((char *)dd);
  489.     }
  490.  
  491. static void
  492. XmLDrawnBDrawStringCB(Widget w,
  493.               XtPointer clientData,
  494.               XtPointer callData)
  495.     {
  496.     XmLDrawnBData *dd;
  497.     XmFontList fontlist;
  498.     XmString str;
  499.     XmStringDirection stringDir;
  500.     unsigned char drawDir, alignment;
  501.     int width, height, xoff, yoff, drawWidth;
  502.     Pixel fg;
  503.     Dimension highlightThickness;
  504.     Dimension shadowThickness, marginWidth, marginHeight;
  505.     Dimension marginLeft, marginRight, marginTop, marginBottom;
  506.  
  507.     if (!XtIsRealized(w))
  508.         return;
  509.     dd = (XmLDrawnBData *)clientData;
  510.     XtVaGetValues(w,
  511.         XmNlabelString, &str,
  512.         NULL);
  513.     if (!str && XtName(w))
  514.         str = XmStringCreateSimple(XtName(w));
  515.     if (!str)
  516.         return;
  517.     XtVaGetValues(w,
  518.         XmNforeground, &fg,
  519.         XmNfontList, &fontlist,
  520.         XmNalignment, &alignment,
  521.         XmNhighlightThickness, &highlightThickness,
  522.         XmNshadowThickness, &shadowThickness,
  523.         XmNmarginWidth, &marginWidth,
  524.         XmNmarginHeight, &marginHeight, 
  525.         XmNmarginLeft, &marginLeft,
  526.         XmNmarginRight, &marginRight,
  527.         XmNmarginTop, &marginTop,
  528.         XmNmarginBottom, &marginBottom,
  529.         NULL);
  530.     xoff = highlightThickness + shadowThickness + marginLeft + marginWidth;
  531.     yoff = highlightThickness + shadowThickness + marginTop + marginHeight;
  532.     width = XtWidth(w) - xoff - xoff + marginLeft - marginRight;
  533.     height = XtHeight(w) - yoff - yoff + marginTop - marginBottom;
  534.     if (XmIsManager(XtParent(w)))
  535.         XtVaGetValues(XtParent(w),
  536.             XmNstringDirection, &stringDir,
  537.             NULL);
  538.     else
  539.         stringDir = XmSTRING_DIRECTION_L_TO_R;
  540.     switch (dd->dir)
  541.         {
  542.         case XmDRAWNB_LEFT:
  543.             drawDir = XmSTRING_LEFT;
  544.             break;
  545.         case XmDRAWNB_UP:
  546.             drawDir = XmSTRING_UP;
  547.             break;
  548.         case XmDRAWNB_DOWN:
  549.             drawDir = XmSTRING_DOWN;
  550.             break;
  551.         default:
  552.             drawDir = XmSTRING_RIGHT;
  553.             break;
  554.         }
  555.     if (drawDir == XmSTRING_LEFT || drawDir == XmSTRING_RIGHT)
  556.         drawWidth = width;
  557.     else
  558.         drawWidth = height;
  559.     if (!dd->gc)
  560.         {
  561.         dd->gc = XCreateGC(XtDisplay(w), XtWindow(w), 0, NULL);
  562.         dd->fontStruct = XLoadQueryFont(XtDisplay(w), "fixed");
  563.         if (!dd->fontStruct)
  564.             {
  565.             XmLWarning(w, "DrawnBDrawString() - FATAL can't load fixed font");
  566.             return;
  567.             }
  568.         XSetFont(XtDisplay(w), dd->gc, dd->fontStruct->fid);
  569.         }
  570.     XSetForeground(XtDisplay(w), dd->gc, fg);
  571.     XmLStringDrawDirection(XtDisplay(w), XtWindow(w), fontlist,
  572.         str, dd->gc, xoff, yoff, drawWidth, alignment, stringDir, drawDir);
  573.     XmStringFree(str);
  574.     }
  575.  
  576. static void
  577. XmLDrawnBDrawCB(Widget w,
  578.         XtPointer clientData,
  579.         XtPointer callData)
  580.     {
  581.     XmLDrawnBData *dd;
  582.     XmDrawnButtonWidget b;
  583.     /*    unsigned char drawDir;*/
  584.     /*    unsigned char alignment;*/
  585.     Display *dpy;
  586.     Window win;
  587.     GC gc;
  588.     XPoint p[2][5];
  589.     XSegment seg;
  590.     int np[2];
  591.     int i, j, temp;
  592.     int md, type, dir;
  593.     int avgx, avgy, xoff, yoff, st;
  594.  
  595.     if (!XtIsRealized(w))
  596.         return;
  597.     dd = (XmLDrawnBData *)clientData;
  598.     type = dd->type;
  599.     dir = dd->dir;
  600.     gc = dd->gc;
  601.     b = (XmDrawnButtonWidget)w;
  602.     win = XtWindow(w);
  603.     dpy = XtDisplay(w);
  604.     st = b->primitive.shadow_thickness;
  605.     i = st * 2 + b->primitive.highlight_thickness * 2;
  606.     /* calculate max dimension */
  607.     md = XtWidth(w) - i;
  608.     if (md > ((int)XtHeight(w) - i))
  609.         md = XtHeight(w) - i;
  610.     if (md < 4)
  611.         return;
  612.     xoff = ((int)XtWidth(w) - md) / 2;
  613.     yoff = ((int)XtHeight(w) - md) / 2;
  614.     np[0] = 0;
  615.     np[1] = 0;
  616.     switch (type)
  617.         {
  618.         case XmDRAWNB_ARROW:
  619.             p[0][0].x = md / 6;
  620.             p[0][0].y = md / 6;
  621.             p[0][1].x = md / 6;
  622.             p[0][1].y = md - md / 6;
  623.             p[0][2].x = md - md / 6;
  624.             p[0][2].y = md / 2;
  625.             np[0] = 3;
  626.             break;
  627.         case XmDRAWNB_ARROWLINE:
  628.             p[0][0].x = md / 5;
  629.             p[0][0].y = md / 5;
  630.             p[0][1].x = md / 5;
  631.             p[0][1].y = md - md / 5;
  632.             p[0][2].x = md - md / 5;
  633.             p[0][2].y = md / 2;
  634.             np[0] = 3;
  635.             p[1][0].x = md - md / 5 + 1;
  636.             p[1][0].y = md / 5;
  637.             p[1][1].x = md - md / 5 + 1;
  638.             p[1][1].y = md - md / 5;
  639.             p[1][2].x = md - md / 10;
  640.             p[1][2].y = md - md / 5;
  641.             p[1][3].x = md - md / 10;
  642.             p[1][3].y = md / 5;
  643.             np[1] = 4;
  644.             break;
  645.         case XmDRAWNB_DOUBLEARROW:
  646.             /* odd major dimensions can give jagged lines */
  647.             if (md % 2)
  648.                 md -= 1;
  649.             p[0][0].x = md / 10;
  650.             p[0][0].y = md / 10;
  651.             p[0][1].x = md / 10;
  652.             p[0][1].y = md - md / 10;
  653.             p[0][2].x = md / 2;
  654.             p[0][2].y = md / 2;
  655.             np[0] = 3;
  656.             p[1][0].x = md - md / 2;
  657.             p[1][0].y = md / 10;
  658.             p[1][1].x = md - md / 2;
  659.             p[1][1].y = md - md / 10;
  660.             p[1][2].x = md - md / 10;
  661.             p[1][2].y = md / 2;
  662.             np[1] = 3;
  663.             break;
  664.         case XmDRAWNB_SQUARE:
  665.             p[0][0].x = md / 3;
  666.             p[0][0].y = md / 3;
  667.             p[0][1].x = md / 3;
  668.             p[0][1].y = md - md / 3;
  669.             p[0][2].x = md - md / 3;
  670.             p[0][2].y = md - md / 3;
  671.             p[0][3].x = md - md / 3;
  672.             p[0][3].y = md / 3;
  673.             np[0] = 4;
  674.             break;
  675.         case XmDRAWNB_DOUBLEBAR:
  676.             p[0][0].x = md / 3;
  677.             p[0][0].y = md / 4;
  678.             p[0][1].x = md / 3;
  679.             p[0][1].y = md - md / 4;
  680.             p[0][2].x = md / 2 - md / 10;
  681.             p[0][2].y = md - md / 4;
  682.             p[0][3].x = md / 2 - md / 10;
  683.             p[0][3].y = md / 4;
  684.             np[0] = 4;
  685.             p[1][0].x = md - md / 3;
  686.             p[1][0].y = md / 4;
  687.             p[1][1].x = md - md / 3;
  688.             p[1][1].y = md - md / 4;
  689.             p[1][2].x = md - md / 2 + md / 10;
  690.             p[1][2].y = md - md / 4;
  691.             p[1][3].x = md - md / 2 + md / 10;
  692.             p[1][3].y = md / 4;
  693.             np[1] = 4;
  694.             break;
  695.         }
  696.     for (i = 0; i < 2; i++)
  697.         {
  698.         avgx = 0;
  699.         avgy = 0;
  700.         for (j = 0; j < np[i]; j++)
  701.             {
  702.             switch (dir)
  703.                 {
  704.                 case XmDRAWNB_RIGHT:
  705.                     /* points unchanged */
  706.                     break;
  707.                 case XmDRAWNB_LEFT:
  708.                     p[i][j].x = md - p[i][j].x;
  709.                     break;
  710.                 case XmDRAWNB_UP:
  711.                     temp = p[i][j].x;
  712.                     p[i][j].x = p[i][j].y;
  713.                     p[i][j].y = md - temp;
  714.                     break;
  715.                 case XmDRAWNB_DOWN:
  716.                     temp = p[i][j].x;
  717.                     p[i][j].x = p[i][j].y;
  718.                     p[i][j].y = temp;
  719.                     break;
  720.             }
  721.             p[i][j].x += xoff;
  722.             p[i][j].y += yoff;
  723.             avgx += p[i][j].x;
  724.             avgy += p[i][j].y;
  725.             }
  726.         if (!np[i])
  727.             continue;
  728.         avgx /= np[i];
  729.         avgy /= np[i];
  730.         XFillPolygon(dpy, win, gc, p[i], np[i], Nonconvex, CoordModeOrigin);
  731.         p[i][np[i]].x = p[i][0].x;
  732.         p[i][np[i]].y = p[i][0].y;
  733.         for (j = 0; j < np[i]; j++)
  734.             {
  735.             seg.x1 = p[i][j].x;
  736.             seg.y1 = p[i][j].y;
  737.             seg.x2 = p[i][j + 1].x;
  738.             seg.y2 = p[i][j + 1].y;
  739.             if ((seg.x1 <= avgx && seg.x2 <= avgx) ||
  740.                 (seg.y1 <= avgy && seg.y2 <= avgy))
  741.                 XDrawSegments(dpy, win,
  742.                     b->primitive.bottom_shadow_GC, &seg, 1);
  743.             else
  744.                 XDrawSegments(dpy, win,
  745.                     b->primitive.top_shadow_GC, &seg, 1);
  746.             }
  747.         }
  748.     }
  749.  
  750. #define XmLDrawNODRAW  0
  751. #define XmLDrawNOCLIP  1
  752. #define XmLDrawCLIPPED 2
  753.  
  754. static int
  755. XmLDrawCalc(Widget w,
  756.         Dimension width,
  757.         Dimension height,
  758.         unsigned char alignment,
  759.         XRectangle *rect,
  760.         XRectangle *clipRect,
  761.         int *x,
  762.         int *y)
  763.     {
  764.     if (rect->width <= 4 || rect->height <= 4 ||
  765.         clipRect->width < 3 || clipRect->height < 3 ||
  766.         !width || !height ||
  767.         !XtIsRealized(w) ||
  768.         XmLRectIntersect(rect, clipRect) == XmLRectOutside)
  769.         return XmLDrawNODRAW;
  770.     if (alignment == XmALIGNMENT_TOP_LEFT ||
  771.         alignment == XmALIGNMENT_LEFT ||
  772.         alignment == XmALIGNMENT_BOTTOM_LEFT)
  773.         *x = rect->x + 2;
  774.     else if (alignment == XmALIGNMENT_TOP ||
  775.         alignment == XmALIGNMENT_CENTER ||
  776.         alignment == XmALIGNMENT_BOTTOM)
  777.         *x = rect->x + ((int)rect->width - (int)width) / 2;
  778.     else
  779.         *x = rect->x + rect->width - width - 2;
  780.     if (alignment == XmALIGNMENT_TOP ||
  781.         alignment == XmALIGNMENT_TOP_LEFT ||
  782.         alignment == XmALIGNMENT_TOP_RIGHT)
  783.         *y = rect->y + 2;
  784.     else if (alignment == XmALIGNMENT_LEFT ||
  785.         alignment == XmALIGNMENT_CENTER ||
  786.         alignment == XmALIGNMENT_RIGHT)
  787.         *y = rect->y + ((int)rect->height - (int)height) / 2;
  788.     else
  789.         *y = rect->y + rect->height - height - 2;
  790.     if (clipRect->x == rect->x &&
  791.         clipRect->y == rect->y &&
  792.         clipRect->width == rect->width &&
  793.         clipRect->height == rect->height &&
  794.         (int)width + 4 <= (int)clipRect->width &&
  795.         (int)height + 4 <= (int)clipRect->height)
  796.         return XmLDrawNOCLIP;
  797.     return XmLDrawCLIPPED;
  798.     }
  799.  
  800. void
  801. XmLDrawToggle(Widget w,
  802.           Boolean state,
  803.           Dimension size,
  804.           unsigned char alignment,
  805.           GC gc,
  806.           Pixel backgroundColor,
  807.           Pixel topColor,
  808.           Pixel bottomColor,
  809.           Pixel checkColor,
  810.           XRectangle *rect,
  811.           XRectangle *clipRect)
  812.     {
  813.     Display *dpy;
  814.     Window win;
  815.     XPoint point[5];
  816.     int x, y, cx[3], cy[4], drawType;
  817.  
  818.     drawType = XmLDrawCalc(w, size, size, alignment, rect, clipRect, &x, &y);
  819.     if (size < 3 || drawType == XmLDrawNODRAW)
  820.         return;
  821.     dpy = XtDisplay(w);
  822.     win = XtWindow(w);
  823.     if (drawType == XmLDrawCLIPPED)
  824.         XSetClipRectangles(dpy, gc, 0, 0, clipRect, 1, Unsorted);
  825.     /* background */
  826.     XSetForeground(dpy, gc, backgroundColor);
  827.     XFillRectangle(dpy, win, gc, x, y, size, size);
  828.     /* box shadow */
  829.     XSetForeground(dpy, gc, topColor);
  830.     point[0].x = x;
  831.     point[0].y = y + size - 1;
  832.     point[1].x = x;
  833.     point[1].y = y;
  834.     point[2].x = x + size - 1;
  835.     point[2].y = y;
  836.     XDrawLines(dpy, win, gc, point, 3, CoordModeOrigin);
  837.     point[1].x = x + size - 1;
  838.     point[1].y = y + size - 1;
  839.     XSetForeground(dpy, gc, bottomColor);
  840.     XDrawLines(dpy, win, gc, point, 3, CoordModeOrigin);
  841.     if (state == True)
  842.         {
  843.         /* check */
  844.         cx[0] = x + 1;
  845.         cx[1] = x + (((int)size - 3) / 3) + 1;
  846.         cx[2] = x + size - 2;
  847.         cy[0] = y + 1;
  848.         cy[1] = y + (((int)size - 3) / 2) + 1;
  849.         cy[2] = y + ((((int)size - 3) * 2) / 3) + 1;
  850.         cy[3] = y + size - 2;
  851.         point[0].x = cx[0];
  852.         point[0].y = cy[1];
  853.         point[1].x = cx[1];
  854.         point[1].y = cy[3];
  855.         point[2].x = cx[2];
  856.         point[2].y = cy[0];
  857.         point[3].x = cx[1];
  858.         point[3].y = cy[2];
  859.         point[4].x = point[0].x;
  860.         point[4].y = point[0].y;
  861.         XSetForeground(dpy, gc, checkColor);
  862.         XFillPolygon(dpy, win, gc, point, 4, Nonconvex, CoordModeOrigin);
  863.         XDrawLines(dpy, win, gc, point, 5, CoordModeOrigin);
  864.         }
  865.     if (drawType == XmLDrawCLIPPED)
  866.         XSetClipMask(dpy, gc, None);
  867.     }
  868.  
  869. int
  870. XmLRectIntersect(XRectangle *r1,
  871.          XRectangle *r2)
  872.     {
  873.     if (!r1->width || !r1->height || !r2->width || !r2->height)
  874.         return XmLRectOutside;
  875.     if (r1->x + (int)r1->width - 1 < r2->x ||
  876.         r1->x > r2->x + (int)r2->width - 1 ||
  877.         r1->y + (int)r1->height - 1 < r2->y ||
  878.         r1->y > r2->y + (int)r2->height - 1)
  879.         return XmLRectOutside;
  880.     if (r1->x >= r2->x &&
  881.         r1->x + (int)r1->width <= r2->x + (int)r2->width &&
  882.         r1->y >= r2->y &&
  883.         r1->y + (int)r1->height <= r2->y + (int)r2->height)
  884.         return XmLRectInside; /* r1 inside r2 */
  885.     return XmLRectPartial;
  886.     }
  887.  
  888.  
  889. XmFontList
  890. XmLFontListCopyDefault(Widget widget)
  891.     {
  892.     Widget parent;
  893.     XFontStruct *font;
  894.     XmFontList fontList, fl;
  895.  
  896.     fontList = 0;
  897.     parent = XtParent(widget);
  898.     while (parent)
  899.         {
  900.         fl = 0;
  901.         if (XmIsVendorShell(parent) || XmIsMenuShell(parent))
  902.             XtVaGetValues(parent, XmNdefaultFontList, &fl, NULL);
  903.         else if (XmIsBulletinBoard(parent))
  904.             XtVaGetValues(parent, XmNbuttonFontList, &fl, NULL);
  905.         if (fl)
  906.             {
  907.             fontList = XmFontListCopy(fl);
  908.             parent = 0;
  909.             }
  910.         if (parent)
  911.             parent = XtParent(parent);
  912.         }
  913.     if (!fontList)
  914.         {
  915.         font = XLoadQueryFont(XtDisplay(widget), "fixed");
  916.         if (!font)
  917.             XmLWarning(widget,
  918.                 "FontListCopyDefault() - FATAL ERROR - can't load fixed font");
  919.         fontList = XmFontListCreate(font, XmSTRING_DEFAULT_CHARSET);
  920.         }
  921.     return fontList;
  922.     }
  923.  
  924. void
  925. XmLFontListGetDimensions(XmFontList fontList,
  926.              short *width,
  927.              short *height,
  928.              Boolean useAverageWidth)
  929.     {
  930.     XmStringCharSet charset;
  931.     XmFontContext context;
  932.     XFontStruct *fs;
  933.     short w, h;
  934. #if XmVersion < 2000
  935.     /* --- begin code to work around Motif 1.x internal bug */
  936.     typedef struct {
  937.         XmFontList nextFontList;
  938.         Boolean unused;
  939.     } XmFontListContextRec;
  940.     typedef struct {
  941.         XFontStruct *font;
  942.         XmStringCharSet unused;
  943.     } XmFontListRec;
  944.     XmFontList nextFontList;
  945. #endif
  946.  
  947.     *width = 0;
  948.     *height = 0;
  949.     if (XmFontListInitFontContext(&context, fontList))
  950.         {
  951.         while (1)
  952.             {
  953. #if XmVersion < 2000
  954.             /* --- begin code to work around Motif internal bug */
  955.             /* --- this code must be removed for Motif 2.0    */
  956.             nextFontList = ((XmFontListContextRec *)context)->nextFontList;
  957.             if (!nextFontList)
  958.                 break;
  959.             if (!((XmFontListRec *)nextFontList)->font)
  960.                 break;
  961.             /* --- end Motif workaround code */
  962. #endif
  963.             if (XmFontListGetNextFont(context, &charset, &fs) == False)
  964.                 break;
  965.             XtFree(charset);
  966.             if (useAverageWidth == True)
  967.                 XmLFontGetAverageWidth(fs, &w);
  968.             else
  969.                 w = fs->max_bounds.width;
  970.             h = fs->max_bounds.ascent + fs->max_bounds.descent;
  971.             if (*height < h)
  972.                 *height = h;
  973.             if (*width < w)
  974.                 *width = w;
  975.             }    
  976.         XmFontListFreeFontContext(context);
  977.         }
  978.     }
  979.  
  980. static void
  981. XmLFontGetAverageWidth(XFontStruct *fs,
  982.                short *width)
  983.     {
  984.     long aw, n;
  985.     int r, c, mm, i;
  986.     XCharStruct *cs;
  987.  
  988.     n = 0;
  989.     aw = 0;
  990.     mm = fs->max_char_or_byte2 - fs->min_char_or_byte2 + 1;
  991.     for (r = fs->min_byte1; r <= fs->max_byte1; r++)
  992.         for (c = fs->min_char_or_byte2; c <= fs->max_char_or_byte2; c++)
  993.             {
  994.             if (!fs->per_char)
  995.                 continue;
  996.             i = ((r - fs->min_byte1) * mm) + (c - fs->min_char_or_byte2);
  997.             cs = &fs->per_char[i];
  998.             if (!cs->width)
  999.                 continue;
  1000.             aw += cs->width;
  1001.             n++;
  1002.             }
  1003.     if (n)
  1004.         aw = aw / n;
  1005.     else
  1006.         aw = fs->min_bounds.width;
  1007.     *width = (short)aw;
  1008.     }
  1009.  
  1010. int _XmLKey;
  1011.  
  1012. void XmLInitialize(void)
  1013.     {
  1014.     static int first = 1;
  1015.     
  1016.     if (!first)
  1017.         return;
  1018.     first = 0;
  1019.  
  1020. #ifdef XmLEVAL
  1021.     fprintf(stderr, "XmL: This is an evalation version of the Microline\n");
  1022.     fprintf(stderr, "XmL: Widget Library.  Some features are disabled.\n");
  1023. #endif
  1024.  
  1025. #ifdef XmLJAVA
  1026.     if (_XmLKey != 444)
  1027.         {
  1028.         fprintf(stderr, "XmL: Error: This version of the library will only");
  1029.         fprintf(stderr, "XmL: work with JAVA.\n");
  1030.         exit(0);
  1031.         }
  1032. #endif
  1033.     }
  1034.  
  1035. int
  1036. XmLMessageBox(Widget w,
  1037.           char *string,
  1038.           Boolean okOnly)
  1039.     {
  1040.     int status = 0;
  1041.     Widget dialog, shell;
  1042.     Arg args[3];
  1043.     XtAppContext context;
  1044.     XmString str, titleStr;
  1045.     String shellTitle;
  1046.     Atom WM_DELETE_WINDOW;
  1047.  
  1048.     str = XmStringCreateLtoR(string, XmSTRING_DEFAULT_CHARSET);
  1049.     XtSetArg(args[0], XmNmessageString, str);
  1050.     XtSetArg(args[1], XmNdialogStyle, XmDIALOG_APPLICATION_MODAL);
  1051.     shell = XmLShellOfWidget(w);
  1052.     if (shell)
  1053.         XtVaGetValues(shell, XmNtitle, &shellTitle, NULL);
  1054.     if (shell && shellTitle)
  1055.         titleStr = XmStringCreateLtoR(shellTitle,
  1056.             XmSTRING_DEFAULT_CHARSET);
  1057.     else
  1058.         titleStr = XmStringCreateSimple("Notice");
  1059.     XtSetArg(args[2], XmNdialogTitle, titleStr);
  1060.     if (okOnly == True)
  1061.         dialog = XmCreateMessageDialog(XtParent(w), "popup", args, 3);
  1062.     else
  1063.         dialog = XmCreateQuestionDialog(XtParent(w), "popup", args, 3);
  1064.     WM_DELETE_WINDOW = XmInternAtom(XtDisplay(w), "WM_DELETE_WINDOW",
  1065.         False);
  1066.     XmAddWMProtocolCallback(shell, WM_DELETE_WINDOW, XmLMessageBoxWMDelete,
  1067.         (caddr_t)&status);
  1068.     XmStringFree(str);
  1069.     XmStringFree(titleStr);
  1070.     XtAddCallback(dialog, XmNokCallback, XmLMessageBoxResponse,
  1071.         (XtPointer)&status);
  1072.     if (okOnly == True)
  1073.         {
  1074.         XtUnmanageChild(XmMessageBoxGetChild(dialog,
  1075.             XmDIALOG_CANCEL_BUTTON));
  1076.         XtUnmanageChild(XmMessageBoxGetChild(dialog,
  1077.             XmDIALOG_HELP_BUTTON));
  1078.         }
  1079.     else
  1080.         {
  1081.         XtAddCallback(dialog, XmNcancelCallback, XmLMessageBoxResponse,
  1082.             (XtPointer)&status);
  1083.         XtAddCallback(dialog, XmNhelpCallback, XmLMessageBoxResponse,
  1084.             (XtPointer)&status);
  1085.         }
  1086.     XtManageChild(dialog);
  1087.  
  1088.     context = XtWidgetToApplicationContext(w);
  1089.     while (!status ||  XtAppPending(context))
  1090.         XtAppProcessEvent(context, XtIMAll);
  1091.     XtDestroyWidget(dialog);
  1092.     return status;
  1093.     }
  1094.  
  1095. static void
  1096. XmLMessageBoxWMDelete(Widget w,
  1097.               XtPointer clientData,
  1098.               XtPointer callData)
  1099.     {
  1100.     int *status = (int *)clientData;
  1101.     *status = 1;
  1102.     }
  1103.  
  1104. static void
  1105. XmLMessageBoxResponse(Widget w,
  1106.               XtPointer clientData,
  1107.               XtPointer callData)
  1108.     {
  1109.     int *status = (int *)clientData;
  1110.     XmAnyCallbackStruct *reason;
  1111.  
  1112.     reason = (XmAnyCallbackStruct *)callData;
  1113.     switch (reason->reason)
  1114.         {
  1115.         case XmCR_OK:
  1116.             *status = 1;
  1117.             break;
  1118.         case XmCR_CANCEL:
  1119.             *status = 2;
  1120.             break;
  1121.         case XmCR_HELP:
  1122.             *status = 3;
  1123.             break;
  1124.         }
  1125.     }
  1126.  
  1127. void
  1128. XmLPixmapDraw(Widget w,
  1129.           Pixmap pixmap,
  1130.           Pixmap pixmask,
  1131.           int pixmapWidth,
  1132.           int pixmapHeight,
  1133.           unsigned char alignment,
  1134.           GC gc,
  1135.           XRectangle *rect,
  1136.           XRectangle *clipRect)
  1137.     {
  1138.     Display *dpy;
  1139.     Window win;
  1140.     int px, py, x, y, width, height, drawType;
  1141.  
  1142.     if (pixmap == XmUNSPECIFIED_PIXMAP)
  1143.         return;
  1144.     dpy = XtDisplay(w);
  1145.     win = XtWindow(w);
  1146.     width = pixmapWidth;
  1147.     height = pixmapHeight;
  1148.     if (!width || !height)
  1149.         {
  1150.         alignment = XmALIGNMENT_TOP_LEFT;
  1151.         width = clipRect->width - 4;
  1152.         height = clipRect->height - 4;
  1153.         }
  1154.     drawType = XmLDrawCalc(w, width, height, alignment,
  1155.         rect, clipRect, &x, &y);
  1156.     if (drawType == XmLDrawNODRAW)
  1157.         return;
  1158.     px = 0;
  1159.     py = 0;
  1160.     /* clip top */
  1161.     if (clipRect->y > y && clipRect->y < y + height - 1)
  1162.         {
  1163.         py = clipRect->y - y;
  1164.         y += py;
  1165.         height -= py;
  1166.         }
  1167.     /* clip bottom */
  1168.     if (clipRect->y + (int)clipRect->height - 1 >= y &&
  1169.         clipRect->y + (int)clipRect->height - 1 <= y + height - 1)
  1170.         height = clipRect->y + clipRect->height - y;
  1171.     /* clip left */
  1172.     if (clipRect->x > x && clipRect->x < x + width - 1)
  1173.         {
  1174.         px = clipRect->x - x;
  1175.         x += px;
  1176.         width -= px;
  1177.         }
  1178.     /* clip right */
  1179.     if (clipRect->x + (int)clipRect->width - 1 >= x &&
  1180.         clipRect->x + (int)clipRect->width - 1 <= x + width - 1)
  1181.         width = clipRect->x + clipRect->width - x;
  1182.  
  1183.     if (pixmask != XmUNSPECIFIED_PIXMAP)
  1184.         {
  1185.         XSetClipMask(dpy, gc, pixmask);
  1186.         XSetClipOrigin(dpy, gc, x - px, y - py);
  1187.         }
  1188.     XSetGraphicsExposures(dpy, gc, False);
  1189.     XCopyArea(dpy, pixmap, win, gc, px, py, width, height, x, y);
  1190.     XSetGraphicsExposures(dpy, gc, True);
  1191.     if (pixmask != XmUNSPECIFIED_PIXMAP)
  1192.         {
  1193.         XSetClipMask(dpy, gc, None);
  1194.         XSetClipOrigin(dpy, gc, 0, 0);
  1195.         }
  1196.     }
  1197.  
  1198. Widget
  1199. XmLShellOfWidget(Widget w)
  1200.     {
  1201.     while(1)
  1202.         {
  1203.         if (!w)
  1204.             return 0;
  1205.         if (XtIsSubclass(w, shellWidgetClass))
  1206.             return w;
  1207.         w = XtParent(w);
  1208.         }    
  1209.     }
  1210.  
  1211. static XmLSortCompareFunc XmLSortCompare;
  1212. static int XmLSortEleSize;
  1213. static void *XmLSortUserData;
  1214.  
  1215. void
  1216. XmLSort(void *base,
  1217.     int numItems,
  1218.     unsigned int itemSize,
  1219.     XmLSortCompareFunc compare,
  1220.     void *userData)
  1221.     {
  1222.     XmLSortCompareFunc oldCompare;
  1223.     int oldEleSize;
  1224.     void *oldUserData;
  1225.     char *lvec, *rvec;
  1226.  
  1227.     if (numItems < 2)
  1228.         return;
  1229.  
  1230.     /* for sorts within a sort compare function, we must
  1231.        save any global sort variables on the local stack
  1232.        and restore them when finished */
  1233.     oldCompare = XmLSortCompare;
  1234.     oldEleSize = XmLSortEleSize;
  1235.     oldUserData = XmLSortUserData;
  1236.     XmLSortCompare = compare;
  1237.     XmLSortEleSize = itemSize;
  1238.     XmLSortUserData = userData;
  1239.  
  1240.     lvec = (char *)base;
  1241.     rvec = lvec + (numItems - 1) * itemSize;
  1242.     XmLSortFunc(lvec, rvec);
  1243.  
  1244.     XmLSortCompare = oldCompare;
  1245.     XmLSortEleSize = oldEleSize;
  1246.     XmLSortUserData = oldUserData;
  1247.     }
  1248.  
  1249. #define SWAP(p1, p2) \
  1250.         { \
  1251.         if (p1 != p2) \
  1252.             { \
  1253.             int zi; \
  1254.             char zc; \
  1255.             for (zi = 0; zi < XmLSortEleSize; zi++) \
  1256.                 { \
  1257.                 zc = (p1)[zi]; \
  1258.                 (p1)[zi] = (p2)[zi]; \
  1259.                 (p2)[zi] = zc; \
  1260.                 } \
  1261.             }\
  1262.         }
  1263.  
  1264. static void
  1265. XmLSortFunc(char *lvec,
  1266.         char *rvec)
  1267.     {
  1268.     int i;
  1269.     char *nlvec, *nrvec, *pvec;
  1270.  
  1271. start:
  1272.     i = (*XmLSortCompare)(XmLSortUserData, lvec, rvec);
  1273.  
  1274.     /* two item sort */
  1275.     if (rvec == lvec + XmLSortEleSize)
  1276.         {
  1277.         if (i > 0)
  1278.             SWAP(lvec, rvec)
  1279.         return;
  1280.         }
  1281.  
  1282.     /* find mid of three items */
  1283.     pvec = lvec + ((rvec - lvec) / (XmLSortEleSize * 2)) * XmLSortEleSize;
  1284.     if (i < 0)
  1285.         {
  1286.         i = (*XmLSortCompare)(XmLSortUserData, lvec, pvec);
  1287.         if (i > 0)
  1288.             pvec = lvec;
  1289.         else if (i == 0)
  1290.             pvec = rvec;
  1291.         }
  1292.     else if (i > 0)
  1293.         {
  1294.         i = (*XmLSortCompare)(XmLSortUserData, rvec, pvec);
  1295.         if (i > 0)
  1296.             pvec = rvec;
  1297.         else if (i == 0)
  1298.             pvec = lvec;
  1299.         }
  1300.     else
  1301.         {
  1302.         pvec = lvec + XmLSortEleSize;
  1303.         while (1)
  1304.             {
  1305.             i = (*XmLSortCompare)(XmLSortUserData, lvec, pvec);
  1306.             if (i < 0)
  1307.                 break;
  1308.             else if (i > 0)
  1309.                 {
  1310.                 pvec = lvec;
  1311.                 break;
  1312.                 }
  1313.             if (pvec == rvec)
  1314.                 return;
  1315.             pvec += XmLSortEleSize;
  1316.             }
  1317.         }
  1318.  
  1319.     /* partition the set */
  1320.     nlvec = lvec;
  1321.     nrvec = rvec;
  1322.     while (1)
  1323.         {
  1324.         if (pvec == nrvec)
  1325.             pvec = nlvec;
  1326.         else if (pvec == nlvec)
  1327.             pvec = nrvec;
  1328.         SWAP(nrvec, nlvec)
  1329.         while ((*XmLSortCompare)(XmLSortUserData, nlvec, pvec) < 0)
  1330.             nlvec += XmLSortEleSize;
  1331.         while ((*XmLSortCompare)(XmLSortUserData, nrvec, pvec) >= 0)
  1332.             nrvec -= XmLSortEleSize;
  1333.         if (nlvec > nrvec)
  1334.             break;
  1335.         }
  1336.  
  1337.     /* sort partitioned sets */
  1338.     if (lvec < nlvec - XmLSortEleSize)
  1339.         XmLSortFunc(lvec, nlvec - XmLSortEleSize);
  1340.     if (nlvec < rvec)
  1341.         {
  1342.         lvec = nlvec;
  1343.         goto start;
  1344.         }
  1345.     }
  1346.  
  1347. void
  1348. XmLStringDraw(Widget w,
  1349.           XmString string,
  1350.           XmStringDirection stringDir,
  1351.           XmFontList fontList,
  1352.           unsigned char alignment,
  1353.           GC gc,
  1354.           XRectangle *rect,
  1355.           XRectangle *clipRect)
  1356.     {
  1357.     Display *dpy;
  1358.     Window win;
  1359.     Dimension width, height;
  1360.     int x, y, drawType;
  1361.     unsigned char strAlignment;
  1362.  
  1363.     if (!string)
  1364.         return;
  1365.     dpy = XtDisplay(w);
  1366.     win = XtWindow(w);
  1367.     XmStringExtent(fontList, string, &width, &height);
  1368.     drawType = XmLDrawCalc(w, width, height, alignment,
  1369.         rect, clipRect, &x, &y);
  1370.     if (drawType == XmLDrawNODRAW)
  1371.         return;
  1372.     x = rect->x + 2;
  1373.     if (alignment == XmALIGNMENT_LEFT ||
  1374.         alignment == XmALIGNMENT_TOP_LEFT ||
  1375.         alignment == XmALIGNMENT_BOTTOM_LEFT)
  1376.         strAlignment = XmALIGNMENT_BEGINNING;
  1377.     else if (alignment == XmALIGNMENT_CENTER ||
  1378.         alignment == XmALIGNMENT_TOP ||
  1379.         alignment == XmALIGNMENT_BOTTOM)
  1380.         strAlignment = XmALIGNMENT_CENTER;
  1381.     else
  1382.         strAlignment = XmALIGNMENT_END;
  1383.     /* XmStringDraw clipping doesnt work in all cases
  1384.        so we use a clip region for clipping */
  1385.     if (drawType == XmLDrawCLIPPED)
  1386.         XSetClipRectangles(dpy, gc, 0, 0, clipRect, 1, Unsorted);
  1387.     XmStringDraw(dpy, win, fontList, string, gc,
  1388.         x, y, rect->width - 4, strAlignment, stringDir, clipRect);
  1389.     if (drawType == XmLDrawCLIPPED)
  1390.         XSetClipMask(dpy, gc, None);
  1391.     }
  1392.  
  1393. void
  1394. XmLStringDrawDirection(Display *dpy,
  1395.                Window win,
  1396.                XmFontList fontlist,
  1397.                XmString string,
  1398.                GC gc,
  1399.                int x,
  1400.                int y,
  1401.                Dimension width,
  1402.                unsigned char alignment,
  1403.                unsigned char layout_direction,
  1404.                unsigned char drawing_direction)
  1405. {
  1406.     Screen *screen;
  1407.     XFontStruct *fontStruct;
  1408.     XImage *sourceImage, *destImage;
  1409.     Pixmap pixmap;
  1410.     GC pixmapGC;
  1411.     /*    int sourceWidth, sourceHeight;*/
  1412.     int destWidth, destHeight;
  1413.     int stringWidth, stringHeight;
  1414.     int i, j, bytesPerLine;
  1415.     Dimension dW, dH;
  1416.     char *data;
  1417.  
  1418.     screen = DefaultScreenOfDisplay(dpy);
  1419.     XmStringExtent(fontlist, string, &dW, &dH);
  1420.     stringWidth = (int)dW;
  1421.     stringHeight = (int)dH;
  1422.     if (!stringWidth || !stringHeight)
  1423.         return;
  1424.  
  1425.     /* draw string into 1 bit deep pixmap */
  1426.     pixmap = XCreatePixmap(dpy, win, stringWidth, stringHeight, 1);
  1427.     pixmapGC = XCreateGC(dpy, pixmap, 0, NULL);
  1428.     fontStruct = XLoadQueryFont(dpy, "fixed");
  1429.     if (!fontStruct)
  1430.         {
  1431.         fprintf(stderr, "XmLStringDrawDirection: error - ");
  1432.         fprintf(stderr, "can't load fixed font\n");
  1433.         return;
  1434.         }
  1435.     XSetFont(dpy, pixmapGC, fontStruct->fid);
  1436.     XSetBackground(dpy, pixmapGC, 0L);
  1437.     XSetForeground(dpy, pixmapGC, 0L);
  1438.     XFillRectangle(dpy, pixmap, pixmapGC, 0, 0, stringWidth, stringHeight);
  1439.     XSetForeground(dpy, pixmapGC, 1L);
  1440.     XmStringDraw(dpy, pixmap, fontlist, string, pixmapGC, 0, 0, stringWidth,
  1441.         XmALIGNMENT_BEGINNING, layout_direction, 0);
  1442.     XFreeFont(dpy, fontStruct);
  1443.  
  1444.     /* copy 1 bit deep pixmap into source image */
  1445.     sourceImage = XGetImage(dpy, pixmap, 0, 0, stringWidth, stringHeight,
  1446.         1, XYPixmap);
  1447.     XFreePixmap(dpy, pixmap);
  1448.  
  1449.     /* draw rotated text into destination image */
  1450.     if (drawing_direction == XmSTRING_UP || drawing_direction == XmSTRING_DOWN)
  1451.         {
  1452.         destWidth = stringHeight;
  1453.         destHeight = stringWidth;
  1454.         }
  1455.     else
  1456.         {
  1457.         destWidth = stringWidth;
  1458.         destHeight = stringHeight;
  1459.         }
  1460.     bytesPerLine  = (destWidth - 1) / 8 + 1;
  1461.     data = (char *)malloc(bytesPerLine * destHeight);
  1462.     destImage = XCreateImage(dpy, DefaultVisualOfScreen(screen),
  1463.         1, XYBitmap, 0, data, destWidth, destHeight, 8, 0);
  1464.     for (i = 0; i < stringWidth; i++)
  1465.         for (j = 0; j < stringHeight; j++)
  1466.             {
  1467.             if (drawing_direction == XmSTRING_UP)
  1468.                 XPutPixel(destImage, j, i,
  1469.                     XGetPixel(sourceImage, stringWidth - i - 1, j));
  1470.             else if (drawing_direction == XmSTRING_DOWN)
  1471.                 XPutPixel(destImage, stringHeight - j - 1, stringWidth - i - 1,
  1472.                     XGetPixel(sourceImage, stringWidth - i - 1, j));
  1473.             else if (drawing_direction == XmSTRING_LEFT)
  1474.                 XPutPixel(destImage, i, stringHeight - j - 1,
  1475.                     XGetPixel(sourceImage, stringWidth - i - 1, j));
  1476.             else
  1477.                 XPutPixel(destImage, i, j,
  1478.                     XGetPixel(sourceImage, i, j));
  1479.             }
  1480.     XDestroyImage(sourceImage);
  1481.  
  1482.     /* copy rotated image into 1 bit deep pixmap */
  1483.     pixmap = XCreatePixmap(dpy, win, destWidth, destHeight, 1);
  1484.     XPutImage(dpy, pixmap, pixmapGC, destImage, 0, 0, 0, 0,
  1485.         destWidth, destHeight);
  1486.     XDestroyImage(destImage);
  1487.     XFreeGC(dpy, pixmapGC);
  1488.  
  1489.     /* adjust position for alignment */
  1490.     if (drawing_direction == XmSTRING_UP || drawing_direction == XmSTRING_DOWN)
  1491.         {
  1492.         if (alignment == XmALIGNMENT_BEGINNING)
  1493.             ;
  1494.         else if (alignment == XmALIGNMENT_CENTER)
  1495.             y += width / 2 - stringWidth / 2;
  1496.         else if (alignment == XmALIGNMENT_END)
  1497.             y += (int)width - stringWidth;
  1498.         }
  1499.     else
  1500.         {
  1501.         if (alignment == XmALIGNMENT_BEGINNING)
  1502.             ;
  1503.         else if (alignment == XmALIGNMENT_CENTER)
  1504.             x += width / 2 - stringWidth / 2;
  1505.         else if (alignment == XmALIGNMENT_END)
  1506.             x += (int)width - stringWidth;
  1507.         }
  1508.  
  1509.     /* draw the pixmap as a stipple in the window */
  1510.     XSetStipple(dpy, gc, pixmap);
  1511.     XSetFillStyle(dpy, gc, FillStippled);
  1512.     XSetTSOrigin(dpy, gc, x % destWidth, y % destHeight);
  1513.     XFillRectangle(dpy, win, gc, x, y, destWidth, destHeight);
  1514.     XFreePixmap(dpy, pixmap);
  1515.     XSetFillStyle(dpy, gc, FillSolid);
  1516.     }
  1517.  
  1518. void
  1519. XmLWarning(Widget w,
  1520.        char *msg)
  1521.     {
  1522.     XtAppContext app;
  1523.     char s[512], *cname, *name;
  1524.     WidgetClass c;
  1525.  
  1526.     app = XtWidgetToApplicationContext(w);
  1527.     name = XtName(w);
  1528.     if (!name)
  1529.         name = "[No Name]";
  1530.     c = XtClass(w);
  1531.     cname = c->core_class.class_name;
  1532.     if (!cname)
  1533.         cname = "[No Class]";
  1534.     sprintf(s, "%s: %s: %s\n", cname, name, msg);
  1535.     XtAppWarning(app, s);
  1536.     }
  1537.