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