From 62ad6298a589dd16820c7d0bbfcd2b5381a2589e Mon Sep 17 00:00:00 2001 From: Roland Mainz Date: Mon, 24 May 2004 03:17:44 +0000 Subject: Fix for http://pdx.freedesktop.org/cgi-bin/bugzilla/show_bug.cgi?id=611 - Adding simple text viewer (xmore) --- print.c | 353 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 353 insertions(+) create mode 100644 print.c (limited to 'print.c') diff --git a/print.c b/print.c new file mode 100644 index 0000000..d8d93d7 --- /dev/null +++ b/print.c @@ -0,0 +1,353 @@ +/* + * $Xorg: print.c,v 1.1 2004/04/30 02:05:54 gisburn Exp $ + * +Copyright 2004 Roland Mainz + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + * + */ + +/* Turn a NULL pointer string into an empty string */ +#define NULLSTR(x) (((x)!=NULL)?(x):("")) + +#define Error(x) { printf x ; exit(EXIT_FAILURE); } +#define Assertion(expr, msg) { if (!(expr)) { Error msg } } +#define Log(x) { if(True) printf x; } + +#include "xmore.h" +#include "print.h" +#include +#include +#include +#include +#include + +#define PRINT_PAGEHEADER 1 + +static Widget +CreatePrintShell(Widget videoshell, + Screen *pscreen, + String printshell_name, + ArgList args, + Cardinal numargs) +{ + String videoname, + videoclass; + Widget pappshell, + printshell; + Display *pdpy = XDisplayOfScreen(pscreen); + int dummyc = 0; + String dummys = ""; + XtGetApplicationNameAndClass(XtDisplay(videoshell), + &videoname, &videoclass); + + /* XXX: Why is the |dummyc|&&|dummys| stuff needed here ? */ + XtDisplayInitialize(XtWidgetToApplicationContext(videoshell), pdpy, + videoname, videoclass, + NULL, 0, + &dummyc, &dummys); + + pappshell = XtVaAppCreateShell(videoname, videoclass, + applicationShellWidgetClass, + pdpy, + XtNscreen, pscreen, + NULL); + printshell = XtCreatePopupShell(printshell_name, + xawPrintShellWidgetClass, + pappshell, args, numargs); + + + /* we're mapping/unmapping at start/end page time */ + XtSetMappedWhenManaged(printshell, False); + + /* We realise the widget when we're done with building the widget tree... */ + + return printshell; +} + +typedef struct +{ + Widget toplevel; + Bool isPrinting; + Widget printshell; + struct + { + Widget form; + Widget pageheaderlabel; + Widget text; + } content; /* content to print */ + int numpages; + Display *pdpy; + Screen *pscreen; + XPContext pcontext; + void *printtofile_handle; + const char *jobtitle; +} AppPrintData; + +static AppPrintData apdx; +static AppPrintData *apd = &apdx; + +/* Count pages in a text widget + * WARNING: This will reset the current position of the text widget + * back to the beginning */ +static +long CountPages(Widget textWidget) +{ + long numpages = 0; + + XawTextPosition prevpagepos = -1, + currpos = 0; + + /* Move to the top of the file... */ + XtCallActionProc(textWidget, "beginning-of-file", NULL, NULL, 0); + + /* ... count pages ...*/ + do + { + prevpagepos = XawTextTopPosition(textWidget); + XtCallActionProc(textWidget, "next-page", NULL, NULL, 0); + currpos = XawTextTopPosition(textWidget); + numpages++; + } while(prevpagepos != currpos); + + /* ... and move to the top of the file... */ + XtCallActionProc(textWidget, "beginning-of-file", NULL, NULL, 0); + + return numpages; +} + +static +int GetCurrPageNum(Widget printshell) +{ + Cardinal n; + Arg args[2]; + int pagenum = -666; /* bah! */ + + n = 0; + XtSetArg(args[n], XawNcurrPageNumInJob, &pagenum); n++; + XtGetValues(printshell, args, n); + + return pagenum; +} + +static void +PageSetupCB(Widget widget, XtPointer client_data, XtPointer call_data) +{ + Widget pshell = widget; + XawPrintShellCallbackStruct *psp = (XawPrintShellCallbackStruct *)call_data; + AppPrintData *p = (AppPrintData *)client_data; + + Log(("--> PageSetupCB\n")); + + if (!psp->last_page_in_job) { + int currpage = GetCurrPageNum(pshell); +#ifdef PRINT_PAGEHEADER + char buffer[256]; + sprintf(buffer, "Title: %s / Page: %d/%d", p->jobtitle, currpage, p->numpages); + XtVaSetValues(apd->content.pageheaderlabel, XtNlabel, buffer, NULL); +#endif /* PRINT_PAGEHEADER */ + + /* Note: XawPrintShell's pagecount starts with '1' + * (=first page is page no. '1') */ + if (currpage > 1) { + Log(("pagedown %d\n", currpage)); + XtCallActionProc(p->content.text, "next-page", NULL, NULL, 0); + } + else + { + Log(("first page\n")); + } + + if (currpage >= p->numpages) { + psp->last_page_in_job = True; + } + } +} + +void FinishPrinting(AppPrintData *p) +{ + if (p->printtofile_handle) { + if (XpuWaitForPrintFileChild(p->printtofile_handle) != XPGetDocFinished) { + fprintf(stderr, "%s: Error while printing to file.\n", ProgramName); + } + p->printtofile_handle = NULL; + } + + if (p->printshell) { + XtDestroyWidget(p->printshell); + p->printshell = NULL; + } + + /* |p->pdpy| and |p->pcontext| are destroyed when th + * print dialog widget gets destroyed. */ + + p->toplevel = NULL; + p->isPrinting = False; + p->pdpy = NULL; + p->pscreen = NULL; + p->pcontext = None; +} + +static +void PrintEndJobCB(Widget pshell, XtPointer client_data, XtPointer call_data) +{ + AppPrintData *p = (AppPrintData *)client_data; + + Log(("--> PrintEndJobCB\n")); + + /* Finish printing and destroy print shell (it's legal to destroy Xt + * widgets from within it's own callbacks) */ + FinishPrinting(p); +} + +XFontStruct *GetPrintTextFont(Display *pdpy, long dpi) +{ + XFontStruct *font; + char fontname[1024]; + + sprintf(fontname, "-adobe-courier-medium-r-normal--40-*-%ld-%ld-*-*-iso8859-1", dpi, dpi); + font = XLoadQueryFont(pdpy, fontname); + if (!font) { + sprintf(fontname, "-*-*-*-*-*-*-*-160-%ld-%ld-*-*-iso8859-1", dpi, dpi); + font = XLoadQueryFont(pdpy, fontname); + } + if (!font) + Error(("XLoadQueryFont failure.\n")); + return font; +} + +void DoPrint(Widget toplevel, Display *pdpy, XPContext pcontext, + const char *jobtitle, const char *toFile) +{ + long dpi = 0; + int n; + Arg args[20]; + XFontStruct *textfont = NULL; + + if (apd->isPrinting) { + fprintf(stderr, "%s: Already busy with printing.\n", ProgramName); + return; + } + + /* Configure the print context (paper size, title etc.) + * We must do this before creating any Xt widgets - otherwise they will + * make wrong assuptions about fonts, resultions etc. ... + */ + XpuSetJobTitle(pdpy, pcontext, jobtitle); + + /* Configuration done, set the context */ + XpSetContext(pdpy, pcontext); + + /* Get default printer resolution */ + if (XpuGetResolution(pdpy, pcontext, &dpi) != 1) { + fprintf(stderr, "%s: No default resolution for printer.\n", ProgramName); + XpuClosePrinterDisplay(pdpy, pcontext); + return; + } + + apd->toplevel = toplevel; + apd->pdpy = pdpy; + apd->pcontext = pcontext; + apd->pscreen = XpGetScreenOfContext(pdpy, pcontext); + apd->jobtitle = jobtitle; + + n = 0; + XtSetArg(args[n], XawNlayoutMode, XawPrintLAYOUTMODE_DRAWABLEAREA); n++; + apd->printshell = CreatePrintShell(toplevel, apd->pscreen, "Print", args, n); + + n = 0; + XtSetArg(args[n], XtNresizable, True); n++; + XtSetArg(args[n], XtNright, XtChainRight); n++; + apd->content.form = XtCreateManagedWidget("form", formWidgetClass, apd->printshell, args, n); + + textfont = GetPrintTextFont(pdpy, dpi); + +#ifdef PRINT_PAGEHEADER + n = 0; + XtSetArg(args[n], XtNfromHoriz, NULL); n++; + XtSetArg(args[n], XtNfromVert, NULL); n++; + XtSetArg(args[n], XtNtop, XtChainTop); n++; + XtSetArg(args[n], XtNright, XtChainRight); n++; + XtSetArg(args[n], XtNresizable, True); n++; + XtSetArg(args[n], XtNfont, textfont); n++; /* fontset would be better */ + XtSetArg(args[n], XtNlabel, "Page: n/n"); n++; + XtSetArg(args[n], XtNjustify, XtJustifyRight); n++; + apd->content.pageheaderlabel = XtCreateManagedWidget("pageinfo", labelWidgetClass, apd->content.form, args, n); +#endif /* PRINT_PAGEHEADER */ + + n = 0; + XtSetArg(args[n], XtNtype, XawAsciiFile); n++; + XtSetArg(args[n], XtNstring, viewFileName); n++; + XtSetArg(args[n], XtNscrollHorizontal, XawtextScrollNever); n++; + XtSetArg(args[n], XtNscrollVertical, XawtextScrollNever); n++; + +/* Usually I would expect that using |XtNfromVert, apd->content.pageheaderlabel| + * would be the correct way to place the text widget with the main content below + * the page header widget - but for an unknown reason this doesn not work: The + * text widget squishes itself into the bottom half of the page and only occupies + * 1/2 of the page's with... ;-(( */ +#define WORKAROUND_FOR_SOMETHING_IS_WRONG 1 +#ifdef WORKAROUND_FOR_SOMETHING_IS_WRONG + XtSetArg(args[n], XtNtop, XtChainTop); n++; + XtSetArg(args[n], XtNright, XtChainRight); n++; + XtSetArg(args[n], XtNvertDistance, (textfont->ascent+textfont->descent+2)*2); n++; +#else + XtSetArg(args[n], XtNfromHoriz, NULL); n++; + XtSetArg(args[n], XtNfromVert, apd->content.pageheaderlabel); n++; +#endif + XtSetArg(args[n], XtNfont, textfont); n++; /* fontset would be better */ + apd->content.text = XtCreateManagedWidget("text", asciiTextWidgetClass, apd->content.form, args, n); + /* Disable the caret - that is not needed for printing */ + XawTextDisplayCaret(apd->content.text, False); + + XtAddCallback(apd->printshell, XawNpageSetupCallback, PageSetupCB, (XtPointer)apd); + XtAddCallback(apd->printshell, XawNendJobCallback, PrintEndJobCB, (XtPointer)apd); + + /* Realise print shell (which will set position+size of the child + * widgets based on the current page size) */ + XtRealizeWidget(apd->printshell); + + /* Count number of pages in the text widget */ + apd->numpages = CountPages(apd->content.text); + + /* Make sure that the Xt machinery is really using the right screen (assertion) */ + if (XpGetScreenOfContext(XtDisplay(apd->printshell), apd->pcontext) != XtScreen(apd->printshell)) + Error(("Widget's screen != print screen. BAD.\n")); + + apd->isPrinting = True; + + if (toFile) { + printf("%s: Printing to file '%s'...\n", ProgramName, toFile); + apd->printtofile_handle = XpuStartJobToFile(pdpy, pcontext, toFile); + if (!apd->printtofile_handle) { + perror("XpuStartJobToFile failure"); + apd->isPrinting = False; + return; + } + } + else + { + printf("%s: Printing to printer...\n", ProgramName); + XpuStartJobToSpooler(pdpy); + } +} + + -- cgit v1.2.3