This is ImportMain.c in view mode; [Download] [Up]
/* * $RCSfile: ImportMain.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 */ /*************************************************************** ** ** INCLUDES ** ***************************************************************/ #include "Import.h" #include <X11/cursorfont.h> #include <sys/stat.h> #include <X11/Xatom.h> /*************************************************************** ** ** DATA DECLARATIONS ** ***************************************************************/ /* ** Global pointers to the application data block */ AppDataType AppData; /* ** Global resource management data */ MrmHierarchy SMrmHierarchy; /* MRM database hierarchy ID */ static MrmType *DummyClass; /* and class variable. */ static char *DbFilenameVec [] = /* Mrm.heirarchy file list. */ { "Import.uid" }; static void resizeWindow(), refreshWindow(), createProc(), quitApp(), traceProc(), showBufferProc(), bufferExposeProc(), initApplication(), mouseDown(), fileProc(), cutProc(), copyProc(), pasteProc(), deleteProc(), rotateProc(), scaleProc(), frontProc(), backProc(), origSizeProc(), origRatioProc(), useBoxProc(), setPreview(); /* Names and addresses for Mrm to bind */ static MrmRegisterArg RegList [] = { {"resizeWindow" , (XtPointer) resizeWindow }, {"refreshWindow" , (XtPointer) refreshWindow }, {"graphicExpose" , (XtPointer) graphicExpose }, {"createProc" , (XtPointer) createProc }, {"quitApp" , (XtPointer) quitApp }, {"scrollProc" , (XtPointer) scrollProc }, {"traceProc" , (XtPointer) traceProc }, {"showBufferProc" , (XtPointer) showBufferProc }, {"bufferExposeProc", (XtPointer) bufferExposeProc}, {"fileProc" , (XtPointer) fileProc }, {"cutProc" , (XtPointer) cutProc }, {"copyProc" , (XtPointer) copyProc }, {"pasteProc" , (XtPointer) pasteProc }, {"deleteProc" , (XtPointer) deleteProc }, {"rotateProc" , (XtPointer) rotateProc }, {"scaleProc" , (XtPointer) scaleProc }, {"frontProc" , (XtPointer) frontProc }, {"backProc" , (XtPointer) backProc }, {"origSizeProc" , (XtPointer) origSizeProc }, {"origRatioProc" , (XtPointer) origRatioProc }, {"useBoxProc" , (XtPointer) useBoxProc }, {"setPreview" , (XtPointer) setPreview } }; static XrmOptionDescRec CommandLineOptions[] = { { "-trace", ".trace", XrmoptionNoArg, (caddr_t) "True",}, }; static XtResource Resources[] = { { "trace", "Trace", XtRBoolean, sizeof (Boolean), XtOffset (AppDataTypePtr, trace), XtRImmediate, (caddr_t) False }, { "pixmapMaxSize", "PixmapMaxSize", XtRInt, sizeof (int), XtOffset (AppDataTypePtr, pixmapMaxSize), XtRImmediate, (caddr_t) 2097152 /* Two megabytes */ } }; static Atom XA_CLIPBOARD, XA_TARGETS, XA_ADOBE_EPS, XA_ADOBE_EPSI, XA_FILE_NAME; /*************************************************************** ** ** FUNCTION: main ** ** DESCRIPTION: Main procedure for the Import Application. ** This procedure sets up the X Window environment ** and then enters event dispatching loop. ** ** PARAMETERS: argc argument count of command line call ** argv array of command line arguments ** ** RETURN: N/A ** ***************************************************************/ main(argc, argv) int argc; char *argv[]; { XtAppContext appContext; Widget toplevel; Widget mainWindow; /* ** Initialize MRM before initializing the X Toolkit. */ MrmInitialize(); /* ** Initialize the X Toolkit. We get back a top level shell widget. */ toplevel = XtAppInitialize ( &appContext, "Import", CommandLineOptions, XtNumber(CommandLineOptions), &argc, argv, (String) NULL, (ArgList) NULL, 0); XtGetApplicationResources ( toplevel, (XtPointer) &AppData, (XtResourceList) 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, "MainWindow", toplevel, &mainWindow, &DummyClass) != MrmSUCCESS) { fprintf (stderr, "Can't fetch main window\n"); exit (0); } /* ** Get the show buffer box widget */ if (MrmFetchWidget(SMrmHierarchy, "BufferBox", mainWindow, &AppData.bufferBox, &DummyClass) != MrmSUCCESS) { fprintf(stderr, "Can't fetch show buffer window\n"); exit(0); } /* ** Manage the main window and option box and realize everything. ** The interface comes up on the display now. */ XtManageChild(mainWindow); XtRealizeWidget(toplevel); /* Perform onetime initialization of application data structures */ initApplication(); /* ** Do all the post-realization DPS/X processing here */ 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() */ /*************************************************************** ** ** FUNCTION: initApplication ** ** DESCRIPTION: One-time initialization of application data ** structures. ** ** PARAMETERS: None. ** ** RETURN: None. ** ***************************************************************/ static void initApplication() { XGCValues values; Display *dpy = XtDisplay(AppData.drawingArea); Window win = XtWindow(AppData.drawingArea); Pixmap p; /* ** Initialize the booleans */ AppData.showBuffer = False; AppData.scrolling = False; AppData.includePreview = True; AppData.deepPreview = False; AppData.moveElement = NULL; /* ** Create GCs */ values.foreground = WhitePixelOfScreen(XtScreen(AppData.drawingArea)); AppData.gc = XCreateGC(dpy, win, GCForeground, &values); values.foreground = BlackPixelOfScreen(XtScreen(AppData.drawingArea)); AppData.blackgc = XCreateGC(dpy, win, GCForeground, &values); p = XCreatePixmap(dpy, win, 1, 1, 1); values.foreground = 0; AppData.bitmapgc = XCreateGC(dpy, p, GCForeground, &values); XFreePixmap(dpy, p); /* ** Find depth of drawing area */ XtVaGetValues(AppData.drawingArea, XtNdepth, &AppData.depth, NULL); /* ** Create cursors */ AppData.crosshairCursor = XCreateFontCursor(dpy, XC_crosshair); AppData.busyCursor = XCreateFontCursor(dpy, XC_watch); /* ** Initialize atoms */ XA_CLIPBOARD = XInternAtom(dpy, "CLIPBOARD", False); XA_TARGETS = XInternAtom(dpy, "TARGETS", False); XA_ADOBE_EPS = XInternAtom(dpy, "_ADOBE_EPS", False); XA_ADOBE_EPSI = XInternAtom(dpy, "_ADOBE_EPSI", False); XA_FILE_NAME = XInternAtom(dpy, "FILE_NAME", False); } /* end initApplication() */ /*************************************************************** ** ** FUNCTION: resizeWindow ** ** DESCRIPTION: Callback routine to handle resize events. ** ** PARAMETERS: w callback widget ID ** clientData callback client data ** callData callback Motif data structure ** ** RETURN: None. ** ***************************************************************/ static void resizeWindow(w, clientData, callData) Widget w; XtPointer clientData, callData; { int depth; Display *dpy = XtDisplay(w); 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(AppData.drawingArea, XtNheight, &AppData.drawingHeight, XtNwidth, &AppData.drawingWidth, XtNdepth, &depth, NULL); /* ** Change the sizes of the buffer windows */ XtVaSetValues(AppData.bufOrig, XtNheight, AppData.drawingHeight, XtNwidth, AppData.drawingWidth, NULL); XtVaSetValues(AppData.bufComp, XtNheight, AppData.drawingHeight, XtNwidth, AppData.drawingWidth, NULL); /* ** Create new pixmaps to match the drawable */ XFreePixmap(dpy, AppData.original); XFreePixmap(dpy, AppData.composite); AppData.original = XCreatePixmap(dpy, XtWindow(w), AppData.drawingWidth, AppData.drawingHeight, depth); AppData.composite = XCreatePixmap(dpy, XtWindow(w), AppData.drawingWidth, AppData.drawingHeight, depth); /* ** Clear pixmaps */ XFillRectangle(dpy, AppData.original, AppData.gc, 0, 0, AppData.drawingWidth, AppData.drawingHeight); XFillRectangle(dpy, AppData.composite, AppData.gc, 0, 0, AppData.drawingWidth, AppData.drawingHeight); /* ** Update the gstates for the buffers to reflect the new pixmaps */ XDPSSetContextGState(AppData.dpsCtxt, AppData.origGState); XDPSSetContextDrawable(AppData.dpsCtxt, AppData.original, AppData.drawingHeight); XDPSUpdateContextGState(AppData.dpsCtxt, AppData.origGState); XDPSSetContextGState(AppData.dpsCtxt, AppData.compGState); XDPSSetContextDrawable(AppData.dpsCtxt, AppData.composite, AppData.drawingHeight); XDPSUpdateContextGState(AppData.dpsCtxt, AppData.compGState); /* ** Update the gstate for the window to reflect the new origin */ XDPSSetContextGState(AppData.dpsCtxt, AppData.winGState); AppData.yOffset = AppData.drawingHeight; PSsetXoffset(AppData.xOffset, AppData.yOffset); XDPSUpdateContextGState(AppData.dpsCtxt, AppData.winGState); /* ** Move the drawing area so the upper left corner ** of the image remains located at the upper left corner */ positionDrawingArea(point.x, point.y, 0, 0); drawSelfAndUpdate(NULL); } /* end resizeWindow() */ /*************************************************************** ** ** FUNCTION: refreshWindow ** ** DESCRIPTION: Callback routine to handle regular expose events ** to the main window. Updates the window by copying ** from the original pixmap ** ** PARAMETERS: w callback widget ID ** clientData callback client data ** callData callback Motif data structure ** ** RETURN: None. ** ***************************************************************/ static void refreshWindow(w, clientData, callData) Widget w; XtPointer clientData, callData; { XmDrawingAreaCallbackStruct *callback = (XmDrawingAreaCallbackStruct *) callData; XExposeEvent *e = &callback->event->xexpose; /* ** Only update exposed areas */ XCopyArea(XtDisplay(w), AppData.original, XtWindow(w), AppData.gc, e->x, e->y, e->width, e->height, e->x, e->y); if (AppData.selected) drawSelectionMarks(); } /* end refreshWindow() */ /*************************************************************** ** ** 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 */ switch (widgetNum) { case cMainDrawArea: AppData.drawingArea= w; /* ** Add event handlers for main window */ XtAddRawEventHandler(w, 0, True, graphicExpose, NULL); XtAddEventHandler(w, ButtonPressMask, False, mouseDown, NULL); break; case cBufferDrawArea0: AppData.bufOrig = w; break; case cBufferDrawArea1: AppData.bufComp = w; break; case cMainHorzSBar: AppData.hScroll = w; break; case cMainVertSBar: AppData.vScroll = w; break; case cTraceToggle: if (AppData.trace) XtVaSetValues(w, XmNset, True, NULL); break; } /* end switch */ } /* end createProc() */ /*************************************************************** ** ** FUNCTION: quitApp ** ** 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: Returns to OS. ** ***************************************************************/ static void quitApp(w, clientData, callData) Widget w; XtPointer clientData, callData; { XtDestroyApplicationContext(XtWidgetToApplicationContext(w)); exit(0); } /* end quitApp() */ /*************************************************************** ** ** FUNCTION: traceProc ** ** DESCRIPTION: Callback routine for the trace toggle buttons. ** Sets or resets the appropriate tracing flags. ** ** 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); XDPSChainTextContext (AppData.imageCtxt, toggle->set); } /* end traceProc() */ /*************************************************************** ** ** FUNCTION: showBufferProc ** ** DESCRIPTION: Callback routine for show buffer toggle button ** ** PARAMETERS: w callback widget ID ** clientData callback client data ** callData callback Motif data structure ** ** RETURN: None. ** ***************************************************************/ static void showBufferProc(w, clientData, callData) Widget w; XtPointer clientData, callData; { XmToggleButtonCallbackStruct *toggle = (XmToggleButtonCallbackStruct *) callData; AppData.showBuffer = toggle->set; if (AppData.showBuffer) { /* ** Resize buffers to match current window size and pop up */ XtVaSetValues(AppData.bufOrig, XtNheight, AppData.drawingHeight, XtNwidth, AppData.drawingWidth, NULL); XtVaSetValues(AppData.bufComp, XtNheight, AppData.drawingHeight, XtNwidth, AppData.drawingWidth, NULL); XtManageChild(AppData.bufferBox); } else XtUnmanageChild(AppData.bufferBox); } /* end showBufferProc() */ /*************************************************************** ** ** FUNCTION: bufferExposeProc ** ** DESCRIPTION: Callback routine for buffer exposure ** ** PARAMETERS: w callback widget ID ** clientData callback client data ** callData callback Motif data structure ** ** RETURN: None. ** ***************************************************************/ static void bufferExposeProc(w, clientData, callData) Widget w; XtPointer clientData, callData; { XmDrawingAreaCallbackStruct *callback = (XmDrawingAreaCallbackStruct *) callData; XExposeEvent *e = &callback->event->xexpose; /* ** Only update exposed areas */ if (w == AppData.bufOrig) { XCopyArea(XtDisplay(w), AppData.original, XtWindow(w), AppData.gc, e->x, e->y, e->width, e->height, e->x, e->y); } else { XCopyArea(XtDisplay(w), AppData.composite, XtWindow(w), AppData.gc, e->x, e->y, e->width, e->height, e->x, e->y); } } /* end bufferExposeProc() */ /*************************************************************** ** ** 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); } /* end cancelFileCallback() */ /*************************************************************** ** ** 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; } /* end makeNormalString() */ /************************************************************* ** ** FUNCTION: doOpen ** ** DESCRIPTION: Opens a file and adds it to the drawing ** ** PARAMETERS: name name of file ** f pointer to open file ** ** RETURN: None ** *************************************************************/ static void doOpen(name, f) String name; FILE *f; { Element *e; struct stat buf; /* ** Create a new element structure, or reuse the previous one */ if (AppData.adding != NULL) { e = AppData.adding; XtFree(e->filename); freeResourceList(e->resources); fclose(e->f); } else { e = XtNew(Element); e->tx = e->ty = e->sx = e->sy = e->rotation = 0.0; e->origBBox.ll.x = e->origBBox.ll.y = e->origBBox.ur.x = e->origBBox.ur.y = 0.0; } /* ** Fill element structure with info about file */ (void) fstat(fileno(f), &buf); e->filename = name; e->length = buf.st_size; e->f = f; e->image = e->mask = None; e->next = NULL; e->resources = NULL; /* ** Set cursor to busy while we parse the file for comments */ XDefineCursor(XtDisplay(AppData.drawingArea), XtWindow(AppData.drawingArea), AppData.busyCursor); XFlush(XtDisplay(AppData.drawingArea)); if (parseFileHeader(e)) { /* ** Get ready to add file. We don't really do anything here; instead ** it gets added in the mouseDown event handler */ AppData.adding = e; XDefineCursor(XtDisplay(AppData.drawingArea), XtWindow(AppData.drawingArea), AppData.crosshairCursor); } else { /* ** Parse error, back out */ XDefineCursor(XtDisplay(AppData.drawingArea), XtWindow(AppData.drawingArea), None); XtFree(e->filename); fclose(e->f); XtFree((XtPointer) e); AppData.adding = NULL; } if (AppData.selected != NULL) unselect(); } /* end doOpen() */ /************************************************************* ** ** FUNCTION: writeToFileFunc ** ** DESCRIPTION: Function to write its data out to a file. When ** passed to writePictureToFile, this makes the output ** go to a file ** ** PARAMETERS: buf Null-terminated string to write ** clientData Pointer to file ** ** RETURN: None ** *************************************************************/ static void writeToFileFunc(buf, clientData) char *buf; char *clientData; { FILE *f = (FILE *) clientData; fputs(buf, f); } /* end writeToFileFunc() */ /************************************************************* ** ** FUNCTION: doSave ** ** DESCRIPTION: Write the picture out to a file ** ** PARAMETERS: f File pointer to output file ** ** RETURN: None ** *************************************************************/ static void doSave(f) FILE *f; { /* ** If nothing in picture, don't write anything */ if (AppData.elements == NULL) { fclose(f); return; } writePictureToFile(writeToFileFunc, (char *) f, (Element *) NULL, AppData.includePreview); fclose(f); } /* end doSave() */ /*************************************************************** ** ** FUNCTION: openFileCallback ** ** DESCRIPTION: Callback procedure to open a file for input or for saving ** ** 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; String str = makeNormalString(fdata->value); int *action = (int *) clientData; FILE *f; /* ** Open the file for reading (if input) or writing (if output) */ if (*action == 0) f = fopen(str, "r"); else f = fopen(str, "w"); if (f == NULL) { fprintf(stderr, "Error: Could not open file %f\n", str); } else { XtUnmanageChild(AppData.fileDialog); if (*action == 0) doOpen(str, f); else doSave(f); } } /* end openFileCallback() */ /*************************************************************** ** ** FUNCTION: fileProc ** ** DESCRIPTION: Callback routine to open or save a file ** ** PARAMETERS: w callback widget ID ** clientData callback client data ** callData callback Motif data structure ** ** RETURN: None. ** ***************************************************************/ static void fileProc(w, clientData, callData) Widget w; XtPointer clientData, callData; { static int action; action = *(int *) clientData; /* ** If there is no file dialog, create one and unmanage the help button */ if (AppData.fileDialog == NULL) { AppData.fileDialog = XmCreateFileSelectionDialog(AppData.drawingArea, "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); } XtManageChild(AppData.fileDialog); } /* end fileProc() */ /************************************************************* ** ** FUNCTION: convertSelection ** ** DESCRIPTION: Callback procedure to deliver selection value ** ** PARAMETERS: w Widget owning selection ** selection Selection desired ** target Type of information required ** ** RETURN: type Data type of selection ** value Selection data ** length Length of selection data ** format Size of selection data units ** *************************************************************/ static Boolean convertSelection(w, selection, target, type, value, length, format) Widget w; Atom *selection, *target; Atom *type; XtPointer *value; unsigned long *length; int *format; { Element *e; char *buf; /* ** Type of TARGETS means a request for supported types */ if (*target == XA_TARGETS) { Atom *targets = (Atom *) XtMalloc(4 * sizeof(Atom)); targets[0] = XA_ADOBE_EPS; targets[1] = XA_ADOBE_EPSI; targets[2] = XA_FILE_NAME; targets[3] = XA_PIXMAP; *value = (XtPointer) targets; *type = XA_ATOM; *length = 4; *format = 32; return True; } /* ** If there is a pending cut, deliver it; otherwise deliver selected ** element. If nothing is selected, no data to return */ if (AppData.pendingCut != NULL) e = AppData.pendingCut; else if (AppData.selected != NULL) e = AppData.selected; else return False; /* ** Return data in EPS format either with or without a preview image */ if (*target == XA_ADOBE_EPS || *target == XA_ADOBE_EPSI) { XDefineCursor(XtDisplay(AppData.drawingArea), XtWindow(AppData.drawingArea), AppData.busyCursor); buf = convertToEPS(e, (*target == XA_ADOBE_EPSI)); XDefineCursor(XtDisplay(AppData.drawingArea), XtWindow(AppData.drawingArea), None); *value = (XtPointer) buf; *length = strlen(buf) + 1; *type = XA_STRING; *format = 8; return True; } /* ** Return name of selected file */ if (*target == XA_FILE_NAME) { char *name = XtNewString(e->filename); *value = (XtPointer) name; *length = strlen(name) + 1; *type = XA_STRING; *format = 8; return True; } /* ** Return pixmap id of rendered image */ if (*target == XA_PIXMAP) { Pixmap *p; if (e->image == None) renderElement(e); if (e->image == None) return False; p = XtNew(Pixmap); *p = e->image; *value = (XtPointer) p; *length = 1; *type = XA_DRAWABLE; *format = 32; return True; } /* ** Unrecognized target type */ return False; } /* end convertSelection() */ /************************************************************* ** ** FUNCTION: loseSelection ** ** DESCRIPTION: Callback procedure for losing selection. If there ** is a pending cut selection, free it ** ** PARAMETERS: w Widget owning selection ** selection Selection being lost ** ** RETURN: None ** *************************************************************/ static void loseSelection(w, selection) Widget w; Atom *selection; { if (AppData.pendingCut != NULL) { freeElement(AppData.pendingCut); AppData.pendingCut = NULL; } } /* end loseSelection() */ /*************************************************************** ** ** FUNCTION: cutProc ** ** DESCRIPTION: Callback routine to cut selection ** ** PARAMETERS: w callback widget ID ** clientData callback client data ** callData callback Motif data structure ** ** RETURN: None. ** ***************************************************************/ static void cutProc(w, clientData, callData) Widget w; XtPointer clientData, callData; { Element *e = AppData.selected; /* ** If nothing selected, return. If there's already a pending cut, ** delete it */ if (e == NULL) return; if (AppData.pendingCut != NULL) freeElement(AppData.pendingCut); /* ** Remove selected element from the list of element and move to pending cut */ if (e->next == NULL) AppData.lastElement = e->prev; else e->next->prev = e->prev; if (e->prev == NULL) AppData.elements = e->next; else e->prev->next = e->next; AppData.pendingCut = e; AppData.selected = NULL; drawSelfAndUpdate(NULL); /* ** Assert ownership of the selection */ XtOwnSelection(AppData.drawingArea, XA_CLIPBOARD, XtLastTimestampProcessed(XtDisplay(w)), convertSelection, loseSelection, NULL); } /* end cutProc() */ /*************************************************************** ** ** FUNCTION: copyProc ** ** DESCRIPTION: Callback routine to copy selection ** ** PARAMETERS: w callback widget ID ** clientData callback client data ** callData callback Motif data structure ** ** RETURN: None. ** ***************************************************************/ static void copyProc(w, clientData, callData) Widget w; XtPointer clientData, callData; { if (AppData.selected == NULL) return; /* ** Assert ownership of the selection */ (void) XtOwnSelection(AppData.drawingArea, XA_CLIPBOARD, XtLastTimestampProcessed(XtDisplay(w)), convertSelection, loseSelection, NULL); } /* end copyProc() */ /************************************************************* ** ** FUNCTION: gotSelection ** ** DESCRIPTION: ** ** PARAMETERS: ** ** RETURN: None ** *************************************************************/ static void gotSelection(w, data, selection, type, value, length, format) Widget w; XtPointer data; Atom *selection, *type; XtPointer value; unsigned long *length; int *format; { /* ** Check that we got what we expected */ if (*selection != XA_CLIPBOARD || *type != XA_STRING || *format != 8 || value == NULL) return; /* ** Paste the selection value into the picture */ XDefineCursor(XtDisplay(AppData.drawingArea), XtWindow(AppData.drawingArea), AppData.busyCursor); pasteEPS((char *) value, *length); XDefineCursor(XtDisplay(AppData.drawingArea), XtWindow(AppData.drawingArea), None); } /* end gotSelection() */ /*************************************************************** ** ** FUNCTION: pasteProc ** ** DESCRIPTION: Callback routine to paste selection ** ** PARAMETERS: w callback widget ID ** clientData callback client data ** callData callback Motif data structure ** ** RETURN: None. ** ***************************************************************/ static void pasteProc(w, clientData, callData) Widget w; XtPointer clientData, callData; { /* ** Fetch the value of the clipboard selection */ XtGetSelectionValue(AppData.drawingArea, XA_CLIPBOARD, XA_ADOBE_EPS, gotSelection, NULL, XtLastTimestampProcessed(XtDisplay(w))); } /* end pasteProc() */ /*************************************************************** ** ** FUNCTION: deleteProc ** ** DESCRIPTION: Callback routine to delete selection ** ** PARAMETERS: w callback widget ID ** clientData callback client data ** callData callback Motif data structure ** ** RETURN: None. ** ***************************************************************/ static void deleteProc(w, clientData, callData) Widget w; XtPointer clientData, callData; { Element *e = AppData.selected; if (e == NULL) return; /* ** Remove selected element from the chain */ if (e->next == NULL) AppData.lastElement = e->prev; else e->next->prev = e->prev; if (e->prev == NULL) AppData.elements = e->next; else e->prev->next = e->next; AppData.selected = NULL; freeElement(e); drawSelfAndUpdate(NULL); } /* end deleteProc() */ /*************************************************************** ** ** FUNCTION: rotateProc ** ** DESCRIPTION: Callback routine to rotate selection ** ** PARAMETERS: w callback widget ID ** clientData callback client data ** callData callback Motif data structure ** ** RETURN: None. ** ***************************************************************/ static void rotateProc(w, clientData, callData) Widget w; XtPointer clientData, callData; { Element *e = AppData.selected; if (e == NULL) return; /* ** Just redefine cursor. Real work takes place in mouseDown procedure */ XDefineCursor(XtDisplay(AppData.drawingArea), XtWindow(AppData.drawingArea), AppData.crosshairCursor); AppData.rotating = True; } /* end rotateProc() */ /*************************************************************** ** ** FUNCTION: scaleProc ** ** DESCRIPTION: Callback routine to scale selection ** ** PARAMETERS: w callback widget ID ** clientData callback client data ** callData callback Motif data structure ** ** RETURN: None. ** ***************************************************************/ static void scaleProc(w, clientData, callData) Widget w; XtPointer clientData, callData; { Element *e = AppData.selected; if (e == NULL) return; /* ** Just redefine cursor. Real work takes place in mouseDown procedure */ XDefineCursor(XtDisplay(AppData.drawingArea), XtWindow(AppData.drawingArea), AppData.crosshairCursor); AppData.scaling = True; } /* end scaleProc() */ /*************************************************************** ** ** FUNCTION: frontProc ** ** DESCRIPTION: Callback routine to raise selection ** ** PARAMETERS: w callback widget ID ** clientData callback client data ** callData callback Motif data structure ** ** RETURN: None. ** ***************************************************************/ static void frontProc(w, clientData, callData) Widget w; XtPointer clientData, callData; { Element *e = AppData.selected; /* ** If nothing selected or selected element is already in front, return */ if (e == NULL || e == AppData.elements) return; /* ** Remove from list and re-insert at the front */ if (e->next == NULL) AppData.lastElement = e->prev; else e->next->prev = e->prev; if (e->prev == NULL) AppData.elements = e->next; else e->prev->next = e->next; e->next = AppData.elements; e->prev = NULL; AppData.elements->prev = e; AppData.elements = e; drawSelfAndUpdate(e); } /* end frontProc() */ /*************************************************************** ** ** FUNCTION: backProc ** ** DESCRIPTION: Callback routine to lower selection ** ** PARAMETERS: w callback widget ID ** clientData callback client data ** callData callback Motif data structure ** ** RETURN: None. ** ***************************************************************/ static void backProc(w, clientData, callData) Widget w; XtPointer clientData, callData; { Element *e = AppData.selected; /* ** If nothing selected or selected element is already in back, return */ if (e == NULL || e == AppData.lastElement) return; /* ** Remove from list and re-insert at the end */ if (e->next == NULL) AppData.lastElement = e->prev; else e->next->prev = e->prev; if (e->prev == NULL) AppData.elements = e->next; else e->prev->next = e->next; e->prev = AppData.lastElement; e->next = NULL; AppData.lastElement->next = e; AppData.lastElement = e; drawSelfAndUpdate(NULL); } /* end backProc() */ /*************************************************************** ** ** FUNCTION: origSizeProc ** ** DESCRIPTION: Callback routine to restore selection to original size ** ** PARAMETERS: w callback widget ID ** clientData callback client data ** callData callback Motif data structure ** ** RETURN: None. ** ***************************************************************/ static void origSizeProc(w, clientData, callData) Widget w; XtPointer clientData, callData; { Element *e = AppData.selected; if (e == NULL || (e->sx == 1.0 && e->sy == 1.0)) return; /* ** Set the x and y scale factors to 1 and redraw */ e->sx = e->sy = 1.0; updateElement(e); drawSelfAndUpdate(NULL); } /* end origSizeProc() */ /*************************************************************** ** ** FUNCTION: origRatioProc ** ** DESCRIPTION: Callback routine to restore selection to original ratio ** ** PARAMETERS: w callback widget ID ** clientData callback client data ** callData callback Motif data structure ** ** RETURN: None. ** ***************************************************************/ static void origRatioProc(w, clientData, callData) Widget w; XtPointer clientData, callData; { Element *e = AppData.selected; float s; if (e == NULL || ABS(e->sx) == ABS(e->sy)) return; /* ** Set the x and y scale factors to the minimum of the two, but keep the ** signs unchanged. This makes the new size fit within the previous size */ s = MIN(ABS(e->sx), ABS(e->sy)); e->sx = SIGN(e->sx) * s; e->sy = SIGN(e->sy) * s; updateElement(e); drawSelfAndUpdate(NULL); } /* end origRatioProc() */ /*************************************************************** ** ** FUNCTION: useBoxProc ** ** DESCRIPTION: Callback routine to use boxes instead of pictures ** ** PARAMETERS: w callback widget ID ** clientData callback client data ** callData callback Motif data structure ** ** RETURN: None. ** ***************************************************************/ static void useBoxProc(w, clientData, callData) Widget w; XtPointer clientData, callData; { XmToggleButtonCallbackStruct *toggle = (XmToggleButtonCallbackStruct *) callData; Element *e; AppData.useBoxes = toggle->set; /* ** If turning off boxes, go through elements and render those that have ** no pixmaps */ if (!toggle->set) { for (e = AppData.elements; e != NULL; e = e->next) { if (e->image == NULL) renderElement(e); } } drawSelfAndUpdate(NULL); } /* end useBoxProc() */ /*************************************************************** ** ** FUNCTION: setPreview ** ** DESCRIPTION: Callback routine to set preview options ** ** PARAMETERS: w callback widget ID ** clientData callback client data ** callData callback Motif data structure ** ** RETURN: None. ** ***************************************************************/ static void setPreview(w, clientData, callData) Widget w; XtPointer clientData, callData; { XmToggleButtonCallbackStruct *toggle = (XmToggleButtonCallbackStruct *) callData; int action = *(int *) clientData; if (action == 0) AppData.includePreview = toggle->set; else AppData.deepPreview = toggle->set; } /* end setPreview() */ /*************************************************************** ** ** FUNCTION: mouseDown ** ** DESCRIPTION: This function acts as the event handler for the ** ButtonDown event. If we're adding something, start ** sweeping out an area. If we're scaling, start scaling box ** If rotating, start rotating box. If none of the above, ** see if we can select or move something ** ** 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; XRect rect; XButtonPressedEvent *bp = (XButtonPressedEvent *) event; Element *e; if (event->xany.window != XtWindow(AppData.drawingArea)) return; xpoint.x = bp->x; xpoint.y = bp->y; /* ** If adding an element, sweep out a rectangle and add */ if (AppData.adding != NULL) { sweepRectangle(&xpoint, &AppData.adding->origBBox, &rect); XDefineCursor(XtDisplay(AppData.drawingArea), XtWindow(AppData.drawingArea), AppData.busyCursor); addElement(&rect); XDefineCursor(XtDisplay(AppData.drawingArea), XtWindow(AppData.drawingArea), None); /* ** If rotating, start rotation */ } else if (AppData.rotating) { e = AppData.selected; unselect(); rotateElement(&xpoint, e); AppData.rotating = False; selectElement(e); /* ** If scaling, start scale operation */ } else if (AppData.scaling) { e = AppData.selected; unselect(); scaleElement(&xpoint, e); AppData.scaling = False; selectElement(e); } else { /* ** Try to select something. Convert mouse point into document ** coordinates */ xpoint.x -= AppData.originX; xpoint.y += AppData.scaledHeight - AppData.originY; for (e = AppData.elements; e != NULL; e = e->next) { /* ** Check if mouse point is in element */ if (pointInElement(&xpoint, e)) { if (e == AppData.selected) { /* ** If the newly selected element is the same as the ** current one, start move */ unselect(); xpoint.x += AppData.originX; xpoint.y -= AppData.scaledHeight - AppData.originY; moveElement(&xpoint, e); } else unselect(); selectElement(e); return; } } unselect(); } } /* end mouseDown() */
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.