Back to index

tetex-bin  3.0
print-log.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2002-2004  Paul Vojta and the xdvik development team
00003  * 
00004  * Permission is hereby granted, free of charge, to any person obtaining a copy
00005  * of this software and associated documentation files (the "Software"), to
00006  * deal in the Software without restriction, including without limitation the
00007  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
00008  * sell copies of the Software, and to permit persons to whom the Software is
00009  * furnished to do so, subject to the following conditions:
00010  * 
00011  * The above copyright notice and this permission notice shall be included in
00012  * all copies or substantial portions of the Software.
00013  * 
00014  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00015  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00016  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
00017  * PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
00018  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
00019  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
00020  * OTHER DEALINGS IN THE SOFTWARE.
00021  */
00022 
00023 #include <string.h>
00024 #include "xdvi-config.h"
00025 #include "xdvi.h"
00026 
00027 #include "xdvi-debug.h"
00028 #include "print-dialog.h"
00029 #include "print-log.h" /* for adjust_vertically() */
00030 #include "util.h"
00031 #include "x_util.h"
00032 #include "xlwradio.h"
00033 
00034 #include <X11/Xatom.h>
00035 #include <X11/StringDefs.h>
00036 
00037 /* FIXME: change #if XAW to #if !defined(MOTIF) to make it consistent with other files */
00038 
00039 #ifdef MOTIF
00040 # include <Xm/BulletinB.h>
00041 # include <Xm/DialogS.h>
00042 # include <Xm/MessageB.h>
00043 # include <Xm/LabelG.h>
00044 # include <Xm/Form.h>
00045 # include <Xm/Frame.h>
00046 # include <Xm/ToggleBG.h>
00047 # include <Xm/PanedW.h>
00048 # include <Xm/Text.h>
00049 # include <Xm/TextF.h>
00050 # include <Xm/PushB.h>
00051 # include <Xm/Protocols.h>
00052 # include <Xm/AtomMgr.h>
00053 #else
00054 # include <X11/Shell.h>
00055 # include <X11/Xaw/Paned.h>
00056 # include <X11/Xaw/Box.h>
00057 # include <X11/Xaw/Form.h>
00058 # include <X11/Xaw/Label.h>
00059 # include <X11/Xaw/Command.h>
00060 # include <X11/Xaw/Toggle.h>
00061 # include <X11/Xaw/AsciiText.h>
00062 
00063 /* XawFmt8Bit is only available starting with X11R6: */
00064 # if XtSpecificationRelease < 6
00065 #  define XawFmt8Bit    FMT8BIT
00066 # endif
00067 
00068 #endif /* MOTIF */
00069 
00070 static Boolean printlog_active = False; /* if the print log is active */
00071 static Widget printlog_shell = NULL;
00072 
00073 /* global callbacks - FIXME: avoid this, by passing the callback as argument to the action? */
00074 static void (*g_close_callback)(Widget w, XtPointer client_data, XtPointer call_data);
00075 static void (*g_cancel_callback)(Widget w, XtPointer client_data, XtPointer call_data);
00076 static void (*g_destroy_callback)(Widget w, XtPointer client_data, XtPointer call_data);
00077 
00078 static void printlog_act_close(Widget, XEvent *, String *, Cardinal *);
00079 static void printlog_act_keep(Widget, XEvent *, String *, Cardinal *);
00080 static void printlog_act_unkeep(Widget, XEvent *, String *, Cardinal *);
00081 static void printlog_act_cancel(Widget, XEvent *, String *, Cardinal *);
00082 static void printlog_act_destroy(Widget, XEvent *, String *, Cardinal *);
00083 
00084 #ifdef MOTIF
00085 static void xm_printlog_act_destroy(Widget w, XtPointer a, XtPointer b)
00086 {
00087     UNUSED(w);
00088     UNUSED(a);
00089     UNUSED(b);
00090     ASSERT(g_destroy_callback != NULL, "Callback not initialized");
00091     (g_destroy_callback)(NULL, NULL, NULL);
00092 }
00093 #endif
00094 
00095 static Atom WM_DELETE_WINDOW;
00096 
00097 static XtActionsRec printlog_actions[] = {
00098     {"printlogIntClose",    printlog_act_close},
00099     {"printlogIntKeep",            printlog_act_keep},
00100     {"printlogIntUnkeep",   printlog_act_unkeep},
00101     {"printlogIntCancel",   printlog_act_cancel},
00102     {"WM_destroy",          printlog_act_destroy },
00103 };
00104 
00105 static char *text_translations = \
00106        "<Key>Return:printlogIntClose()\n"
00107        "^<Key>c:printlogIntCancel()\n"
00108        "^<Key>s:printlogIntKeep()\n"
00109        "^<Key>q:printlogIntUnkeep()";
00110 
00111 static Widget printlog_text;
00112 static Widget printlog_close;
00113 static Widget printlog_unkeep;
00114 static Widget printlog_cancel;
00115 
00116 
00117 #ifdef MOTIF
00118 static XmTextPosition printlog_length;
00119 #else
00120 static XawTextPosition printlog_length;
00121 #endif
00122 
00123 Boolean
00124 printlog_raise_active(void)
00125 {
00126     if (printlog_active) {
00127        XRaiseWindow(DISP, XtWindow(printlog_shell));
00128        return True;
00129     }
00130     return False;
00131 }
00132 
00133 void
00134 printlog_popup(void)
00135 {
00136     printlog_length = 0;
00137     center_window(printlog_shell, globals.widgets.top_level);
00138     XtMapWidget(printlog_shell);
00139 /*     XtPopup(printlog_shell, XtGrabNone); */
00140     printlog_active = True;
00141 #ifndef MOTIF
00142     XSetWMProtocols(XtDisplay(printlog_shell), XtWindow(printlog_shell), &WM_DELETE_WINDOW, 1);
00143 #else
00144     XmProcessTraversal(printlog_cancel, XmTRAVERSE_CURRENT);
00145     XtOverrideTranslations(printlog_text, XtParseTranslationTable(text_translations));
00146 #endif
00147 }
00148 
00149 void
00150 printlog_reset(void)
00151 {
00152     printlog_length = 0;
00153 }
00154 
00155 
00156 
00157 void
00158 printlog_create(const char *title,
00159               const char *close_label,
00160               void (*close_callback)(Widget w, XtPointer client_data, XtPointer call_data),
00161               void (*cancel_callback)(Widget w, XtPointer client_data, XtPointer call_data),
00162               void (*destroy_callback)(Widget w, XtPointer client_data, XtPointer call_data),
00163               void (*unkeep_callback)(Widget w, XtPointer client_data, XtPointer call_data))
00164 {
00165     /*
00166       FIXME BETA: The printlog presents too much detail and is confusing for users.
00167       Re-implement it using an `printing page n of m' message,
00168       i.e. according to the spec on:
00169       http://xdvi.sourceforge.net/gui.html#file-print
00170       Possible save the detailed log to a different window that can be viewed
00171       via `File -> logs', as described on:
00172       http://xdvi.sourceforge.net/gui.html#file-logs
00173      */
00174     XtAddActions(printlog_actions, XtNumber(printlog_actions));
00175     g_destroy_callback = destroy_callback;
00176     
00177 #ifndef MOTIF
00178     /* Create popup window */
00179     if (printlog_shell == NULL) {
00180        Widget form, box, paned;
00181 /*     int ddist; */
00182 /*     Dimension w0, w1, w2, w3, b; */
00183        
00184        XtTranslations wm_translations = XtParseTranslationTable("<Message>WM_PROTOCOLS: WM_destroy()");
00185        printlog_shell = XtVaCreatePopupShell("printlog",
00186                                          transientShellWidgetClass, globals.widgets.top_level,
00187                                          XtNtitle, title,
00188                                          XtNtransientFor, globals.widgets.top_level,
00189                                          XtNmappedWhenManaged, False,
00190                                          XtNtranslations, wm_translations,
00191                                          XtNtransientFor, globals.widgets.top_level,
00192                                          NULL);
00193 
00194        WM_DELETE_WINDOW = XInternAtom(XtDisplay(printlog_shell), "WM_DELETE_WINDOW", False);
00195        
00196        paned = XtVaCreateManagedWidget("paned", panedWidgetClass, printlog_shell, NULL);
00197        
00198        form = XtVaCreateManagedWidget("form", formWidgetClass,
00199                                  paned,
00200                                  XtNdefaultDistance, 6,
00201                                  NULL);
00202        printlog_text = XtVaCreateManagedWidget("text",
00203                                           asciiTextWidgetClass, form,
00204                                           XtNstring, "",
00205                                           XtNdataCompression, False,
00206                                           XtNeditType, XawtextAppend,
00207                                           XtNscrollHorizontal, XawtextScrollAlways,
00208                                           XtNscrollVertical, XawtextScrollAlways,
00209                                           XtNwidth, 600,
00210                                           XtNheight, 400,
00211                                           XtNleft, XawChainLeft,
00212                                           XtNright, XawChainRight,
00213                                           XtNtop, XawChainTop,
00214                                           XtNbottom, XawChainBottom,
00215                                           NULL);
00216        XtOverrideTranslations(printlog_text, XtParseTranslationTable(text_translations));
00217 
00218        printlog_unkeep = XtVaCreateManagedWidget("keep",
00219 #ifdef XAW
00220                                             radioWidgetClass,
00221 #else
00222                                             toggleWidgetClass,
00223 #endif
00224                                             form,
00225                                             XtNlabel, close_label,
00226                                             XtNborderWidth, 0,
00227                                             XtNisRadio, False,
00228                                             XtNhighlightThickness, 1,
00229                                             XtNfromVert, printlog_text,
00230                                             XtNleft, XawChainLeft,
00231                                             XtNright, XawChainLeft,
00232                                             XtNtop, XawChainBottom,
00233                                             XtNbottom, XawChainBottom,
00234                                             NULL);
00235        XtVaSetValues(printlog_unkeep,
00236                     XtNstate, resource.dvips_hang > 0 && resource.dvips_fail_hang > 0,
00237                     NULL);
00238        XtAddCallback(printlog_unkeep, XtNcallback, unkeep_callback, NULL);
00239        
00240        /* box for the Close/Cancel button */
00241        box = XtVaCreateManagedWidget("box", formWidgetClass,
00242                                   paned,
00243                                   /* resizing by user isn't needed */
00244                                   XtNshowGrip, False,
00245                                   XtNdefaultDistance, 6, /* some padding */
00246                                   /* resizing the window shouldn't influence this box,
00247                                    * but  only the pane widget
00248                                    */
00249                                   XtNskipAdjust, True,
00250                                   XtNaccelerators, G_accels_cr,
00251                                   NULL);
00252        
00253        printlog_close = XtVaCreateManagedWidget("close",
00254                                            commandWidgetClass, box,
00255                                            XtNlabel, "Close",
00256                                            XtNsensitive, False,
00257                                            XtNleft, XawChainLeft,
00258                                            XtNright, XawChainLeft,
00259                                            XtNtop, XawChainBottom,
00260                                            XtNbottom, XawChainBottom,
00261                                            NULL);
00262        XtAddCallback(printlog_close, XtNcallback, close_callback, NULL);
00263        g_close_callback = close_callback;
00264        
00265        printlog_cancel = XtVaCreateManagedWidget("cancel",
00266                                             commandWidgetClass, box,
00267                                             XtNlabel, "Cancel",
00268                                             XtNfromHoriz, printlog_unkeep,
00269                                             XtNleft, XawChainRight,
00270                                             XtNright, XawChainRight,
00271                                             XtNtop, XawChainBottom,
00272                                             XtNbottom, XawChainBottom,
00273                                             NULL);
00274        XtAddCallback(printlog_cancel, XtNcallback, cancel_callback, NULL);
00275        g_cancel_callback = cancel_callback;
00276        XtManageChild(printlog_shell);
00277     }
00278     else {
00279        XtSetSensitive(printlog_close, False);
00280        XtSetSensitive(printlog_cancel, True);
00281     }
00282     
00283 #else /* MOTIF */
00284 
00285     /* Create popup window */
00286     if (printlog_shell == NULL) {
00287        Widget form, pane, box;
00288        XmString str;
00289        Arg args[10];
00290        int n;
00291        
00292        printlog_shell = XtVaCreatePopupShell("printlog",
00293                                          xmDialogShellWidgetClass, globals.widgets.top_level,
00294                                          XmNdeleteResponse, XmDO_NOTHING, /* we'll take care of that ourselves */
00295                                          XmNtitle, title,
00296                                          XtNmappedWhenManaged, False,
00297                                          NULL);
00298 
00299        WM_DELETE_WINDOW = XmInternAtom(XtDisplay(printlog_shell), "WM_DELETE_WINDOW", False);
00300        XmAddWMProtocolCallback(printlog_shell, WM_DELETE_WINDOW, xm_printlog_act_destroy, NULL);
00301 
00302        pane = XtVaCreateWidget("printlog_pane", xmPanedWindowWidgetClass, printlog_shell,
00303                             /* make sashes invisible */
00304                             XmNsashWidth, 1,
00305                             XmNsashHeight, 1,
00306                             NULL);
00307        
00308        form = XtVaCreateWidget("form", xmFormWidgetClass, pane,
00309                             XmNhorizontalSpacing, DDIST,
00310                             XmNverticalSpacing, DDIST,
00311                             XmNautoUnmanage, False,
00312                             NULL);
00313        /* force vertical scrollbars. Under Motif 2.x (2.1.0 and 2.2.2 at least),
00314           XmNeditMode must be set early in order to have an effect. */
00315        n = 0;
00316        XtSetArg(args[n], XmNeditMode, XmMULTI_LINE_EDIT);      n++;
00317        XtSetArg(args[n], XmNeditable, False);                  n++;
00318        XtSetArg(args[n], XmNrows, 24);                         n++;
00319        XtSetArg(args[n], XmNcolumns, 80);               n++;
00320        
00321        printlog_text = XmCreateScrolledText(form, "text", args, n);
00322 
00323        XtVaSetValues(XtParent(printlog_text),
00324                     XmNtopAttachment, XmATTACH_FORM,
00325                     XmNleftAttachment, XmATTACH_FORM,
00326                     XmNrightAttachment, XmATTACH_FORM,
00327                     NULL);
00328 
00329        XtManageChild(printlog_text);
00330 
00331        str = XmStringCreateLocalized((char *)close_label);
00332        printlog_unkeep = XtVaCreateManagedWidget("keep",
00333                                           xmToggleButtonGadgetClass, form,
00334                                           XmNlabelString, str,
00335                                           XmNnavigationType, XmTAB_GROUP,
00336                                           XmNtopAttachment, XmATTACH_WIDGET,
00337                                           XmNtopWidget, XtParent(printlog_text),
00338                                           XmNleftAttachment, XmATTACH_FORM,
00339                                           NULL);
00340        XmStringFree(str);
00341        XtAddCallback(printlog_unkeep, XmNvalueChangedCallback, unkeep_callback, NULL);
00342        XmToggleButtonGadgetSetState(printlog_unkeep, resource.dvips_hang > 0 && resource.dvips_fail_hang > 0, False);
00343 
00344        /* box for Close/Cancel button */
00345        box = XtVaCreateManagedWidget("box", xmFormWidgetClass,
00346                                   pane,
00347                                   NULL);
00348        
00349        str = XmStringCreateLocalized("Close");
00350        printlog_close = XtVaCreateManagedWidget("close",
00351                                            xmPushButtonWidgetClass, box,
00352                                            XmNlabelString, str,
00353                                            XmNshowAsDefault, True,
00354                                            XmNsensitive, False,
00355                                            XmNdefaultButtonShadowThickness, 1,
00356                                            XmNtopAttachment, XmATTACH_FORM,
00357                                            XmNbottomAttachment, XmATTACH_FORM,
00358                                            XmNleftAttachment, XmATTACH_FORM,
00359                                            /* to mimick appearance of native dialog buttons: */
00360                                            XmNmarginWidth, 6,
00361                                            XmNmarginHeight, 4,
00362                                            XmNtopOffset, 10,
00363                                            XmNbottomOffset, 10,
00364                                            XmNleftOffset, 10,
00365                                            NULL);
00366        XmStringFree(str);
00367        XtAddCallback(printlog_close, XmNactivateCallback, close_callback, NULL);
00368        g_close_callback = close_callback;
00369 
00370        str = XmStringCreateLocalized("Cancel");
00371        printlog_cancel = XtVaCreateManagedWidget("cancel",
00372                                             xmPushButtonWidgetClass, box,
00373                                             XmNlabelString, str,
00374                                             XmNdefaultButtonShadowThickness, 1,
00375                                             XmNtopAttachment, XmATTACH_FORM,
00376                                             XmNbottomAttachment, XmATTACH_FORM,
00377                                             XmNrightAttachment, XmATTACH_FORM,
00378                                             /* to mimick appearance of native dialog buttons: */
00379                                             XmNmarginWidth, 6,
00380                                             XmNmarginHeight, 4,
00381                                             XmNtopOffset, 10,
00382                                             XmNbottomOffset, 10,
00383                                             XmNrightOffset, 10,
00384                                             NULL);
00385        XmStringFree(str);
00386        XtAddCallback(printlog_cancel, XmNactivateCallback, cancel_callback, NULL);
00387        g_cancel_callback = cancel_callback;
00388 
00389        XtManageChild(box);
00390        XtManageChild(form);
00391        XtManageChild(pane);
00392 /*     center_window(printlog_shell, globals.widgets.top_level); */
00393 /*     XtMapWidget(printlog_shell); */
00394        /* this doesn't help */
00395        /* XtOverrideTranslations(form, XtParseTranslationTable(text_translations)); */
00396        /* XtOverrideTranslations(pane, XtParseTranslationTable(text_translations)); */
00397     }
00398     else {
00399        XtSetSensitive(printlog_close, False);
00400        XtSetSensitive(printlog_cancel, True);
00401     }
00402 #endif
00403     adjust_width(printlog_close, printlog_cancel);
00404 }
00405 
00406 void
00407 printlog_append(const char *str, size_t len)
00408 {
00409 #ifndef MOTIF
00410     
00411     static XawTextBlock block = {0, 0, NULL, 0};
00412 
00413     block.ptr = (char *) str;
00414     block.length = len;
00415     block.format = XawFmt8Bit;
00416     while (XawTextReplace(printlog_text, printlog_length, printlog_length, &block)
00417           != XawEditDone) {
00418        int length;
00419 
00420        XtVaGetValues(printlog_text, XtNlength, &length, NULL);
00421        printlog_length = length;
00422     }
00423     printlog_length += len;
00424     XawTextSetInsertionPoint(printlog_text, printlog_length);
00425 
00426 #else /* MOTIF */
00427     
00428     XmTextInsert(printlog_text, printlog_length, (char *) str);
00429     printlog_length += len;
00430     XtVaSetValues(printlog_text, XmNcursorPosition, printlog_length, NULL);
00431     XmTextShowPosition(printlog_text, printlog_length);
00432     
00433 #endif /* MOTIF */
00434 }
00435 
00436 void
00437 printlog_append_str(const char *str)
00438 {
00439     printlog_append(str, strlen(str));
00440 }
00441 
00442 /* disable cancel button, enable close button */
00443 void
00444 printlog_enable_closebutton(void)
00445 {
00446     XtSetSensitive(printlog_close, True);
00447     XtSetSensitive(printlog_cancel, False);
00448 #if MOTIF
00449     XmProcessTraversal(printlog_close, XmTRAVERSE_CURRENT);
00450 #endif
00451 }
00452 
00453 static void
00454 printlog_internal_close(void)
00455 {
00456     XtUnmapWidget(printlog_shell);
00457     printlog_active = False;
00458 #ifndef MOTIF
00459     XtVaSetValues(printlog_text, XtNstring, "", NULL);
00460 #else
00461     XmTextSetString(printlog_text, "");
00462 #endif
00463 }
00464 
00465 void
00466 printlog_popdown(Boolean force)
00467 {
00468     if (force) { /* user clicked on `Close' */
00469        printlog_internal_close();
00470     }
00471     else { /* timer elapsed */
00472 #ifndef MOTIF
00473        Boolean state;
00474        XtVaGetValues(printlog_unkeep, XtNstate, &state, NULL);
00475        if (state) {
00476            printlog_internal_close();
00477        }
00478 #else
00479        if (XmToggleButtonGadgetGetState(printlog_unkeep)) {
00480            printlog_internal_close();
00481        }
00482 #endif
00483     }    
00484 }
00485 
00486 
00487 static void
00488 printlog_act_close(Widget w, XEvent *event, String *params, Cardinal *num_params)
00489 {
00490     UNUSED(w);
00491     UNUSED(event);
00492     UNUSED(params);
00493     UNUSED(num_params);
00494 
00495     ASSERT(g_close_callback != NULL, "Callback not initialized");
00496     (g_close_callback)(NULL, NULL, NULL);
00497 }
00498 
00499 static void
00500 printlog_act_keep(Widget w, XEvent *event, String *params, Cardinal *num_params)
00501 {
00502     UNUSED(w);
00503     UNUSED(event);
00504     UNUSED(params);
00505     UNUSED(num_params);
00506 
00507 #ifdef MOTIF
00508     XmToggleButtonGadgetSetState(printlog_unkeep, False, False);
00509 #else
00510     XtVaSetValues(printlog_unkeep, XtNstate, False, NULL);
00511 #endif
00512 }
00513 
00514 
00515 
00516 static void
00517 printlog_act_unkeep(Widget w, XEvent *event, String *params, Cardinal *num_params)
00518 {
00519     UNUSED(w);
00520     UNUSED(event);
00521     UNUSED(params);
00522     UNUSED(num_params);
00523 #ifdef MOTIF
00524     XmToggleButtonGadgetSetState(printlog_unkeep, True, False);
00525 #else
00526     XtVaSetValues(printlog_unkeep, XtNstate, True, NULL);
00527 #endif
00528 }
00529 
00530 static void
00531 printlog_act_cancel(Widget w, XEvent *event, String *params, Cardinal *num_params)
00532 {
00533     UNUSED(w);
00534     UNUSED(event);
00535     UNUSED(params);
00536     UNUSED(num_params);
00537 
00538     ASSERT(g_cancel_callback != NULL, "Callback not initialized");
00539     (g_cancel_callback)(NULL, NULL, NULL);
00540 }
00541 
00542 static void
00543 printlog_act_destroy(Widget w, XEvent *event, String *params, Cardinal *num_params)
00544 {
00545     UNUSED(w);
00546     UNUSED(event);
00547     UNUSED(params);
00548     UNUSED(num_params);
00549 
00550     ASSERT((g_destroy_callback) != NULL, "Callback not initialized");
00551     (g_destroy_callback)(NULL, NULL, NULL);
00552 }