Mercurial > projects > dwt2
annotate org.eclipse.swt.gtk.linux.x86/src/org/eclipse/swt/dnd/DragSource.d @ 47:65761bc28ab2
swt linux again compilable for d1.
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Fri, 27 Mar 2009 11:43:53 +0100 |
parents | f713da8bc051 |
children | 7e78af7adab5 |
rev | line source |
---|---|
25 | 1 /******************************************************************************* |
2 * Copyright (c) 2000, 2008 IBM Corporation and others. | |
3 * All rights reserved. This program and the accompanying materials | |
4 * are made available under the terms of the Eclipse Public License v1.0 | |
5 * which accompanies this distribution, and is available at | |
6 * http://www.eclipse.org/legal/epl-v10.html | |
7 * | |
8 * Contributors: | |
9 * IBM Corporation - initial API and implementation | |
10 * Port to the D programming language: | |
11 * Frank Benoit <benoit@tionex.de> | |
12 *******************************************************************************/ | |
13 module org.eclipse.swt.dnd.DragSource; | |
14 | |
15 | |
16 | |
17 import org.eclipse.swt.SWT; | |
18 import org.eclipse.swt.SWTError; | |
19 import org.eclipse.swt.SWTException; | |
20 import org.eclipse.swt.graphics.Image; | |
21 import org.eclipse.swt.graphics.ImageData; | |
22 import org.eclipse.swt.internal.gtk.OS; | |
23 import org.eclipse.swt.widgets.Control; | |
24 import org.eclipse.swt.widgets.Display; | |
25 import org.eclipse.swt.widgets.Event; | |
26 import org.eclipse.swt.widgets.Listener; | |
27 import org.eclipse.swt.widgets.Table; | |
28 import org.eclipse.swt.widgets.Tree; | |
29 import org.eclipse.swt.widgets.Widget; | |
30 import org.eclipse.swt.dnd.Transfer; | |
31 import org.eclipse.swt.dnd.DragSourceEffect; | |
32 import org.eclipse.swt.dnd.DragSourceListener; | |
33 import org.eclipse.swt.dnd.DND; | |
34 import org.eclipse.swt.dnd.TreeDragSourceEffect; | |
35 import org.eclipse.swt.dnd.TableDragSourceEffect; | |
36 import org.eclipse.swt.dnd.DNDListener; | |
37 import org.eclipse.swt.dnd.DNDEvent; | |
38 import org.eclipse.swt.dnd.TransferData; | |
39 import java.lang.all; | |
40 | |
47
65761bc28ab2
swt linux again compilable for d1.
Frank Benoit <benoit@tionex.de>
parents:
25
diff
changeset
|
41 import java.lang.Thread; |
25 | 42 |
43 /** | |
44 * | |
45 * <code>DragSource</code> defines the source object for a drag and drop transfer. | |
46 * | |
47 * <p>IMPORTANT: This class is <em>not</em> intended to be subclassed.</p> | |
48 * | |
49 * <p>A drag source is the object which originates a drag and drop operation. For the specified widget, | |
50 * it defines the type of data that is available for dragging and the set of operations that can | |
51 * be performed on that data. The operations can be any bit-wise combination of DND.MOVE, DND.COPY or | |
52 * DND.LINK. The type of data that can be transferred is specified by subclasses of Transfer such as | |
53 * TextTransfer or FileTransfer. The type of data transferred can be a predefined system type or it | |
54 * can be a type defined by the application. For instructions on how to define your own transfer type, | |
55 * refer to <code>ByteArrayTransfer</code>.</p> | |
56 * | |
57 * <p>You may have several DragSources in an application but you can only have one DragSource | |
58 * per Control. Data dragged from this DragSource can be dropped on a site within this application | |
59 * or it can be dropped on another application such as an external Text editor.</p> | |
60 * | |
61 * <p>The application supplies the content of the data being transferred by implementing the | |
62 * <code>DragSourceListener</code> and associating it with the DragSource via DragSource#addDragListener.</p> | |
63 * | |
64 * <p>When a successful move operation occurs, the application is required to take the appropriate | |
65 * action to remove the data from its display and remove any associated operating system resources or | |
66 * internal references. Typically in a move operation, the drop target makes a copy of the data | |
67 * and the drag source deletes the original. However, sometimes copying the data can take a long | |
68 * time (such as copying a large file). Therefore, on some platforms, the drop target may actually | |
69 * move the data in the operating system rather than make a copy. This is usually only done in | |
70 * file transfers. In this case, the drag source is informed in the DragEnd event that a | |
71 * DROP_TARGET_MOVE was performed. It is the responsibility of the drag source at this point to clean | |
72 * up its displayed information. No action needs to be taken on the operating system resources.</p> | |
73 * | |
74 * <p> The following example shows a Label widget that allows text to be dragged from it.</p> | |
75 * | |
76 * <code><pre> | |
77 * // Enable a label as a Drag Source | |
78 * Label label = new Label(shell, SWT.NONE); | |
79 * // This example will allow text to be dragged | |
80 * Transfer[] types = new Transfer[] {TextTransfer.getInstance()}; | |
81 * // This example will allow the text to be copied or moved to the drop target | |
82 * int operations = DND.DROP_MOVE | DND.DROP_COPY; | |
83 * | |
84 * DragSource source = new DragSource(label, operations); | |
85 * source.setTransfer(types); | |
86 * source.addDragListener(new DragSourceListener() { | |
87 * public void dragStart(DragSourceEvent e) { | |
88 * // Only start the drag if there is actually text in the | |
89 * // label - this text will be what is dropped on the target. | |
90 * if (label.getText().length() is 0) { | |
91 * event.doit = false; | |
92 * } | |
93 * }; | |
94 * public void dragSetData(DragSourceEvent event) { | |
95 * // A drop has been performed, so provide the data of the | |
96 * // requested type. | |
97 * // (Checking the type of the requested data is only | |
98 * // necessary if the drag source supports more than | |
99 * // one data type but is shown here as an example). | |
100 * if (TextTransfer.getInstance().isSupportedType(event.dataType)){ | |
101 * event.data = label.getText(); | |
102 * } | |
103 * } | |
104 * public void dragFinished(DragSourceEvent event) { | |
105 * // A Move operation has been performed so remove the data | |
106 * // from the source | |
107 * if (event.detail is DND.DROP_MOVE) | |
108 * label.setText(""); | |
109 * } | |
110 * }); | |
111 * </pre></code> | |
112 * | |
113 * | |
114 * <dl> | |
115 * <dt><b>Styles</b></dt> <dd>DND.DROP_NONE, DND.DROP_COPY, DND.DROP_MOVE, DND.DROP_LINK</dd> | |
116 * <dt><b>Events</b></dt> <dd>DND.DragStart, DND.DragSetData, DND.DragEnd</dd> | |
117 * </dl> | |
118 * | |
119 * @see <a href="http://www.eclipse.org/swt/snippets/#dnd">Drag and Drop snippets</a> | |
120 * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: DNDExample</a> | |
121 * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a> | |
122 */ | |
123 public class DragSource : Widget { | |
124 | |
125 // info for registering as a drag source | |
126 Control control; | |
127 Listener controlListener; | |
128 Transfer[] transferAgents; | |
129 DragSourceEffect dragEffect; | |
130 | |
131 void* targetList; | |
132 | |
133 //workaround - remember action performed for DragEnd | |
134 bool moveData = false; | |
135 | |
136 static const String DEFAULT_DRAG_SOURCE_EFFECT = "DEFAULT_DRAG_SOURCE_EFFECT"; //$NON-NLS-1$ | |
137 | |
138 // static Callback DragGetData; | |
139 // static Callback DragEnd; | |
140 // static Callback DragDataDelete; | |
141 // static this() { | |
142 // DragGetData = new Callback(DragSource.class, "DragGetData", 5); //$NON-NLS-1$ | |
143 // if (DragGetData.getAddress() is 0) SWT.error(SWT.ERROR_NO_MORE_CALLBACKS); | |
144 // DragEnd = new Callback(DragSource.class, "DragEnd", 2); //$NON-NLS-1$ | |
145 // if (DragEnd.getAddress() is 0) SWT.error(SWT.ERROR_NO_MORE_CALLBACKS); | |
146 // DragDataDelete = new Callback(DragSource.class, "DragDataDelete", 2); //$NON-NLS-1$ | |
147 // if (DragDataDelete.getAddress() is 0) SWT.error(SWT.ERROR_NO_MORE_CALLBACKS); | |
148 // } | |
149 | |
150 /** | |
151 * Creates a new <code>DragSource</code> to handle dragging from the specified <code>Control</code>. | |
152 * Creating an instance of a DragSource may cause system resources to be allocated depending on the platform. | |
153 * It is therefore mandatory that the DragSource instance be disposed when no longer required. | |
154 * | |
155 * @param control the <code>Control</code> that the user clicks on to initiate the drag | |
156 * @param style the bitwise OR'ing of allowed operations; this may be a combination of any of | |
157 * DND.DROP_NONE, DND.DROP_COPY, DND.DROP_MOVE, DND.DROP_LINK | |
158 * | |
159 * @exception SWTException <ul> | |
160 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li> | |
161 * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li> | |
162 * </ul> | |
163 * @exception SWTError <ul> | |
164 * <li>ERROR_CANNOT_INIT_DRAG - unable to initiate drag source; this will occur if more than one | |
165 * drag source is created for a control or if the operating system will not allow the creation | |
166 * of the drag source</li> | |
167 * </ul> | |
168 * | |
169 * <p>NOTE: ERROR_CANNOT_INIT_DRAG should be an SWTException, since it is a | |
170 * recoverable error, but can not be changed due to backward compatibility.</p> | |
171 * | |
172 * @see Widget#dispose | |
173 * @see DragSource#checkSubclass | |
174 * @see DND#DROP_NONE | |
175 * @see DND#DROP_COPY | |
176 * @see DND#DROP_MOVE | |
177 * @see DND#DROP_LINK | |
178 */ | |
179 public this(Control control, int style) { | |
180 super (control, checkStyle(style)); | |
181 this.control = control; | |
182 // if (DragGetData is null || DragEnd is null || DragDataDelete is null) { | |
183 // DND.error(DND.ERROR_CANNOT_INIT_DRAG); | |
184 // } | |
185 if (control.getData(DND.DRAG_SOURCE_KEY) !is null) { | |
186 DND.error(DND.ERROR_CANNOT_INIT_DRAG); | |
187 } | |
188 control.setData(DND.DRAG_SOURCE_KEY, this); | |
189 | |
190 OS.g_signal_connect(control.handle, OS.drag_data_get.ptr, cast(GCallback)&DragGetData, null); | |
191 OS.g_signal_connect(control.handle, OS.drag_end.ptr, cast(GCallback)&DragEnd, null); | |
192 OS.g_signal_connect(control.handle, OS.drag_data_delete.ptr, cast(GCallback)&DragDataDelete, null); | |
193 | |
194 controlListener = new class() Listener { | |
195 public void handleEvent (Event event) { | |
196 if (event.type is SWT.Dispose) { | |
197 if (!this.outer.isDisposed()) { | |
198 this.outer.dispose(); | |
199 } | |
200 } | |
201 if (event.type is SWT.DragDetect) { | |
202 if (!this.outer.isDisposed()) { | |
203 this.outer.drag(event); | |
204 } | |
205 } | |
206 } | |
207 }; | |
208 control.addListener (SWT.Dispose, controlListener); | |
209 control.addListener (SWT.DragDetect, controlListener); | |
210 | |
211 Object effect = control.getData(DEFAULT_DRAG_SOURCE_EFFECT); | |
212 if ( auto de = cast(DragSourceEffect)effect ) { | |
213 dragEffect = de; | |
214 } else if ( auto tree = cast(Tree)control) { | |
215 dragEffect = new TreeDragSourceEffect(tree); | |
216 } else if ( auto table = cast(Table)control ) { | |
217 dragEffect = new TableDragSourceEffect(table); | |
218 } | |
219 | |
220 this.addListener(SWT.Dispose, new class() Listener { | |
221 public void handleEvent(Event e) { | |
222 onDispose(); | |
223 } | |
224 }); | |
225 } | |
226 | |
227 static int checkStyle (int style) { | |
228 if (style is SWT.NONE) return DND.DROP_MOVE; | |
229 return style; | |
230 } | |
231 | |
232 private static extern(C) void DragDataDelete( | |
233 GtkWidget *widget, | |
234 GdkDragContext *drag_context, | |
235 void* user_data ) | |
236 { | |
237 DragSource source = FindDragSource(widget); | |
238 if (source is null) return; | |
239 source.dragDataDelete(widget, drag_context); | |
240 return; | |
241 } | |
242 | |
243 private static extern(C) void DragEnd ( | |
244 GtkWidget *widget, | |
245 GdkDragContext *drag_context, | |
246 void* user_data) | |
247 { | |
248 DragSource source = FindDragSource(widget); | |
249 if (source is null) return; | |
250 source.dragEnd(widget, drag_context); | |
251 return; | |
252 } | |
253 | |
254 private static extern(C) void DragGetData( | |
255 GtkWidget *widget, | |
256 GdkDragContext *context, | |
257 GtkSelectionData *selection_data, | |
258 uint info, | |
259 uint time, | |
260 void* user_data ) | |
261 { | |
262 DragSource source = FindDragSource(widget); | |
263 if (source is null) return; | |
264 source.dragGetData(widget, context, selection_data, cast(int)/*64*/info, cast(int)/*64*/time); | |
265 return; | |
266 } | |
267 | |
268 static DragSource FindDragSource(GtkWidget* handle) { | |
47
65761bc28ab2
swt linux again compilable for d1.
Frank Benoit <benoit@tionex.de>
parents:
25
diff
changeset
|
269 Display display = Display.findDisplay(Thread.currentThread()); |
25 | 270 if (display is null || display.isDisposed()) return null; |
271 Widget widget = display.findWidget(handle); | |
272 if (widget is null) return null; | |
273 return cast(DragSource)widget.getData(DND.DRAG_SOURCE_KEY); | |
274 } | |
275 | |
276 /** | |
277 * Adds the listener to the collection of listeners who will | |
278 * be notified when a drag and drop operation is in progress, by sending | |
279 * it one of the messages defined in the <code>DragSourceListener</code> | |
280 * interface. | |
281 * | |
282 * <p><ul> | |
283 * <li><code>dragStart</code> is called when the user has begun the actions required to drag the widget. | |
284 * This event gives the application the chance to decide if a drag should be started. | |
285 * <li><code>dragSetData</code> is called when the data is required from the drag source. | |
286 * <li><code>dragFinished</code> is called when the drop has successfully completed (mouse up | |
287 * over a valid target) or has been terminated (such as hitting the ESC key). Perform cleanup | |
288 * such as removing data from the source side on a successful move operation. | |
289 * </ul></p> | |
290 * | |
291 * @param listener the listener which should be notified | |
292 * | |
293 * @exception IllegalArgumentException <ul> | |
294 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> | |
295 * </ul> | |
296 * @exception SWTException <ul> | |
297 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
298 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
299 * </ul> | |
300 * | |
301 * @see DragSourceListener | |
302 * @see #getDragListeners | |
303 * @see #removeDragListener | |
304 * @see DragSourceEvent | |
305 */ | |
306 public void addDragListener(DragSourceListener listener) { | |
307 if (listener is null) DND.error (SWT.ERROR_NULL_ARGUMENT); | |
308 DNDListener typedListener = new DNDListener (listener); | |
309 typedListener.dndWidget = this; | |
310 addListener (DND.DragStart, typedListener); | |
311 addListener (DND.DragSetData, typedListener); | |
312 addListener (DND.DragEnd, typedListener); | |
313 } | |
314 | |
315 protected override void checkSubclass () { | |
316 String name = this.classinfo.name; | |
317 String validName = DragSource.classinfo.name; | |
318 if ( validName !=/*eq*/ name ) { | |
319 DND.error (SWT.ERROR_INVALID_SUBCLASS); | |
320 } | |
321 } | |
322 | |
323 void drag(Event dragEvent) { | |
324 moveData = false; | |
325 DNDEvent event = new DNDEvent(); | |
326 event.widget = this; | |
327 event.x = dragEvent.x; | |
328 event.y = dragEvent.y; | |
329 event.time = dragEvent.time; | |
330 event.doit = true; | |
331 notifyListeners(DND.DragStart, event); | |
332 if (!event.doit || transferAgents is null || transferAgents.length is 0) return; | |
333 if (targetList is null) return; | |
334 | |
335 int actions = opToOsOp(getStyle()); | |
336 Image image = event.image; | |
337 auto context = OS.gtk_drag_begin(control.handle, targetList, actions, 1, null); | |
338 if (context !is null && image !is null) { | |
339 auto pixbuf = createPixbuf(image); | |
340 OS.gtk_drag_set_icon_pixbuf(context, pixbuf, 0, 0); | |
341 OS.g_object_unref(pixbuf); | |
342 } | |
343 } | |
344 | |
345 void dragEnd( | |
346 GtkWidget *widget, | |
347 GdkDragContext *context ) | |
348 { | |
349 /* | |
350 * Bug in GTK. If a drag is initiated using gtk_drag_begin and the | |
351 * mouse is released immediately, the mouse and keyboard remain | |
352 * grabbed. The fix is to release the grab on the mouse and keyboard | |
353 * whenever the drag is terminated. | |
354 * | |
355 * NOTE: We believe that it is never an error to ungrab when | |
356 * a drag is finished. | |
357 */ | |
358 OS.gdk_pointer_ungrab(OS.GDK_CURRENT_TIME); | |
359 OS.gdk_keyboard_ungrab(OS.GDK_CURRENT_TIME); | |
360 | |
361 int operation = DND.DROP_NONE; | |
362 if (context !is null) { | |
363 GdkDragContext* gdkDragContext = context; | |
364 if (gdkDragContext.dest_window !is null) { //NOTE: if dest_window is 0, drag was aborted | |
365 if (moveData) { | |
366 operation = DND.DROP_MOVE; | |
367 } else { | |
368 operation = osOpToOp(gdkDragContext.action); | |
369 if (operation is DND.DROP_MOVE) operation = DND.DROP_NONE; | |
370 } | |
371 } | |
372 } | |
373 | |
374 DNDEvent event = new DNDEvent(); | |
375 event.widget = this; | |
376 //event.time = ??? | |
377 event.doit = operation !is 0; | |
378 event.detail = operation; | |
379 notifyListeners(DND.DragEnd, event); | |
380 moveData = false; | |
381 } | |
382 | |
383 void dragGetData( | |
384 GtkWidget *widget, | |
385 GdkDragContext *context, | |
386 GtkSelectionData *gtkSelectionData, | |
387 uint info, | |
388 uint time ) | |
389 { | |
390 if (gtkSelectionData is null) return; | |
391 if (gtkSelectionData.target is null) return; | |
392 | |
393 TransferData transferData = new TransferData(); | |
394 transferData.type = gtkSelectionData.target; | |
395 transferData.pValue = gtkSelectionData.data; | |
396 transferData.length = gtkSelectionData.length; | |
397 transferData.format = gtkSelectionData.format; | |
398 | |
399 DNDEvent event = new DNDEvent(); | |
400 event.widget = this; | |
401 event.time = time; | |
402 event.dataType = transferData; | |
403 notifyListeners(DND.DragSetData, event); | |
404 | |
405 Transfer transfer = null; | |
406 for (int i = 0; i < transferAgents.length; i++) { | |
407 Transfer transferAgent = transferAgents[i]; | |
408 if (transferAgent !is null && transferAgent.isSupportedType(transferData)) { | |
409 transfer = transferAgent; | |
410 break; | |
411 } | |
412 } | |
413 if (transfer is null) return; | |
414 transfer.javaToNative(event.data, transferData); | |
415 if (transferData.result !is 1) return; | |
416 OS.gtk_selection_data_set(gtkSelectionData, transferData.type, transferData.format, transferData.pValue, transferData.length); | |
417 OS.g_free(transferData.pValue); | |
418 return; | |
419 } | |
420 | |
421 void dragDataDelete( | |
422 GtkWidget *widget, | |
423 GdkDragContext *drag_context) | |
424 { | |
425 moveData = true; | |
426 } | |
427 | |
428 /** | |
429 * Returns the Control which is registered for this DragSource. This is the control that the | |
430 * user clicks in to initiate dragging. | |
431 * | |
432 * @return the Control which is registered for this DragSource | |
433 */ | |
434 public Control getControl () { | |
435 return control; | |
436 } | |
437 | |
438 /** | |
439 * Returns an array of listeners who will be notified when a drag and drop | |
440 * operation is in progress, by sending it one of the messages defined in | |
441 * the <code>DragSourceListener</code> interface. | |
442 * | |
443 * @return the listeners who will be notified when a drag and drop | |
444 * operation is in progress | |
445 * | |
446 * @exception SWTException <ul> | |
447 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
448 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
449 * </ul> | |
450 * | |
451 * @see DragSourceListener | |
452 * @see #addDragListener | |
453 * @see #removeDragListener | |
454 * @see DragSourceEvent | |
455 * | |
456 * @since 3.4 | |
457 */ | |
458 public DragSourceListener[] getDragListeners() { | |
459 Listener[] listeners = getListeners(DND.DragStart); | |
460 int length = listeners.length; | |
461 DragSourceListener[] dragListeners = new DragSourceListener[length]; | |
462 int count = 0; | |
463 for (int i = 0; i < length; i++) { | |
464 Listener listener = listeners[i]; | |
465 if ( auto l = cast(DNDListener)listener ) { | |
466 dragListeners[count] = cast(DragSourceListener) (l.getEventListener()); | |
467 count++; | |
468 } | |
469 } | |
470 if (count is length) return dragListeners; | |
471 DragSourceListener[] result = new DragSourceListener[count]; | |
472 SimpleType!(DragSourceListener).arraycopy(dragListeners, 0, result, 0, count); | |
473 return result; | |
474 } | |
475 | |
476 /** | |
477 * Returns the drag effect that is registered for this DragSource. This drag | |
478 * effect will be used during a drag and drop operation. | |
479 * | |
480 * @return the drag effect that is registered for this DragSource | |
481 * | |
482 * @since 3.3 | |
483 */ | |
484 public DragSourceEffect getDragSourceEffect() { | |
485 return dragEffect; | |
486 } | |
487 | |
488 /** | |
489 * Returns the list of data types that can be transferred by this DragSource. | |
490 * | |
491 * @return the list of data types that can be transferred by this DragSource | |
492 */ | |
493 public Transfer[] getTransfer(){ | |
494 return transferAgents; | |
495 } | |
496 | |
497 void onDispose() { | |
498 if (control is null) return; | |
499 if (targetList !is null) { | |
500 OS.gtk_target_list_unref(targetList); | |
501 } | |
502 targetList = null; | |
503 if (controlListener !is null) { | |
504 control.removeListener(SWT.Dispose, controlListener); | |
505 control.removeListener(SWT.DragDetect, controlListener); | |
506 } | |
507 controlListener = null; | |
508 control.setData(DND.DRAG_SOURCE_KEY, null); | |
509 control = null; | |
510 transferAgents = null; | |
511 } | |
512 | |
513 int opToOsOp(int operation){ | |
514 int osOperation = 0; | |
515 | |
516 if ((operation & DND.DROP_COPY) is DND.DROP_COPY) | |
517 osOperation |= OS.GDK_ACTION_COPY; | |
518 if ((operation & DND.DROP_MOVE) is DND.DROP_MOVE) | |
519 osOperation |= OS.GDK_ACTION_MOVE; | |
520 if ((operation & DND.DROP_LINK) is DND.DROP_LINK) | |
521 osOperation |= OS.GDK_ACTION_LINK; | |
522 | |
523 return osOperation; | |
524 } | |
525 | |
526 int osOpToOp(int osOperation){ | |
527 int operation = DND.DROP_NONE; | |
528 | |
529 if ((osOperation & OS.GDK_ACTION_COPY) is OS.GDK_ACTION_COPY) | |
530 operation |= DND.DROP_COPY; | |
531 if ((osOperation & OS.GDK_ACTION_MOVE) is OS.GDK_ACTION_MOVE) | |
532 operation |= DND.DROP_MOVE; | |
533 if ((osOperation & OS.GDK_ACTION_LINK) is OS.GDK_ACTION_LINK) | |
534 operation |= DND.DROP_LINK; | |
535 | |
536 return operation; | |
537 } | |
538 | |
539 /** | |
540 * Removes the listener from the collection of listeners who will | |
541 * be notified when a drag and drop operation is in progress. | |
542 * | |
543 * @param listener the listener which should no longer be notified | |
544 * | |
545 * @exception IllegalArgumentException <ul> | |
546 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> | |
547 * </ul> | |
548 * @exception SWTException <ul> | |
549 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
550 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
551 * </ul> | |
552 * | |
553 * @see DragSourceListener | |
554 * @see #addDragListener | |
555 * @see #getDragListeners | |
556 */ | |
557 public void removeDragListener(DragSourceListener listener) { | |
558 if (listener is null) DND.error (SWT.ERROR_NULL_ARGUMENT); | |
559 removeListener (DND.DragStart, listener); | |
560 removeListener (DND.DragSetData, listener); | |
561 removeListener (DND.DragEnd, listener); | |
562 } | |
563 | |
564 /** | |
565 * Specifies the drag effect for this DragSource. This drag effect will be | |
566 * used during a drag and drop operation. | |
567 * | |
568 * @param effect the drag effect that is registered for this DragSource | |
569 * | |
570 * @since 3.3 | |
571 */ | |
572 public void setDragSourceEffect(DragSourceEffect effect) { | |
573 dragEffect = effect; | |
574 } | |
575 | |
576 /** | |
577 * Specifies the list of data types that can be transferred by this DragSource. | |
578 * The application must be able to provide data to match each of these types when | |
579 * a successful drop has occurred. | |
580 * | |
581 * @param transferAgents a list of Transfer objects which define the types of data that can be | |
582 * dragged from this source | |
583 */ | |
584 public void setTransfer(Transfer[] transferAgents){ | |
585 if (targetList !is null) { | |
586 OS.gtk_target_list_unref(targetList); | |
587 targetList = null; | |
588 } | |
589 this.transferAgents = transferAgents; | |
590 if (transferAgents is null || transferAgents.length is 0) return; | |
591 | |
592 GtkTargetEntry*[] targets; | |
593 for (int i = 0; i < transferAgents.length; i++) { | |
594 Transfer transfer = transferAgents[i]; | |
595 if (transfer !is null) { | |
596 int[] typeIds = transfer.getTypeIds(); | |
597 String[] typeNames = transfer.getTypeNames(); | |
598 for (int j = 0; j < typeIds.length; j++) { | |
599 GtkTargetEntry* entry = new GtkTargetEntry(); | |
600 String type = typeNames[j]; | |
601 entry.target = cast(char*)OS.g_malloc(type.length+1); | |
602 entry.target[ 0 .. type.length ] = type[]; | |
603 entry.target[ type.length ] = '\0'; | |
604 entry.info = typeIds[j]; | |
605 GtkTargetEntry*[] newTargets = new GtkTargetEntry*[targets.length + 1]; | |
606 SimpleType!(GtkTargetEntry*).arraycopy(targets, 0, newTargets, 0, targets.length); | |
607 newTargets[targets.length] = entry; | |
608 targets = newTargets; | |
609 } | |
610 } | |
611 } | |
612 | |
613 void* pTargets = OS.g_malloc(targets.length * GtkTargetEntry.sizeof); | |
614 for (int i = 0; i < targets.length; i++) { | |
615 tango.stdc.string.memmove(pTargets + i*GtkTargetEntry.sizeof, targets[i], GtkTargetEntry.sizeof); | |
616 } | |
617 targetList = OS.gtk_target_list_new(pTargets, targets.length); | |
618 | |
619 for (int i = 0; i < targets.length; i++) { | |
620 OS.g_free(targets[i].target); | |
621 } | |
622 } | |
623 | |
624 static GdkDrawable* createPixbuf(Image image) { | |
625 int w, h; | |
626 OS.gdk_drawable_get_size (image.pixmap, &w, &h); | |
627 auto colormap = OS.gdk_colormap_get_system (); | |
628 void* pixbuf; | |
629 bool hasMask = image.mask !is null && OS.gdk_drawable_get_depth (image.mask) is 1; | |
630 if (hasMask) { | |
631 pixbuf = OS.gdk_pixbuf_new (OS.GDK_COLORSPACE_RGB, true, 8, w, h); | |
632 if (pixbuf is null) SWT.error (SWT.ERROR_NO_HANDLES); | |
633 OS.gdk_pixbuf_get_from_drawable (pixbuf, image.pixmap, colormap, 0, 0, 0, 0, w , h); | |
634 auto maskPixbuf = OS.gdk_pixbuf_new(OS.GDK_COLORSPACE_RGB, false, 8, w , h ); | |
635 if (maskPixbuf is null) SWT.error (SWT.ERROR_NO_HANDLES); | |
636 OS.gdk_pixbuf_get_from_drawable(maskPixbuf, image.mask, null, 0, 0, 0, 0, w , h ); | |
637 int stride = OS.gdk_pixbuf_get_rowstride(pixbuf); | |
638 auto pixels = OS.gdk_pixbuf_get_pixels(pixbuf); | |
639 byte[] line = new byte[stride]; | |
640 int maskStride = OS.gdk_pixbuf_get_rowstride(maskPixbuf); | |
641 auto maskPixels = OS.gdk_pixbuf_get_pixels(maskPixbuf); | |
642 byte[] maskLine = new byte[maskStride]; | |
643 for (int y=0; y<h; y++) { | |
644 auto offset = pixels + (y * stride); | |
645 tango.stdc.string.memmove(line.ptr, offset, stride); | |
646 auto maskOffset = maskPixels + (y * maskStride); | |
647 tango.stdc.string.memmove(maskLine.ptr, maskOffset, maskStride); | |
648 for (int x=0; x<w; x++) { | |
649 if (maskLine[x * 3] is 0) { | |
650 line[x * 4 + 3] = 0; | |
651 } | |
652 } | |
653 tango.stdc.string.memmove(offset, line.ptr, stride); | |
654 } | |
655 OS.g_object_unref(maskPixbuf); | |
656 } else { | |
657 ImageData data = image.getImageData (); | |
658 bool hasAlpha = data.getTransparencyType () is SWT.TRANSPARENCY_ALPHA; | |
659 pixbuf = OS.gdk_pixbuf_new (OS.GDK_COLORSPACE_RGB, hasAlpha, 8, w , h ); | |
660 if (pixbuf is null) SWT.error (SWT.ERROR_NO_HANDLES); | |
661 OS.gdk_pixbuf_get_from_drawable (pixbuf, image.pixmap, colormap, 0, 0, 0, 0, w , h ); | |
662 if (hasAlpha) { | |
663 byte [] alpha = data.alphaData; | |
664 int stride = OS.gdk_pixbuf_get_rowstride (pixbuf); | |
665 auto pixels = OS.gdk_pixbuf_get_pixels (pixbuf); | |
666 byte [] line = new byte [stride]; | |
667 for (int y = 0; y < h ; y++) { | |
668 auto offset = pixels + (y * stride); | |
669 tango.stdc.string.memmove (line.ptr, offset, stride); | |
670 for (int x = 0; x < w ; x++) { | |
671 line [x*4+3] = alpha [y*w +x]; | |
672 } | |
673 tango.stdc.string.memmove (offset, line.ptr, stride); | |
674 } | |
675 } | |
676 } | |
677 return cast(GdkDrawable*)pixbuf; | |
678 } | |
679 } |