1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /* vim:expandtab:shiftwidth=4:tabstop=4:
3 : */
4 : /* ***** BEGIN LICENSE BLOCK *****
5 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 : *
7 : * The contents of this file are subject to the Mozilla Public License Version
8 : * 1.1 (the "License"); you may not use this file except in compliance with
9 : * the License. You may obtain a copy of the License at
10 : * http://www.mozilla.org/MPL/
11 : *
12 : * Software distributed under the License is distributed on an "AS IS" basis,
13 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 : * for the specific language governing rights and limitations under the
15 : * License.
16 : *
17 : * The Original Code is mozilla.org code.
18 : *
19 : * The Initial Developer of the Original Code is
20 : * Christopher Blizzard <blizzard@mozilla.org>.
21 : * Portions created by the Initial Developer are Copyright (C) 1998
22 : * the Initial Developer. All Rights Reserved.
23 : *
24 : * Contributor(s):
25 : * Christopher Blizzard <blizzard@mozilla.org>
26 : * Markus G. Kuhn <mkuhn@acm.org>
27 : * Richard Verhoeven <river@win.tue.nl>
28 : * Frank Tang <ftang@netscape.com> adopt into mozilla
29 : * Ginn Chen <ginn.chen@sun.com>
30 : *
31 : * Alternatively, the contents of this file may be used under the terms of
32 : * either the GNU General Public License Version 2 or later (the "GPL"), or
33 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
34 : * in which case the provisions of the GPL or the LGPL are applicable instead
35 : * of those above. If you wish to allow use of your version of this file only
36 : * under the terms of either the GPL or the LGPL, and not to allow others to
37 : * use your version of this file under the terms of the MPL, indicate your
38 : * decision by deleting the provisions above and replace them with the notice
39 : * and other provisions required by the GPL or the LGPL. If you do not delete
40 : * the provisions above, a recipient may use your version of this file under
41 : * the terms of any one of the MPL, the GPL or the LGPL.
42 : *
43 : * ***** END LICENSE BLOCK ***** */
44 :
45 : #include "nsDragService.h"
46 : #include "nsIObserverService.h"
47 : #include "nsWidgetsCID.h"
48 : #include "nsWindow.h"
49 : #include "nsIServiceManager.h"
50 : #include "nsXPCOM.h"
51 : #include "nsISupportsPrimitives.h"
52 : #include "nsIIOService.h"
53 : #include "nsIFileURL.h"
54 : #include "nsNetUtil.h"
55 : #include "prlog.h"
56 : #include "nsTArray.h"
57 : #include "nsPrimitiveHelpers.h"
58 : #include "prtime.h"
59 : #include "prthread.h"
60 : #include <gtk/gtk.h>
61 : #include <gdk/gdkx.h>
62 : #include "nsCRT.h"
63 : #include "mozilla/Services.h"
64 :
65 : #include "gfxASurface.h"
66 : #include "gfxXlibSurface.h"
67 : #include "gfxContext.h"
68 : #include "nsImageToPixbuf.h"
69 : #include "nsPresContext.h"
70 : #include "nsIDocument.h"
71 : #include "nsISelection.h"
72 : #include "nsIFrame.h"
73 :
74 : // This sets how opaque the drag image is
75 : #define DRAG_IMAGE_ALPHA_LEVEL 0.5
76 :
77 : // These values are copied from GtkDragResult (rather than using GtkDragResult
78 : // directly) so that this code can be compiled against versions of GTK+ that
79 : // do not have GtkDragResult.
80 : // GtkDragResult is available from GTK+ version 2.12.
81 : enum {
82 : MOZ_GTK_DRAG_RESULT_SUCCESS,
83 : MOZ_GTK_DRAG_RESULT_NO_TARGET
84 : };
85 :
86 : // Some gobject functions expect functions for gpointer arguments.
87 : // gpointer is void* but C++ doesn't like casting functions to void*.
88 : template<class T> static inline gpointer
89 0 : FuncToGpointer(T aFunction)
90 : {
91 : return reinterpret_cast<gpointer>
92 : (reinterpret_cast<uintptr_t>
93 : // This cast just provides a warning if T is not a function.
94 0 : (reinterpret_cast<void (*)()>(aFunction)));
95 : }
96 :
97 : static PRLogModuleInfo *sDragLm = NULL;
98 : static guint sMotionEventTimerID;
99 :
100 : static const char gMimeListType[] = "application/x-moz-internal-item-list";
101 : static const char gMozUrlType[] = "_NETSCAPE_URL";
102 : static const char gTextUriListType[] = "text/uri-list";
103 : static const char gTextPlainUTF8Type[] = "text/plain;charset=utf-8";
104 :
105 : static void
106 : invisibleSourceDragBegin(GtkWidget *aWidget,
107 : GdkDragContext *aContext,
108 : gpointer aData);
109 :
110 : static void
111 : invisibleSourceDragEnd(GtkWidget *aWidget,
112 : GdkDragContext *aContext,
113 : gpointer aData);
114 :
115 : static gboolean
116 : invisibleSourceDragFailed(GtkWidget *aWidget,
117 : GdkDragContext *aContext,
118 : gint aResult,
119 : gpointer aData);
120 :
121 : static void
122 : invisibleSourceDragDataGet(GtkWidget *aWidget,
123 : GdkDragContext *aContext,
124 : GtkSelectionData *aSelectionData,
125 : guint aInfo,
126 : guint32 aTime,
127 : gpointer aData);
128 :
129 0 : nsDragService::nsDragService()
130 : {
131 : // We have to destroy the hidden widget before the event loop stops
132 : // running.
133 : nsCOMPtr<nsIObserverService> obsServ =
134 0 : mozilla::services::GetObserverService();
135 0 : obsServ->AddObserver(this, "quit-application", false);
136 :
137 : // our hidden source widget
138 0 : mHiddenWidget = gtk_invisible_new();
139 : // make sure that the widget is realized so that
140 : // we can use it as a drag source.
141 0 : gtk_widget_realize(mHiddenWidget);
142 : // hook up our internal signals so that we can get some feedback
143 : // from our drag source
144 0 : g_signal_connect(mHiddenWidget, "drag_begin",
145 0 : G_CALLBACK(invisibleSourceDragBegin), this);
146 0 : g_signal_connect(mHiddenWidget, "drag_data_get",
147 0 : G_CALLBACK(invisibleSourceDragDataGet), this);
148 0 : g_signal_connect(mHiddenWidget, "drag_end",
149 0 : G_CALLBACK(invisibleSourceDragEnd), this);
150 : // drag-failed is available from GTK+ version 2.12
151 : guint dragFailedID = g_signal_lookup("drag-failed",
152 0 : G_TYPE_FROM_INSTANCE(mHiddenWidget));
153 0 : if (dragFailedID) {
154 : g_signal_connect_closure_by_id(mHiddenWidget, dragFailedID, 0,
155 : g_cclosure_new(G_CALLBACK(invisibleSourceDragFailed),
156 : this, NULL),
157 0 : FALSE);
158 : }
159 :
160 : // set up our logging module
161 0 : if (!sDragLm)
162 0 : sDragLm = PR_NewLogModule("nsDragService");
163 0 : PR_LOG(sDragLm, PR_LOG_DEBUG, ("nsDragService::nsDragService"));
164 0 : mGrabWidget = 0;
165 0 : mTargetWidget = 0;
166 0 : mTargetDragContext = 0;
167 0 : mTargetTime = 0;
168 0 : mCanDrop = false;
169 0 : mTargetDragDataReceived = false;
170 0 : mTargetDragData = 0;
171 0 : mTargetDragDataLen = 0;
172 0 : }
173 :
174 0 : nsDragService::~nsDragService()
175 : {
176 0 : PR_LOG(sDragLm, PR_LOG_DEBUG, ("nsDragService::~nsDragService"));
177 0 : }
178 :
179 0 : NS_IMPL_ISUPPORTS_INHERITED2(nsDragService, nsBaseDragService,
180 : nsIDragSessionGTK, nsIObserver)
181 :
182 : // nsIObserver
183 :
184 : NS_IMETHODIMP
185 0 : nsDragService::Observe(nsISupports *aSubject, const char *aTopic,
186 : const PRUnichar *aData)
187 : {
188 0 : if (!nsCRT::strcmp(aTopic, "quit-application")) {
189 0 : PR_LOG(sDragLm, PR_LOG_DEBUG,
190 : ("nsDragService::Observe(\"quit-application\")"));
191 0 : if (mHiddenWidget) {
192 0 : gtk_widget_destroy(mHiddenWidget);
193 0 : mHiddenWidget = 0;
194 : }
195 0 : TargetResetData();
196 : } else {
197 0 : NS_NOTREACHED("unexpected topic");
198 0 : return NS_ERROR_UNEXPECTED;
199 : }
200 :
201 0 : return NS_OK;
202 : }
203 :
204 : // Support for periodic drag events
205 :
206 : // http://www.whatwg.org/specs/web-apps/current-work/multipage/dnd.html#drag-and-drop-processing-model
207 : // and the Xdnd protocol both recommend that drag events are sent periodically,
208 : // but GTK does not normally provide this.
209 : //
210 : // Here GTK is periodically stimulated by copies of the most recent mouse
211 : // motion events so as to send drag position messages to the destination when
212 : // appropriate (after it has received a status event from the previous
213 : // message).
214 : //
215 : // (If events were sent only on the destination side then the destination
216 : // would have no message to which it could reply with a drag status. Without
217 : // sending a drag status to the source, the destination would not be able to
218 : // change its feedback re whether it could accept the drop, and so the
219 : // source's behavior on drop will not be consistent.)
220 :
221 : struct MotionEventData {
222 0 : MotionEventData(GtkWidget *aWidget, GdkEvent *aEvent)
223 0 : : mWidget(aWidget), mEvent(gdk_event_copy(aEvent))
224 : {
225 0 : MOZ_COUNT_CTOR(MotionEventData);
226 0 : g_object_ref(mWidget);
227 0 : }
228 0 : ~MotionEventData()
229 : {
230 0 : MOZ_COUNT_DTOR(MotionEventData);
231 0 : g_object_unref(mWidget);
232 0 : gdk_event_free(mEvent);
233 0 : }
234 : GtkWidget *mWidget;
235 : GdkEvent *mEvent;
236 : };
237 :
238 : static void
239 0 : DestroyMotionEventData(gpointer data)
240 : {
241 0 : delete static_cast<MotionEventData*>(data);
242 0 : }
243 :
244 : static gboolean
245 0 : DispatchMotionEventCopy(gpointer aData)
246 : {
247 0 : MotionEventData *data = static_cast<MotionEventData*>(aData);
248 :
249 : // Clear the timer id before OnSourceGrabEventAfter is called during event dispatch.
250 0 : sMotionEventTimerID = 0;
251 :
252 : // If there is no longer a grab on the widget, then the drag is over and
253 : // there is no need to continue drag motion.
254 0 : if (gtk_grab_get_current() == data->mWidget) {
255 0 : gtk_propagate_event(data->mWidget, data->mEvent);
256 : }
257 :
258 : // Cancel this timer;
259 : // We've already started another if the motion event was dispatched.
260 0 : return FALSE;
261 : }
262 :
263 : static void
264 0 : OnSourceGrabEventAfter(GtkWidget *widget, GdkEvent *event, gpointer user_data)
265 : {
266 0 : if (event->type != GDK_MOTION_NOTIFY)
267 0 : return;
268 :
269 0 : if (sMotionEventTimerID) {
270 0 : g_source_remove(sMotionEventTimerID);
271 : }
272 :
273 0 : MotionEventData *data = new MotionEventData(widget, event);
274 :
275 : // G_PRIORITY_DEFAULT_IDLE is lower priority than GDK's redraw idle source
276 : // and lower than GTK's idle source that sends drag position messages after
277 : // motion-notify signals.
278 : //
279 : // http://www.whatwg.org/specs/web-apps/current-work/multipage/dnd.html#drag-and-drop-processing-model
280 : // recommends an interval of 350ms +/- 200ms.
281 : sMotionEventTimerID =
282 : g_timeout_add_full(G_PRIORITY_DEFAULT_IDLE, 350,
283 0 : DispatchMotionEventCopy, data, DestroyMotionEventData);
284 : }
285 :
286 : // nsIDragService
287 :
288 : NS_IMETHODIMP
289 0 : nsDragService::InvokeDragSession(nsIDOMNode *aDOMNode,
290 : nsISupportsArray * aArrayTransferables,
291 : nsIScriptableRegion * aRegion,
292 : PRUint32 aActionType)
293 : {
294 0 : PR_LOG(sDragLm, PR_LOG_DEBUG, ("nsDragService::InvokeDragSession"));
295 : nsresult rv = nsBaseDragService::InvokeDragSession(aDOMNode,
296 : aArrayTransferables,
297 0 : aRegion, aActionType);
298 0 : NS_ENSURE_SUCCESS(rv, rv);
299 :
300 : // make sure that we have an array of transferables to use
301 0 : if (!aArrayTransferables)
302 0 : return NS_ERROR_INVALID_ARG;
303 : // set our reference to the transferables. this will also addref
304 : // the transferables since we're going to hang onto this beyond the
305 : // length of this call
306 0 : mSourceDataItems = aArrayTransferables;
307 : // get the list of items we offer for drags
308 0 : GtkTargetList *sourceList = GetSourceList();
309 :
310 0 : if (!sourceList)
311 0 : return NS_OK;
312 :
313 : // stored temporarily until the drag-begin signal has been received
314 0 : mSourceRegion = aRegion;
315 :
316 : // save our action type
317 0 : GdkDragAction action = GDK_ACTION_DEFAULT;
318 :
319 0 : if (aActionType & DRAGDROP_ACTION_COPY)
320 0 : action = (GdkDragAction)(action | GDK_ACTION_COPY);
321 0 : if (aActionType & DRAGDROP_ACTION_MOVE)
322 0 : action = (GdkDragAction)(action | GDK_ACTION_MOVE);
323 0 : if (aActionType & DRAGDROP_ACTION_LINK)
324 0 : action = (GdkDragAction)(action | GDK_ACTION_LINK);
325 :
326 : // Create a fake event for the drag so we can pass the time (so to speak).
327 : // If we don't do this, then, when the timestamp for the pending button
328 : // release event is used for the ungrab, the ungrab can fail due to the
329 : // timestamp being _earlier_ than CurrentTime.
330 : GdkEvent event;
331 0 : memset(&event, 0, sizeof(GdkEvent));
332 0 : event.type = GDK_BUTTON_PRESS;
333 0 : event.button.window = mHiddenWidget->window;
334 0 : event.button.time = nsWindow::GetLastUserInputTime();
335 :
336 : // start our drag.
337 : GdkDragContext *context = gtk_drag_begin(mHiddenWidget,
338 : sourceList,
339 : action,
340 : 1,
341 0 : &event);
342 :
343 0 : mSourceRegion = nsnull;
344 :
345 0 : if (context) {
346 0 : StartDragSession();
347 :
348 : // GTK uses another hidden window for receiving mouse events.
349 0 : mGrabWidget = gtk_grab_get_current();
350 0 : if (mGrabWidget) {
351 0 : g_object_ref(mGrabWidget);
352 : // Only motion events are required but connect to
353 : // "event-after" as this is never blocked by other handlers.
354 0 : g_signal_connect(mGrabWidget, "event-after",
355 0 : G_CALLBACK(OnSourceGrabEventAfter), NULL);
356 : }
357 : }
358 : else {
359 0 : rv = NS_ERROR_FAILURE;
360 : }
361 :
362 0 : gtk_target_list_unref(sourceList);
363 :
364 0 : return rv;
365 : }
366 :
367 : bool
368 0 : nsDragService::SetAlphaPixmap(gfxASurface *aSurface,
369 : GdkDragContext *aContext,
370 : PRInt32 aXOffset,
371 : PRInt32 aYOffset,
372 : const nsIntRect& dragRect)
373 : {
374 0 : GdkScreen* screen = gtk_widget_get_screen(mHiddenWidget);
375 :
376 : // Transparent drag icons need, like a lot of transparency-related things,
377 : // a compositing X window manager
378 0 : if (!gdk_screen_is_composited(screen))
379 0 : return false;
380 :
381 0 : GdkColormap* alphaColormap = gdk_screen_get_rgba_colormap(screen);
382 0 : if (!alphaColormap)
383 0 : return false;
384 :
385 : GdkPixmap* pixmap = gdk_pixmap_new(NULL, dragRect.width, dragRect.height,
386 0 : gdk_colormap_get_visual(alphaColormap)->depth);
387 0 : if (!pixmap)
388 0 : return false;
389 :
390 0 : gdk_drawable_set_colormap(GDK_DRAWABLE(pixmap), alphaColormap);
391 :
392 : // Make a gfxXlibSurface wrapped around the pixmap to render on
393 : nsRefPtr<gfxASurface> xPixmapSurface =
394 0 : nsWindow::GetSurfaceForGdkDrawable(GDK_DRAWABLE(pixmap),
395 0 : dragRect.Size());
396 0 : if (!xPixmapSurface)
397 0 : return false;
398 :
399 0 : nsRefPtr<gfxContext> xPixmapCtx = new gfxContext(xPixmapSurface);
400 :
401 : // Clear it...
402 0 : xPixmapCtx->SetOperator(gfxContext::OPERATOR_CLEAR);
403 0 : xPixmapCtx->Paint();
404 :
405 : // ...and paint the drag image with translucency
406 0 : xPixmapCtx->SetOperator(gfxContext::OPERATOR_SOURCE);
407 0 : xPixmapCtx->SetSource(aSurface);
408 0 : xPixmapCtx->Paint(DRAG_IMAGE_ALPHA_LEVEL);
409 :
410 : // The drag transaction addrefs the pixmap, so we can just unref it from us here
411 : gtk_drag_set_icon_pixmap(aContext, alphaColormap, pixmap, NULL,
412 0 : aXOffset, aYOffset);
413 0 : g_object_unref(pixmap);
414 0 : return true;
415 : }
416 :
417 : NS_IMETHODIMP
418 0 : nsDragService::StartDragSession()
419 : {
420 0 : PR_LOG(sDragLm, PR_LOG_DEBUG, ("nsDragService::StartDragSession"));
421 0 : return nsBaseDragService::StartDragSession();
422 : }
423 :
424 : NS_IMETHODIMP
425 0 : nsDragService::EndDragSession(bool aDoneDrag)
426 : {
427 0 : PR_LOG(sDragLm, PR_LOG_DEBUG, ("nsDragService::EndDragSession %d",
428 : aDoneDrag));
429 :
430 0 : if (mGrabWidget) {
431 0 : g_signal_handlers_disconnect_by_func(mGrabWidget,
432 0 : FuncToGpointer(OnSourceGrabEventAfter), NULL);
433 0 : g_object_unref(mGrabWidget);
434 0 : mGrabWidget = NULL;
435 :
436 0 : if (sMotionEventTimerID) {
437 0 : g_source_remove(sMotionEventTimerID);
438 0 : sMotionEventTimerID = 0;
439 : }
440 : }
441 :
442 : // unset our drag action
443 0 : SetDragAction(DRAGDROP_ACTION_NONE);
444 0 : return nsBaseDragService::EndDragSession(aDoneDrag);
445 : }
446 :
447 : // nsIDragSession
448 : NS_IMETHODIMP
449 0 : nsDragService::SetCanDrop(bool aCanDrop)
450 : {
451 0 : PR_LOG(sDragLm, PR_LOG_DEBUG, ("nsDragService::SetCanDrop %d",
452 : aCanDrop));
453 0 : mCanDrop = aCanDrop;
454 0 : return NS_OK;
455 : }
456 :
457 : NS_IMETHODIMP
458 0 : nsDragService::GetCanDrop(bool *aCanDrop)
459 : {
460 0 : PR_LOG(sDragLm, PR_LOG_DEBUG, ("nsDragService::GetCanDrop"));
461 0 : *aCanDrop = mCanDrop;
462 0 : return NS_OK;
463 : }
464 :
465 : // count the number of URIs in some text/uri-list format data.
466 : static PRUint32
467 0 : CountTextUriListItems(const char *data,
468 : PRUint32 datalen)
469 : {
470 0 : const char *p = data;
471 0 : const char *endPtr = p + datalen;
472 0 : PRUint32 count = 0;
473 :
474 0 : while (p < endPtr) {
475 : // skip whitespace (if any)
476 0 : while (p < endPtr && *p != '\0' && isspace(*p))
477 0 : p++;
478 : // if we aren't at the end of the line ...
479 0 : if (p != endPtr && *p != '\0' && *p != '\n' && *p != '\r')
480 0 : count++;
481 : // skip to the end of the line
482 0 : while (p < endPtr && *p != '\0' && *p != '\n')
483 0 : p++;
484 0 : p++; // skip the actual newline as well.
485 : }
486 0 : return count;
487 : }
488 :
489 : // extract an item from text/uri-list formatted data and convert it to
490 : // unicode.
491 : static void
492 0 : GetTextUriListItem(const char *data,
493 : PRUint32 datalen,
494 : PRUint32 aItemIndex,
495 : PRUnichar **convertedText,
496 : PRInt32 *convertedTextLen)
497 : {
498 0 : const char *p = data;
499 0 : const char *endPtr = p + datalen;
500 0 : unsigned int count = 0;
501 :
502 0 : *convertedText = nsnull;
503 0 : while (p < endPtr) {
504 : // skip whitespace (if any)
505 0 : while (p < endPtr && *p != '\0' && isspace(*p))
506 0 : p++;
507 : // if we aren't at the end of the line, we have a url
508 0 : if (p != endPtr && *p != '\0' && *p != '\n' && *p != '\r')
509 0 : count++;
510 : // this is the item we are after ...
511 0 : if (aItemIndex + 1 == count) {
512 0 : const char *q = p;
513 0 : while (q < endPtr && *q != '\0' && *q != '\n' && *q != '\r')
514 0 : q++;
515 : nsPrimitiveHelpers::ConvertPlatformPlainTextToUnicode(
516 0 : p, q - p, convertedText, convertedTextLen);
517 0 : break;
518 : }
519 : // skip to the end of the line
520 0 : while (p < endPtr && *p != '\0' && *p != '\n')
521 0 : p++;
522 0 : p++; // skip the actual newline as well.
523 : }
524 :
525 : // didn't find the desired item, so just pass the whole lot
526 0 : if (!*convertedText) {
527 : nsPrimitiveHelpers::ConvertPlatformPlainTextToUnicode(
528 0 : data, datalen, convertedText, convertedTextLen);
529 : }
530 0 : }
531 :
532 : NS_IMETHODIMP
533 0 : nsDragService::GetNumDropItems(PRUint32 * aNumItems)
534 : {
535 0 : PR_LOG(sDragLm, PR_LOG_DEBUG, ("nsDragService::GetNumDropItems"));
536 0 : bool isList = IsTargetContextList();
537 0 : if (isList)
538 0 : mSourceDataItems->Count(aNumItems);
539 : else {
540 0 : GdkAtom gdkFlavor = gdk_atom_intern(gTextUriListType, FALSE);
541 0 : GetTargetDragData(gdkFlavor);
542 0 : if (mTargetDragData) {
543 0 : const char *data = reinterpret_cast<char*>(mTargetDragData);
544 0 : *aNumItems = CountTextUriListItems(data, mTargetDragDataLen);
545 : } else
546 0 : *aNumItems = 1;
547 : }
548 0 : PR_LOG(sDragLm, PR_LOG_DEBUG, ("%d items", *aNumItems));
549 0 : return NS_OK;
550 : }
551 :
552 :
553 : NS_IMETHODIMP
554 0 : nsDragService::GetData(nsITransferable * aTransferable,
555 : PRUint32 aItemIndex)
556 : {
557 0 : PR_LOG(sDragLm, PR_LOG_DEBUG, ("nsDragService::GetData %d", aItemIndex));
558 :
559 : // make sure that we have a transferable
560 0 : if (!aTransferable)
561 0 : return NS_ERROR_INVALID_ARG;
562 :
563 : // get flavor list that includes all acceptable flavors (including
564 : // ones obtained through conversion). Flavors are nsISupportsStrings
565 : // so that they can be seen from JS.
566 0 : nsresult rv = NS_ERROR_FAILURE;
567 0 : nsCOMPtr<nsISupportsArray> flavorList;
568 : rv = aTransferable->FlavorsTransferableCanImport(
569 0 : getter_AddRefs(flavorList));
570 0 : if (NS_FAILED(rv))
571 0 : return rv;
572 :
573 : // count the number of flavors
574 : PRUint32 cnt;
575 0 : flavorList->Count(&cnt);
576 : unsigned int i;
577 :
578 : // check to see if this is an internal list
579 0 : bool isList = IsTargetContextList();
580 :
581 0 : if (isList) {
582 0 : PR_LOG(sDragLm, PR_LOG_DEBUG, ("it's a list..."));
583 : // find a matching flavor
584 0 : for (i = 0; i < cnt; ++i) {
585 0 : nsCOMPtr<nsISupports> genericWrapper;
586 0 : flavorList->GetElementAt(i, getter_AddRefs(genericWrapper));
587 0 : nsCOMPtr<nsISupportsCString> currentFlavor;
588 0 : currentFlavor = do_QueryInterface(genericWrapper);
589 0 : if (!currentFlavor)
590 0 : continue;
591 :
592 0 : nsXPIDLCString flavorStr;
593 0 : currentFlavor->ToString(getter_Copies(flavorStr));
594 0 : PR_LOG(sDragLm,
595 : PR_LOG_DEBUG,
596 : ("flavor is %s\n", (const char *)flavorStr));
597 : // get the item with the right index
598 0 : nsCOMPtr<nsISupports> genericItem;
599 0 : mSourceDataItems->GetElementAt(aItemIndex,
600 0 : getter_AddRefs(genericItem));
601 0 : nsCOMPtr<nsITransferable> item(do_QueryInterface(genericItem));
602 0 : if (!item)
603 0 : continue;
604 :
605 0 : nsCOMPtr<nsISupports> data;
606 0 : PRUint32 tmpDataLen = 0;
607 0 : PR_LOG(sDragLm, PR_LOG_DEBUG,
608 : ("trying to get transfer data for %s\n",
609 : (const char *)flavorStr));
610 0 : rv = item->GetTransferData(flavorStr,
611 0 : getter_AddRefs(data),
612 0 : &tmpDataLen);
613 0 : if (NS_FAILED(rv)) {
614 0 : PR_LOG(sDragLm, PR_LOG_DEBUG, ("failed.\n"));
615 0 : continue;
616 : }
617 0 : PR_LOG(sDragLm, PR_LOG_DEBUG, ("succeeded.\n"));
618 0 : rv = aTransferable->SetTransferData(flavorStr,data,tmpDataLen);
619 0 : if (NS_FAILED(rv)) {
620 0 : PR_LOG(sDragLm,
621 : PR_LOG_DEBUG,
622 : ("fail to set transfer data into transferable!\n"));
623 0 : continue;
624 : }
625 : // ok, we got the data
626 0 : return NS_OK;
627 : }
628 : // if we got this far, we failed
629 0 : return NS_ERROR_FAILURE;
630 : }
631 :
632 : // Now walk down the list of flavors. When we find one that is
633 : // actually present, copy out the data into the transferable in that
634 : // format. SetTransferData() implicitly handles conversions.
635 0 : for ( i = 0; i < cnt; ++i ) {
636 0 : nsCOMPtr<nsISupports> genericWrapper;
637 0 : flavorList->GetElementAt(i,getter_AddRefs(genericWrapper));
638 0 : nsCOMPtr<nsISupportsCString> currentFlavor;
639 0 : currentFlavor = do_QueryInterface(genericWrapper);
640 0 : if (currentFlavor) {
641 : // find our gtk flavor
642 0 : nsXPIDLCString flavorStr;
643 0 : currentFlavor->ToString(getter_Copies(flavorStr));
644 0 : GdkAtom gdkFlavor = gdk_atom_intern(flavorStr, FALSE);
645 0 : PR_LOG(sDragLm, PR_LOG_DEBUG,
646 : ("looking for data in type %s, gdk flavor %ld\n",
647 : static_cast<const char*>(flavorStr), gdkFlavor));
648 0 : bool dataFound = false;
649 0 : if (gdkFlavor) {
650 0 : GetTargetDragData(gdkFlavor);
651 : }
652 0 : if (mTargetDragData) {
653 0 : PR_LOG(sDragLm, PR_LOG_DEBUG, ("dataFound = true\n"));
654 0 : dataFound = true;
655 : }
656 : else {
657 0 : PR_LOG(sDragLm, PR_LOG_DEBUG, ("dataFound = false\n"));
658 :
659 : // Dragging and dropping from the file manager would cause us
660 : // to parse the source text as a nsILocalFile URL.
661 0 : if ( strcmp(flavorStr, kFileMime) == 0 ) {
662 0 : gdkFlavor = gdk_atom_intern(kTextMime, FALSE);
663 0 : GetTargetDragData(gdkFlavor);
664 0 : if (mTargetDragData) {
665 0 : const char* text = static_cast<char*>(mTargetDragData);
666 0 : PRUnichar* convertedText = nsnull;
667 0 : PRInt32 convertedTextLen = 0;
668 :
669 : GetTextUriListItem(text, mTargetDragDataLen, aItemIndex,
670 0 : &convertedText, &convertedTextLen);
671 :
672 0 : if (convertedText) {
673 0 : nsCOMPtr<nsIIOService> ioService = do_GetIOService(&rv);
674 0 : nsCOMPtr<nsIURI> fileURI;
675 0 : nsresult rv = ioService->NewURI(NS_ConvertUTF16toUTF8(convertedText),
676 0 : nsnull, nsnull, getter_AddRefs(fileURI));
677 0 : if (NS_SUCCEEDED(rv)) {
678 0 : nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(fileURI, &rv);
679 0 : if (NS_SUCCEEDED(rv)) {
680 0 : nsCOMPtr<nsIFile> file;
681 0 : rv = fileURL->GetFile(getter_AddRefs(file));
682 0 : if (NS_SUCCEEDED(rv)) {
683 : // The common wrapping code at the end of
684 : // this function assumes the data is text
685 : // and calls text-specific operations.
686 : // Make a secret hideout here for nsILocalFile
687 : // objects and return early.
688 : aTransferable->SetTransferData(flavorStr, file,
689 0 : convertedTextLen);
690 0 : g_free(convertedText);
691 0 : return NS_OK;
692 : }
693 : }
694 : }
695 0 : g_free(convertedText);
696 : }
697 0 : continue;
698 : }
699 : }
700 :
701 : // if we are looking for text/unicode and we fail to find it
702 : // on the clipboard first, try again with text/plain. If that
703 : // is present, convert it to unicode.
704 0 : if ( strcmp(flavorStr, kUnicodeMime) == 0 ) {
705 0 : PR_LOG(sDragLm, PR_LOG_DEBUG,
706 : ("we were looking for text/unicode... \
707 : trying with text/plain;charset=utf-8\n"));
708 0 : gdkFlavor = gdk_atom_intern(gTextPlainUTF8Type, FALSE);
709 0 : GetTargetDragData(gdkFlavor);
710 0 : if (mTargetDragData) {
711 0 : PR_LOG(sDragLm, PR_LOG_DEBUG, ("Got textplain data\n"));
712 : const char* castedText =
713 0 : reinterpret_cast<char*>(mTargetDragData);
714 0 : PRUnichar* convertedText = nsnull;
715 : NS_ConvertUTF8toUTF16 ucs2string(castedText,
716 0 : mTargetDragDataLen);
717 0 : convertedText = ToNewUnicode(ucs2string);
718 0 : if ( convertedText ) {
719 0 : PR_LOG(sDragLm, PR_LOG_DEBUG,
720 : ("successfully converted plain text \
721 : to unicode.\n"));
722 : // out with the old, in with the new
723 0 : g_free(mTargetDragData);
724 0 : mTargetDragData = convertedText;
725 0 : mTargetDragDataLen = ucs2string.Length() * 2;
726 0 : dataFound = true;
727 : } // if plain text data on clipboard
728 : } else {
729 0 : PR_LOG(sDragLm, PR_LOG_DEBUG,
730 : ("we were looking for text/unicode... \
731 : trying again with text/plain\n"));
732 0 : gdkFlavor = gdk_atom_intern(kTextMime, FALSE);
733 0 : GetTargetDragData(gdkFlavor);
734 0 : if (mTargetDragData) {
735 0 : PR_LOG(sDragLm, PR_LOG_DEBUG, ("Got textplain data\n"));
736 : const char* castedText =
737 0 : reinterpret_cast<char*>(mTargetDragData);
738 0 : PRUnichar* convertedText = nsnull;
739 0 : PRInt32 convertedTextLen = 0;
740 : nsPrimitiveHelpers::ConvertPlatformPlainTextToUnicode(
741 : castedText, mTargetDragDataLen,
742 0 : &convertedText, &convertedTextLen);
743 0 : if ( convertedText ) {
744 0 : PR_LOG(sDragLm, PR_LOG_DEBUG,
745 : ("successfully converted plain text \
746 : to unicode.\n"));
747 : // out with the old, in with the new
748 0 : g_free(mTargetDragData);
749 0 : mTargetDragData = convertedText;
750 0 : mTargetDragDataLen = convertedTextLen * 2;
751 0 : dataFound = true;
752 : } // if plain text data on clipboard
753 : } // if plain text flavor present
754 : } // if plain text charset=utf-8 flavor present
755 : } // if looking for text/unicode
756 :
757 : // if we are looking for text/x-moz-url and we failed to find
758 : // it on the clipboard, try again with text/uri-list, and then
759 : // _NETSCAPE_URL
760 0 : if (strcmp(flavorStr, kURLMime) == 0) {
761 0 : PR_LOG(sDragLm, PR_LOG_DEBUG,
762 : ("we were looking for text/x-moz-url...\
763 : trying again with text/uri-list\n"));
764 0 : gdkFlavor = gdk_atom_intern(gTextUriListType, FALSE);
765 0 : GetTargetDragData(gdkFlavor);
766 0 : if (mTargetDragData) {
767 0 : PR_LOG(sDragLm, PR_LOG_DEBUG,
768 : ("Got text/uri-list data\n"));
769 : const char *data =
770 0 : reinterpret_cast<char*>(mTargetDragData);
771 0 : PRUnichar* convertedText = nsnull;
772 0 : PRInt32 convertedTextLen = 0;
773 :
774 : GetTextUriListItem(data, mTargetDragDataLen, aItemIndex,
775 0 : &convertedText, &convertedTextLen);
776 :
777 0 : if ( convertedText ) {
778 0 : PR_LOG(sDragLm, PR_LOG_DEBUG,
779 : ("successfully converted \
780 : _NETSCAPE_URL to unicode.\n"));
781 : // out with the old, in with the new
782 0 : g_free(mTargetDragData);
783 0 : mTargetDragData = convertedText;
784 0 : mTargetDragDataLen = convertedTextLen * 2;
785 0 : dataFound = true;
786 : }
787 : }
788 : else {
789 0 : PR_LOG(sDragLm, PR_LOG_DEBUG,
790 : ("failed to get text/uri-list data\n"));
791 : }
792 0 : if (!dataFound) {
793 0 : PR_LOG(sDragLm, PR_LOG_DEBUG,
794 : ("we were looking for text/x-moz-url...\
795 : trying again with _NETSCAP_URL\n"));
796 0 : gdkFlavor = gdk_atom_intern(gMozUrlType, FALSE);
797 0 : GetTargetDragData(gdkFlavor);
798 0 : if (mTargetDragData) {
799 0 : PR_LOG(sDragLm, PR_LOG_DEBUG,
800 : ("Got _NETSCAPE_URL data\n"));
801 : const char* castedText =
802 0 : reinterpret_cast<char*>(mTargetDragData);
803 0 : PRUnichar* convertedText = nsnull;
804 0 : PRInt32 convertedTextLen = 0;
805 0 : nsPrimitiveHelpers::ConvertPlatformPlainTextToUnicode(castedText, mTargetDragDataLen, &convertedText, &convertedTextLen);
806 0 : if ( convertedText ) {
807 0 : PR_LOG(sDragLm,
808 : PR_LOG_DEBUG,
809 : ("successfully converted _NETSCAPE_URL \
810 : to unicode.\n"));
811 : // out with the old, in with the new
812 0 : g_free(mTargetDragData);
813 0 : mTargetDragData = convertedText;
814 0 : mTargetDragDataLen = convertedTextLen * 2;
815 0 : dataFound = true;
816 : }
817 : }
818 : else {
819 0 : PR_LOG(sDragLm, PR_LOG_DEBUG,
820 : ("failed to get _NETSCAPE_URL data\n"));
821 : }
822 : }
823 : }
824 :
825 : } // else we try one last ditch effort to find our data
826 :
827 0 : if (dataFound) {
828 : // the DOM only wants LF, so convert from MacOS line endings
829 : // to DOM line endings.
830 : nsLinebreakHelpers::ConvertPlatformToDOMLinebreaks(
831 : flavorStr,
832 : &mTargetDragData,
833 0 : reinterpret_cast<int*>(&mTargetDragDataLen));
834 :
835 : // put it into the transferable.
836 0 : nsCOMPtr<nsISupports> genericDataWrapper;
837 : nsPrimitiveHelpers::CreatePrimitiveForData(flavorStr,
838 : mTargetDragData, mTargetDragDataLen,
839 0 : getter_AddRefs(genericDataWrapper));
840 : aTransferable->SetTransferData(flavorStr,
841 : genericDataWrapper,
842 0 : mTargetDragDataLen);
843 : // we found one, get out of this loop!
844 0 : PR_LOG(sDragLm, PR_LOG_DEBUG, ("dataFound and converted!\n"));
845 : break;
846 : }
847 : } // if (currentFlavor)
848 : } // foreach flavor
849 :
850 0 : return NS_OK;
851 :
852 : }
853 :
854 : NS_IMETHODIMP
855 0 : nsDragService::IsDataFlavorSupported(const char *aDataFlavor,
856 : bool *_retval)
857 : {
858 0 : PR_LOG(sDragLm, PR_LOG_DEBUG, ("nsDragService::IsDataFlavorSupported %s",
859 : aDataFlavor));
860 0 : if (!_retval)
861 0 : return NS_ERROR_INVALID_ARG;
862 :
863 : // set this to no by default
864 0 : *_retval = false;
865 :
866 : // check to make sure that we have a drag object set, here
867 0 : if (!mTargetDragContext) {
868 0 : PR_LOG(sDragLm, PR_LOG_DEBUG,
869 : ("*** warning: IsDataFlavorSupported \
870 : called without a valid drag context!\n"));
871 0 : return NS_OK;
872 : }
873 :
874 : // check to see if the target context is a list.
875 0 : bool isList = IsTargetContextList();
876 : // if it is, just look in the internal data since we are the source
877 : // for it.
878 0 : if (isList) {
879 0 : PR_LOG(sDragLm, PR_LOG_DEBUG, ("It's a list.."));
880 0 : PRUint32 numDragItems = 0;
881 : // if we don't have mDataItems we didn't start this drag so it's
882 : // an external client trying to fool us.
883 0 : if (!mSourceDataItems)
884 0 : return NS_OK;
885 0 : mSourceDataItems->Count(&numDragItems);
886 0 : for (PRUint32 itemIndex = 0; itemIndex < numDragItems; ++itemIndex) {
887 0 : nsCOMPtr<nsISupports> genericItem;
888 0 : mSourceDataItems->GetElementAt(itemIndex,
889 0 : getter_AddRefs(genericItem));
890 0 : nsCOMPtr<nsITransferable> currItem(do_QueryInterface(genericItem));
891 0 : if (currItem) {
892 0 : nsCOMPtr <nsISupportsArray> flavorList;
893 0 : currItem->FlavorsTransferableCanExport(
894 0 : getter_AddRefs(flavorList));
895 0 : if (flavorList) {
896 : PRUint32 numFlavors;
897 0 : flavorList->Count( &numFlavors );
898 0 : for ( PRUint32 flavorIndex = 0;
899 : flavorIndex < numFlavors ;
900 : ++flavorIndex ) {
901 0 : nsCOMPtr<nsISupports> genericWrapper;
902 0 : flavorList->GetElementAt(flavorIndex,
903 0 : getter_AddRefs(genericWrapper));
904 0 : nsCOMPtr<nsISupportsCString> currentFlavor;
905 0 : currentFlavor = do_QueryInterface(genericWrapper);
906 0 : if (currentFlavor) {
907 0 : nsXPIDLCString flavorStr;
908 0 : currentFlavor->ToString(getter_Copies(flavorStr));
909 0 : PR_LOG(sDragLm, PR_LOG_DEBUG,
910 : ("checking %s against %s\n",
911 : (const char *)flavorStr, aDataFlavor));
912 0 : if (strcmp(flavorStr, aDataFlavor) == 0) {
913 0 : PR_LOG(sDragLm, PR_LOG_DEBUG,
914 : ("boioioioiooioioioing!\n"));
915 0 : *_retval = true;
916 : }
917 : }
918 : }
919 : }
920 : }
921 : }
922 0 : return NS_OK;
923 : }
924 :
925 : // check the target context vs. this flavor, one at a time
926 : GList *tmp;
927 0 : for (tmp = mTargetDragContext->targets; tmp; tmp = tmp->next) {
928 : /* Bug 331198 */
929 0 : GdkAtom atom = GDK_POINTER_TO_ATOM(tmp->data);
930 0 : gchar *name = NULL;
931 0 : name = gdk_atom_name(atom);
932 0 : PR_LOG(sDragLm, PR_LOG_DEBUG,
933 : ("checking %s against %s\n", name, aDataFlavor));
934 0 : if (name && (strcmp(name, aDataFlavor) == 0)) {
935 0 : PR_LOG(sDragLm, PR_LOG_DEBUG, ("good!\n"));
936 0 : *_retval = true;
937 : }
938 : // check for automatic text/uri-list -> text/x-moz-url mapping
939 0 : if (!*_retval &&
940 : name &&
941 0 : (strcmp(name, gTextUriListType) == 0) &&
942 0 : (strcmp(aDataFlavor, kURLMime) == 0)) {
943 0 : PR_LOG(sDragLm, PR_LOG_DEBUG,
944 : ("good! ( it's text/uri-list and \
945 : we're checking against text/x-moz-url )\n"));
946 0 : *_retval = true;
947 : }
948 : // check for automatic _NETSCAPE_URL -> text/x-moz-url mapping
949 0 : if (!*_retval &&
950 : name &&
951 0 : (strcmp(name, gMozUrlType) == 0) &&
952 0 : (strcmp(aDataFlavor, kURLMime) == 0)) {
953 0 : PR_LOG(sDragLm, PR_LOG_DEBUG,
954 : ("good! ( it's _NETSCAPE_URL and \
955 : we're checking against text/x-moz-url )\n"));
956 0 : *_retval = true;
957 : }
958 : // check for auto text/plain -> text/unicode mapping
959 0 : if (!*_retval &&
960 : name &&
961 0 : (strcmp(name, kTextMime) == 0) &&
962 0 : ((strcmp(aDataFlavor, kUnicodeMime) == 0) ||
963 0 : (strcmp(aDataFlavor, kFileMime) == 0))) {
964 0 : PR_LOG(sDragLm, PR_LOG_DEBUG,
965 : ("good! ( it's text plain and we're checking \
966 : against text/unicode or application/x-moz-file)\n"));
967 0 : *_retval = true;
968 : }
969 0 : g_free(name);
970 : }
971 0 : return NS_OK;
972 : }
973 :
974 : // nsIDragSessionGTK
975 :
976 : NS_IMETHODIMP
977 0 : nsDragService::TargetSetLastContext(GtkWidget *aWidget,
978 : GdkDragContext *aContext,
979 : guint aTime)
980 : {
981 0 : PR_LOG(sDragLm, PR_LOG_DEBUG, ("nsDragService::TargetSetLastContext"));
982 0 : mTargetWidget = aWidget;
983 0 : mTargetDragContext = aContext;
984 0 : mTargetTime = aTime;
985 0 : return NS_OK;
986 : }
987 :
988 : NS_IMETHODIMP
989 0 : nsDragService::TargetStartDragMotion(void)
990 : {
991 0 : PR_LOG(sDragLm, PR_LOG_DEBUG, ("nsDragService::TargetStartDragMotion"));
992 0 : mCanDrop = false;
993 0 : return NS_OK;
994 : }
995 :
996 : NS_IMETHODIMP
997 0 : nsDragService::TargetEndDragMotion(GtkWidget *aWidget,
998 : GdkDragContext *aContext,
999 : guint aTime)
1000 : {
1001 0 : PR_LOG(sDragLm, PR_LOG_DEBUG,
1002 : ("nsDragService::TargetEndDragMotion %d", mCanDrop));
1003 :
1004 0 : if (mCanDrop) {
1005 : GdkDragAction action;
1006 : // notify the dragger if we can drop
1007 0 : switch (mDragAction) {
1008 : case DRAGDROP_ACTION_COPY:
1009 0 : action = GDK_ACTION_COPY;
1010 0 : break;
1011 : case DRAGDROP_ACTION_LINK:
1012 0 : action = GDK_ACTION_LINK;
1013 0 : break;
1014 : default:
1015 0 : action = GDK_ACTION_MOVE;
1016 0 : break;
1017 : }
1018 0 : gdk_drag_status(aContext, action, aTime);
1019 : }
1020 : else {
1021 0 : gdk_drag_status(aContext, (GdkDragAction)0, aTime);
1022 : }
1023 :
1024 0 : return NS_OK;
1025 : }
1026 :
1027 : NS_IMETHODIMP
1028 0 : nsDragService::TargetDataReceived(GtkWidget *aWidget,
1029 : GdkDragContext *aContext,
1030 : gint aX,
1031 : gint aY,
1032 : GtkSelectionData *aSelectionData,
1033 : guint aInfo,
1034 : guint32 aTime)
1035 : {
1036 0 : PR_LOG(sDragLm, PR_LOG_DEBUG, ("nsDragService::TargetDataReceived"));
1037 0 : TargetResetData();
1038 0 : mTargetDragDataReceived = true;
1039 0 : if (aSelectionData->length > 0) {
1040 0 : mTargetDragDataLen = aSelectionData->length;
1041 0 : mTargetDragData = g_malloc(mTargetDragDataLen);
1042 0 : memcpy(mTargetDragData, aSelectionData->data, mTargetDragDataLen);
1043 : }
1044 : else {
1045 0 : PR_LOG(sDragLm, PR_LOG_DEBUG,
1046 : ("Failed to get data. selection data len was %d\n",
1047 : aSelectionData->length));
1048 : }
1049 0 : return NS_OK;
1050 : }
1051 :
1052 :
1053 : NS_IMETHODIMP
1054 0 : nsDragService::TargetSetTimeCallback(nsIDragSessionGTKTimeCB aCallback)
1055 : {
1056 0 : return NS_OK;
1057 : }
1058 :
1059 :
1060 : bool
1061 0 : nsDragService::IsTargetContextList(void)
1062 : {
1063 0 : bool retval = false;
1064 :
1065 0 : if (!mTargetDragContext)
1066 0 : return retval;
1067 :
1068 : // gMimeListType drags only work for drags within a single process.
1069 : // The gtk_drag_get_source_widget() function will return NULL if the
1070 : // source of the drag is another app, so we use it to check if a
1071 : // gMimeListType drop will work or not.
1072 0 : if (gtk_drag_get_source_widget(mTargetDragContext) == NULL)
1073 0 : return retval;
1074 :
1075 : GList *tmp;
1076 :
1077 : // walk the list of context targets and see if one of them is a list
1078 : // of items.
1079 0 : for (tmp = mTargetDragContext->targets; tmp; tmp = tmp->next) {
1080 : /* Bug 331198 */
1081 0 : GdkAtom atom = GDK_POINTER_TO_ATOM(tmp->data);
1082 0 : gchar *name = NULL;
1083 0 : name = gdk_atom_name(atom);
1084 0 : if (name && strcmp(name, gMimeListType) == 0)
1085 0 : retval = true;
1086 0 : g_free(name);
1087 0 : if (retval)
1088 0 : break;
1089 : }
1090 0 : return retval;
1091 : }
1092 :
1093 : // Maximum time to wait for a "drag_received" arrived, in microseconds
1094 : #define NS_DND_TIMEOUT 500000
1095 :
1096 : void
1097 0 : nsDragService::GetTargetDragData(GdkAtom aFlavor)
1098 : {
1099 0 : PR_LOG(sDragLm, PR_LOG_DEBUG, ("getting data flavor %d\n", aFlavor));
1100 0 : PR_LOG(sDragLm, PR_LOG_DEBUG, ("mLastWidget is %p and mLastContext is %p\n",
1101 : mTargetWidget, mTargetDragContext));
1102 : // reset our target data areas
1103 0 : TargetResetData();
1104 0 : gtk_drag_get_data(mTargetWidget, mTargetDragContext, aFlavor, mTargetTime);
1105 :
1106 0 : PR_LOG(sDragLm, PR_LOG_DEBUG, ("about to start inner iteration."));
1107 0 : PRTime entryTime = PR_Now();
1108 0 : while (!mTargetDragDataReceived && mDoingDrag) {
1109 : // check the number of iterations
1110 0 : PR_LOG(sDragLm, PR_LOG_DEBUG, ("doing iteration...\n"));
1111 0 : PR_Sleep(20*PR_TicksPerSecond()/1000); /* sleep for 20 ms/iteration */
1112 0 : if (PR_Now()-entryTime > NS_DND_TIMEOUT) break;
1113 0 : gtk_main_iteration();
1114 : }
1115 0 : PR_LOG(sDragLm, PR_LOG_DEBUG, ("finished inner iteration\n"));
1116 0 : }
1117 :
1118 : void
1119 0 : nsDragService::TargetResetData(void)
1120 : {
1121 0 : mTargetDragDataReceived = false;
1122 : // make sure to free old data if we have to
1123 0 : g_free(mTargetDragData);
1124 0 : mTargetDragData = 0;
1125 0 : mTargetDragDataLen = 0;
1126 0 : }
1127 :
1128 : GtkTargetList *
1129 0 : nsDragService::GetSourceList(void)
1130 : {
1131 0 : if (!mSourceDataItems)
1132 0 : return NULL;
1133 0 : nsTArray<GtkTargetEntry*> targetArray;
1134 : GtkTargetEntry *targets;
1135 0 : GtkTargetList *targetList = 0;
1136 0 : PRUint32 targetCount = 0;
1137 0 : unsigned int numDragItems = 0;
1138 :
1139 0 : mSourceDataItems->Count(&numDragItems);
1140 :
1141 : // Check to see if we're dragging > 1 item.
1142 0 : if (numDragItems > 1) {
1143 : // as the Xdnd protocol only supports a single item (or is it just
1144 : // gtk's implementation?), we don't advertise all flavours listed
1145 : // in the nsITransferable.
1146 :
1147 : // the application/x-moz-internal-item-list format, which preserves
1148 : // all information for drags within the same mozilla instance.
1149 0 : GdkAtom listAtom = gdk_atom_intern(gMimeListType, FALSE);
1150 : GtkTargetEntry *listTarget =
1151 0 : (GtkTargetEntry *)g_malloc(sizeof(GtkTargetEntry));
1152 0 : listTarget->target = g_strdup(gMimeListType);
1153 0 : listTarget->flags = 0;
1154 : /* Bug 331198 */
1155 0 : listTarget->info = NS_PTR_TO_UINT32(listAtom);
1156 0 : PR_LOG(sDragLm, PR_LOG_DEBUG,
1157 : ("automatically adding target %s with id %ld\n",
1158 : listTarget->target, listAtom));
1159 0 : targetArray.AppendElement(listTarget);
1160 :
1161 : // check what flavours are supported so we can decide what other
1162 : // targets to advertise.
1163 0 : nsCOMPtr<nsISupports> genericItem;
1164 0 : mSourceDataItems->GetElementAt(0, getter_AddRefs(genericItem));
1165 0 : nsCOMPtr<nsITransferable> currItem(do_QueryInterface(genericItem));
1166 :
1167 0 : if (currItem) {
1168 0 : nsCOMPtr <nsISupportsArray> flavorList;
1169 0 : currItem->FlavorsTransferableCanExport(getter_AddRefs(flavorList));
1170 0 : if (flavorList) {
1171 : PRUint32 numFlavors;
1172 0 : flavorList->Count( &numFlavors );
1173 0 : for (PRUint32 flavorIndex = 0;
1174 : flavorIndex < numFlavors ;
1175 : ++flavorIndex ) {
1176 0 : nsCOMPtr<nsISupports> genericWrapper;
1177 0 : flavorList->GetElementAt(flavorIndex,
1178 0 : getter_AddRefs(genericWrapper));
1179 0 : nsCOMPtr<nsISupportsCString> currentFlavor;
1180 0 : currentFlavor = do_QueryInterface(genericWrapper);
1181 0 : if (currentFlavor) {
1182 0 : nsXPIDLCString flavorStr;
1183 0 : currentFlavor->ToString(getter_Copies(flavorStr));
1184 :
1185 : // check if text/x-moz-url is supported.
1186 : // If so, advertise
1187 : // text/uri-list.
1188 0 : if (strcmp(flavorStr, kURLMime) == 0) {
1189 0 : listAtom = gdk_atom_intern(gTextUriListType, FALSE);
1190 : listTarget =
1191 0 : (GtkTargetEntry *)g_malloc(sizeof(GtkTargetEntry));
1192 0 : listTarget->target = g_strdup(gTextUriListType);
1193 0 : listTarget->flags = 0;
1194 : /* Bug 331198 */
1195 0 : listTarget->info = NS_PTR_TO_UINT32(listAtom);
1196 0 : PR_LOG(sDragLm, PR_LOG_DEBUG,
1197 : ("automatically adding target %s with \
1198 : id %ld\n", listTarget->target, listAtom));
1199 0 : targetArray.AppendElement(listTarget);
1200 : }
1201 : }
1202 : } // foreach flavor in item
1203 : } // if valid flavor list
1204 : } // if item is a transferable
1205 0 : } else if (numDragItems == 1) {
1206 0 : nsCOMPtr<nsISupports> genericItem;
1207 0 : mSourceDataItems->GetElementAt(0, getter_AddRefs(genericItem));
1208 0 : nsCOMPtr<nsITransferable> currItem(do_QueryInterface(genericItem));
1209 0 : if (currItem) {
1210 0 : nsCOMPtr <nsISupportsArray> flavorList;
1211 0 : currItem->FlavorsTransferableCanExport(getter_AddRefs(flavorList));
1212 0 : if (flavorList) {
1213 : PRUint32 numFlavors;
1214 0 : flavorList->Count( &numFlavors );
1215 0 : for (PRUint32 flavorIndex = 0;
1216 : flavorIndex < numFlavors ;
1217 : ++flavorIndex ) {
1218 0 : nsCOMPtr<nsISupports> genericWrapper;
1219 0 : flavorList->GetElementAt(flavorIndex,
1220 0 : getter_AddRefs(genericWrapper));
1221 0 : nsCOMPtr<nsISupportsCString> currentFlavor;
1222 0 : currentFlavor = do_QueryInterface(genericWrapper);
1223 0 : if (currentFlavor) {
1224 0 : nsXPIDLCString flavorStr;
1225 0 : currentFlavor->ToString(getter_Copies(flavorStr));
1226 : // get the atom
1227 0 : GdkAtom atom = gdk_atom_intern(flavorStr, FALSE);
1228 : GtkTargetEntry *target =
1229 0 : (GtkTargetEntry *)g_malloc(sizeof(GtkTargetEntry));
1230 0 : target->target = g_strdup(flavorStr);
1231 0 : target->flags = 0;
1232 : /* Bug 331198 */
1233 0 : target->info = NS_PTR_TO_UINT32(atom);
1234 0 : PR_LOG(sDragLm, PR_LOG_DEBUG,
1235 : ("adding target %s with id %ld\n",
1236 : target->target, atom));
1237 0 : targetArray.AppendElement(target);
1238 : // Check to see if this is text/unicode.
1239 : // If it is, add text/plain
1240 : // since we automatically support text/plain
1241 : // if we support text/unicode.
1242 0 : if (strcmp(flavorStr, kUnicodeMime) == 0) {
1243 : // get the atom for the unicode string
1244 : GdkAtom plainUTF8Atom =
1245 0 : gdk_atom_intern(gTextPlainUTF8Type, FALSE);
1246 : GtkTargetEntry *plainUTF8Target =
1247 0 : (GtkTargetEntry *)g_malloc(sizeof(GtkTargetEntry));
1248 0 : plainUTF8Target->target = g_strdup(gTextPlainUTF8Type);
1249 0 : plainUTF8Target->flags = 0;
1250 : /* Bug 331198 */
1251 0 : plainUTF8Target->info = NS_PTR_TO_UINT32(plainUTF8Atom);
1252 0 : PR_LOG(sDragLm, PR_LOG_DEBUG,
1253 : ("automatically adding target %s with \
1254 : id %ld\n", plainUTF8Target->target, plainUTF8Atom));
1255 0 : targetArray.AppendElement(plainUTF8Target);
1256 :
1257 : // get the atom for the ASCII string
1258 : GdkAtom plainAtom =
1259 0 : gdk_atom_intern(kTextMime, FALSE);
1260 : GtkTargetEntry *plainTarget =
1261 0 : (GtkTargetEntry *)g_malloc(sizeof(GtkTargetEntry));
1262 0 : plainTarget->target = g_strdup(kTextMime);
1263 0 : plainTarget->flags = 0;
1264 : /* Bug 331198 */
1265 0 : plainTarget->info = NS_PTR_TO_UINT32(plainAtom);
1266 0 : PR_LOG(sDragLm, PR_LOG_DEBUG,
1267 : ("automatically adding target %s with \
1268 : id %ld\n", plainTarget->target, plainAtom));
1269 0 : targetArray.AppendElement(plainTarget);
1270 : }
1271 : // Check to see if this is the x-moz-url type.
1272 : // If it is, add _NETSCAPE_URL
1273 : // this is a type used by everybody.
1274 0 : if (strcmp(flavorStr, kURLMime) == 0) {
1275 : // get the atom name for it
1276 : GdkAtom urlAtom =
1277 0 : gdk_atom_intern(gMozUrlType, FALSE);
1278 : GtkTargetEntry *urlTarget =
1279 0 : (GtkTargetEntry *)g_malloc(sizeof(GtkTargetEntry));
1280 0 : urlTarget->target = g_strdup(gMozUrlType);
1281 0 : urlTarget->flags = 0;
1282 : /* Bug 331198 */
1283 0 : urlTarget->info = NS_PTR_TO_UINT32(urlAtom);
1284 0 : PR_LOG(sDragLm, PR_LOG_DEBUG,
1285 : ("automatically adding target %s with \
1286 : id %ld\n", urlTarget->target, urlAtom));
1287 0 : targetArray.AppendElement(urlTarget);
1288 : }
1289 : }
1290 : } // foreach flavor in item
1291 : } // if valid flavor list
1292 : } // if item is a transferable
1293 : } // if it is a single item drag
1294 :
1295 : // get all the elements that we created.
1296 0 : targetCount = targetArray.Length();
1297 0 : if (targetCount) {
1298 : // allocate space to create the list of valid targets
1299 : targets =
1300 0 : (GtkTargetEntry *)g_malloc(sizeof(GtkTargetEntry) * targetCount);
1301 : PRUint32 targetIndex;
1302 0 : for ( targetIndex = 0; targetIndex < targetCount; ++targetIndex) {
1303 0 : GtkTargetEntry *disEntry = targetArray.ElementAt(targetIndex);
1304 : // this is a string reference but it will be freed later.
1305 0 : targets[targetIndex].target = disEntry->target;
1306 0 : targets[targetIndex].flags = disEntry->flags;
1307 0 : targets[targetIndex].info = disEntry->info;
1308 : }
1309 0 : targetList = gtk_target_list_new(targets, targetCount);
1310 : // clean up the target list
1311 0 : for (PRUint32 cleanIndex = 0; cleanIndex < targetCount; ++cleanIndex) {
1312 0 : GtkTargetEntry *thisTarget = targetArray.ElementAt(cleanIndex);
1313 0 : g_free(thisTarget->target);
1314 0 : g_free(thisTarget);
1315 : }
1316 0 : g_free(targets);
1317 : }
1318 0 : return targetList;
1319 : }
1320 :
1321 : void
1322 0 : nsDragService::SourceEndDragSession(GdkDragContext *aContext,
1323 : gint aResult)
1324 : {
1325 : // this just releases the list of data items that we provide
1326 0 : mSourceDataItems = nsnull;
1327 :
1328 0 : if (!mDoingDrag)
1329 0 : return; // EndDragSession() was already called on drop or drag-failed
1330 :
1331 : gint x, y;
1332 0 : GdkDisplay* display = gdk_display_get_default();
1333 0 : if (display) {
1334 0 : gdk_display_get_pointer(display, NULL, &x, &y, NULL);
1335 0 : SetDragEndPoint(nsIntPoint(x, y));
1336 : }
1337 :
1338 : // Either the drag was aborted or the drop occurred outside the app.
1339 : // The dropEffect of mDataTransfer is not updated for motion outside the
1340 : // app, but is needed for the dragend event, so set it now.
1341 :
1342 : PRUint32 dropEffect;
1343 :
1344 0 : if (aResult == MOZ_GTK_DRAG_RESULT_SUCCESS) {
1345 :
1346 : // With GTK+ versions 2.10.x and prior the drag may have been
1347 : // cancelled (but no drag-failed signal would have been sent).
1348 : // aContext->dest_window will be non-NULL only if the drop was sent.
1349 : GdkDragAction action =
1350 0 : aContext->dest_window ? aContext->action : (GdkDragAction)0;
1351 :
1352 : // Only one bit of action should be set, but, just in case someone
1353 : // does something funny, erring away from MOVE, and not recording
1354 : // unusual action combinations as NONE.
1355 0 : if (!action)
1356 0 : dropEffect = DRAGDROP_ACTION_NONE;
1357 0 : else if (action & GDK_ACTION_COPY)
1358 0 : dropEffect = DRAGDROP_ACTION_COPY;
1359 0 : else if (action & GDK_ACTION_LINK)
1360 0 : dropEffect = DRAGDROP_ACTION_LINK;
1361 0 : else if (action & GDK_ACTION_MOVE)
1362 0 : dropEffect = DRAGDROP_ACTION_MOVE;
1363 : else
1364 0 : dropEffect = DRAGDROP_ACTION_COPY;
1365 :
1366 : } else {
1367 :
1368 0 : dropEffect = DRAGDROP_ACTION_NONE;
1369 :
1370 0 : if (aResult != MOZ_GTK_DRAG_RESULT_NO_TARGET) {
1371 0 : mUserCancelled = true;
1372 : }
1373 : }
1374 :
1375 0 : if (mDataTransfer) {
1376 0 : mDataTransfer->SetDropEffectInt(dropEffect);
1377 : }
1378 :
1379 : // Inform the drag session that we're ending the drag.
1380 0 : EndDragSession(true);
1381 : }
1382 :
1383 : static void
1384 0 : CreateUriList(nsISupportsArray *items, gchar **text, gint *length)
1385 : {
1386 : PRUint32 i, count;
1387 0 : GString *uriList = g_string_new(NULL);
1388 :
1389 0 : items->Count(&count);
1390 0 : for (i = 0; i < count; i++) {
1391 0 : nsCOMPtr<nsISupports> genericItem;
1392 0 : items->GetElementAt(i, getter_AddRefs(genericItem));
1393 0 : nsCOMPtr<nsITransferable> item;
1394 0 : item = do_QueryInterface(genericItem);
1395 :
1396 0 : if (item) {
1397 0 : PRUint32 tmpDataLen = 0;
1398 0 : void *tmpData = NULL;
1399 0 : nsresult rv = 0;
1400 0 : nsCOMPtr<nsISupports> data;
1401 0 : rv = item->GetTransferData(kURLMime,
1402 0 : getter_AddRefs(data),
1403 0 : &tmpDataLen);
1404 :
1405 0 : if (NS_SUCCEEDED(rv)) {
1406 : nsPrimitiveHelpers::CreateDataFromPrimitive(kURLMime,
1407 : data,
1408 : &tmpData,
1409 0 : tmpDataLen);
1410 0 : char* plainTextData = nsnull;
1411 : PRUnichar* castedUnicode = reinterpret_cast<PRUnichar*>
1412 0 : (tmpData);
1413 0 : PRInt32 plainTextLen = 0;
1414 : nsPrimitiveHelpers::ConvertUnicodeToPlatformPlainText(
1415 : castedUnicode,
1416 : tmpDataLen / 2,
1417 : &plainTextData,
1418 0 : &plainTextLen);
1419 0 : if (plainTextData) {
1420 : PRInt32 j;
1421 :
1422 : // text/x-moz-url is of form url + "\n" + title.
1423 : // We just want the url.
1424 0 : for (j = 0; j < plainTextLen; j++)
1425 0 : if (plainTextData[j] == '\n' ||
1426 0 : plainTextData[j] == '\r') {
1427 0 : plainTextData[j] = '\0';
1428 0 : break;
1429 : }
1430 0 : g_string_append(uriList, plainTextData);
1431 0 : g_string_append(uriList, "\r\n");
1432 : // this wasn't allocated with glib
1433 0 : free(plainTextData);
1434 : }
1435 0 : if (tmpData) {
1436 : // this wasn't allocated with glib
1437 0 : free(tmpData);
1438 : }
1439 : }
1440 : }
1441 : }
1442 0 : *text = uriList->str;
1443 0 : *length = uriList->len + 1;
1444 0 : g_string_free(uriList, FALSE); // don't free the data
1445 0 : }
1446 :
1447 :
1448 : void
1449 0 : nsDragService::SourceDataGet(GtkWidget *aWidget,
1450 : GdkDragContext *aContext,
1451 : GtkSelectionData *aSelectionData,
1452 : guint aInfo,
1453 : guint32 aTime)
1454 : {
1455 0 : PR_LOG(sDragLm, PR_LOG_DEBUG, ("nsDragService::SourceDataGet"));
1456 0 : GdkAtom atom = (GdkAtom)aInfo;
1457 0 : nsXPIDLCString mimeFlavor;
1458 0 : gchar *typeName = 0;
1459 0 : typeName = gdk_atom_name(atom);
1460 0 : if (!typeName) {
1461 0 : PR_LOG(sDragLm, PR_LOG_DEBUG, ("failed to get atom name.\n"));
1462 : return;
1463 : }
1464 :
1465 0 : PR_LOG(sDragLm, PR_LOG_DEBUG, ("Type is %s\n", typeName));
1466 : // make a copy since |nsXPIDLCString| won't use |g_free|...
1467 0 : mimeFlavor.Adopt(nsCRT::strdup(typeName));
1468 0 : g_free(typeName);
1469 : // check to make sure that we have data items to return.
1470 0 : if (!mSourceDataItems) {
1471 0 : PR_LOG(sDragLm, PR_LOG_DEBUG, ("Failed to get our data items\n"));
1472 : return;
1473 : }
1474 :
1475 0 : nsCOMPtr<nsISupports> genericItem;
1476 0 : mSourceDataItems->GetElementAt(0, getter_AddRefs(genericItem));
1477 0 : nsCOMPtr<nsITransferable> item;
1478 0 : item = do_QueryInterface(genericItem);
1479 0 : if (item) {
1480 : // if someone was asking for text/plain, lookup unicode instead so
1481 : // we can convert it.
1482 0 : bool needToDoConversionToPlainText = false;
1483 0 : const char* actualFlavor = mimeFlavor;
1484 0 : if (strcmp(mimeFlavor, kTextMime) == 0 ||
1485 0 : strcmp(mimeFlavor, gTextPlainUTF8Type) == 0) {
1486 0 : actualFlavor = kUnicodeMime;
1487 0 : needToDoConversionToPlainText = true;
1488 : }
1489 : // if someone was asking for _NETSCAPE_URL we need to convert to
1490 : // plain text but we also need to look for x-moz-url
1491 0 : else if (strcmp(mimeFlavor, gMozUrlType) == 0) {
1492 0 : actualFlavor = kURLMime;
1493 0 : needToDoConversionToPlainText = true;
1494 : }
1495 : // if someone was asking for text/uri-list we need to convert to
1496 : // plain text.
1497 0 : else if (strcmp(mimeFlavor, gTextUriListType) == 0) {
1498 0 : actualFlavor = gTextUriListType;
1499 0 : needToDoConversionToPlainText = true;
1500 : }
1501 : else
1502 0 : actualFlavor = mimeFlavor;
1503 :
1504 0 : PRUint32 tmpDataLen = 0;
1505 0 : void *tmpData = NULL;
1506 : nsresult rv;
1507 0 : nsCOMPtr<nsISupports> data;
1508 0 : rv = item->GetTransferData(actualFlavor,
1509 0 : getter_AddRefs(data),
1510 0 : &tmpDataLen);
1511 0 : if (NS_SUCCEEDED(rv)) {
1512 : nsPrimitiveHelpers::CreateDataFromPrimitive (actualFlavor, data,
1513 0 : &tmpData, tmpDataLen);
1514 : // if required, do the extra work to convert unicode to plain
1515 : // text and replace the output values with the plain text.
1516 0 : if (needToDoConversionToPlainText) {
1517 0 : char* plainTextData = nsnull;
1518 : PRUnichar* castedUnicode = reinterpret_cast<PRUnichar*>
1519 0 : (tmpData);
1520 0 : PRInt32 plainTextLen = 0;
1521 0 : if (strcmp(mimeFlavor, gTextPlainUTF8Type) == 0) {
1522 : plainTextData =
1523 : ToNewUTF8String(
1524 0 : nsDependentString(castedUnicode, tmpDataLen / 2),
1525 0 : (PRUint32*)&plainTextLen);
1526 : } else {
1527 : nsPrimitiveHelpers::ConvertUnicodeToPlatformPlainText(
1528 : castedUnicode,
1529 : tmpDataLen / 2,
1530 : &plainTextData,
1531 0 : &plainTextLen);
1532 : }
1533 0 : if (tmpData) {
1534 : // this was not allocated using glib
1535 0 : free(tmpData);
1536 0 : tmpData = plainTextData;
1537 0 : tmpDataLen = plainTextLen;
1538 : }
1539 : }
1540 0 : if (tmpData) {
1541 : // this copies the data
1542 : gtk_selection_data_set(aSelectionData,
1543 : aSelectionData->target,
1544 : 8,
1545 0 : (guchar *)tmpData, tmpDataLen);
1546 : // this wasn't allocated with glib
1547 0 : free(tmpData);
1548 : }
1549 : } else {
1550 0 : if (strcmp(mimeFlavor, gTextUriListType) == 0) {
1551 : // fall back for text/uri-list
1552 : gchar *uriList;
1553 : gint length;
1554 0 : CreateUriList(mSourceDataItems, &uriList, &length);
1555 : gtk_selection_data_set(aSelectionData,
1556 : aSelectionData->target,
1557 0 : 8, (guchar *)uriList, length);
1558 0 : g_free(uriList);
1559 : return;
1560 : }
1561 : }
1562 : }
1563 : }
1564 :
1565 0 : void nsDragService::SetDragIcon(GdkDragContext* aContext)
1566 : {
1567 0 : if (!mHasImage && !mSelection)
1568 0 : return;
1569 :
1570 0 : nsIntRect dragRect;
1571 : nsPresContext* pc;
1572 0 : nsRefPtr<gfxASurface> surface;
1573 : DrawDrag(mSourceNode, mSourceRegion, mScreenX, mScreenY,
1574 0 : &dragRect, getter_AddRefs(surface), &pc);
1575 0 : if (!pc)
1576 : return;
1577 :
1578 0 : PRInt32 sx = mScreenX, sy = mScreenY;
1579 0 : ConvertToUnscaledDevPixels(pc, &sx, &sy);
1580 :
1581 0 : PRInt32 offsetX = sx - dragRect.x;
1582 0 : PRInt32 offsetY = sy - dragRect.y;
1583 :
1584 : // If a popup is set as the drag image, use its widget. Otherwise, use
1585 : // the surface that DrawDrag created.
1586 0 : if (mDragPopup) {
1587 0 : GtkWidget* gtkWidget = nsnull;
1588 0 : nsIFrame* frame = mDragPopup->GetPrimaryFrame();
1589 0 : if (frame) {
1590 : // DrawDrag ensured that this is a popup frame.
1591 0 : nsCOMPtr<nsIWidget> widget = frame->GetNearestWidget();
1592 0 : if (widget) {
1593 0 : gtkWidget = (GtkWidget *)widget->GetNativeData(NS_NATIVE_SHELLWIDGET);
1594 0 : if (gtkWidget) {
1595 0 : OpenDragPopup();
1596 0 : gtk_drag_set_icon_widget(aContext, gtkWidget, offsetX, offsetY);
1597 : }
1598 : }
1599 : }
1600 : }
1601 0 : else if (surface) {
1602 0 : if (!SetAlphaPixmap(surface, aContext, offsetX, offsetY, dragRect)) {
1603 : GdkPixbuf* dragPixbuf =
1604 0 : nsImageToPixbuf::SurfaceToPixbuf(surface, dragRect.width, dragRect.height);
1605 0 : if (dragPixbuf) {
1606 0 : gtk_drag_set_icon_pixbuf(aContext, dragPixbuf, offsetX, offsetY);
1607 0 : g_object_unref(dragPixbuf);
1608 : }
1609 : }
1610 : }
1611 : }
1612 :
1613 : static void
1614 0 : invisibleSourceDragBegin(GtkWidget *aWidget,
1615 : GdkDragContext *aContext,
1616 : gpointer aData)
1617 : {
1618 0 : PR_LOG(sDragLm, PR_LOG_DEBUG, ("invisibleSourceDragBegin"));
1619 0 : nsDragService *dragService = (nsDragService *)aData;
1620 :
1621 0 : dragService->SetDragIcon(aContext);
1622 0 : }
1623 :
1624 : static void
1625 0 : invisibleSourceDragDataGet(GtkWidget *aWidget,
1626 : GdkDragContext *aContext,
1627 : GtkSelectionData *aSelectionData,
1628 : guint aInfo,
1629 : guint32 aTime,
1630 : gpointer aData)
1631 : {
1632 0 : PR_LOG(sDragLm, PR_LOG_DEBUG, ("invisibleSourceDragDataGet"));
1633 0 : nsDragService *dragService = (nsDragService *)aData;
1634 : dragService->SourceDataGet(aWidget, aContext,
1635 0 : aSelectionData, aInfo, aTime);
1636 0 : }
1637 :
1638 : static gboolean
1639 0 : invisibleSourceDragFailed(GtkWidget *aWidget,
1640 : GdkDragContext *aContext,
1641 : gint aResult,
1642 : gpointer aData)
1643 : {
1644 0 : PR_LOG(sDragLm, PR_LOG_DEBUG, ("invisibleSourceDragFailed %i", aResult));
1645 0 : nsDragService *dragService = (nsDragService *)aData;
1646 : // End the drag session now (rather than waiting for the drag-end signal)
1647 : // so that operations performed on dropEffect == none can start immediately
1648 : // rather than waiting for the drag-failed animation to finish.
1649 0 : dragService->SourceEndDragSession(aContext, aResult);
1650 :
1651 : // We should return TRUE to disable the drag-failed animation iff the
1652 : // source performed an operation when dropEffect was none, but the handler
1653 : // of the dragend DOM event doesn't provide this information.
1654 0 : return FALSE;
1655 : }
1656 :
1657 : static void
1658 0 : invisibleSourceDragEnd(GtkWidget *aWidget,
1659 : GdkDragContext *aContext,
1660 : gpointer aData)
1661 : {
1662 0 : PR_LOG(sDragLm, PR_LOG_DEBUG, ("invisibleSourceDragEnd"));
1663 0 : nsDragService *dragService = (nsDragService *)aData;
1664 :
1665 : // The drag has ended. Release the hostages!
1666 0 : dragService->SourceEndDragSession(aContext, MOZ_GTK_DRAG_RESULT_SUCCESS);
1667 0 : }
1668 :
|