/* * callbacks.c -- X11 callbacks for ghostview. * Copyright (C) 1992 Timothy O. Theisen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Author: Tim Theisen Systems Programmer * Internet: tim@cs.wisc.edu Department of Computer Sciences * UUCP: uwvax!tim University of Wisconsin-Madison * Phone: (608)262-0438 1210 West Dayton Street * FAX: (608)262-9777 Madison, WI 53706 */ /* This file is part of the hacked version of the ghostview package */ /* which is distributed under the terms of the gnu license. The */ /* modification referred to above is by Tanmoy Bhattacharya, */ /* on Nov 17, 1994. Neither the modification, */ /* nor the original program provides any warranty. */ #include #ifndef BUFSIZ #define BUFSIZ 1024 #endif #ifdef VMS #define getenv _getenv #endif extern char *getenv(); #include #include #include #include #include #include #include #include #include "Ghostview.h" #include "gv.h" #include "ps.h" #include "pdf.h" int pagehistory[1024], pageindex=0; /* Start application folding up by Destroying the top level widget. */ /* The application exits when the last interpreter is killed during */ /* a destroy callback from ghostview widgets. */ void quit_ghostview(w, client_data, call_data) Widget w; XtPointer client_data, call_data; { XtDestroyWidget(toplevel); } /* Popup a window. */ void popup(w, client_data, call_data) Widget w; XtPointer client_data, call_data; { positionpopup((Widget)client_data); XtPopup((Widget)client_data, XtGrabNone); XRaiseWindow(XtDisplay((Widget)client_data), XtWindow((Widget)client_data)); } /* Popup a dialog box. */ void popup_dialog(w, client_data, call_data) Widget w; XtPointer client_data, call_data; { #ifdef SELFILE Widget button; String okay, cancel; String name, init_path; Arg args[1]; FILE* fp; struct stat sbuf; extern FILE *XsraSelFile(); button = XtNameToWidget(dialog, "cancel"); if (button) { XtSetArg(args[0], XtNlabel, &cancel); XtGetValues(button, args, ONE); } button = XtNameToWidget(dialog, "okay"); if (button) { XtSetArg(args[0], XtNlabel, &okay); XtGetValues(button, args, ONE); } #endif mode = (int) client_data; switch (mode) { case PRINT_WHOLE: case PRINT_MARKED: SetDialogPrompt(dialog, app_res.print_prompt); if (app_res.default_printer) SetDialogResponse(dialog, app_res.default_printer); else ClearDialogResponse(dialog); popup(w, (XtPointer)dialogpopup, call_data); break; case OPEN: #ifdef SELFILE if (filename && strcmp(filename, "-")) init_path = filename; else init_path = NULL; fp = XsraSelFile(toplevel, app_res.open_prompt, okay, cancel, app_res.open_fail, init_path, "r", NULL, &name); if (fp == NULL) break; if (oldfilename) XtFree(oldfilename); oldfilename = filename; filename = name; if (psfile) fclose(psfile); psfile = fp; stat(filename, &sbuf); mtime = sbuf.st_mtime; new_file(0); show_page(0); #else SetDialogPrompt(dialog, app_res.open_prompt); if (filename && strcmp(filename, "-")) SetDialogResponse(dialog, filename); else ClearDialogResponse(dialog); popup(w, dialogpopup, call_data); #endif break; case SAVE: #ifdef SELFILE fp = XsraSelFile(toplevel, app_res.save_prompt, okay, cancel, app_res.save_fail, "", "w", NULL, &name); if (fp == NULL) break; pscopydoc(fp); fclose(fp); XtFree(name); #else SetDialogPrompt(dialog, app_res.save_prompt); ClearDialogResponse(dialog); popup(w, dialogpopup, call_data); #endif break; } } /* Explicitly reopen the file. */ void reopen_file(w, client_data, call_data) Widget w; XtPointer client_data, call_data; { extern int pagehistory[], pageindex; struct stat sbuf; int number = current_page; pdf_clear(); fclose(psfile); pageindex=0; XtSetSensitive(backbutton, False); psfile = fopen(filename, "r"); mtime = sbuf.st_mtime; if (oldfilename) XtFree(oldfilename); oldfilename = XtNewString(filename); new_file(number); show_page(number); } /* Get the selection, if no selection, get the insertion point. */ /* If the new_page is different from the current page show it. */ /* If not at the first page, show the previous page. */ void prev_page(w, client_data, call_data) Widget w; XtPointer client_data, call_data; { XawTextPosition pos, end; int new_page; XawTextGetSelectionPos(toc, &pos, &end); if (pos == end) { /* Nothing selected */ pos = XawTextGetInsertionPoint(toc); } if ((new_page = pos/toc_entry_length) == current_page) { new_page = current_page - 1; } if (new_page < 0) return; show_page(new_page); } void back_page(w, client_data, call_data) Widget w; XtPointer client_data, call_data; { extern int pagehistory[], pageindex; if (pageindex>0) show_page(pagehistory[--pageindex]); else prev_page(w, client_data, call_data); XtSetSensitive(backbutton, pageindex>0); return; } /* Get the selection, if no selection, get the insertion point. */ /* Show this page. */ void this_page(w, client_data, call_data) Widget w; XtPointer client_data, call_data; { if (toc_text) { XawTextPosition pos, end; int new_page; XawTextGetSelectionPos(toc, &pos, &end); if (pos == end) { /* Nothing selected */ pos = XawTextGetInsertionPoint(toc); } new_page = pos/toc_entry_length; show_page(new_page); } else { GhostviewDisableInterpreter(page); show_page(0); } } /* Get the selection, if no selection, get the insertion point. */ /* If the new_page is different from the current page show it. */ /* If not at the last page, show the next page. */ void next_page(w, client_data, call_data) Widget w; XtPointer client_data, call_data; { XawTextPosition pos, end; int new_page = 0; if (toc_text) { XawTextGetSelectionPos(toc, &pos, &end); if (pos == end) { /* Nothing selected */ pos = XawTextGetInsertionPoint(toc); } if ((new_page = pos/toc_entry_length) == current_page) { new_page = current_page + 1; } if (new_page >= doc->numpages) return; } show_page(new_page); } /* Center the viewport over the page */ void center_page(w, client_data, call_data) Widget w; XtPointer client_data, call_data; { Arg args[2]; Widget scroll; float top, shown; scroll = XtNameToWidget(pageview, "vertical"); if (scroll) { XtSetArg(args[0], XtNshown, &shown); XtSetArg(args[1], XtNtopOfThumb, &top); XtGetValues(scroll, args, TWO); top = (1.0 - shown) / 2.0; XtCallCallbacks(scroll, XtNjumpProc, &top); } scroll = XtNameToWidget(pageview, "horizontal"); if (scroll) { XtSetArg(args[0], XtNshown, &shown); XtSetArg(args[1], XtNtopOfThumb, &top); XtGetValues(scroll, args, TWO); top = (1.0 - shown) / 2.0; XtCallCallbacks(scroll, XtNjumpProc, &top); } } /* Get the selection, if no selection, get the insertion point. */ /* Mark all pages in range, and cause toc to update. */ void mark_page(w, client_data, call_data) Widget w; XtPointer client_data, call_data; { XawTextPosition begin, end; int i; XawTextGetSelectionPos(toc, &begin, &end); if (begin == end) { /* Nothing selected */ begin = end = XawTextGetInsertionPoint(toc); } else { end--; /* Sometimes end spills onto next line */ } for (i = begin/toc_entry_length; i <= end/toc_entry_length; i++) { toc_text[i*toc_entry_length] = '*'; XawTextInvalidate(toc, i*toc_entry_length, i*toc_entry_length+1); } } /* Get the selection, if no selection, get the insertion point. */ /* Unmark all pages in range, and cause toc to update. */ void unmark_page(w, client_data, call_data) Widget w; XtPointer client_data, call_data; { XawTextPosition begin, end; int i; XawTextGetSelectionPos(toc, &begin, &end); if (begin == end) { /* Nothing selected */ begin = end = XawTextGetInsertionPoint(toc); } else { end--; /* Sometimes end spills onto next line */ } for (i = begin/toc_entry_length; i <= end/toc_entry_length; i++) { toc_text[i*toc_entry_length] = ' '; XawTextInvalidate(toc, i*toc_entry_length, i*toc_entry_length+1); } } /* Set new magstep. Reshow the current page if magstep changed. */ void set_magstep(w, client_data, call_data) Widget w; XtPointer client_data, call_data; { app_res.magstep = (int)client_data; if (set_new_magstep()) { layout_ghostview(); show_page(current_page); } } /* Set new orientation. Reshow the current page if orientation changed. */ void set_orientation(w, client_data, call_data) Widget w; XtPointer client_data, call_data; { app_res.force_orientation = force_setting; app_res.orientation = (XtPageOrientation) client_data; if (set_new_orientation(current_page)) { layout_ghostview(); show_page(current_page); } } /* Swap the landscape labels and change the flag. */ void swap_landscape(w, client_data, call_data) Widget w; XtPointer client_data, call_data; { Arg args[1]; String s1, s2; app_res.swap_landscape = !app_res.swap_landscape; XtSetArg(args[0], XtNlabel, &s1); XtGetValues(landscapebutton, args, ONE); s1 = XtNewString(s1); XtSetArg(args[0], XtNlabel, &s2); XtGetValues(seascapebutton, args, ONE); s2 = XtNewString(s2); XtSetArg(args[0], XtNlabel, s2); XtSetValues(landscapebutton, args, ONE); XtSetArg(args[0], XtNlabel, s1); XtSetValues(seascapebutton, args, ONE); XtFree(s1); XtFree(s2); if (set_new_orientation(current_page)) { layout_ghostview(); show_page(current_page); } } /* Set new page media. If new page media is different, update app_resources */ /* and redisplay page. */ void set_pagemedia(w, client_data, call_data) Widget w; XtPointer client_data, call_data; { int new_pagemedia = (int) client_data; if (new_pagemedia >= base_papersize) { default_pagemedia = new_pagemedia; app_res.force_pagemedia = force_setting; } else { document_media = new_pagemedia; force_document_media = force_setting; } if (set_new_pagemedia(current_page)) { layout_ghostview(); show_page(current_page); } } /* track mouse pointer and popup zoom window */ void track_and_zoom(w, client_data, call_data) Widget w; XtPointer client_data, call_data; { Arg args[20]; Cardinal num_args; Dimension width, height; Widget zoom; Widget zoomform; Widget zoompage; Widget zoomdismiss; FILE *zoomfile; struct stat sbuf; GhostviewReturnStruct *p = (GhostviewReturnStruct *)call_data; int llx; int lly; int urx; int ury; int bottom_margin; int left_margin; int right_margin; int top_margin; int i; int gotopage; /* locator events have zero width and height */ if ((p->width == 0) || (p->height == 0)) { char buf[32]; if (!app_res.show_locator) return; sprintf(buf, "(%d, %d)", p->psx, p->psy); XtSetArg(args[0], XtNlabel, buf); XtSetValues(locator, args, ONE); return; } /* If no file, nothing to zoom. */ if (!psfile) return; /* If in an anchor jump to instead */ if ((gotopage=pdf_page(p->psx,p->psy))>=0) { if(pageindexpsx - p->width/2; lly = p->psy - p->height/2; urx = p->psx + p->width/2; ury = p->psy + p->height/2; /* Make sure zoom window doesn't go off the edge of the page */ if (llx < current_llx) { llx = current_llx; urx = llx + p->width; } if (lly < current_lly) { lly = current_lly; ury = lly + p->height; } if (urx > current_urx) { urx = current_urx; llx = urx - p->width; } if (ury > current_ury) { ury = current_ury; lly = ury - p->height; } if (llx < current_llx) { llx = current_llx; } if (lly < current_lly) { lly = current_lly; } bottom_margin = lly - current_lly; left_margin = llx - current_llx; right_margin = current_urx - urx; top_margin = current_ury - ury; num_args = 0; XtSetArg(args[num_args], XtNtop, XtChainTop); num_args++; XtSetArg(args[num_args], XtNbottom, XtChainBottom); num_args++; XtSetArg(args[num_args], XtNleft, XtChainLeft); num_args++; XtSetArg(args[num_args], XtNright, XtChainRight); num_args++; XtSetArg(args[num_args], XtNorientation, current_orientation); num_args++; XtSetArg(args[num_args], XtNllx, llx); num_args++; XtSetArg(args[num_args], XtNlly, lly); num_args++; XtSetArg(args[num_args], XtNurx, urx); num_args++; XtSetArg(args[num_args], XtNury, ury); num_args++; XtSetArg(args[num_args], XtNbottomMargin, bottom_margin); num_args++; XtSetArg(args[num_args], XtNleftMargin, left_margin); num_args++; XtSetArg(args[num_args], XtNrightMargin, right_margin); num_args++; XtSetArg(args[num_args], XtNtopMargin, top_margin); num_args++; XtSetArg(args[num_args], XtNbottomMargin, bottom_margin); num_args++; XtSetFloatArg(args[num_args], XtNxdpi, p->xdpi); num_args++; XtSetFloatArg(args[num_args], XtNydpi, p->ydpi); num_args++; if (!toc_text) { XtSetArg(args[num_args], XtNfilename, filename); num_args++; } zoompage = XtCreateManagedWidget("page", ghostviewWidgetClass, zoomform, args, num_args); num_ghosts++; XtAddCallback(zoompage, XtNcallback, track_and_zoom, (XtPointer)0); XtAddCallback(zoompage, XtNmessageCallback, message, (XtPointer)zoompage); XtAddCallback(zoompage, XtNdestroyCallback, destroy_ghost, (XtPointer)zoompage); num_args = 0; XtSetArg(args[num_args], XtNfromVert, zoompage); num_args++; XtSetArg(args[num_args], XtNtop, XtChainBottom); num_args++; XtSetArg(args[num_args], XtNbottom, XtChainBottom); num_args++; XtSetArg(args[num_args], XtNleft, XtChainLeft); num_args++; XtSetArg(args[num_args], XtNright, XtChainRight); num_args++; zoomdismiss = XtCreateManagedWidget("dismiss", commandWidgetClass, zoomform, args, num_args); XtAddCallback(zoomdismiss, XtNcallback, destroy, (XtPointer)zoom); XtSetArg(args[0], XtNwidth, &width); XtGetValues(zoompage, args, ONE); XtSetArg(args[0], XtNwidth, width); XtSetValues(zoomdismiss, args, ONE); XtRealizeWidget(zoom); positionpopup(zoom); num_args = 0; XtSetArg(args[num_args], XtNwidth, &width); num_args++; XtSetArg(args[num_args], XtNheight, &height); num_args++; XtGetValues(zoom, args, num_args); num_args = 0; XtSetArg(args[num_args], XtNminWidth, width); num_args++; XtSetArg(args[num_args], XtNminHeight, height); num_args++; XtSetArg(args[num_args], XtNmaxWidth, width); num_args++; XtSetArg(args[num_args], XtNmaxHeight, height); num_args++; XtSetValues(zoom, args, num_args); XSetWMProtocols(XtDisplay(zoom), XtWindow(zoom), &wm_delete_window, 1); XtPopup(zoom, XtGrabNone); if (toc_text) { zoomfile = fopen(filename, "r"); if (zoomfile == NULL) return; GhostviewSendPS(zoompage, zoomfile, doc->beginprolog, doc->lenprolog, False); GhostviewSendPS(zoompage, zoomfile, doc->beginsetup, doc->lensetup, False); if (doc->pageorder == DESCEND) i = (doc->numpages - 1) - current_page; else i = current_page; GhostviewSendPS(zoompage, zoomfile, doc->pages[i].begin, doc->pages[i].len, True); } } /* Process messages from ghostscript */ /* Refresh occurs when window was resized unexpectedly */ void message(w, client_data, call_data) Widget w; XtPointer client_data, call_data; { int i; char *error; if (!strcmp((char *) call_data, "Failed")) { if ((Widget)client_data == page) { error = "Error: PostScript interpreter failed in main window.\n\n"; } else { error = "Error: PostScript interpreter failed in zoom window.\n\n"; } output(w, NULL, error); } else if (!strcmp((char *) call_data, "BadAlloc")) { if ((Widget)client_data == page) { error = "Warning: Could not allocate backing pixmap in main window.\n\n"; } else { error = "Warning: Could not allocate backing pixmap in zoom window.\n\n"; } output(w, NULL, error); } else if (!strcmp((char *) call_data, "Refresh")) { if (toc_text) { GhostviewSendPS(w, psfile, doc->beginprolog, doc->lenprolog, False); GhostviewSendPS(w, psfile, doc->beginsetup, doc->lensetup, False); if (doc->pageorder == DESCEND) i = (doc->numpages - 1) - current_page; else i = current_page; GhostviewSendPS(w, psfile, doc->pages[i].begin, doc->pages[i].len, False); } } } /* Take output from ghostscript and display it in the infotext popup window */ void output(w, client_data, call_data) Widget w; XtPointer client_data, call_data; { Arg args[2]; XawTextBlock message_block; message_block.firstPos = 0; message_block.length = strlen(call_data); message_block.ptr = call_data; message_block.format = FMT8BIT; XawTextDisableRedisplay(infotext); XtSetArg(args[0], XtNeditType, XawtextAppend); XtSetValues(infotext, args, ONE); XawTextReplace(infotext, info_length, info_length, &message_block); info_length = info_length + message_block.length; XtSetArg(args[0], XtNeditType, XawtextRead); XtSetArg(args[1], XtNinsertPosition, info_length); XtSetValues(infotext, args, TWO); XawTextEnableRedisplay(infotext); if (!info_up) XtPopup(infopopup, XtGrabNone); info_up = True; } /* Dismiss popup dialog */ void okay(w, client_data, call_data) Widget w; XtPointer client_data, call_data; { String name, error; Widget dialog; dialog = (Widget)client_data; name = GetDialogResponse(dialog); switch (mode) { case PRINT_WHOLE: case PRINT_MARKED: if (error = print_file(name, (mode == PRINT_WHOLE))) { char *buf = XtMalloc(strlen(error) + strlen(app_res.print_prompt) + 2); sprintf(buf, "%s\n%s", error, app_res.print_prompt); SetDialogPrompt(dialog, buf); XtFree(error); XtFree(buf); } else { XtPopdown(XtParent(dialog)); } break; case OPEN: if (error = open_file(name)) { char *buf = XtMalloc(strlen(error) + strlen(app_res.open_prompt) + 2); sprintf(buf, "%s\n%s", error, app_res.open_prompt); SetDialogPrompt(dialog, buf); XtFree(error); XtFree(buf); } else { XtPopdown(XtParent(dialog)); } break; case SAVE: if (error = save_file(name)) { char *buf = XtMalloc(strlen(error) + strlen(app_res.save_prompt) + 2); sprintf(buf, "%s\n%s", error, app_res.save_prompt); SetDialogPrompt(dialog, buf); XtFree(error); XtFree(buf); } else { XtPopdown(XtParent(dialog)); } break; } XtFree(name); } /* Dismiss popup window */ void dismiss(w, client_data, call_data) Widget w; XtPointer client_data, call_data; { XtPopdown((Widget)client_data); if ((Widget)client_data == infopopup) info_up = False; } /* Destroy popup window */ void destroy(w, client_data, call_data) Widget w; XtPointer client_data, call_data; { XtDestroyWidget((Widget)client_data); } /* destroy callback for Ghostview widgets. */ /* The disable interpreter call ensures that ghostscript is killed. */ /* One the count goes to 0, we are sure that all forked processes have */ /* been killed and that we can safely exit. */ void destroy_ghost(w, client_data, call_data) Widget w; XtPointer client_data, call_data; { GhostviewDisableInterpreter((Widget) client_data); num_ghosts--; if (num_ghosts) return; if (dying) old_Xerror(XtDisplay(w), &bomb); XtDestroyApplicationContext(app_con); exit(0); }