VkCutPaste(3x)
VkCutPaste - A simple API for Cut/Copy/Drag/Drop
As shipped in IRIX 6.5.19. Last changed in IRIX 6.5.5.
NAME VkCutPaste - A simple API for Cut/Copy/Drag/Drop INHERITS FROM VkCallbackObject : VkBase HEADER FILE #include <Vk/VkCutPaste.h> PUBLIC PROTOCOL SUMMARY Constructor/Destructor VkCutPaste(Widget w); void ~VkCutPaste(void); Copy (Export) Methods void clear(Atom selection, Time time = CurrentTime); Boolean putCopy(Atom selection, Atom target, XtPointer data, unsigned long numBytes); Boolean putCopy(Atom selection, const char *targetName, XtPointer data, unsigned long numBytes); Boolean putReference(Atom selection, Atom target, XtPointer data, unsigned long numBytes); Boolean putReference(Atom selection, const char *targetName, XtPointer data, unsigned long numBytes); Boolean getLocalReference(Atom selection, int index, Atom *target, XtPointer *dataRet, unsigned long *numBytesRet); Boolean getLocalTypeReference(Atom selection, Atom target, XtPointer *dataRet, unsigned long *numBytesRet); Boolean remove(Atom selection, Atom target); Copy (Export) Methods - ViewKit 1.5.3 only Boolean export(Atom selection, Time time = CurrentTime); Copy (Export) Methods - ViewKit 2.1 only Boolean exportData(Atom selection, Time time = CurrentTime); Paste (Import) Methods void import(Atom selection, Atom *interestList, int interestListLen, ImportCallbackProc proc, void *clientData = NULL, Time theTime = CurrentTime); XtPointer importImmediate(Atom selection, Atom *interestList, int interestListLen, Atom *targetRet, unsigned long *numBytesRet, Time theTime = CurrentTime); Drag Away Methods Widget dragAwayCopy(Widget w, XEvent *xev, Atom target, XtPointer data, unsigned long numBytes, DragAwayCallbackProc dragAwayProc = NULL, void *clientData = NULL); Widget dragAwayCopy(Widget w, XEvent *xev, const char *targetName, XtPointer data, unsigned long numBytes, DragAwayCallbackProc dragAwayProc = NULL, void *clientData = NULL); Widget dragAwayCopyExtended(Widget w, XEvent *xev, Atom *targetList, XtPointer *dataList, unsigned long *lenList, int numDragItems, DragAwayCallbackProc dragAwayProc = NULL, void *clientData = NULL, ArgList args = NULL, int numArgs = 0); Drop Methods Boolean registerDropSite(Widget w, Atom *interestList, int interestListLen, DropSiteCallbackProc dropProc, void *clientData = NULL); Boolean registerDropSiteExtended(Widget w, Atom *interestList, int interestListLen, DropSiteCallbackProc dropProc, DragCallbackProc dragProc = NULL, void *clientData = NULL, Arg *args = NULL, int numArgs = 0); Boolean unregisterDropSite(Widget w); Data Type and Converter Methods void registerDataType(Atom target, Atom type, int format, unsigned long flags = CUTPASTE_NORMAL_TYPE, DestroyProc destroyProc = NULL, void *clientData = NULL); void registerDataType(const char *targetName, const char *typeName, int format, unsigned long flags = CUTPASTE_NORMAL_TYPE, DestroyProc destroyProc = NULL, void *clientData = NULL); Boolean getDataTypeInfo(Atom target, Atom *type, int *format, unsigned long *flags); void registerConverter(Atom from, Atom to, ConvertProc converter, CanConvertProc canConvert = NULL, void *clientData = NULL); void registerConverter(const char *fromName, const char *toName, ConvertProc converter, CanConvertProc canConvert = NULL, void *clientData = NULL); Other Methods unsigned long getVersion(void); Atom primaryAtom(void); Atom clipboardAtom(void); Widget getWidget(void); Time getXServerTime(void); void setTransactionsTimeout(unsigned long numSeconds); Boolean isOwnedByMe(Atom selection); Boolean isOwnedByLocalHost(Atom selection); Boolean registerLoseSelection(Atom selection, LoseSelectionProc loseSelProc, void *clientData); Boolean getFilenamesFromSGI_ICON(char *sgiIconData, unsigned long numBytes, char ***fileNameArrayRet, int *numFilesRet); void freeFilenamesFromSGI_ICON(char **fileNameArray, int numFiles); Callback Function Prototypes typedef Boolean (*ConvertProc)(Widget w, Atom selection, void *clientData, Atom srcTarget, XtPointer src, unsigned long numSrcBytes, Atom dstTarget, XtPointer *dst, unsigned long *numDstBytes); typedef Boolean (*CanConvertProc)(Widget w, Atom selection, void *clientData, Atom srcTarget, XtPointer src, unsigned long numSrcBytes, Atom dstTarget); typedef void (*DestroyProc)(Widget w, Atom selection, Atom target, XtPointer data, unsigned long numBytes, void *clientData); typedef void (*LoseSelectionProc)(Widget w, Atom selection, void *clientData); typedef void (*DropSiteCallbackProc)(Widget w, Atom target, XtPointer data, unsigned long numBytes, int x, int y, void *clientData); typedef void (*DragCallbackProc)(Widget w, Atom target, int reason, int x, int y, void *clientData); typedef void (*DragAwayCallbackProc)(Widget w, Boolean result,void *clientData); typedef void (*ImportCallbackProc)(Widget w, Atom target, XtPointer data, unsigned long numBytes, void *clientData); CLASS DESCRIPTION The VkCutPaste class provides a simple C++ API that helps developers add inter-application Copy/Paste/Drag/Drop to their applications with very little effort, and with little or no understanding of Motif's and X-Window's complex protocols. The VkCutPaste library uses the Xt Intrinsics and Motif to implement a totally standard X-Selection ICCCM compliant communication, so your application must link with those libraries to use this API. The VkCutPaste does not require other parts of ViewKit, and can be used in a standard Motif application. FUNCTION DESCRIPTIONS VkCutPaste() VkCutPaste(Widget w); Instantiates a VkCutPaste object. The "w" must not be destroyed for the life of this class, since it is used by the VkCutPaste class during the execution of most of the methods. Do not pass the same widget into more than one concurrent instance of the VkCutPaste class. ~VkCutPaste() void ~VkCutPaste(void); This deletes any remaining memory allocated by the VkCutPaste class. Because the VkCutPaste class will sometimes create temporary files, it is important to always call the destructor when you are through with the class. clear() void clear(Atom selection, Time time = CurrentTime); Usually called immediately before a "putCopy()". Clears the indicated selection, and frees any memory that was allocated as part of an earlier "putCopy()". After a "clear()", no data is being offered to any other ICCCM clients on this selection. The "selection" is either CLIPBOARD or PRIMARY. clipboardAtom() Atom clipboardAtom(void); Returns the CLIPBOARD atom. This is a convenience function, and returns exactly the same thing as XmInternAtom(dpy, "CLIPBOARD", False). dragAwayCopy() Widget dragAwayCopy(Widget w, XEvent *xev, Atom target, XtPointer data, unsigned long numBytes, DragAwayCallbackProc dragAwayProc = NULL, void *clientData = NULL); Widget dragAwayCopy(Widget w, XEvent *xev, const char *targetName, XtPointer data, unsigned long numBytes, DragAwayCallbackProc dragAwayProc = NULL, void *clientData = NULL); Drags away data from this application. The "data" can be free'd immediately after calling this function, because this function makes a copy of the data for its use. The "xev" should be the ButtonPress event that the user did to initiate the drag. The optional "dragAwayProc" is called after the drag completes, and one of the parameters to that function indicates if the drag was successful or not. The DragContext created for this drag and drop transaction is returned (see XmDragStart). dragAwayCopyExtended() Widget dragAwayCopyExtended(Widget w, XEvent *xev, Atom *targetList, XtPointer *dataList, unsigned long *lenList, int numDragItems, DragAwayCallbackProc dragAwayProc = NULL, void *clientData = NULL, ArgList args = NULL, int numArgs = 0); This does exactly what "dragAwayCopy()" does, but provides more options for the advanced programmer who needs more control. For example, the programmer could specify the drag away data as more than one "target" (it should be the same conceptual object, just in different formats, like GIF and XPM format data of the same image). The programmer could also use this function to specify the various drag icons by specifying those parameters in the "args" argument. "Args" and "numArgs" are passed of to XmDragStart(). The following "args" are not allowed: XmNconvertProc, XmNdragOperations, XmNexportTargets, XmNnumExportTargets, XmNclientData. See the XmDragContext man page for information on other valid arguments. Motif's Drop Copy protocol (XmDROP_COPY) is the only drag and drop operation supported. The DragContext created for this drag and drop transaction is returned (see XmDragStart). export() - ViewKit 1.5.3 only Boolean export(Atom selection, Time time = CurrentTime); Usually called immediately after a "putCopy()", this makes the data in the indicated selection available to other ICCCM clients. exportData() - ViewKit 2.1 only Boolean exportData(Atom selection, Time time = CurrentTime); Usually called immediately after a "putCopy()", this makes the data in the indicated selection available to other ICCCM clients. freeFilenamesFromSGI_ICON() void freeFilenamesFromSGI_ICON(char **fileNameArray, int numFiles); This frees the data that is returned from the "getFilenamesFromSGI_ICON()" method. getFilenamesFromSGI_ICON() Boolean getFilenamesFromSGI_ICON(char *sgiIconData, unsigned long numBytes, char ***fileNameArrayRet, int *numFilesRet); This convenience method parses the data of target _SGI_ICON which the SGI desktop uses to drag one or more files around. An application would call this function inside of its "DropSiteCallbackProc" when it receives a target of _SGI_ICON. After an application is done with the filename list, it should free the memory allocated inside "getFilenamesFromSGI_ICON()" by calling "freeFilenamesFromSGI_ICON()". getDataTypeInfo() Boolean getDataTypeInfo(Atom target, Atom *type, int *format, unsigned long *flags); Given the "target", this method returns the "type" and the "format" of this kind of target as specified by the ICCCM manual, and also any associated "flags". True is returned if the "target" was found, and False otherwise. The VkCutPaste class knows about an extensive list of targets already. This list can be added to by calling the "registerDataType()" method. The "flags" returned is a bit mask of the following flags: CUTPASTE_NORMAL_TYPE, CUTPASTE_FILENAME_TYPE, and CUTPASTE_HIDDEN_TYPE. See "registerDataType()" for more information. getLocalReference() Boolean getLocalReference(Atom selection, int index, Atom *target, XtPointer *dataRet, unsigned long *numBytesRet); Allows you to retrieve the contents of the local export selection. This is NOT X Selections based. This only gives you a pointer, so the data must not be free'd or modified. Returns a pointer to the data at "index" (if multiple "putCopy()" were called, the first one is at index 0, the second is at index 1, and so on). getLocalTypeReference() Boolean getLocalTypeReference(Atom selection, Atom target, XtPointer *dataRet, unsigned long *numBytesRet); Does exactly the same thing as "getLocalReference()", but instead of specifying an "index", you specify the "target" you wish to retrieve from the exported selection. getVersion() unsigned long getVersion(void); Returns the version number of this implementation of the VkCutPaste class. For example, the first version is 0x010000, version 2.1 will be 0x020100, etc. getWidget() Widget getWidget(void); Returns the widget that was originally passed to the VkCutPaste constructor. getXServerTime() Time getXServerTime(void); Invokes a round trip to the X-Server, and returns a server timestamp. Most applications should try to avoid this call and use the "CurrentTime" flag to the VkCutPaste methods, or even better should use the timestamp out of a recent X-Event. However, there are some rare situations where there are no X-Events handy and CurrentTime will not work, so this convenience method is a failsafe way to get a valid server timestamp. import() void import(Atom selection, Atom *interestList, int interestListLen, ImportCallbackProc proc, void *clientData = NULL, Time theTime = CurrentTime); This is a non-blocking method which will retrieve Copy and Paste data from any ICCCM client. The "selection" should be either CLIPBOARD or PRIMARY. The "interestList" is an ordered array of the targets this application is interested in. For example, interestList[0] might be XPM, interestList[1] might be GIF_89, and interestList[2] might be STRING. In this example, you would set "interestListLen" to be "3". The "proc" will be invoked with either NULL data, or an XPM, GIF_89, or STRING. NULL simply means that nothing was available of any of the requested types. "import()" makes a copy of the interestList, so you can free this data immediately after this call completes (and before the "proc" is called). importImmediate() XtPointer importImmediate(Atom selection, Atom *interestList, int interestListLen, Atom *targetRet, unsigned long *numBytesRet, Time theTime = CurrentTime); This is a blocking version of the "import()" method. This function blocks until the data is retrieved, so it eliminates the callback. Since this function uses it's own internal event loop, clients that are not using the standard "XtAppMainLoop()" (or in ViewKit are not using the standard "app->run()") might want to avoid this call. isOwnedByLocalHost() Boolean isOwnedByLocalHost(Atom selection); Returns True if the indicated selection is currently owned by a client running on the same machine as this client. This call is useful if you are planning to copy and paste filenames with other clients, since a file that is on a different machine is not accessible to your client. Some examples of filename targets are XPM_FILE and GIF_89_FILE. Data stream types like XPM and GIF_89 are always safe and will always work, and should be used unless there is some overwhelming reason to exchange filenames. isOwnedByMe() Boolean isOwnedByMe(Atom selection); Returns True if the selection is currently owned by this client. This can be used to optimize the "Paste()" function to be faster when this client would have exchanged data with itself anyway. primaryAtom() Atom primaryAtom(void); Returns the PRIMARY atom. This is a convenience function, and returns exactly the same thing as XmInternAtom(dpy, "PRIMARY", False). putCopy() Boolean putCopy(Atom selection, Atom target, XtPointer data, unsigned long numBytes); Boolean putCopy(Atom selection, const char *targetName, XtPointer data, unsigned long numBytes); This method is usually called immediately after a "clear()" and immediately before "export()" (or "exportData()" if using ViewKit 2.1). These three methods make the "data" specified in the putCopy() available to any ICCCM client on the indicated "selection", which should be either PRIMARY or CLIPBOARD. The "data" passed into "putCopy()" can be free'd immediately after this call, since "putCopy()" makes a copy of the data. putReference() Boolean putReference(Atom selection, Atom target, XtPointer data, unsigned long numBytes); Boolean putReference(Atom selection, const char *targetName, XtPointer data, unsigned long numBytes); This method can be used instead of "putCopy()" if the data is so large that an extra copy is not possible or is terribly inefficient. This call DOES NOT make a copy of the data, so you must not ever free "data" until after you "remove()" this data from the currently exported selection. If for whatever reason the data becomes invalid, you must call "remove()" to remove this reference. registerConverter() void registerConverter(Atom from, Atom to, ConvertProc converter, CanConvertProc canConvert = NULL, void *clientData = NULL); void registerConverter(const char *fromName, const char *toName, ConvertProc converter, CanConvertProc canConvert = NULL, void *clientData = NULL); Registers a converter between two data targets. The VkCutPaste class provides integral support for converters. Converters are used to extend the targets that your application understands. For example, if you call "dragAway()" with XPM data (this is an image), and a drop site in another ICCCM application only accepts images of type GIF_89, then the drop would normally fail. However, if you have registered a converter from XPM to GIF_89, the VkCutPaste class will automatically call your converter and successfully drop the GIF_89 on the destination client. This same converter will fire if you attempt to "import()" a GIF_89 yourself, yet the other client is only offering XPM. The converter is called to provide you with the data type you requested. The optional "canConvertProc" is provided so that your application can conditionally offer conversion support for a given target. The "canConvert" function returns True if the converter can perform the requested conversion, and False otherwise. The "canConvert" function is called by VkCutPaste so that VkCutPaste doesn't offer targets to requesting clients that cannot actually be produced. If your conversions will always work under all circumstances, do not register a "CanConvertProc". registerDataType() void registerDataType(Atom target, Atom type, int format, unsigned long flags = CUTPASTE_NORMAL_TYPE, DestroyProc destroyProc = NULL, void *clientData = NULL); void registerDataType(const char *targetName, const char *typeName, int format, unsigned long flags = CUTPASTE_NORMAL_TYPE, DestroyProc destroyProc = NULL, void *clientData = NULL); Registers a data target with the VkCutPaste class, and at the same time tells the class what the type, format, and flags are. This is only necessary if the VkCutPaste class has never heard of this format before (the VkCutPaste class contains an extensive internal list of known targets, see the REGISTERED TARGETS section for more information). The "flags" are a bit mask of the following flags: CUTPASTE_NORMAL_TYPE, CUTPASTE_FILENAME_TYPE, and CUTPASTE_HIDDEN_TYPE. Any new filename target as described here needs to be flagged as a "CUTPASTE_FILENAME_TYPE" so that the VkCutPaste class can deal with it properly. A "CUTPASTE_HIDDEN_TYPE" means that this target will never be published to other clients. This is unusual, but can be useful if you are using an internal representation you do not wish to ever expose. You can optionally specify a function that is called to destroy auxiliary data associated with this data target. An example usage of the DestroyProc would be if you need to register a new target as filename data (CUTPASTE_FILENAME_TYPE). cnp->registerDataType("MY_FILE", "MY_FILE", 8, CUT_PASTE_FILENAME_TYPE, fileDestroyProc, NULL); Before your client calls putCopy() with a filename target, it needs to create a file that will be given to the VkCutPaste class. The VkCutPaste class will call the DestroyProc when this file is no longer needed. cnp->putCopy(xaCLIPBOARD, "MY_FILE", filename, strlen(filename) + 1); Now, when the VkCutPaste class no longer needs the file referenced by filename, the DestroyProc is called. For file targets, the DestroyProc should remove the file. In the DestroyProc, "data" is a copy of the data that was made when your client called putCopy(). For this example, data is the filename that was handed over to the VkCutPaste class. static void fileDestroyProc(Widget w, Atom selection, Atom target, XtPointer data, unsigned long numBytes, void * clientData) { // DO NOT free the filename itself, just remove the file. if (target == MY_FILE && data != NULL) { char *fname = (char *)data; unlink(fname); } } Notice that this is only necessary if you need to register a new data type. See the section "FILE AND DATA OWNERSHIP" for more information. registerDropSite() Boolean registerDropSite(Widget w, Atom *interestList, int interestListLen, DropSiteCallbackProc dropProc, void *clientData = NULL); Registers a widget as a drop site. The "interestList" is an ordered list of what data targets the drop site will accept. When another client drops data on this widget, the "dropProc" will be called with exactly one target. That target is the earliest one found in the interestList which the other client can supply, or that can be converted to, see "registerConverter()"). registerDropSiteExtended() Boolean registerDropSiteExtended(Widget w, Atom *interestList, int interestListLen, DropSiteCallbackProc dropProc, DragCallbackProc dragProc = NULL, void *clientData = NULL, Arg *args = NULL, int numArgs = 0); This does exactly what "registerDropSite()" does, but provides more options for the advanced programmer who needs more control. For example, the programmer could specify the various drop icons by specifying those parameters in the "args" argument. "Args" and "numArgs" are passed off to XmDropSiteRegister(). The following "args" are not allowed: XmNdragProc, XmNdropProc, XmNdropSiteOperations, XmNinportTargets, XmNnumImportTargets. See the XmDropSite man page for information on other valid arguments. Motif's Drop Copy protocol (XmDROP_COPY) is the only drag and drop operation supported. Possible "reasons" that are passed to the DragCallbackProc are: XmCR_DROP_SITE_LEAVE_MESSAGE, XmCR_DROP_SITE_ENTER_MESSAGE, and XmCR_DROP_SITE_MOTION_MESSAGE. registerLoseSelection() Boolean registerLoseSelection(Atom selection, LoseSelectionProc loseSelProc, void *clientData); The "loseSelProc" will be called when this application loses the selection ownership to some other client. This is very useful in the case of PRIMARY, since in the loseSelProc callback the application should un-highlight what was previously highlighted as the PRIMARY selection. remove() Boolean remove(Atom selection, Atom target); Removes the indicated "target" from the currently exported selection. For example, if you had called "putReference(XPM)" and now the XPM data has become invalid for some reason, you must call "remove(XPM)". setTransactionsTimeout() void setTransactionsTimeout(unsigned long numSeconds); Sets the transaction timeout. The default Motif timeout is 5 seconds, which means that if the remote client does not respond to a request for data within 5 seconds, the transaction is canceled and no data is transferred. For some large data targets, or those that require long conversions, 5 seconds may not be adequate. unregisterDropSite() Boolean unregisterDropSite(Widget w); Unregisters a drop site. This makes it stop accepting drops of any kind. EXAMPLES This section provides examples to help get you started using the VkCutPaste class. For a detailed description on data and file ownership during cut/paste and drag/drop operations, see the section "FILE AND DATA OWNERSHIP". There are four separate actions supported by the VkCutPaste class: COPY - make some data available to another X-Client PASTE - import data from another X-Client DRAG - drag some data away to another X-Client DROP - accept some data that is dropped on us Before you can use any of this support, you must instantiate the VkCutPaste class in your program (probably at program startup). This can be done with the following two lines of code, where "someWidget" is any widget in your Motif or ViewKit program that will be valid during the lifetime of the VkCutPaste class: #include <Vk/VkCutPaste.h> cnp = new VkCutPaste(someWidget); COPY - In your application, let's imagine that an XPM image is currently highlighted, and that the user has selected the Copy menu item from the Edit menu. In the menu Callback, you might put the following code: extern XtPointer image; // ptr to XPM Image buffer extern unsigned long numBytes; // num bytes of Image data Atom xaCLIPBOARD = cnp->clipboardAtom(); Atom xaXPM = XmInternAtom(dpy, "XPM", False); cnp->clear(xaCLIPBOARD); // clear clipboard cnp->putCopy(xaCLIPBOARD, xaXPM, image, numBytes); cnp->export(xaCLIPBOARD); // make it available Now any application on your desktop is able to "Paste" the data (assuming of course that the destination application has implemented standard X- Window Copy and Paste). To make this data available on the PRIMARY selection, you could simply substitute xaCLIPBOARD with XA_PRIMARY (or cnp->primaryAtom()). PASTE - In your application, let's imagine that the user has selected the Paste menu item from the Edit menu, and that you are willing to paste either a GIF Image or an XPM Image. In the menu Callback, you might put the following code: XtPointer image; unsigned long numBytes; Atom targetRet; Atom xaCLIPBOARD = cnp->clipboardAtom(); Atom xaGIF = XmInternAtom(dpy, "GIF_89", False); Atom xaXPM = XmInternAtom(dpy, "XPM", False); Atom interestList[2]; interestList[0] = xaGIF_89; // we first prefer GIF Image interestList[1] = xaXPM; // we also accept XPM Image int numItemsInList = 2; image = cnp->importImmediate(xaCLIPBOARD, interestList, numItemsInList, &targetRet, &numBytes); if (image == NULL) printf("No Images available."); else if (targetRet == xaGIF) printf("We received a GIF Image."); else if (targetRet == xaXPM) printf("We received an XPM Image."); The image that is returned should eventually be freed with "XtFree(image);" The list of "targets" you are willing to accept can be arbitrarily long, and just happens to be "2" in this example. DRAG - In your application, let's imagine that the user has just pressed a mouse button down on an XPM Image and has begun dragging it out of your application to be dropped on another application. At the moment you want the drag to begin, you might put the following code: extern XtPointer image; // ptr to XPM Image data extern unsigned long numBytes; // num bytes of Image data extern XEvent *xev; // X-event causing drag extern Widget theWidget; // widget where drag begins Atom xaXPM = XmInternAtom(dpy, "XPM", False); cnp->dragAwayCopy(theWidget, xev, xaXPM, image, numBytes); The "dragAwayCopy" makes a copy of your data, and so you can free the image data immediately after the call. There are two optional parameters that are not usually specified, but if you wish to know when the dragAway is finished, or if the dragAway was successful or not, you can pass in a callback procedure and any data you like. This would look like: // dragAwayCB is invoked after completion of the dragAway // void dragAwayCB(Widget w, Boolean dragSuccess, XtPointer clientData) { printf("Drag success=%d.", dragSuccess); printf("ClientData=%d.", clientData); } cnp->dragAwayCopy(theWidget, xev, xaXPM, image, numBytes, dragAwayCB, (XtPointer) 123); DROP - In your application, let's imagine that you want to accept a "drop" on a certain widget of either an XPM Image or a GIF Image. After you create the widget that will be "dropped" on, you might write the following code: Atom xaXPM = XmInternAtom(dpy, "XPM", False); Atom xaGIF = XmInternAtom(dpy, "GIF_89", False); // dropProcCB - invoked whenever anyone drops an image // on the widget // void dropProcCB(Widget w, Atom target, XtPointer data, unsigned long numBytes, int x, int y, XtPointer clientData) { if (target == xaXPM) printf("XPM Image dropped at x=%d, y=%d.", x, y); else if (target == xaGIF) printf("GIF Image dropped at x=%d, y=%d.", x, y); // eventually you should "XtFree(data)" to free the mem } // this code is done once, and makes the indicated widget // a "DropSite" // extern Widget theWidget; // the widget that is // to become a dropSite Atom interestList[2]; interestList[0] = xaXPM; // we first prefer XPM interestList[1] = xaGIF_89; // we also accept GIF int numItemsInList = 2; cnp->registerDropSite(theWidget, interestList, numItemsInList, dropProcCB, (XtPointer) 123); The list of "targets" you accept on the DropSite can be arbitrarily long, and just happens to be "2" in this example. ADVANCED EXAMPLES The above examples show the most simple uses of the VkCutPaste library. However, we support much more functionality for those programmers who wish to customize the behavior in some way, or have additional needs. REGISTERING CONVERTERS - The VkCutPaste library provides integral support for converters. It has unified the interface, so that once the programmer registers one converter, it will convert for Drag, Drop, Copy and Paste invisibly. The example code below places only an XPM Image on the clipboard, yet the VkCutPaste class offers up both the XPM Image and also a GIF Image, because the appropriate converter has been registered. Atom xaXPM = XmInternAtom(dpy, "XPM", False); Atom xaGIF = XmInternAtom(dpy, "GIF_89", False); Atom xaCLIPBOARD = cnp->clipboardAtom(); extern XtPointer image; // ptr to XPM Image buffer extern unsigned long numBytes; // num bytes of Image data Boolean convertXPMtoGIF(Widget w, Atom selection, void *clientData, Atom srcTarget, XtPointer src, unsigned long numSrcBytes, Atom dstTarget, XtPointer *dst, unsigned long *numDstBytes) { // code to convert from XPM Image to GIF omitted, but // this will malloc space for the dst image, and set // *numDstBytes to indicate the number of bytes // malloc'ed, and set *dst to point at the new image } cnp->registerConverter(xaXPM, xaGIF, convertXPMtoGIF); cnp->clear(xaCLIPBOARD); // clear clipboard cnp->putCopy(xaCLIPBOARD, xaXPM, image, numBytes); cnp->export(xaCLIPBOARD); // make it available At this point, if any other application asks us for a GIF Image, we will supply it by calling the convertXPMtoGIF() converter function on the fly. Also, if we ask specifically to import a GIF at this point with the following code: image = cnp->importImmediate(xaCLIPBOARD, &xaGIF, 1, &targetRet, &numBytes); then we will successfully get a GIF Image even if the remote client is only offering a XPM Image. The converter will fire during the "importImmediate()" call to supply us with the correct data. This same converter will fire automatically now on DragAway calls and also on Drop calls. FILE AND DATA OWNERSHIP The pseudocode below details the ownership of files and data during different stages of cut/paste and drag/drop. The examples show copy/paste and drag/drop of stream data, and of filename data. Filename data simply means the data that is transfered is a filename. For example, when transferring a XPM_FILE target, the data transferred is actually the filename, not the data contained in the file. The receiving application will need to retrieve the filename, then access the file. The VkCutPaste class will only recognize targets as being filename targets if they have been registered with the CUTPASTE_FILENAME_TYPE flag (see registerDataType()). See the "REGISTERED TARGETS" section below for a list of targets which have been pre-registered. A note on filename targets It should be noted that applications should rarely need to use filename targets for cut/paste and drag/drop operations. In fact exchanging filenames with other applications simply WILL NOT WORK when the sender and receiver applications are running on different computers. When given a choice between filename targets and the corresponding data stream targets, applications should always exchange the data stream targets. In the examples below, cnp is an instance of the VkCutPaste class, and filename target is any target which has been registered with the CUTPASTE_FILENAME_TYPE flag (see registerDataType()). Copy of Filenames: // // Create a file on disk. Ownership of the file will be transferred // to the VkCutPaste class at putCopy() time. // char *filename = create a file, return the malloc'ed filename; // // Clear any prior putCopy() or export(). // cnp->clear(); // // Copies the filename 'filename', and transfers the ownership of the // file on disk to the VkCutPaste class. Note that the file itself // is NOT copied, only the filename. The client can now free the // memory used by filename, but must NOT reference the disk file // again. // cnp->putCopy(filename); // // The VkCutPaste class has made a copy of the filename, so the // original data should be freed by the client. // free(filename); // // Make the data available to other clients. // cnp->export(); ... // // Some time later, if the VkCutPaste class gets a request for this // filename, the VkCutPaste class will clone the file, and hand off to // the requesting client the cloned filename. Ownership of this // cloned file is transferred to the requesting client. // ... // // The next time clear() is called, any data that has been copied // during prior putCopy() calls is freed, and any files that the // VkCutPaste class has obtained ownership of during prior putCopy() // calls are removed. After this clear(), this VkCutPaste instance // no longer has any data available for export. // cnp->clear(); Copy of Stream Data: // // Create some data in memory. // char *data = create some data; // // Clear any prior putCopy() or export(). // cnp->clear(); // // The VkCutPaste class makes a copy of the data. This copy of // the data will be freed during the next "clear()" operation. // cnp->putCopy(data); // // The VkCutPaste class has made a copy of the data, so the original // data should be freed by the client. // free(data); // // Make the data available to other clients. // cnp->export(); ... // // The next time clear() is called, any data that has been copied // during prior putCopy() calls is freed, and any files that the // VkCutPaste class has obtained ownership of during prior // putCopy() calls are removed. After this clear(), this // VkCutPaste instance no longer has any data available for export. // cnp->clear(); Paste of Filenames: // // Client requests a filename target. The filename returned and // the corresponding file on disk are now owned by this client. It // is therefore the responsibility of the requesting client to remove // (unlink()) the file when the client is finished with it, and // free the filename. // cnp->importImmediate(filename); // // After this client is done with the file, the file must be // removed, and the filename freed. // unlink(filename); free(filename); Paste of Stream Data: // // Client requests the data. This data is now owned by this // client. The client will use data, and should free it when // it is done processing the data. // cnp->importImmediate(data); // // Free the imported data when you are done processing it. // free(data); Drag of Filenames: // // Create a file on disk. Ownership of the file will be // transferred to the VkCutPaste class at dragAwayCopy() time. // char *filename = create a file, return the malloc'ed filename; // // Copies the filename 'filename', and transfers the ownership of the // file on disk to the VkCutPaste class. Note that the file itself // is NOT copied, only the filename. The client can now free the // memory used by filename, but must NOT reference the disk file // again. The VkCutPaste class will free this copy of the data, and // remove the file when the drag and drop operation is complete. // cnp->dragAwayCopy(filename); // // The VkCutPaste class has made a copy of the filename, so the // original data should be freed by the client. // free(filename); ... // // Some time later, if the VkCutPaste class gets a request for this // filename, the VkCutPaste class will clone the file, and hand off // the cloned filename to the requesting client. Ownership of this // cloned file is transferred to the requesting client. The // original file is removed when the drag and drop operation is // complete. // Drag of Stream Data: // // Create some data in memory. // char *data = create some data; // // The VkCutPaste class makes a copy of the data. The VkCutPaste // class will free this copy of the data when the drag and drop // operation is complete. // cnp->dragAwayCopy(data); // // The client can now free the original data. // free(data); Drop of Filenames: // // The "drop" client registers a drop site. // cnp->registerDropSite(dropFilenameCallback); ... // // Some time later, the dropFilenameCallback() routine is called. // Inside of the dropFilenameCallback, the filename passed in and // the corresponding file on disk are now owned by this client. It // is therefore the responsibility of the requesting client to remove // (unlink()) the file when the client is finished with it, and free // the filename. // dropFilenameCallback(filename) { // Do some processing on the file. unlink(filename); // After this client is done with // the file, the file must be removed, free(filename); // and the filename freed. } Drop of Stream Data: // // The "drop" client registers a drop site. // cnp->registerDropSite(dropDataCallback); ... // // Some time later, the dropDataCallback() routine is called. // dropDataCallback(data) { // Do some processing with this data. // // Free the data when you are done processing it. // free(data); } REGISTERED TARGETS Filename Targets AIFF_C_FILE, AIFF_FILE, APPLE_QUICKTIME_FILE, AUTODESK_3DS_FILE, AUTODESK_DXF_FILE, AVID_OMFI_FILE, AVI_FILE, FITS_FILE, GIF_89_FILE, HTML_FILE, IGES_FILE, INVENTOR_2_0_FILE, INVENTOR_2_1_FILE, JFIF_FILE, MPEG_1_AUDIO_FILE, MPEG_1_VIDEO_FILE, NEXT_FILE, PGM_FILE, PHOTO_CD_FILE, PIXAR_RIB_FILE, PNM_FILE, PPM_FILE, SD2_FILE, SGI_AUDIO_FILE, _SGI_AUDIO_FILENAME, SGI_MOVIE_FILE, _SGI_MOVIE_FILENAME, SGI_RGBIMAGE_FILE, _SGI_RGB_IMAGE_FILENAME, SGI_SHOWCASE_FILE, SOFTIMAGE_DSC_FILE, SOFTIMAGE_HRC_FILE, TIFF_FILE, VRML_1_0_FILE, WAVERONT_OBJ_FILE, WAVE_FILE, XPM_FILE Stream Targets AIFF, AIFF_C, APPLE_QUICKTIME, AUTODESK_3DS, AUTODESK_DXF, AVI, AVID_OMFI, BACKGROUND, BITMAP, CLASS, CLIENT_WINDOW, COLORMAP, COMPOUND_TEXT, DECNET_ADDRESS, DRAWABLE, FILE_NAME, FITS, FOREGROUND, GIF_89, HOSTNAME, HOST_NAME, HTML, IGES, INVENTOR, INVENTOR_2_0, INVENTOR_2_1, IP_ADDRESS, JFIF, MPEG_1_AUDIO, MPEG_1_SYSTEMS, MPEG_1_VIDEO, MULTIPLE, NAME, NEXT, ODIF, OWNER_OS, PGM, PHOTO_CD, PIXAR_RIB, PIXMAP, PNM, PPM, SD2, SGI_AUDIO, _SGI_AUDIO, _SGI_ICON, SGI_MOVIE, _SGI_MOVIE, SGI_RGBIMAGE, _SGI_RGB_IMAGE, SGI_SHOWCASE, SOFTIMAGE_DSC, SOFTIMAGE_HRC, STRING, TARGETS, TEXT, TIFF, TIMESTAMP, USER, VRML_1_0, WAVE, WAVERONT_OBJ, XPM AUTHORS VkCutPaste was written by Jim Young and Brian Wilson of Silicon Graphics, Inc. INHERITED MEMBER FUNCTIONS Inherited from VkComponent installDestroyHandler(), removeDestroyHandler(), widgetDestroyed(), setDefaultResources(), getResources(), VkComponent(), manage(), unmanage(), baseWidget(), okToQuit(), _name, _baseWidget, _w, deleteCallback CLASSES USED BY THIS CLASS None SEE ALSO VkComponent, VkApp Inter-Client Communications Conventions Manual, Version 2.0 ViewKit Programmer's Guide The X Window System, DEC Press, Bob Sheifler and Jim Gettys The X Window System Toolkit, DEC Press, Paul Asente and Ralph Swick The OSF/Motif Programmers Reference, Prentice Hall, OSF