xditview.c revision 00994698
1/* 2 3Copyright (c) 1991 X Consortium 4 5Permission is hereby granted, free of charge, to any person obtaining 6a copy of this software and associated documentation files (the 7"Software"), to deal in the Software without restriction, including 8without limitation the rights to use, copy, modify, merge, publish, 9distribute, sublicense, and/or sell copies of the Software, and to 10permit persons to whom the Software is furnished to do so, subject to 11the following conditions: 12 13The above copyright notice and this permission notice shall be included 14in all copies or substantial portions of the Software. 15 16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR 20OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22OTHER DEALINGS IN THE SOFTWARE. 23 24Except as contained in this notice, the name of the X Consortium shall 25not be used in advertising or otherwise to promote the sale, use or 26other dealings in this Software without prior written authorization 27from the X Consortium. 28 29*/ 30/* 31 * xditview -- 32 * 33 * Display ditroff output in an X window 34 */ 35 36#ifdef HAVE_CONFIG_H 37# include "config.h" 38#endif 39 40#include <X11/Intrinsic.h> 41#include <X11/StringDefs.h> 42#include <X11/Xatom.h> 43#include <X11/Shell.h> 44#include <X11/Xos.h> 45#include <X11/Xaw/Paned.h> 46#include <X11/Xaw/Panner.h> 47#include <X11/Xaw/Porthole.h> 48#include <X11/Xaw/Viewport.h> 49#include <X11/Xaw/Box.h> 50#include <X11/Xaw/Command.h> 51#include <X11/Xaw/Dialog.h> 52#include <X11/Xaw/Label.h> 53#include <X11/Xaw/MenuButton.h> 54#include <X11/Xaw/SimpleMenu.h> 55#include <X11/Xaw/SmeBSB.h> 56#include <X11/Xaw/AsciiText.h> 57 58#include "Dvi.h" 59 60#include "xdit.bm" 61#include "xdit_mask.bm" 62#include <stdio.h> 63#include <stdlib.h> 64#include <sys/stat.h> 65 66/* Command line options table. Only resources are entered here...there is a 67 pass over the remaining options after XtParseCommand is let loose. */ 68 69static XrmOptionDescRec options[] = { 70 {"-page", "*dvi.pageNumber", XrmoptionSepArg, NULL}, 71 {"-backingStore", "*dvi.backingStore", XrmoptionSepArg, NULL}, 72 {"-noPolyText", "*dvi.noPolyText", XrmoptionNoArg, "TRUE"}, 73 {"-resolution", "*dvi.screenResolution", XrmoptionSepArg, NULL}, 74}; 75 76static char current_file_name[1024]; 77static FILE *current_file; 78 79static void MakePrompt(Widget, const char *, void (*)(char *), char *); 80 81/* 82 * Report the syntax for calling xditview. 83 */ 84 85static void 86Syntax(const char *call, int exitval) 87{ 88 (void) printf("Usage: %s [-fg <color>] [-bg <color>]\n%s\n", call, 89 " [-bd <color>] [-bw <pixels>] [-help] [-version]\n" 90 " [-display displayname] [-geometry geom]\n" 91 " [-page <page-number>] [-backing <backing-store>]\n" 92 " [-resolution <screen-resolution>]\n"); 93 exit(exitval); 94} 95 96static void NewResolution(char *resString); 97static void NewFile(char *name); 98static void DisplayPageNumber(void); 99static void VisitFile(char *name, Boolean resetPage); 100 101static Widget toplevel, paned, porthole, dvi; 102static Widget popupMenu; 103static Widget menuBar; 104static Widget fileMenuButton, fileMenu; 105static Widget pageNumber; 106 107static void NextPage(Widget entry, XtPointer name, XtPointer data); 108static void PreviousPage(Widget entry, XtPointer name, XtPointer data); 109static void SetResolution(Widget entry, XtPointer name, XtPointer data); 110static void OpenFile(Widget entry, XtPointer name, XtPointer data); 111static void RevisitFile(Widget entry, XtPointer name, XtPointer data); 112static void Quit(Widget entry, XtPointer closure, XtPointer data); 113 114struct menuEntry { 115 char *name; 116 void (*function)(Widget entry, XtPointer name, XtPointer data); 117}; 118 119static struct menuEntry popupMenuEntries[] = { 120 {"nextPage", NextPage}, 121 {"previousPage", PreviousPage}, 122 {"setResolution", SetResolution}, 123 {"openFile", OpenFile}, 124 {"revisitFile", RevisitFile}, 125 {"quit", Quit} 126}; 127 128static struct menuEntry fileMenuEntries[] = { 129 {"openFile", OpenFile}, 130 {"revisitFile", RevisitFile}, 131 {"setResolution", SetResolution}, 132 {"quit", Quit} 133}; 134 135static void NextPageAction(Widget, XEvent *, String *, Cardinal *); 136static void PreviousPageAction(Widget, XEvent *, String *, Cardinal *); 137static void SetResolutionAction(Widget, XEvent *, String *, Cardinal *); 138static void OpenFileAction(Widget, XEvent *, String *, Cardinal *); 139static void RevisitFileAction(Widget, XEvent *, String *, Cardinal *); 140static void QuitAction(Widget, XEvent *, String *, Cardinal *); 141static void AcceptAction(Widget, XEvent *, String *, Cardinal *); 142static void CancelAction(Widget, XEvent *, String *, Cardinal *); 143static void UpdatePageNumber(Widget, XEvent *, String *, Cardinal *); 144static void Noop(Widget, XEvent *, String *, Cardinal *); 145 146static XtActionsRec xditview_actions[] = { 147 {"NextPage", NextPageAction}, 148 {"PreviousPage", PreviousPageAction}, 149 {"SetResolution", SetResolutionAction}, 150 {"OpenFile", OpenFileAction}, 151 {"Quit", QuitAction}, 152 {"Accept", AcceptAction}, 153 {"Cancel", CancelAction}, 154 {"SetPageNumber", UpdatePageNumber}, 155 {"Noop", Noop} 156}; 157 158static Atom wm_delete_window; 159 160 161int 162main(int argc, char **argv) 163{ 164 char * file_name = NULL; 165 XtAppContext xtcontext; 166 Arg topLevelArgs[2]; 167 168 XtSetLanguageProc(NULL, (XtLanguageProc) NULL, NULL); 169 170 /* Handle args that don't require opening a display */ 171 for (int n = 1; n < argc; n++) { 172 const char *argn = argv[n]; 173 /* accept single or double dash for -help & -version */ 174 if (argn[0] == '-' && argn[1] == '-') { 175 argn++; 176 } 177 if (strcmp(argn, "-help") == 0) { 178 Syntax(argv[0], 0); 179 } 180 if (strcmp(argn, "-version") == 0) { 181 puts(PACKAGE_STRING); 182 exit(0); 183 } 184 } 185 186 toplevel = XtAppInitialize(&xtcontext, "Xditview", 187 options, XtNumber(options), 188 &argc, argv, NULL, NULL, 0); 189 if (argc > 2) { 190 fputs("Unknown argument(s):", stderr); 191 for (int n = 1; n < argc; n++) { 192 if ((n < (argc -1)) || (argv[n][0] == '-')) { 193 fprintf(stderr, " %s", argv[n]); 194 } 195 } 196 fputs("\n\n", stderr); 197 Syntax(argv[0], 1); 198 } 199 200 XtAppAddActions(xtcontext, xditview_actions, XtNumber(xditview_actions)); 201 XtOverrideTranslations 202 (toplevel, XtParseTranslationTable("<Message>WM_PROTOCOLS: Quit()")); 203 204 XtSetArg(topLevelArgs[0], XtNiconPixmap, 205 XCreateBitmapFromData(XtDisplay(toplevel), 206 XtScreen(toplevel)->root, 207 (char *) xdit_bits, 208 xdit_width, xdit_height)); 209 210 XtSetArg(topLevelArgs[1], XtNiconMask, 211 XCreateBitmapFromData(XtDisplay(toplevel), 212 XtScreen(toplevel)->root, 213 (char *) xdit_mask_bits, 214 xdit_mask_width, xdit_mask_height)); 215 XtSetValues(toplevel, topLevelArgs, 2); 216 if (argc > 1) 217 file_name = argv[1]; 218 219 /* 220 * create the popup menu and insert the entries 221 */ 222 popupMenu = XtCreatePopupShell("popupMenu", simpleMenuWidgetClass, toplevel, 223 NULL, 0); 224 for (Cardinal i = 0; i < XtNumber(popupMenuEntries); i++) { 225 Widget entry = XtCreateManagedWidget(popupMenuEntries[i].name, 226 smeBSBObjectClass, popupMenu, 227 NULL, (Cardinal) 0); 228 XtAddCallback(entry, XtNcallback, popupMenuEntries[i].function, NULL); 229 } 230 231 paned = XtCreateManagedWidget("paned", panedWidgetClass, toplevel, 232 NULL, (Cardinal) 0); 233 menuBar = XtCreateManagedWidget("menuBar", boxWidgetClass, paned, NULL, 0); 234 235 fileMenuButton = 236 XtCreateManagedWidget("fileMenuButton", menuButtonWidgetClass, menuBar, 237 NULL, (Cardinal) 0); 238 fileMenu = 239 XtCreatePopupShell("fileMenu", simpleMenuWidgetClass, fileMenuButton, 240 NULL, (Cardinal) 0); 241 for (Cardinal i = 0; i < XtNumber(fileMenuEntries); i++) { 242 Widget entry = XtCreateManagedWidget(fileMenuEntries[i].name, 243 smeBSBObjectClass, fileMenu, 244 NULL, (Cardinal) 0); 245 XtAddCallback(entry, XtNcallback, fileMenuEntries[i].function, NULL); 246 } 247 248 (void) XtCreateManagedWidget("prevButton", commandWidgetClass, 249 menuBar, NULL, (Cardinal) 0); 250 251 pageNumber = XtCreateManagedWidget("pageNumber", asciiTextWidgetClass, 252 menuBar, NULL, (Cardinal) 0); 253 254 (void) XtCreateManagedWidget("nextButton", commandWidgetClass, 255 menuBar, NULL, (Cardinal) 0); 256 257 porthole = XtCreateManagedWidget("viewport", viewportWidgetClass, 258 paned, NULL, 0); 259 dvi = XtCreateManagedWidget("dvi", dviWidgetClass, porthole, NULL, 0); 260 if (file_name) 261 VisitFile(file_name, FALSE); 262 XtRealizeWidget(toplevel); 263 wm_delete_window = XInternAtom(XtDisplay(toplevel), "WM_DELETE_WINDOW", 264 False); 265 (void) XSetWMProtocols(XtDisplay(toplevel), XtWindow(toplevel), 266 &wm_delete_window, 1); 267 XtAppMainLoop(xtcontext); 268 269 return 0; 270} 271 272static void 273DisplayPageNumber(void) 274{ 275 Arg arg[2]; 276 int actual_number, last_page; 277 XawTextBlock text; 278 int length; 279 char value[128]; 280 char * cur; 281 282 XtSetArg(arg[0], XtNpageNumber, &actual_number); 283 XtSetArg(arg[1], XtNlastPageNumber, &last_page); 284 XtGetValues(dvi, arg, 2); 285 if (actual_number == 0) 286 snprintf(value, sizeof(value), "<none>"); 287 else if (last_page > 0) 288 snprintf(value, sizeof(value), "%d of %d", actual_number, last_page); 289 else 290 snprintf(value, sizeof(value), "%d", actual_number); 291 text.firstPos = 0; 292 text.length = strlen(value); 293 text.ptr = value; 294 text.format = FMT8BIT; 295 XtSetArg(arg[0], XtNstring, &cur); 296 XtGetValues(XawTextGetSource(pageNumber), arg, 1); 297 length = strlen(cur); 298 XawTextReplace(pageNumber, 0, length, &text); 299} 300 301static void 302SetPageNumber(int number) 303{ 304 Arg arg[1]; 305 306 XtSetArg(arg[0], XtNpageNumber, number); 307 XtSetValues(dvi, arg, 1); 308 DisplayPageNumber(); 309} 310 311static void 312UpdatePageNumber(Widget w, XEvent *xev, String *s, Cardinal *c) 313{ 314 char *string; 315 Arg arg[1]; 316 317 XtSetArg(arg[0], XtNstring, &string); 318 XtGetValues(XawTextGetSource(pageNumber), arg, 1); 319 SetPageNumber(atoi(string)); 320} 321 322static void 323NewResolution(char *resString) 324{ 325 int res; 326 Arg arg[1]; 327 328 res = atoi(resString); 329 if (res <= 0) 330 return; 331 XtSetArg(arg[0], XtNscreenResolution, res); 332 XtSetValues(dvi, arg, 1); 333} 334 335static void 336VisitFile(char *name, Boolean resetPage) 337{ 338 Arg arg[3]; 339 char *n; 340 FILE *new_file; 341 Boolean seek = 0; 342 int i; 343 344 if (current_file) { 345 if (!strcmp(current_file_name, "-")) 346 ; 347 else if (current_file_name[0] == '|') 348 pclose(current_file); 349 else 350 fclose(current_file); 351 } 352 if (!strcmp(name, "-")) 353 new_file = stdin; 354 else if (name[0] == '|') 355 new_file = popen(name + 1, "r"); 356 else { 357 struct stat stbuf; 358 359 new_file = fopen(name, "r"); 360 361 if (!new_file) { 362 perror(name); 363 return; 364 } 365 /* Make sure it is a regular file */ 366 if (fstat(fileno(new_file), &stbuf) != 0) { 367 perror(name); 368 fclose(new_file); 369 return; 370 } 371 if (!S_ISREG(stbuf.st_mode)) { 372 fprintf(stderr, "%s is not a regular file.\n", name); 373 fclose(new_file); 374 return; 375 } 376 377 seek = 1; 378 } 379 if (!new_file) { 380 /* XXX display error message */ 381 return; 382 } 383 i = 0; 384 XtSetArg(arg[i], XtNfile, new_file); 385 i++; 386 XtSetArg(arg[i], XtNseek, seek); 387 i++; 388 if (resetPage) { 389 XtSetArg(arg[i], XtNpageNumber, 1); 390 i++; 391 } 392 XtSetValues(dvi, arg, i); 393 XtSetArg(arg[0], XtNtitle, name); 394 if (name[0] != '/' && (n = strrchr(name, '/'))) 395 n = n + 1; 396 else 397 n = name; 398 XtSetArg(arg[1], XtNiconName, n); 399 XtSetValues(toplevel, arg, 2); 400 strncpy(current_file_name, name, sizeof(current_file_name)); 401 current_file_name[sizeof(current_file_name) - 1] = '\0'; 402 current_file = new_file; 403 DisplayPageNumber(); 404} 405 406static void 407NewFile(char *name) 408{ 409 VisitFile(name, TRUE); 410} 411 412static char fileBuf[1024]; 413static char resolutionBuf[1024]; 414 415static void 416ResetMenuEntry(Widget entry) 417{ 418 Arg arg[1]; 419 420 XtSetArg(arg[0], XtNpopupOnEntry, entry); 421 XtSetValues(XtParent(entry), arg, (Cardinal) 1); 422} 423 424/*ARGSUSED*/ 425static void 426NextPage(Widget entry, XtPointer name, XtPointer data) 427{ 428 NextPageAction(entry, NULL, NULL, NULL); 429 ResetMenuEntry(entry); 430} 431 432static void 433NextPageAction(Widget w, XEvent *xev, String *s, Cardinal *c) 434{ 435 Arg args[1]; 436 int number; 437 438 XtSetArg(args[0], XtNpageNumber, &number); 439 XtGetValues(dvi, args, 1); 440 SetPageNumber(number + 1); 441} 442 443/*ARGSUSED*/ 444static void 445PreviousPage(Widget entry, XtPointer name, XtPointer data) 446{ 447 PreviousPageAction(entry, NULL, NULL, NULL); 448 ResetMenuEntry(entry); 449} 450 451static void 452PreviousPageAction(Widget w, XEvent *xev, String *s, Cardinal *c) 453{ 454 Arg args[1]; 455 int number; 456 457 XtSetArg(args[0], XtNpageNumber, &number); 458 XtGetValues(dvi, args, 1); 459 SetPageNumber(number - 1); 460} 461 462/*ARGSUSED*/ 463static void 464SetResolution(Widget entry, XtPointer name, XtPointer data) 465{ 466 SetResolutionAction(entry, NULL, NULL, NULL); 467 ResetMenuEntry(entry); 468} 469 470static void 471SetResolutionAction(Widget w, XEvent *xev, String *s, Cardinal *c) 472{ 473 Arg args[1]; 474 int cur; 475 476 XtSetArg(args[0], XtNscreenResolution, &cur); 477 XtGetValues(dvi, args, 1); 478 snprintf(resolutionBuf, sizeof(resolutionBuf), "%d", cur); 479 MakePrompt(toplevel, "Screen resolution:", NewResolution, resolutionBuf); 480} 481 482/*ARGSUSED*/ 483static void 484OpenFile(Widget entry, XtPointer name, XtPointer data) 485{ 486 OpenFileAction(entry, NULL, NULL, NULL); 487 ResetMenuEntry(entry); 488} 489 490static void 491OpenFileAction(Widget w, XEvent *xev, String *s, Cardinal *c) 492{ 493 if (current_file_name[0]) { 494 strncpy(fileBuf, current_file_name, sizeof(fileBuf)); 495 fileBuf[sizeof(fileBuf) - 1] = '\0'; 496 } 497 else 498 fileBuf[0] = '\0'; 499 MakePrompt(toplevel, "File to open:", NewFile, fileBuf); 500} 501 502/*ARGSUSED*/ 503static void 504RevisitFile(Widget entry, XtPointer name, XtPointer data) 505{ 506 RevisitFileAction(entry, NULL, NULL, NULL); 507 ResetMenuEntry(entry); 508} 509 510static void 511RevisitFileAction(Widget w, XEvent *xev, String *s, Cardinal *c) 512{ 513 if (current_file_name[0]) 514 VisitFile(current_file_name, FALSE); 515} 516 517/*ARGSUSED*/ 518static void 519Quit(Widget entry, XtPointer closure, XtPointer data) 520{ 521 QuitAction(entry, NULL, NULL, NULL); 522} 523 524static void 525QuitAction(Widget w, XEvent *xev, String *s, Cardinal *c) 526{ 527 exit(0); 528} 529 530static Widget promptShell, promptDialog; 531static void (*promptfunction)(char *); 532 533/* ARGSUSED */ 534static void 535CancelAction(Widget widget, XEvent *event, 536 String *params, Cardinal *num_params) 537{ 538 if (promptShell) { 539 XtSetKeyboardFocus(toplevel, (Widget) None); 540 XtDestroyWidget(promptShell); 541 promptShell = (Widget) 0; 542 } 543} 544 545/* ARGSUSED */ 546static void 547AcceptAction(Widget widget, XEvent *event, 548 String *params, Cardinal *num_params) 549{ 550 (*promptfunction) (XawDialogGetValueString(promptDialog)); 551 CancelAction(widget, event, params, num_params); 552} 553 554static void 555Noop(Widget w, XEvent *xev, String *s, Cardinal *c) 556{ 557} 558 559static void 560MakePrompt(Widget centerw, const char *prompt, void (*func)(char *), char *def) 561{ 562 static Arg dialogArgs[] = { 563 {XtNlabel,(XtArgVal) 0}, 564 {XtNvalue,(XtArgVal) 0}, 565 }; 566 Arg centerArgs[2]; 567 Position source_x, source_y; 568 Position dest_x, dest_y; 569 Dimension center_width, center_height; 570 Dimension prompt_width, prompt_height; 571 Widget valueWidget; 572 573 CancelAction((Widget) NULL, (XEvent *) 0, (String *) 0, (Cardinal *) 0); 574 promptShell = XtCreatePopupShell("promptShell", transientShellWidgetClass, 575 toplevel, NULL, (Cardinal) 0); 576 dialogArgs[0].value = (XtArgVal) prompt; 577 dialogArgs[1].value = (XtArgVal) def; 578 promptDialog = XtCreateManagedWidget("promptDialog", dialogWidgetClass, 579 promptShell, dialogArgs, 580 XtNumber(dialogArgs)); 581 XawDialogAddButton(promptDialog, "accept", NULL, NULL); 582 XawDialogAddButton(promptDialog, "cancel", NULL, NULL); 583 valueWidget = XtNameToWidget(promptDialog, "value"); 584 if (valueWidget) { 585 Arg valueArgs[1]; 586 587 XtSetArg(valueArgs[0], XtNresizable, TRUE); 588 XtSetValues(valueWidget, valueArgs, 1); 589 /* 590 * as resizable isn't set until just above, the 591 * default value will be displayed incorrectly. 592 * rectify the situation by resetting the values 593 */ 594 XtSetValues(promptDialog, dialogArgs, XtNumber(dialogArgs)); 595 } 596 XtSetKeyboardFocus(promptDialog, valueWidget); 597 XtSetKeyboardFocus(toplevel, valueWidget); 598 XtRealizeWidget(promptShell); 599 /* 600 * place the widget in the center of the "parent" 601 */ 602 XtSetArg(centerArgs[0], XtNwidth, ¢er_width); 603 XtSetArg(centerArgs[1], XtNheight, ¢er_height); 604 XtGetValues(centerw, centerArgs, 2); 605 XtSetArg(centerArgs[0], XtNwidth, &prompt_width); 606 XtSetArg(centerArgs[1], XtNheight, &prompt_height); 607 XtGetValues(promptShell, centerArgs, 2); 608 source_x = (int) (center_width - prompt_width) / 2; 609 source_y = (int) (center_height - prompt_height) / 3; 610 XtTranslateCoords(centerw, source_x, source_y, &dest_x, &dest_y); 611 XtSetArg(centerArgs[0], XtNx, dest_x); 612 XtSetArg(centerArgs[1], XtNy, dest_y); 613 XtSetValues(promptShell, centerArgs, 2); 614 XtMapWidget(promptShell); 615 promptfunction = func; 616} 617