diff options
author | Paul Pazderski | 2019-06-24 14:45:51 +0000 |
---|---|---|
committer | Paul Pazderski | 2019-06-30 07:19:05 +0000 |
commit | c1dbf469eda9d72bf46f698d1fc4b676aecb5559 (patch) | |
tree | 136bfe6d69bceae4c61c192e5bf23dfb05ebecea | |
parent | 0f3e134c4c34e816c8b0fd1862574fcce3a9b9f1 (diff) | |
download | eclipse.platform.swt-c1dbf469eda9d72bf46f698d1fc4b676aecb5559.tar.gz eclipse.platform.swt-c1dbf469eda9d72bf46f698d1fc4b676aecb5559.tar.xz eclipse.platform.swt-c1dbf469eda9d72bf46f698d1fc4b676aecb5559.zip |
Bug 547634 - [win32] Add CFSTR_SHELLIDLIST transfer type to FileTransfer
to support drop on taskbar
CFSTR_SHELLIDLIST transfer type is only added as drag source not as drop
target. Like the existing CF_HDROP transfer type implementation the new
transfer type allow dragging non existing file paths.
Change-Id: I02c4f64081ec2b55073e1878f99b8e52eeabdd01
Signed-off-by: Paul Pazderski <paul-eclipse@ppazderski.de>
19 files changed, 720 insertions, 50 deletions
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/FileTransfer.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/FileTransfer.java index 7f6ecfcf6f..2b94832fcf 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/FileTransfer.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/FileTransfer.java @@ -27,8 +27,8 @@ import org.eclipse.swt.internal.win32.*; * below:</p> * * <pre><code> - * File file1 = new File("C:\temp\file1"); - * File file2 = new File("C:\temp\file2"); + * File file1 = new File("C:\\temp\\file1"); + * File file2 = new File("C:\\temp\\file2"); * String[] fileData = new String[2]; * fileData[0] = file1.getAbsolutePath(); * fileData[1] = file2.getAbsolutePath(); @@ -39,8 +39,10 @@ import org.eclipse.swt.internal.win32.*; public class FileTransfer extends ByteArrayTransfer { private static FileTransfer _instance = new FileTransfer(); - private static final String CF_HDROP = "CF_HDROP "; //$NON-NLS-1$ + private static final String CF_HDROP = "CF_HDROP"; //$NON-NLS-1$ private static final int CF_HDROPID = COM.CF_HDROP; + private static final String CFSTR_SHELLIDLIST = "Shell IDList Array"; //$NON-NLS-1$ + private static final int CFSTR_SHELLIDLISTID = registerType(CFSTR_SHELLIDLIST); private FileTransfer() {} @@ -71,30 +73,37 @@ public void javaToNative(Object object, TransferData transferData) { DND.error(DND.ERROR_INVALID_DATA); } String[] fileNames = (String[]) object; - StringBuffer allFiles = new StringBuffer(); - for (int i = 0; i < fileNames.length; i++) { - allFiles.append(fileNames[i]); - allFiles.append('\0'); // each name is null terminated + long newPtr = 0; + if (transferData.type == CF_HDROPID) { + StringBuffer allFiles = new StringBuffer(); + for (int i = 0; i < fileNames.length; i++) { + allFiles.append(fileNames[i]); + allFiles.append('\0'); // each name is null terminated + } + allFiles.append('\0'); // there is an extra null terminator at the very end + char [] buffer = new char [allFiles.length()]; + allFiles.getChars(0, allFiles.length(), buffer, 0); + DROPFILES dropfiles = new DROPFILES(); + dropfiles.pFiles = DROPFILES.sizeof; + dropfiles.pt_x = dropfiles.pt_y = 0; + dropfiles.fNC = 0; + dropfiles.fWide = 1; + // Allocate the memory because the caller (DropTarget) has not handed it in + // The caller of this method must release the data when it is done with it. + int byteCount = buffer.length * TCHAR.sizeof; + newPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, DROPFILES.sizeof + byteCount); + if (newPtr != 0) { + OS.MoveMemory(newPtr, dropfiles, DROPFILES.sizeof); + OS.MoveMemory(newPtr + DROPFILES.sizeof, buffer, byteCount); + } + } else if (transferData.type == CFSTR_SHELLIDLISTID) { + newPtr = generateCidaFromFilepaths(fileNames); } - allFiles.append('\0'); // there is an extra null terminator at the very end - char [] buffer = new char [allFiles.length()]; - allFiles.getChars(0, allFiles.length(), buffer, 0); - DROPFILES dropfiles = new DROPFILES(); - dropfiles.pFiles = DROPFILES.sizeof; - dropfiles.pt_x = dropfiles.pt_y = 0; - dropfiles.fNC = 0; - dropfiles.fWide = 1; - // Allocate the memory because the caller (DropTarget) has not handed it in - // The caller of this method must release the data when it is done with it. - int byteCount = buffer.length * TCHAR.sizeof; - long newPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, DROPFILES.sizeof + byteCount); - OS.MoveMemory(newPtr, dropfiles, DROPFILES.sizeof); - OS.MoveMemory(newPtr + DROPFILES.sizeof, buffer, byteCount); transferData.stgmedium = new STGMEDIUM(); transferData.stgmedium.tymed = COM.TYMED_HGLOBAL; transferData.stgmedium.unionField = newPtr; transferData.stgmedium.pUnkForRelease = 0; - transferData.result = COM.S_OK; + transferData.result = newPtr != 0 ? COM.S_OK : COM.E_FAIL; } /** @@ -141,14 +150,84 @@ public Object nativeToJava(TransferData transferData) { return fileNames; } +/** + * Generate {@link CIDA} structure and trailing data to transfer filenames + * as {@link #CFSTR_SHELLIDLIST}. + * <p> + * For more information on the {@link CIDA} structure see also {@link #resolveCidaToFilepaths(long)}. + * </p> + * + * @param fileNames filenames to pack in {@link CIDA}. + * @return pointer to global memory chunk filled with generated data or <code>0</code> on failure + */ +private long generateCidaFromFilepaths(String[] fileNames) { + final int n = fileNames.length; + long [] pidls = new long [n]; + try { + CIDA cida = new CIDA(); + cida.cidl = n; + int cidaSize = CIDA.sizeof + 4 * n; + cida.aoffset = cidaSize; // offsets are from cida begin so the first is equal to cida size + + int[] pidlOffsets = new int[n]; + int[] pidlSizes = new int[n]; + int pidlSizeSum = 2; // initialize with 2 for the empty (but double null terminated) parent pidl + for (int i = 0; i < n; i++) { + TCHAR szfileName = new TCHAR(0, fileNames[i], true); + long [] ppv = new long [1]; + int hr = COM.PathToPIDL(szfileName.chars, ppv); + if (hr != OS.S_OK) { + return 0; + } + pidls[i] = ppv[0]; + pidlSizes[i] = OS.ILGetSize(pidls[i]); + pidlSizeSum += pidlSizes[i]; + + if (i == 0) { + pidlOffsets[0] = cidaSize + 2; + } + else { + pidlOffsets[i] = pidlOffsets[i - 1] + pidlSizes[i - 1]; + } + } + + long newPtr = OS.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, cidaSize + pidlSizeSum); + if (newPtr != 0) { + OS.MoveMemory(newPtr, cida, CIDA.sizeof); + OS.MoveMemory(newPtr + CIDA.sizeof, pidlOffsets, 4 * cida.cidl); + for (int i = 0; i < n; i++) { + OS.MoveMemory(newPtr + pidlOffsets[i], pidls[i], pidlSizes[i]); + } + } + return newPtr; + } finally { + for (int i = 0; i < n; i++) { + if (pidls[i] != 0) { + OS.CoTaskMemFree(pidls[i]); + } + } + } +} + +@Override +public boolean isSupportedType(TransferData transferData) { + // filter Shell ID List Array transfer only for dropping + if (transferData != null && transferData.pIDataObject != 0 && transferData.type == CFSTR_SHELLIDLISTID) { + return false; + } + return super.isSupportedType(transferData); +} + @Override protected int[] getTypeIds(){ - return new int[] {CF_HDROPID}; + // Note: FileTransfer adds Shell ID List as transfer type but later + // limit this type for dragging only. + return new int[] {CF_HDROPID, CFSTR_SHELLIDLISTID}; } @Override protected String[] getTypeNames(){ - return new String[] {CF_HDROP}; + return new String[] {CF_HDROP, CFSTR_SHELLIDLIST}; } boolean checkFile(Object object) { if (object == null || !(object instanceof String[]) || ((String[])object).length == 0) return false; diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/ImageTransfer.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/ImageTransfer.java index f5e21ec2a6..0c678f16c3 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/ImageTransfer.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/win32/org/eclipse/swt/dnd/ImageTransfer.java @@ -27,8 +27,8 @@ import org.eclipse.swt.internal.win32.*; * <p>An example of a java <code>ImageData</code> is shown below:</p> * * <pre><code> - * Image image = new Image(display, "C:\temp\img1.gif"); - * ImageData imgData = image.getImageData(); + * Image image = new Image(display, "C:\\temp\\img1.gif"); + * ImageData imgData = image.getImageData(); * </code></pre> * * @see Transfer diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/win32/library/com.c b/bundles/org.eclipse.swt/Eclipse SWT PI/win32/library/com.c index 11d2eff2fc..d663eca6e7 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/win32/library/com.c +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/win32/library/com.c @@ -894,6 +894,25 @@ fail: } #endif +#ifndef NO_PathToPIDL +JNIEXPORT jint JNICALL COM_NATIVE(PathToPIDL) + (JNIEnv *env, jclass that, jcharArray arg0, jlongArray arg1) +{ + jchar *lparg0=NULL; + jlong *lparg1=NULL; + jint rc = 0; + COM_NATIVE_ENTER(env, that, PathToPIDL_FUNC); + if (arg0) if ((lparg0 = (*env)->GetCharArrayElements(env, arg0, NULL)) == NULL) goto fail; + if (arg1) if ((lparg1 = (*env)->GetLongArrayElements(env, arg1, NULL)) == NULL) goto fail; + rc = (jint)PathToPIDL((PCWSTR)lparg0, (PIDLIST_ABSOLUTE)lparg1); +fail: + if (arg1 && lparg1) (*env)->ReleaseLongArrayElements(env, arg1, lparg1, 0); + if (arg0 && lparg0) (*env)->ReleaseCharArrayElements(env, arg0, lparg0, 0); + COM_NATIVE_EXIT(env, that, PathToPIDL_FUNC); + return rc; +} +#endif + #ifndef NO_ProgIDFromCLSID JNIEXPORT jint JNICALL COM_NATIVE(ProgIDFromCLSID) (JNIEnv *env, jclass that, jobject arg0, jlongArray arg1) diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/win32/library/com_custom.c b/bundles/org.eclipse.swt/Eclipse SWT PI/win32/library/com_custom.c deleted file mode 100644 index 590330a0fb..0000000000 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/win32/library/com_custom.c +++ /dev/null @@ -1,19 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2000, 2010 IBM Corporation and others. - * - * This program and the accompanying materials - * are made available under the terms of the Eclipse Public License 2.0 - * which accompanies this distribution, and is available at - * https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * IBM Corporation - initial API and implementation - *******************************************************************************/ - -#include "swt.h" -#include "com_structs.h" -#include "com_stats.h" - -#define COM_NATIVE(func) Java_org_eclipse_swt_internal_ole_win32_COM_##func diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/win32/library/com_custom.cpp b/bundles/org.eclipse.swt/Eclipse SWT PI/win32/library/com_custom.cpp new file mode 100644 index 0000000000..e4509e4c94 --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/win32/library/com_custom.cpp @@ -0,0 +1,108 @@ +/******************************************************************************* + * Copyright (c) 2000, 2019 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + * Paul Pazderski - Bug 547634: PathToPIDL + *******************************************************************************/ + +#include "swt.h" +#include "com_structs.h" +#include "com_stats.h" +#include <Shlobj.h> + +#define COM_NATIVE(func) Java_org_eclipse_swt_internal_ole_win32_COM_##func + +class CFileSysBindData : public IFileSystemBindData +{ +public: + CFileSysBindData() : refCount(1) + { + ZeroMemory(&findData, sizeof(findData)); + } + + IFACEMETHODIMP QueryInterface(REFIID riid, void **ppv) + { + *ppv = nullptr; + HRESULT hr = E_NOINTERFACE; + if (riid == IID_IUnknown || riid == IID_IFileSystemBindData) { + *ppv = static_cast<IFileSystemBindData*>(this); + AddRef(); + hr = S_OK; + } + return hr; + } + + IFACEMETHODIMP_(ULONG) AddRef() + { + return InterlockedIncrement(&refCount); + } + + IFACEMETHODIMP_(ULONG) Release() + { + long rc = InterlockedDecrement(&refCount); + if (!rc) + delete this; + return rc; + } + + IFACEMETHODIMP SetFindData(const WIN32_FIND_DATAW *pfd) + { + findData = *pfd; + return S_OK; + } + + IFACEMETHODIMP GetFindData(WIN32_FIND_DATAW *pfd) + { + *pfd = findData; + return S_OK; + } + +private: + long refCount; + WIN32_FIND_DATAW findData; +}; + +/* + * An extended version of SHParseDisplayName which ignores the attribute query part + * and use bind context to support creation of simple PIDLs for non existing paths. + */ +extern "C" HRESULT PathToPIDL(PCWSTR pszName, PIDLIST_ABSOLUTE *ppidl) +{ + if (!ppidl) return E_FAIL; + *ppidl = nullptr; + + IFileSystemBindData *pfsbd = new CFileSysBindData(); + if (!pfsbd) return E_OUTOFMEMORY; + + WIN32_FIND_DATAW data = {}; + pfsbd->SetFindData(&data); + + IBindCtx* pbc; + + HRESULT hr = CreateBindCtx(0, &pbc); + if (hr == S_OK) + { + BIND_OPTS bo = { sizeof(bo), 0, STGM_CREATE, 0 }; + hr = pbc->SetBindOptions(&bo); + if (hr == S_OK) + { + hr = pbc->RegisterObjectParam(STR_FILE_SYS_BIND_DATA, pfsbd); + if (hr == S_OK) + { + SFGAOF sfgao = 0; + hr = SHParseDisplayName(pszName, pbc, ppidl, sfgao, &sfgao); + } + } + pbc->Release(); + } + pfsbd->Release(); + return hr; +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/win32/library/com_custom.h b/bundles/org.eclipse.swt/Eclipse SWT PI/win32/library/com_custom.h index d7bbd072b4..eff05db8cc 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/win32/library/com_custom.h +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/win32/library/com_custom.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2010 IBM Corporation and others. + * Copyright (c) 2000, 2019 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -21,3 +21,12 @@ #define AccessibleObjectFromWindow_LIB "oleacc.dll" #define CreateStdAccessibleObject_LIB "oleacc.dll" #define LresultFromObject_LIB "oleacc.dll" + +/* Custom functions */ +#ifdef __cplusplus +extern "C" { +#endif +HRESULT PathToPIDL(_In_ PCWSTR pszName, _Outptr_ PIDLIST_ABSOLUTE *ppidl); +#ifdef __cplusplus +} +#endif diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/win32/library/com_stats.c b/bundles/org.eclipse.swt/Eclipse SWT PI/win32/library/com_stats.c index 407a2b5da8..492c6b530e 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/win32/library/com_stats.c +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/win32/library/com_stats.c @@ -78,6 +78,7 @@ char * COM_nativeFunctionNames[] = { "OleSetContainedObject", "OleSetMenuDescriptor", "OleTranslateColor", + "PathToPIDL", "ProgIDFromCLSID", "RegisterDragDrop", "ReleaseStgMedium", diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/win32/library/com_stats.h b/bundles/org.eclipse.swt/Eclipse SWT PI/win32/library/com_stats.h index 8f6070dd67..b25d4f9f20 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/win32/library/com_stats.h +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/win32/library/com_stats.h @@ -88,6 +88,7 @@ typedef enum { OleSetContainedObject_FUNC, OleSetMenuDescriptor_FUNC, OleTranslateColor_FUNC, + PathToPIDL_FUNC, ProgIDFromCLSID_FUNC, RegisterDragDrop_FUNC, ReleaseStgMedium_FUNC, diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/win32/library/os.c b/bundles/org.eclipse.swt/Eclipse SWT PI/win32/library/os.c index 416a2eee99..7ff02ec395 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/win32/library/os.c +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/win32/library/os.c @@ -450,6 +450,18 @@ JNIEXPORT jint JNICALL OS_NATIVE(CHOOSEFONT_1sizeof) } #endif +#ifndef NO_CIDA_1sizeof +JNIEXPORT jint JNICALL OS_NATIVE(CIDA_1sizeof) + (JNIEnv *env, jclass that) +{ + jint rc = 0; + OS_NATIVE_ENTER(env, that, CIDA_1sizeof_FUNC); + rc = (jint)CIDA_sizeof(); + OS_NATIVE_EXIT(env, that, CIDA_1sizeof_FUNC); + return rc; +} +#endif + #ifndef NO_COMBOBOXINFO_1sizeof JNIEXPORT jint JNICALL OS_NATIVE(COMBOBOXINFO_1sizeof) (JNIEnv *env, jclass that) @@ -4106,6 +4118,18 @@ fail: } #endif +#ifndef NO_ILGetSize +JNIEXPORT jint JNICALL OS_NATIVE(ILGetSize) + (JNIEnv *env, jclass that, jlong arg0) +{ + jint rc = 0; + OS_NATIVE_ENTER(env, that, ILGetSize_FUNC); + rc = (jint)ILGetSize((PCIDLIST_ABSOLUTE)arg0); + OS_NATIVE_EXIT(env, that, ILGetSize_FUNC); + return rc; +} +#endif + #ifndef NO_INITCOMMONCONTROLSEX_1sizeof JNIEXPORT jint JNICALL OS_NATIVE(INITCOMMONCONTROLSEX_1sizeof) (JNIEnv *env, jclass that) @@ -5392,6 +5416,19 @@ JNIEXPORT void JNICALL OS_NATIVE(MoveMemory__JJI) } #endif +#ifndef NO_MoveMemory__JLorg_eclipse_swt_internal_win32_CIDA_2I +JNIEXPORT void JNICALL OS_NATIVE(MoveMemory__JLorg_eclipse_swt_internal_win32_CIDA_2I) + (JNIEnv *env, jclass that, jlong arg0, jobject arg1, jint arg2) +{ + CIDA _arg1, *lparg1=NULL; + OS_NATIVE_ENTER(env, that, MoveMemory__JLorg_eclipse_swt_internal_win32_CIDA_2I_FUNC); + if (arg1) if ((lparg1 = getCIDAFields(env, arg1, &_arg1)) == NULL) goto fail; + MoveMemory((PVOID)arg0, (CONST VOID *)lparg1, arg2); +fail: + OS_NATIVE_EXIT(env, that, MoveMemory__JLorg_eclipse_swt_internal_win32_CIDA_2I_FUNC); +} +#endif + #ifndef NO_MoveMemory__JLorg_eclipse_swt_internal_win32_DEVMODE_2I JNIEXPORT void JNICALL OS_NATIVE(MoveMemory__JLorg_eclipse_swt_internal_win32_DEVMODE_2I) (JNIEnv *env, jclass that, jlong arg0, jobject arg1, jint arg2) @@ -5862,6 +5899,20 @@ fail: } #endif +#ifndef NO_MoveMemory__Lorg_eclipse_swt_internal_win32_CIDA_2JI +JNIEXPORT void JNICALL OS_NATIVE(MoveMemory__Lorg_eclipse_swt_internal_win32_CIDA_2JI) + (JNIEnv *env, jclass that, jobject arg0, jlong arg1, jint arg2) +{ + CIDA _arg0, *lparg0=NULL; + OS_NATIVE_ENTER(env, that, MoveMemory__Lorg_eclipse_swt_internal_win32_CIDA_2JI_FUNC); + if (arg0) if ((lparg0 = &_arg0) == NULL) goto fail; + MoveMemory((PVOID)lparg0, (CONST VOID *)arg1, arg2); +fail: + if (arg0 && lparg0) setCIDAFields(env, arg0, lparg0); + OS_NATIVE_EXIT(env, that, MoveMemory__Lorg_eclipse_swt_internal_win32_CIDA_2JI_FUNC); +} +#endif + #ifndef NO_MoveMemory__Lorg_eclipse_swt_internal_win32_DEVMODE_2JI JNIEXPORT void JNICALL OS_NATIVE(MoveMemory__Lorg_eclipse_swt_internal_win32_DEVMODE_2JI) (JNIEnv *env, jclass that, jobject arg0, jlong arg1, jint arg2) diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/win32/library/os_stats.c b/bundles/org.eclipse.swt/Eclipse SWT PI/win32/library/os_stats.c index 19895a44cc..fb697d329a 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/win32/library/os_stats.c +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/win32/library/os_stats.c @@ -53,6 +53,7 @@ char * OS_nativeFunctionNames[] = { "CERT_1PUBLIC_1KEY_1INFO_1sizeof", "CHOOSECOLOR_1sizeof", "CHOOSEFONT_1sizeof", + "CIDA_1sizeof", "COMBOBOXINFO_1sizeof", "COMPOSITIONFORM_1sizeof", "CREATESTRUCT_1sizeof", @@ -313,6 +314,7 @@ char * OS_nativeFunctionNames[] = { "HideCaret", "ICONINFO_1sizeof", "IIDFromString", + "ILGetSize", "INITCOMMONCONTROLSEX_1sizeof", "INPUT_1sizeof", "ImageList_1Add", @@ -410,6 +412,7 @@ char * OS_nativeFunctionNames[] = { "ModifyWorldTransform", "MonitorFromWindow", "MoveMemory__JJI", + "MoveMemory__JLorg_eclipse_swt_internal_win32_CIDA_2I", "MoveMemory__JLorg_eclipse_swt_internal_win32_DEVMODE_2I", "MoveMemory__JLorg_eclipse_swt_internal_win32_DOCHOSTUIINFO_2I", "MoveMemory__JLorg_eclipse_swt_internal_win32_DROPFILES_2I", @@ -445,6 +448,7 @@ char * OS_nativeFunctionNames[] = { "MoveMemory__Lorg_eclipse_swt_internal_win32_BITMAPINFOHEADER_2_3BI", "MoveMemory__Lorg_eclipse_swt_internal_win32_CERT_1CONTEXT_2JI", "MoveMemory__Lorg_eclipse_swt_internal_win32_CERT_1INFO_2JI", + "MoveMemory__Lorg_eclipse_swt_internal_win32_CIDA_2JI", "MoveMemory__Lorg_eclipse_swt_internal_win32_DEVMODE_2JI", "MoveMemory__Lorg_eclipse_swt_internal_win32_DOCHOSTUIINFO_2JI", "MoveMemory__Lorg_eclipse_swt_internal_win32_DRAWITEMSTRUCT_2JI", diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/win32/library/os_stats.h b/bundles/org.eclipse.swt/Eclipse SWT PI/win32/library/os_stats.h index ab3155cf1a..0508568c46 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/win32/library/os_stats.h +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/win32/library/os_stats.h @@ -63,6 +63,7 @@ typedef enum { CERT_1PUBLIC_1KEY_1INFO_1sizeof_FUNC, CHOOSECOLOR_1sizeof_FUNC, CHOOSEFONT_1sizeof_FUNC, + CIDA_1sizeof_FUNC, COMBOBOXINFO_1sizeof_FUNC, COMPOSITIONFORM_1sizeof_FUNC, CREATESTRUCT_1sizeof_FUNC, @@ -323,6 +324,7 @@ typedef enum { HideCaret_FUNC, ICONINFO_1sizeof_FUNC, IIDFromString_FUNC, + ILGetSize_FUNC, INITCOMMONCONTROLSEX_1sizeof_FUNC, INPUT_1sizeof_FUNC, ImageList_1Add_FUNC, @@ -420,6 +422,7 @@ typedef enum { ModifyWorldTransform_FUNC, MonitorFromWindow_FUNC, MoveMemory__JJI_FUNC, + MoveMemory__JLorg_eclipse_swt_internal_win32_CIDA_2I_FUNC, MoveMemory__JLorg_eclipse_swt_internal_win32_DEVMODE_2I_FUNC, MoveMemory__JLorg_eclipse_swt_internal_win32_DOCHOSTUIINFO_2I_FUNC, MoveMemory__JLorg_eclipse_swt_internal_win32_DROPFILES_2I_FUNC, @@ -455,6 +458,7 @@ typedef enum { MoveMemory__Lorg_eclipse_swt_internal_win32_BITMAPINFOHEADER_2_3BI_FUNC, MoveMemory__Lorg_eclipse_swt_internal_win32_CERT_1CONTEXT_2JI_FUNC, MoveMemory__Lorg_eclipse_swt_internal_win32_CERT_1INFO_2JI_FUNC, + MoveMemory__Lorg_eclipse_swt_internal_win32_CIDA_2JI_FUNC, MoveMemory__Lorg_eclipse_swt_internal_win32_DEVMODE_2JI_FUNC, MoveMemory__Lorg_eclipse_swt_internal_win32_DOCHOSTUIINFO_2JI_FUNC, MoveMemory__Lorg_eclipse_swt_internal_win32_DRAWITEMSTRUCT_2JI_FUNC, diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/win32/library/os_structs.c b/bundles/org.eclipse.swt/Eclipse SWT PI/win32/library/os_structs.c index 0e58a96622..4a8266ed5e 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/win32/library/os_structs.c +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/win32/library/os_structs.c @@ -819,6 +819,40 @@ void setCHOOSEFONTFields(JNIEnv *env, jobject lpObject, CHOOSEFONT *lpStruct) } #endif +#ifndef NO_CIDA +typedef struct CIDA_FID_CACHE { + int cached; + jclass clazz; + jfieldID cidl, aoffset; +} CIDA_FID_CACHE; + +CIDA_FID_CACHE CIDAFc; + +void cacheCIDAFields(JNIEnv *env, jobject lpObject) +{ + if (CIDAFc.cached) return; + CIDAFc.clazz = (*env)->GetObjectClass(env, lpObject); + CIDAFc.cidl = (*env)->GetFieldID(env, CIDAFc.clazz, "cidl", "I"); + CIDAFc.aoffset = (*env)->GetFieldID(env, CIDAFc.clazz, "aoffset", "I"); + CIDAFc.cached = 1; +} + +CIDA *getCIDAFields(JNIEnv *env, jobject lpObject, CIDA *lpStruct) +{ + if (!CIDAFc.cached) cacheCIDAFields(env, lpObject); + lpStruct->cidl = (*env)->GetIntField(env, lpObject, CIDAFc.cidl); + lpStruct->aoffset[0] = (*env)->GetIntField(env, lpObject, CIDAFc.aoffset); + return lpStruct; +} + +void setCIDAFields(JNIEnv *env, jobject lpObject, CIDA *lpStruct) +{ + if (!CIDAFc.cached) cacheCIDAFields(env, lpObject); + (*env)->SetIntField(env, lpObject, CIDAFc.cidl, (jint)lpStruct->cidl); + (*env)->SetIntField(env, lpObject, CIDAFc.aoffset, (jint)lpStruct->aoffset[0]); +} +#endif + #ifndef NO_COMBOBOXINFO typedef struct COMBOBOXINFO_FID_CACHE { int cached; diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/win32/library/os_structs.h b/bundles/org.eclipse.swt/Eclipse SWT PI/win32/library/os_structs.h index c704b10f8c..6182b6c01b 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/win32/library/os_structs.h +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/win32/library/os_structs.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2018 IBM Corporation and others. + * Copyright (c) 2000, 2019 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -197,6 +197,18 @@ void setCHOOSEFONTFields(JNIEnv *env, jobject lpObject, CHOOSEFONT *lpStruct); #define CHOOSEFONT_sizeof() 0 #endif +#ifndef NO_CIDA +void cacheCIDAFields(JNIEnv *env, jobject lpObject); +CIDA *getCIDAFields(JNIEnv *env, jobject lpObject, CIDA *lpStruct); +void setCIDAFields(JNIEnv *env, jobject lpObject, CIDA *lpStruct); +#define CIDA_sizeof() sizeof(CIDA) +#else +#define cacheCIDAFields(a,b) +#define getCIDAFields(a,b,c) NULL +#define setCIDAFields(a,b,c) +#define CIDA_sizeof() 0 +#endif + #ifndef NO_COMBOBOXINFO void cacheCOMBOBOXINFOFields(JNIEnv *env, jobject lpObject); COMBOBOXINFO *getCOMBOBOXINFOFields(JNIEnv *env, jobject lpObject, COMBOBOXINFO *lpStruct); diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/win32/org/eclipse/swt/internal/ole/win32/COM.java b/bundles/org.eclipse.swt/Eclipse SWT PI/win32/org/eclipse/swt/internal/ole/win32/COM.java index db75d0c91d..11da510822 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/win32/org/eclipse/swt/internal/ole/win32/COM.java +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/win32/org/eclipse/swt/internal/ole/win32/COM.java @@ -633,6 +633,12 @@ public static final native int OleSetMenuDescriptor(long holemenu, long hwndFram * @param pcolorref cast=(COLORREF *) */ public static final native int OleTranslateColor(int clr, long hpal, int[] pcolorref); +/** + * Custom native function. + * @param pszName cast=(PCWSTR) + * @param ppidl cast=(PIDLIST_ABSOLUTE) + */ +public static final native int PathToPIDL (char [] pszName, long [] ppidl); /** @param lplpszProgID cast=(LPOLESTR *) */ public static final native int ProgIDFromCLSID(GUID clsid, long[] lplpszProgID); /** diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/win32/org/eclipse/swt/internal/win32/CIDA.java b/bundles/org.eclipse.swt/Eclipse SWT PI/win32/org/eclipse/swt/internal/win32/CIDA.java new file mode 100644 index 0000000000..ad0085386f --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/win32/org/eclipse/swt/internal/win32/CIDA.java @@ -0,0 +1,25 @@ +/******************************************************************************* + * Copyright (c) 2019 Paul Pazderski and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Paul Pazderski - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.internal.win32; + +/** + * @see <a href="https://docs.microsoft.com/en-us/windows/desktop/api/shlobj_core/ns-shlobj_core-_ida">WinAPI documentation: CIDA</a> + */ +public class CIDA { + public int cidl; + /** @field accessor=aoffset[0] */ + public int aoffset; + // minimum size since the actual size depends on the number of offsets + public static final int sizeof = OS.CIDA_sizeof (); +} diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/win32/org/eclipse/swt/internal/win32/OS.java b/bundles/org.eclipse.swt/Eclipse SWT PI/win32/org/eclipse/swt/internal/win32/OS.java index 739dc438f4..2ba2550243 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT PI/win32/org/eclipse/swt/internal/win32/OS.java +++ b/bundles/org.eclipse.swt/Eclipse SWT PI/win32/org/eclipse/swt/internal/win32/OS.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2018 IBM Corporation and others. + * Copyright (c) 2000, 2019 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 @@ -2021,6 +2021,7 @@ public static final native int HDHITTESTINFO_sizeof (); public static final native int HELPINFO_sizeof (); public static final native int HIGHCONTRAST_sizeof (); public static final native int ICONINFO_sizeof (); +public static final native int CIDA_sizeof (); public static final native int INITCOMMONCONTROLSEX_sizeof (); public static final native int INPUT_sizeof (); public static final native int KEYBDINPUT_sizeof (); @@ -3108,6 +3109,10 @@ public static final native boolean HideCaret (long hWnd); */ public static final native int IIDFromString (char[] lpsz, byte[] lpiid); /** + * @param pidl cast=(PCIDLIST_ABSOLUTE) + */ +public static final native int ILGetSize(long pidl); +/** * @param himl cast=(HIMAGELIST) * @param hbmImage cast=(HBITMAP) * @param hbmMask cast=(HBITMAP) @@ -3790,6 +3795,16 @@ public static final native void MoveMemory (long Destination, MOUSEINPUT Source, */ public static final native void MoveMemory (long Destination, GESTURECONFIG Source, int Length); /** + * @param Destination cast=(PVOID) + * @param Source cast=(CONST VOID *),flags=no_out + */ +public static final native void MoveMemory (long Destination, CIDA Source, int Length); +/** + * @param Destination cast=(PVOID),flags=no_in + * @param Source cast=(CONST VOID *) + */ +public static final native void MoveMemory (CIDA Destination, long Source, int Length); +/** * @param hdc cast=(HDC) * @param lPoint cast=(LPPOINT) */ diff --git a/tests/org.eclipse.swt.tests.win32/JUnit Tests/org/eclipse/swt/tests/win32/AllWin32Tests.java b/tests/org.eclipse.swt.tests.win32/JUnit Tests/org/eclipse/swt/tests/win32/AllWin32Tests.java index 411fe41953..4bdcf97204 100644 --- a/tests/org.eclipse.swt.tests.win32/JUnit Tests/org/eclipse/swt/tests/win32/AllWin32Tests.java +++ b/tests/org.eclipse.swt.tests.win32/JUnit Tests/org/eclipse/swt/tests/win32/AllWin32Tests.java @@ -14,19 +14,20 @@ */ package org.eclipse.swt.tests.win32; +import org.junit.runner.JUnitCore; import org.junit.runner.RunWith; import org.junit.runners.Suite; @RunWith(Suite.class) @Suite.SuiteClasses({ - // Test.class be added here. + Test_org_eclipse_swt_dnd_DND.class, }) public class AllWin32Tests { public static void main(String[] args) { -// JUnitCore.main(AllWin32Tests.class.getName()); // Enable once a test is added. + JUnitCore.main(AllWin32Tests.class.getName()); } } diff --git a/tests/org.eclipse.swt.tests.win32/JUnit Tests/org/eclipse/swt/tests/win32/SwtWin32TestUtil.java b/tests/org.eclipse.swt.tests.win32/JUnit Tests/org/eclipse/swt/tests/win32/SwtWin32TestUtil.java new file mode 100644 index 0000000000..d374b9f64d --- /dev/null +++ b/tests/org.eclipse.swt.tests.win32/JUnit Tests/org/eclipse/swt/tests/win32/SwtWin32TestUtil.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright (c) 2019 Paul Pazderski and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Paul Pazderski - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.tests.win32; + +import java.util.function.BooleanSupplier; + +import org.eclipse.swt.widgets.Display; + +public class SwtWin32TestUtil { + +/** + * Dispatch events until <em>condition</em> is <code>true</code> or timeout reached. + * + * @param display display to dispatch events for (not <code>null</code>) + * @param timeoutMs max time in milliseconds to process events + * @param condition optional condition. If the condition returns <code>true</code> event processing is stopped. + */ +public static void processEvents(Display display, int timeoutMs, BooleanSupplier condition) throws InterruptedException { + if (condition == null) { + condition = () -> false; + } + long targetTimestamp = System.currentTimeMillis() + timeoutMs; + while (!condition.getAsBoolean()) { + if (!display.readAndDispatch()) { + if (System.currentTimeMillis() < targetTimestamp) { + Thread.sleep(50); + } else { + return; + } + } + } +} +} diff --git a/tests/org.eclipse.swt.tests.win32/JUnit Tests/org/eclipse/swt/tests/win32/Test_org_eclipse_swt_dnd_DND.java b/tests/org.eclipse.swt.tests.win32/JUnit Tests/org/eclipse/swt/tests/win32/Test_org_eclipse_swt_dnd_DND.java new file mode 100644 index 0000000000..6d6d56678b --- /dev/null +++ b/tests/org.eclipse.swt.tests.win32/JUnit Tests/org/eclipse/swt/tests/win32/Test_org_eclipse_swt_dnd_DND.java @@ -0,0 +1,276 @@ +/******************************************************************************* + * Copyright (c) 2019 Paul Pazderski and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Paul Pazderski - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.tests.win32; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.util.Random; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.dnd.ByteArrayTransfer; +import org.eclipse.swt.dnd.DND; +import org.eclipse.swt.dnd.DragSource; +import org.eclipse.swt.dnd.DropTarget; +import org.eclipse.swt.dnd.FileTransfer; +import org.eclipse.swt.dnd.HTMLTransfer; +import org.eclipse.swt.dnd.ImageTransfer; +import org.eclipse.swt.dnd.RTFTransfer; +import org.eclipse.swt.dnd.TextTransfer; +import org.eclipse.swt.dnd.Transfer; +import org.eclipse.swt.dnd.URLTransfer; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.ImageData; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.layout.RowLayout; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Shell; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +/** + * Some simple tests for drag and drop. + * <p> + * To test drag and drop the appropriate user input must be simulated. This + * requires that the test window is visible/active/focused and if it fails may + * move something or trigger other actions when the input is simulated but the + * test window not at the expected position. This should be no problem for fully + * automated tests but may disturb when run locally in background as part of a + * larger test suite. + * </p> + */ +public class Test_org_eclipse_swt_dnd_DND { + +private Shell shell; + +@Before +public void setUp() { + shell = new Shell(); + shell.setLayout(new RowLayout()); + shell.setSize(300, 300); + shell.open(); + try { + SwtWin32TestUtil.processEvents(shell.getDisplay(), 1000, shell::isVisible); + } catch (InterruptedException e) { + fail("Initialization interrupted"); + } + assertTrue("Shell not visible.", shell.isVisible()); +} + +@After +public void tearDown() { + Display display = shell.getDisplay(); + display.dispose(); + assertTrue(display.isDisposed()); +} + +/** + * DnD some random bytes using a custom transfer type and the abstract {@link ByteArrayTransfer}. + */ +@Test +public void testByteArrayTransfer() throws InterruptedException { + final byte[] drag = new byte[1024]; + final byte[] drop; + + new Random(4).nextBytes(drag); + drop = testTransferRoundtrip(new ByteArrayTransfer() { + private final String TEST_TYPE = "SWT JUnit Transfer Test"; + private final int TEST_ID = registerType(TEST_TYPE); + + @Override + protected String[] getTypeNames() { + return new String[] { TEST_TYPE }; + } + + @Override + protected int[] getTypeIds() { + return new int[] { TEST_ID }; + } + }, drag); + assertArrayEquals("Drop received other data as we dragged.", drag, drop); +} + +/** + * DnD some filenames using the {@link FileTransfer}. + */ +@Test +public void testFileTransfer() throws InterruptedException { + final String[] drag = new String[] { "C:\\temp\\file1", "C:\\temp\\file2" }; + final String[] drop; + + drop = testTransferRoundtrip(FileTransfer.getInstance(), drag); + assertArrayEquals("Drop received other data as we dragged.", drag, drop); +} + +/** + * DnD some HTML using the {@link HTMLTransfer}. + */ +@Test +public void testHtmlTransfer() throws InterruptedException { + final String drag = "<p>This is a paragraph of text.</p>"; + final String drop; + + drop = testTransferRoundtrip(HTMLTransfer.getInstance(), drag); + assertEquals("Drop received other data as we dragged.", drag, drop); +} + +/** + * DnD an image using the {@link ImageTransfer}. + */ +@Test +public void testImageTransfer() throws InterruptedException { + final Image image = new Image(shell.getDisplay(), 16, 16); + try { + Color color = shell.getDisplay().getSystemColor(SWT.COLOR_DARK_BLUE); + GC gc = new GC(image); + gc.setBackground(color); + gc.fillRectangle(image.getBounds()); + gc.dispose(); + + final ImageData drag = image.getImageData(); + final ImageData drop; + + drop = testTransferRoundtrip(ImageTransfer.getInstance(), drag); + // ImageData has no custom equals method and the default one isn't sufficient + boolean equals = (drag == drop); + if (!equals && drag != null && drop != null) { + equals = (drag.width == drop.width && drag.height == drop.height); + if (equals) { + outer: for (int y = 0; y < drag.height; y++) { + for (int x = 0; x < drag.width; x++) { + if (drag.getPixel(x, y) != drop.getPixel(x, y)) { + equals = false; + break outer; + } + } + } + } + } + assertTrue("Drop received other data as we dragged.", equals); + } finally { + image.dispose(); + } +} + +/** + * DnD some formatted text using the {@link RTFTransfer}. + */ +@Test +public void testRtfTransfer() throws InterruptedException { + final String drag = "{\\rtf1{\\colortbl;\\red255\\green0\\blue0;}\\uc1\\b\\i Hello World}"; + final String drop; + + drop = testTransferRoundtrip(RTFTransfer.getInstance(), drag); + assertEquals("Drop received other data as we dragged.", drag, drop); +} + +/** + * DnD some simple text using the {@link TextTransfer}. + */ +@Test +public void testTextTransfer() throws InterruptedException { + final String drag = "Hello World"; + final String drop; + + drop = testTransferRoundtrip(TextTransfer.getInstance(), drag); + assertEquals("Drop received other data as we dragged.", drag, drop); +} + +/** + * DnD an URL using the {@link URLTransfer}. + */ +@Test +public void testUrlTransfer() throws InterruptedException { + final String drag = "https://www.eclipse.org"; + final String drop; + + drop = testTransferRoundtrip(URLTransfer.getInstance(), drag); + assertEquals("Drop received other data as we dragged.", drag, drop); +} + +/** + * Test transfer implementation by dragging and dropping some data onto ourself. + * + * @param <T> the data's type + * @param transfer the transfer type to test + * @param data the data to drag and drop + * @return the data received from the drop + */ +private <T> T testTransferRoundtrip(Transfer transfer, T data) throws InterruptedException { + int maxTries = 3; + AtomicBoolean dropped = new AtomicBoolean(false); + AtomicReference<T> droppedData = new AtomicReference<>(null); + + DragSource source = new DragSource(shell, DND.DROP_LINK | DND.DROP_COPY | DND.DROP_MOVE); + source.setTransfer(transfer); + source.addListener(DND.DragSetData, event -> event.data = data); + + DropTarget target = new DropTarget(shell, DND.DROP_DEFAULT | DND.DROP_COPY | DND.DROP_LINK | DND.DROP_MOVE); + target.setTransfer(transfer); + target.addListener(DND.Drop, event -> { + try { + @SuppressWarnings("unchecked") + T o = (T) event.data; + droppedData.set(o); + } catch (ClassCastException ex) { + } + dropped.set(true); + }); + + do { + postDragAndDropEvents(); + SwtWin32TestUtil.processEvents(shell.getDisplay(), 2000, dropped::get); + } while(!dropped.get() && --maxTries > 0); + + assertTrue("No drop received.", dropped.get()); + assertNotNull("No data was dropped.", droppedData.get()); + + return droppedData.get(); +} + +/** + * Posts the events required to do a drag and drop. (i.e. click and hold mouse button and move mouse) + * <p> + * The caller is responsible to ensure the generated events are processed by the event loop. + * </p> + */ +private void postDragAndDropEvents() { + shell.forceActive(); + assertTrue("Test shell requires input focus.", shell.forceFocus()); + Event event = new Event(); + Point pt = shell.toDisplay(50, 50); + event.x = pt.x; + event.y = pt.y; + event.type = SWT.MouseMove; + shell.getDisplay().post(event); + event.button = 1; + event.count = 1; + event.type = SWT.MouseDown; + shell.getDisplay().post(event); + event.x += 30; + event.type = SWT.MouseMove; + shell.getDisplay().post(event); + event.type = SWT.MouseUp; + shell.getDisplay().post(event); +} +} |