1 /* 2 * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #include "common.h" 27 28 #include "GlassDnD.h" 29 #include "GlassClipboard.h" 30 #include "GlassApplication.h" 31 32 #include "com_sun_glass_events_MouseEvent.h" 33 34 //Ctrl + Shift -> ACTION_LINK 35 //Ctrl -> ACTION_COPY 36 //Shift -> ACTION_MOVE 37 GlassDropTarget::GlassDropTarget(ViewContainer *viewContainer, HWND hwnd) 38 { 39 OLE_TRY 40 41 m_viewContainer = viewContainer; 42 m_hwnd = hwnd; 43 44 OLE_HRT(CoCreateInstance( 45 CLSID_DragDropHelper, 46 NULL, 47 CLSCTX_ALL, 48 IID_IDropTargetHelper, 49 (LPVOID*)&m_spDropTargetHelper 50 )) 51 OLE_HRT(::RegisterDragDrop(m_hwnd, this)) 52 OLE_CATCH 53 STRACE(_T("{GlassDropTarget")); 54 } 55 56 GlassDropTarget::~GlassDropTarget() 57 { 58 m_spDropTargetHelper = NULL; 59 ::RevokeDragDrop(m_hwnd); 60 STRACE(_T("}GlassDropTarget")); 61 } 62 63 HRESULT GlassDropTarget::UpdateDnDClipboardData( 64 IDataObject *pDataObj) 65 { 66 JNIEnv *env = GetEnv(); 67 //Get "DnD" clipboard 68 JLClass jcWinDnDClipboard(env, 69 GlassApplication::ClassForName(env, "com.sun.glass.ui.win.WinDnDClipboard")); 70 ASSERT(jcWinDnDClipboard) 71 static jmethodID midGetInstance = env->GetStaticMethodID(jcWinDnDClipboard, "getInstance", 72 "()Lcom/sun/glass/ui/win/WinDnDClipboard;"); 73 ASSERT(midGetInstance) 74 HRESULT result = checkJavaException(env); 75 if (result != S_OK) { 76 return result; 77 } 78 JLObject jDnDClipboard(env, env->CallStaticObjectMethod(jcWinDnDClipboard, midGetInstance)); 79 ASSERT(jDnDClipboard) 80 81 IDataObject *pOldDataObj = getPtr(env, jDnDClipboard); 82 if (pOldDataObj != pDataObj) { 83 if (NULL != pDataObj) { 84 //lock it till clipboard close 85 pDataObj->AddRef(); 86 } 87 setPtr(env, jDnDClipboard, pDataObj); 88 if (NULL != pOldDataObj) { 89 //unlock old data instance 90 pOldDataObj->Release(); 91 } 92 } 93 94 return checkJavaException(env); 95 } 96 97 HRESULT GlassDropTarget::CallbackToJava( 98 /* [in] */ jmethodID method, 99 /* [in] */ DWORD grfKeyState, 100 /* [in] */ POINTL pt, 101 /* [out][in] */ DWORD *pdwEffect) 102 { 103 if (!m_viewContainer->GetView()) { 104 return S_OK; 105 } 106 107 JNIEnv *env = GetEnv(); 108 POINT ptClient = *(LPPOINT)&pt; 109 ::ScreenToClient(m_hwnd, &ptClient); 110 111 SetSourceSupportedActions(getACTION(*pdwEffect)); 112 113 //We want to be Explorer-like. 114 //Found the action from keyboard state. 115 DWORD like = DROPEFFECT_MOVE; 116 grfKeyState &= MK_CONTROL | MK_SHIFT | MK_ALT; 117 if ( (MK_CONTROL | MK_SHIFT)== grfKeyState || MK_ALT == grfKeyState) { 118 like = DROPEFFECT_LINK; 119 } else if (MK_CONTROL == grfKeyState) { 120 like = DROPEFFECT_COPY; 121 } 122 123 static DROPEFFECT DesiredActions[] = { 124 //Actions in order of priority (the same order is in Explorer) 125 DROPEFFECT_COPY, 126 DROPEFFECT_MOVE, 127 DROPEFFECT_LINK 128 }; 129 130 //Let's check the target ability for selected action. 131 for( int iDesiredIndex = 0; 132 133 (like & *pdwEffect) == 0 //action is not supported by target 134 && iDesiredIndex < sizeof(DesiredActions)/sizeof(*DesiredActions); 135 136 ++iDesiredIndex) 137 { 138 //target cannot do the action, let's try the next 139 like = DesiredActions[iDesiredIndex]; 140 } 141 142 *pdwEffect = getDROPEFFECT(DROPEFFECT(env->CallIntMethod(m_viewContainer->GetView(), method, 143 jint(ptClient.x), jint(ptClient.y), jint(pt.x), jint(pt.y), getACTION(like)))); 144 145 return checkJavaException(env); 146 } 147 148 HRESULT GlassDropTarget::DragEnter( 149 /* [unique][in] */ IDataObject *pDataObj, 150 /* [in] */ DWORD grfKeyState, 151 /* [in] */ POINTL pt, 152 /* [out][in] */ DWORD *pdwEffect) 153 { 154 OLE_TRY 155 OLE_HRT(UpdateDnDClipboardData(pDataObj)) 156 //dragAction = View.notifyDragEnter(...) 157 OLE_HRT(CallbackToJava(javaIDs.View.notifyDragEnter, grfKeyState, pt, pdwEffect)) 158 //ignore HRESULT - just no image 159 m_spDropTargetHelper->DragEnter(m_hwnd, pDataObj, (LPPOINT)&pt, *pdwEffect); 160 OLE_CATCH 161 OLE_RETURN_HR 162 } 163 164 HRESULT GlassDropTarget::DragOver( 165 /* [in] */ DWORD grfKeyState, 166 /* [in] */ POINTL pt, 167 /* [out][in] */ DWORD *pdwEffect) 168 { 169 OLE_TRY 170 //dragAction = View.notifyDragOver(...) 171 OLE_HRT(OLE_HRT(CallbackToJava(javaIDs.View.notifyDragOver, grfKeyState, pt, pdwEffect))) 172 //ignore HRESULT - just no image 173 m_spDropTargetHelper->DragOver((LPPOINT)&pt, *pdwEffect); 174 OLE_CATCH 175 OLE_RETURN_HR 176 } 177 178 HRESULT GlassDropTarget::DragLeave() 179 { 180 if (!m_viewContainer->GetView()) { 181 return S_OK; 182 } 183 184 OLE_TRY 185 JNIEnv *env = GetEnv(); 186 //View.notifyDragLeave() 187 env->CallIntMethod(m_viewContainer->GetView(), javaIDs.View.notifyDragLeave); 188 OLE_HRT(checkJavaException(env)) 189 //ignore HRESULT - just no image 190 m_spDropTargetHelper->DragLeave(); 191 OLE_CATCH 192 OLE_RETURN_HR 193 } 194 195 HRESULT GlassDropTarget::Drop( 196 /* [unique][in] */ IDataObject *pDataObj, 197 /* [in] */ DWORD grfKeyState, 198 /* [in] */ POINTL pt, 199 /* [out][in] */ DWORD *pdwEffect) 200 { 201 OLE_TRY 202 OLE_HRT(UpdateDnDClipboardData(pDataObj)) 203 //performedAction = View.notifyDragDrop(...) 204 OLE_HRT(OLE_HRT(CallbackToJava(javaIDs.View.notifyDragDrop, grfKeyState, pt, pdwEffect))) 205 //ignore HRESULT - just no image 206 m_spDropTargetHelper->Drop(pDataObj, (LPPOINT)&pt, *pdwEffect); 207 OLE_CATCH 208 OLE_RETURN_HR 209 } 210 211 /*static*/ 212 HRESULT GlassDropTarget::SetSourceSupportedActions(/*in*/jint actions) 213 { 214 JNIEnv *env = GetEnv(); 215 //Get "DnD" clipboard 216 JLClass jcWinDnDClipboard(env, 217 GlassApplication::ClassForName(env, "com.sun.glass.ui.win.WinDnDClipboard")); 218 ASSERT(jcWinDnDClipboard) 219 static jmethodID midGetInstance = env->GetStaticMethodID(jcWinDnDClipboard, "getInstance", 220 "()Lcom/sun/glass/ui/win/WinDnDClipboard;"); 221 ASSERT(midGetInstance) 222 HRESULT result = checkJavaException(env); 223 if (result != S_OK) { 224 return result; 225 } 226 227 static jmethodID midSetSourceSupportedActions = env->GetMethodID(jcWinDnDClipboard, "setSourceSupportedActions", 228 "(I)V"); 229 ASSERT(midSetSourceSupportedActions) 230 result = checkJavaException(env); 231 if (result != S_OK) { 232 return result; 233 } 234 235 JLObject jDnDClipboard(env, env->CallStaticObjectMethod(jcWinDnDClipboard, midGetInstance)); 236 ASSERT(jDnDClipboard) 237 238 env->CallVoidMethod(jDnDClipboard, midSetSourceSupportedActions, actions); 239 240 return checkJavaException(env); 241 } 242 243 ////////////////////////////////////////////////////////////////////////// 244 // GlassDropSource 245 ////////////////////////////////////////////////////////////////////////// 246 247 /*static*/ 248 HRESULT GlassDropSource::SetDragButton(jint button) 249 { 250 JNIEnv *env = GetEnv(); 251 //Get "DnD" clipboard 252 JLClass jcWinDnDClipboard(env, 253 GlassApplication::ClassForName(env, "com.sun.glass.ui.win.WinDnDClipboard")); 254 ASSERT(jcWinDnDClipboard) 255 static jmethodID midGetInstance = env->GetStaticMethodID(jcWinDnDClipboard, "getInstance", 256 "()Lcom/sun/glass/ui/win/WinDnDClipboard;"); 257 ASSERT(midGetInstance) 258 HRESULT result = checkJavaException(env); 259 if (result != S_OK) { 260 return result; 261 } 262 263 static jmethodID midSetDragButton = env->GetMethodID(jcWinDnDClipboard, "setDragButton", 264 "(I)V"); 265 ASSERT(midSetDragButton) 266 result = checkJavaException(env); 267 if (result != S_OK) { 268 return result; 269 } 270 271 JLObject jDnDClipboard(env, env->CallStaticObjectMethod(jcWinDnDClipboard, midGetInstance)); 272 ASSERT(jDnDClipboard) 273 274 env->CallVoidMethod(jDnDClipboard, midSetDragButton, button); 275 276 return checkJavaException(env); 277 } 278 279 GlassDropSource::GlassDropSource(jobject jDnDClipboard) 280 { 281 JNIEnv *env = GetEnv(); 282 static jmethodID midGetDragButton = 0; 283 if (0 == midGetDragButton) { 284 JLClass jcWinDnDClipboard(env, 285 GlassApplication::ClassForName(env, "com.sun.glass.ui.win.WinDnDClipboard")); 286 ASSERT(jcWinDnDClipboard) 287 288 midGetDragButton = env->GetMethodID(jcWinDnDClipboard, "getDragButton", 289 "()I"); 290 ASSERT(midGetDragButton) 291 HRESULT result = checkJavaException(env); 292 if (result != S_OK) { 293 return; 294 } 295 } 296 297 jint jbutton = env->CallIntMethod(jDnDClipboard, midGetDragButton); 298 switch (jbutton) { 299 case com_sun_glass_events_MouseEvent_BUTTON_LEFT: 300 m_button = MK_LBUTTON; 301 break; 302 case com_sun_glass_events_MouseEvent_BUTTON_RIGHT: 303 m_button = MK_RBUTTON; 304 break; 305 case com_sun_glass_events_MouseEvent_BUTTON_OTHER: 306 m_button = MK_MBUTTON; 307 break; 308 default: 309 m_button = 0; 310 break; 311 } 312 STRACE(_T("{GlassDropSource")); 313 } 314 315 GlassDropSource::~GlassDropSource() 316 { 317 STRACE(_T("}GlassDropSource")); 318 } 319 320 HRESULT GlassDropSource::QueryContinueDrag( 321 /* [in] */ BOOL fEscapePressed, 322 /* [in] */ DWORD grfKeyState) 323 { 324 return fEscapePressed 325 ? DRAGDROP_S_CANCEL 326 : 0 == (grfKeyState & m_button) 327 ? DRAGDROP_S_DROP 328 : S_OK; 329 } 330 331 HRESULT GlassDropSource::GiveFeedback(/* [in] */DWORD dwEffect) 332 { 333 return DRAGDROP_S_USEDEFAULTCURSORS; 334 }