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