xdvi.c (26096B)
1 /*========================================================================*\ 2 3 Copyright (c) 1990-2013 Paul Vojta 4 5 Permission is hereby granted, free of charge, to any person obtaining a copy 6 of this software and associated documentation files (the "Software"), to 7 deal in the Software without restriction, including without limitation the 8 rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9 sell copies of the Software, and to permit persons to whom the Software is 10 furnished to do so, subject to the following conditions: 11 12 The above copyright notice and this permission notice shall be included in 13 all copies or substantial portions of the Software. 14 15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 IN NO EVENT SHALL PAUL VOJTA OR ANY OTHER AUTHOR OF OR CONTRIBUTOR TO 19 THIS SOFTWARE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22 IN THE SOFTWARE. 23 24 NOTE: 25 xdvi is based on prior work as noted in the modification history, below. 26 27 \*========================================================================*/ 28 29 /* 30 * DVI previewer for X. 31 * 32 * Eric Cooper, CMU, September 1985. 33 * 34 * Code derived from dvi-imagen.c. 35 * 36 * Modification history: 37 * 1/1986 Modified for X.10 --Bob Scheifler, MIT LCS. 38 * 7/1988 Modified for X.11 --Mark Eichin, MIT 39 * 12/1988 Added 'R' option, toolkit, magnifying glass 40 * --Paul Vojta, UC Berkeley. 41 * 2/1989 Added tpic support --Jeffrey Lee, U of Toronto 42 * 4/1989 Modified for System V --Donald Richardson, Clarkson Univ. 43 * 3/1990 Added VMS support --Scott Allendorf, U of Iowa 44 * 7/1990 Added reflection mode --Michael Pak, Hebrew U of Jerusalem 45 * 1/1992 Added greyscale code --Till Brychcy, Techn. Univ. Muenchen 46 * and Lee Hetherington, MIT 47 * 4/1994 Added DPS support, bounding box 48 * --Ricardo Telichevesky 49 * and Luis Miguel Silveira, MIT RLE. 50 * 1/2001 Added source specials --including ideas from Stefan Ulrich, 51 * U Munich 52 * 53 * Compilation options: 54 * WORDS_BIGENDIAN store bitmaps internally with most significant bit first 55 * BMTYPE store bitmaps in unsigned BMTYPE 56 * BMBYTES sizeof(unsigned BMTYPE) 57 * ALTFONT default for -altfont option 58 * SHRINK default for -s option (shrink factor) 59 * MFMODE default for -mfmode option 60 * A4 use European size paper, and change default dimension to cm 61 */ 62 63 #include <ctype.h> /* isdigit() */ 64 #include <err.h> 65 #include <stdarg.h> 66 #include <stdlib.h> /* exit(), atoi() */ 67 68 #include <X11/cursorfont.h> /* XC_cross */ 69 #include <X11/Shell.h> /* XtNiconX */ 70 #include <X11/IntrinsicI.h> 71 #include <X11/IntrinsicP.h> 72 #include <X11/Xaw/Viewport.h> 73 #include <X11/Xaw/AsciiText.h> 74 75 #include "default.h" /* default_dvi, default_dvi_len */ 76 #include "dvi-init.h" /* init_dvi_file(), init_page() */ 77 #include "dvi-draw.h" /* prescan() */ 78 #include "events.h" /* compile_action(), ... */ 79 #include "font-open.h" /* init_font_open() */ 80 #include "util.h" /* xmalloc() */ 81 #include "version.h" 82 #include "xdvi.h" 83 #include "xdvi.icon" 84 85 #define ALTFONT "cmr10" 86 #define SHRINK 3 87 #define BDPI 600 88 #define MFMODE "cx:600" 89 90 #if A4 91 #define DEFAULT_PAPER "a4" 92 #else 93 #define DEFAULT_PAPER "letter" 94 #endif 95 96 97 struct WindowRec mane = {(Window) 0, 1, 0, 0, 0, 0, MAXDIM, 0, MAXDIM, 0}; 98 struct WindowRec alt = {(Window) 0, 1, 0, 0, 0, 0, MAXDIM, 0, MAXDIM, 0}; 99 /* currwin is temporary storage except for within redraw() */ 100 struct WindowRec currwin= {(Window) 0, 1, 0, 0, 0, 0, MAXDIM, 0, MAXDIM, 0}; 101 102 /* 103 * Data for options processing 104 */ 105 106 static XrmOptionDescRec options[] = { 107 {"-s", ".shrinkFactor", XrmoptionSepArg, NULL}, 108 {"-nocolor", ".color", XrmoptionNoArg, "off"}, 109 {"+nocolor", ".color", XrmoptionNoArg, "on"}, 110 {"-gamma", ".gamma", XrmoptionSepArg, NULL}, 111 {"-p", ".pixelsPerInch", XrmoptionSepArg, NULL}, 112 {"-altfont", ".altFont", XrmoptionSepArg, NULL}, 113 {"-mfmode", ".mfMode", XrmoptionSepArg, NULL}, 114 {"-l", ".listFonts", XrmoptionNoArg, "on"}, 115 {"+l", ".listFonts", XrmoptionNoArg, "off"}, 116 {"-fg", ".foreground", XrmoptionSepArg, NULL}, 117 {"-foreground", ".foreground", XrmoptionSepArg, NULL}, 118 {"-bg", ".background", XrmoptionSepArg, NULL}, 119 {"-background", ".background", XrmoptionSepArg, NULL}, 120 {"-copy", ".copy", XrmoptionNoArg, "on"}, 121 {"+copy", ".copy", XrmoptionNoArg, "off"}, 122 {"-thorough", ".thorough", XrmoptionNoArg, "on"}, 123 {"+thorough", ".thorough", XrmoptionNoArg, "off"}, 124 {"-debug", ".debugLevel", XrmoptionSepArg, NULL}, 125 {"-v", ".version", XrmoptionNoArg, "on"}, 126 }; 127 128 static const char base_translations[] = "" 129 "^<Key>c:quit()\n" /* Control keys first */ 130 "^<Key>d:quit()\n" 131 "^<Key>m:forward-page()\n" 132 "^<Key>j:forward-page()\n" 133 "^<Key>l:forward-page(0)\n" 134 "^<Key>h:back-page()\n" 135 "^<Key>p:print()\n" 136 "a<Key>p:show-display-attributes()\n" 137 "\"q\":quit()\n" 138 "\"d\":down()\n" 139 "\"f\":show-links()\n" 140 "\"n\":forward-page()\n" 141 "\" \":down-or-next()\n" 142 "<Key>Return:addr-go()\n" 143 "\"p\":back-page()\n" 144 "\"b\":back-page()\n" 145 "<Key>Delete:up-or-previous()\n" 146 "<Key>BackSpace:up-or-previous()\n" 147 "\"P\":declare-page-number()\n" 148 "\"g\":goto-page()\n" 149 "\"\\^\":home()\n" 150 "\"c\":center()\n" 151 "\"l\":left()\n" 152 "\"r\":right()\n" 153 "\"u\":up()\n" 154 "\"s\":set-shrink-factor()\n" 155 "\"S\":set-density()\n" 156 "<Key>Home:home()\n" 157 "<Key>Left:left()\n" 158 "<Key>Up:up()\n" 159 "<Key>Right:right()\n" 160 "<Key>Down:down()\n" 161 "<Key>Prior:back-page()\n" 162 "<Key>Next:forward-page()\n" 163 "\"C\":set-color()\n" 164 "<Key>Escape:discard-number()\n" /* Esc */ 165 "s<Btn1Down>:drag(|)\n" 166 "s<Btn2Down>:drag(+)\n" 167 "s<Btn3Down>:drag(-)\n" 168 "<Btn1Down>:magnifier(*1)\n" 169 "<Btn2Down>:magnifier(*2)\n" 170 "<Btn3Down>:magnifier(*3)\n"; 171 172 #define offset(field) XtOffsetOf(struct _resource, field) 173 174 static XtResource application_resources[] = { 175 {"shrinkFactor", "ShrinkFactor", XtRInt, sizeof(int), 176 offset(shrinkfactor), XtRImmediate, (XtPointer) SHRINK}, 177 {"mainTranslations", "MainTranslations", XtRString, sizeof(char *), 178 offset(main_translations), XtRString, NULL}, 179 {"wheelTranslations", "WheelTranslations", XtRString, sizeof(char *), 180 offset(wheel_translations), XtRString, "<Btn4Down>:wheel(-1.)\n\ 181 <Btn5Down>:wheel(1.)\n<Btn6Down>:hwheel(-1.)\n<Btn7Down>:hwheel(1.)"}, 182 {"gamma", "Gamma", XtRFloat, sizeof(float), 183 offset(_gamma), XtRString, "1"}, 184 {"pixelsPerInch", "PixelsPerInch", XtRInt, sizeof(int), 185 offset(_pixels_per_inch), XtRImmediate, (XtPointer) BDPI}, 186 {"altFont", "AltFont", XtRString, sizeof(char *), 187 offset(_alt_font), XtRString, ALTFONT}, 188 {"mfMode", "MfMode", XtRString, sizeof(char *), 189 offset(mfmode), XtRString, MFMODE}, 190 {"listFonts", "ListFonts", XtRBoolean, sizeof(Boolean), 191 offset(_list_fonts), XtRString, "false"}, 192 {"reverseVideo", "ReverseVideo", XtRBoolean, sizeof(Boolean), 193 offset(reverse), XtRString, "false"}, 194 {"copy", "Copy", XtRBoolean, sizeof(Boolean), 195 offset(copy), XtRString, "false"}, 196 {"thorough", "Thorough", XtRBoolean, sizeof(Boolean), 197 offset(thorough), XtRString, "false"}, 198 {"debugLevel", "DebugLevel", XtRString, sizeof(char *), 199 offset(debug_arg), XtRString, NULL}, 200 {"version", "Version", XtRBoolean, sizeof(Boolean), 201 offset(version_flag), XtRString, "false"}, 202 {"color", "Color", XtRBoolean, sizeof(Boolean), 203 offset(_use_color), XtRString, "true"}, 204 }; 205 206 static XtResource app_pixel_resources[] = { /* get these later */ 207 {"foreground", "Foreground", XtRPixel, sizeof(Pixel), 208 offset(_fore_Pixel), XtRString, XtDefaultForeground}, 209 {"background", "Background", XtRPixel, sizeof(Pixel), 210 offset(_back_Pixel), XtRString, XtDefaultBackground}, 211 }; 212 #undef offset 213 214 215 static XtGeometryResult 216 QueryGeometry(Widget w, XtWidgetGeometry *constraints, XtWidgetGeometry *reply) 217 { 218 reply->request_mode = CWWidth | CWHeight; 219 reply->width = page_w; 220 reply->height = page_h; 221 return XtGeometryAlmost; 222 } 223 224 static WidgetClassRec drawingWidgetClass = { 225 /* superclass */ &widgetClassRec, 226 /* class_name */ "Draw", 227 /* widget_size */ sizeof(WidgetRec), 228 /* class_initialize */ NULL, 229 /* class_part_initialize*/ NULL, 230 /* class_inited */ FALSE, 231 /* initialize */ NULL, 232 /* initialize_hook */ NULL, 233 /* realize */ XtInheritRealize, 234 /* actions */ NULL, 235 /* num_actions */ 0, 236 /* resources */ NULL, 237 /* num_resources */ 0, 238 /* xrm_class */ NULLQUARK, 239 /* compress_motion */ FALSE, 240 /* compress_exposure */ TRUE, 241 /* compress_enterleave*/ FALSE, 242 /* visible_interest */ FALSE, 243 /* destroy */ NULL, 244 /* resize */ XtInheritResize, 245 /* expose */ XtInheritExpose, 246 /* set_values */ NULL, 247 /* set_values_hook */ NULL, 248 /* set_values_almost */ XtInheritSetValuesAlmost, 249 /* get_values_hook */ NULL, 250 /* accept_focus */ XtInheritAcceptFocus, 251 /* version */ XtVersion, 252 /* callback_offsets */ NULL, 253 /* tm_table */ XtInheritTranslations, 254 /* query_geometry */ QueryGeometry, 255 /* display_accelerator */ XtInheritDisplayAccelerator, 256 /* extension */ NULL 257 }; 258 259 static void 260 usage(const char *message, ...) 261 { 262 va_list args; 263 264 va_start(args, message); 265 vwarnx(message, args); 266 va_end(args); 267 268 fprintf(stderr, "\nUsage: wdvi "); 269 fprintf(stderr, 270 "[-s <shrink>] [-nocolor] [-gamma <g>] [-p <pixels>] [-altfont <font>]\n" 271 "\t[-mfmode <mode-def>] [-l] [-rv]\n" 272 "\t[-display <host:display>]\n" 273 "\t[-fg <color>] [-bg <color>] [-bd <color>]\n" 274 "\t[-geometry <geometry>] [-font <font>] [-copy] [-thorough]\n" 275 "\t[-debug <bitmask>] [-v] url\n"); 276 277 exit(1); 278 } 279 280 281 /** 282 ** Main program starts here. 283 **/ 284 285 struct modifierinf { 286 int len; 287 const char *name; 288 Modifiers mask; 289 KeySym keysym; 290 }; 291 292 /* Allowed modifiers, sorted by length and then lexicographically. */ 293 294 static struct modifierinf modifiers[] = { 295 {1, "a", 0, XK_Alt_L}, 296 {1, "c", ControlMask, 0}, 297 {1, "h", 0, XK_Hyper_L}, 298 {1, "l", LockMask, 0}, 299 {1, "m", 0, XK_Meta_L}, 300 {1, "s", ShiftMask, 0}, 301 {2, "su", 0, XK_Super_L}, 302 {3, "Alt", 0, XK_Alt_L}, 303 {4, "Ctrl", ControlMask, 0}, 304 {4, "Lock", LockMask, 0}, 305 {4, "Meta", 0, XK_Meta_L}, 306 {4, "Mod1", Mod1Mask, 0}, 307 {4, "Mod2", Mod2Mask, 0}, 308 {4, "Mod3", Mod3Mask, 0}, 309 {4, "Mod4", Mod4Mask, 0}, 310 {4, "Mod5", Mod5Mask, 0}, 311 {5, "Hyper", 0, XK_Hyper_L}, 312 {5, "Shift", ShiftMask, 0}, 313 {5, "Super", 0, XK_Super_L}, 314 {7, "Button1", Button1Mask, 0}, 315 {7, "Button2", Button2Mask, 0}, 316 {7, "Button3", Button3Mask, 0}, 317 {7, "Button4", Button4Mask, 0}, 318 {7, "Button5", Button5Mask, 0}, 319 }; 320 321 #define MODSCTRLINDEX 1 /* index of "c" in the above array */ 322 #define MODSMETAINDEX 4 /* index of "m" */ 323 324 325 static Bool 326 compile_modifiers(const char **pp, struct wheel_acts *wactp) 327 { 328 const char *p = *pp; 329 const char *p1; 330 LateBindingsPtr latep = NULL; 331 int nlate; 332 333 while (*p == ' ' || *p == '\t') ++p; 334 335 p1 = p; 336 while ((*p1 | ('a' ^ 'A')) >= 'a' && (*p1 | ('a' ^ 'A')) <= 'z') 337 ++p1; 338 339 if (p1 - p == 3 && memcmp(p, "Any", 3) == 0) { 340 wactp->mask = wactp->value = 0; 341 p = p1; 342 while (*p == ' ' || *p == '\t') ++p; 343 if (*p != '<') 344 return False; 345 } 346 else if (p1 - p == 4 && memcmp(p, "None", 4) == 0) { 347 wactp->mask = ~0; 348 wactp->value = 0; 349 p = p1; 350 while (*p == ' ' || *p == '\t') ++p; 351 if (*p != '<') 352 return False; 353 } 354 else { 355 if (*p == '!') { 356 do { 357 ++p; 358 } while (*p == ' ' || *p == '\t'); 359 } 360 361 for (;;) { 362 Bool negated = False; 363 struct modifierinf *mp; 364 365 if (*p == '<') 366 break; 367 368 if (*p == '~') { 369 negated = True; 370 ++p; 371 } 372 373 if (*p == '^') { 374 mp = &modifiers[MODSCTRLINDEX]; 375 ++p; 376 } 377 else if (*p == '$') { 378 mp = &modifiers[MODSMETAINDEX]; 379 ++p; 380 } 381 else { 382 int min, max; 383 384 p1 = p; 385 while (((*p | ('a' ^ 'A')) >= 'a' 386 && (*p | ('a' ^ 'A')) <= 'z') 387 || (*p >= '0' && *p <= '9')) 388 ++p; 389 390 /* do binary search */ 391 min = -1; 392 max = XtNumber(modifiers); 393 for (;;) { 394 int i, diff; 395 396 i = (min + max) / 2; 397 if (i == min) 398 return False; /* if not found */ 399 mp = &modifiers[i]; 400 401 diff = (p - p1) - mp->len; 402 if (diff == 0) 403 diff = memcmp(p1, mp->name, p - p1); 404 405 if (diff == 0) 406 break; 407 if (diff > 0) min = i; 408 else max = i; 409 } 410 } 411 if (mp->mask) { 412 wactp->mask |= mp->mask; 413 if (!negated) wactp->value |= mp->mask; 414 } 415 else { 416 LateBindingsPtr lp1; 417 418 if (latep == NULL) { 419 nlate = 3; 420 latep = xmalloc(3 * sizeof(LateBindings)); 421 latep->ref_count = 1; 422 } 423 else { 424 nlate += 2; 425 latep = xrealloc(latep, nlate * sizeof(LateBindings)); 426 } 427 lp1 = &latep[nlate - 3]; 428 lp1->knot = lp1[1].knot = negated; 429 lp1->pair = True; 430 lp1->keysym = mp->keysym; 431 ++lp1; 432 lp1->pair = False; 433 lp1->ref_count = 0; 434 lp1->keysym = mp->keysym + 1; 435 ++lp1; 436 lp1->knot = lp1->pair = False; 437 lp1->ref_count = 0; 438 lp1->keysym = 0; 439 } 440 441 while (*p == ' ' || *p == '\t') ++p; 442 } 443 } 444 445 wactp->late_bindings = latep; 446 *pp = p; 447 448 return True; 449 } 450 451 static Bool 452 compile_evtype(const char **pp, unsigned int *buttonp) 453 { 454 const char *p = *pp; 455 const char *p0; 456 457 ++p; /* already assumed to be '<' */ 458 while (*p == ' ' || *p == '\t') ++p; 459 460 p0 = p; 461 while (((*p | ('a' ^ 'A')) >= 'a' && (*p | ('a' ^ 'A')) <= 'z') 462 && p - p0 < 3) 463 ++p; 464 465 if (p - p0 != 3 || memcmp(p0, "Btn", 3) != 0) 466 return False; 467 468 if (*p >= '1' && *p <= '9') { 469 unsigned int n = *p - '0'; 470 471 while (*++p >= '0' && *p <= '9') 472 n = n * 10 + (*p - '0'); 473 474 *buttonp = n; 475 } 476 477 p0 = p; 478 while (((*p | ('a' ^ 'A')) >= 'a' && (*p | ('a' ^ 'A')) <= 'z')) 479 ++p; 480 481 if (p - p0 != 4 || memcmp(p0, "Down", 4) != 0) 482 return False; 483 484 while (*p == ' ' || *p == '\t') ++p; 485 486 if (*p++ != '>') 487 return False; 488 489 while (*p == ' ' || *p == '\t') ++p; 490 491 if (*p++ != ':') 492 return False; 493 494 *pp = p; 495 496 return True; 497 } 498 499 static void 500 compile_wheel_actions(void) 501 { 502 struct wheel_acts **wactpp; 503 struct wheel_acts *wactp; 504 const char *p = resource.wheel_translations; 505 const char *p_end = p + strlen(p); 506 struct wheel_acts wact; 507 508 wactpp = &wheel_actions; 509 510 for (;;) { 511 while (*p == ' ' || *p == '\t') ++p; 512 513 if (*p == '\n') continue; 514 if (*p == '\0') break; 515 516 wact.mask = wact.value = 0; 517 wact.button = 0; 518 519 if (!compile_modifiers(&p, &wact) 520 || !compile_evtype(&p, &wact.button)) 521 warnx("syntax error in wheel translations"); 522 else if (compile_action(p, &wact.action) || wact.action != NULL) { 523 wactp = xmalloc(sizeof(struct wheel_acts)); 524 *wactp = wact; 525 526 *wactpp = wactp; 527 wactpp = &wactp->next; 528 } 529 530 p = memchr(p, '\n', p_end - p); 531 if (p == NULL) break; 532 ++p; 533 } 534 535 *wactpp = NULL; 536 } 537 538 static void 539 set_default_winsize(void) 540 { 541 Dimension addr_bwidth; 542 Dimension bwidth; 543 Dimension screen_w, screen_h; 544 XtWidgetGeometry addr_reply; 545 XtWidgetGeometry constraints; 546 XtWidgetGeometry reply; 547 int i; 548 int addr_height; 549 550 XtQueryGeometry(addr_widget, NULL, &addr_reply); 551 XtVaGetValues(addr_widget, XtNborderWidth, &addr_bwidth, NULL); 552 addr_height = addr_reply.height + 2 * addr_bwidth; 553 554 /* 555 * The total screen_{w,h} is what is left over after the address bar 556 * and borders have been taken into account. 557 */ 558 XtVaGetValues(top_level, XtNborderWidth, &bwidth, NULL); 559 screen_w = WidthOfScreen(SCRN) - 2 * bwidth; 560 screen_h = HeightOfScreen(SCRN) - 2 * bwidth - addr_height; 561 562 Arg set_wh_args[] = { 563 {XtNwidth, (XtArgVal) 0}, 564 {XtNheight, (XtArgVal) 0}, 565 }; 566 for (;;) { /* actually, at most two passes */ 567 constraints.request_mode = reply.request_mode = 0; 568 constraints.width = page_w; 569 if (page_w > screen_w) { 570 constraints.request_mode = CWWidth; 571 constraints.width = screen_w; 572 } 573 constraints.height = page_h; 574 if (page_h > screen_h) { 575 constraints.request_mode |= CWHeight; 576 constraints.height = screen_h; 577 } 578 if (constraints.request_mode != 0 579 && constraints.request_mode != (CWWidth | CWHeight)) 580 XtQueryGeometry(vport_widget, &constraints, &reply); 581 if (!(reply.request_mode & CWWidth)) 582 reply.width = constraints.width; 583 if (reply.width >= screen_w) 584 reply.width = screen_w; 585 if (!(reply.request_mode & CWHeight)) 586 reply.height = constraints.height; 587 if (reply.height >= screen_h) 588 reply.height = screen_h; 589 590 /* now reply.{width,height} contain max. usable window size */ 591 592 if (shrink_factor != 0) 593 break; 594 595 shrink_factor = ROUNDUP(unshrunk_page_w, reply.width - 2); 596 i = ROUNDUP(unshrunk_page_h, reply.height - 2); 597 if (i >= shrink_factor) 598 shrink_factor = i; 599 if (shrink_factor > 1) 600 bak_shrink = shrink_factor; 601 mane.shrinkfactor = shrink_factor; 602 init_page(); 603 set_wh_args[0].value = (XtArgVal) page_w; 604 set_wh_args[1].value = (XtArgVal) page_h; 605 XtSetValues(draw_widget, set_wh_args, XtNumber(set_wh_args)); 606 } 607 set_wh_args[0].value = reply.width; 608 set_wh_args[1].value = reply.height + addr_height; 609 XtSetValues(top_level, set_wh_args, XtNumber(set_wh_args)); 610 611 set_wh_args[0].value = reply.width - (2 * addr_bwidth); 612 XtSetValues(addr_widget, set_wh_args, 1); 613 } 614 615 /* 616 * main program 617 */ 618 619 int 620 main(int argc, char *argv[]) 621 { 622 const char *url = NULL; 623 const char *arg; 624 XrmDatabase db; 625 int i; 626 627 628 /* 629 * Step 1: Process command-line options and resources. 630 */ 631 632 top_level = XtInitialize("wdvi", "XDvi", options, XtNumber(options), 633 &argc, argv); 634 XtAddActions(Actions, num_actions); 635 636 while (--argc > 0) { 637 arg = *++argv; 638 639 if (arg[0] == '-') 640 usage("Unknown option '%s'.", arg); 641 if (url != NULL) 642 usage("More than one url specified", arg); 643 else 644 url = arg; 645 } 646 647 DISP = XtDisplay(top_level); 648 SCRN = XtScreen(top_level); 649 650 db = XtScreenDatabase(SCRN); 651 652 /* It's easier to do this than track creations and deletions of the 653 scrollbars. */ 654 XrmPutStringResource(&db, "XDvi.file.form.vport.vertical.translations", 655 "#override<Btn4Down>:file-scroll(-w)\n<Btn5Down>:file-scroll(w)"); 656 XrmPutStringResource(&db, "XDvi.file.form.vport.horizontal.translations", 657 "#override<Btn4Down>:file-scroll(-w)\n<Btn5Down>:file-scroll(w)"); 658 659 XtGetApplicationResources(top_level, &resource, application_resources, 660 XtNumber(application_resources), (ArgList) NULL, 0); 661 shrink_factor = resource.shrinkfactor; 662 663 if (resource.version_flag) 664 errx(0, "version %s", VERSION); 665 666 if (resource.debug_arg != NULL) 667 debug = isdigit(*resource.debug_arg) ? atoi(resource.debug_arg) 668 : DBG_ALL; 669 670 char *atom_names[] = { "WM_DELETE_WINDOW", "WM_PROTOCOLS" }; 671 if (!XInternAtoms(DISP, atom_names, XtNumber(atom_names), False, atoms)) 672 errx(1, "XInternAtoms failed."); 673 674 if (debug & DBG_CLIENT) { 675 for (i = 0; i < XtNumber(atom_names); ++i) 676 printf("Atom(%s) = %lu\n", atom_names[i], atoms[i]); 677 } 678 679 if (DefaultDepthOfScreen(SCRN) < 24) 680 errx(1, "X depth < 24 is not supported."); 681 if (DefaultVisualOfScreen(SCRN)->class != TrueColor) 682 errx(1, "X visual not 'TrueColor' is not supported."); 683 684 /* 685 * The default document is always available and simplifies startup 686 * by giving inital window sizes and no error popups. 687 */ 688 if ((dvi_file = fmemopen(default_dvi, default_dvi_len, "r")) == NULL) 689 err(1, "fmemopen"); 690 dvi_name = "default.dvi"; 691 ev_flags |= EV_NEWDOC; 692 read_events(EV_GE_NEWDOC); 693 ev_flags &= ~EV_NEWDOC; 694 695 if (resource.mfmode != NULL) { 696 char *p; 697 698 p = rindex(resource.mfmode, ':'); 699 if (p != NULL) { 700 unsigned int len; 701 char *p1; 702 703 ++p; 704 len = p - resource.mfmode; 705 p1 = xmalloc(len); 706 bcopy(resource.mfmode, p1, len - 1); 707 p1[len - 1] = '\0'; 708 resource.mfmode = p1; 709 pixels_per_inch = atoi(p); 710 } 711 } 712 if (shrink_factor < 0 || shrink_factor > 10) 713 usage("Invalid shrink factor: %d.", shrink_factor); 714 if (pixels_per_inch <= 0) 715 usage("Invalid dpi value: %d.", pixels_per_inch); 716 717 if (shrink_factor > 1) { 718 bak_shrink = shrink_factor; 719 mane.shrinkfactor = shrink_factor; /* otherwise it's 1 */ 720 } 721 722 /* 1 inch */ 723 offset_x = pixels_per_inch; 724 offset_y = pixels_per_inch; 725 726 unshrunk_paper_w = 8.5 * pixels_per_inch; 727 unshrunk_paper_h = 11 * pixels_per_inch; 728 729 /* 730 * Step 2: Settle colormap issues. This should be done before 731 * other widgets are created, so that they get the right 732 * pixel values. (The top-level widget won't have the right 733 * values, but I don't think that makes any difference.) 734 */ 735 736 XtGetApplicationResources(top_level, &resource, 737 app_pixel_resources, XtNumber(app_pixel_resources), 738 (ArgList) NULL, 0); 739 740 fore_color_data.pixel = resource._fore_Pixel; 741 back_color_data.pixel = resource._back_Pixel; 742 XQueryColors(DISP, DefaultColormapOfScreen(SCRN), color_data, 2); 743 744 fg_initial.r = fore_color_data.red; 745 fg_initial.g = fore_color_data.green; 746 fg_initial.b = fore_color_data.blue; 747 bg_initial.r = back_color_data.red; 748 bg_initial.g = back_color_data.green; 749 bg_initial.b = back_color_data.blue; 750 751 /* 752 * Step 3: Initialize the dvi file and set titles. 753 */ 754 755 init_font_open(); 756 if (init_dvi_file() == False) 757 errx(1, "Bad default DVI document"); 758 prescan(); 759 init_page(); 760 761 /* 762 * Step 4: Set initial window size. 763 * This needs to be done before colors are assigned because if 764 * -s 0 is specified, then we need to compute the shrink factor 765 * (which in turn affects whether init_pix is called). 766 */ 767 768 /* Create icon. */ 769 XtVaSetValues(top_level, XtNiconPixmap, 770 XCreateBitmapFromData( DISP, XtScreen(top_level)->root, 771 (const char *) xdvi_bits, xdvi_width, xdvi_height), 772 NULL); 773 774 XtVaSetValues(top_level, XtNinput, True, NULL); 775 776 XrmPutStringResource(&db, "XDvi.form.baseTranslations", 777 base_translations); 778 779 if (resource.main_translations != NULL) 780 XrmPutStringResource(&db, "XDvi.form.translations", 781 resource.main_translations); 782 783 /* 784 * Widget creation. 785 */ 786 form_widget = XtVaCreateManagedWidget("form", formWidgetClass, 787 top_level, XtNdefaultDistance, 0, 788 NULL); 789 790 vport_widget = XtVaCreateManagedWidget("vport", viewportWidgetClass, 791 form_widget, 792 XtNborderWidth, 0, 793 XtNtop, XawChainTop, 794 XtNbottom, XawChainBottom, 795 XtNleft, XawChainLeft, 796 XtNright, XawChainRight, 797 XtNallowHoriz, True, 798 XtNallowVert, True, 799 NULL); 800 801 clip_widget = XtNameToWidget(vport_widget, "clip"); 802 803 draw_widget = XtVaCreateManagedWidget("drawing", &drawingWidgetClass, 804 vport_widget, 805 XtNwidth, page_w, 806 XtNheight, page_h, 807 XtNx, 0, 808 XtNy, 0, 809 XtNlabel, (XtArgVal) "", 810 NULL); 811 812 addr_widget = XtVaCreateManagedWidget("address", asciiTextWidgetClass, 813 form_widget, 814 XtNfromVert, (XtArgVal) vport_widget, 815 XtNdataCompression, False, 816 XtNeditType, XawtextEdit, 817 /* Don't resize this widget with the rest of the form. */ 818 XtNtop, XawChainBottom, 819 XtNbottom, XawChainBottom, 820 XtNstring, (XtArgVal) (url ? url : addr_default), 821 XtNinsertPosition, strlen(url ? url : addr_default), 822 NULL); 823 824 XtOverrideTranslations(addr_widget, XtParseTranslationTable( 825 "<Key>Return:addr-go()")); 826 827 XtOverrideTranslations(form_widget, XtParseTranslationTable( 828 "\"0\":digit(0)\n" 829 "\"1\":digit(1)\n" 830 "\"2\":digit(2)\n" 831 "\"3\":digit(3)\n" 832 "\"4\":digit(4)\n" 833 "\"5\":digit(5)\n" 834 "\"6\":digit(6)\n" 835 "\"7\":digit(7)\n" 836 "\"8\":digit(8)\n" 837 "\"9\":digit(9)\n" 838 "\"-\":minus()\n" 839 "<Motion>:motion()\n" 840 "<BtnUp>:release()")); 841 842 if (resource.wheel_translations != NULL) { 843 XtAugmentTranslations(form_widget, XtParseTranslationTable( 844 "<BtnDown>:wheel-actions()")); 845 846 compile_wheel_actions(); 847 } 848 849 /* set background colors of the drawing and clip widgets */ 850 Arg back_args = {XtNbackground, (XtArgVal) resource._back_Pixel}; 851 XtSetValues(draw_widget, &back_args, 1); 852 XtSetValues(clip_widget, &back_args, 1); 853 854 set_default_winsize(); 855 856 /* 857 * Step 5: Realize the widgets (or windows). 858 */ 859 860 861 XtAddEventHandler(vport_widget, StructureNotifyMask, False, 862 handle_resize, NULL); 863 XtAddEventHandler(draw_widget, ExposureMask, False, handle_expose, 864 &mane); 865 XtRealizeWidget(top_level); 866 867 /* 868 * Assume that if we have a vertical scroll bar its because of 869 * vertical overflow. Make the window wider to account for the 870 * bars width. 871 */ 872 Widget y_bar = XtNameToWidget(vport_widget, "vertical"); 873 if (y_bar != NULL) { 874 Dimension width; 875 XtWidgetGeometry reply; 876 877 XtVaGetValues(y_bar, XtNwidth, &width, NULL); 878 XtQueryGeometry(top_level, NULL, &reply); 879 880 XtVaSetValues(top_level, XtNwidth, reply.width + width + 1, 881 NULL); 882 } 883 884 XSetWMProtocols(DISP, XtWindow(top_level), &XA_WM_DELETE_WINDOW, 1); 885 XtAddEventHandler(top_level, NoEventMask, True, handle_messages, NULL); 886 887 currwin.win = mane.win = XtWindow(draw_widget); 888 889 XSetWindowAttributes wattrs; 890 wattrs.backing_store = Always; 891 XChangeWindowAttributes(DISP, mane.win, CWBackingStore, &wattrs); 892 893 image = XCreateImage(DISP, CopyFromParent, 1, XYBitmap, 0, 894 (char *) NULL, 0, 0, BMBITS, 0); 895 image->bitmap_unit = BMBITS; 896 #ifdef WORDS_BIGENDIAN 897 image->bitmap_bit_order = MSBFirst; 898 #else 899 image->bitmap_bit_order = LSBFirst; 900 #endif 901 short endian = MSBFirst << 8 | LSBFirst; 902 image->byte_order = *((char *) &endian); 903 904 /* 905 * Step 6: Assign colors and GCs. 906 * Because of the latter, this has to go after Step 5. 907 * In color mode, color changes affect foreGC, foreGC2, 908 * and ruleGC, but not copyGC. 909 */ 910 911 if (resource._gamma == 0.0) 912 resource._gamma = 1.0; 913 if (resource.reverse) 914 resource._gamma = 1.5; 915 916 #define MakeGC(fcn, fg, bg) (values.function = fcn, \ 917 values.foreground=fg, values.background=bg, \ 918 XCreateGC(DISP, XtWindow(top_level), \ 919 GCFunction | GCForeground | GCBackground, &values)) 920 921 XGCValues values; 922 923 /* Not affected by color changes. */ 924 copyGC = MakeGC(GXcopy, resource._fore_Pixel, resource._back_Pixel); 925 linkGC = MakeGC(GXxor, resource._fore_Pixel ^ resource._back_Pixel, 926 resource._back_Pixel); 927 928 ready_cursor = XCreateFontCursor(DISP, XC_cross); 929 redraw_cursor = XCreateFontCursor(DISP, XC_watch); 930 931 for(;;) /* normal operation */ 932 do_pages(); 933 }