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