LCOV - code coverage report
Current view: directory - widget/gtk2 - nsDragService.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 763 0 0.0 %
Date: 2012-06-02 Functions: 41 0 0.0 %

       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                 : 

Generated by: LCOV version 1.7