/******************************************************************************* * Copyright (c) 2000, 2005 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.swt.dnd; import org.eclipse.swt.*; import org.eclipse.swt.internal.*; import org.eclipse.swt.internal.motif.*; import org.eclipse.swt.widgets.*; class ClipboardProxy { Display display; int shellHandle; int atomAtom, clipboardAtom, motifClipboardAtom, primaryAtom, targetsAtom; int[][] convertData = new int[10][3]; Clipboard activeClipboard = null; Clipboard activePrimaryClipboard = null; Object[] clipboardData; Transfer[] clipboardDataTypes; Object[] primaryClipboardData; Transfer[] primaryClipboardDataTypes; boolean done = false; Object selectionValue; Transfer selectionTransfer; Callback XtConvertSelectionCallback; Callback XtLoseSelectionCallback; Callback XtSelectionDoneCallback; Callback XtSelectionCallbackCallback; static byte [] ATOM = Converter.wcsToMbcs (null, "ATOM", true); //$NON-NLS-1$ static byte [] CLIPBOARD = Converter.wcsToMbcs (null, "CLIPBOARD", true); //$NON-NLS-1$ static byte [] PRIMARY = Converter.wcsToMbcs (null, "PRIMARY", true); //$NON-NLS-1$ static byte [] TARGETS = Converter.wcsToMbcs (null, "TARGETS", true); //$NON-NLS-1$ static byte [] _MOTIF_CLIPBOARD_TARGETS = Converter.wcsToMbcs (null, "_MOTIF_CLIPBOARD_TARGETS", true); //$NON-NLS-1$ static String ID = "CLIPBOARD PROXY OBJECT"; //$NON-NLS-1$ static ClipboardProxy _getInstance(final Display display) { ClipboardProxy proxy = (ClipboardProxy) display.getData(ID); if (proxy != null) return proxy; proxy = new ClipboardProxy(display); display.setData(ID, proxy); display.addListener(SWT.Dispose, new Listener() { public void handleEvent(Event event) { ClipboardProxy clipbordProxy = (ClipboardProxy)display.getData(ID); if (clipbordProxy == null) return; display.setData(ID, null); clipbordProxy.dispose(); } }); return proxy; } ClipboardProxy(Display display) { this.display = display; XtConvertSelectionCallback = new Callback(this, "XtConvertSelection", 7); //$NON-NLS-1$ if (XtConvertSelectionCallback.getAddress() == 0) SWT.error(SWT.ERROR_NO_MORE_CALLBACKS); XtLoseSelectionCallback = new Callback(this, "XtLoseSelection", 2); //$NON-NLS-1$ if (XtLoseSelectionCallback.getAddress() == 0) SWT.error(SWT.ERROR_NO_MORE_CALLBACKS); XtSelectionDoneCallback = new Callback(this, "XtSelectionDone", 3); //$NON-NLS-1$ if (XtSelectionDoneCallback.getAddress() == 0) SWT.error(SWT.ERROR_NO_MORE_CALLBACKS); XtSelectionCallbackCallback = new Callback(this, "XtSelectionCallback", 7); //$NON-NLS-1$ if (XtSelectionCallbackCallback.getAddress() == 0) SWT.error(SWT.ERROR_NO_MORE_CALLBACKS); int widgetClass = OS.topLevelShellWidgetClass (); shellHandle = OS.XtAppCreateShell (null, null, widgetClass, display.xDisplay, null, 0); OS.XtSetMappedWhenManaged (shellHandle, false); OS.XtRealizeWidget (shellHandle); int xDisplay = OS.XtDisplay(shellHandle); atomAtom = OS.XmInternAtom(xDisplay, ATOM, true); clipboardAtom = OS.XmInternAtom(xDisplay, CLIPBOARD, true); motifClipboardAtom = OS.XmInternAtom(xDisplay, _MOTIF_CLIPBOARD_TARGETS, true); primaryAtom = OS.XmInternAtom(xDisplay, PRIMARY, true); targetsAtom = OS.XmInternAtom(xDisplay, TARGETS, true); } void clear(Clipboard owner, int clipboards) { int xDisplay = OS.XtDisplay(shellHandle); if (xDisplay == 0) return; if ((clipboards & DND.CLIPBOARD) != 0 && activeClipboard == owner) { OS.XtDisownSelection(shellHandle, clipboardAtom, OS.CurrentTime); } if ((clipboards & DND.SELECTION_CLIPBOARD) != 0 && activePrimaryClipboard == owner) { OS.XtDisownSelection(shellHandle, primaryAtom, OS.CurrentTime); } } void dispose () { if (display == null) return; if (shellHandle != 0) { OS.XtDestroyWidget (shellHandle); shellHandle = 0; } if (XtConvertSelectionCallback != null) XtConvertSelectionCallback.dispose(); XtConvertSelectionCallback = null; if (XtLoseSelectionCallback != null) XtLoseSelectionCallback.dispose(); XtLoseSelectionCallback = null; if (XtSelectionCallbackCallback != null) XtSelectionCallbackCallback.dispose(); XtSelectionCallbackCallback = null; if (XtSelectionDoneCallback != null) XtSelectionDoneCallback.dispose(); XtSelectionDoneCallback = null; activeClipboard = null; activePrimaryClipboard = null; clipboardData = null; clipboardDataTypes = null; primaryClipboardData = null; primaryClipboardDataTypes = null; } Object getContents(Transfer transfer, int clipboardType) { int[] types = getAvailableTypes(clipboardType); int index = -1; TransferData transferData = new TransferData(); for (int i = 0; i < types.length; i++) { transferData.type = types[i]; if (transfer.isSupportedType(transferData)) { index = i; break; } } if (index == -1) return null; done = false; selectionValue = null; selectionTransfer = transfer; int selection = clipboardType == DND.CLIPBOARD ? clipboardAtom : primaryAtom; OS.XtGetSelectionValue(shellHandle, selection, types[index], XtSelectionCallbackCallback.getAddress(), 0, OS.CurrentTime); if (!done) { int xDisplay = OS.XtDisplay (shellHandle); if (xDisplay == 0) return null; int xtContext = OS.XtDisplayToApplicationContext(xDisplay); int selectionTimeout = OS.XtAppGetSelectionTimeout(xtContext); wait(selectionTimeout); } return (!done) ? null : selectionValue; } int[] getAvailableTypes(int clipboardType) { int xDisplay = OS.XtDisplay (shellHandle); if (xDisplay == 0) return new int[0]; done = false; selectionValue = null; selectionTransfer = null; int selection = clipboardType == DND.CLIPBOARD ? clipboardAtom : primaryAtom; int target = targetsAtom; OS.XtGetSelectionValue(shellHandle, selection, target, XtSelectionCallbackCallback.getAddress(), 0, OS.CurrentTime); if (!done) { int xtContext = OS.XtDisplayToApplicationContext(xDisplay); int selectionTimeout = OS.XtAppGetSelectionTimeout(xtContext); wait(selectionTimeout); } if (done && selectionValue == null) { done = false; target = motifClipboardAtom; OS.XtGetSelectionValue(shellHandle, selection, target, XtSelectionCallbackCallback.getAddress(), 0, OS.CurrentTime); if (!done) { int xtContext = OS.XtDisplayToApplicationContext(xDisplay); int selectionTimeout = OS.XtAppGetSelectionTimeout(xtContext); wait(selectionTimeout); } } if (done && selectionValue == null) { done = false; target = atomAtom; OS.XtGetSelectionValue(shellHandle, selection, target, XtSelectionCallbackCallback.getAddress(), 0, OS.CurrentTime); if (!done) { int xtContext = OS.XtDisplayToApplicationContext(xDisplay); int selectionTimeout = OS.XtAppGetSelectionTimeout(xtContext); wait(selectionTimeout); } } return (!done || selectionValue == null) ? new int[0] : (int[])selectionValue; } void setContents(Clipboard owner, Object[] data, Transfer[] dataTypes, int clipboards) { if ((clipboards & DND.CLIPBOARD) != 0) { clipboardData = data; clipboardDataTypes = dataTypes; int XtConvertSelectionProc = XtConvertSelectionCallback.getAddress(); int XtLoseSelectionProc = XtLoseSelectionCallback.getAddress(); int XtSelectionDoneProc = XtSelectionDoneCallback.getAddress(); if (!OS.XtOwnSelection(shellHandle, clipboardAtom, OS.CurrentTime, XtConvertSelectionProc, XtLoseSelectionProc, XtSelectionDoneProc)) { DND.error(DND.ERROR_CANNOT_SET_CLIPBOARD); } activeClipboard = owner; } if ((clipboards & DND.SELECTION_CLIPBOARD) != 0) { primaryClipboardData = data; primaryClipboardDataTypes = dataTypes; int XtConvertSelectionProc = XtConvertSelectionCallback.getAddress(); int XtLoseSelectionProc = XtLoseSelectionCallback.getAddress(); int XtSelectionDoneProc = XtSelectionDoneCallback.getAddress(); if (!OS.XtOwnSelection(shellHandle, primaryAtom, OS.CurrentTime, XtConvertSelectionProc, XtLoseSelectionProc, XtSelectionDoneProc)) { DND.error(DND.ERROR_CANNOT_SET_CLIPBOARD); } activePrimaryClipboard = owner; } } void storePtr(int ptr, int selection, int target) { int index = -1; for (int i = 0; i < convertData.length; i++) { if (convertData[i][0] == 0){ index = i; break; } } if (index == -1) { int[][] newConvertData = new int[convertData.length + 4][3]; System.arraycopy(convertData, 0, newConvertData, 0, convertData.length); index = convertData.length; convertData = newConvertData; } convertData[index][0] = selection; convertData[index][1] = target; convertData[index][2] = ptr; } void wait(int timeout) { int xDisplay = OS.XtDisplay(shellHandle); if (xDisplay == 0) return; long start = System.currentTimeMillis(); Callback checkEventCallback = new Callback(this, "checkEvent", 3); //$NON-NLS-1$ int checkEventProc = checkEventCallback.getAddress(); if (checkEventProc == 0) SWT.error(SWT.ERROR_NO_MORE_CALLBACKS); int xEvent = OS.XtMalloc (XEvent.sizeof); display.timerExec(timeout, new Runnable() { public void run() { // timer required to force display.sleep() to wake up // in the case where no events are received } }); while (!done && System.currentTimeMillis() - start < timeout && display != null) { if (OS.XCheckIfEvent (xDisplay, xEvent, checkEventProc, 0) != 0) { OS.XtDispatchEvent(xEvent); } else { display.sleep(); } } OS.XtFree (xEvent); checkEventCallback.dispose(); } int checkEvent(int display, int event, int arg) { XEvent xEvent = new XEvent(); OS.memmove (xEvent, event, XEvent.sizeof); switch (xEvent.type) { case OS.SelectionClear: case OS.SelectionNotify: case OS.SelectionRequest: case OS.PropertyNotify: return 1; } return 0; } int XtConvertSelection(int widget, int selection, int target, int type, int value, int length, int format) { int selectionAtom = 0; if (selection != 0) { int[] dest = new int[1]; OS.memmove(dest, selection, 4); selectionAtom = dest[0]; } if (selectionAtom == 0) return 0; Transfer[] types = null; if (selectionAtom == clipboardAtom) types = clipboardDataTypes; if (selectionAtom == primaryAtom) types = primaryClipboardDataTypes; if (types == null) return 0; int targetAtom = 0; if (target != 0) { int[] dest = new int[1]; OS.memmove(dest, target, 4); targetAtom = dest[0]; } if (targetAtom == atomAtom || targetAtom == targetsAtom || targetAtom == motifClipboardAtom) { int[] transferTypes = new int[] {targetAtom}; for (int i = 0; i < types.length; i++) { TransferData[] subTypes = types[i].getSupportedTypes(); int[] newtransferTypes = new int[transferTypes.length + subTypes.length]; System.arraycopy(transferTypes, 0, newtransferTypes, 0, transferTypes.length); int index = transferTypes.length; transferTypes = newtransferTypes; for (int j = 0; j < subTypes.length; j++) { transferTypes[index++] = subTypes[j].type; } } int ptr = OS.XtMalloc(transferTypes.length*4); storePtr(ptr, selectionAtom, targetAtom); OS.memmove(ptr, transferTypes, transferTypes.length*4); OS.memmove(type, new int[]{targetAtom}, 4); OS.memmove(value, new int[] {ptr}, 4); OS.memmove(length, new int[]{transferTypes.length}, 4); OS.memmove(format, new int[]{32}, 4); return 1; } TransferData tdata = new TransferData(); tdata.type = targetAtom; int index = -1; for (int i = 0; i < types.length; i++) { if (types[i].isSupportedType(tdata)) { index = i; break; } } if (index == -1) return 0; Object[] data = selectionAtom == clipboardAtom ? clipboardData : primaryClipboardData; types[index].javaToNative(data[index], tdata); if (tdata.format < 8 || tdata.format % 8 != 0) { OS.XtFree(tdata.pValue); return 0; } // copy data back to value OS.memmove(type, new int[]{tdata.type}, 4); OS.memmove(value, new int[]{tdata.pValue}, 4); OS.memmove(length, new int[]{tdata.length}, 4); OS.memmove(format, new int[]{tdata.format}, 4); storePtr(tdata.pValue, selectionAtom, targetAtom); return 1; } int XtLoseSelection(int widget, int selection) { if (selection == clipboardAtom) { activeClipboard = null; clipboardData = null; clipboardDataTypes = null; } if (selection == primaryAtom) { activePrimaryClipboard = null; primaryClipboardData = null; primaryClipboardDataTypes = null; } return 0; } int XtSelectionCallback(int widget, int client_data, int selection, int type, int value, int length, int format) { done = true; int[] selectionType = new int[1]; if (type != 0) OS.memmove(selectionType, type, 4); if (selectionType[0] == 0) return 0; int[] selectionLength = new int[1]; if (length != 0) OS.memmove(selectionLength, length, 4); if (selectionLength[0] == 0) return 0; int[] selectionFormat = new int[1]; if (format != 0) OS.memmove(selectionFormat, format, 4); if (selectionType[0] == atomAtom || selectionType[0] == targetsAtom || selectionType[0] == motifClipboardAtom) { int[] targets = new int[selectionLength[0]]; OS.memmove(targets, value, selectionLength[0] * selectionFormat [0] / 8); selectionValue = targets; return 0; } if (selectionTransfer != null) { TransferData transferData = new TransferData(); transferData.type = selectionType[0]; transferData.length = selectionLength[0]; transferData.format = selectionFormat[0]; transferData.pValue = value; transferData.result = 1; selectionValue = selectionTransfer.nativeToJava(transferData); } return 0; } int XtSelectionDone(int widget, int selection, int target) { if (target == 0 || selection == 0) return 0; int[] selectionAtom = new int[1]; OS.memmove(selectionAtom, selection, 4); int[] targetAtom = new int[1]; OS.memmove(targetAtom, target, 4); for (int i = 0; i < convertData.length; i++) { if (convertData[i][0] == selectionAtom[0] && convertData[i][1] == targetAtom[0]) { OS.XtFree(convertData[i][2]); convertData[i][0] = convertData[i][1] = convertData[i][2] = 0; break; } } return 0; } }