package org.eclipse.swt.dnd; | |
/* | |
* (c) Copyright IBM Corp. 2000, 2001. | |
* All Rights Reserved | |
*/ | |
import org.eclipse.swt.*; | |
import org.eclipse.swt.internal.*; | |
import org.eclipse.swt.internal.motif.*; | |
import org.eclipse.swt.widgets.*; | |
/** | |
* IMPORTANT: This class is <em>not</em> intended to be subclassed. | |
*/ | |
public class Clipboard { | |
private Display display; | |
private final int MAX_RETRIES = 10; | |
private int shellHandle; | |
public Clipboard(Display display) { | |
checkSubclass (); | |
if (display == null) { | |
display = Display.getCurrent(); | |
if (display == null) { | |
display = Display.getDefault(); | |
} | |
} | |
if (display.getThread() != Thread.currentThread()) { | |
SWT.error(SWT.ERROR_THREAD_INVALID_ACCESS); | |
} | |
this.display = display; | |
int widgetClass = OS.TopLevelShellWidgetClass (); | |
shellHandle = OS.XtAppCreateShell (null, null, widgetClass, display.xDisplay, null, 0); | |
OS.XtSetMappedWhenManaged (shellHandle, false); | |
OS.XtRealizeWidget (shellHandle); | |
} | |
protected void checkSubclass () { | |
String name = getClass().getName (); | |
String validName = Clipboard.class.getName(); | |
if (!validName.equals(name)) { | |
DND.error (SWT.ERROR_INVALID_SUBCLASS); | |
} | |
} | |
public void dispose () { | |
if (shellHandle != 0) OS.XtDestroyWidget (shellHandle); | |
shellHandle = 0; | |
display = null; | |
} | |
public Object getContents(Transfer transfer) { | |
if (display.isDisposed() ) return null; | |
int xDisplay = OS.XtDisplay (shellHandle); | |
if (xDisplay == 0) return null; | |
int xWindow = OS.XtWindow (shellHandle); | |
if (xWindow == 0) return null; | |
// Open clipboard for retrieval | |
int retries = 0; | |
int status = OS.XmClipboardStartRetrieve(xDisplay, xWindow, OS.XtLastTimestampProcessed(xDisplay)); | |
while ( status == OS.XmClipboardLocked && retries < MAX_RETRIES) { | |
retries ++; | |
status = OS.XmClipboardStartRetrieve(xDisplay, xWindow, OS.XtLastTimestampProcessed(xDisplay)); | |
}; | |
if (status != OS.XmClipboardSuccess) return null; | |
// Does Clipboard have data in required format? | |
String type = null; | |
int[] length = new int[1]; | |
String[] supportedTypes = transfer.getTypeNames(); | |
for (int i = 0; i < supportedTypes.length; i++) { | |
if (OS.XmClipboardInquireLength(xDisplay, xWindow, supportedTypes[i].getBytes(), length) == 1 /*OS.XmClipboardSuccess*/ ) { | |
type = supportedTypes[i]; | |
break; | |
} | |
} | |
// Retrieve data from Clipboard | |
byte[] data = null; | |
if (type != null) { | |
data = new byte[length[0]]; | |
status = OS.XmClipboardRetrieve(xDisplay, xWindow, type.getBytes(), data, length[0], new int[1], new int[1]); | |
if (status != OS.XmClipboardSuccess) { | |
data = null; | |
} | |
} | |
// Close Clipboard | |
status = OS.XmClipboardEndRetrieve(xDisplay, xWindow); | |
if (data == null) return null; | |
// Pass data to transfer agent for conversion to a Java Object | |
// Memory is allocated here to emulate the way Drag and Drop transfers data. | |
TransferData transferData = new TransferData(); | |
byte[] bName = Converter.wcsToMbcs (null, type, false); | |
transferData.type = OS.XmInternAtom (xDisplay, bName, false); | |
transferData.pValue = OS.XtMalloc(data.length); | |
OS.memmove(transferData.pValue, data, data.length); | |
transferData.length = data.length; | |
transferData.format = 8; | |
transferData.result = 1; | |
Object result = transfer.nativeToJava(transferData); | |
// Clean up allocated memory | |
OS.XtFree(transferData.pValue); | |
return result; | |
} | |
public void setContents(Object[] data, Transfer[] transferAgents){ | |
if (data == null) { | |
DND.error(SWT.ERROR_NOT_IMPLEMENTED); | |
} | |
if (transferAgents == null || data.length != transferAgents.length) { | |
DND.error(SWT.ERROR_INVALID_ARGUMENT); | |
} | |
if (display.isDisposed() ) | |
DND.error(DND.ERROR_CANNOT_SET_CLIPBOARD); | |
int xDisplay = OS.XtDisplay (shellHandle); | |
if (xDisplay == 0) | |
DND.error(DND.ERROR_CANNOT_SET_CLIPBOARD); | |
int xWindow = OS.XtWindow (shellHandle); | |
if (xWindow == 0) | |
DND.error(DND.ERROR_CANNOT_SET_CLIPBOARD); | |
// Open clipboard for setting | |
int[] item_id = new int[1]; | |
int retries = 0; | |
int status = OS.XmClipboardStartCopy(xDisplay, xWindow, 0, OS.XtLastTimestampProcessed(xDisplay), shellHandle, 0, item_id); | |
while ( status == OS.XmClipboardLocked && retries < MAX_RETRIES) { | |
retries ++; | |
status = OS.XmClipboardStartCopy(xDisplay, xWindow, 0, OS.XtLastTimestampProcessed(xDisplay), shellHandle, 0, item_id); | |
}; | |
if (status != OS.XmClipboardSuccess) | |
DND.error(DND.ERROR_CANNOT_SET_CLIPBOARD); | |
// copy data directly over to System clipboard (not deferred) | |
for (int i = 0; i < transferAgents.length; i++) { | |
String[] names = transferAgents[i].getTypeNames(); | |
for (int j = 0; j < names.length; j++) { | |
TransferData transferData = new TransferData(); | |
byte[] bName = Converter.wcsToMbcs (null, names[j], false); | |
transferData.type = OS.XmInternAtom (xDisplay, bName, false); | |
transferAgents[i].javaToNative(data[i], transferData); | |
status = OS.XmClipboardFail; | |
if (transferData.result == 1 && transferData.format == 8){ | |
byte[] buffer = new byte[transferData.length]; | |
OS.memmove(buffer, transferData.pValue, transferData.length); | |
status = OS.XmClipboardCopy(xDisplay, xWindow, item_id[0], bName, buffer, transferData.length, 0, null); | |
} | |
// Clean up allocated memory | |
if (transferData.pValue != 0) { | |
OS.XtFree(transferData.pValue); | |
} | |
} | |
} | |
// close clipboard for setting | |
OS.XmClipboardEndCopy(xDisplay, xWindow, item_id[0]); | |
if (status != OS.XmClipboardSuccess) | |
DND.error(DND.ERROR_CANNOT_SET_CLIPBOARD); | |
} | |
/* | |
* Note: getAvailableTypeNames is a tool for writing a Transfer sub-class only. It should | |
* NOT be used within an application because it provides platform specfic | |
* information. | |
*/ | |
public String[] getAvailableTypeNames() { | |
int[] count = new int[1]; | |
int[] max_length = new int[1]; | |
int xDisplay = OS.XtDisplay (shellHandle); | |
if (xDisplay == 0) | |
DND.error(SWT.ERROR_UNSPECIFIED); | |
int xWindow = OS.XtWindow (shellHandle); | |
if (xWindow == 0) | |
DND.error(SWT.ERROR_UNSPECIFIED); | |
if (OS.XmClipboardInquireCount(xDisplay, xWindow, count, max_length) != OS.XmClipboardSuccess) | |
DND.error(SWT.ERROR_UNSPECIFIED); | |
String[] types = new String[count[0]]; | |
for (int i = 0; i < count[0]; i++) { | |
byte[] buffer = new byte[max_length[0]]; | |
int[] copied_length = new int[1]; | |
int rc = OS.XmClipboardInquireFormat(xDisplay, xWindow, i + 1, buffer, buffer.length, copied_length); | |
if (rc == OS.XmClipboardNoData){ | |
types[i] = ""; | |
continue; | |
} | |
if (rc != OS.XmClipboardSuccess) | |
DND.error(SWT.ERROR_UNSPECIFIED); | |
byte[] buffer2 = new byte[copied_length[0]]; | |
System.arraycopy(buffer, 0, buffer2, 0, copied_length[0]); | |
types[i] = new String(buffer2); | |
} | |
return types; | |
} | |
} |