gecko-dev/cmd/xfe/Microline3.0/XmL/XmL.c
1999-11-02 22:43:10 +00:00

1553 lines
36 KiB
C

/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
/*
* The following source code is part of the Microline Widget Library.
* The Microline widget library is made available to Mozilla developers
* under the Netscape Public License (NPL) by Neuron Data. To learn
* more about Neuron Data, please visit the Neuron Data Home Page at
* http://www.neurondata.com.
*/
#include <XmL/XmL.h>
#include <Xm/XmP.h>
#include <Xm/LabelP.h>
#include <Xm/DrawnBP.h>
#include <Xm/MessageB.h>
#include <Xm/Protocols.h>
#include <Xm/AtomMgr.h>
#ifdef MOTIF11
#include <Xm/VendorE.h>
#else
#include <Xm/VendorS.h>
#endif
#include <Xm/BulletinB.h>
#include <Xm/MenuShell.h>
#include <stdlib.h>
#include <stdio.h>
#ifdef SUNOS4
int fprintf(FILE *, char *, ...);
#endif
static void XmLDrawnBDestroyCB(Widget w, XtPointer clientData, XtPointer);
static void XmLDrawnBDrawCB(Widget, XtPointer, XtPointer);
static void XmLDrawnBDrawStringCB(Widget, XtPointer, XtPointer);
static int XmLDrawCalc(Widget w, Dimension width, Dimension height,
unsigned char alignment, XRectangle *rect, XRectangle *clipRect,
int *x, int *y);
static void XmLFontGetAverageWidth(XFontStruct *fs, short *width);
static void XmLMessageBoxResponse(Widget, XtPointer, XtPointer);
static void XmLMessageBoxWMDelete(Widget, XtPointer, XtPointer);
static void XmLSortFunc(char *lvec, char *rvec);
struct _XmLArrayRec
{
char _autonumber, _growFast;
int _count, _size;
void **_items;
};
XmLArray
XmLArrayNew(char autonumber,
char growFast)
{
XmLArray array;
array = (XmLArray)malloc(sizeof(struct _XmLArrayRec));
array->_count = 0;
array->_size = 0;
array->_items = 0;
array->_autonumber = autonumber;
array->_growFast = growFast;
return array;
}
void
XmLArrayFree(XmLArray array)
{
if (array->_items)
free((char *)array->_items);
free((char *)array);
}
void
XmLArrayAdd(XmLArray array,
int pos,
int count)
{
int i;
void **items;
if (count < 1)
return;
if (pos < 0 || pos > array->_count)
pos = array->_count;
if (array->_count + count >= array->_size)
{
if (array->_growFast)
{
if (!array->_size)
array->_size = count + 256;
else
array->_size = (array->_count + count) * 2;
}
else
array->_size = array->_count + count;
items = (void **)malloc(sizeof(void *) * array->_size);
if (array->_items)
{
for (i = 0; i < array->_count; i++)
items[i] = array->_items[i];
free((char *)array->_items);
}
array->_items = items;
}
for (i = array->_count + count - 1; i >= pos + count; i--)
{
array->_items[i] = array->_items[i - count];
if (array->_autonumber)
((XmLArrayItem *)array->_items[i])->pos = i;
}
for (i = pos; i < pos + count; i++)
array->_items[i] = 0;
array->_count += count;
}
int
XmLArrayDel(XmLArray array,
int pos,
int count)
{
int i;
if (pos < 0 || pos + count > array->_count)
return -1;
for (i = pos; i < array->_count - count; i++)
{
array->_items[i] = array->_items[i + count];
if (array->_autonumber)
((XmLArrayItem *)array->_items[i])->pos = i;
}
array->_count -= count;
if (!array->_count)
{
if (array->_items)
free((char *)array->_items);
array->_items = 0;
array->_size = 0;
}
return 0;
}
int
XmLArraySet(XmLArray array,
int pos,
void *item)
{
if (pos < 0 || pos >= array->_count)
return -1;
if (array->_items[pos])
fprintf(stderr, "XmLArraySet: warning: overwriting pointer\n");
array->_items[pos] = item;
if (array->_autonumber)
((XmLArrayItem *)array->_items[pos])->pos = pos;
return 0;
}
void *
XmLArrayGet(XmLArray array,
int pos)
{
if (pos < 0 || pos >= array->_count)
return 0;
return array->_items[pos];
}
int
XmLArrayGetCount(XmLArray array)
{
return array->_count;
}
int
XmLArrayMove(XmLArray array,
int newPos,
int pos,
int count)
{
void **items;
int i;
if (count <= 0)
return -1;
if (newPos < 0 || newPos + count > array->_count)
return -1;
if (pos < 0 || pos + count > array->_count)
return -1;
if (pos == newPos)
return 0;
/* copy items to move */
items = (void **)malloc(sizeof(void *) * count);
for (i = 0; i < count; i++)
items[i] = array->_items[pos + i];
/* move real items around */
if (newPos < pos)
for (i = pos + count - 1; i >= newPos + count; i--)
{
array->_items[i] = array->_items[i - count];
if (array->_autonumber)
((XmLArrayItem *)array->_items[i])->pos = i;
}
else
for (i = pos; i < newPos; i++)
{
array->_items[i] = array->_items[i + count];
if (array->_autonumber)
((XmLArrayItem *)array->_items[i])->pos = i;
}
/* move items copy back */
for (i = 0; i < count; i++)
{
array->_items[newPos + i] = items[i];
if (array->_autonumber)
((XmLArrayItem *)array->_items[newPos + i])->pos = newPos + i;
}
free((char *)items);
return 0;
}
int
XmLArrayReorder(XmLArray array,
int *newPositions,
int pos,
int count)
{
int i;
void **items;
if (count <= 0)
return -1;
if (pos < 0 || pos + count > array->_count)
return -1;
for (i = 0; i < count; i++)
{
if (newPositions[i] < pos || newPositions[i] >= pos + count)
return -1;
}
items = (void **)malloc(sizeof(void *) * count);
for (i = 0; i < count; i++)
items[i] = array->_items[newPositions[i]];
for (i = 0; i < count; i++)
{
array->_items[pos + i] = items[i];
if (array->_autonumber)
((XmLArrayItem *)array->_items[pos + i])->pos = pos + i;
}
free((char *)items);
return 0;
}
int
XmLArraySort(XmLArray array,
XmLArrayCompareFunc compare,
void *userData,
int pos,
int count)
{
int i;
if (pos < 0 || pos + count > array->_count)
return -1;
XmLSort(&array->_items[pos], count, sizeof(void *),
(XmLSortCompareFunc)compare, userData);
if (array->_autonumber)
for (i = pos; i < pos + count; i++)
((XmLArrayItem *)array->_items[i])->pos = i;
return 0;
}
Boolean
XmLCvtStringToUChar(Display *dpy,
char *resname,
XmLStringToUCharMap *map,
XrmValuePtr fromVal,
XrmValuePtr toVal)
{
char *from;
int i, /*num,*/ valid;
from = (char *)fromVal->addr;
valid = 0;
i = 0;
while (map[i].name)
{
if (!strcmp(from, map[i].name))
{
valid = 1;
break;
}
i++;
}
if (!valid)
{
XtDisplayStringConversionWarning(dpy, from, resname);
toVal->size = 0;
toVal->addr = 0;
return False;
}
if (toVal->addr)
{
if (toVal->size < sizeof(unsigned char))
{
toVal->size = sizeof(unsigned char);
return False;
}
*(unsigned char *)(toVal->addr) = map[i].value;
}
else
toVal->addr = (caddr_t)&map[i].value;
toVal->size = sizeof(unsigned char);
return True;
}
int
XmLDateDaysInMonth(int m,
int y)
{
static int d[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
if (m < 1 || m > 12 || y < 1753 || y > 9999)
return -1;
if (m == 2 && (!((y % 4) && (y % 100)) || !(y % 400)))
return 29;
return d[m - 1];
}
/* Calculation from Communications Of The ACM, Vol 6, No 8, p 444 */
/* sun is 0, sat is 6 */
int
XmLDateWeekDay(int m,
int d,
int y)
{
long jd, j1, j2;
if (m < 1 || m > 12 || d < 1 || d > XmLDateDaysInMonth(m, y) ||
y < 1753 || y > 9999)
return -1;
if (m > 2)
m -= 3;
else
{
m += 9;
y--;
}
j1 = y / 100;
j2 = y - 100 * j1;
jd = (146097 * j1) / 4 + (1461 * j2) / 4 + (153 * m + 2) / 5 +
1721119 + d;
return (jd + 1) % 7;
}
typedef struct
{
GC gc;
int type;
int dir;
XFontStruct *fontStruct;
} XmLDrawnBData;
void
XmLDrawnButtonSetType(Widget w,
int drawnType,
int drawnDir)
{
XmLDrawnBData *dd;
XmDrawnButtonWidget b;
XmString str;
XmFontList fontlist;
XGCValues values;
XtGCMask mask;
Dimension width, height, dim;
Dimension highlightThickness, shadowThickness;
Dimension marginWidth, marginHeight;
Dimension marginTop, marginBottom, marginLeft, marginRight;
if (!XtIsSubclass(w, xmDrawnButtonWidgetClass))
{
XmLWarning(w, "DrawnButtonSetType() - not an XmDrawnButton");
return;
}
XtVaSetValues(w,
XmNpushButtonEnabled, True,
NULL);
XtRemoveAllCallbacks(w, XmNexposeCallback);
XtRemoveAllCallbacks(w, XmNresizeCallback);
if (drawnType == XmDRAWNB_STRING && drawnDir == XmDRAWNB_RIGHT)
{
XtVaSetValues(w,
XmNlabelType, XmSTRING,
NULL);
return;
}
b = (XmDrawnButtonWidget)w;
dd = (XmLDrawnBData *)malloc(sizeof(XmLDrawnBData));
dd->type = drawnType;
dd->dir = drawnDir;
dd->gc = 0;
if (dd->type == XmDRAWNB_STRING)
{
XtVaGetValues(w,
XmNlabelString, &str,
XmNfontList, &fontlist,
XmNhighlightThickness, &highlightThickness,
XmNshadowThickness, &shadowThickness,
XmNmarginHeight, &marginHeight,
XmNmarginWidth, &marginWidth,
XmNmarginTop, &marginTop,
XmNmarginBottom, &marginBottom,
XmNmarginLeft, &marginLeft,
XmNmarginRight, &marginRight,
NULL);
if (!str && XtName(w))
str = XmStringCreateSimple(XtName(w));
if (!str)
str = XmStringCreateSimple("");
XmStringExtent(fontlist, str, &width, &height);
XmStringFree(str);
if (drawnDir == XmDRAWNB_UP || drawnDir == XmDRAWNB_DOWN)
{
dim = width;
width = height;
height = dim;
}
height += (highlightThickness + shadowThickness +
marginHeight) * 2 + marginTop + marginBottom;
width += (highlightThickness + shadowThickness +
marginWidth) * 2 + marginLeft + marginRight;
/* change to pixmap type so label string isnt drawn */
XtVaSetValues(w,
XmNlabelType, XmPIXMAP,
NULL);
XtVaSetValues(w,
XmNwidth, width,
XmNheight, height,
NULL);
XtAddCallback(w, XmNexposeCallback, XmLDrawnBDrawStringCB,
(XtPointer)dd);
XtAddCallback(w, XmNresizeCallback, XmLDrawnBDrawStringCB,
(XtPointer)dd);
}
else
{
mask = GCForeground;
values.foreground = b->primitive.foreground;
dd->gc = XtGetGC(w, mask, &values);
XtAddCallback(w, XmNexposeCallback, XmLDrawnBDrawCB, (XtPointer)dd);
XtAddCallback(w, XmNresizeCallback, XmLDrawnBDrawCB, (XtPointer)dd);
}
XtAddCallback(w, XmNdestroyCallback, XmLDrawnBDestroyCB, (XtPointer)dd);
}
static void
XmLDrawnBDestroyCB(Widget w,
XtPointer clientData,
XtPointer callData)
{
XmLDrawnBData *dd;
dd = (XmLDrawnBData *)clientData;
if (dd->type == XmDRAWNB_STRING)
{
if (dd->gc)
{
XFreeGC(XtDisplay(w), dd->gc);
XFreeFont(XtDisplay(w), dd->fontStruct);
}
}
else
XtReleaseGC(w, dd->gc);
free((char *)dd);
}
static void
XmLDrawnBDrawStringCB(Widget w,
XtPointer clientData,
XtPointer callData)
{
XmLDrawnBData *dd;
XmFontList fontlist;
XmString str;
XmStringDirection stringDir;
unsigned char drawDir, alignment;
int width, height, xoff, yoff, drawWidth;
Pixel fg;
Dimension highlightThickness;
Dimension shadowThickness, marginWidth, marginHeight;
Dimension marginLeft, marginRight, marginTop, marginBottom;
if (!XtIsRealized(w))
return;
dd = (XmLDrawnBData *)clientData;
XtVaGetValues(w,
XmNlabelString, &str,
NULL);
if (!str && XtName(w))
str = XmStringCreateSimple(XtName(w));
if (!str)
return;
XtVaGetValues(w,
XmNforeground, &fg,
XmNfontList, &fontlist,
XmNalignment, &alignment,
XmNhighlightThickness, &highlightThickness,
XmNshadowThickness, &shadowThickness,
XmNmarginWidth, &marginWidth,
XmNmarginHeight, &marginHeight,
XmNmarginLeft, &marginLeft,
XmNmarginRight, &marginRight,
XmNmarginTop, &marginTop,
XmNmarginBottom, &marginBottom,
NULL);
xoff = highlightThickness + shadowThickness + marginLeft + marginWidth;
yoff = highlightThickness + shadowThickness + marginTop + marginHeight;
width = XtWidth(w) - xoff - xoff + marginLeft - marginRight;
height = XtHeight(w) - yoff - yoff + marginTop - marginBottom;
if (XmIsManager(XtParent(w)))
XtVaGetValues(XtParent(w),
XmNstringDirection, &stringDir,
NULL);
else
stringDir = XmSTRING_DIRECTION_L_TO_R;
switch (dd->dir)
{
case XmDRAWNB_LEFT:
drawDir = XmSTRING_LEFT;
break;
case XmDRAWNB_UP:
drawDir = XmSTRING_UP;
break;
case XmDRAWNB_DOWN:
drawDir = XmSTRING_DOWN;
break;
default:
drawDir = XmSTRING_RIGHT;
break;
}
if (drawDir == XmSTRING_LEFT || drawDir == XmSTRING_RIGHT)
drawWidth = width;
else
drawWidth = height;
if (!dd->gc)
{
dd->gc = XCreateGC(XtDisplay(w), XtWindow(w), 0, NULL);
dd->fontStruct = XLoadQueryFont(XtDisplay(w), "fixed");
if (!dd->fontStruct)
{
XmLWarning(w, "DrawnBDrawString() - FATAL can't load fixed font");
return;
}
XSetFont(XtDisplay(w), dd->gc, dd->fontStruct->fid);
}
XSetForeground(XtDisplay(w), dd->gc, fg);
XmLStringDrawDirection(XtDisplay(w), XtWindow(w), fontlist,
str, dd->gc, xoff, yoff, drawWidth, alignment, stringDir, drawDir);
XmStringFree(str);
}
static void
XmLDrawnBDrawCB(Widget w,
XtPointer clientData,
XtPointer callData)
{
XmLDrawnBData *dd;
XmDrawnButtonWidget b;
/* unsigned char drawDir;*/
/* unsigned char alignment;*/
Display *dpy;
Window win;
GC gc;
XPoint p[2][5];
XSegment seg;
int np[2];
int i, j, temp;
int md, type, dir;
int avgx, avgy, xoff, yoff, st;
if (!XtIsRealized(w))
return;
dd = (XmLDrawnBData *)clientData;
type = dd->type;
dir = dd->dir;
gc = dd->gc;
b = (XmDrawnButtonWidget)w;
win = XtWindow(w);
dpy = XtDisplay(w);
st = b->primitive.shadow_thickness;
i = st * 2 + b->primitive.highlight_thickness * 2;
/* calculate max dimension */
md = XtWidth(w) - i;
if (md > ((int)XtHeight(w) - i))
md = XtHeight(w) - i;
if (md < 4)
return;
xoff = ((int)XtWidth(w) - md) / 2;
yoff = ((int)XtHeight(w) - md) / 2;
np[0] = 0;
np[1] = 0;
switch (type)
{
case XmDRAWNB_SMALLARROW:
p[0][0].x = md / 4;
p[0][0].y = md / 4;
p[0][1].x = md / 4;
p[0][1].y = md - md / 4;
p[0][2].x = md - md / 4;
p[0][2].y = md / 2;
np[0] = 3;
break;
case XmDRAWNB_ARROW:
p[0][0].x = md / 6;
p[0][0].y = md / 6;
p[0][1].x = md / 6;
p[0][1].y = md - md / 6;
p[0][2].x = md - md / 6;
p[0][2].y = md / 2;
np[0] = 3;
break;
case XmDRAWNB_ARROWLINE:
p[0][0].x = md / 5;
p[0][0].y = md / 5;
p[0][1].x = md / 5;
p[0][1].y = md - md / 5;
p[0][2].x = md - md / 5;
p[0][2].y = md / 2;
np[0] = 3;
p[1][0].x = md - md / 5 + 1;
p[1][0].y = md / 5;
p[1][1].x = md - md / 5 + 1;
p[1][1].y = md - md / 5;
p[1][2].x = md - md / 10;
p[1][2].y = md - md / 5;
p[1][3].x = md - md / 10;
p[1][3].y = md / 5;
np[1] = 4;
break;
case XmDRAWNB_DOUBLEARROW:
/* odd major dimensions can give jagged lines */
if (md % 2)
md -= 1;
p[0][0].x = md / 10;
p[0][0].y = md / 10;
p[0][1].x = md / 10;
p[0][1].y = md - md / 10;
p[0][2].x = md / 2;
p[0][2].y = md / 2;
np[0] = 3;
p[1][0].x = md - md / 2;
p[1][0].y = md / 10;
p[1][1].x = md - md / 2;
p[1][1].y = md - md / 10;
p[1][2].x = md - md / 10;
p[1][2].y = md / 2;
np[1] = 3;
break;
case XmDRAWNB_SQUARE:
p[0][0].x = md / 3;
p[0][0].y = md / 3;
p[0][1].x = md / 3;
p[0][1].y = md - md / 3;
p[0][2].x = md - md / 3;
p[0][2].y = md - md / 3;
p[0][3].x = md - md / 3;
p[0][3].y = md / 3;
np[0] = 4;
break;
case XmDRAWNB_DOUBLEBAR:
p[0][0].x = md / 3;
p[0][0].y = md / 4;
p[0][1].x = md / 3;
p[0][1].y = md - md / 4;
p[0][2].x = md / 2 - md / 10;
p[0][2].y = md - md / 4;
p[0][3].x = md / 2 - md / 10;
p[0][3].y = md / 4;
np[0] = 4;
p[1][0].x = md - md / 3;
p[1][0].y = md / 4;
p[1][1].x = md - md / 3;
p[1][1].y = md - md / 4;
p[1][2].x = md - md / 2 + md / 10;
p[1][2].y = md - md / 4;
p[1][3].x = md - md / 2 + md / 10;
p[1][3].y = md / 4;
np[1] = 4;
break;
}
for (i = 0; i < 2; i++)
{
avgx = 0;
avgy = 0;
for (j = 0; j < np[i]; j++)
{
switch (dir)
{
case XmDRAWNB_RIGHT:
/* points unchanged */
break;
case XmDRAWNB_LEFT:
p[i][j].x = md - p[i][j].x - 1;
break;
case XmDRAWNB_UP:
temp = p[i][j].x;
p[i][j].x = p[i][j].y;
p[i][j].y = md - temp;
break;
case XmDRAWNB_DOWN:
temp = p[i][j].x;
p[i][j].x = p[i][j].y;
p[i][j].y = temp;
break;
}
p[i][j].x += xoff;
p[i][j].y += yoff;
avgx += p[i][j].x;
avgy += p[i][j].y;
}
if (!np[i])
continue;
avgx /= np[i];
avgy /= np[i];
XFillPolygon(dpy, win, gc, p[i], np[i], Nonconvex, CoordModeOrigin);
p[i][np[i]].x = p[i][0].x;
p[i][np[i]].y = p[i][0].y;
for (j = 0; j < np[i]; j++)
{
seg.x1 = p[i][j].x;
seg.y1 = p[i][j].y;
seg.x2 = p[i][j + 1].x;
seg.y2 = p[i][j + 1].y;
if ((seg.x1 <= avgx && seg.x2 <= avgx) ||
(seg.y1 <= avgy && seg.y2 <= avgy))
XDrawSegments(dpy, win,
b->primitive.bottom_shadow_GC, &seg, 1);
else
XDrawSegments(dpy, win,
b->primitive.top_shadow_GC, &seg, 1);
}
}
}
#define XmLDrawNODRAW 0
#define XmLDrawNOCLIP 1
#define XmLDrawCLIPPED 2
static int
XmLDrawCalc(Widget w,
Dimension width,
Dimension height,
unsigned char alignment,
XRectangle *rect,
XRectangle *clipRect,
int *x,
int *y)
{
if (rect->width <= 4 || rect->height <= 4 ||
clipRect->width < 3 || clipRect->height < 3 ||
!width || !height ||
!XtIsRealized(w) ||
XmLRectIntersect(rect, clipRect) == XmLRectOutside)
return XmLDrawNODRAW;
if (alignment == XmALIGNMENT_TOP_LEFT ||
alignment == XmALIGNMENT_LEFT ||
alignment == XmALIGNMENT_BOTTOM_LEFT)
*x = rect->x + 2;
else if (alignment == XmALIGNMENT_TOP ||
alignment == XmALIGNMENT_CENTER ||
alignment == XmALIGNMENT_BOTTOM)
*x = rect->x + ((int)rect->width - (int)width) / 2;
else
*x = rect->x + rect->width - width - 2;
if (alignment == XmALIGNMENT_TOP ||
alignment == XmALIGNMENT_TOP_LEFT ||
alignment == XmALIGNMENT_TOP_RIGHT)
*y = rect->y + 2;
else if (alignment == XmALIGNMENT_LEFT ||
alignment == XmALIGNMENT_CENTER ||
alignment == XmALIGNMENT_RIGHT)
*y = rect->y + ((int)rect->height - (int)height) / 2;
else
*y = rect->y + rect->height - height - 2;
if (clipRect->x == rect->x &&
clipRect->y == rect->y &&
clipRect->width == rect->width &&
clipRect->height == rect->height &&
(int)width + 4 <= (int)clipRect->width &&
(int)height + 4 <= (int)clipRect->height)
return XmLDrawNOCLIP;
return XmLDrawCLIPPED;
}
void
XmLDrawToggle(Widget w,
Boolean state,
Dimension size,
unsigned char alignment,
GC gc,
Pixel backgroundColor,
Pixel topColor,
Pixel bottomColor,
Pixel checkColor,
XRectangle *rect,
XRectangle *clipRect)
{
Display *dpy;
Window win;
XPoint point[5];
int x, y, cx[3], cy[4], drawType;
drawType = XmLDrawCalc(w, size, size, alignment, rect, clipRect, &x, &y);
if (size < 3 || drawType == XmLDrawNODRAW)
return;
dpy = XtDisplay(w);
win = XtWindow(w);
if (drawType == XmLDrawCLIPPED)
XSetClipRectangles(dpy, gc, 0, 0, clipRect, 1, Unsorted);
/* background */
XSetForeground(dpy, gc, backgroundColor);
XFillRectangle(dpy, win, gc, x, y, size, size);
/* box shadow */
XSetForeground(dpy, gc, topColor);
point[0].x = x;
point[0].y = y + size - 1;
point[1].x = x;
point[1].y = y;
point[2].x = x + size - 1;
point[2].y = y;
XDrawLines(dpy, win, gc, point, 3, CoordModeOrigin);
point[1].x = x + size - 1;
point[1].y = y + size - 1;
XSetForeground(dpy, gc, bottomColor);
XDrawLines(dpy, win, gc, point, 3, CoordModeOrigin);
if (state == True)
{
/* check */
cx[0] = x + 1;
cx[1] = x + (((int)size - 3) / 3) + 1;
cx[2] = x + size - 2;
cy[0] = y + 1;
cy[1] = y + (((int)size - 3) / 2) + 1;
cy[2] = y + ((((int)size - 3) * 2) / 3) + 1;
cy[3] = y + size - 2;
point[0].x = cx[0];
point[0].y = cy[1];
point[1].x = cx[1];
point[1].y = cy[3];
point[2].x = cx[2];
point[2].y = cy[0];
point[3].x = cx[1];
point[3].y = cy[2];
point[4].x = point[0].x;
point[4].y = point[0].y;
XSetForeground(dpy, gc, checkColor);
XFillPolygon(dpy, win, gc, point, 4, Nonconvex, CoordModeOrigin);
XDrawLines(dpy, win, gc, point, 5, CoordModeOrigin);
}
if (drawType == XmLDrawCLIPPED)
XSetClipMask(dpy, gc, None);
}
int
XmLRectIntersect(XRectangle *r1,
XRectangle *r2)
{
if (!r1->width || !r1->height || !r2->width || !r2->height)
return XmLRectOutside;
if (r1->x + (int)r1->width - 1 < r2->x ||
r1->x > r2->x + (int)r2->width - 1 ||
r1->y + (int)r1->height - 1 < r2->y ||
r1->y > r2->y + (int)r2->height - 1)
return XmLRectOutside;
if (r1->x >= r2->x &&
r1->x + (int)r1->width <= r2->x + (int)r2->width &&
r1->y >= r2->y &&
r1->y + (int)r1->height <= r2->y + (int)r2->height)
return XmLRectInside; /* r1 inside r2 */
return XmLRectPartial;
}
XmFontList
XmLFontListCopyDefault(Widget widget)
{
Widget parent;
XFontStruct *font;
XmFontList fontList, fl;
fontList = 0;
parent = XtParent(widget);
while (parent)
{
fl = 0;
if (XmIsVendorShell(parent) || XmIsMenuShell(parent))
XtVaGetValues(parent, XmNdefaultFontList, &fl, NULL);
else if (XmIsBulletinBoard(parent))
XtVaGetValues(parent, XmNbuttonFontList, &fl, NULL);
if (fl)
{
fontList = XmFontListCopy(fl);
parent = 0;
}
if (parent)
parent = XtParent(parent);
}
if (!fontList)
{
font = XLoadQueryFont(XtDisplay(widget), "fixed");
if (!font)
XmLWarning(widget,
"FontListCopyDefault() - FATAL ERROR - can't load fixed font");
fontList = XmFontListCreate(font, XmSTRING_DEFAULT_CHARSET);
}
return fontList;
}
void
XmLFontListGetDimensions(XmFontList fontList,
short *width,
short *height,
Boolean useAverageWidth)
{
XmStringCharSet charset;
XmFontContext context;
XFontStruct *fs;
short w, h;
#if XmVersion < 2000
/* --- begin code to work around Motif 1.x internal bug */
typedef struct {
XmFontList nextFontList;
Boolean unused;
} XmFontListContextRec;
typedef struct {
XFontStruct *font;
XmStringCharSet unused;
} XmFontListRec;
XmFontList nextFontList;
#endif
*width = 0;
*height = 0;
if (XmFontListInitFontContext(&context, fontList))
{
while (1)
{
#if XmVersion < 2000
/* --- begin code to work around Motif internal bug */
/* --- this code must be removed for Motif 2.0 */
nextFontList = ((XmFontListContextRec *)context)->nextFontList;
if (!nextFontList)
break;
if (!((XmFontListRec *)nextFontList)->font)
break;
/* --- end Motif workaround code */
#endif
if (XmFontListGetNextFont(context, &charset, &fs) == False)
break;
XtFree(charset);
if (useAverageWidth == True)
XmLFontGetAverageWidth(fs, &w);
else
w = fs->max_bounds.width;
h = fs->max_bounds.ascent + fs->max_bounds.descent;
if (*height < h)
*height = h;
if (*width < w)
*width = w;
}
XmFontListFreeFontContext(context);
}
}
static void
XmLFontGetAverageWidth(XFontStruct *fs,
short *width)
{
long aw, n;
int r, c, mm, i;
XCharStruct *cs;
n = 0;
aw = 0;
mm = fs->max_char_or_byte2 - fs->min_char_or_byte2 + 1;
for (r = fs->min_byte1; r <= fs->max_byte1; r++)
for (c = fs->min_char_or_byte2; c <= fs->max_char_or_byte2; c++)
{
if (!fs->per_char)
continue;
i = ((r - fs->min_byte1) * mm) + (c - fs->min_char_or_byte2);
cs = &fs->per_char[i];
if (!cs->width)
continue;
aw += cs->width;
n++;
}
if (n)
aw = aw / n;
else
aw = fs->min_bounds.width;
*width = (short)aw;
}
int _XmLKey;
void XmLInitialize(void)
{
static int first = 1;
if (!first)
return;
first = 0;
#ifdef XmLEVAL
fprintf(stderr, "XmL: This is an evalation version of the Microline\n");
fprintf(stderr, "XmL: Widget Library. Some features are disabled.\n");
#endif
#ifdef XmLJAVA
if (_XmLKey != 444)
{
fprintf(stderr, "XmL: Error: This version of the library will only");
fprintf(stderr, "XmL: work with JAVA.\n");
exit(0);
}
#endif
}
int
XmLMessageBox(Widget w,
char *string,
Boolean okOnly)
{
int status = 0;
Widget dialog, shell;
Arg args[3];
XtAppContext context;
XmString str, titleStr;
String shellTitle;
Atom WM_DELETE_WINDOW;
str = XmStringCreateLtoR(string, XmSTRING_DEFAULT_CHARSET);
XtSetArg(args[0], XmNmessageString, str);
XtSetArg(args[1], XmNdialogStyle, XmDIALOG_APPLICATION_MODAL);
shell = XmLShellOfWidget(w);
if (shell)
XtVaGetValues(shell, XmNtitle, &shellTitle, NULL);
if (shell && shellTitle)
titleStr = XmStringCreateLtoR(shellTitle,
XmSTRING_DEFAULT_CHARSET);
else
titleStr = XmStringCreateSimple("Notice");
XtSetArg(args[2], XmNdialogTitle, titleStr);
if (okOnly == True)
dialog = XmCreateMessageDialog(XtParent(w), "popup", args, 3);
else
dialog = XmCreateQuestionDialog(XtParent(w), "popup", args, 3);
WM_DELETE_WINDOW = XmInternAtom(XtDisplay(w), "WM_DELETE_WINDOW",
False);
XmAddWMProtocolCallback(shell, WM_DELETE_WINDOW, XmLMessageBoxWMDelete,
(caddr_t)&status);
XmStringFree(str);
XmStringFree(titleStr);
XtAddCallback(dialog, XmNokCallback, XmLMessageBoxResponse,
(XtPointer)&status);
if (okOnly == True)
{
XtUnmanageChild(XmMessageBoxGetChild(dialog,
XmDIALOG_CANCEL_BUTTON));
XtUnmanageChild(XmMessageBoxGetChild(dialog,
XmDIALOG_HELP_BUTTON));
}
else
{
XtAddCallback(dialog, XmNcancelCallback, XmLMessageBoxResponse,
(XtPointer)&status);
XtAddCallback(dialog, XmNhelpCallback, XmLMessageBoxResponse,
(XtPointer)&status);
}
XtManageChild(dialog);
context = XtWidgetToApplicationContext(w);
while (!status || XtAppPending(context))
XtAppProcessEvent(context, XtIMAll);
XtDestroyWidget(dialog);
return status;
}
static void
XmLMessageBoxWMDelete(Widget w,
XtPointer clientData,
XtPointer callData)
{
int *status = (int *)clientData;
*status = 1;
}
static void
XmLMessageBoxResponse(Widget w,
XtPointer clientData,
XtPointer callData)
{
int *status = (int *)clientData;
XmAnyCallbackStruct *reason;
reason = (XmAnyCallbackStruct *)callData;
switch (reason->reason)
{
case XmCR_OK:
*status = 1;
break;
case XmCR_CANCEL:
*status = 2;
break;
case XmCR_HELP:
*status = 3;
break;
}
}
void
XmLPixmapDraw(Widget w,
Pixmap pixmap,
Pixmap pixmask,
int pixmapWidth,
int pixmapHeight,
unsigned char alignment,
GC gc,
XRectangle *rect,
XRectangle *clipRect)
{
Display *dpy;
Window win;
int px, py, x, y, width, height, drawType;
if (pixmap == XmUNSPECIFIED_PIXMAP)
return;
dpy = XtDisplay(w);
win = XtWindow(w);
width = pixmapWidth;
height = pixmapHeight;
if (!width || !height)
{
alignment = XmALIGNMENT_TOP_LEFT;
width = clipRect->width - 4;
height = clipRect->height - 4;
}
drawType = XmLDrawCalc(w, width, height, alignment,
rect, clipRect, &x, &y);
if (drawType == XmLDrawNODRAW)
return;
px = 0;
py = 0;
/* clip top */
if (clipRect->y > y && clipRect->y < y + height - 1)
{
py = clipRect->y - y;
y += py;
height -= py;
}
/* clip bottom */
if (clipRect->y + (int)clipRect->height - 1 >= y &&
clipRect->y + (int)clipRect->height - 1 <= y + height - 1)
height = clipRect->y + clipRect->height - y;
/* clip left */
if (clipRect->x > x && clipRect->x < x + width - 1)
{
px = clipRect->x - x;
x += px;
width -= px;
}
/* clip right */
if (clipRect->x + (int)clipRect->width - 1 >= x &&
clipRect->x + (int)clipRect->width - 1 <= x + width - 1)
width = clipRect->x + clipRect->width - x;
if (pixmask != XmUNSPECIFIED_PIXMAP)
{
XSetClipMask(dpy, gc, pixmask);
XSetClipOrigin(dpy, gc, x - px, y - py);
}
XSetGraphicsExposures(dpy, gc, False);
XCopyArea(dpy, pixmap, win, gc, px, py, width, height, x, y);
XSetGraphicsExposures(dpy, gc, True);
if (pixmask != XmUNSPECIFIED_PIXMAP)
{
XSetClipMask(dpy, gc, None);
XSetClipOrigin(dpy, gc, 0, 0);
}
}
Widget
XmLShellOfWidget(Widget w)
{
while(1)
{
if (!w)
return 0;
if (XtIsSubclass(w, shellWidgetClass))
return w;
w = XtParent(w);
}
}
static XmLSortCompareFunc XmLSortCompare;
static int XmLSortEleSize;
static void *XmLSortUserData;
void
XmLSort(void *base,
int numItems,
unsigned int itemSize,
XmLSortCompareFunc compare,
void *userData)
{
XmLSortCompareFunc oldCompare;
int oldEleSize;
void *oldUserData;
char *lvec, *rvec;
if (numItems < 2)
return;
/* for sorts within a sort compare function, we must
save any global sort variables on the local stack
and restore them when finished */
oldCompare = XmLSortCompare;
oldEleSize = XmLSortEleSize;
oldUserData = XmLSortUserData;
XmLSortCompare = compare;
XmLSortEleSize = itemSize;
XmLSortUserData = userData;
lvec = (char *)base;
rvec = lvec + (numItems - 1) * itemSize;
XmLSortFunc(lvec, rvec);
XmLSortCompare = oldCompare;
XmLSortEleSize = oldEleSize;
XmLSortUserData = oldUserData;
}
#define SWAP(p1, p2) \
{ \
if (p1 != p2) \
{ \
int zi; \
char zc; \
for (zi = 0; zi < XmLSortEleSize; zi++) \
{ \
zc = (p1)[zi]; \
(p1)[zi] = (p2)[zi]; \
(p2)[zi] = zc; \
} \
}\
}
static void
XmLSortFunc(char *lvec,
char *rvec)
{
int i;
char *nlvec, *nrvec, *pvec;
start:
i = (*XmLSortCompare)(XmLSortUserData, lvec, rvec);
/* two item sort */
if (rvec == lvec + XmLSortEleSize)
{
if (i > 0)
SWAP(lvec, rvec)
return;
}
/* find mid of three items */
pvec = lvec + ((rvec - lvec) / (XmLSortEleSize * 2)) * XmLSortEleSize;
if (i < 0)
{
i = (*XmLSortCompare)(XmLSortUserData, lvec, pvec);
if (i > 0)
pvec = lvec;
else if (i == 0)
pvec = rvec;
}
else if (i > 0)
{
i = (*XmLSortCompare)(XmLSortUserData, rvec, pvec);
if (i > 0)
pvec = rvec;
else if (i == 0)
pvec = lvec;
}
else
{
pvec = lvec + XmLSortEleSize;
while (1)
{
i = (*XmLSortCompare)(XmLSortUserData, lvec, pvec);
if (i < 0)
break;
else if (i > 0)
{
pvec = lvec;
break;
}
if (pvec == rvec)
return;
pvec += XmLSortEleSize;
}
}
/* partition the set */
nlvec = lvec;
nrvec = rvec;
while (1)
{
if (pvec == nrvec)
pvec = nlvec;
else if (pvec == nlvec)
pvec = nrvec;
SWAP(nrvec, nlvec)
while ((*XmLSortCompare)(XmLSortUserData, nlvec, pvec) < 0)
nlvec += XmLSortEleSize;
while ((*XmLSortCompare)(XmLSortUserData, nrvec, pvec) >= 0)
nrvec -= XmLSortEleSize;
if (nlvec > nrvec)
break;
}
/* sort partitioned sets */
if (lvec < nlvec - XmLSortEleSize)
XmLSortFunc(lvec, nlvec - XmLSortEleSize);
if (nlvec < rvec)
{
lvec = nlvec;
goto start;
}
}
void
XmLStringDraw(Widget w,
XmString string,
XmStringDirection stringDir,
XmFontList fontList,
unsigned char alignment,
GC gc,
XRectangle *rect,
XRectangle *clipRect)
{
Display *dpy;
Window win;
Dimension width, height;
int x, y, drawType;
unsigned char strAlignment;
if (!string)
return;
dpy = XtDisplay(w);
win = XtWindow(w);
XmStringExtent(fontList, string, &width, &height);
drawType = XmLDrawCalc(w, width, height, alignment,
rect, clipRect, &x, &y);
if (drawType == XmLDrawNODRAW)
return;
x = rect->x + 2;
if (alignment == XmALIGNMENT_LEFT ||
alignment == XmALIGNMENT_TOP_LEFT ||
alignment == XmALIGNMENT_BOTTOM_LEFT)
strAlignment = XmALIGNMENT_BEGINNING;
else if (alignment == XmALIGNMENT_CENTER ||
alignment == XmALIGNMENT_TOP ||
alignment == XmALIGNMENT_BOTTOM)
if (width <= rect->width - 4)
strAlignment = XmALIGNMENT_CENTER;
else
strAlignment = XmALIGNMENT_BEGINNING;
else
strAlignment = XmALIGNMENT_END;
/* XmStringDraw clipping doesnt work in all cases
so we use a clip region for clipping */
if (drawType == XmLDrawCLIPPED)
XSetClipRectangles(dpy, gc, 0, 0, clipRect, 1, Unsorted);
XmStringDraw(dpy, win, fontList, string, gc,
x, y, rect->width - 4, strAlignment, stringDir, clipRect);
if (drawType == XmLDrawCLIPPED)
XSetClipMask(dpy, gc, None);
}
void
XmLStringDrawDirection(Display *dpy,
Window win,
XmFontList fontlist,
XmString string,
GC gc,
int x,
int y,
Dimension width,
unsigned char alignment,
unsigned char layout_direction,
unsigned char drawing_direction)
{
Screen *screen;
XFontStruct *fontStruct;
XImage *sourceImage, *destImage;
Pixmap pixmap;
GC pixmapGC;
/* int sourceWidth, sourceHeight;*/
int destWidth, destHeight;
int stringWidth, stringHeight;
int i, j, bytesPerLine;
Dimension dW, dH;
char *data;
screen = DefaultScreenOfDisplay(dpy);
XmStringExtent(fontlist, string, &dW, &dH);
stringWidth = (int)dW;
stringHeight = (int)dH;
if (!stringWidth || !stringHeight)
return;
/* draw string into 1 bit deep pixmap */
pixmap = XCreatePixmap(dpy, win, stringWidth, stringHeight, 1);
pixmapGC = XCreateGC(dpy, pixmap, 0, NULL);
fontStruct = XLoadQueryFont(dpy, "fixed");
if (!fontStruct)
{
fprintf(stderr, "XmLStringDrawDirection: error - ");
fprintf(stderr, "can't load fixed font\n");
return;
}
XSetFont(dpy, pixmapGC, fontStruct->fid);
XSetBackground(dpy, pixmapGC, 0L);
XSetForeground(dpy, pixmapGC, 0L);
XFillRectangle(dpy, pixmap, pixmapGC, 0, 0, stringWidth, stringHeight);
XSetForeground(dpy, pixmapGC, 1L);
XmStringDraw(dpy, pixmap, fontlist, string, pixmapGC, 0, 0, stringWidth,
XmALIGNMENT_BEGINNING, layout_direction, 0);
XFreeFont(dpy, fontStruct);
/* copy 1 bit deep pixmap into source image */
sourceImage = XGetImage(dpy, pixmap, 0, 0, stringWidth, stringHeight,
1, XYPixmap);
XFreePixmap(dpy, pixmap);
/* draw rotated text into destination image */
if (drawing_direction == XmSTRING_UP || drawing_direction == XmSTRING_DOWN)
{
destWidth = stringHeight;
destHeight = stringWidth;
}
else
{
destWidth = stringWidth;
destHeight = stringHeight;
}
bytesPerLine = (destWidth - 1) / 8 + 1;
data = (char *)malloc(bytesPerLine * destHeight);
destImage = XCreateImage(dpy, DefaultVisualOfScreen(screen),
1, XYBitmap, 0, data, destWidth, destHeight, 8, 0);
for (i = 0; i < stringWidth; i++)
for (j = 0; j < stringHeight; j++)
{
if (drawing_direction == XmSTRING_UP)
XPutPixel(destImage, j, i,
XGetPixel(sourceImage, stringWidth - i - 1, j));
else if (drawing_direction == XmSTRING_DOWN)
XPutPixel(destImage, stringHeight - j - 1, stringWidth - i - 1,
XGetPixel(sourceImage, stringWidth - i - 1, j));
else if (drawing_direction == XmSTRING_LEFT)
XPutPixel(destImage, i, stringHeight - j - 1,
XGetPixel(sourceImage, stringWidth - i - 1, j));
else
XPutPixel(destImage, i, j,
XGetPixel(sourceImage, i, j));
}
XDestroyImage(sourceImage);
/* copy rotated image into 1 bit deep pixmap */
pixmap = XCreatePixmap(dpy, win, destWidth, destHeight, 1);
XPutImage(dpy, pixmap, pixmapGC, destImage, 0, 0, 0, 0,
destWidth, destHeight);
XDestroyImage(destImage);
XFreeGC(dpy, pixmapGC);
/* adjust position for alignment */
if (drawing_direction == XmSTRING_UP || drawing_direction == XmSTRING_DOWN)
{
if (alignment == XmALIGNMENT_BEGINNING)
;
else if (alignment == XmALIGNMENT_CENTER)
y += width / 2 - stringWidth / 2;
else if (alignment == XmALIGNMENT_END)
y += (int)width - stringWidth;
}
else
{
if (alignment == XmALIGNMENT_BEGINNING)
;
else if (alignment == XmALIGNMENT_CENTER)
x += width / 2 - stringWidth / 2;
else if (alignment == XmALIGNMENT_END)
x += (int)width - stringWidth;
}
/* draw the pixmap as a stipple in the window */
XSetStipple(dpy, gc, pixmap);
XSetFillStyle(dpy, gc, FillStippled);
XSetTSOrigin(dpy, gc, x % destWidth, y % destHeight);
XFillRectangle(dpy, win, gc, x, y, destWidth, destHeight);
XFreePixmap(dpy, pixmap);
XSetFillStyle(dpy, gc, FillSolid);
}
void
XmLWarning(Widget w,
char *msg)
{
XtAppContext app;
char s[512], *cname, *name;
WidgetClass c;
app = XtWidgetToApplicationContext(w);
name = XtName(w);
if (!name)
name = "[No Name]";
c = XtClass(w);
cname = c->core_class.class_name;
if (!cname)
cname = "[No Class]";
sprintf(s, "%s: %s: %s\n", cname, name, msg);
XtAppWarning(app, s);
}