UNIXworkcode

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