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