This is ScrollMain.c in view mode; [Download] [Up]
/*
* $RCSfile: ScrollMain.c,v $
*
* Copyright (C) 1992 by Adobe Systems Incorporated.
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software and its
* documentation for any purpose and without fee is hereby granted,
* provided that the above copyright notices appear in all copies and that
* both those copyright notices and this permission notice appear in
* supporting documentation and that the name of Adobe Systems
* Incorporated not be used in advertising or publicity pertaining to
* distribution of the software without specific, written prior
* permission. If any portion of this software is changed, it cannot be
* marketed under Adobe's trademarks and/or copyrights unless Adobe, in
* its sole discretion, approves by a prior writing the quality of the
* resulting implementation.
*
* ADOBE MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THE SOFTWARE FOR
* ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
* ADOBE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR PURPOSE AND
* NON-INFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL ADOBE BE LIABLE
* TO YOU OR ANY OTHER PARTY FOR ANY SPECIAL, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE, STRICT LIABILITY OR ANY OTHER ACTION ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ADOBE WILL NOT
* PROVIDE ANY TRAINING OR OTHER SUPPORT FOR THE SOFTWARE.
*
* PostScript, Display PostScript, and Adobe are trademarks of Adobe Systems
* Incorporated registered in the U.S.A. and other countries.
*
* Author: Adobe Systems Incorporated
*/
#include "Scroll.h"
#include "zoom.xbm"
#include "zoom_mask.xbm"
#include <X11/cursorfont.h>
#include <Xm/FileSB.h>
/***************************************************************
**
** FUNCTION DECLARATIONS
**
***************************************************************/
/***************************************************************
**
** DATA DECLARATIONS
**
***************************************************************/
/*
** Global pointers to the application data block
*/
AppDataType AppData;
/*
** Global resource management data
*/
static MrmHierarchy SMrmHierarchy; /* MRM database hierarchy ID */
static MrmType *DummyClass; /* and class variable. */
static char *DbFilenameVec[] = /* Mrm.heirarchy file list. */
{
"Scrolling.uid"
};
static void initApplication(), mouseDown(), traceProc(), quitProc(),
exposeProc(), selfResizeProc(), autoResizeProc(), redrawProc(),
createProc(), selectProc(), scrollStrategyProc(), zoomProc(),
drawStrategyProc(), clippingProc(), gstateProc(), strokeProc(),
appendProc(), appendProc(), bufferProc();
static MrmRegisterArg RegList [] =
{
{"traceProc" , (caddr_t) traceProc },
{"scrollProc" , (caddr_t) scrollProc },
{"exposeProc" , (caddr_t) exposeProc },
{"resizeProc" , (caddr_t) selfResizeProc },
{"redrawProc" , (caddr_t) redrawProc },
{"scrollStrategyProc" , (caddr_t) scrollStrategyProc },
{"bufferProc" , (caddr_t) bufferProc },
{"zoomProc" , (caddr_t) zoomProc },
{"drawStrategyProc" , (caddr_t) drawStrategyProc },
{"clippingProc" , (caddr_t) clippingProc },
{"gstateProc" , (caddr_t) gstateProc },
{"strokeProc" , (caddr_t) strokeProc },
{"appendProc" , (caddr_t) appendProc },
{"redrawProc" , (caddr_t) redrawProc },
{"selectProc" , (caddr_t) selectProc },
{"quitProc" , (caddr_t) quitProc },
{"createProc" , (caddr_t) createProc },
};
static XrmOptionDescRec CommandLineOptions[] = {
{ "-trace", ".trace", XrmoptionNoArg, (caddr_t)"True",},
};
static XtResource Resources[] = {
{ "trace", "Trace", XtRBoolean, sizeof (Boolean),
XtOffset (AppDataTypePtr, trace), XtRImmediate, (caddr_t) False
},
{ "noAutoPixmapMessage", "NoAutoPixmapMessage", XmRXmString,
sizeof (XmString), XtOffset (AppDataTypePtr, noAutoPixmapMessage),
XtRString, (caddr_t) "Auto scrolling pixmap could not be allocated\n\
Switching to auto-scroll unbuffered."
},
{ "noSelfPixmapMessage", "NoSelfPixmapMessage", XmRXmString,
sizeof (XmString), XtOffset (AppDataTypePtr, noSelfPixmapMessage),
XtRString, (caddr_t) "Self scrolling pixmap could not be allocated\n\
Switching to self-scroll unbuffered."
},
{ "noInputFileMessage", "NoInputFileMessage", XmRXmString,
sizeof (XmString), XtOffset (AppDataTypePtr, noInputFileMessage),
XtRString, (caddr_t) "Could not open file for input"
},
{ "noOutputFileMessage", "NoOutputFileMessage", XmRXmString,
sizeof (XmString), XtOffset (AppDataTypePtr, noOutputFileMessage),
XtRString, (caddr_t) "Could not open file for output"
},
{ "noDistillFileMessage", "NoDistillFileMessage", XmRXmString,
sizeof (XmString), XtOffset (AppDataTypePtr, noDistillFileMessage),
XtRString, (caddr_t) "Could not distillery file for input"
},
{ "noMemoryMessage", "NoMemoryMessage", XmRXmString, sizeof (XmString),
XtOffset (AppDataTypePtr, noMemoryMessage), XtRString,
(caddr_t) "Not enough memory to parse or distill file"
},
{ "badReadMessage", "BadReadMessage", XmRXmString, sizeof (XmString),
XtOffset (AppDataTypePtr, badReadMessage), XtRString,
(caddr_t) "Read error trying to parse file"
},
{ "badWriteMessage", "BadWriteMessage", XmRXmString, sizeof (XmString),
XtOffset (AppDataTypePtr, badWriteMessage), XtRString,
(caddr_t) "Write error trying to distillfile"
},
{ "badFileMessage", "BadFileMessage", XmRXmString, sizeof (XmString),
XtOffset (AppDataTypePtr, badFileMessage), XtRString,
(caddr_t) "File is not a PostScript language file, or\n\
it was not created by the distillery"
},
{ "parserErrorMessage", "ParserErrorMessage", XmRXmString, sizeof (XmString),
XtOffset (AppDataTypePtr, parserErrorMessage), XtRString,
(caddr_t) "Parser error:\n"
},
{ "noDistillContextMessage", "noDistillContextMessage", XmRXmString,
sizeof (XmString), XtOffset (AppDataTypePtr, noDistillContextMessage),
XtRString, (caddr_t) "Could not create context for distillery"
},
{ "distillErrorMessage", "DistillErrorMessage", XmRXmString,
sizeof (XmString), XtOffset (AppDataTypePtr, distillErrorMessage),
XtRString, (caddr_t) "Error prevented file distillation"
},
{ "distillCompleteMessage", "DistillCompleteMessage", XmRXmString,
sizeof (XmString), XtOffset (AppDataTypePtr, distillCompleteMessage),
XtRString, (caddr_t) "File successfull distilled.\n\
Distilled file has extension .dst"
},
{ "pixmapMaxSize", "PixmapMaxSize", XtRInt, sizeof (int),
XtOffset (AppDataTypePtr, pixmapMaxSize), XtRImmediate,
(caddr_t) 2097152 /* Two megabytes */
}
};
static Cursor zoomCursor;
/***************************************************************
**
** FUNCTION: main
**
** DESCRIPTION: OS transfer point. The main routine does all
** the one-time setup and then calls dispatching loop
**
** PARAMETERS: argc command line argument count
** argv array of pointers to command line args.
**
** RETURN: None.
**
***************************************************************/
void main(argc, argv)
unsigned int argc;
char *argv [];
{
XtAppContext appContext;
Widget toplevel;
/*
** Initialize MRM before initializing the X Toolkit.
*/
MrmInitialize ();
/*
** Initialize the X Toolkit. We get back a top level shell widget.
*/
toplevel = XtAppInitialize (
&appContext, "Scrolling", CommandLineOptions,
XtNumber(CommandLineOptions), &argc, argv,
(String) NULL, (ArgList) NULL, 0);
XtGetApplicationResources (
toplevel, (XtPointer) &AppData, Resources,
XtNumber(Resources), (ArgList) NULL, 0
);
if (!XDPSExtensionPresent(XtDisplay(toplevel)))
{
fprintf (stderr, "%s: DPS extension not in server\n", argv[0]);
exit (1);
}
/*
** Open the UID files (the output of the UIL compiler)
*/
if (MrmOpenHierarchy (XtNumber(DbFilenameVec), DbFilenameVec, NULL,
&SMrmHierarchy) != MrmSUCCESS) {
fprintf (stderr, "Can't open heirarchy\n");
exit (1);
}
/*
** Register the items MRM needs to bind for us.
*/
MrmRegisterNames (RegList, XtNumber(RegList));
/*
** Get the main window for the application.
*/
if (MrmFetchWidget (SMrmHierarchy, "ControlDialog", toplevel,
&AppData.mainWindow, &DummyClass) != MrmSUCCESS)
{
fprintf (stderr, "Can't fetch main window\n");
exit (1);
}
/*
** Get the auto drawing widget
*/
if (MrmFetchWidget(SMrmHierarchy, "AutoScroller", AppData.mainWindow,
&AppData.autoScrolling, &DummyClass) != MrmSUCCESS)
{
fprintf(stderr, "Can't fetch auto-scrolling window\n");
exit(1);
}
/*
** Get the auto drawing widget
*/
if (MrmFetchWidget(SMrmHierarchy, "SelfScroller", AppData.mainWindow,
&AppData.selfScrolling, &DummyClass) != MrmSUCCESS)
{
fprintf(stderr, "Can't fetch self-scrolling window\n");
exit(1);
}
/*
** Manage the option box and realize everything.
** The interface comes up on the display now.
*/
XtManageChild(AppData.mainWindow);
XtVaSetValues(
toplevel,
XmNmwmFunctions,
MWM_FUNC_ALL | MWM_FUNC_RESIZE | MWM_FUNC_MAXIMIZE | MWM_FUNC_CLOSE,
XmNmwmDecorations,
MWM_DECOR_ALL | MWM_DECOR_MAXIMIZE | MWM_DECOR_RESIZEH,
NULL
);
XtRealizeWidget(toplevel);
initApplication();
initDPSContext ();
/*
** Sit around forever waiting to process X-events.
** From here on, we only execute our callback routines.
*/
while (1) {
XEvent event;
XtAppNextEvent(appContext, &event);
if (!XDPSDispatchEvent(&event)) (void) XtDispatchEvent(&event);
}
} /* end main () */
/***************************************************************
**
** PRIVATE FUNCTIONS
**
***************************************************************/
/***************************************************************
**
** FUNCTION: initApplication
**
** DESCRIPTION: One-time initialization of GlobalData struct
**
** PARAMETERS: None.
**
** RETURN: None.
**
***************************************************************/
static void initApplication()
{
Display *dpy = XtDisplay(AppData.time);
Window win = XtWindow(AppData.time);
XGCValues values;
Pixmap cursor, mask;
XColor fore, back;
/*
** Initialize the non-zero application control values
*/
AppData.magnify = 100.0;
AppData.scale = 1.0;
AppData.scrollStrategy = scroll_background;
AppData.showDrawing = False;
AppData.drawStrategy = draw_userpaths;
AppData.clientClipping = True;
AppData.optimizeChanges = True;
AppData.wireFrame = False;
AppData.consolidate = True;
/*
** Create a GC for copying
*/
AppData.gc = XCreateGC(dpy, win, 0, &values);
/*
** Create a zoom cursor
*/
cursor = XCreateBitmapFromData(dpy, win, zoom_bits,
zoom_width, zoom_height);
mask = XCreateBitmapFromData(dpy, win, zoom_mask_bits,
zoom_mask_width, zoom_mask_height);
if (cursor != None && mask != None) {
fore.red = fore.green = fore.blue = 0;
back.red = back.green = back.blue = 65535;
fore.flags = back.flags = DoRed | DoGreen | DoBlue;
zoomCursor = XCreatePixmapCursor(dpy, cursor, mask, &fore, &back,
zoom_x_hot, zoom_y_hot);
XFreePixmap(dpy, cursor);
XFreePixmap(dpy, mask);
} else zoomCursor = None;
/*
** Create wait cursor
*/
AppData.waitCursor = XCreateFontCursor(dpy, XC_watch);
} /* end initApplication() */
/***************************************************************
**
** FUNCTION: createProc
**
** DESCRIPTION: Callback routine for widget creation.
**
** PARAMETERS: w callback widget ID
** clientData callback client data
** callData callback Motif data structure
**
** RETURN: None.
**
***************************************************************/
static void createProc (w, clientData, callData)
Widget w;
XtPointer clientData, callData;
{
int widgetNum = *((int *) clientData);
/*
** Save widget ID in application data structure; sometimes do more...
*/
switch (widgetNum) {
case cSelfDrawArea:
AppData.selfDrawingArea = w;
/*
** Add event handlers to handle mouse press and GraphicsExpose
*/
XtAddEventHandler(w, ButtonPressMask, False, mouseDown, NULL);
XtAddRawEventHandler(w, 0, True, graphicsExpose, NULL);
break;
case cAutoDrawArea:
AppData.autoDrawingArea = w;
/*
** Add event handler to handle mouse press to parent (clip window)
*/
XtAddEventHandler(w, ButtonPressMask, False,
mouseDown, NULL);
/*
** Add resize callback to parent (the clip window)
*/
XtAddCallback(XtParent(w), XmNresizeCallback,
autoResizeProc, (XtPointer) NULL);
break;
case cTraceToggle:
if (AppData.trace) XtVaSetValues(w, XmNset, True, NULL);
break;
case cAutoScrollWin:
/*
** Find out the horizontal and vertical scroll bar id's
*/
XtVaGetValues(w,
XmNhorizontalScrollBar, &AppData.autoHScroll,
XmNverticalScrollBar, &AppData.autoVScroll, NULL);
break;
case cSelfHsb: AppData.selfHScroll = w; break;
case cSelfVsb: AppData.selfVScroll = w; break;
case cTimingText: AppData.time = w; break;
case cBackgroundToggle: AppData.currentStrategy = w; break;
case cAutoRedrawToggle: AppData.autoRedraw = w; break;
case cSelfRedrawToggle: AppData.selfRedraw = w; break;
case cWatchFrame: AppData.watchFrame = w; break;
}
} /* end createProc () */
/***************************************************************
**
** FUNCTION: traceProc
**
** DESCRIPTION: Callback routine for TraceToggle manipulation.
**
** PARAMETERS: w callback widget ID
** clientData callback client data
** callData callback Motif data structure
**
** RETURN: None.
**
***************************************************************/
static void traceProc (w, clientData, callData)
Widget w;
XtPointer clientData, callData;
{
XmToggleButtonCallbackStruct *toggle =
(XmToggleButtonCallbackStruct *) callData;
XDPSChainTextContext (AppData.dpsCtxt, toggle->set);
} /* end traceProc () */
/***************************************************************
**
** FUNCTION: selfResizeProc
**
** DESCRIPTION: Callback routine to handle resize events on the
** self-scrolling drawing window
**
** PARAMETERS: w callback widget ID
** clientData callback client data
** callData callback Motif data structure
**
** RETURN: None.
**
***************************************************************/
static void selfResizeProc (w, clientData, callData)
Widget w;
XtPointer clientData, callData;
{
XPoint xpoint;
Point point;
if (!XtIsRealized(w)) return;
/*
** Convert upper left corner into PS units so we can keep it fixed
*/
xpoint.x = 0;
xpoint.y = 0;
convertToDPS(&xpoint, &point);
/*
** Get new size of drawing area
*/
XtVaGetValues(w, XtNheight, &AppData.drawingHeight,
XtNwidth, &AppData.drawingWidth, NULL);
/*
** Move the drawing area so the top left corner
** of the image remains located at the top left corner
*/
setupAndDraw(False, point.x, point.y, xpoint.x, xpoint.y);
} /* end of selfResizeProc () */
/***************************************************************
**
** FUNCTION: autoResizeProc
**
** DESCRIPTION: Callback routine to handle resize events on the
** auto-scrolling clip window
**
** PARAMETERS: w callback widget ID
** clientData callback client data
** callData callback Motif data structure
**
** RETURN: None.
**
***************************************************************/
static void autoResizeProc(w, clientData, callData)
Widget w;
XtPointer clientData, callData;
{
XPoint xpoint;
Point point;
Position x, y;
Boolean setup;
if (!XtIsRealized(w)) return;
/*
** Convert upper left corner into PS units so we can keep it fixed
*/
XtVaGetValues(AppData.autoDrawingArea, XtNx, &x, XtNy, &y, NULL);
xpoint.x = -x;
xpoint.y = -y;
convertToDPS(&xpoint, &point);
/*
** We have to redraw if the old or new window size is larger than the
** scaled size; this means that we're showing some gray background
** and have to recenter
*/
setup = AppData.drawingHeight > AppData.scaledHeight ||
AppData.drawingWidth > AppData.scaledWidth;
/*
** Get new size of drawing area
*/
XtVaGetValues(w, XtNheight, &AppData.drawingHeight,
XtNwidth, &AppData.drawingWidth, NULL);
setup = setup || AppData.drawingHeight > AppData.scaledHeight ||
AppData.drawingWidth > AppData.scaledWidth;
/*
** Make the window size match the scaled size
*/
setWindowSize(AppData.scaledWidth, AppData.scaledHeight);
/*
** Move the drawing area so the top left corner
** of the image remains located at the top left corner
*/
if (setup) setupAndDraw(False, point.x, point.y, 0, 0);
} /* end of autoResizeProc () */
/***************************************************************
**
** FUNCTION: addExposureToBBox
**
** DESCRIPTION: Adds the exposed rectangle from the expose event
** to the bbox list
**
** PARAMETERS: bbox pointer to bbox data list
** len pointer to total number of entries in bbox list
** count pointer to current number of entries in bbox list
** e pointer to expose event
**
** RETURN: None. (bbox, count, and len are updated)
**
***************************************************************/
void addExposureToBBox(box, len, count, e)
int **box;
int *len, *count;
XExposeEvent *e;
{
/*
** Grow bounding box list if necessary
*/
if (*count + 4 > *len) {
*box = (int *) XtRealloc((XtPointer) *box, (*len + 12) * sizeof(int));
*len += 12;
}
/*
** Store rectangle in list
*/
(*box)[(*count)++] = e->x;
(*box)[(*count)++] = e->y + e->height;
(*box)[(*count)++] = e->width;
(*box)[(*count)++] = e->height;
}
/***************************************************************
**
** FUNCTION: checkExposeEvent
**
** DESCRIPTION: Utility procedure for XCheckEvent to see of there
** are any more expose events for the window. This always
** returns False, since we don't actually want to remove the
** event from the queue; the answer is returned in the "found"
** parameter of CheckData.
**
** PARAMETERS: dpy Display pointer
** e Event pointer
** arg Pointer to CheckData structure
**
** RETURN: Always False
**
***************************************************************/
typedef struct {
Window w;
Boolean found;
} CheckData;
static Bool checkExposeEvent(dpy, e, arg)
Display *dpy;
XEvent *e;
char *arg;
{
CheckData *d = (CheckData *) arg;
if (!d->found && e->type == Expose &&
d->w == e->xany.window) d->found = True;
return False;
}
/***************************************************************
**
** FUNCTION: exposeProc
**
** DESCRIPTION: Callback routine to handle expose events on the
** main graphics display.
**
** PARAMETERS: w callback widget ID
** clientData callback client data
** callData callback Motif data structure
**
** RETURN: None.
**
***************************************************************/
static void exposeProc (w, clientData, callData)
Widget w;
XtPointer clientData, callData;
{
XmDrawingAreaCallbackStruct *callback =
(XmDrawingAreaCallbackStruct *) callData;
XExposeEvent *e = &callback->event->xexpose;
static int *bboxList = NULL;
static int bboxLen = 0, bboxCount = 0;
XEvent event;
Display *dpy = XtDisplay(w);
CheckData cd;
/*
** If we are in the midst of scrolling, the exposed area must be offset
** by the most recent scroll
*/
if (AppData.scrolling) {
e->x -= AppData.lastXdelta;
e->y -= AppData.lastYdelta;
}
switch (AppData.scrollStrategy) {
/*
** If using window background, nothing to do
*/
case scroll_background:
break;
/*
** If using a buffered window, copy the exposed area from the buffer
*/
case scroll_auto_buffer:
case scroll_self_buffer:
XCopyArea(dpy, AppData.buf, XtWindow(w), AppData.gc,
e->x, e->y, e->width, e->height, e->x, e->y);
break;
/*
** If using a redraw window, add the exposure to the list of
** bounding boxes. If there are no more expose
** events, set the view clip to the bounding box list and redraw
*/
case scroll_auto_redraw:
case scroll_self_redraw:
addExposureToBBox(&bboxList, &bboxLen, &bboxCount, e);
if (e->count == 0) {
/*
** Check the event queue for more expose events; if there
** are any don't redraw just yet
*/
if (XPending(dpy) > 0) {
cd.w = XtWindow(w);
cd.found = False;
(void) XCheckIfEvent(dpy, &event, checkExposeEvent,
(char *) &cd);
if (cd.found) return;
}
drawSelf(bboxList, bboxCount/4);
bboxCount = 0;
}
break;
}
} /* end of exposeProc () */
/***************************************************************
**
** FUNCTION: cancelFileCallback
**
** DESCRIPTION: Unmanages file dialog when cancelled
**
** PARAMETERS: w callback widget ID
** clientData callback client data
** callData callback Motif data structure
**
** RETURN: None.
**
***************************************************************/
static void cancelFileCallback(w, clientData, callData)
Widget w;
XtPointer clientData, callData;
{
XtUnmanageChild(AppData.fileDialog);
}
/***************************************************************
**
** FUNCTION: makeNormalString
**
** DESCRIPTION: Extracts a normal string from a compound string.
** Caller should free string with XtFree
**
** PARAMETERS: xmstring compound string
**
** RETURN: The normal string
**
***************************************************************/
static char *makeNormalString(xmstring)
XmString xmstring;
{
String answer;
answer = (String) XtMalloc(XmStringLength (xmstring) + 1);
XmStringGetLtoR(xmstring, XmSTRING_DEFAULT_CHARSET, &answer);
return answer;
}
/***************************************************************
**
** FUNCTION: setWaitCursor
**
** DESCRIPTION: Puts up the wait cursor in the main window and, if mapped,
** the current display window
**
** PARAMETERS: None.
**
** RETURN: None.
**
***************************************************************/
void setWaitCursor()
{
if (AppData.waitCursor != None) {
if (AppData.currentDraw != NULL) {
XDefineCursor(XtDisplay(AppData.currentDraw),
XtWindow(AppData.currentDraw), AppData.waitCursor);
}
XDefineCursor(XtDisplay(AppData.mainWindow),
XtWindow(AppData.mainWindow), AppData.waitCursor);
/*
** Flush connection to make cursor change happen
*/
XFlush(XtDisplay(AppData.mainWindow));
}
}
/***************************************************************
**
** FUNCTION: clearWaitCursor
**
** DESCRIPTION: Takes down the wait cursor
**
** PARAMETERS: None.
**
** RETURN: None.
**
***************************************************************/
void clearWaitCursor()
{
if (AppData.waitCursor != None) {
if (AppData.currentDraw != NULL) {
XUndefineCursor(XtDisplay(AppData.currentDraw),
XtWindow(AppData.currentDraw));
}
XUndefineCursor(XtDisplay(AppData.mainWindow),
XtWindow(AppData.mainWindow));
/*
** Flush connection to make cursor change happen
*/
XFlush(XtDisplay(AppData.mainWindow));
}
}
/***************************************************************
**
** FUNCTION: openFileCallback
**
** DESCRIPTION: Callback procedure to open a file for input or
** distillation
**
** PARAMETERS: w callback widget ID
** clientData callback client data
** callData callback Motif data structure
**
** RETURN: None.
**
***************************************************************/
static void openFileCallback(w, clientData, callData)
Widget w;
XtPointer clientData, callData;
{
XmFileSelectionBoxCallbackStruct *fdata =
(XmFileSelectionBoxCallbackStruct *) callData;
FILE *f;
String str = makeNormalString(fdata->value);
Action *action = (Action *) clientData;
Boolean success;
/*
** Open the selected filename for read, then unmanage the file dialog
*/
f = fopen(str, "r");
if (f == NULL) {
putUpInfoDialog(AppData.noInputFileMessage);
XtFree(str);
return;
}
XtUnmanageChild(AppData.fileDialog);
/*
** If loading a file, try to parse, and if successful redraw. If this
** is the first time, pass True for the center parameter so that the
** picture is centered. If this isn't the first time, call
** setupAndDrawUnmoving so the current position is maintained.
*/
if (*action == action_load) {
setWaitCursor();
success = parseFile(f);
clearWaitCursor();
XtFree(str);
fclose(f);
if (success) {
if (AppData.currentDraw == NULL) {
setupAndDraw(True, 0.0, 0.0, 0, 0);
} else setupAndDrawUnmoving();
}
} else { /* distilling the file */
setWaitCursor();
distillFile(f, str);
clearWaitCursor();
XtFree(str);
fclose(f);
}
}
/***************************************************************
**
** FUNCTION: selectProc
**
** DESCRIPTION: Callback for the Open and Distill buttons; creates
** and manages the file selection dialog
**
** PARAMETERS: w callback widget ID
** clientData callback client data
** callData callback Motif data structure
**
** RETURN: None.
**
***************************************************************/
static void selectProc (w, clientData, callData)
Widget w;
XtPointer clientData, callData;
{
static XmString eps, dst;
static Action action;
action = *((Action *)clientData);
/*
** If there is no file dialog, create one and unmanage the help button
*/
if (AppData.fileDialog == NULL) {
AppData.fileDialog =
XmCreateFileSelectionDialog(AppData.time, "fileDialog",
(ArgList) NULL, 0);
w = XmFileSelectionBoxGetChild(AppData.fileDialog,
XmDIALOG_HELP_BUTTON);
XtUnmanageChild(w);
XtAddCallback(AppData.fileDialog, XmNcancelCallback,
cancelFileCallback, (XtPointer) NULL);
XtAddCallback(AppData.fileDialog, XmNokCallback,
openFileCallback, (XtPointer) &action);
/*
** Create compound strings for the extensions
*/
eps = XmStringCreate("*.eps", XmSTRING_DEFAULT_CHARSET);
dst = XmStringCreate("*.dst", XmSTRING_DEFAULT_CHARSET);
}
/*
** Set the appropriate file extension and manage the file dialog.
** The file dialog callback will do the real work.
*/
if (action == action_load) {
XtVaSetValues(AppData.fileDialog, XmNpattern, dst, NULL);
} else { /* action_distill */
XtVaSetValues(AppData.fileDialog, XmNpattern, eps, NULL);
}
XtManageChild(AppData.fileDialog);
} /* end of selectProc () */
/***************************************************************
**
** FUNCTION: quitProc
**
** DESCRIPTION: Callback routine for "quit" command menu
** selection. Exits from the application.
**
** PARAMETERS: w callback widget ID
** clientData callback client data
** callData callback Motif data structure
**
** RETURN: None; terminates process.
**
***************************************************************/
static void quitProc (w, clientData, callData)
Widget w;
XtPointer clientData, callData;
{
XtDestroyApplicationContext(XtWidgetToApplicationContext(w));
exit(0);
} /* end quitProc () */
/***************************************************************
**
** FUNCTION: scrollStrategyProc
**
** DESCRIPTION: Callback for scroll strategy buttons on ctrl panel.
**
** PARAMETERS: w callback widget ID
** clientData callback client data
** callData callback Motif data structure
**
** RETURN: None.
**
***************************************************************/
static void scrollStrategyProc (w, clientData, callData)
Widget w;
XtPointer clientData;
XtPointer callData;
{
int val = *((int *) clientData);
XmToggleButtonCallbackStruct *toggle =
(XmToggleButtonCallbackStruct *) callData;
/*
** Ignore callbacks from button unsets
*/
if (!toggle->set || val == (int) AppData.scrollStrategy) return;
/*
** If changing away from background scrolling, reset the window
** background to be white
*/
if (AppData.scrollStrategy == scroll_background &&
AppData.currentDraw != NULL) {
XSetWindowBackground(XtDisplay(w), XtWindow(AppData.currentDraw),
WhitePixelOfScreen(XtScreen(w)));
}
/*
** If selecting a redraw method, make watch progress box insensitive
*/
if (val & SCROLL_REDRAW) {
XtSetSensitive(AppData.watchFrame, False);
} else XtSetSensitive(AppData.watchFrame, True);
/*
** Update the global data flag
*/
AppData.scrollStrategy = val;
AppData.currentStrategy = w;
if (AppData.currentDraw != NULL) setupAndDrawUnmoving();
} /* end scrollStrategyProc () */
/***************************************************************
**
** FUNCTION: zoomProc
**
** DESCRIPTION: Callback for zoom toggle buttons on ctrl panel.
**
** PARAMETERS: w callback widget ID
** clientData callback client data
** callData callback Motif data structure
**
** RETURN: None.
**
***************************************************************/
static void zoomProc (w, clientData, callData)
Widget w;
XtPointer clientData, callData;
{
int num = *(int *) clientData;
XmToggleButtonCallbackStruct *toggle =
(XmToggleButtonCallbackStruct *) callData;
/*
** Change the selected radio button if toggle state is set
*/
if (toggle->set && AppData.magnify != num) {
AppData.magnify = num;
if (AppData.currentDraw == NULL) {
/*
** No current drawing, but compute new scale and size
** for when we decide to draw
*/
AppData.scale = (float) num / 100.0;
AppData.scaledWidth = PAGE_WIDTH * AppData.origXScale *
AppData.scale;
AppData.scaledHeight = PAGE_HEIGHT * AppData.origYScale *
AppData.scale;
} else {
/*
** Set zooming flag and cursor. Actual work takes place
** in mouse event handler when the user clicks
*/
AppData.zooming = True;
if (zoomCursor != None) {
XDefineCursor(XtDisplay(AppData.currentDraw),
XtWindow(AppData.currentDraw), zoomCursor);
}
}
}
} /* end of zoomProc () */
/***************************************************************
**
** FUNCTION: flushAndClear
**
** DESCRIPTION: Deletes all expose events for the window, then clears it
**
** PARAMETERS: w widget to flush and clear
**
** RETURN: None.
**
***************************************************************/
void flushAndClear(w)
Widget w;
{
XEvent e;
/*
** Make sure everything is here that's a'comin'
*/
XSync(XtDisplay(w), False);
/*
** Check for Expose events and remove them from the queue
*/
while (XCheckTypedWindowEvent(XtDisplay(w), XtWindow(w), Expose, &e)) {}
/*
** Clear the window, generating expose events for the visible areas
*/
XClearArea(XtDisplay(w), XtWindow(w), 0, 0, 0, 0, True);
}
/***************************************************************
**
** FUNCTION: forceRedraw
**
** DESCRIPTION: Forces a redraw of the picture
**
** PARAMETERS: None
**
** RETURN: None.
**
***************************************************************/
static void forceRedraw()
{
int area[4];
Widget w = AppData.currentDraw;
switch (AppData.scrollStrategy) {
/*
** Auto-scrolling buffered methods have the entire page as
** a clipping area. Redraw.
*/
case scroll_background:
case scroll_auto_buffer:
area[0] = 0;
area[1] = AppData.pixmapHeight;
area[2] = AppData.pixmapWidth;
area[3] = AppData.pixmapHeight;
drawSelf(area, 1);
/*
** If using background, install it. Otherwise clear the window;
** the expose event will cause a copy from the buffer
*/
if (AppData.scrollStrategy == scroll_background) {
XSetWindowBackgroundPixmap(XtDisplay(w), XtWindow(w),
AppData.buf);
XClearWindow(XtDisplay(w), XtWindow(w));
} else if (!AppData.showDrawing) flushAndClear(w);
break;
/*
** Self-scrolling buffered requires finding the bounding box
** of the actual buffer area
*/
case scroll_self_buffer:
area[0] = 0;
area[1] = AppData.drawingHeight;
area[2] = AppData.drawingWidth;
area[3] = AppData.drawingHeight;
drawSelf(area, 1);
/*
** Clear drawing window to force copy from redrawn pixmap
*/
if (!AppData.showDrawing) flushAndClear(w);
break;
/*
** If redrawing, just clear and wait for expose events
*/
case scroll_auto_redraw:
case scroll_self_redraw:
flushAndClear(w);
break;
}
}
/***************************************************************
**
** FUNCTION: drawStrategyProc
**
** DESCRIPTION: Callback for draw strategy toggle buttons on ctrl panel.
**
** PARAMETERS: w callback widget ID
** clientData callback client data
** callData callback Motif data structure
**
** RETURN: None.
**
***************************************************************/
static void drawStrategyProc (w, clientData, callData)
Widget w;
XtPointer clientData, callData;
{
int val = *((int *) clientData);
XmToggleButtonCallbackStruct *toggle =
(XmToggleButtonCallbackStruct *) callData;
/*
** Ignore callbacks from button unsets
*/
if (!toggle->set || val == (int) AppData.drawStrategy) return;
/*
** Update the global flag
*/
AppData.drawStrategy = val;
if (AppData.currentDraw != NULL) forceRedraw();
} /* end drawStrategyProc () */
/***************************************************************
**
** FUNCTION: clippingProc
**
** DESCRIPTION: Callback for bounds toggle buttons on ctrl panel.
**
** PARAMETERS: w callback widget ID
** clientData callback client data
** callData callback Motif data structure
**
** RETURN: None.
**
***************************************************************/
static void clippingProc (w, clientData, callData)
Widget w;
XtPointer clientData, callData;
{
int val = *((int *) clientData);
XmToggleButtonCallbackStruct *toggle =
(XmToggleButtonCallbackStruct *) callData;
/*
** Ignore callbacks from button unsets
*/
if (!toggle->set || val == AppData.clientClipping) return;
/*
** Update the global flag
*/
AppData.clientClipping = val;
if (AppData.currentDraw != NULL) forceRedraw();
} /* end of clippingProc () */
/***************************************************************
**
** FUNCTION: bufferProc
**
** DESCRIPTION: Callback for show progress buttons on ctrl panel.
**
** PARAMETERS: w callback widget ID
** clientData callback client data
** callData callback Motif data structure
**
** RETURN: None.
**
***************************************************************/
static void bufferProc (w, clientData, callData)
Widget w;
XtPointer clientData, callData;
{
int val = *((int *) clientData);
XmToggleButtonCallbackStruct *toggle =
(XmToggleButtonCallbackStruct *) callData;
/*
** Ignore callbacks from button unsets
*/
if (!toggle->set || val == AppData.showDrawing) return;
/*
** Update the global flag
*/
AppData.showDrawing = val;
if (AppData.currentDraw != NULL) setupAndDrawUnmoving();
} /* end of bufferProc () */
/***************************************************************
**
** FUNCTION: gstateProc
**
** DESCRIPTION: Callback for gstate toggle buttons on ctrl panel.
**
** PARAMETERS: w callback widget ID
** clientData callback client data
** callData callback Motif data structure
**
** RETURN: None.
**
***************************************************************/
static void gstateProc (w, clientData, callData)
Widget w;
XtPointer clientData, callData;
{
int val = *((int *) clientData);
XmToggleButtonCallbackStruct *toggle =
(XmToggleButtonCallbackStruct *) callData;
/*
** Ignore callbacks from button unsets
*/
if (!toggle->set || val == AppData.optimizeChanges) return;
/*
** Update the global flag
*/
AppData.optimizeChanges = val;
if (AppData.currentDraw != NULL) forceRedraw();
} /* end gstateProc () */
/***************************************************************
**
** FUNCTION: strokeProc
**
** DESCRIPTION: Callback for stroke toggle buttons on ctrl panel.
**
** PARAMETERS: w callback widget ID
** clientData callback client data
** callData callback Motif data structure
**
** RETURN: None.
**
***************************************************************/
static void strokeProc (w, clientData, callData)
Widget w;
XtPointer clientData, callData;
{
int val = *((int *) clientData);
XmToggleButtonCallbackStruct *toggle =
(XmToggleButtonCallbackStruct *) callData;
/*
** Ignore callbacks from button unsets
*/
if (!toggle->set || val == AppData.wireFrame) return;
/*
** Update the global flag
*/
AppData.wireFrame = val;
if (AppData.currentDraw != NULL) forceRedraw();
} /* end strokeProc () */
/***************************************************************
**
** FUNCTION: appendProc
**
** DESCRIPTION: Callback for append toggle buttons on ctrl panel.
**
** PARAMETERS: w callback widget ID
** clientData callback client data
** callData callback Motif data structure
**
** RETURN: None.
**
***************************************************************/
static void appendProc (w, clientData, callData)
Widget w;
XtPointer clientData, callData;
{
int val = *((int *) clientData);
XmToggleButtonCallbackStruct *toggle =
(XmToggleButtonCallbackStruct *) callData;
/*
** Ignore callbacks from button unsets
*/
if (!toggle->set || val == AppData.consolidate) return;
/*
** Update the global flag
*/
AppData.consolidate = val;
if (AppData.currentDraw != NULL) forceRedraw();
} /* end appendProc () */
/***************************************************************
**
** FUNCTION: mouseDown
**
** DESCRIPTION: This function acts as the event handler for the
** ButtonDown event. If the magnification is being
** changed (zooming), then scale and position the
** drawing view.
**
** PARAMETERS: w window widget
** clientData clientdata
** event event information
** goOn continue to dispatch
**
** RETURN: None
**
***************************************************************/
static void mouseDown(w, clientData, event, goOn)
Widget w;
XtPointer clientData;
XEvent *event;
Boolean *goOn;
{
XPoint xpoint;
Point point;
XButtonPressedEvent *bp = (XButtonPressedEvent *) event;
Position x, y;
if (event->xany.window != XtWindow(AppData.currentDraw)) return;
/*
** If zooming, rescale so clicked-on point remains fixed
*/
if (AppData.zooming) {
/*
** Convert point to PS units and scale
*/
xpoint.x = bp->x;
xpoint.y = bp->y;
convertToDPS(&xpoint, &point);
/*
** If auto-drawing, find out how where the drawing window is
** compared to the clip window, and add the position to find
** the mouse coordinates in the clip window
*/
if (AppData.scrollStrategy & SCROLL_AUTO) {
XtVaGetValues(AppData.autoDrawingArea, XtNx, &x, XtNy, &y, NULL);
xpoint.x += x;
xpoint.y += y;
}
scaleDrawingArea();
setupAndDraw(False, point.x, point.y, xpoint.x, xpoint.y);
AppData.zooming = False;
if (zoomCursor != None) {
XUndefineCursor(XtDisplay(w), XtWindow(w));
}
}
} /* end mouseDown() */
/***************************************************************
**
** FUNCTION: redrawProc
**
** DESCRIPTION: Callback routine for redraw button pushed.
** Redraws the patterns and displays the time.
**
** PARAMETERS: w callback widget ID
** clientData callback client data
** callData callback Motif data structure
**
** RETURN: None.
**
***************************************************************/
static void redrawProc (w, clientData, callData)
Widget w;
XtPointer clientData, callData;
{
forceRedraw();
} /* end redrawProc () */
/***************************************************************
**
** FUNCTION: putUpInfoDialog
**
** DESCRIPTION: Creates and manages the information dialog with
** the specified compound string as the message
**
** PARAMETERS: message String to display
**
** RETURN: None.
**
***************************************************************/
void putUpInfoDialog(message)
XmString message;
{
Widget w;
static Widget infoDialog;
/*
** If this is the first time, create the info dialog
*/
if (infoDialog == NULL) {
infoDialog =
XmCreateInformationDialog(AppData.time, "infoDialog",
(ArgList) NULL, 0);
XtVaSetValues(infoDialog,
XmNdialogStyle, XmDIALOG_APPLICATION_MODAL, NULL);
w = XmMessageBoxGetChild(infoDialog, XmDIALOG_CANCEL_BUTTON);
XtUnmanageChild(w);
w = XmMessageBoxGetChild(infoDialog, XmDIALOG_HELP_BUTTON);
XtUnmanageChild(w);
}
/*
** Set the message and pop it up
*/
XtVaSetValues(infoDialog, XmNmessageString, message, NULL);
XtManageChild(infoDialog);
} /* end putUpInfoDialog() */
/***************************************************************
**
** FUNCTION: showTime
**
** DESCRIPTION: Routine to set timing value in options box.
**
** PARAMETERS: iTime timing value
**
** RETURN: None.
**
***************************************************************/
void showTime(iTime)
int iTime;
{
char cTime [15];
if (iTime == 0) strcpy (cTime, " ");
else sprintf (cTime, "%d", iTime);
XtVaSetValues (AppData.time,
XmNlabelString, XmStringCreateSimple(cTime), NULL);
} /* end setTimingValue () */
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.