trace.c revision 4419d26b
1/* $XTermId: trace.c,v 1.236 2022/02/18 08:48:47 tom Exp $ */ 2 3/* 4 * Copyright 1997-2021,2022 by Thomas E. Dickey 5 * 6 * All Rights Reserved 7 * 8 * Permission is hereby granted, free of charge, to any person obtaining a 9 * copy of this software and associated documentation files (the 10 * "Software"), to deal in the Software without restriction, including 11 * without limitation the rights to use, copy, modify, merge, publish, 12 * distribute, sublicense, and/or sell copies of the Software, and to 13 * permit persons to whom the Software is furnished to do so, subject to 14 * the following conditions: 15 * 16 * The above copyright notice and this permission notice shall be included 17 * in all copies or substantial portions of the Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22 * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY 23 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 24 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 25 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 * 27 * Except as contained in this notice, the name(s) of the above copyright 28 * holders shall not be used in advertising or otherwise to promote the 29 * sale, use or other dealings in this Software without prior written 30 * authorization. 31 */ 32 33/* 34 * debugging support via TRACE macro. 35 */ 36 37#include <xterm.h> /* for definition of GCC_UNUSED */ 38#include <xstrings.h> 39#include <wcwidth.h> 40#include <version.h> 41 42#if OPT_TRACE 43 44#include <data.h> 45#include <trace.h> 46 47#include <time.h> 48#include <stdlib.h> 49#include <unistd.h> 50#include <sys/types.h> 51#include <sys/stat.h> 52#include <stdio.h> 53#include <assert.h> 54 55#include <X11/Xatom.h> 56#include <X11/Xmu/Atoms.h> 57#include <X11/Xmu/Error.h> 58 59#ifdef HAVE_X11_TRANSLATEI_H 60#include <X11/ConvertI.h> 61#include <X11/TranslateI.h> 62#else 63#ifdef __cplusplus 64extern "C" { 65#endif 66 67 extern String _XtPrintXlations(Widget w, 68 XtTranslations xlations, 69 Widget accelWidget, 70 _XtBoolean includeRHS); 71#ifdef __cplusplus 72} 73#endif 74#endif 75const char *trace_who = "parent"; 76 77static FILE *trace_fp; 78 79static FILE * 80TraceOpen(void) 81{ 82 static const char *trace_out; 83 84 if (trace_fp != 0 85 && trace_who != trace_out) { 86 fclose(trace_fp); 87 trace_fp = 0; 88 } 89 trace_out = trace_who; 90 91 if (!trace_fp) { 92 static char dot[] = "."; 93 mode_t oldmask = umask(077); 94 char *home; 95 char *name; 96 /* 97 * Put the trace-file in user's home-directory if the current 98 * directory is not writable. 99 */ 100 home = ((access(dot, R_OK | W_OK) == 0) 101 ? dot 102 : getenv("HOME")); 103 if (home != NULL && 104 (name = malloc(strlen(home) + strlen(trace_who) + 50)) != NULL) { 105#if OPT_TRACE_UNIQUE /* usually I do not want unique names */ 106 int unique; 107 for (unique = 0;; ++unique) { 108 if (unique) 109 sprintf(name, "%s/Trace-%s.out-%d", home, trace_who, unique); 110 else 111 sprintf(name, "%s/Trace-%s.out", home, trace_who); 112 if ((trace_fp = fopen(name, "r")) == 0) { 113 break; 114 } 115 fclose(trace_fp); 116 } 117#else 118 sprintf(name, "%s/Trace-%s.out", home, trace_who); 119#endif 120 trace_fp = fopen(name, "w"); 121 if (trace_fp != 0) { 122 fprintf(trace_fp, "%s\n", xtermVersion()); 123 TraceIds(NULL, 0); 124 } 125 if (!trace_fp) { 126 xtermWarning("Cannot open \"%s\"\n", name); 127 exit(EXIT_FAILURE); 128 } 129 (void) umask(oldmask); 130 free(name); 131 } 132 } 133 return trace_fp; 134} 135 136void 137Trace(const char *fmt, ...) 138{ 139 va_list ap; 140 FILE *fp = TraceOpen(); 141 142 va_start(ap, fmt); 143 vfprintf(fp, fmt, ap); 144 (void) fflush(fp); 145 va_end(ap); 146} 147 148void 149TraceVA(const char *fmt, va_list ap) 150{ 151 FILE *fp = TraceOpen(); 152 153 vfprintf(fp, fmt, ap); 154 (void) fflush(fp); 155} 156 157void 158TraceClose(void) 159{ 160 if (trace_fp != 0) { 161 (void) fclose(trace_fp); 162 (void) fflush(stdout); 163 (void) fflush(stderr); 164 (void) visibleChars(NULL, 0); 165 (void) visibleIChars(NULL, 0); 166 trace_fp = 0; 167 } 168} 169 170void 171TraceXError(Display *d, XErrorEvent *ev) 172{ 173 FILE *fp = TraceOpen(); 174 (void) XmuPrintDefaultErrorMessage(d, ev, fp); 175 (void) fflush(fp); 176} 177 178void 179TraceIds(const char *fname, int lnum) 180{ 181 Trace("process %d ", (int) getpid()); 182#ifdef HAVE_UNISTD_H 183 Trace("real (%u/%u) effective (%u/%u)", 184 (unsigned) getuid(), (unsigned) getgid(), 185 (unsigned) geteuid(), (unsigned) getegid()); 186#endif 187 if (fname != 0) { 188 Trace(" (%s@%d)\n", fname, lnum); 189 } else { 190 time_t now = time((time_t *) 0); 191 Trace("-- %s", ctime(&now)); 192 } 193} 194 195void 196TraceTime(const char *fname, int lnum) 197{ 198 time_t now; 199 if (fname != 0) { 200 Trace("datetime (%s@%d) ", fname, lnum); 201 } 202 now = time((time_t *) 0); 203 Trace("-- %s", ctime(&now)); 204} 205 206static void 207formatAscii(char *dst, unsigned value) 208{ 209 switch (value) { 210 case '\\': 211 sprintf(dst, "\\\\"); 212 break; 213 case '\b': 214 sprintf(dst, "\\b"); 215 break; 216 case '\n': 217 sprintf(dst, "\\n"); 218 break; 219 case '\r': 220 sprintf(dst, "\\r"); 221 break; 222 case '\t': 223 sprintf(dst, "\\t"); 224 break; 225 default: 226 if (E2A(value) < 32 || (E2A(value) >= 127 && E2A(value) < 160)) 227 sprintf(dst, "\\%03o", value & 0xff); 228 else 229 sprintf(dst, "%c", CharOf(value)); 230 break; 231 } 232} 233 234#if OPT_DEC_CHRSET 235 236const char * 237visibleDblChrset(unsigned chrset) 238{ 239 const char *result = "?"; 240 switch (chrset) { 241 case CSET_SWL: 242 result = "CSET_SWL"; 243 break; 244 case CSET_DHL_TOP: 245 result = "CSET_DHL_TOP"; 246 break; 247 case CSET_DHL_BOT: 248 result = "CSET_DHL_BOT"; 249 break; 250 case CSET_DWL: 251 result = "CSET_DWL"; 252 break; 253 } 254 return result; 255} 256#endif 257 258const char * 259visibleScsCode(DECNRCM_codes chrset) 260{ 261#define MAP(to,from) case from: result = to ":" #from; break 262 const char *result = "<ERR>"; 263 switch ((DECNRCM_codes) chrset) { 264 MAP("B", nrc_ASCII); 265 MAP("A", nrc_British); 266 MAP("A", nrc_British_Latin_1); 267 MAP("&4", nrc_DEC_Cyrillic); 268 MAP("0", nrc_DEC_Spec_Graphic); 269 MAP("1", nrc_DEC_Alt_Chars); 270 MAP("2", nrc_DEC_Alt_Graphics); 271 MAP("<", nrc_DEC_Supp); 272 MAP("%5", nrc_DEC_Supp_Graphic); 273 MAP(">", nrc_DEC_Technical); 274 MAP("4", nrc_Dutch); 275 MAP("5", nrc_Finnish); 276 MAP("C", nrc_Finnish2); 277 MAP("R", nrc_French); 278 MAP("f", nrc_French2); 279 MAP("Q", nrc_French_Canadian); 280 MAP("9", nrc_French_Canadian2); 281 MAP("K", nrc_German); 282 MAP("\"?", nrc_DEC_Greek_Supp); 283 MAP("\">", nrc_Greek); 284 MAP("F", nrc_ISO_Greek_Supp); 285 MAP("\"4", nrc_DEC_Hebrew_Supp); 286 MAP("%=", nrc_Hebrew); 287 MAP("H", nrc_ISO_Hebrew_Supp); 288 MAP("Y", nrc_Italian); 289 MAP("A", nrc_ISO_Latin_1_Supp); 290 MAP("B", nrc_ISO_Latin_2_Supp); 291 MAP("M", nrc_ISO_Latin_5_Supp); 292 MAP("L", nrc_ISO_Latin_Cyrillic); 293 MAP("`", nrc_Norwegian_Danish); 294 MAP("E", nrc_Norwegian_Danish2); 295 MAP("6", nrc_Norwegian_Danish3); 296 MAP("%6", nrc_Portugese); 297 MAP("&5", nrc_Russian); 298 MAP("%3", nrc_SCS_NRCS); 299 MAP("Z", nrc_Spanish); 300 MAP("7", nrc_Swedish); 301 MAP("H", nrc_Swedish2); 302 MAP("=", nrc_Swiss); 303 MAP("%2", nrc_Turkish); 304 MAP("%0", nrc_DEC_Turkish_Supp); 305 MAP("<UNK>", nrc_Unknown); 306 } 307#undef MAP 308 return result; 309} 310 311const char * 312visibleChars(const Char *buf, unsigned len) 313{ 314 static char *result; 315 static unsigned used; 316 317 if (buf != 0) { 318 unsigned limit = ((len + 1) * 8) + 1; 319 320 if (limit > used) { 321 used = limit; 322 result = XtRealloc(result, used); 323 } 324 if (result != 0) { 325 char *dst = result; 326 *dst = '\0'; 327 while (len--) { 328 unsigned value = *buf++; 329 formatAscii(dst, value); 330 dst += strlen(dst); 331 } 332 } 333 } else { 334 FreeAndNull(result); 335 used = 0; 336 } 337 return NonNull(result); 338} 339 340const char * 341visibleEventMode(EventMode value) 342{ 343 const char *result; 344 switch (value) { 345 case NORMAL: 346 result = "NORMAL"; 347 break; 348 case LEFTEXTENSION: 349 result = "LEFTEXTENSION"; 350 break; 351 case RIGHTEXTENSION: 352 result = "RIGHTEXTENSION"; 353 break; 354 default: 355 result = "?"; 356 break; 357 } 358 return result; 359} 360 361const char * 362visibleIChars(const IChar *buf, unsigned len) 363{ 364 static char *result; 365 static unsigned used; 366 367 if (buf != 0) { 368 unsigned limit = ((len + 1) * 12) + 1; 369 370 if (limit > used) { 371 used = limit; 372 result = XtRealloc(result, used); 373 } 374 if (result != 0) { 375 char *dst = result; 376 *dst = '\0'; 377 while (len--) { 378 unsigned value = *buf++; 379#if OPT_WIDE_CHARS 380 if (value > 255) 381 sprintf(dst, "\\U+%04X", value); 382 else 383#endif 384 formatAscii(dst, value); 385 dst += strlen(dst); 386 } 387 } 388 } else { 389 FreeAndNull(result); 390 used = 0; 391 } 392 return NonNull(result); 393} 394 395const char * 396visibleUChar(unsigned chr) 397{ 398 IChar buf[1]; 399 buf[0] = (IChar) chr; 400 return visibleIChars(buf, 1); 401} 402 403const char * 404visibleEventType(int type) 405{ 406 const char *result = "?"; 407 switch (type) { 408 CASETYPE(KeyPress); 409 CASETYPE(KeyRelease); 410 CASETYPE(ButtonPress); 411 CASETYPE(ButtonRelease); 412 CASETYPE(MotionNotify); 413 CASETYPE(EnterNotify); 414 CASETYPE(LeaveNotify); 415 CASETYPE(FocusIn); 416 CASETYPE(FocusOut); 417 CASETYPE(KeymapNotify); 418 CASETYPE(Expose); 419 CASETYPE(GraphicsExpose); 420 CASETYPE(NoExpose); 421 CASETYPE(VisibilityNotify); 422 CASETYPE(CreateNotify); 423 CASETYPE(DestroyNotify); 424 CASETYPE(UnmapNotify); 425 CASETYPE(MapNotify); 426 CASETYPE(MapRequest); 427 CASETYPE(ReparentNotify); 428 CASETYPE(ConfigureNotify); 429 CASETYPE(ConfigureRequest); 430 CASETYPE(GravityNotify); 431 CASETYPE(ResizeRequest); 432 CASETYPE(CirculateNotify); 433 CASETYPE(CirculateRequest); 434 CASETYPE(PropertyNotify); 435 CASETYPE(SelectionClear); 436 CASETYPE(SelectionRequest); 437 CASETYPE(SelectionNotify); 438 CASETYPE(ColormapNotify); 439 CASETYPE(ClientMessage); 440 CASETYPE(MappingNotify); 441 } 442 return result; 443} 444 445const char * 446visibleMappingMode(int code) 447{ 448 const char *result = "?"; 449 switch (code) { 450 CASETYPE(MappingModifier); 451 CASETYPE(MappingKeyboard); 452 CASETYPE(MappingPointer); 453 } 454 return result; 455} 456 457const char * 458visibleNotifyMode(int code) 459{ 460 const char *result = "?"; 461 switch (code) { 462 CASETYPE(NotifyNormal); 463 CASETYPE(NotifyGrab); 464 CASETYPE(NotifyUngrab); 465 CASETYPE(NotifyWhileGrabbed); 466 } 467 return result; 468} 469 470const char * 471visibleNotifyDetail(int code) 472{ 473 const char *result = "?"; 474 switch (code) { 475 CASETYPE(NotifyAncestor); 476 CASETYPE(NotifyVirtual); 477 CASETYPE(NotifyInferior); 478 CASETYPE(NotifyNonlinear); 479 CASETYPE(NotifyNonlinearVirtual); 480 CASETYPE(NotifyPointer); 481 CASETYPE(NotifyPointerRoot); 482 CASETYPE(NotifyDetailNone); 483 } 484 return result; 485} 486 487const char * 488visibleSelectionTarget(Display *d, Atom a) 489{ 490 const char *result = "?"; 491 492 if (a == XA_STRING) { 493 result = "XA_STRING"; 494 } else if (a == XA_TEXT(d)) { 495 result = "XA_TEXT()"; 496 } else if (a == XA_COMPOUND_TEXT(d)) { 497 result = "XA_COMPOUND_TEXT()"; 498 } else if (a == XA_UTF8_STRING(d)) { 499 result = "XA_UTF8_STRING()"; 500 } else if (a == XA_TARGETS(d)) { 501 result = "XA_TARGETS()"; 502 } 503 504 return result; 505} 506 507const char * 508visibleTekparse(int code) 509{ 510 static const struct { 511 int code; 512 const char *name; 513 } table[] = { 514#include "Tekparse.cin" 515 }; 516 const char *result = "?"; 517 Cardinal n; 518 for (n = 0; n < XtNumber(table); ++n) { 519 if (table[n].code == code) { 520 result = table[n].name; 521 break; 522 } 523 } 524 return result; 525} 526 527const char * 528visibleVTparse(int code) 529{ 530 static const struct { 531 int code; 532 const char *name; 533 } table[] = { 534#include "VTparse.cin" 535 }; 536 const char *result = "?"; 537 Cardinal n; 538 for (n = 0; n < XtNumber(table); ++n) { 539 if (table[n].code == code) { 540 result = table[n].name; 541 break; 542 } 543 } 544 return result; 545} 546 547const char * 548visibleXError(int code) 549{ 550 static char temp[80]; 551 const char *result = "?"; 552 switch (code) { 553 CASETYPE(Success); 554 CASETYPE(BadRequest); 555 CASETYPE(BadValue); 556 CASETYPE(BadWindow); 557 CASETYPE(BadPixmap); 558 CASETYPE(BadAtom); 559 CASETYPE(BadCursor); 560 CASETYPE(BadFont); 561 CASETYPE(BadMatch); 562 CASETYPE(BadDrawable); 563 CASETYPE(BadAccess); 564 CASETYPE(BadAlloc); 565 CASETYPE(BadColor); 566 CASETYPE(BadGC); 567 CASETYPE(BadIDChoice); 568 CASETYPE(BadName); 569 CASETYPE(BadLength); 570 CASETYPE(BadImplementation); 571 default: 572 sprintf(temp, "%d", code); 573 result = temp; 574 break; 575 } 576 return result; 577} 578 579#if OPT_TRACE_FLAGS 580#define isScrnFlag(flag) ((flag) == LINEWRAPPED) 581 582static char * 583ScrnText(LineData *ld) 584{ 585 return visibleIChars(ld->charData, ld->lineSize); 586} 587 588#define SHOW_BAD_LINE(name, ld) \ 589 Trace("OOPS " #name " bad row\n") 590 591#define SHOW_SCRN_FLAG(name,code) \ 592 Trace(#name " %s:%s\n", \ 593 code ? "*" : "", \ 594 ScrnText(ld)) 595 596void 597LineClrFlag(LineData *ld, int flag) 598{ 599 if (ld == 0) { 600 SHOW_BAD_LINE(LineClrFlag, ld); 601 assert(0); 602 } else if (isScrnFlag(flag)) { 603 SHOW_SCRN_FLAG(LineClrFlag, 0); 604 } 605 606 LineFlags(ld) &= ~flag; 607} 608 609void 610LineSetFlag(LineData *ld, int flag) 611{ 612 if (ld == 0) { 613 SHOW_BAD_LINE(LineSetFlag, ld); 614 assert(0); 615 } else if (isScrnFlag(flag)) { 616 SHOW_SCRN_FLAG(LineSetFlag, 1); 617 } 618 619 LineFlags(ld) |= flag; 620} 621 622int 623LineTstFlag(LineData ld, int flag) 624{ 625 int code = 0; 626 if (ld == 0) { 627 SHOW_BAD_LINE(LineTstFlag, ld); 628 } else { 629 code = LineFlags(ld); 630 631 if (isScrnFlag(flag)) { 632 SHOW_SCRN_FLAG(LineTstFlag, code); 633 } 634 } 635 return code; 636} 637#endif /* OPT_TRACE_FLAGS */ 638 639const char * 640TraceAtomName(Display *dpy, Atom atom) 641{ 642 static char *result; 643 free(result); 644 if (atom != 0) { 645 result = XGetAtomName(dpy, atom); 646 } else { 647 result = x_strdup("NONE"); 648 } 649 return result; 650} 651 652/* 653 * Trace the normal or alternate screen, showing color values up to 16, e.g., 654 * for debugging with vttest. 655 */ 656void 657TraceScreen(XtermWidget xw, int whichBuf) 658{ 659 TScreen *screen = TScreenOf(xw); 660 661 if (screen->editBuf_index[whichBuf]) { 662 int row; 663 664 TRACE(("TraceScreen %d:\n", whichBuf)); 665 for (row = 0; row <= LastRowNumber(screen); ++row) { 666 LineData *ld = getLineData(screen, row); 667 668 TRACE((" %3d:", row)); 669 if (ld != 0) { 670 int col; 671 672 for (col = 0; col < ld->lineSize; ++col) { 673 int ch = (int) ld->charData[col]; 674 if (ch < ' ') 675 ch = ' '; 676 if (ch >= 127) 677 ch = '#'; 678 TRACE(("%c", ch)); 679 } 680 TRACE((":\n")); 681 682#if 0 683 TRACE((" xx:")); 684 for (col = 0; col < ld->lineSize; ++col) { 685 unsigned attrs = ld->attribs[col]; 686 char ch; 687 if (attrs & PROTECTED) { 688 ch = '*'; 689 } else if (attrs & BLINK) { 690 ch = 'B'; 691 } else if (attrs & CHARDRAWN) { 692 ch = '+'; 693 } else { 694 ch = ' '; 695 } 696 TRACE(("%c", ch)); 697 } 698 TRACE((":\n")); 699#endif 700 701#if 0 702 TRACE((" fg:")); 703 for (col = 0; col < ld->lineSize; ++col) { 704 unsigned fg = extract_fg(xw, ld->color[col], ld->attribs[col]); 705 if (fg > 15) 706 fg = 15; 707 TRACE(("%1x", fg)); 708 } 709 TRACE((":\n")); 710 711 TRACE((" bg:")); 712 for (col = 0; col < ld->lineSize; ++col) { 713 unsigned bg = extract_bg(xw, ld->color[col], ld->attribs[col]); 714 if (bg > 15) 715 bg = 15; 716 TRACE(("%1x", bg)); 717 } 718 TRACE((":\n")); 719#endif 720 } else { 721 TRACE(("null lineData\n")); 722 } 723 } 724 } else { 725 TRACE(("TraceScreen %d is nil\n", whichBuf)); 726 } 727} 728 729static char * 730formatEventMask(char *target, unsigned source, Boolean buttons) 731{ 732#define DATA(name) { name ## Mask, #name } 733 static struct { 734 unsigned mask; 735 const char *name; 736 } table[] = { 737 DATA(Shift), 738 DATA(Lock), 739 DATA(Control), 740 DATA(Mod1), 741 DATA(Mod2), 742 DATA(Mod3), 743 DATA(Mod4), 744 DATA(Mod5), 745 DATA(Button1), 746 DATA(Button2), 747 DATA(Button3), 748 DATA(Button4), 749 DATA(Button5), 750 }; 751#undef DATA 752 Cardinal n; 753 char marker = L_CURL; 754 char *base = target; 755 756 for (n = 0; n < XtNumber(table); ++n) { 757 if (!buttons && (table[n].mask >= Button1Mask)) 758 continue; 759 if ((table[n].mask & source)) { 760 UIntClr(source, table[n].mask); 761 sprintf(target, "%c%s", marker, table[n].name); 762 target += strlen(target); 763 marker = '|'; 764 } 765 } 766 767 if (source != 0) { 768 sprintf(target, "%c?%#x", marker, source); 769 target += strlen(target); 770 marker = '|'; 771 } 772 773 if (marker == L_CURL) 774 *target++ = L_CURL; 775 *target++ = R_CURL; 776 777 *target = '\0'; 778 return base; 779} 780 781void 782TraceEvent(const char *tag, XEvent *ev, String *params, Cardinal *num_params) 783{ 784 char mask_buffer[160]; 785 786 TRACE(("Event #%lu %s: %#lx %s", 787 ev->xany.serial, 788 tag, 789 ev->xany.window, 790 visibleEventType(ev->type))); 791 792 switch (ev->type) { 793 case KeyPress: 794 /* FALLTHRU */ 795 case KeyRelease: 796 TRACE((" keycode 0x%04X %s", 797 ev->xkey.keycode, 798 formatEventMask(mask_buffer, ev->xkey.state, False))); 799 break; 800 case ButtonPress: 801 /* FALLTHRU */ 802 case ButtonRelease: 803 TRACE((" button %u state %#x %s", 804 ev->xbutton.button, 805 ev->xbutton.state, 806 formatEventMask(mask_buffer, ev->xbutton.state, True))); 807 break; 808 case MotionNotify: 809 TRACE((" (%d,%d) state %#x %s", 810 ev->xmotion.y_root, 811 ev->xmotion.x_root, 812 ev->xmotion.state, 813 formatEventMask(mask_buffer, ev->xmotion.state, True))); 814 break; 815 case EnterNotify: 816 case LeaveNotify: 817 TRACE((" at %d,%d root %d,%d %s %s", 818 ev->xcrossing.y, 819 ev->xcrossing.x, 820 ev->xcrossing.y_root, 821 ev->xcrossing.x_root, 822 visibleNotifyMode(ev->xcrossing.mode), 823 visibleNotifyDetail(ev->xcrossing.detail))); 824 break; 825 case FocusIn: 826 case FocusOut: 827 TRACE((" %s %s", 828 visibleNotifyMode(ev->xfocus.mode), 829 visibleNotifyDetail(ev->xfocus.detail))); 830 break; 831 case MapNotify: 832 TRACE((" event %#lx %s", 833 ev->xmap.event, 834 ev->xmap.override_redirect ? "override" : "")); 835 break; 836 case UnmapNotify: 837 TRACE((" event %#lx %s", 838 ev->xunmap.event, 839 ev->xunmap.from_configure ? "configure" : "")); 840 break; 841 case ReparentNotify: 842 TRACE((" at %d,%d event %#lx parent %#lx %s", 843 ev->xreparent.y, 844 ev->xreparent.x, 845 ev->xreparent.event, 846 ev->xreparent.parent, 847 ev->xreparent.override_redirect ? "override" : "")); 848 break; 849 case ConfigureNotify: 850 TRACE((" at %d,%d size %dx%d bd %d above %#lx", 851 ev->xconfigure.y, 852 ev->xconfigure.x, 853 ev->xconfigure.height, 854 ev->xconfigure.width, 855 ev->xconfigure.border_width, 856 ev->xconfigure.above)); 857 break; 858 case CreateNotify: 859 TRACE((" at %d,%d size %dx%d bd %d", 860 ev->xcreatewindow.y, 861 ev->xcreatewindow.x, 862 ev->xcreatewindow.height, 863 ev->xcreatewindow.width, 864 ev->xcreatewindow.border_width)); 865 break; 866 case ResizeRequest: 867 TRACE((" size %dx%d", 868 ev->xresizerequest.height, 869 ev->xresizerequest.width)); 870 break; 871 case PropertyNotify: 872 TRACE((" %s %s", 873 TraceAtomName(XtDisplay(toplevel), ev->xproperty.atom), 874 ((ev->xproperty.state == PropertyNewValue) 875 ? "NewValue" 876 : ((ev->xproperty.state == PropertyDelete) 877 ? "Delete" 878 : "?")))); 879 880 break; 881 case Expose: 882 TRACE((" at %d,%d size %dx%d count %d", 883 ev->xexpose.y, 884 ev->xexpose.x, 885 ev->xexpose.height, 886 ev->xexpose.width, 887 ev->xexpose.count)); 888 break; 889 case MappingNotify: 890 TRACE((" %s first_keycode %d count %d", 891 visibleMappingMode(ev->xmapping.request), 892 ev->xmapping.first_keycode, 893 ev->xmapping.count)); 894 break; 895 case VisibilityNotify: 896 TRACE((" state %d", 897 ev->xvisibility.state)); 898 break; 899 case KeymapNotify: 900 { 901 Cardinal j; 902 for (j = 0; j < XtNumber(ev->xkeymap.key_vector); ++j) { 903 if (ev->xkeymap.key_vector[j] != 0) { 904 Cardinal k; 905 for (k = 0; k < 8; ++k) { 906 if (ev->xkeymap.key_vector[j] & (1 << k)) { 907 TRACE((" key%u", (j * 8) + k)); 908 } 909 } 910 } 911 } 912 } 913 break; 914 case NoExpose: 915 TRACE((" send_event:%d display %p major:%d minor:%d", 916 ev->xnoexpose.send_event, 917 (void *) ev->xnoexpose.display, 918 ev->xnoexpose.major_code, 919 ev->xnoexpose.minor_code)); 920 break; 921 case GraphicsExpose: 922 TRACE((" send_event:%d display %p major:%d minor:%d", 923 ev->xgraphicsexpose.send_event, 924 (void *) ev->xgraphicsexpose.display, 925 ev->xgraphicsexpose.major_code, 926 ev->xgraphicsexpose.minor_code)); 927 break; 928 case SelectionClear: 929 TRACE((" selection:%s", 930 TraceAtomName(ev->xselectionclear.display, 931 ev->xselectionclear.selection))); 932 break; 933 case SelectionRequest: 934 TRACE((" owner:%#lx requestor:%#lx", 935 ev->xselectionrequest.owner, 936 ev->xselectionrequest.requestor)); 937 TRACE((" selection:%s", 938 TraceAtomName(ev->xselectionrequest.display, 939 ev->xselectionrequest.selection))); 940 TRACE((" target:%s", 941 TraceAtomName(ev->xselectionrequest.display, 942 ev->xselectionrequest.target))); 943 TRACE((" property:%s", 944 TraceAtomName(ev->xselectionrequest.display, 945 ev->xselectionrequest.property))); 946 break; 947 default: 948 TRACE((":FIXME")); 949 break; 950 } 951 TRACE(("\n")); 952 if (params != 0 && *num_params != 0) { 953 Cardinal n; 954 for (n = 0; n < *num_params; ++n) { 955 TRACE((" param[%d] = %s\n", n, params[n])); 956 } 957 } 958} 959 960#if OPT_RENDERFONT && OPT_WIDE_CHARS 961void 962TraceFallback(XtermWidget xw, const char *tag, unsigned wc, int n, XftFont *font) 963{ 964 TScreen *screen = TScreenOf(xw); 965 XGlyphInfo gi; 966 int expect = my_wcwidth((wchar_t) wc); 967 int hijack = mk_wcwidth_cjk((wchar_t) wc); 968 int actual; 969 970 XftTextExtents32(screen->display, font, &wc, 1, &gi); 971 actual = ((gi.xOff + FontWidth(screen) - 1) 972 / FontWidth(screen)); 973 974 TRACE(("FALLBACK #%d %s U+%04X %d,%d pos," 975 " %d,%d off," " %dx%d size," 976 " %d/%d next," " %d vs %d/%d cells%s\n", 977 n + 1, tag, wc, 978 gi.y, gi.x, 979 gi.yOff, gi.xOff, 980 gi.height, gi.width, 981 font->max_advance_width, 982 FontWidth(screen), 983 actual, expect, hijack, 984 ((actual != expect) 985 ? ((actual == hijack) 986 ? " OOPS" 987 : " oops") 988 : ""))); 989} 990#endif /* OPT_RENDERFONT */ 991 992void 993TraceFocus(Widget w, XEvent *ev) 994{ 995 TRACE(("trace_focus event type %d:%s\n", 996 ev->type, visibleEventType(ev->type))); 997 switch (ev->type) { 998 case FocusIn: 999 case FocusOut: 1000 { 1001 XFocusChangeEvent *event = (XFocusChangeEvent *) ev; 1002 TRACE(("\tdetail: %s\n", visibleNotifyDetail(event->detail))); 1003 TRACE(("\tmode: %s\n", visibleNotifyMode(event->mode))); 1004 TRACE(("\twindow: %#lx\n", event->window)); 1005 } 1006 break; 1007 case EnterNotify: 1008 case LeaveNotify: 1009 { 1010 XCrossingEvent *event = (XCrossingEvent *) ev; 1011 TRACE(("\tdetail: %s\n", visibleNotifyDetail(event->detail))); 1012 TRACE(("\tmode: %s\n", visibleNotifyMode(event->mode))); 1013 TRACE(("\twindow: %#lx\n", event->window)); 1014 TRACE(("\tfocus: %d\n", event->focus)); 1015 TRACE(("\troot: %#lx\n", event->root)); 1016 TRACE(("\tsubwindow: %#lx\n", event->subwindow)); 1017 } 1018 break; 1019 } 1020 while (w != 0) { 1021 TRACE(("w %p -> %#lx\n", (void *) w, XtWindow(w))); 1022 w = XtParent(w); 1023 } 1024} 1025 1026void 1027TraceSizeHints(XSizeHints * hints) 1028{ 1029 TRACE(("size hints:\n")); 1030 if (hints->flags & (USPosition | PPosition)) { 1031 TRACE((" position %d,%d%s%s\n", hints->y, hints->x, 1032 (hints->flags & USPosition) ? " user" : "", 1033 (hints->flags & PPosition) ? " prog" : "")); 1034 } 1035 if (hints->flags & (USSize | PSize)) { 1036 TRACE((" size %d,%d%s%s\n", hints->height, hints->width, 1037 (hints->flags & USSize) ? " user" : "", 1038 (hints->flags & PSize) ? " prog" : "")); 1039 } 1040 if (hints->flags & PMinSize) { 1041 TRACE((" min %d,%d\n", hints->min_height, hints->min_width)); 1042 } 1043 if (hints->flags & PMaxSize) { 1044 TRACE((" max %d,%d\n", hints->max_height, hints->max_width)); 1045 } 1046 if (hints->flags & PResizeInc) { 1047 TRACE((" inc %d,%d\n", hints->height_inc, hints->width_inc)); 1048 } else { 1049 TRACE((" inc NONE!\n")); 1050 } 1051 if (hints->flags & PAspect) { 1052 TRACE((" min aspect %d/%d\n", hints->min_aspect.y, hints->min_aspect.y)); 1053 TRACE((" max aspect %d/%d\n", hints->max_aspect.y, hints->max_aspect.y)); 1054 } 1055 if (hints->flags & PBaseSize) { 1056 TRACE((" base %d,%d\n", hints->base_height, hints->base_width)); 1057 } 1058 if (hints->flags & PWinGravity) { 1059 TRACE((" gravity %d\n", hints->win_gravity)); 1060 } 1061} 1062 1063static void 1064TraceEventMask(const char *tag, long mask) 1065{ 1066#define DATA(name) { name##Mask, #name } 1067 /* *INDENT-OFF* */ 1068 static struct { 1069 long mask; 1070 const char *name; 1071 } table[] = { 1072 DATA(KeyPress), 1073 DATA(KeyRelease), 1074 DATA(ButtonPress), 1075 DATA(ButtonRelease), 1076 DATA(EnterWindow), 1077 DATA(LeaveWindow), 1078 DATA(PointerMotion), 1079 DATA(PointerMotionHint), 1080 DATA(Button1Motion), 1081 DATA(Button2Motion), 1082 DATA(Button3Motion), 1083 DATA(Button4Motion), 1084 DATA(Button5Motion), 1085 DATA(ButtonMotion), 1086 DATA(KeymapState), 1087 DATA(Exposure), 1088 DATA(VisibilityChange), 1089 DATA(StructureNotify), 1090 DATA(ResizeRedirect), 1091 DATA(SubstructureNotify), 1092 DATA(SubstructureRedirect), 1093 DATA(FocusChange), 1094 DATA(PropertyChange), 1095 DATA(ColormapChange), 1096 DATA(OwnerGrabButton), 1097 }; 1098#undef DATA 1099 Cardinal n; 1100 /* *INDENT-ON* */ 1101 1102 for (n = 0; n < XtNumber(table); ++n) { 1103 if (table[n].mask & mask) { 1104 TRACE(("%s %s\n", tag, table[n].name)); 1105 } 1106 } 1107} 1108 1109void 1110TraceWindowAttributes(XWindowAttributes * attrs) 1111{ 1112 TRACE(("window attributes:\n")); 1113 TRACE((" position %d,%d\n", attrs->y, attrs->x)); 1114 TRACE((" size %dx%d\n", attrs->height, attrs->width)); 1115 TRACE((" border %d\n", attrs->border_width)); 1116 TRACE((" depth %d\n", attrs->depth)); 1117 TRACE((" bit_gravity %d\n", attrs->bit_gravity)); 1118 TRACE((" win_gravity %d\n", attrs->win_gravity)); 1119 TRACE((" root %#lx\n", (long) attrs->root)); 1120 TRACE((" class %s\n", ((attrs->class == InputOutput) 1121 ? "InputOutput" 1122 : ((attrs->class == InputOnly) 1123 ? "InputOnly" 1124 : "unknown")))); 1125 TRACE((" map_state %s\n", ((attrs->map_state == IsUnmapped) 1126 ? "IsUnmapped" 1127 : ((attrs->map_state == IsUnviewable) 1128 ? "IsUnviewable" 1129 : ((attrs->map_state == IsViewable) 1130 ? "IsViewable" 1131 : "unknown"))))); 1132 TRACE((" all_events\n")); 1133 TraceEventMask(" ", attrs->all_event_masks); 1134 TRACE((" your_events\n")); 1135 TraceEventMask(" ", attrs->your_event_mask); 1136 TRACE((" no_propagate\n")); 1137 TraceEventMask(" ", attrs->do_not_propagate_mask); 1138} 1139 1140void 1141TraceWMSizeHints(XtermWidget xw) 1142{ 1143 XSizeHints sizehints = xw->hints; 1144 1145 getXtermSizeHints(xw); 1146 TraceSizeHints(&xw->hints); 1147 xw->hints = sizehints; 1148} 1149 1150const char * 1151ModifierName(unsigned modifier) 1152{ 1153 const char *s = ""; 1154 if (modifier & ShiftMask) 1155 s = " Shift"; 1156 else if (modifier & LockMask) 1157 s = " Lock"; 1158 else if (modifier & ControlMask) 1159 s = " Control"; 1160 else if (modifier & Mod1Mask) 1161 s = " Mod1"; 1162 else if (modifier & Mod2Mask) 1163 s = " Mod2"; 1164 else if (modifier & Mod3Mask) 1165 s = " Mod3"; 1166 else if (modifier & Mod4Mask) 1167 s = " Mod4"; 1168 else if (modifier & Mod5Mask) 1169 s = " Mod5"; 1170 return s; 1171} 1172 1173void 1174TraceTranslations(const char *name, Widget w) 1175{ 1176 String result; 1177 XErrorHandler save = XSetErrorHandler(ignore_x11_error); 1178 XtTranslations xlations; 1179 Widget xcelerat; 1180 1181 TRACE(("TraceTranslations for %s (widget %#lx) " TRACE_L "\n", 1182 name, (long) w)); 1183 if (w) { 1184 XtVaGetValues(w, 1185 XtNtranslations, &xlations, 1186 XtNaccelerators, &xcelerat, 1187 (XtPointer) 0); 1188 TRACE(("... xlations %#08lx\n", (long) xlations)); 1189 TRACE(("... xcelerat %#08lx\n", (long) xcelerat)); 1190 result = _XtPrintXlations(w, xlations, xcelerat, True); 1191 TRACE(("%s\n", NonNull(result))); 1192 if (result) 1193 XFree((char *) result); 1194 } else { 1195 TRACE(("none (widget is null)\n")); 1196 } 1197 TRACE((TRACE_R "\n")); 1198 XSetErrorHandler(save); 1199} 1200 1201XtGeometryResult 1202TraceResizeRequest(const char *fn, int ln, Widget w, 1203 unsigned reqwide, 1204 unsigned reqhigh, 1205 Dimension *gotwide, 1206 Dimension *gothigh) 1207{ 1208 XtGeometryResult rc; 1209 1210 TRACE(("%s@%d ResizeRequest %ux%u\n", fn, ln, reqhigh, reqwide)); 1211 rc = XtMakeResizeRequest((Widget) w, 1212 (Dimension) reqwide, 1213 (Dimension) reqhigh, 1214 gotwide, gothigh); 1215 TRACE(("... ResizeRequest -> ")); 1216 if (gothigh && gotwide) 1217 TRACE(("%dx%d ", *gothigh, *gotwide)); 1218 TRACE(("(%d)\n", rc)); 1219 return rc; 1220} 1221 1222#define XRES_S(name) Trace(#name " = %s\n", NonNull(resp->name)) 1223#define XRES_B(name) Trace(#name " = %s\n", MtoS(resp->name)) 1224#define XRES_I(name) Trace(#name " = %d\n", resp->name) 1225 1226void 1227TraceXtermResources(void) 1228{ 1229 XTERM_RESOURCE *resp = &resource; 1230 1231 Trace("XTERM_RESOURCE settings:\n"); 1232 XRES_S(icon_geometry); 1233 XRES_S(title); 1234 XRES_S(icon_hint); 1235 XRES_S(icon_name); 1236 XRES_S(term_name); 1237 XRES_S(tty_modes); 1238 XRES_I(minBufSize); 1239 XRES_I(maxBufSize); 1240 XRES_B(hold_screen); 1241 XRES_B(utmpInhibit); 1242 XRES_B(utmpDisplayId); 1243 XRES_B(messages); 1244 XRES_S(menuLocale); 1245 XRES_S(omitTranslation); 1246 XRES_S(keyboardType); 1247#ifdef HAVE_LIB_XCURSOR 1248 XRES_S(cursorTheme); 1249#endif 1250#if OPT_PRINT_ON_EXIT 1251 XRES_I(printModeNow); 1252 XRES_I(printModeOnXError); 1253 XRES_I(printOptsNow); 1254 XRES_I(printOptsOnXError); 1255 XRES_S(printFileNow); 1256 XRES_S(printFileOnXError); 1257#endif 1258#if OPT_SUNPC_KBD 1259 XRES_B(sunKeyboard); 1260#endif 1261#if OPT_HP_FUNC_KEYS 1262 XRES_B(hpFunctionKeys); 1263#endif 1264#if OPT_SCO_FUNC_KEYS 1265 XRES_B(scoFunctionKeys); 1266#endif 1267#if OPT_SUN_FUNC_KEYS 1268 XRES_B(sunFunctionKeys); 1269#endif 1270#if OPT_INITIAL_ERASE 1271 XRES_B(ptyInitialErase); 1272 XRES_B(backarrow_is_erase); 1273#endif 1274 XRES_B(useInsertMode); 1275#if OPT_ZICONBEEP 1276 XRES_I(zIconBeep); 1277 XRES_S(zIconFormat); 1278#endif 1279#if OPT_PTY_HANDSHAKE 1280 XRES_B(wait_for_map); 1281 XRES_B(ptyHandshake); 1282 XRES_B(ptySttySize); 1283#endif 1284#if OPT_REPORT_CCLASS 1285 XRES_B(reportCClass); 1286#endif 1287#if OPT_REPORT_COLORS 1288 XRES_B(reportColors); 1289#endif 1290#if OPT_REPORT_FONTS 1291 XRES_B(reportFonts); 1292#endif 1293#if OPT_REPORT_ICONS 1294 XRES_B(reportIcons); 1295#endif 1296#if OPT_SAME_NAME 1297 XRES_B(sameName); 1298#endif 1299#if OPT_SESSION_MGT 1300 XRES_B(sessionMgt); 1301#endif 1302#if OPT_TOOLBAR 1303 XRES_B(toolBar); 1304#endif 1305#if OPT_MAXIMIZE 1306 XRES_B(maximized); 1307 XRES_S(fullscreen_s); 1308#endif 1309#if USE_DOUBLE_BUFFER 1310 XRES_B(buffered); 1311 XRES_I(buffered_fps); 1312#endif 1313} 1314 1315void 1316TraceArgv(const char *tag, char **argv) 1317{ 1318 TRACE(("%s:\n", tag)); 1319 if (argv != 0) { 1320 int n = 0; 1321 1322 while (*argv != 0) { 1323 TRACE((" %d:%s\n", n++, *argv++)); 1324 } 1325 } 1326} 1327 1328static char * 1329parse_option(char *dst, String src, int first) 1330{ 1331 char *s; 1332 1333 if (!strncmp(src, "-/+", (size_t) 3)) { 1334 dst[0] = (char) first; 1335 strcpy(dst + 1, src + 3); 1336 } else { 1337 strcpy(dst, src); 1338 } 1339 for (s = dst; *s != '\0'; s++) { 1340 if (*s == '#' || *s == '%' || *s == 'S') { 1341 s[1] = '\0'; 1342 } else if (*s == ' ') { 1343 *s = '\0'; 1344 break; 1345 } 1346 } 1347 return dst; 1348} 1349 1350static Bool 1351same_option(OptionHelp * opt, XrmOptionDescRec * res) 1352{ 1353 char temp[BUFSIZ]; 1354 return !strcmp(parse_option(temp, opt->opt, res->option[0]), res->option); 1355} 1356 1357static Bool 1358standard_option(String opt) 1359{ 1360 static const char *table[] = 1361 { 1362 "+rv", 1363 "+synchronous", 1364 "-background", 1365 "-bd", 1366 "-bg", 1367 "-bordercolor", 1368 "-borderwidth", 1369 "-bw", 1370 "-display", 1371 "-fg", 1372 "-fn", 1373 "-font", 1374 "-foreground", 1375 "-geometry", 1376 "-iconic", 1377 "-name", 1378 "-reverse", 1379 "-rv", 1380 "-selectionTimeout", 1381 "-synchronous", 1382 "-title", 1383 "-xnllanguage", 1384 "-xrm", 1385 "-xtsessionID", 1386 }; 1387 Cardinal n; 1388 char temp[BUFSIZ]; 1389 1390 opt = parse_option(temp, opt, '-'); 1391 for (n = 0; n < XtNumber(table); n++) { 1392 if (!strcmp(opt, table[n])) 1393 return True; 1394 } 1395 return False; 1396} 1397 1398/* 1399 * Analyse the options/help messages for inconsistencies. 1400 */ 1401void 1402TraceOptions(OptionHelp * options, XrmOptionDescRec * resources, Cardinal res_count) 1403{ 1404 OptionHelp *opt_array = sortedOpts(options, resources, res_count); 1405 size_t j, k; 1406 XrmOptionDescRec *res_array = sortedOptDescs(resources, res_count); 1407 Bool first, found; 1408 1409 TRACE(("Checking options-tables for inconsistencies:\n")); 1410 1411#if 0 1412 TRACE(("Options listed in help-message:\n")); 1413 for (j = 0; options[j].opt != 0; j++) 1414 TRACE(("%5d %-28s %s\n", j, opt_array[j].opt, opt_array[j].desc)); 1415 TRACE(("Options listed in resource-table:\n")); 1416 for (j = 0; j < res_count; j++) 1417 TRACE(("%5d %-28s %s\n", j, res_array[j].option, res_array[j].specifier)); 1418#endif 1419 1420 /* list all options[] not found in resources[] */ 1421 for (j = 0, first = True; options[j].opt != 0; j++) { 1422 found = False; 1423 for (k = 0; k < res_count; k++) { 1424 if (same_option(&opt_array[j], &res_array[k])) { 1425 found = True; 1426 break; 1427 } 1428 } 1429 if (!found) { 1430 if (first) { 1431 TRACE(("Options listed in help, not found in resource list:\n")); 1432 first = False; 1433 } 1434 TRACE((" %-28s%s\n", opt_array[j].opt, 1435 standard_option(opt_array[j].opt) ? " (standard)" : "")); 1436 } 1437 } 1438 1439 /* list all resources[] not found in options[] */ 1440 for (j = 0, first = True; j < res_count; j++) { 1441 found = False; 1442 for (k = 0; options[k].opt != 0; k++) { 1443 if (same_option(&opt_array[k], &res_array[j])) { 1444 found = True; 1445 break; 1446 } 1447 } 1448 if (!found) { 1449 if (first) { 1450 TRACE(("Resource list items not found in options-help:\n")); 1451 first = False; 1452 } 1453 TRACE((" %s\n", res_array[j].option)); 1454 } 1455 } 1456 1457 TRACE(("Resource list items that will be ignored by XtOpenApplication:\n")); 1458 for (j = 0; j < res_count; j++) { 1459 switch (res_array[j].argKind) { 1460 case XrmoptionSkipArg: 1461 TRACE((" %-28s {param}\n", res_array[j].option)); 1462 break; 1463 case XrmoptionSkipNArgs: 1464 TRACE((" %-28s {%ld params}\n", res_array[j].option, (long) 1465 res_array[j].value)); 1466 break; 1467 case XrmoptionSkipLine: 1468 TRACE((" %-28s {remainder of line}\n", res_array[j].option)); 1469 break; 1470 case XrmoptionIsArg: 1471 case XrmoptionNoArg: 1472 case XrmoptionResArg: 1473 case XrmoptionSepArg: 1474 case XrmoptionStickyArg: 1475 default: 1476 break; 1477 } 1478 } 1479} 1480#else 1481extern void empty_trace(void); 1482void 1483empty_trace(void) 1484{ 1485} 1486#endif 1487