popups.c (40721B)
1 /*========================================================================*\ 2 3 Copyright (c) 2001-2004 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 \*========================================================================*/ 25 26 /* 27 * Code for popup windows. 28 */ 29 30 #include <sys/socket.h> /* socketpair */ 31 #include <sys/stat.h> 32 #include <sys/wait.h> 33 34 #include <ctype.h> 35 #include <err.h> 36 #include <errno.h> 37 #include <fcntl.h> /* fcntl() */ 38 #include <poll.h> /* POLLIN */ 39 #include <signal.h> 40 #include <stdarg.h> 41 #include <stdlib.h> /* free(), atoi(), getenv() */ 42 #include <unistd.h> /* getpid() */ 43 44 #include <X11/Xatom.h> 45 #include <X11/Xos.h> 46 #include <X11/StringDefs.h> 47 #include <X11/Shell.h> 48 #include <X11/Xaw/Form.h> 49 #include <X11/Xaw/Label.h> 50 #include <X11/Xaw/Command.h> 51 #include <X11/Xaw/Toggle.h> 52 #include <X11/Xaw/AsciiText.h> 53 #include <X11/Xaw/Viewport.h> 54 55 #include "events.h" /* handle_messages(), mane, struct xio */ 56 #include "popups.h" 57 #include "xdvi.h" 58 #include "util.h" /* xfopen() */ 59 60 61 #ifdef EWOULDBLOCK 62 # ifdef EAGAIN 63 # define AGAIN_CONDITION (errno == EWOULDBLOCK || errno == EAGAIN) 64 # else 65 # define AGAIN_CONDITION (errno == EWOULDBLOCK) 66 # endif 67 #else /* EWOULDBLOCK */ 68 # ifdef EAGAIN 69 # define AGAIN_CONDITION (errno == EAGAIN) 70 # endif 71 #endif /* EWOULDBLOCK */ 72 73 74 75 /* 76 * New variants on printf. 77 */ 78 79 static int uintlen(i) 80 unsigned int i; 81 { 82 int len = 0; 83 84 do { 85 ++len; 86 i /= 10; 87 } 88 while (i != 0); 89 90 return len; 91 } 92 93 /* 94 * (v)nprintf(fmt, ...) - return the length of the string produced. 95 */ 96 #define vnprintf(fmt, ap) vsnprintf(NULL, 0, fmt, ap) 97 98 99 /* 100 * (v)mprintf(fmt, ...) - printf to allocated string. 101 */ 102 103 static char * 104 vmprintf(format, args) 105 const char *format; 106 va_list args; 107 { 108 char *result; 109 110 if (vasprintf(&result, format, args) < 0) 111 errx(1, "vasprintf failed with format '%s'.", format); 112 113 return result; 114 } 115 116 static char * 117 mprintf(const char *format, ...) 118 { 119 va_list args; 120 char *result; 121 122 va_start(args, format); 123 124 result = vmprintf(format, args); 125 va_end(args); 126 return result; 127 } 128 129 130 131 /* 132 * Realize the widget and set the callback for the WM_DESTROY protocol. 133 */ 134 135 static void 136 XdviXawRealizePopup(shell, callback) 137 Widget shell; 138 XtCallbackProc callback; 139 { 140 XtRealizeWidget(shell); 141 142 XSetWMProtocols(DISP, XtWindow(shell), &XA_WM_DELETE_WINDOW, 1); 143 XtAddEventHandler(shell, NoEventMask, True, handle_messages, callback); 144 } 145 146 147 /* 148 * Warning popup - used for most error and notice conditions. 149 * It includes a message and a button (and, in the case of the Motif 150 * toolkit, a bitmap). 151 */ 152 153 static void 154 warn_callback(w, client_data, call_data) 155 Widget w; 156 XtPointer client_data; 157 XtPointer call_data; 158 { 159 /* XtIsShell(w) holds if this is caused by the WM_DESTROY protocol */ 160 XtDestroyWidget(XtIsShell(w) ? w : (Widget) client_data); 161 } 162 163 164 void 165 do_popup(shell) 166 Widget shell; 167 { 168 Position x, y; 169 Dimension w1, h1, w2, h2; 170 171 /* Get the size and location of the main window */ 172 x = y = 0; 173 w1 = WidthOfScreen(SCRN); 174 h1 = HeightOfScreen(SCRN); 175 if (mane.win != (Window) 0) 176 XtVaGetValues(top_level, XtNx, &x, XtNy, &y, 177 XtNwidth, &w1, XtNheight, &h1, NULL); 178 179 /* Get the size of the popup window */ 180 XtVaGetValues(shell, XtNwidth, &w2, XtNheight, &h2, NULL); 181 182 /* Center the popup over the main window */ 183 XtVaSetValues(shell, XtNx, x + (w1 - w2) / 2, 184 XtNy, y + (h1 - h2) / 2, NULL); 185 186 XtPopup(shell, XtGrabNone); 187 } 188 189 Widget 190 warning_popup(message, button_name, callback) 191 const char *message; 192 const char *button_name; 193 XtCallbackProc callback; 194 { 195 Widget shell, form, label, button; 196 Dimension w1, w2, bw; 197 int dist; 198 199 XtAccelerators accels_cr_click = XtParseAcceleratorTable( 200 "<Key>Return:set()notify()unset()\n" 201 "<Btn1Down>:set()\n" 202 "<Btn1Up>:notify()unset()"); 203 204 shell = XtVaCreatePopupShell("warn", transientShellWidgetClass, 205 top_level, 206 XtNtitle, "Xdvi warning", 207 XtNmappedWhenManaged, False, 208 XtNtransientFor, top_level, 209 NULL); 210 form = XtCreateManagedWidget("form", formWidgetClass, shell, 211 NULL, 0); 212 label = XtVaCreateManagedWidget("label", labelWidgetClass, form, 213 XtNlabel, message, 214 XtNborderWidth, 0, 215 XtNleft, XtChainLeft, 216 XtNright, XtChainLeft, 217 NULL); 218 button = XtVaCreateManagedWidget(button_name, commandWidgetClass, form, 219 XtNaccelerators, accels_cr_click, 220 XtNfromVert, label, 221 NULL); 222 XtAddCallback(button, XtNcallback, 223 callback != NULL ? callback : warn_callback, shell); 224 XtInstallAccelerators(form, button); 225 226 /* Center button under message */ 227 XtVaGetValues(label, XtNwidth, &w1, NULL); 228 XtVaGetValues(button, XtNwidth, &w2, XtNborderWidth, &bw, NULL); 229 w2 += 2 * bw; 230 if (w1 > w2) { 231 XtVaGetValues(button, XtNhorizDistance, &dist, NULL); 232 XtVaSetValues(button, XtNhorizDistance, dist + (w1 - w2) / 2, NULL); 233 } 234 else if (w1 < w2) { 235 XtVaGetValues(label, XtNhorizDistance, &dist, NULL); 236 XtVaSetValues(label, XtNhorizDistance, dist + (w2 - w1) / 2, NULL); 237 } 238 239 XdviXawRealizePopup(shell, callback != NULL ? callback : warn_callback); 240 do_popup(shell); 241 242 return shell; 243 } 244 245 246 Widget 247 warning_popup_long(const char *format, 248 const char *button_name, XtCallbackProc callback, ...) 249 { 250 va_list args; 251 char *str; 252 Widget w; 253 254 va_start(args, callback); 255 str = vmprintf(format, args); 256 va_end(args); 257 258 w = warning_popup(str, button_name, callback); 259 260 free(str); 261 262 return w; 263 } 264 265 266 267 /* 268 * Confirm popup - Pop up a window and ask a yes/no question. 269 */ 270 271 static Widget 272 confirm_popup(message, button_name, callback, yes_answer, no_answer) 273 const char *message; 274 const char *button_name; 275 XtCallbackProc callback; 276 XtPointer yes_answer, no_answer; 277 { 278 XtAccelerators accels_cr; 279 Widget shell, form, label, button1, button2; 280 int ddist; 281 Dimension w0, w1, w2, bw1, bw2, tw; 282 283 accels_cr = XtParseAcceleratorTable("<Key>Return:set()notify()unset()"); 284 285 shell = XtVaCreatePopupShell("confirm", transientShellWidgetClass, 286 top_level, 287 XtNtitle, "Xdvi question", 288 XtNmappedWhenManaged, False, 289 XtNtransientFor, top_level, 290 NULL); 291 form = XtCreateManagedWidget("form", formWidgetClass, shell, 292 NULL, 0); 293 label = XtVaCreateManagedWidget("label", labelWidgetClass, form, 294 XtNlabel, message, 295 XtNborderWidth, 0, 296 XtNleft, XtChainLeft, 297 XtNright, XtChainLeft, 298 NULL); 299 300 button1 = XtVaCreateManagedWidget(button_name, commandWidgetClass, form, 301 XtNaccelerators, accels_cr, 302 XtNfromVert, label, 303 NULL); 304 XtAddCallback(button1, XtNcallback, callback, yes_answer); 305 XtInstallAccelerators(form, button1); 306 307 button2 = XtVaCreateManagedWidget("Cancel", commandWidgetClass, form, 308 XtNfromVert, label, 309 XtNfromHoriz, button1, 310 NULL); 311 XtAddCallback(button2, XtNcallback, callback, no_answer); 312 313 /* Move cancel button to the right */ 314 XtVaGetValues(label, XtNwidth, &w0, NULL); 315 XtVaGetValues(button1, XtNwidth, &w1, XtNborderWidth, &bw1, NULL); 316 XtVaGetValues(button2, XtNwidth, &w2, XtNborderWidth, &bw2, NULL); 317 XtVaGetValues(form, XtNdefaultDistance, &ddist, NULL); 318 tw = w1 + w2 + 2 * (bw1 + bw2); 319 if (tw < w0 + ddist) 320 XtVaSetValues(button2, XtNhorizDistance, w0 - tw, NULL); 321 322 XdviXawRealizePopup(shell, callback); 323 do_popup(shell); 324 325 return shell; 326 } 327 328 /* 329 * Print popup - pop up a window to allow the user to print page(s) 330 * from the dvi file. 331 */ 332 333 static Boolean print_active = False; /* if print window is showing */ 334 static Widget print_shell = NULL; /* shell widget of popup */ 335 static Widget r1radio1, r1radio2; 336 static Widget r2label, r2text; 337 static Widget r3label, r3text; 338 static Widget r4text; 339 static Widget r6radio, r7radio; 340 static Widget r7text1, r7text2; 341 static Widget r8text; 342 static Widget r9prev; 343 344 /* &r1radio1 = printer, &r1radio2 = to file */ 345 static Widget *pr_current_fileradio = &r1radio1; 346 347 /* &r6radio = whole file, &r7radio = page range */ 348 static Widget *pr_current_pageradio = &r6radio; 349 350 /* Stuff to save between popups */ 351 352 static Widget *pr_save_fileradio = &r1radio1; 353 static Widget *pr_save_pageradio = &r6radio; 354 static const char *pr_save_cmd = NULL; 355 static const char *pr_save_file = NULL; 356 static const char *pr_save_printer= NULL; 357 static const char *pr_save_xargs = NULL; 358 359 /* Things to do with running the dvips process */ 360 361 static Boolean printlog_active = False; /* if the print log is active */ 362 static Widget printlog_shell = NULL; 363 static Widget printlog_keep; 364 365 /* Forward reference */ 366 367 static void print_precheck(void); 368 369 370 static void 371 set_sensitivity(fileradio) 372 Widget *fileradio; 373 { 374 Boolean sensitivity; 375 376 if (fileradio == pr_current_fileradio) /* if no change */ 377 return; 378 379 pr_current_fileradio = fileradio; 380 381 sensitivity = (fileradio == &r1radio1); 382 XtSetSensitive(r2label, sensitivity); 383 XtSetSensitive(r2text, sensitivity); 384 385 sensitivity ^= (True ^ False); 386 XtSetSensitive(r3label, sensitivity); 387 XtSetSensitive(r3text, sensitivity); 388 } 389 390 static void 391 cb_print_cancel(w, client_data, call_data) 392 Widget w; 393 XtPointer client_data; 394 XtPointer call_data; 395 { 396 XtPopdown(print_shell); 397 print_active = False; 398 399 if (w == r9prev && !printlog_active) { 400 XtSetSensitive(printlog_keep, False); 401 XtPopup(printlog_shell, XtGrabNone); 402 printlog_active = True; 403 } 404 } 405 406 static void 407 cb_print(w, client_data, call_data) 408 Widget w; 409 XtPointer client_data; 410 XtPointer call_data; 411 { 412 print_precheck(); 413 } 414 415 static void print_act_go(Widget, XEvent *, String *, Cardinal *); 416 static void printlog_act_close(Widget, XEvent *, String *, Cardinal *); 417 static void printlog_act_keep(Widget, XEvent *, String *, Cardinal *); 418 static void printlog_act_unkeep(Widget, XEvent *, String *, Cardinal *); 419 static void printlog_act_cancel(Widget, XEvent *, String *, Cardinal *); 420 421 static XtActionsRec print_actions[] = { 422 {"printInternal", print_act_go}, 423 {"printlogIntClose", printlog_act_close}, 424 {"printlogIntKeep", printlog_act_keep}, 425 {"printlogIntUnkeep", printlog_act_unkeep}, 426 {"printlogIntCancel", printlog_act_cancel}, 427 }; 428 429 430 #ifndef PRINTINDENT 431 # define PRINTINDENT 25 432 #endif 433 434 static void 435 cb_print_vs_file(w, client_data, call_data) 436 Widget w; 437 XtPointer client_data; 438 XtPointer call_data; 439 { 440 Widget *fileradio = XawToggleGetCurrent(r1radio1); 441 442 if (fileradio != NULL) 443 set_sensitivity(fileradio); 444 } 445 446 static void 447 cb_range(w, client_data, call_data) 448 Widget w; 449 XtPointer client_data; 450 XtPointer call_data; 451 { 452 Widget *pageradio = XawToggleGetCurrent(r6radio); 453 454 if (pageradio != NULL) 455 pr_current_pageradio = pageradio; 456 } 457 458 static void 459 range_handle_key(widget, closure, ev, cont) 460 Widget widget; 461 XtPointer closure; 462 XEvent *ev; 463 Boolean *cont; 464 { 465 if (pr_current_pageradio != &r7radio) 466 XawToggleSetCurrent(r6radio, &r7radio); 467 } 468 469 static void 470 print_act_go(Widget w, XEvent *event, String *params, Cardinal *num_params) 471 { 472 print_precheck(); 473 } 474 475 void 476 Act_print(Widget w, XEvent *event, String *params, Cardinal *num_params) 477 { 478 static Widget r7label3; 479 static Widget r9cancel; 480 static Dimension sw; /* shell width */ 481 static int canceladjust; 482 char *ofstring; 483 484 if (print_active) { 485 XRaiseWindow(DISP, XtWindow(print_shell)); 486 return; 487 } 488 489 if (printlog_active) { 490 XRaiseWindow(DISP, XtWindow(printlog_shell)); 491 return; 492 } 493 494 if (dvi_file == NULL) { 495 WARN(XmDIALOG_ERROR, "No active dvi file"); 496 return; 497 } 498 499 ofstring = (pageno_correct == 1 ? mprintf("of %d", total_pages) 500 : mprintf("of %d to %d", pageno_correct, 501 total_pages + pageno_correct - 1)); 502 503 if (print_shell == NULL) { 504 Widget form; 505 Widget r1label; 506 Widget r4label; 507 Widget r5label; 508 Widget r6form; 509 Widget r7form, r7label1, r7label2; 510 Widget r8label; 511 Widget r9ok; 512 XtTranslations xlats, xlats2; 513 XtAccelerators accels2; 514 int ddist; 515 516 XtAddActions(print_actions, XtNumber(print_actions)); 517 print_shell = XtVaCreatePopupShell("print", 518 transientShellWidgetClass, 519 top_level, 520 XtNtitle, "Print dvi file", 521 XtNmappedWhenManaged, False, 522 XtNtransientFor, top_level, 523 XtNallowShellResize, True, 524 NULL); 525 526 form = XtCreateManagedWidget("form", formWidgetClass, print_shell, 527 NULL, 0); 528 XtVaGetValues(form, XtNdefaultDistance, &ddist, NULL); 529 530 r1label = XtVaCreateManagedWidget("printto", labelWidgetClass, form, 531 XtNlabel, "Print to:", 532 XtNborderWidth, 0, 533 XtNleft, XawChainLeft, 534 XtNright, XawChainLeft, 535 NULL); 536 537 xlats = XtParseTranslationTable("<EnterWindow>:highlight(Always)\n\ 538 <LeaveWindow>:unhighlight()\n\ 539 <Btn1Down>,<Btn1Up>:set()notify()"); 540 r1radio1 = XtVaCreateManagedWidget("toprinter", toggleWidgetClass, 541 form, 542 XtNlabel, "Printer", 543 XtNradioData, &r1radio1, 544 XtNstate, True, 545 XtNtranslations, xlats, 546 XtNfromHoriz, r1label, 547 XtNleft, XawChainLeft, 548 XtNright, XawChainLeft, 549 NULL); 550 XtAddCallback(r1radio1, XtNcallback, cb_print_vs_file, NULL); 551 552 r1radio2 = XtVaCreateManagedWidget("tofile", toggleWidgetClass, 553 form, 554 XtNlabel, "File", 555 XtNradioGroup, r1radio1, 556 XtNradioData, &r1radio2, 557 XtNtranslations, xlats, 558 XtNfromHoriz, r1radio1, 559 XtNleft, XawChainLeft, 560 XtNright, XawChainLeft, 561 NULL); 562 XtAddCallback(r1radio2, XtNcallback, cb_print_vs_file, NULL); 563 564 /* Rows 2, 3: Print command or file name */ 565 566 r2label = XtVaCreateManagedWidget("prncommand", labelWidgetClass, 567 form, 568 XtNlabel, "Print command:", 569 XtNborderWidth, 0, 570 XtNfromVert, r1radio1, 571 XtNhorizDistance, ddist + PRINTINDENT, 572 XtNleft, XawChainLeft, 573 XtNright, XawChainLeft, 574 NULL); 575 576 r2text = XtVaCreateManagedWidget("prntext", asciiTextWidgetClass, 577 form, 578 XtNdataCompression, False, 579 XtNeditType, XawtextEdit, 580 XtNfromHoriz, r2label, 581 XtNfromVert, r1radio1, 582 XtNleft, XawChainLeft, 583 XtNright, XawChainLeft, 584 NULL); 585 xlats2 = XtParseTranslationTable("<Key>Return:printInternal()"); 586 XtOverrideTranslations(r2text, xlats2); 587 588 r3label = XtVaCreateManagedWidget("filename", labelWidgetClass, 589 form, 590 XtNlabel, "File name:", 591 XtNsensitive, False, 592 XtNborderWidth, 0, 593 XtNfromVert, r2text, 594 XtNhorizDistance, ddist + PRINTINDENT, 595 XtNleft, XawChainLeft, 596 XtNright, XawChainLeft, 597 NULL); 598 599 r3text = XtVaCreateManagedWidget("filetext", asciiTextWidgetClass, 600 form, 601 XtNdataCompression, False, 602 XtNeditType, XawtextEdit, 603 XtNsensitive, False, 604 XtNfromHoriz, r3label, 605 XtNfromVert, r2text, 606 XtNleft, XawChainLeft, 607 XtNright, XawChainLeft, 608 NULL); 609 XtOverrideTranslations(r3text, xlats2); 610 611 { /* align left edges of asciitext widgets */ 612 Dimension w2, w3; 613 614 XtVaGetValues(r2label, XtNwidth, &w2, NULL); 615 XtVaGetValues(r3label, XtNwidth, &w3, NULL); 616 if (w3 > w2) 617 XtVaSetValues(r2text, XtNhorizDistance, ddist + (w3 - w2), 618 NULL); 619 else if (w2 > w3) 620 XtVaSetValues(r3text, XtNhorizDistance, ddist + (w2 - w3), 621 NULL); 622 } 623 624 /* Row 4: printer name (for dvips) */ 625 626 r4label = XtVaCreateManagedWidget("prname", labelWidgetClass, 627 form, 628 XtNlabel, "Printer name (used by dvips):", 629 XtNborderWidth, 0, 630 XtNfromVert, r3text, 631 XtNleft, XawChainLeft, 632 XtNright, XawChainLeft, 633 NULL); 634 635 r4text = XtVaCreateManagedWidget("prtext", asciiTextWidgetClass, 636 form, 637 XtNdataCompression, False, 638 XtNeditType, XawtextEdit, 639 XtNwidth, 50, 640 XtNfromHoriz, r4label, 641 XtNfromVert, r3text, 642 XtNleft, XawChainLeft, 643 XtNright, XawChainLeft, 644 NULL); 645 XtOverrideTranslations(r4text, xlats2); 646 647 /* Rows 5-7: page selection */ 648 649 r5label = XtVaCreateManagedWidget("rangelab", labelWidgetClass, 650 form, 651 XtNlabel, "Print range:", 652 XtNborderWidth, 0, 653 XtNfromVert, r4text, 654 XtNleft, XawChainLeft, 655 XtNright, XawChainLeft, 656 NULL); 657 658 r6form = XtVaCreateManagedWidget("rangeallform", formWidgetClass, 659 form, 660 XtNdefaultDistance, 0, 661 XtNborderWidth, 0, 662 XtNfromVert, r5label, 663 XtNhorizDistance, ddist + PRINTINDENT, 664 XtNleft, XawChainLeft, 665 XtNright, XawChainLeft, 666 NULL); 667 668 accels2 = XtParseAcceleratorTable( 669 "<Btn1Down>,<Btn1Up>:set()notify()"); 670 r6radio = XtVaCreateManagedWidget("rangeall", toggleWidgetClass, 671 r6form, 672 XtNlabel, " ", 673 XtNradioData, &r6radio, 674 XtNstate, True, 675 XtNtranslations, xlats, 676 XtNaccelerators, accels2, 677 NULL); 678 XtAddCallback(r6radio, XtNcallback, cb_range, NULL); 679 XtInstallAccelerators(r6form, r6radio); 680 681 (void) XtVaCreateManagedWidget("rangealllab", labelWidgetClass, 682 r6form, 683 XtNlabel, "All", 684 XtNborderWidth, 0, 685 XtNfromHoriz, r6radio, 686 XtNhorizDistance, ddist, 687 NULL); 688 689 r7form = XtVaCreateManagedWidget("rangefromtoform", formWidgetClass, 690 form, 691 XtNdefaultDistance, 0, 692 XtNborderWidth, 0, 693 XtNresizable, True, 694 XtNfromVert, r6form, 695 XtNhorizDistance, ddist + PRINTINDENT, 696 XtNleft, XawChainLeft, 697 XtNright, XawChainLeft, 698 NULL); 699 700 r7radio = XtVaCreateManagedWidget("rangefromto", toggleWidgetClass, 701 r7form, 702 XtNlabel, " ", 703 XtNradioGroup, r6radio, 704 XtNradioData, &r7radio, 705 XtNtranslations, xlats, 706 XtNaccelerators, accels2, 707 NULL); 708 XtAddCallback(r7radio, XtNcallback, cb_range, NULL); 709 XtInstallAccelerators(r7form, r7radio); 710 711 r7label1 = XtVaCreateManagedWidget("rangefromlab", labelWidgetClass, 712 r7form, 713 XtNlabel, "From", 714 XtNborderWidth, 0, 715 XtNfromHoriz, r7radio, 716 XtNhorizDistance, ddist, 717 NULL); 718 719 r7text1 = XtVaCreateManagedWidget("rangefrom", asciiTextWidgetClass, 720 r7form, 721 XtNdataCompression, False, 722 XtNeditType, XawtextEdit, 723 XtNwidth, 50, 724 XtNfromHoriz, r7label1, 725 XtNhorizDistance, ddist, 726 NULL); 727 XtOverrideTranslations(r7text1, xlats2); 728 XtAddEventHandler(r7text1, KeyPressMask, False, 729 range_handle_key, (XtPointer) NULL); 730 731 r7label2 = XtVaCreateManagedWidget("rangetolab", labelWidgetClass, 732 r7form, 733 XtNlabel, "to", 734 XtNborderWidth, 0, 735 XtNfromHoriz, r7text1, 736 XtNhorizDistance, ddist, 737 NULL); 738 739 r7text2 = XtVaCreateManagedWidget("rangeto", asciiTextWidgetClass, 740 r7form, 741 XtNdataCompression, False, 742 XtNeditType, XawtextEdit, 743 XtNwidth, 50, 744 XtNfromHoriz, r7label2, 745 XtNhorizDistance, ddist, 746 NULL); 747 XtOverrideTranslations(r7text2, xlats2); 748 XtAddEventHandler(r7text2, KeyPressMask, False, 749 range_handle_key, (XtPointer) NULL); 750 751 r7label3 = XtVaCreateManagedWidget("rangeof", labelWidgetClass, 752 r7form, 753 XtNlabel, ofstring, 754 XtNborderWidth, 0, 755 XtNresizable, True, 756 XtNfromHoriz, r7text2, 757 XtNhorizDistance, ddist, 758 NULL); 759 760 /* Row 8: additional dvips args */ 761 762 r8label = XtVaCreateManagedWidget("xargsname", labelWidgetClass, 763 form, 764 XtNlabel, "Additional dvips arguments (optional):", 765 XtNborderWidth, 0, 766 XtNfromVert, r7form, 767 XtNleft, XawChainLeft, 768 XtNright, XawChainLeft, 769 NULL); 770 771 r8text = XtVaCreateManagedWidget("xargstext", asciiTextWidgetClass, 772 form, 773 XtNdataCompression, False, 774 XtNeditType, XawtextEdit, 775 XtNwidth, 50, 776 XtNresizable, True, 777 XtNfromVert, r8label, 778 XtNhorizDistance, ddist + PRINTINDENT, 779 XtNleft, XawChainLeft, 780 XtNright, XawChainRight, 781 NULL); 782 XtOverrideTranslations(r8text, xlats2); 783 784 /* Row 9: action buttons */ 785 786 XtAccelerators accels_cr; 787 accels_cr = XtParseAcceleratorTable("<Key>Return:set()notify()unset()"); 788 789 r9ok = XtVaCreateManagedWidget("ok", commandWidgetClass, form, 790 XtNlabel, "OK", 791 XtNaccelerators, accels_cr, 792 XtNfromVert, r8text, 793 XtNleft, XawChainLeft, 794 XtNright, XawChainLeft, 795 NULL); 796 XtAddCallback(r9ok, XtNcallback, cb_print, NULL); 797 XtInstallAccelerators(form, r9ok); 798 XtInstallAccelerators(r2text, r9ok); 799 XtInstallAccelerators(r3text, r9ok); 800 801 r9prev = XtVaCreateManagedWidget("prev", commandWidgetClass, form, 802 XtNlabel, "Show previous log", 803 XtNsensitive, False, 804 XtNfromHoriz, r9ok, 805 XtNfromVert, r8text, 806 XtNleft, XawChainLeft, 807 XtNright, XawChainLeft, 808 NULL); 809 XtAddCallback(r9prev, XtNcallback, cb_print_cancel, NULL); 810 811 r9cancel = XtVaCreateManagedWidget("cancel", commandWidgetClass, 812 form, 813 XtNlabel, "Cancel", 814 XtNfromHoriz, r9prev, 815 XtNfromVert, r8text, 816 XtNleft, XawChainRight, 817 XtNright, XawChainRight, 818 NULL); 819 XtAddCallback(r9cancel, XtNcallback, cb_print_cancel, NULL); 820 821 /* Realize and set destroy callback */ 822 XdviXawRealizePopup(print_shell, cb_print_cancel); 823 824 { /* Center the popup over the main window */ 825 Dimension sh; /* sw was defined earlier */ 826 Position tx, ty; 827 Dimension tw, th; 828 829 /* Get the size of the popup window */ 830 XtVaGetValues(print_shell, XtNwidth, &sw, XtNheight, &sh, NULL); 831 832 /* Center the popup over the main window */ 833 XtVaGetValues(top_level, XtNx, &tx, XtNy, &ty, 834 XtNwidth, &tw, XtNheight, &th, NULL); 835 XtVaSetValues(print_shell, XtNx, tx + (tw - sw) / 2, 836 XtNy, ty + (th - sh) / 2, NULL); 837 } 838 839 { 840 /* Set width of dvips-xargs text widget */ 841 Dimension b; 842 843 XtVaGetValues(r8text, XtNborderWidth, &b, NULL); 844 XtVaSetValues(r8text, 845 XtNwidth, sw - 2 * (b + ddist) - PRINTINDENT, 846 NULL); 847 } 848 849 { /* Set canceladjust */ 850 Dimension cw, cb; 851 Position cx; 852 853 XtVaGetValues(r9cancel, XtNwidth, &cw, XtNborderWidth, &cb, 854 XtNx, &cx, NULL); 855 canceladjust = cx + cw + 2 * cb - ddist; 856 } 857 } 858 else { /* if the window was already created */ 859 XawToggleSetCurrent(r1radio1, pr_save_fileradio); 860 set_sensitivity(pr_save_fileradio); 861 XawToggleSetCurrent(r6radio, pr_save_pageradio); 862 863 XtVaSetValues(r7label3, XtNlabel, ofstring, NULL); 864 865 if (pr_save_printer != NULL) { 866 XtVaSetValues(r4text, XtNstring, pr_save_printer, NULL); 867 XawTextSetInsertionPoint(r4text, strlen(pr_save_printer)); 868 } 869 else 870 XtVaSetValues(r4text, XtNstring, "", NULL); 871 872 if (pr_save_xargs != NULL) { 873 XtVaSetValues(r8text, XtNstring, pr_save_xargs, NULL); 874 XawTextSetInsertionPoint(r8text, strlen(pr_save_xargs)); 875 } 876 else 877 XtVaSetValues(r8text, XtNstring, "", NULL); 878 879 XtVaGetValues(print_shell, XtNwidth, &sw, NULL); 880 } 881 882 free(ofstring); 883 XtVaSetValues(r9prev, XtNhorizDistance, (sw - canceladjust) / 2, NULL); 884 XtVaSetValues(r9cancel, XtNhorizDistance, (sw - canceladjust) / 2, 885 NULL); 886 887 { /* set initial values of print command and file name fields */ 888 const char *s; 889 char s2[3 * sizeof(int) + 1]; 890 891 s = pr_save_cmd; 892 if (s == NULL) s = "lpr"; 893 /* for some reason two separate XtVaSetValues calls are necessary */ 894 XtVaSetValues(r2text, XtNstring, s, NULL); 895 XawTextSetInsertionPoint(r2text, strlen(s)); 896 897 if (pr_save_file == NULL) { 898 char *s2; 899 int n; 900 901 s = rindex(dvi_name, '/'); 902 if (s == NULL) s = dvi_name; 903 else ++s; 904 n = strlen(s); 905 if (n >= 4 && strncasecmp(s + n - 4, ".dvi", 4) == 0) n -= 4; 906 s2 = xmalloc(n + 4); 907 memcpy(s2, s, n); 908 memcpy(s2 + n, ".ps", 4); 909 pr_save_file = s2; 910 } 911 s = pr_save_file; 912 XtVaSetValues(r3text, XtNstring, s, NULL); 913 XawTextSetInsertionPoint(r3text, strlen(s)); 914 915 (void) snprintf(s2, sizeof s2, "%d", current_page + pageno_correct); 916 XtVaSetValues(r7text1, XtNstring, s2, NULL); 917 XawTextSetInsertionPoint(r7text1, strlen(s2)); 918 XtVaSetValues(r7text2, XtNstring, s2, NULL); 919 XawTextSetInsertionPoint(r7text2, strlen(s2)); 920 } 921 922 XtPopup(print_shell, XtGrabNone); 923 print_active = True; 924 } 925 926 927 928 /* 929 * The actual printing 930 */ 931 932 static int pageno1, pageno2; /* page range */ 933 static Widget print_confirm = NULL; 934 static Widget printlog_text; 935 static Widget printlog_close; 936 static Widget printlog_cancel; 937 938 static XawTextPosition printlog_length; 939 940 static void dvips_ended(int); 941 static struct xchild print_child = {NULL, 0, True, dvips_ended}; 942 943 static void read_from_dvips(void); 944 static struct xio print_xio = {NULL, 0, POLLIN, NULL, 945 read_from_dvips, NULL}; 946 947 static int dvips_status; 948 #define DVIPS_STAT_NONE 0 949 #define DVIPS_STAT_RUN 1 950 #define DVIPS_STAT_WAIT 2 951 static int dvips_sig; /* SIGINT or SIGKILL */ 952 953 /* Forward reference */ 954 955 static void print_do_it(void); 956 957 static int 958 getpageno(w) 959 Widget w; 960 { 961 char *s, *p; 962 963 XtVaGetValues(w, XtNstring, &s, NULL); 964 p = s; 965 if (*p == '-') ++p; 966 if (!isdigit(*p)) return 0; 967 do ++p; while (isdigit(*p)); 968 if (*p != '\0') return 0; 969 970 return atoi(s) - pageno_correct + 1; 971 } 972 973 static void 974 cb_print_confirm(w, client_data, call_data) 975 Widget w; 976 XtPointer client_data; 977 XtPointer call_data; 978 { 979 XtDestroyWidget(print_confirm); 980 print_confirm = NULL; 981 982 if (client_data != NULL) 983 print_do_it(); 984 } 985 986 static void 987 print_precheck() 988 { 989 char *dest; 990 struct stat statbuf; 991 992 /* Check for active confirm box */ 993 if (print_confirm != NULL) { 994 XRaiseWindow(DISP, XtWindow(print_confirm)); 995 return; 996 } 997 998 /* Validate page range (if given) */ 999 if (pr_current_pageradio == &r7radio) { /* if page range selected */ 1000 pageno1 = getpageno(r7text1); 1001 pageno2 = getpageno(r7text2); 1002 if (pageno1 <= 0 || pageno1 > pageno2 || pageno2 > total_pages) { 1003 WARN(XmDIALOG_ERROR, "Invalid page range"); 1004 return; 1005 } 1006 } 1007 1008 /* Pop down window */ 1009 cb_print_cancel(NULL, NULL, NULL); 1010 1011 /* Check for whether to clobber existing file */ 1012 if (pr_current_fileradio == &r1radio2) { /* if print to file */ 1013 XtVaGetValues(r3text, XtNstring, &dest, NULL); 1014 if (stat(dest, &statbuf) == 0 && S_ISREG(statbuf.st_mode)) { 1015 char *msg; 1016 1017 msg = mprintf("Overwrite existing file %s?", dest); 1018 print_confirm = confirm_popup(msg, "OK", cb_print_confirm, 1019 (XtPointer) print_shell, NULL); 1020 free(msg); 1021 return; 1022 } 1023 } 1024 1025 print_do_it(); 1026 } 1027 1028 1029 static void cb_dvips_close(Widget, XtPointer, XtPointer); 1030 static void cb_dvips_keep(Widget, XtPointer, XtPointer); 1031 static void cb_dvips_cancel(Widget, XtPointer, XtPointer); 1032 static void cb_dvips_delete(Widget, XtPointer, XtPointer); 1033 static void printlog_append(const char *, int); 1034 1035 struct dvips_env { 1036 const char *envname; 1037 const char *en1, *en2; 1038 const char *envval; 1039 }; 1040 1041 static struct dvips_env dvips_envs[] = { 1042 {NULL, "TEXPICTS", "TEXINPUTS", NULL}, 1043 {NULL, "TEXPSHEADERS", "PSHEADERS", NULL}}; 1044 1045 static void 1046 print_do_it() 1047 { 1048 const char *dest; 1049 const char *prn; 1050 const char *xargs; 1051 FILE *f; 1052 unsigned int len; /* length of command line */ 1053 unsigned int argc; 1054 char **argv; 1055 char **argnext; 1056 int print_io[2]; 1057 char *p, **pp; 1058 const char *q; 1059 1060 if (dvi_file == NULL) { 1061 WARN(XmDIALOG_ERROR, "No active dvi file"); 1062 return; 1063 } 1064 1065 /* Save state of window for next time */ 1066 pr_save_fileradio = pr_current_fileradio; 1067 pr_save_pageradio = pr_current_pageradio; 1068 1069 1070 if (pr_save_fileradio == &r1radio1) { /* if print to printer */ 1071 if (pr_save_cmd != NULL) 1072 free((char *) pr_save_cmd); 1073 XtVaGetValues(r2text, XtNstring, &dest, NULL); 1074 dest = pr_save_cmd = xstrdup(dest); 1075 } 1076 else { /* if print to file */ 1077 if (pr_save_file != NULL) 1078 free((char *) pr_save_file); 1079 XtVaGetValues(r3text, XtNstring, &dest, NULL); 1080 dest = pr_save_file = xstrdup(dest); 1081 } 1082 1083 XtVaGetValues(r4text, XtNstring, &prn, NULL); 1084 if (pr_save_printer != NULL) 1085 free((char *) pr_save_printer); 1086 if (*prn != '\0') 1087 prn = pr_save_printer = xstrdup(prn); 1088 else 1089 prn = pr_save_printer = NULL; 1090 1091 XtVaGetValues(r8text, XtNstring, &xargs, NULL); 1092 if (pr_save_xargs != NULL) 1093 free((char *) pr_save_xargs); 1094 if (*xargs != '\0') 1095 xargs = pr_save_xargs = xstrdup(xargs); 1096 else 1097 xargs = pr_save_xargs = NULL; 1098 1099 1100 /* Open file for writing (if necessary) */ 1101 if (pr_save_fileradio == &r1radio2) { /* if print to file */ 1102 f = xfopen(dest, "w"); 1103 if (f == NULL) { 1104 WARN2(XmDIALOG_ERROR, "Error opening file: %s\n%s.", dest, 1105 strerror(errno)); 1106 return; 1107 } 1108 } 1109 1110 /* Create popup window */ 1111 if (printlog_shell == NULL) { 1112 Widget form; 1113 int ddist; 1114 Dimension w0, w1, w2, w3, b; 1115 1116 XtSetSensitive(r9prev, True); 1117 printlog_shell = XtVaCreatePopupShell("printlog", 1118 transientShellWidgetClass, top_level, 1119 XtNtitle, "Xdvi print process", 1120 XtNmappedWhenManaged, False, 1121 XtNtransientFor, top_level, 1122 NULL); 1123 form = XtCreateManagedWidget("form", formWidgetClass, 1124 printlog_shell, NULL, 0); 1125 printlog_text = XtVaCreateManagedWidget("text", 1126 asciiTextWidgetClass, form, 1127 XtNstring, "", 1128 XtNdataCompression, False, 1129 XtNeditType, XawtextAppend, 1130 XtNscrollHorizontal, XawtextScrollAlways, 1131 XtNscrollVertical, XawtextScrollAlways, 1132 XtNwidth, 600, 1133 XtNheight, 400, 1134 XtNleft, XawChainLeft, 1135 XtNright, XawChainRight, 1136 XtNtop, XawChainTop, 1137 XtNbottom, XawChainBottom, 1138 NULL); 1139 XtOverrideTranslations(printlog_text, XtParseTranslationTable( 1140 "<Key>Return:printlogIntClose()\n\ 1141 ^<Key>c:printlogIntCancel()\n\ 1142 ^<Key>s:printlogIntKeep()\n\ 1143 ^<Key>q:printlogIntUnkeep()")); 1144 1145 printlog_close = XtVaCreateManagedWidget("close", 1146 commandWidgetClass, form, 1147 XtNlabel, "Close window", 1148 XtNsensitive, False, 1149 XtNfromVert, printlog_text, 1150 XtNleft, XawChainLeft, 1151 XtNright, XawChainLeft, 1152 XtNtop, XawChainBottom, 1153 XtNbottom, XawChainBottom, 1154 NULL); 1155 XtAddCallback(printlog_close, XtNcallback, cb_dvips_close, NULL); 1156 1157 printlog_keep = XtVaCreateManagedWidget("keep", toggleWidgetClass, 1158 form, 1159 XtNlabel, "Keep window open", 1160 XtNfromVert, printlog_text, 1161 XtNfromHoriz, printlog_close, 1162 XtNtop, XawChainBottom, 1163 XtNbottom, XawChainBottom, 1164 NULL); 1165 XtAddCallback(printlog_keep, XtNcallback, cb_dvips_keep, NULL); 1166 1167 printlog_cancel = XtVaCreateManagedWidget("cancel", 1168 commandWidgetClass, form, 1169 XtNlabel, "Cancel", 1170 XtNfromVert, printlog_text, 1171 XtNfromHoriz, printlog_keep, 1172 XtNleft, XawChainRight, 1173 XtNright, XawChainRight, 1174 XtNtop, XawChainBottom, 1175 XtNbottom, XawChainBottom, 1176 NULL); 1177 XtAddCallback(printlog_cancel, XtNcallback, cb_dvips_cancel, NULL); 1178 1179 /* Move the buttons to the right spots */ 1180 XtVaGetValues(printlog_text, XtNwidth, &w0, NULL); 1181 XtVaGetValues(form, XtNdefaultDistance, &ddist, NULL); 1182 XtVaGetValues(printlog_close, XtNwidth, &w1, XtNborderWidth, &b, 1183 NULL); 1184 w1 += 2 * b + ddist; 1185 XtVaGetValues(printlog_keep, XtNwidth, &w2, XtNborderWidth, &b, 1186 NULL); 1187 w2 += 2 * b; 1188 if (w0 > w2 + 2 * w1) { 1189 XtVaSetValues(printlog_keep, 1190 XtNhorizDistance, (w0 - w2) / 2 - w1, NULL); 1191 w1 += (w0 - w2) / 2 - w1 - ddist; 1192 } 1193 w1 += w2; 1194 XtVaGetValues(printlog_cancel, XtNwidth, &w3, XtNborderWidth, &b, 1195 NULL); 1196 w3 += 2 * b; 1197 if (w1 + ddist + w3 < w0) 1198 XtVaSetValues(printlog_cancel, XtNhorizDistance, w0 - w1 - w3, 1199 NULL); 1200 1201 XdviXawRealizePopup(printlog_shell, cb_dvips_delete); 1202 } 1203 else { 1204 XtVaSetValues(printlog_text, XtNstring, "", NULL); 1205 XtSetSensitive(printlog_close, False); 1206 XtSetSensitive(printlog_keep, True); 1207 XtSetSensitive(printlog_cancel, True); 1208 } 1209 1210 1211 /* Compute length of dvips command line */ 1212 /* dvips [-Pps] -f [-o!command] [-p=n -lm] [xargs] */ 1213 argc = 3; 1214 len = strlen("dvips") + 4; 1215 /* "dvips -f\0" */ 1216 if (prn != NULL) argc = 4, len += strlen(prn) + 3; 1217 if (pr_save_fileradio == &r1radio1) ++argc, len += strlen(dest) + 4; 1218 if (pr_save_pageradio == &r7radio) { 1219 argc += 2; 1220 len += uintlen(pageno1) + uintlen(pageno2) + 7; 1221 } 1222 if (pr_save_xargs != NULL) { 1223 const char *q = pr_save_xargs; 1224 1225 len += strlen(pr_save_xargs); 1226 for (;;) { 1227 while (*q == ' ' || *q == '\t') ++q, --len; 1228 if (*q == '\0') break; 1229 ++argc; 1230 ++len; 1231 while (*q != '\0' && *q != ' ' && *q != '\t') ++q; 1232 } 1233 } 1234 1235 /* Compute actual dvips command line */ 1236 argv = xmalloc(argc * sizeof(char *)); 1237 p = argv[0] = xmalloc(len + 1); 1238 argnext = argv + 1; 1239 p += strlen(strcpy(p, "dvips")); 1240 *p++ = ' '; 1241 *argnext++ = p; 1242 1243 if (prn != NULL) { 1244 sprintf(p, "-P%s ", prn); 1245 p += strlen(p); 1246 *argnext++ = p; 1247 } 1248 1249 *p++ = '-'; 1250 *p++ = 'f'; 1251 *p++ = ' '; 1252 *argnext++ = p; 1253 1254 if (pr_save_fileradio == &r1radio1) { 1255 sprintf(p, "-o!%s ", dest); 1256 p += strlen(p); 1257 *argnext++ = p; 1258 } 1259 1260 if (pr_save_pageradio == &r7radio) { 1261 sprintf(p, "-p=%u ", pageno1); 1262 p += strlen(p); 1263 *argnext++ = p; 1264 sprintf(p, "-l%u ", pageno2); 1265 p += strlen(p); 1266 *argnext++ = p; 1267 } 1268 1269 if (pr_save_xargs != NULL) { 1270 const char *q = pr_save_xargs; 1271 1272 for (;;) { 1273 while (*q == ' ' || *q == '\t') ++q; 1274 if (*q == '\0') break; 1275 while (*q != '\0' && *q != ' ' && *q != '\t') *p++ = *q++; 1276 *p++ = ' '; 1277 *argnext++ = p; 1278 } 1279 } 1280 1281 #if 0 1282 if (argnext - argv != argc) 1283 errx(1, "dvips command count mismatch: %u != %u", argc, 1284 argnext - argv); 1285 if (p - argv[0] != len) 1286 errx(1, "dvips command length mismatch: %u != %u", len, p - argv[0]); 1287 #endif 1288 1289 p[-1] = '\n'; 1290 1291 printlog_length = 0; 1292 1293 q = rindex(dvi_name, '/'); 1294 if (q != NULL) { 1295 struct dvips_env *dep; 1296 1297 if (dvips_envs[0].envname == NULL) { 1298 for (dep = dvips_envs; dep < dvips_envs + XtNumber(dvips_envs); 1299 ++dep) { 1300 const char *envname; 1301 const char *envval; 1302 unsigned int len; 1303 1304 envval = getenv(envname = dep->en1); 1305 if (envval == NULL) { 1306 envval = getenv(dep->en2); 1307 if (envval != NULL) envname = dep->en2; 1308 } 1309 dep->envname = envname; 1310 len = q - dvi_name + 2; 1311 if (envval != NULL) 1312 len += strlen(envval); 1313 dep->envval = p = xmalloc(len); 1314 bcopy(dvi_name, p, q - dvi_name); 1315 p += q - dvi_name; 1316 *p++ = ':'; 1317 *p = '\0'; 1318 if (envval != NULL) 1319 strcpy(p, envval); 1320 if (setenv(dep->envname, dep->envval, 1) == -1) 1321 err(1, "setenv"); 1322 } 1323 } 1324 for (dep = dvips_envs; dep < dvips_envs + XtNumber(dvips_envs); 1325 ++dep) { 1326 printlog_append(dep->envname, strlen(dep->envname)); 1327 printlog_append("=", 1); 1328 printlog_append(dep->envval, strlen(dep->envval)); 1329 printlog_append(" ", 1); 1330 } 1331 } 1332 1333 printlog_append(argv[0], len); 1334 do_popup(printlog_shell); 1335 printlog_active = True; 1336 1337 --argnext; 1338 for (pp = argv + 1; pp <= argnext; ++pp) (*pp)[-1] = '\0'; 1339 *argnext = NULL; 1340 1341 if (socketpair(AF_UNIX, SOCK_STREAM, 0, print_io) != 0) { 1342 warnx("pipe"); 1343 return; 1344 } 1345 1346 /* Fork process */ 1347 fflush(stderr); /* avoid double buffering */ 1348 print_child.pid = vfork(); 1349 if (print_child.pid == 0) { /* if child */ 1350 int fd; 1351 1352 (void) close(0); 1353 (void) fclose(dvi_file); 1354 fd = open(dvi_name, O_RDONLY); 1355 if (fd < 0) { 1356 perror(dvi_name); 1357 fflush(stderr); 1358 _exit(1); 1359 } 1360 if (fd > 0) { 1361 dup2(fd, 0); 1362 (void) close(fd); 1363 } 1364 1365 (void) close(1); 1366 if (pr_save_fileradio == &r1radio1) { /* if printing to printer */ 1367 (void) dup2(print_io[1], 1); 1368 } 1369 else { /* printing to file */ 1370 (void) dup2(fileno(f), 1); 1371 (void) close(fileno(f)); 1372 } 1373 (void) close(2); 1374 (void) dup2(print_io[1], 2); 1375 (void) close(print_io[1]); 1376 (void) close(print_io[0]); 1377 1378 if (setsid() == -1) { /* so we can kill the process group */ 1379 perror("setsid"); 1380 fflush(stderr); 1381 _exit(1); 1382 } 1383 (void) execvp(*argv, argv); 1384 warn("Execvp of '%s' failed.", *argv); 1385 fflush(stderr); 1386 _exit(1); 1387 } 1388 1389 free(argv[0]); 1390 free(argv); 1391 if (pr_save_fileradio == &r1radio2) 1392 fclose(f); 1393 1394 if (print_child.pid == -1) { /* error */ 1395 perror("[xdvi] vfork"); 1396 return; 1397 } 1398 1399 set_chld(&print_child); 1400 dvips_sig = SIGINT; 1401 1402 (void) close(print_io[1]); 1403 1404 /* Set up file descriptor for non-blocking I/O */ 1405 fcntl(print_io[0], F_SETFL, fcntl(print_io[0], F_GETFL, 0) | O_NONBLOCK); 1406 if (fcntl(print_io[0], F_SETOWN, getpid()) == -1) 1407 warnx("fcntl F_SETOWN"); 1408 if (fcntl(print_io[0], F_SETFL, fcntl(print_io[0], F_GETFL, 0) | FASYNC) == -1) 1409 warnx("fcntl F_SETFL"); 1410 1411 print_xio.fd = print_io[0]; 1412 set_io(&print_xio); 1413 1414 dvips_status = DVIPS_STAT_RUN; /* running */ 1415 } 1416 1417 1418 1419 static void 1420 printlog_append(str, len) 1421 const char *str; 1422 int len; 1423 { 1424 static XawTextBlock block = {0, 0, NULL, 0}; 1425 1426 block.ptr = (char *) str; 1427 block.length = len; 1428 block.format = XawFmt8Bit; 1429 while (XawTextReplace(printlog_text, printlog_length, printlog_length, 1430 &block) != XawEditDone) { 1431 int length; 1432 1433 XtVaGetValues(printlog_text, XtNlength, &length, NULL); 1434 printlog_length = length; 1435 } 1436 printlog_length += len; 1437 XawTextSetInsertionPoint(printlog_text, printlog_length); 1438 } 1439 1440 1441 static void 1442 read_from_dvips() 1443 { 1444 int bytes; 1445 char line[80]; 1446 1447 for (;;) { 1448 bytes = read(print_xio.fd, line, sizeof line); 1449 if (bytes < 0) { 1450 if (AGAIN_CONDITION) 1451 break; 1452 perror("xdvi: read_from_dvips"); 1453 break; 1454 } 1455 1456 if (bytes == 0) 1457 break; 1458 else { 1459 printlog_append(line, bytes); 1460 } 1461 } 1462 } 1463 1464 static void 1465 cb_dvips_cancel(w, client_data, call_data) 1466 Widget w; 1467 XtPointer client_data; 1468 XtPointer call_data; 1469 { 1470 if (dvips_status != DVIPS_STAT_RUN) 1471 return; /* How did we get here? */ 1472 1473 kill(print_child.pid, dvips_sig); 1474 dvips_sig = SIGKILL; 1475 printlog_append("^C", 2); 1476 } 1477 1478 static void 1479 dvips_ended(int status) 1480 { 1481 char *str; 1482 1483 read_from_dvips(); 1484 clear_io(&print_xio); 1485 (void) close(print_xio.fd); 1486 1487 if (WIFEXITED(status)) { 1488 if (WEXITSTATUS(status) == 0) { 1489 printlog_append("Done.\n", 6); 1490 str = NULL; 1491 } 1492 else 1493 str = mprintf("\nPrint process returned exit code %d.\n", 1494 WEXITSTATUS(status)); 1495 } 1496 else if (WIFSIGNALED(status)) 1497 str = mprintf("\nPrint process terminated by signal %d.\n", 1498 WTERMSIG(status)); 1499 else 1500 str = mprintf("\nPrint process returned unknown status 0x%x.\n", 1501 status); 1502 1503 if (str != NULL) { 1504 printlog_append(str, strlen(str)); 1505 free(str); 1506 } 1507 1508 printlog_act_keep(NULL, NULL, NULL, NULL); 1509 dvips_status = DVIPS_STAT_NONE; 1510 1511 XtSetSensitive(printlog_close, True); 1512 XtSetSensitive(printlog_cancel, False); 1513 } 1514 1515 static void 1516 dvips_pop_down() 1517 { 1518 XtPopdown(printlog_shell); 1519 printlog_active = False; 1520 } 1521 1522 static void 1523 cb_dvips_close(w, client_data, call_data) 1524 Widget w; 1525 XtPointer client_data; 1526 XtPointer call_data; 1527 { 1528 if (dvips_status == DVIPS_STAT_RUN) 1529 return; /* How did we get here? */ 1530 1531 if (dvips_status == DVIPS_STAT_WAIT) { 1532 dvips_status = DVIPS_STAT_NONE; 1533 } 1534 1535 dvips_pop_down(); 1536 } 1537 1538 static void 1539 cb_dvips_keep(w, client_data, call_data) 1540 Widget w; 1541 XtPointer client_data; 1542 XtPointer call_data; 1543 { 1544 Boolean state; 1545 1546 if (dvips_status != DVIPS_STAT_NONE) 1547 return; /* Nothing to do */ 1548 1549 XtVaGetValues(printlog_keep, XtNstate, &state, NULL); 1550 if (!state) 1551 dvips_pop_down(); 1552 } 1553 1554 static void 1555 cb_dvips_delete(w, client_data, call_data) 1556 Widget w; 1557 XtPointer client_data; 1558 XtPointer call_data; 1559 { 1560 if (dvips_status == DVIPS_STAT_RUN) 1561 cb_dvips_cancel(w, client_data, call_data); 1562 else 1563 cb_dvips_close(w, client_data, call_data); 1564 } 1565 1566 static void 1567 printlog_act_close(Widget w, XEvent *event, String *params, Cardinal *num_params) 1568 { 1569 cb_dvips_close(NULL, NULL, NULL); 1570 } 1571 1572 static void 1573 printlog_act_keep(Widget w, XEvent *event, String *params, Cardinal *num_params) 1574 { 1575 XtVaSetValues(printlog_keep, XtNstate, True, NULL); 1576 } 1577 1578 static void 1579 printlog_act_unkeep(Widget w, XEvent *event, String *params, 1580 Cardinal *num_params) 1581 { 1582 XtVaSetValues(printlog_keep, XtNstate, False, NULL); 1583 if (dvips_status == DVIPS_STAT_NONE) 1584 dvips_pop_down(); 1585 } 1586 1587 static void 1588 printlog_act_cancel(Widget w, XEvent *event, String *params, 1589 Cardinal *num_params) 1590 { 1591 cb_dvips_cancel(NULL, NULL, NULL); 1592 }