/** * * $Header: /cvsroot/lesstif/lesstif/lib/Xm-2.1/CutPaste.c,v 1.1 2004/08/28 19:22:43 dannybackx Exp $ * * Copyright © 1995 Free Software Foundation, Inc. * Copyright © 1995-2001, 2002, 2004 LessTif Development Team * * This file is part of the GNU LessTif Library. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * **/ static const char rcsid[] = "$Header: /cvsroot/lesstif/lesstif/lib/Xm-2.1/CutPaste.c,v 1.1 2004/08/28 19:22:43 dannybackx Exp $"; #include #include #include #include #include #include #include #include #include #include #define UNLOCKED 0 #define LOCKED 1 #define ITEM_INCR 1000 /* * FIX ME: InquireCount and InquireFormat AREN'T FILLED IN FOR THE ICCCM USAGE * OF THE CLIPBOARD, only for the M*tif way. Look for FIX ME. */ /* * internal functions */ static Atom _XmClipboardGetAtomFromId(Display *display, int id); static void _XmClipboardDeleteId(Display *display, int id); static void _XmClipboardDeleteItemLabel(Display *display, Window window, int id); static void _XmClipboardDeleteMarked(Display *display, Window window, XmClipboard * clip); static void _XmClipboardDeleteFormat(Display *display, int id); static int _XmClipboardRegisterFormat(Display *display, char *format_name, int format_len); static void _XmClipboardDeleteFormats(Display *display, Window window, int id); static void _XmClipboardDeleteItem(Display *display, Window window, XmClipboard * clip, unsigned item); static int _XmClipboardGetWindowProperty(Display *display, Window win, Atom item, unsigned **data, int *len, int *type_return, int *format_return, Boolean deleteflag); static Boolean _XmClipboardSearchForWindow(Display *display, Window root, Window window); static Time _XmClipboardGetCurrentTime(Display *display); static Atom _XmClipboardGetAtomFromFormat(Display *display, char *format_name); static Boolean _XmClipboardGetLenFromFormat(Display *display, char *format_name, int *format); static Boolean _XmClipboardWindowExists(Display *display, Window window); static int _XmClipboardFindItem(Display *display, int id, unsigned **data, int *len, int *format_return, unsigned new_item); static Boolean _XmClipboardIsMarkedForDelete(Display *display, XmClipboard * clip, int item); static XmClipboardFormat *_XmClipboardFindFormat(Display *display, XmClipboard * clip, char *format_name, long item_id, int index, int *namelen, int *num_formats, int *format_len); static void _XmClipboardReplaceItem(Display *display, int id, unsigned *data, int len, int mode, int format, Boolean free); static int _XmClipboardRetrieveItem(Display *display, int id, int extra_size, int size, unsigned **data, int *len, int *format_return, unsigned new_item, Boolean truncate); static Boolean _XmClipboardSendMessage(Display *display, Window window, XmClipboardFormat * format, int id); static void _XmAssertClipboardSelection(Display *display, Window window, XmClipboard * clip, Time locktime); static Boolean _XmClipboardGetSelection(Display *display, Window window, char *format_name, XmClipboard * clip, unsigned **data, int *len); static void _XmClipboardMarkItem(Display *display, XmClipboard * clip, unsigned id, Boolean delete_on); static void _XmClipboardSetNextItemId(Display *display, int item_id); static unsigned _XmClipboardGetNewItemId(Display *display); static void _XmClipboardSetAccess(Display *display, Window window); static XmClipboard *_XmClipboardOpen(Display *display, int extra_size); static void _XmClipboardClose(Display *display, XmClipboard * clip); static int _XmClipboardLock(Display *display, Window window); static int _XmClipboardUnlock(Display *display, Window window, Boolean remove_all_locks); static void _XmClipboardEventHandler(Widget widget, XtPointer client_data, XEvent *event, Boolean *dontSwallow); static Window _XmClipboardInitializeSelection(Display *display, XmClipboard * clip, Window window, Time locktime); static Boolean _XmClipboardWeOwnSelection(Display *display, XmClipboard * clip); /******************************* low level ******************************/ static Atom _XmClipboardGetAtomFromId(Display *display, int id) { char buf[128]; if (id == XmCLIP_HEADER) { #if 0 DEBUGOUT(_LtDebug(__FILE__, NULL, "_XmClipboardGetAtomFromId(id=%i, XmCLIP_HEADER -> _XA_MOTIF_CLIP_HEADER)\n", id)); #endif return XmInternAtom(display, _XA_MOTIF_CLIP_HEADER, False); } else if (id == XmCLIP_NEXT_ID) { #if 0 DEBUGOUT(_LtDebug(__FILE__, NULL, "_XmClipboardGetAtomFromId(id=%i, XmCLIP_NEXT_ID -> _XA_MOTIF_CLIP_NEXT_ID)\n", id)); #endif return XmInternAtom(display, _XA_MOTIF_CLIP_NEXT_ID, False); } sprintf(buf, _XA_MOTIF_CLIP_ITEM_N, id); #if 0 DEBUGOUT(_LtDebug(__FILE__, NULL, "_XmClipboardGetAtomFromId(id=%i -> %s)\n", id, buf)); #endif return XmInternAtom(display, buf, False); } static Boolean _XmClipboardIsMarkedForDelete(Display *display, XmClipboard * clip, int item) { Boolean ret; unsigned *data; int len; Atom hdr; if (item == 0) { hdr = XmInternAtom(display, _XA_MOTIF_CLIP_HEADER, False); XDeleteProperty(display, DefaultRootWindow(display), hdr); _XmWarning(NULL, "Item label is missing!"); return False; } _XmClipboardFindItem(display, item, &data, &len, NULL, XmCLIP_PROP_ITEM); if (data == NULL) { _XmWarning(NULL, "_XmClipboardIsMarkedForDelete: " "_XmClipboardFindItem returned NULL data\n"); return True; /* ??? FIX ME */ } ret = ((XmClipboardItem *) data)->marked_for_delete; XtFree((char *)data); return ret; } static void _XmClipboardDeleteId(Display *display, int id) { Atom atom; atom = _XmClipboardGetAtomFromId(display, id); XDeleteProperty(display, DefaultRootWindow(display), atom); } static void _XmClipboardDeleteItemLabel(Display *display, Window window, int id) { unsigned *data; int len, status; XmClipboardItem *item; Atom hdr; status = _XmClipboardFindItem(display, id, &data, &len, NULL, XmCLIP_PROP_ITEM); if (status == XmClipboardFail) { return; } if (data == NULL) { hdr = XmInternAtom(display, _XA_MOTIF_CLIP_HEADER, False); XDeleteProperty(display, DefaultRootWindow(display), hdr); _XmWarning(NULL, "Item label is missing!"); return; } item = (XmClipboardItem *) data; _XmClipboardDeleteId(display, item->label_id); XtFree((char *)item); } static int _XmClipboardRegisterFormat(Display *display, char *format_name, int format_len) { Atom fmt; int flen; fmt = _XmClipboardGetAtomFromFormat(display, format_name); if (_XmClipboardGetLenFromFormat(display, format_name, &flen)) { if (flen == format_len) { return XmClipboardSuccess; } else { return XmClipboardFail; } } XChangeProperty(display, DefaultRootWindow(display), fmt, fmt, 32, PropModeReplace, (unsigned char *)&format_len, 1); return XmClipboardSuccess; } static void _XmClipboardDeleteFormat(Display *display, int id) { unsigned *data, *idata; int len, ilen, item_id; Atom hdr; XmClipboardFormat *format; XmClipboardItem *item; _XmClipboardFindItem(display, id, &data, &len, NULL, XmCLIP_PROP_FORMAT); if (data == NULL) { hdr = XmInternAtom(display, _XA_MOTIF_CLIP_HEADER, False); XDeleteProperty(display, DefaultRootWindow(display), hdr); _XmWarning(NULL, "Format is missing in delete format"); return; } format = (XmClipboardFormat *) data; if (format->by_name || format->marked_for_delete != 0) { return; } item_id = format->item_id; _XmClipboardFindItem(display, item_id, &idata, &ilen, NULL, XmCLIP_PROP_ITEM); if (idata == NULL) { hdr = XmInternAtom(display, _XA_MOTIF_CLIP_HEADER, False); XDeleteProperty(display, DefaultRootWindow(display), hdr); _XmWarning(NULL, "Item is missing in delete format"); return; } item = (XmClipboardItem *) idata; item->del_format_count++; if (item->del_format_count == item->format_count) { item->marked_for_delete = True; } format->marked_for_delete = True; _XmClipboardReplaceItem(display, id, data, len, PropModeReplace, 32, True); _XmClipboardReplaceItem(display, item_id, idata, ilen, PropModeReplace, 32, True); } static void _XmClipboardDeleteFormats(Display *display, Window window, int id) { unsigned *data, *addr, *fdata; int len, i; Atom hdr; XmClipboardItem *item; DEBUGOUT(_LtDebug(__FILE__, NULL, "_XmClipboardDeleteFormats\n")); _XmClipboardFindItem(display, id, &data, &len, NULL, XmCLIP_PROP_ITEM); if (data == NULL) { hdr = XmInternAtom(display, _XA_MOTIF_CLIP_HEADER, False); XDeleteProperty(display, DefaultRootWindow(display), hdr); _XmWarning(NULL, "Can't find item to delete formats for"); return; } item = (XmClipboardItem *) data; addr = (unsigned *)((char *)item + item->item_size); for (i = 0; i < item->format_count; i++) { XmClipboardFormat *format; _XmClipboardFindItem(display, *addr, &fdata, &len, NULL, XmCLIP_PROP_FORMAT); if (fdata == NULL) { hdr = XmInternAtom(display, _XA_MOTIF_CLIP_HEADER, False); XDeleteProperty(display, DefaultRootWindow(display), hdr); _XmWarning(NULL, "Can't find item to delete formats for"); return; } format = (XmClipboardFormat *) fdata; if (format->by_name) { _XmClipboardSendMessage(display, window, format, XmCLIP_NEXT_ID); } _XmClipboardDeleteId(display, format->data_id); _XmClipboardDeleteId(display, format->format_id); XtFree((char *)format); *addr = 0; addr++; } XtFree((char *)data); } static void _XmClipboardDeleteItem(Display *display, Window window, XmClipboard * clip, unsigned item) { unsigned *addr = (unsigned *)((char *)clip + clip->clip_size), *addr2; int idx, pos, lpos, extra; Boolean last; if (clip->item_count == 0) { return; } addr2 = addr; last = False; pos = 0; idx = 0; extra = 0; while (idx < clip->item_count) { idx++; if (*addr == item) { last = True; pos = idx - 2; addr++; } else { last = False; *addr2 = *addr; addr++; addr2++; } } *addr2 = 0; addr = (unsigned *)((char *)clip + clip->clip_size); clip->item_count--; if (item == clip->current_item) { if (last) { pos--; } lpos = pos; if (pos >= 0) { while (pos > 0) { addr2 = addr + pos; if (_XmClipboardIsMarkedForDelete(display, clip, *addr2)) { extra = *addr2; break; } else { pos--; } } } if (extra == 0) { pos = lpos; addr2 = addr + pos; while (pos < clip->item_count) { if (_XmClipboardIsMarkedForDelete(display, clip, *addr2)) { extra = *addr2; break; } else { pos++; } addr2++; } clip->current_item = extra; } else { clip->current_item = extra; } clip->last_item = 0; } _XmClipboardDeleteItemLabel(display, window, item); _XmClipboardDeleteFormats(display, window, item); _XmClipboardDeleteId(display, item); } static void _XmClipboardDeleteMarked(Display *display, Window window, XmClipboard * clip) { unsigned *item; int i; item = (unsigned *)((char *)clip + clip->clip_size); for (i = 0; i < clip->item_count; i++) { if (_XmClipboardIsMarkedForDelete(display, clip, *item)) { _XmClipboardDeleteItem(display, window, clip, *item); } } } static int _XmClipboardGetWindowProperty(Display *display, Window win, Atom item, unsigned **data, int *len, int *type_return, int *format_return, Boolean deleteflag) { long transfersize; long offset; Atom actual_type; int actual_format; unsigned long nitems, alloc_size, alloc_incr; unsigned long bytes_after = 1; unsigned char *prop; unsigned *ret_buf; Bool req_delete=False; transfersize = XMaxRequestSize(display); *data = NULL; *len = 0; ret_buf = (unsigned *)XtMalloc(8); /* minimum size */ ret_buf[0] = 0; offset = 0; alloc_size = 0; while (bytes_after) { if (XGetWindowProperty(display, win, item, offset, transfersize, req_delete, AnyPropertyType, &actual_type, &actual_format, &nitems, &bytes_after, &prop) != Success) { XtFree((char *)ret_buf); return XmClipboardFail; } if (prop == NULL || nitems == 0) { if (deleteflag) { XDeleteProperty(display, win, item); } if (prop) { XFree(prop); } XtFree((char *)ret_buf); #if 0 DEBUGOUT(_LtDebug(__FILE__, NULL, "_XmClipboardGetWindowProperty: XmClipboardFail (alloc_size %d)\n", alloc_size)); #endif return XmClipboardFail; } switch (actual_format) { case 32: alloc_incr = nitems << 2; break; case 16: alloc_incr = nitems << 1; break; case 8: default: alloc_incr = nitems; break; } ret_buf = (unsigned *)XtRealloc((char *)ret_buf, alloc_size + alloc_incr + 1); memcpy(&ret_buf[offset], prop, alloc_incr); alloc_size += alloc_incr; switch (actual_format) { case 32: offset += nitems; break; case 16: offset += nitems >> 1; break; case 8: default: offset += nitems >> 2; break; } XFree(prop); } ((char *)ret_buf)[alloc_size] = 0; *data = ret_buf; *len = alloc_size; if (deleteflag) { XDeleteProperty(display, win, item); } if (format_return) { *format_return = actual_format; } if (type_return) { *type_return = actual_type; } #if 0 DEBUGOUT(_LtDebug(__FILE__, NULL, "_XmClipboardGetWindowProperty: XmClipboardSuccess (alloc_size %d)\n", alloc_size)); #endif return XmClipboardSuccess; } static Boolean _XmClipboardSearchForWindow(Display *display, Window root, Window window) { Window rootret; Window parent = None; Window *children = NULL; unsigned int nchildren = 0, i; Boolean found; if (XQueryTree(display, root, &rootret, &parent, &children, &nchildren) == 0) { return False; } found = False; for (i = 0; i < nchildren; i++) { if (children[i] == window) { found = True; } else { found = _XmClipboardSearchForWindow(display, children[i], window); } if (found) { break; } } if (children) { XFree(children); } return found; } static Time _XmClipboardGetCurrentTime(Display *display) { Window root; Atom time; XEvent event; root = DefaultRootWindow(display); XSelectInput(display, root, PropertyChangeMask); time = XmInternAtom(display, _XA_MOTIF_CLIP_TIME, False); XChangeProperty(display, root, time, time, 8L, PropModeAppend, NULL, 0); XWindowEvent(display, root, PropertyChangeMask, &event); return event.xproperty.time; } static Bool _XmClipboardDataIsReady(Display *display, XEvent *event, XPointer arg) { XDestroyWindowEvent *dev = (XDestroyWindowEvent *) event; XmMatchFormat *match = (XmMatchFormat *) arg; unsigned *data; int len; Boolean ret = False; if (event->type == DestroyNotify && dev->window == match->window) { match->window = None; return True; } else if (event->type == PropertyNotify) { _XmClipboardFindItem(display, match->id, &data, &len, NULL, XmCLIP_PROP_FORMAT); ret = !((XmClipboardFormat *) data)->by_name; XtFree((char *)data); return ret; } return False; } static Boolean _XmClipboardRequestDataAndWait(Display *display, Window win, XmClipboardFormat * format) { XWindowAttributes attr; Window root = DefaultRootWindow(display); XEvent event; XmMatchFormat arg; int status; DEBUGOUT(_LtDebug(__FILE__, NULL, "_XmClipboardRequestDataAndWait\n")); XGetWindowAttributes(display, root, &attr); XSelectInput(display, root, PropertyChangeMask | StructureNotifyMask); if (!_XmClipboardSendMessage(display, win, format, XmCLIP_HEADER)) { XSelectInput(display, root, attr.your_event_mask); return False; } arg.window = win; arg.id = format->format_id; status = XCheckIfEvent(display, &event, _XmClipboardDataIsReady, (XPointer)&arg); if (arg.window == None) { return False; } if (status) { XIfEvent(display, &event, _XmClipboardDataIsReady, (XPointer)&arg); } if (arg.window == None) { return False; } XSelectInput(display, root, attr.your_event_mask); return True; } static Boolean _XmClipboardWindowExists(Display *display, Window window) { Window root; Atom atom, rettype; int fmtret; unsigned long nitems; unsigned long bytes_after; unsigned char *prop; Boolean found = True; root = DefaultRootWindow(display); if (!_XmClipboardSearchForWindow(display, root, window)) { return False; } atom = XmInternAtom(display, _XA_MOTIF_CLIP_LOCK_ACCESS_VALID, False); XGetWindowProperty(display, window, atom, 0L, 10000000L, False, AnyPropertyType, &rettype, &fmtret, &nitems, &bytes_after, &prop); if (!prop) { found = False; } if (!nitems) { found = False; } if (prop) { XFree(prop); } return found; } static int _XmClipboardFindItem(Display *display, int id, unsigned **data, int *len, int *format_return, unsigned prop_id) { Atom item, hdr; Window root; int status; root = DefaultRootWindow(display); item = _XmClipboardGetAtomFromId(display, id); status = _XmClipboardGetWindowProperty(display, root, item, data, len, NULL, format_return, False); if (status != XmClipboardSuccess) { return status; } if (prop_id == XmCLIP_PROP_DONT_CARE) { return XmClipboardSuccess; } if (prop_id == (*data)[0]) { return XmClipboardSuccess; } XtFree((char *)*data); hdr = XmInternAtom(display, _XA_MOTIF_CLIP_HEADER, False); XDeleteProperty(display, root, hdr); _XmWarning(NULL, "ClipboardFindItem failed\n"); return XmClipboardFail; } static XmClipboardFormat * _XmClipboardFindFormat(Display *display, XmClipboard * clip, char *format_name, long item_id, int index, int *namelen, int *num_formats, int *format_len) { unsigned *ldata, *fdata; int llen, status, i, flag; Atom hdr, fmt; XmClipboardItem *item; unsigned *addr; XmClipboardFormat *format; int my_index; *namelen = 0; *num_formats = 0; if (item_id < 0) { return NULL; } if (item_id == 0) { if (clip->item_count == 0) { return NULL; } else { item_id = clip->current_item; } } if (item_id == 0) { return NULL; } status = _XmClipboardFindItem(display, item_id, &ldata, &llen, NULL, XmCLIP_PROP_ITEM); if (status == XmClipboardFail) { return NULL; } if (ldata == NULL) { hdr = XmInternAtom(display, _XA_MOTIF_CLIP_HEADER, False); XDeleteProperty(display, DefaultRootWindow(display), hdr); _XmWarning(NULL, "missing item2"); return NULL; } item = (XmClipboardItem *) ldata; *num_formats = item->format_count - item->del_format_count; if (*num_formats < 0) { *num_formats = 0; } addr = (unsigned *)((char *)item + item->item_size); *format_len = 0; if (format_name == NULL) { fmt = 0L; flag = XmCLIP_PROP_DONT_CARE; DEBUGOUT(_LtDebug(__FILE__, NULL, "_XmClipboardFindFormat(NULL)\n")); } else { fmt = XmInternAtom(display, format_name, False); flag = XmCLIP_PROP_FORMAT; DEBUGOUT(_LtDebug(__FILE__, NULL, "_XmClipboardFindFormat(%s)\n", format_name)); } format = NULL; my_index = 1; for (i = 0; i < item->format_count; i++) { XmClipboardFormat *fitem; Boolean need_free = True; status = _XmClipboardFindItem(display, *addr, &fdata, &llen, NULL, XmCLIP_PROP_FORMAT); if (status == XmClipboardFail) { return NULL; } if (fdata == NULL) { hdr = XmInternAtom(display, _XA_MOTIF_CLIP_HEADER, False); XDeleteProperty(display, DefaultRootWindow(display), hdr); _XmWarning(NULL, "missing item2"); return NULL; } fitem = (XmClipboardFormat *) fdata; if (!fitem->marked_for_delete) { if (*namelen < fitem->name_len) { *namelen = fitem->name_len; } if (flag != XmCLIP_PROP_DONT_CARE) { if (fitem->atom == fmt) { *format_len = llen; format = fitem; need_free = False; } } else if (my_index++ == index) { need_free = False; format = fitem; *format_len = llen; #if 1 } else { need_free = False; format = fitem; *format_len = llen; #endif } } if (need_free) { XtFree((char *)fdata); } addr++; } XtFree((char *)ldata); return format; } static void _XmClipboardReplaceItem(Display *display, int id, unsigned *data, int len, int mode, int format, Boolean free) { Window root; Atom item; int nunits, tstart, tlen; long transferlen; root = DefaultRootWindow(display); item = _XmClipboardGetAtomFromId(display, id); transferlen = XMaxRequestSize(display); switch (format) { case 32: len >>= 2; nunits = transferlen; break; case 16: len >>= 1; nunits = transferlen << 1; break; case 8: default: nunits = transferlen << 2; break; } tstart = 0; do { if (len < nunits) { tlen = len; } else { tlen = nunits; } XChangeProperty(display, root, item, item, format, mode, (unsigned char *)&data[tstart], tlen); len -= tlen; mode = PropModeAppend; tstart += transferlen; } while (len != 0); if (free) { XtFree((char *)data); } } static int _XmClipboardRetrieveItem(Display *display, int id, int extra_size, int size, unsigned **data, int *len, int *format_return, unsigned prop_id, Boolean truncate) { unsigned *ldata, *buf; int llen, status, format; status = _XmClipboardFindItem(display, id, &ldata, &llen, &format, prop_id); if (llen != 0 && status == XmClipboardSuccess) { if (truncate) { llen = 0; } llen += extra_size; *len = llen; } else { *len = size; } buf = (unsigned *)XtMalloc(*len); if (status == XmClipboardSuccess) { memcpy(buf, ldata, *len); } *data = buf; XtFree((char *)ldata); if (format_return) { *format_return = format; } return status; } static unsigned _XmClipboardGetNewItemId(Display *display) { unsigned *data, ret; int len; _XmClipboardFindItem(display, XmCLIP_NEXT_ID, &data, &len, NULL, XmCLIP_PROP_DONT_CARE); ret = data[0]++; _XmClipboardReplaceItem(display, XmCLIP_NEXT_ID, data, len, PropModeReplace, 32, True); return ret; } static Atom _XmClipboardGetAtomFromFormat(Display *display, char *format_name) { char *str; Atom atom; str = XtMalloc(strlen(format_name) + 32); sprintf(str, _XA_MOTIF_CLIP_FORMAT_S, format_name); atom = XmInternAtom(display, str, False); XtFree(str); return atom; } static Boolean _XmClipboardGetLenFromFormat(Display *display, char *format_name, int *format) { Atom actual_type; int actual_format, status; unsigned long nitems; unsigned long bytes_after; unsigned char *prop; Atom atom; Boolean ret = False; atom = _XmClipboardGetAtomFromFormat(display, format_name); status = XGetWindowProperty(display, DefaultRootWindow(display), atom, 0, 10000000L, False, AnyPropertyType, &actual_type, &actual_format, &nitems, &bytes_after, &prop); if (prop == NULL || nitems == 0 || status != Success) { *format = 8; } else { *format = *((int *)(prop)); ret = True; } if (prop) { XFree(prop); } return ret; } static Window _XmClipboardInitializeSelection(Display *display, XmClipboard * clip, Window window, Time locktime) { Atom clipboard; Window clipowner; clipboard = XmInternAtom(display, _XA_CLIPBOARD, False); clipowner = XGetSelectionOwner(display, clipboard); if (clipowner == window && clip->clipboard_selection_owner == None) { XSetSelectionOwner(display, clipboard, None, locktime); clipowner = None; } if (clipowner == None) { _XmAssertClipboardSelection(display, window, clip, locktime); clipowner = XGetSelectionOwner(display, clipboard); } return clipowner; } static Boolean _XmClipboardWeOwnSelection(Display *display, XmClipboard * clip) { Atom clipboard; Window clipowner; clipboard = XmInternAtom(display, _XA_CLIPBOARD, False); clipowner = XGetSelectionOwner(display, clipboard); if (clipowner == clip->clipboard_selection_owner) { return True; } return False; } static void _XmAssertClipboardSelection(Display *display, Window window, XmClipboard * clip, Time locktime) { Widget w; Atom clipboard; clip->copy_lock_time = 0; clip->clipboard_selection_owner = 0; w = XtWindowToWidget(display, window); DEBUGOUT(_LtDebug(__FILE__, w, "_XmAssertClipboardSelection\n")); if (w == NULL || clip->current_item == 0) { return; } clip->copy_lock_time = 0; clip->clipboard_selection_owner = window; clipboard = XmInternAtom(display, _XA_CLIPBOARD, False); XSetSelectionOwner(display, clipboard, window, locktime); XtAddEventHandler(w, None, True, _XmClipboardEventHandler, NULL); } static Bool _XmClipboardSelectionIsReady(Display *display, XEvent *event, XPointer arg) { XmMatchSelection *match = (XmMatchSelection *) arg; Atom ctmp, incr; Boolean have_sel = False; unsigned *data, *buf; int len, type, format, status; ctmp = XmInternAtom(display, _XA_CLIP_TEMPORARY, False); if (event->type == DestroyNotify && event->xdestroywindow.window == match->window) { match->selection_owner = None; return True; } if (event->type == SelectionNotify) { /* could not be converted */ if (event->xselection.property == 0) { return True; } /* conversion ok */ else if (event->xselection.property == ctmp) { match->selection_done = True; have_sel = True; } } if (event->type == PropertyNotify && event->xproperty.atom == ctmp && event->xproperty.state == PropertyNewValue) { have_sel = True; } if (!have_sel || !match->selection_done) { return False; } status = _XmClipboardGetWindowProperty(match->display, match->window, ctmp, &data, &len, &type, &format, True); if (data == NULL || len == 0 || status != XmClipboardSuccess) { return True; } incr = XmInternAtom(display, _XA_INCR, False); if (type == incr) { match->type = type; match->incr = True; return False; } buf = (unsigned *)XtMalloc(len + match->len); memcpy(buf, match->data, match->len); XtFree((char *)match->data); match->data = buf; memcpy((char *)buf + match->len, data, len); XtFree((char *)data); match->len += len; if (match->incr) { return False; } return True; } static Boolean _XmClipboardGetSelection(Display *display, Window window, char *format_name, XmClipboard * clip, unsigned **data, int *len) { Atom format, clipboard, cliptmp; Window clipowner; XWindowAttributes attr, sattr; XmMatchSelection arg; XEvent event; Bool status; format = XmInternAtom(display, format_name, False); clipboard = XmInternAtom(display, _XA_CLIPBOARD, False); clipowner = XGetSelectionOwner(display, clipboard); if (clipowner == None) { return False; } cliptmp = XmInternAtom(display, _XA_CLIP_TEMPORARY, False); XGetWindowAttributes(display, clipowner, &attr); XSelectInput(display, clipowner, attr.your_event_mask | StructureNotifyMask); XGetWindowAttributes(display, window, &sattr); XSelectInput(display, window, sattr.your_event_mask | PropertyChangeMask); XConvertSelection(display, clipboard, format, cliptmp, window, clip->retrieve_lock_time); arg.display = display; arg.window = window; arg.selection_owner = clipowner; arg.retrieve_time = clip->retrieve_lock_time; arg.format_name = format_name; arg.len = 0; arg.data = NULL; arg.incr = False; arg.selection_done = False; status = XCheckIfEvent(display, &event, _XmClipboardSelectionIsReady, (XPointer)&arg); if (arg.selection_owner == None) { XSelectInput(display, window, sattr.your_event_mask); return False; } if (!status) { XIfEvent(display, &event, _XmClipboardSelectionIsReady, (XPointer)&arg); } XSelectInput(display, window, sattr.your_event_mask); if (arg.selection_owner == None) { return False; } XSelectInput(display, clipowner, attr.your_event_mask); *data = arg.data; *len = arg.len; if (*data && *len) { return True; } return False; } static void _XmClipboardSetNextItemId(Display *display, int item_id) { XmClipboard *clip; int cur, last, len, rem; unsigned *data; clip = _XmClipboardOpen(display, 0); cur = clip->current_item; last = clip->last_item; _XmClipboardClose(display, clip); cur--; last--; rem = item_id; for (;;) { rem -= item_id % ITEM_INCR; if (rem > item_id) { rem = ITEM_INCR; } else { rem += ITEM_INCR; } if (rem != cur && rem != last) { break; } } _XmClipboardFindItem(display, XmCLIP_NEXT_ID, &data, &len, NULL, XmCLIP_PROP_DONT_CARE); data[0] = rem; _XmClipboardReplaceItem(display, XmCLIP_NEXT_ID, data, sizeof(int), PropModeReplace, 32, True); } static void _XmClipboardMarkItem(Display *display, XmClipboard * clip, unsigned id, Boolean delete_on) { unsigned *data; int len; Atom hdr; if (id == 0) { return; } _XmClipboardFindItem(display, id, &data, &len, NULL, XmCLIP_PROP_ITEM); if (data == NULL) { hdr = XmInternAtom(display, _XA_MOTIF_CLIP_HEADER, False); XDeleteProperty(display, DefaultRootWindow(display), hdr); _XmWarning(NULL, "missing item when marking for delete"); return; } ((XmClipboardItem *) data)->marked_for_delete = delete_on; _XmClipboardReplaceItem(display, id, data, len, PropModeReplace, 32, True); } static void _XmClipboardSetAccess(Display *display, Window window) { Atom lock_access; lock_access = XmInternAtom(display, _XA_MOTIF_CLIP_LOCK_ACCESS_VALID, False); XChangeProperty(display, window, lock_access, lock_access, 8, PropModeReplace, (unsigned char *)"yes", 3); } static XmClipboard * _XmClipboardOpen(Display *display, int extra_size) { int status, len, dlen; unsigned *data, *id_data, next_id; XmClipboard *clip; status = XmClipboardSuccess; if (!extra_size) { status = _XmClipboardFindItem(display, XmCLIP_HEADER, &data, &len, NULL, XmCLIP_PROP_DONT_CARE); } if (extra_size || status != XmClipboardSuccess) { status = _XmClipboardRetrieveItem(display, XmCLIP_HEADER, extra_size, sizeof(XmClipboard), &data, &len, 0, 0, False); } clip = (XmClipboard *) data; if (status != XmClipboardSuccess) { clip->prop_id = XmCLIP_PROP_HEADER; clip->cpad1 = 0; clip->static_item_count = 1; clip->clip_size = sizeof(XmClipboard); clip->current_item = 0; clip->last_item = 0; clip->next_delete = 0; clip->current_item2 = 0; clip->by_name_id = 0; clip->item_count = 0; clip->clipboard_selection_owner = 0; clip->copy_lock_time = 0; clip->retrieve_lock_time = 0; clip->offset = 0; clip->copy_locked = 0; clip->retrieve_locked = 0; } status = _XmClipboardFindItem(display, XmCLIP_NEXT_ID, &id_data, &dlen, NULL, XmCLIP_PROP_DONT_CARE); if (status != XmClipboardSuccess) { next_id = ITEM_INCR; _XmClipboardReplaceItem(display, XmCLIP_NEXT_ID, &next_id, sizeof(int), PropModeReplace, 32, False); return clip; } XtFree((char *)id_data); return clip; } static void _XmClipboardClose(Display *display, XmClipboard * clip) { _XmClipboardReplaceItem(display, XmCLIP_HEADER, (unsigned *)clip, sizeof(XmClipboard) + clip->item_count * sizeof(unsigned), PropModeReplace, 32, True); } /* * XmClipboardLock locks the clipboard from access by another application until XmClipboardUnlock * is called. All clipboard functions lock and unlock the clipboard to prevent simultaneous access. * This function allows the application to keep the clipboard data from changing between calls to * Inquire and other clipboard functions. The application does not need to lock the clipboard * between calls to XmClipboardStartCopy and XmClipboardEndCopy or to XmClipboardStartRetrieve * and XmClipboardEndRetrieve. * * If the clipboard is already locked by another application, XmClipboardLock returns an error * status. Multiple calls to this function by the same application increase the lock level. */ static int _XmClipboardLock(Display *display, Window window) { Atom lockatom, clipatom, hdr; Window lockowner, clipowner; Boolean need_lock_sel; int len; Time time; XmClipboard *clip; XmClipboardLockRec *lock; lockatom = XmInternAtom(display, _XA_MOTIF_CLIP_LOCK, False); lockowner = XGetSelectionOwner(display, lockatom); if (lockowner != window && lockowner != None) { return XmClipboardLocked; } _XmClipboardFindItem(display, XmCLIP_LOCK, (unsigned **)&lock, &len, NULL, XmCLIP_PROP_DONT_CARE); if (!len) { lock = (XmClipboardLockRec *) XtMalloc(sizeof(XmClipboardLockRec)); lock->lockowner = None; lock->lockdepth = 0; } if (lock->lockdepth == UNLOCKED) { lock->lockowner = window; lock->lockdepth = LOCKED; need_lock_sel = True; } else if (lock->lockowner == window) { lock->lockdepth += LOCKED; need_lock_sel = False; } else { if (_XmClipboardWindowExists(display, lock->lockowner)) { XtFree((char *)lock); return XmClipboardLocked; } clipatom = XmInternAtom(display, _XA_CLIPBOARD, False); clipowner = XGetSelectionOwner(display, clipatom); time = _XmClipboardGetCurrentTime(display); clip = _XmClipboardOpen(display, 0); if (clipowner == clip->clipboard_selection_owner) { XSetSelectionOwner(display, clipatom, None, time); } _XmClipboardClose(display, clip); hdr = XmInternAtom(display, _XA_MOTIF_CLIP_HEADER, False); XDeleteProperty(display, DefaultRootWindow(display), hdr); clip = _XmClipboardOpen(display, 0); _XmClipboardClose(display, clip); lock->lockowner = window; lock->lockdepth = LOCKED; need_lock_sel = True; } if (need_lock_sel) { lockowner = XGetSelectionOwner(display, lockatom); if (lockowner == None) { time = _XmClipboardGetCurrentTime(display); XSetSelectionOwner(display, lockatom, window, time); lockowner = XGetSelectionOwner(display, lockatom); if (lockowner != window) { XtFree((char *)lock); return XmClipboardLocked; } } } _XmClipboardReplaceItem(display, XmCLIP_LOCK, (unsigned *)lock, sizeof(XmClipboardLockRec), PropModeReplace, 32, False); _XmClipboardSetAccess(display, window); XtFree((char *)lock); return XmClipboardSuccess; } static int _XmClipboardUnlock(Display *display, Window window, Boolean remove_all_locks) { Atom lockatom; Window lockowner; int len, status; Time time; XmClipboardLockRec *lock; lockatom = XmInternAtom(display, _XA_MOTIF_CLIP_LOCK, False); lockowner = XGetSelectionOwner(display, lockatom); if (lockowner != window && lockowner != None) { return XmClipboardFail; } status = XmClipboardFail; _XmClipboardFindItem(display, XmCLIP_LOCK, (unsigned **)&lock, &len, NULL, XmCLIP_PROP_DONT_CARE); if (len == 0) return XmClipboardFail; if (lock->lockowner != window) { XtFree((char *)lock); return XmClipboardFail; } if (remove_all_locks) { lock->lockdepth = 0; } else { lock->lockdepth -= LOCKED; } if (lock->lockdepth > UNLOCKED) { len = sizeof(XmClipboardLockRec); } else { status = XmClipboardSuccess; len = 0; } _XmClipboardReplaceItem(display, XmCLIP_LOCK, (unsigned *)lock, len, PropModeReplace, 32, False); XtFree((char *)lock); if (status == XmClipboardSuccess) { time = _XmClipboardGetCurrentTime(display); XSetSelectionOwner(display, lockatom, None, time); } return XmClipboardSuccess; } /* * _XmClipboardEventHandler * * This function is presumably called when another application wants to retrieve * the information that we've placed on the CLIPBOARD. * * FIX ME FIXME Danny */ static void _XmClipboardEventHandler(Widget widget, XtPointer client_data, XEvent *ev, Boolean *dontSwallow) { int fid, pid, status; XClientMessageEvent *event = (XClientMessageEvent *)ev; unsigned *data; int reason, len; XmCutPasteProc cb; #if 1 if (event->type == SelectionClear) { DEBUGOUT(_LtDebug(__FILE__, widget, "_XmClipboardEventHandler(SelectionClear %d no ClientMessage)\n", event->type)); return; } if (event->type == SelectionRequest) { DEBUGOUT(_LtDebug(__FILE__, widget, "_XmClipboardEventHandler(SelectionRequest %d no ClientMessage)\n", event->type)); return; } if (event->type == SelectionNotify) { DEBUGOUT(_LtDebug(__FILE__, widget, "_XmClipboardEventHandler(SelectionNotify %d no ClientMessage)\n", event->type)); return; } #endif if (event->type != ClientMessage) { DEBUGOUT(_LtDebug(__FILE__, widget, "_XmClipboardEventHandler(%d no ClientMessage)\n", event->type)); return; } if (event->message_type != XmInternAtom(event->display, _XA_MOTIF_CLIP_MESSAGE, False)) { DEBUGOUT(_LtDebug(__FILE__, widget, "_XmClipboardEventHandler (not CLIP_MESSAGE)\n")); return; } fid = event->data.l[1]; pid = event->data.l[2]; DEBUGOUT(_LtDebug(__FILE__, widget, "_XmClipboardEventHandler: Find Item\n")); status = _XmClipboardFindItem(event->display, fid, &data, &len, NULL, XmCLIP_PROP_FORMAT); if (status != XmClipboardSuccess) { DEBUGOUT(_LtDebug(__FILE__, widget, "_XmClipboardEventHandler: no XmClipboardSuccess\n")); return; } DEBUGOUT(_LtDebug(__FILE__, widget, "_XmClipboardEventHandler: Found Item\n")); cb = ((XmClipboardFormat *) data)->callback; XtFree((char *)data); if (!cb) { DEBUGOUT(_LtDebug(__FILE__, widget, "_XmClipboardEventHandler: No Callback\n")); return; } if (event->data.l[0] == XmInternAtom(event->display, _XA_MOTIF_CLIP_DATA_REQUEST, False)) { reason = XmCR_CLIPBOARD_DATA_REQUEST; } else if (event->data.l[0] == XmInternAtom(event->display, _XA_MOTIF_CLIP_DATA_DELETE, False)) { reason = XmCR_CLIPBOARD_DATA_DELETE; } else { DEBUGOUT(_LtDebug(__FILE__, widget, "_XmClipboardEventHandler: Bad Atom\n")); return; } (*cb) (widget, &fid, &pid, &reason); if (reason == XmCR_CLIPBOARD_DATA_REQUEST) { DEBUGOUT(_LtDebug(__FILE__, widget, "_XmClipboardEventHandler: Data Request\n")); return; } _XmClipboardFindItem(event->display, XmCLIP_HEADER, &data, &len, NULL, XmCLIP_PROP_DONT_CARE); ((XmClipboard *) data)->by_name_id = 0; _XmClipboardReplaceItem(event->display, XmCLIP_HEADER, data, len, PropModeReplace, 32, True); } static Boolean _XmClipboardSendMessage(Display *display, Window window, XmClipboardFormat * format, int id) { XmClipboard *clip; XClientMessageEvent event; Boolean dummy; unsigned *data; int len; DEBUGOUT(_LtDebug(__FILE__, NULL, "_XmClipboardSendMEssage: %d\n", id)); if (format->widget_window == None) { return False; } event.type = ClientMessage; event.window = format->widget_window; event.display = format->display; event.message_type = XmInternAtom(display, _XA_MOTIF_CLIP_MESSAGE, False); event.format = 32; switch (id) { case XmCLIP_HEADER: _XmClipboardFindItem(display, XmCLIP_HEADER, &data, &len, NULL, XmCLIP_PROP_DONT_CARE); clip = (XmClipboard *) data; clip->by_name_id = format->format_id; _XmClipboardReplaceItem(display, XmCLIP_HEADER, data, len, PropModeReplace, 32, True); /* fall thru */ case XmCLIP_NEXT_ID: event.data.l[0] = XmInternAtom(display, _XA_MOTIF_CLIP_DATA_REQUEST, False); /* fall thru */ default: event.data.l[1] = format->format_id; event.data.l[2] = format->private_id; if (format->window == window && format->display == display) { DEBUGOUT(_LtDebug(__FILE__, NULL, "Call _XmClipboardEventHandler direct\n")); _XmClipboardEventHandler(format->widget, NULL, (XEvent *)&event, &dummy); return True; } else if (_XmClipboardWindowExists(display, format->widget_window)) { XSendEvent(display, format->widget_window, False, 0, (XEvent *)&event); return True; } } return False; } /*************************** public functions **************************/ /* * This is a Motif 1.2 function which is deprecated for 2.* but we'll make * it available in 2.* versions for backwards compatibility nonetheless. * Thus, no * #if XmVERSION == 1 */ extern int XmClipboardBeginCopy(Display *display, Window window, XmString clip_label, Widget widget, VoidProc callback, long *item_id) { return XmClipboardStartCopy(display, window, clip_label, CurrentTime, widget, callback, item_id); } extern int XmClipboardCancelCopy(Display *display, Window window, long item_id) { int status; unsigned *data; int len; XmClipboard *clip; status = _XmClipboardLock(display, window); if (status == XmClipboardLocked) { return status; } _XmClipboardDeleteItemLabel(display, window, item_id); _XmClipboardDeleteFormats(display, window, item_id); _XmClipboardDeleteId(display, item_id); _XmClipboardFindItem(display, XmCLIP_NEXT_ID, &data, &len, NULL, XmCLIP_PROP_DONT_CARE); data[0]--; _XmClipboardReplaceItem(display, XmCLIP_NEXT_ID, data, sizeof(int), PropModeReplace, 32, True); clip = _XmClipboardOpen(display, 0); clip->copy_locked = UNLOCKED; _XmClipboardClose(display, clip); _XmClipboardUnlock(display, window, False); return XmClipboardSuccess; } /* * XmClipboardCopy copies a data item to temporary storage. The data item is moved from * temporary storage to the clipboard data structure when a call to XmClipboardEndCopy * is made. Additional calls to XmClipboardCopy before a call to XmClipboardEndCopy add * additional data item formats to the same data item or append data to an existing format. * Formats are described in the Inter-Client Communication Conventions Manual (ICCCM) as targets. * * NOTE: Do not call XmClipboardCopy before a call to XmClipboardStartCopy has been made. * The latter function allocates temporary storage required by XmClipboardCopy. * * If the buffer argument is NULL, the data is considered to be passed by name. When data * that has been passed by name is later requested by another application, the application * that owns the data receives a callback with a request for the data. The application that * owns the data must then transfer the data to the clipboard with the XmClipboardCopyByName * function. When a data item that was passed by name is deleted from the clipboard, the * application that owns the data receives a callback stating that the data is no longer needed. * * For information on the callback function, see the callback argument description * for XmClipboardStartCopy. */ extern int XmClipboardCopy(Display *display, Window window, long item_id, char *format_name, XtPointer buffer, unsigned long length, long private_id, long *data_id) { XmClipboard *clip; int status, formatlen, namelen, numformats, ilen, fmt; unsigned int *fdata, *idata; XmClipboardItem *item; XmClipboardFormat *format; unsigned long buflen; XtPointer nbuf; Widget w = XtWindowToWidget(display, window); DEBUGOUT(if (strcmp(format_name, "STRING") == 0) { _LtDebug(__FILE__, w, "XmClipboardCopy(win 0x%X, item_id %ld, format %s) [%s]\n", window, item_id, format_name, buffer); } else { _LtDebug(__FILE__, w, "XmClipboardCopy(win 0x%X, item_id %ld, format %s)\n", window, item_id, format_name); }); status = _XmClipboardLock(display, window); if (status == XmClipboardLocked) { return status; } clip = _XmClipboardOpen(display, 0); if (clip->copy_locked == UNLOCKED) { _XmWarning(NULL, "Attempt to copy to unlocked clipboard!"); _XmClipboardUnlock(display, window, False); return XmClipboardFail; } format = _XmClipboardFindFormat(display, clip, format_name, item_id, 0, &namelen, &numformats, &formatlen); if (format == NULL) { int fid1, fid2; status = _XmClipboardRetrieveItem(display, item_id, sizeof(int), 0, &idata, &ilen, NULL, XmCLIP_PROP_ITEM, False); if (status != XmClipboardSuccess) { return status; } item = (XmClipboardItem *) idata; item->format_count++; if (((item->format_count + 1) * 2) >= ITEM_INCR) { _XmWarning(NULL, "Too many formats for item."); XtFree((char *)idata); _XmClipboardUnlock(display, window, False); } format = (XmClipboardFormat *) XtMalloc(sizeof(XmClipboardFormat)); formatlen = sizeof(XmClipboardFormat); fid1 = _XmClipboardGetNewItemId(display); fid2 = _XmClipboardGetNewItemId(display); idata[ilen / sizeof(int) - 1] = fid1; format->prop_id = XmCLIP_PROP_FORMAT; format->atom = XmInternAtom(display, format_name, False); format->length = 0; format->name_len = strlen(format_name); format->format_id = fid1; format->data_id = fid2; format->marked_for_delete = 0; format->private_id = private_id; format->offset = 0; format->item_id = item_id; format->widget = item->widget; format->widget_window = item->widget_window; format->callback = item->callback; format->window = item->window; format->display = item->display; if (buffer == NULL) { format->by_name = 1; item->by_name = 1; buflen = sizeof(int); } else { format->by_name = 0; buflen = length; } _XmClipboardReplaceItem(display, item_id, idata, ilen, PropModeReplace, 32, True); status = _XmClipboardGetLenFromFormat(display, format_name, &fmt); if (status == XmClipboardFail) { XmClipboardRegisterFormat(display, format_name, 0); _XmClipboardGetLenFromFormat(display, format_name, &fmt); } nbuf = XtMalloc(buflen); } else { status = _XmClipboardRetrieveItem(display, format->data_id, length, 0, &fdata, (int *)&buflen, &fmt, XmCLIP_PROP_DONT_CARE, False); nbuf = (char *)fdata + buflen - length; } if (buffer) { memcpy(nbuf, buffer, length); } format->length += length; _XmClipboardReplaceItem(display, format->data_id, (unsigned *)nbuf, buflen, PropModeReplace, fmt, True); _XmClipboardReplaceItem(display, format->format_id, (unsigned *)format, formatlen, PropModeReplace, 32, True); if (data_id) { *data_id = format->format_id; } _XmClipboardClose(display, clip); _XmClipboardUnlock(display, window, False); return XmClipboardSuccess; } /* * XmClipboardCopyByName copies the actual data for a data item that was previously passed * by name to the clipboard. Data is considered to be passed by name when a call to * XmClipboardCopy is made with a NULL buffer parameter. Additional calls to this function * append new data to the existing data. * * window * Specifies the window ID of a widget that relates the application window to the * clipboard. The widget's window ID can be obtained through XtWindow. The same * application instance should pass the same window ID to each clipboard function * it calls. * * data_id * Specifies an identifying number assigned to the data item that uniquely identifies * the data item and the format. This number was assigned by XmClipboardCopy to the * data item. * * buffer * Specifies the buffer from which the clipboard copies the data. * * length * Specifies the number of bytes in the data item. * * private_id * Specifies the private data that the application wants to store with the data item. * * RETURN * XmClipboardSuccess * The function was successful. * * XmClipboardLocked * The function failed because the clipboard was locked by another application. * The application can continue to call the function again with the same * parameters until the lock goes away. This gives the application the * opportunity to ask if the user wants to keep trying or to give up on * the operation. */ extern int XmClipboardCopyByName(Display *display, Window window, long data_id, XtPointer buffer, unsigned long length, long private_id) { unsigned *data, *idata, *fdata; int len, status, ilen, flen, fmt; XmClipboard *clip; Boolean not_in_progress = False; XmClipboardFormat *format; unsigned char *bufstart; _XmClipboardFindItem(display, XmCLIP_HEADER, &data, &len, NULL, XmCLIP_PROP_DONT_CARE); clip = (XmClipboard *) data; if (clip->by_name_id != data_id) { status = _XmClipboardLock(display, window); if (status == XmClipboardLocked) { return status; } not_in_progress = True; } else { clip->by_name_id = 0; _XmClipboardReplaceItem(display, XmCLIP_HEADER, data, len, PropModeReplace, 32, False); } status = _XmClipboardFindItem(display, data_id, &fdata, &flen, NULL, XmCLIP_PROP_FORMAT); if (status == XmClipboardSuccess) { format = (XmClipboardFormat *) fdata; format->private_id = private_id; if (format->by_name) { format->length = length; } else { format->length += length; } _XmClipboardRetrieveItem(display, format->data_id, length, 0, &idata, &ilen, &fmt, XmCLIP_PROP_DONT_CARE, format->by_name); format->by_name = 0; bufstart = (unsigned char *)idata + ilen - length; memcpy(bufstart, buffer, length); _XmClipboardReplaceItem(display, format->data_id, idata, ilen, PropModeReplace, fmt, True); _XmClipboardReplaceItem(display, data_id, fdata, flen, PropModeReplace, 32, True); } if (not_in_progress) { _XmClipboardUnlock(display, window, False); } XtFree((char *)data); return XmClipboardSuccess; } /* Danny */ /* * Deal with the Xt (ICCCM) style CLIPBOARD mechanisms. * These are used e.g. in xclipboard. * * All the data we pass back to our caller will be freed (with XtFree) by Xt, * because we've not registered a DoneProc (in the call of XtOwnSelection). * * The format argument returns the SIZE IN BITS of each element of value. * The length argument returns the length in the units as indicated by format. */ static Boolean _XmConvertSelectionICCCM(Widget w, Atom *selection, Atom *target, Atom *type, XtPointer *value, unsigned long *length, int *format) { Display *d = XtDisplay(w); XSelectionRequestEvent *req = XtGetSelectionRequest(w, *selection, (XtRequestId)NULL); Atom A_Targets = XmInternAtom(d, XmSTARGETS, False), A_ListLength = XmInternAtom(d, "LIST LENGTH", False), A_CharacterPosition = XmInternAtom(d, "CHARACTER POSITION", False), A_String = XmInternAtom(d, "STRING", False), A_Text = XmInternAtom(d, XmSTEXT, False), A_CompoundText = XmInternAtom(d, "COMPOUND TEXT", False), A_Integer = XmInternAtom(d, "INTEGER", False), A_Span = XmInternAtom(d, "SPAN", False), A_Length = XmInternAtom(d, XmSLENGTH, False); unsigned int *data, datalen; DEBUGOUT(_LtDebug(__FILE__, w, "_XmConvertSelectionICCCM\n")); /* * TARGETS : tell the requester which targets we can cope with. */ if (*target == A_Targets) { Atom* targetP; DEBUGOUT(_LtDebug(__FILE__, w, "_XmConvertSelectionICCCM(TARGETS) -> 6 targets\n")); *value = XtMalloc(sizeof(Atom)* 6); targetP = *(Atom**)value; *targetP++ = A_String; *targetP++ = A_Text; *targetP++ = A_CompoundText; *targetP++ = A_Length; *targetP++ = A_ListLength; *targetP++ = A_CharacterPosition; *length = 6 * sizeof(Atom) / 32; *type = XA_ATOM; if (format) *format = 32; return True; } #if 1 /* * This is a complicated piece. * * Go get the stuff we've already put out, and pass it along again. */ if (*target == A_ListLength || *target == A_Length || *target == A_String || *target == A_Text || *target == A_CompoundText || *target == A_CharacterPosition) { Display *display = XtDisplay(w); XmClipboard *clip; int status, len, namelen, numformats, formatlen, format_id, dlen, fetchlen; unsigned int *buf; XmClipboardItem *item; Atom ClipboardAtom = XmInternAtom(display, "CLIPBOARD", False); Window window = XtWindow(w); Boolean got_format = False; char *format_name = "Auch"; XmClipboardFormat *fmt; unsigned char *bufstart = NULL; Boolean partial_copy = False; Boolean got_data = False; int privid = 0; unsigned long llength; DEBUGOUT(_LtDebug(__FILE__, w, "AAAAA\n")); status = _XmClipboardLock(display, window); if (status == XmClipboardLocked) return status; clip = _XmClipboardOpen(display, sizeof(int)); /* Or param 0 ??? */ DEBUGOUT(_LtDebug(__FILE__, w, "AAAAA _XmClipboardOpen => %p\n", clip)); _XmClipboardInitializeSelection(display, clip, window, clip->retrieve_lock_time); got_format = False; if (_XmClipboardWeOwnSelection(display, clip)) { DEBUGOUT(_LtDebug(__FILE__, XtWindowToWidget(display, window), "XmClipboardRetrieve: we own selection\n")); format_name = "STRING"; format_name = NULL; fmt = _XmClipboardFindFormat(display, clip, format_name, 0, 0, &namelen, &numformats, &formatlen); DEBUGOUT(_LtDebug(__FILE__, w, "_XmClipboardFindFormat => %p, nformats %d, formatlen %d\n", fmt, numformats, formatlen)); got_format = True; if (fmt != NULL) { DEBUGOUT(_LtDebug(__FILE__, XtWindowToWidget(display, window), "XmClipboardRetrieve: format != NULL\n")); format_id = fmt->format_id; if (fmt->by_name) { DEBUGOUT(_LtDebug(__FILE__, XtWindowToWidget(display, window), "XmClipboardRetrieve: by name\n")); got_format = _XmClipboardRequestDataAndWait(display, window, fmt); if (got_format) { DEBUGOUT(_LtDebug(__FILE__, XtWindowToWidget(display, window), "XmClipboardRetrieve: got format\n")); XtFree((char *)fmt); _XmClipboardFindItem(display, format_id, &data, &formatlen, NULL, XmCLIP_PROP_FORMAT); fmt = (XmClipboardFormat *) data; } } if (got_format) { DEBUGOUT(_LtDebug(__FILE__, XtWindowToWidget(display, window), "XmClipboardRetrieve: got format 2\n")); _XmClipboardFindItem(display, fmt->data_id, &data, &dlen, NULL, XmCLIP_PROP_DONT_CARE); /* Ok, got it */ datalen = dlen; #if 0 *value = data; *format = 8L; *length = dlen; #endif DEBUGOUT(_LtDebug(__FILE__, NULL, "AAAAA [%s], length %d\n", data, dlen)); #if 0 bufstart = (unsigned char *)data + fmt->offset; if (dlen - fmt->offset > llength) { partial_copy = True; fetchlen = llength; } else { fetchlen = dlen - fmt->offset; } DEBUGOUT(_LtDebug(__FILE__, XtWindowToWidget(display, window), "XmClipboardRetrieve: fetchlen %d partial_copy %s\n", fetchlen, _LtDebugBoolean2String(partial_copy))); if (clip->retrieve_locked) { if (partial_copy) { fmt->offset += fetchlen; } else { fmt->offset = 0; } } #endif got_data = True; } privid = fmt->private_id; _XmClipboardReplaceItem(display, format_id, (unsigned *)fmt, formatlen, PropModeReplace, 32, True); } } /* * return True; */ } /* * End complicated piece. */ #endif if (*target == A_ListLength || *target == A_Length) { long * temp; DEBUGOUT(_LtDebug(__FILE__, w, "Beyond complicated piece, request is a LENGTH\n")); temp = (long *) XtMalloc(sizeof(long)); if (*target == A_ListLength) *temp = 1L; else { /* *target == XA_LENGTH(d) */ *temp = datalen; } *value = (XPointer) temp; *type = XA_INTEGER; *length = 1L * sizeof(int) / 32; if (format) *format = 32; return True; } if (*target == A_CharacterPosition) { long * temp; DEBUGOUT(_LtDebug(__FILE__, w, "Beyond complicated piece, request a POSITION\n")); temp = (long *) XtMalloc(2 * sizeof(long)); temp[0] = (long) 0; temp[1] = datalen; *value = (XPointer) temp; *type = A_Span; *length = 2L * sizeof(long) / 32; if (format) *format = 32; return True; } if (*target == A_String || *target == A_Text || *target == A_CompoundText) { DEBUGOUT(_LtDebug(__FILE__, w, "Beyond complicated piece, request a STRING\n")); if (*target == A_CompoundText) *type = *target; else *type = A_String; *length = datalen; *value = strdup((char *)data); if (format) *format = 8; return True; } return False; } /* * XmClipboardEndCopy locks the clipboard from access by other applications, places data * in the clipboard data structure, and unlocks the clipboard. Data items copied to the * clipboard by XmClipboardCopy are not actually entered in the clipboard data structure * until the call to XmClipboardEndCopy. * * This function also frees up temporary storage that was allocated by XmClipboardStartCopy, * which must be called before XmClipboardEndCopy. The latter function should not be called * if XmClipboardCancelCopy has been called. */ extern int XmClipboardEndCopy(Display *display, Window window, long item_id) { XmClipboard *clip; int status, len; unsigned int *data, *buf; XmClipboardItem *item; Widget w = XtWindowToWidget(display, window); Atom ClipboardAtom = XmInternAtom(display, "CLIPBOARD", False); DEBUGOUT(_LtDebug(__FILE__, w, "XmClipboardEndCopy(win 0x%X, item %ld)\n", window, item_id)); status = _XmClipboardLock(display, window); if (status == XmClipboardLocked) return status; clip = _XmClipboardOpen(display, sizeof(int)); if (clip->copy_locked == UNLOCKED) { _XmWarning(NULL, "Attempt to EndCopy an unlocked clipboard!"); _XmClipboardUnlock(display, window, False); return XmClipboardFail; } _XmClipboardDeleteMarked(display, window, clip); if (clip->item_count >= clip->static_item_count) { buf = (unsigned *)((char *)clip + clip->clip_size); _XmClipboardMarkItem(display, clip, *buf, True); clip->next_delete = *buf; } else { clip->next_delete = 0; } buf = (unsigned *)((char *)clip + clip->clip_size); buf += clip->item_count; *buf = item_id; clip->last_item = clip->current_item; clip->current_item = item_id; clip->current_item2 = item_id; clip->item_count++; clip->copy_locked = UNLOCKED; _XmClipboardFindItem(display, item_id, &data, &len, NULL, XmCLIP_PROP_ITEM); item = (XmClipboardItem *) data; if (item && item->widget) { DEBUGOUT(_LtDebug(__FILE__, NULL, "Add EventHandler from EndCopy\n")); XtAddEventHandler(item->widget, None, True, _XmClipboardEventHandler, NULL); /* Danny */ XtOwnSelection(item->widget, ClipboardAtom, CurrentTime, _XmConvertSelectionICCCM, NULL, NULL); DEBUGOUT(_LtDebug(__FILE__, item->widget, "XtOwnSelection\n")); } else { /* * Figure out the widget for ourselves. * Example OReilly/chapter-21/copy_retrieve demonstrates this. */ Widget w = XtWindowToWidget(display, window); if (w) { XtOwnSelection(w, ClipboardAtom, CurrentTime, _XmConvertSelectionICCCM, NULL, NULL); DEBUGOUT(_LtDebug(__FILE__, w, "XtOwnSelection(ICCCM)\n")); } } if (data) XtFree((char *)data); _XmAssertClipboardSelection(display, window, clip, clip->copy_lock_time); _XmClipboardSetNextItemId(display, item_id); _XmClipboardClose(display, clip); _XmClipboardUnlock(display, window, False); return XmClipboardSuccess; } /* * XmClipboardEndRetrieve suspends copying data incrementally from the clipboard. It tells the * clipboard routines that the application is through copying an item from the clipboard. Until * this function is called, data items can be retrieved incrementally from the clipboard with * XmClipboardRetrieve. The act of copying data is started with the XmClipboardStartRetrieve * function. */ extern int XmClipboardEndRetrieve(Display *display, Window window) { XmClipboard *clip; clip = _XmClipboardOpen(display, 0); clip->retrieve_locked = UNLOCKED; clip->retrieve_lock_time = None; _XmClipboardClose(display, clip); _XmClipboardUnlock(display, window, False); return XmClipboardSuccess; } /* * XmClipboardInquireCount returns the number of data item formats available for the data item * in the clipboard. This function also returns the maximum name-length for all formats * in which the data item is stored. */ extern int XmClipboardInquireCount(Display *display, Window window, int *count, unsigned long *max_length) { XmClipboard *clip; int status, namelen, num_formats, format_len, len; Time time; unsigned *data; XmClipboardFormat *format; status = _XmClipboardLock(display, window); if (status == XmClipboardLocked) { return status; } clip = _XmClipboardOpen(display, 0); if (clip->retrieve_lock_time == 0) { time = _XmClipboardGetCurrentTime(display); } else { time = clip->retrieve_lock_time; } _XmClipboardInitializeSelection(display, clip, window, time); format = NULL; if (_XmClipboardWeOwnSelection(display, clip)) { format = _XmClipboardFindFormat(display, clip, NULL, 0, 0, &namelen, &num_formats, &format_len); } else { if (!_XmClipboardGetSelection(display, window, _XA_TARGETS, clip, &data, &len)) { _XmClipboardClose(display, clip); _XmClipboardUnlock(display, window, False); return XmClipboardFail; } DEBUGOUT(_LtDebug(__FILE__, XtWindowToWidget(display, window), "XmClipboardInquireCount: FIX ME ICCCM\n")); /* FIX ME: This is supposed to be the ICCCM way */ } if (max_length != NULL) { *max_length = format_len; } if (count != NULL) { *count = num_formats; } if (format) { XtFree((char *)format); } _XmClipboardClose(display, clip); _XmClipboardUnlock(display, window, False); return XmClipboardSuccess; } /* * XmClipboardInquireFormat returns a specified format name for the data item in the clipboard. * If the name must be truncated, the function returns a warning status. */ extern int XmClipboardInquireFormat(Display *display, Window window, int index, XtPointer format_name_buf, unsigned long buffer_len, unsigned long *copied_len) { XmClipboard *clip; int status, namelen, num_formats, format_len, len; Time time; XmClipboardFormat *format; unsigned *data; char *name = NULL; status = _XmClipboardLock(display, window); if (status == XmClipboardLocked) { return status; } clip = _XmClipboardOpen(display, 0); time = clip->retrieve_lock_time; _XmClipboardInitializeSelection(display, clip, window, time); if (_XmClipboardWeOwnSelection(display, clip)) { if ((format = _XmClipboardFindFormat(display, clip, NULL, 0, index, &namelen, &num_formats, &format_len)) != NULL) { name = XmGetAtomName(display, format->atom); } } else { /* FIX ME: TARGETS is probably wrong */ if (!_XmClipboardGetSelection(display, window, _XA_TARGETS, clip, &data, &len)) { _XmClipboardClose(display, clip); _XmClipboardUnlock(display, window, False); return XmClipboardFail; } DEBUGOUT(_LtDebug(__FILE__, XtWindowToWidget(display, window), "XmClipboardInquireFormat: FIX ME ICCCM\n")); /* FIX ME: This is supposed to be the ICCCM way of things */ } if (name) { len = strlen(name) <= buffer_len ? strlen(name) : buffer_len; strncpy((char *)format_name_buf, name, len); if (copied_len) { *copied_len = len; } XtFree(name); } else { if (copied_len) { *copied_len = 0; } } _XmClipboardClose(display, clip); _XmClipboardUnlock(display, window, False); return XmClipboardSuccess; } /* * XmClipboardInquireLength returns the length of the data stored under a specified format name * for the clipboard data item. If no data is found for the specified format, or if there is no * item on the clipboard, this function returns a value of 0 (zero) in the length argument. * * Any format passed by name is assumed to have length passed in a call to XmClipboardCopy, * even though the data has not yet been transferred to the clipboard in that format. */ extern int XmClipboardInquireLength(Display *display, Window window, char *format_name, unsigned long *length) { XmClipboard *clip; int status, namelen, num_formats, format_len, len, flen; Time time; unsigned *data; XmClipboardFormat *format; status = _XmClipboardLock(display, window); if (status == XmClipboardLocked) { return status; } clip = _XmClipboardOpen(display, 0); time = clip->retrieve_lock_time; _XmClipboardInitializeSelection(display, clip, window, time); flen = 0; if (_XmClipboardWeOwnSelection(display, clip)) { format = _XmClipboardFindFormat(display, clip, format_name, 0, 0, &namelen, &num_formats, &format_len); if (format) { flen = format->length; XtFree((char *)format); } } else { if (!_XmClipboardGetSelection(display, window, format_name, clip, &data, &len)) { _XmClipboardClose(display, clip); _XmClipboardUnlock(display, window, False); return XmClipboardFail; } XtFree((char *)data); flen = len; } if (length) { *length = flen; } _XmClipboardClose(display, clip); _XmClipboardUnlock(display, window, False); return XmClipboardSuccess; } /* * XmClipboardInquirePendingItems returns a list of data ID/private ID pairs for the specified * format name. A data item is considered pending if the application originally passed it by * name, the application has not yet copied the data, and the item has not been deleted from * the clipboard. The application is responsible for freeing the memory provided by this * function to store the list. To free the memory, call XtFree. * * This function is used by an application when exiting, to determine if the data that is passed * by name should be sent to the clipboard. */ extern int XmClipboardInquirePendingItems(Display *display, Window window, char *format_name, XmClipboardPendingList *item_list, unsigned long *count) { XmClipboard *clip; int status; XmClipboardPendingList items, item; XmClipboardFormat *format; unsigned *ilist; int i, cnt, namelen, numformats, formatlen; status = _XmClipboardLock(display, window); if (status == XmClipboardLocked) { return status; } if (item_list == NULL) { XmClipboardUnlock(display, window, False); return XmClipboardSuccess; } *item_list = NULL; clip = _XmClipboardOpen(display, 0); ilist = (unsigned *)((char *)clip + clip->clip_size); cnt = 0; items = (XmClipboardPendingList)XtMalloc(clip->item_count * sizeof(XmClipboardPendingRec)); item = items; for (i = 0; i < clip->item_count; i++) { format = NULL; if (!_XmClipboardIsMarkedForDelete(display, clip, *ilist)) { _XmClipboardFindFormat(display, clip, format_name, *ilist, 0, &namelen, &numformats, &formatlen); } if (format != NULL) { if (format->by_name) { item->DataId = format->format_id; item->PrivateId = format->private_id; cnt++; item++; } XtFree((char *)format); } } if (count) { *count = cnt; } *item_list = items; _XmClipboardClose(display, clip); _XmClipboardUnlock(display, window, False); return XmClipboardSuccess; } extern int XmClipboardLock(Display *display, Window window) { return _XmClipboardLock(display, window); } /* * XmClipboardRegisterFormat registers a new format. Each format stored on the clipboard should * have a length associated with it; this length must be known to the clipboard routines. * Formats are known as targets in the Inter-Client Communication Conventions Manual (ICCCM). * All of the formats specified by version 1.1 of the ICCCM conventions are preregistered. * Any other format that the application wants to use must either be 8-bit data or be registered * via this routine. Failure to register the length of the data results in incompatible * applications across platforms having different byte-swapping orders. */ extern int XmClipboardRegisterFormat(Display *display, char *format_name, int format_length) { #define REGISTER_IF_KNOWN(dsp, fname, kname, len) \ if (strcmp(fname, kname) == 0) { \ _XmClipboardRegisterFormat(dsp, fname, len); \ return XmClipboardSuccess; \ } if (format_length != 0 && format_length != 8 && format_length != 16 && format_length != 32) { _XmWarning(NULL, "Invalid format length"); return XmClipboardBadFormat; } if (format_name == NULL || strlen(format_name) == 0) { _XmWarning(NULL, "Attempt to register NULL or zero length format name"); } if (format_length != 0) { return _XmClipboardRegisterFormat(display, format_name, format_length); } REGISTER_IF_KNOWN(display, format_name, _XA_TARGETS, 32) REGISTER_IF_KNOWN(display, format_name, _XA_MULTIPLE, 32) REGISTER_IF_KNOWN(display, format_name, _XA_TIMESTAMP, 32) REGISTER_IF_KNOWN(display, format_name, _XA_STRING, 8) REGISTER_IF_KNOWN(display, format_name, _XA_COMPOUND_TEXT, 8) REGISTER_IF_KNOWN(display, format_name, _XA_LIST_LENGTH, 32) REGISTER_IF_KNOWN(display, format_name, _XA_PIXMAP, 32) REGISTER_IF_KNOWN(display, format_name, _XA_DRAWABLE, 32) REGISTER_IF_KNOWN(display, format_name, _XA_BITMAP, 32) REGISTER_IF_KNOWN(display, format_name, _XA_FOREGROUND, 32) REGISTER_IF_KNOWN(display, format_name, _XA_BACKGROUND, 32) REGISTER_IF_KNOWN(display, format_name, _XA_COLORMAP, 32) REGISTER_IF_KNOWN(display, format_name, _XA_ODIF, 8) REGISTER_IF_KNOWN(display, format_name, _XA_OWNER_OS, 8) REGISTER_IF_KNOWN(display, format_name, _XA_FILE_NAME, 8) REGISTER_IF_KNOWN(display, format_name, _XA_HOST_NAME, 8) REGISTER_IF_KNOWN(display, format_name, _XA_CHARACTER_POSITION, 32) REGISTER_IF_KNOWN(display, format_name, _XA_LINE_NUMBER, 32) REGISTER_IF_KNOWN(display, format_name, _XA_COLUMN_NUMBER, 32) REGISTER_IF_KNOWN(display, format_name, _XA_LENGTH, 32) REGISTER_IF_KNOWN(display, format_name, _XA_USER, 8) REGISTER_IF_KNOWN(display, format_name, _XA_PROCEDURE, 8) REGISTER_IF_KNOWN(display, format_name, _XA_MODULE, 8) REGISTER_IF_KNOWN(display, format_name, _XA_PROCESS, 32) REGISTER_IF_KNOWN(display, format_name, _XA_TASK, 32) REGISTER_IF_KNOWN(display, format_name, _XA_CLASS, 8) REGISTER_IF_KNOWN(display, format_name, _XA_NAME, 8) REGISTER_IF_KNOWN(display, format_name, _XA_CLIENT_WINDOW, 32) return XmClipboardFail; } /* * XmClipboardRetrieve retrieves the current data item from clipboard storage. It returns a * warning if the clipboard is locked, if there is no data on the clipboard, or if the data * needs to be truncated because the buffer length is too short. * * Between a call to XmClipboardStartRetrieve and a call to XmClipboardEndRetrieve, multiple * calls to XmClipboardRetrieve with the same format name result in data being incrementally * copied from the clipboard until the data in that format has all been copied. * * The return value XmClipboardTruncate from calls to XmClipboardRetrieve indicates that more * data remains to be copied in the given format. It is recommended that any calls to the * Inquire functions that the application needs to make to effect the copy from the clipboard * be made between the call to XmClipboardStartRetrieve and the first call to * XmClipboardRetrieve. This way, the application does not need to call XmClipboardLock and * XmClipboardUnlock. */ extern int XmClipboardRetrieve(Display *display, Window window, char *format_name, XtPointer buffer, unsigned long length, unsigned long *num_bytes, long *private_id) { XmClipboard *clip; int namelen, numformats, formatlen, dlen, status, format_id; int privid = 0; int fetchlen = 0; XmClipboardFormat *format; Boolean got_format = False; unsigned *data=NULL; unsigned char *bufstart = NULL; Boolean partial_copy = False; Boolean got_data = False; status = _XmClipboardLock(display, window); if (status == XmClipboardLocked) { DEBUGOUT(_LtDebug(__FILE__, XtWindowToWidget(display, window), "XmClipboardRetrieve => XmClipboardLocked\n")); return status; } DEBUGOUT(_LtDebug(__FILE__, XtWindowToWidget(display, window), "XmClipboardRetrieve(fmt %s, maxlen %d)\n", format_name ? format_name : "(null)", length)); clip = _XmClipboardOpen(display, 0); _XmClipboardInitializeSelection(display, clip, window, clip->retrieve_lock_time); got_format = False; if (_XmClipboardWeOwnSelection(display, clip)) { DEBUGOUT(_LtDebug(__FILE__, XtWindowToWidget(display, window), "XmClipboardRetrieve: we own selection\n")); format = _XmClipboardFindFormat(display, clip, format_name, 0, 0, &namelen, &numformats, &formatlen); got_format = True; if (format != NULL) { DEBUGOUT(_LtDebug(__FILE__, XtWindowToWidget(display, window), "XmClipboardRetrieve: format != NULL\n")); format_id = format->format_id; if (format->by_name) { DEBUGOUT(_LtDebug(__FILE__, XtWindowToWidget(display, window), "XmClipboardRetrieve: by name\n")); got_format = _XmClipboardRequestDataAndWait(display, window, format); if (got_format) { DEBUGOUT(_LtDebug(__FILE__, XtWindowToWidget(display, window), "XmClipboardRetrieve: got format\n")); XtFree((char *)format); _XmClipboardFindItem(display, format_id, &data, &formatlen, NULL, XmCLIP_PROP_FORMAT); format = (XmClipboardFormat *) data; } } if (got_format) { DEBUGOUT(_LtDebug(__FILE__, XtWindowToWidget(display, window), "XmClipboardRetrieve: got format 2\n")); _XmClipboardFindItem(display, format->data_id, &data, &dlen, NULL, XmCLIP_PROP_DONT_CARE); bufstart = (unsigned char *)data + format->offset; if (dlen - format->offset > length) { partial_copy = True; fetchlen = length; } else { fetchlen = dlen - format->offset; } DEBUGOUT(_LtDebug(__FILE__, XtWindowToWidget(display, window), "XmClipboardRetrieve: fetchlen %d partial_copy %s\n", fetchlen, _LtDebugBoolean2String(partial_copy))); if (clip->retrieve_locked) { if (partial_copy) { format->offset += fetchlen; } else { format->offset = 0; } } got_data = True; } privid = format->private_id; _XmClipboardReplaceItem(display, format_id, (unsigned *)format, formatlen, PropModeReplace, 32, True); } } else { DEBUGOUT(_LtDebug(__FILE__, XtWindowToWidget(display, window), "XmClipboardRetrieve: we don't own selection !!\n")); /* amai: At least when clipboard is messed up from remaining LT bugs I saw got_data==NULL here ... */ got_data = _XmClipboardGetSelection(display, window, format_name, clip, &data, &dlen); if (got_data) { bufstart = (unsigned char *)data + clip->offset; if (dlen - clip->offset > length) { partial_copy = True; fetchlen = length; } else { fetchlen = dlen - clip->offset; } if (clip->retrieve_locked) { if (partial_copy) { clip->offset += fetchlen; } else { clip->offset = 0; } } } /* if (got_data) */ } /* else */ if (got_data) { memcpy(buffer, bufstart, fetchlen); XtFree((char *)data); } if (num_bytes) { *num_bytes = fetchlen; } if (private_id) { *private_id = privid; } _XmClipboardClose(display, clip); _XmClipboardUnlock(display, window, False); if (fetchlen == 0) { return XmClipboardNoData; } if (partial_copy) { return XmClipboardTruncate; } return XmClipboardSuccess; } /* * XmClipboardStartCopy sets up storage and data structures to receive clipboard data. * An application calls this function during a cut or copy operation. The data item that * these structures receive then becomes the next data item in the clipboard. * * Copying a large piece of data to the clipboard can take a long time. It is possible that, * once the data is copied, no application will ever request that data. The Motif Toolkit * provides a mechanism so that an application does not need to actually pass data to * the clipboard until the data has been requested by some application. * * Instead, the application passes format and length information in XmClipboardCopy * to the clipboard functions, along with a widget ID and a callback function address * that is passed in XmClipboardStartCopy. The widget ID is necessary for communications * between the clipboard functions in the application that owns the data and the clipboard * functions in the application that requests the data. * * The callback functions are responsible for copying the actual data to the clipboard * through XmClipboardCopyByName. The callback function is also called if the data item * is removed from the clipboard and the actual data is no longer needed. */ extern int XmClipboardStartCopy(Display *display, Window window, XmString clip_label, Time timestamp, Widget widget, XmCutPasteProc callback, long *item_id) { XmClipboard *clip; XmClipboardItem *item; unsigned int new_item_id, new_label_id; int llen; Widget w = XtWindowToWidget(display, window); DEBUGOUT(_LtDebug(__FILE__, w, "XmClipboardStartCopy(win 0x%X, clip 0x%X, time %ld)\n", window, clip_label, timestamp)); if (_XmClipboardLock(display, window) == XmClipboardLocked) { return XmClipboardLocked; } clip = _XmClipboardOpen(display, 0); clip->copy_lock_time = timestamp; clip->copy_locked = LOCKED; item = (XmClipboardItem *) XtMalloc(sizeof(XmClipboardItem)); new_item_id = _XmClipboardGetNewItemId(display); new_label_id = _XmClipboardGetNewItemId(display); item->ipad1 = 0; item->item_id = new_item_id; item->prop_id = XmCLIP_PROP_ITEM; item->display = display; item->window = window; item->label_id = new_label_id; item->item_size = sizeof(XmClipboardItem); item->format_count = 0; item->del_format_count = 0; item->by_name = 0; item->marked_for_delete = 0; item->ipad2 = 0; item->callback = NULL; item->widget = NULL; item->widget_window = None; if (callback != NULL && widget != NULL) { item->widget_window = XtWindow(widget); item->widget = widget; item->callback = callback; _XmClipboardSetAccess(display, item->widget_window); } llen = XmStringLength(clip_label); _XmClipboardReplaceItem(display, new_label_id, (unsigned *)clip_label, llen, PropModeReplace, 8, False); _XmClipboardReplaceItem(display, new_item_id, (unsigned *)item, sizeof(XmClipboardItem), PropModeReplace, 32, True); if (item_id) { *item_id = new_item_id; } _XmClipboardClose(display, clip); _XmClipboardUnlock(display, window, False); return XmClipboardSuccess; } /* * XmClipboardStartRetrieve tells the clipboard routines that the application is ready to start * copying an item from the clipboard. The clipboard is locked by this routine and stays locked * until XmClipboardEndRetrieve is called. Between a call to XmClipboardStartRetrieve and a call * to XmClipboardEndRetrieve, multiple calls to XmClipboardRetrieve with the same format name * result in data being incrementally copied from the clipboard until the data in that format * has all been retrieved. * * A return value of XmClipboardTruncate from calls to XmClipboardRetrieve indicates that more * data remains to be copied in the given format. It is recommended that any calls to the * Inquire functions that the application needs to make to complete the copy from the clipboard * be made between the call to XmClipboardStartRetrieve and the first call to XmClipboardRetrieve. * This way, the application does not need to call XmClipboardLock and XmClipboardUnlock. */ extern int XmClipboardStartRetrieve(Display *display, Window window, Time timestamp) { XmClipboard *clip; if (_XmClipboardLock(display, window) == XmClipboardLocked) { return XmClipboardLocked; } clip = _XmClipboardOpen(display, 0); clip->retrieve_lock_time = timestamp; clip->retrieve_locked = LOCKED; clip->offset = 0; _XmClipboardClose(display, clip); return XmClipboardSuccess; } /* * XmClipboardUndoCopy deletes the last item placed on the clipboard if the item was placed there * by an application with the passed display and window arguments. Any data item deleted from the * clipboard by the original call to XmClipboardCopy is restored. If the display or window IDs * do not match the last copied item, no action is taken, and this function has no effect. */ int XmClipboardUndoCopy(Display *display, Window window) { int status; XmClipboard *clip; unsigned *data; int len; XmClipboardFormat *format; Boolean item_marked = False; int tmp; status = _XmClipboardLock(display, window); if (status == XmClipboardLocked) { return status; } clip = _XmClipboardOpen(display, 0); if (clip->current_item2) { _XmClipboardFindItem(display, clip->current_item2, &data, &len, NULL, XmCLIP_PROP_FORMAT); format = (XmClipboardFormat *) data; if (format->window == window && format->display == display) { _XmClipboardMarkItem(display, clip, clip->current_item2, True); item_marked = True; } XtFree((char *)format); } if (!item_marked) { _XmClipboardMarkItem(display, clip, clip->next_delete, False); tmp = clip->current_item2; clip->current_item2 = clip->next_delete; clip->next_delete = tmp; tmp = clip->last_item; clip->last_item = clip->current_item; clip->current_item = tmp; } _XmClipboardClose(display, clip); _XmClipboardUnlock(display, window, False); return XmClipboardSuccess; } /* * XmClipboardUnlock unlocks the clipboard, enabling it to be accessed by other applications. * * If multiple calls to XmClipboardLock have occurred, the same number of calls to * XmClipboardUnlock is necessary to unlock the clipboard, unless remove_all_locks is set to True. */ extern int XmClipboardUnlock(Display *display, Window window, Boolean remove_all_locks) { return _XmClipboardUnlock(display, window, remove_all_locks); } /* * XmClipboardWithdrawFormat indicates that the application no longer supplies a data item * to the clipboard that the application had previously passed by name. */ extern int XmClipboardWithdrawFormat(Display *display, Window window, int data_id) { if (_XmClipboardLock(display, window) == XmClipboardLocked) { return XmClipboardLocked; } _XmClipboardDeleteFormat(display, data_id); _XmClipboardUnlock(display, window, False); return XmClipboardSuccess; }