Back to index

lightning-sunbird  0.9+nobinonly
nsDragService.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
00002  *
00003  * ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is mozilla.org code.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Christopher Blizzard <blizzard@mozilla.org>.
00020  * Portions created by the Initial Developer are Copyright (C) 1998
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Christopher Blizzard <blizzard@mozilla.org>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either the GNU General Public License Version 2 or later (the "GPL"), or
00028  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 #include "nsDragService.h"
00041 #include "nsWidgetsCID.h"
00042 #include "nsIServiceManager.h"
00043 #include "nsXPCOM.h"
00044 #include "nsISupportsPrimitives.h"
00045 #include "nsIObserverService.h"
00046 #include "prlog.h"
00047 #include "nsVoidArray.h"
00048 #include "nsXPIDLString.h"
00049 #include "nsPrimitiveHelpers.h"
00050 #include "nsWidget.h"
00051 #include <gtk/gtkinvisible.h>
00052 #include <gdk/gdkx.h>
00053 #include "nsCRT.h"
00054 
00055 
00056 #ifdef PR_LOGGING
00057 static PRLogModuleInfo *sDragLm = NULL;
00058 #endif
00059 
00060 static const char gMimeListType[] = "application/x-moz-internal-item-list";
00061 static const char gMozUrlType[] = "_NETSCAPE_URL";
00062 static const char gTextUriListType[] = "text/uri-list";
00063 
00064 NS_IMPL_ADDREF_INHERITED(nsDragService, nsBaseDragService)
00065 NS_IMPL_RELEASE_INHERITED(nsDragService, nsBaseDragService)
00066 NS_IMPL_QUERY_INTERFACE5(nsDragService,
00067                          nsIDragService,
00068                          nsIDragService_1_8_BRANCH,
00069                          nsIDragSession,
00070                          nsIDragSessionGTK,
00071                          nsIObserver)
00072 
00073 static void
00074 invisibleSourceDragEnd     (GtkWidget        *aWidget,
00075                             GdkDragContext   *aContext,
00076                             gpointer          aData);
00077 
00078 static void
00079 invisibleSourceDragDataGet (GtkWidget        *aWidget,
00080                             GdkDragContext   *aContext,
00081                             GtkSelectionData *aSelectionData,
00082                             guint             aInfo,
00083                             guint32           aTime,
00084                             gpointer          aData);
00085 
00086 nsDragService::nsDragService()
00087 {
00088   // We have to destroy the hidden widget before the event loop stops running.
00089   nsCOMPtr<nsIObserverService> obsServ =
00090     do_GetService("@mozilla.org/observer-service;1");
00091   obsServ->AddObserver(this, "quit-application", PR_FALSE);
00092 
00093   // our hidden source widget
00094   mHiddenWidget = gtk_invisible_new();
00095   // make sure that the widget is realized so that
00096   // we can use it as a drag source.
00097   gtk_widget_realize(mHiddenWidget);
00098   // hook up our internal signals so that we can get some feedback
00099   // from our drag source
00100   gtk_signal_connect(GTK_OBJECT(mHiddenWidget), "drag_data_get",
00101                      GTK_SIGNAL_FUNC(invisibleSourceDragDataGet), this);
00102   gtk_signal_connect(GTK_OBJECT(mHiddenWidget), "drag_end",
00103                      GTK_SIGNAL_FUNC(invisibleSourceDragEnd), this);
00104 
00105   // set up our logging module
00106 #ifdef PR_LOGGING
00107   if (!sDragLm)
00108     sDragLm = PR_NewLogModule("nsDragService");
00109 #endif
00110   PR_LOG(sDragLm, PR_LOG_DEBUG, ("nsDragService::nsDragService"));
00111   mTargetWidget = 0;
00112   mTargetDragContext = 0;
00113   mTargetTime = 0;
00114   mCanDrop = PR_FALSE;
00115   mTimeCB = 0;
00116   mTargetDragDataReceived = PR_FALSE;
00117   mTargetDragData = 0;
00118   mTargetDragDataLen = 0;
00119 }
00120 
00121 nsDragService::~nsDragService()
00122 {
00123   PR_LOG(sDragLm, PR_LOG_DEBUG, ("nsDragService::~nsDragService"));
00124 }
00125 
00126 // nsIObserver
00127 
00128 NS_IMETHODIMP
00129 nsDragService::Observe(nsISupports *aSubject, const char *aTopic,
00130                        const PRUnichar *aData)
00131 {
00132   if (!nsCRT::strcmp(aTopic, "quit-application")) {
00133     PR_LOG(sDragLm, PR_LOG_DEBUG,
00134            ("nsDragService::Observe(\"quit-application\")"));
00135     gtk_widget_unref(mHiddenWidget);
00136     TargetResetData();
00137   } else {
00138     NS_NOTREACHED("unexpected topic");
00139     return NS_ERROR_UNEXPECTED;
00140   }
00141 
00142   return NS_OK;
00143 }
00144 
00145 // nsIDragService
00146 
00147 NS_IMETHODIMP
00148 nsDragService::InvokeDragSession (nsIDOMNode *aDOMNode,
00149                                   nsISupportsArray * aArrayTransferables,
00150                                   nsIScriptableRegion * aRegion,
00151                                   PRUint32 aActionType)
00152 {
00153   PR_LOG(sDragLm, PR_LOG_DEBUG, ("nsDragService::InvokeDragSession"));
00154   nsresult rv = nsBaseDragService::InvokeDragSession(aDOMNode,
00155                                                      aArrayTransferables,
00156                                                      aRegion, aActionType);
00157   NS_ENSURE_SUCCESS(rv, rv);
00158 
00159   // make sure that we have an array of transferables to use
00160   if (!aArrayTransferables)
00161     return NS_ERROR_INVALID_ARG;
00162   // set our reference to the transferables.  this will also addref
00163   // the transferables since we're going to hang onto this beyond the
00164   // length of this call
00165   mSourceDataItems = aArrayTransferables;
00166   // get the list of items we offer for drags
00167   GtkTargetList *sourceList = 0;
00168 
00169   sourceList = GetSourceList();
00170 
00171   if (sourceList) {
00172     // get the last time event.  we do this because if we don't then
00173     // gdk_drag_begin() will use the current time as the arg for the
00174     // grab.  if you happen to do a drag really quickly and release
00175     // the mouse button before the drag begins ( really easy to do, by
00176     // the way ) then the server ungrab from the mouse button release
00177     // will actually have a time that is _before_ the server grab that
00178     // we are about to cause and it will leave the server in a grabbed
00179     // state after the drag has ended.
00180     guint32 lastTime = 0;
00181     mTimeCB(&lastTime);
00182     // synth an event so that that fun bug in the gtk dnd code doesn't
00183     // rear its ugly head
00184     GdkEvent gdk_event;
00185     gdk_event.type = GDK_BUTTON_PRESS;
00186     gdk_event.button.window = mHiddenWidget->window;
00187     gdk_event.button.send_event = 0;
00188     gdk_event.button.time = lastTime;
00189     gdk_event.button.x = 0;
00190     gdk_event.button.y = 0;
00191     gdk_event.button.pressure = 0;
00192     gdk_event.button.xtilt = 0;
00193     gdk_event.button.ytilt = 0;
00194     gdk_event.button.state = 0;
00195     gdk_event.button.button = 0;
00196     gdk_event.button.source = (GdkInputSource)0;
00197     gdk_event.button.deviceid = 0;
00198     gdk_event.button.x_root = 0;
00199     gdk_event.button.y_root = 0;
00200 
00201     // before we start our drag, give the widget code a chance to
00202     // clean up any state.
00203     nsWidget::DragStarted();
00204 
00205     // save our action type
00206     GdkDragAction action = GDK_ACTION_DEFAULT;
00207 
00208     if (aActionType & DRAGDROP_ACTION_COPY)
00209       action = (GdkDragAction)(action | GDK_ACTION_COPY);
00210     if (aActionType & DRAGDROP_ACTION_MOVE)
00211       action = (GdkDragAction)(action | GDK_ACTION_MOVE);
00212     if (aActionType & DRAGDROP_ACTION_LINK)
00213       action = (GdkDragAction)(action | GDK_ACTION_LINK);
00214 
00215     // start our drag.
00216     GdkDragContext *context = gtk_drag_begin(mHiddenWidget,
00217                                              sourceList,
00218                                              action,
00219                                              1,
00220                                              &gdk_event);
00221     // make sure to set our default icon
00222     gtk_drag_set_icon_default (context);
00223     gtk_target_list_unref(sourceList);
00224   }
00225 
00226   return NS_OK;
00227 }
00228 
00229 NS_IMETHODIMP
00230 nsDragService::StartDragSession()
00231 {
00232   PR_LOG(sDragLm, PR_LOG_DEBUG, ("nsDragService::StartDragSession"));
00233   return nsBaseDragService::StartDragSession();
00234 }
00235  
00236 NS_IMETHODIMP
00237 nsDragService::EndDragSession()
00238 {
00239   PR_LOG(sDragLm, PR_LOG_DEBUG, ("nsDragService::EndDragSession"));
00240   // unset our drag action
00241   SetDragAction(DRAGDROP_ACTION_NONE);
00242   return nsBaseDragService::EndDragSession();
00243 }
00244 
00245 // nsIDragSession
00246 NS_IMETHODIMP
00247 nsDragService::SetCanDrop            (PRBool           aCanDrop)
00248 {
00249   PR_LOG(sDragLm, PR_LOG_DEBUG, ("nsDragService::SetCanDrop %d",
00250                                  aCanDrop));
00251   mCanDrop = aCanDrop;
00252   return NS_OK;
00253 }
00254 
00255 NS_IMETHODIMP
00256 nsDragService::GetCanDrop            (PRBool          *aCanDrop)
00257 {
00258   PR_LOG(sDragLm, PR_LOG_DEBUG, ("nsDragService::GetCanDrop"));
00259   *aCanDrop = mCanDrop;
00260   return NS_OK;
00261 }
00262 
00263 // count the number of URIs in some text/uri-list format data.
00264 static PRUint32
00265 CountTextUriListItems (const char *data,
00266                        PRUint32 datalen)
00267 {
00268   const char *p = data;
00269   const char *endPtr = p + datalen;
00270   PRUint32 count = 0;
00271 
00272   while (p < endPtr) {
00273     // skip whitespace (if any)
00274     while (p < endPtr && *p != '\0' && isspace(*p))
00275       p++;
00276 
00277     // if we aren't at the end of the line ...
00278     if (p != endPtr && *p != '\0' && *p != '\n' && *p != '\r')
00279       count++;
00280 
00281     // skip to the end of the line
00282     while (p < endPtr && *p != '\0' && *p != '\n')
00283       p++;
00284     p++; // skip the actual newline as well.
00285   }
00286   return count;
00287 }
00288 
00289 // extract an item from text/uri-list formatted data and convert it to
00290 // unicode.
00291 static void
00292 GetTextUriListItem(const char *data,
00293                    PRUint32 datalen,
00294                    PRUint32 aItemIndex,
00295                    PRUnichar **convertedText,
00296                    PRInt32 *convertedTextLen)
00297 {
00298   const char *p = data;
00299   const char *endPtr = p + datalen;
00300   unsigned int count = 0;
00301 
00302   *convertedText = nsnull;
00303   while (p < endPtr) {
00304     // skip whitespace (if any)
00305     while (p < endPtr && *p != '\0' && isspace(*p))
00306       p++;
00307 
00308     // if we aren't at the end of the line, we have a url
00309     if (p != endPtr && *p != '\0' && *p != '\n' && *p != '\r')
00310       count++;
00311 
00312     // this is the item we are after ...
00313     if (aItemIndex + 1 == count) {
00314       const char *q = p;
00315 
00316       while (q < endPtr && *q != '\0' && *q != '\n' && *q != '\r')
00317         q++;
00318 
00319       nsPrimitiveHelpers::ConvertPlatformPlainTextToUnicode(p,
00320                                                             q - p, 
00321                                                             convertedText,
00322                                                             convertedTextLen);
00323       break;
00324     }
00325 
00326     // skip to the end of the line
00327     while (p < endPtr && *p != '\0' && *p != '\n')
00328       p++;
00329     p++; // skip the actual newline as well.
00330   }
00331 
00332   // didn't find the desired item, so just pass the whole lot
00333   if (!*convertedText) {
00334     nsPrimitiveHelpers::ConvertPlatformPlainTextToUnicode(data,
00335                                                           datalen,
00336                                                           convertedText,
00337                                                           convertedTextLen);
00338   }
00339 }
00340 
00341 NS_IMETHODIMP
00342 nsDragService::GetNumDropItems       (PRUint32 * aNumItems)
00343 {
00344   PR_LOG(sDragLm, PR_LOG_DEBUG, ("nsDragService::GetNumDropItems"));
00345   PRBool isList = IsTargetContextList();
00346   if (isList)
00347     mSourceDataItems->Count(aNumItems);
00348   else {
00349     GdkAtom gdkFlavor = gdk_atom_intern(gTextUriListType, FALSE);
00350     GetTargetDragData(gdkFlavor);
00351     if (mTargetDragData) {
00352       const char *data = NS_REINTERPRET_CAST(char*, mTargetDragData);
00353 
00354       *aNumItems = CountTextUriListItems(data, mTargetDragDataLen);
00355     } else
00356       *aNumItems = 1;
00357   }
00358   PR_LOG(sDragLm, PR_LOG_DEBUG, ("%d items", *aNumItems));
00359   return NS_OK;
00360 }
00361 
00362 
00363 NS_IMETHODIMP
00364 nsDragService::GetData               (nsITransferable * aTransferable,
00365                                       PRUint32 aItemIndex)
00366 {
00367   PR_LOG(sDragLm, PR_LOG_DEBUG, ("nsDragService::GetData %d", aItemIndex));
00368 
00369   // make sure that we have a transferable
00370   if (!aTransferable)
00371     return NS_ERROR_INVALID_ARG;
00372 
00373   // get flavor list that includes all acceptable flavors (including
00374   // ones obtained through conversion). Flavors are nsISupportsCStrings
00375   // so that they can be seen from JS.
00376   nsresult rv = NS_ERROR_FAILURE;
00377   nsCOMPtr<nsISupportsArray> flavorList;
00378   rv = aTransferable->FlavorsTransferableCanImport(getter_AddRefs(flavorList));
00379   if (NS_FAILED(rv))
00380     return rv;
00381 
00382   // count the number of flavors
00383   PRUint32 cnt;
00384   flavorList->Count (&cnt);
00385   unsigned int i;
00386 
00387   // check to see if this is an internal list
00388   PRBool isList = IsTargetContextList();
00389 
00390   if (isList) {
00391     PR_LOG(sDragLm, PR_LOG_DEBUG, ("it's a list..."));
00392     nsCOMPtr<nsISupports> genericWrapper;
00393     // there is always one element if it's a list
00394     flavorList->GetElementAt(0, getter_AddRefs(genericWrapper));
00395     nsCOMPtr<nsISupportsCString> currentFlavor;
00396     currentFlavor = do_QueryInterface(genericWrapper);
00397     if (currentFlavor) {
00398       nsXPIDLCString flavorStr;
00399       currentFlavor->ToString(getter_Copies(flavorStr));
00400       PR_LOG(sDragLm, PR_LOG_DEBUG, ("flavor is %s\n", (const char *)flavorStr));
00401       // get the item with the right index
00402       nsCOMPtr<nsISupports> genericItem;
00403       mSourceDataItems->GetElementAt(aItemIndex, getter_AddRefs(genericItem));
00404       nsCOMPtr<nsITransferable> item (do_QueryInterface(genericItem));
00405       if (item) {
00406         nsCOMPtr<nsISupports> data;
00407         PRUint32 tmpDataLen = 0;
00408         PR_LOG(sDragLm, PR_LOG_DEBUG, ("trying to get transfer data for %s\n",
00409                                        (const char *)flavorStr));
00410         rv = item->GetTransferData(flavorStr, getter_AddRefs(data), &tmpDataLen);
00411         if (NS_FAILED(rv)) {
00412           PR_LOG(sDragLm, PR_LOG_DEBUG, ("failed.\n"));
00413           return NS_ERROR_FAILURE;
00414         }
00415         PR_LOG(sDragLm, PR_LOG_DEBUG, ("succeeded.\n"));
00416         rv = aTransferable->SetTransferData(flavorStr, data, tmpDataLen);
00417         if (NS_FAILED(rv)) {
00418           PR_LOG(sDragLm, PR_LOG_DEBUG, ("failed to set transfer data into transferable!\n"));
00419           return NS_ERROR_FAILURE;
00420         }
00421         // ok, we got the data
00422         return NS_OK;
00423       }
00424     }
00425     // if we got this far, we failed
00426     return NS_ERROR_FAILURE;
00427   }
00428 
00429   // Now walk down the list of flavors. When we find one that is
00430   // actually present, copy out the data into the transferable in that
00431   // format. SetTransferData() implicitly handles conversions.
00432   for ( i = 0; i < cnt; ++i ) {
00433     nsCOMPtr<nsISupports> genericWrapper;
00434     flavorList->GetElementAt(i,getter_AddRefs(genericWrapper));
00435     nsCOMPtr<nsISupportsCString> currentFlavor;
00436     currentFlavor = do_QueryInterface(genericWrapper);
00437     if (currentFlavor) {
00438       // find our gtk flavor
00439       nsXPIDLCString flavorStr;
00440       currentFlavor->ToString ( getter_Copies(flavorStr) );
00441       GdkAtom gdkFlavor = gdk_atom_intern(flavorStr, FALSE);
00442       PR_LOG(sDragLm, PR_LOG_DEBUG, ("looking for data in type %s, gdk flavor %ld\n",
00443                                      NS_STATIC_CAST(const char*,flavorStr), gdkFlavor));
00444       PRBool dataFound = PR_FALSE;
00445       if (gdkFlavor) {
00446         GetTargetDragData(gdkFlavor);
00447       }
00448       if (mTargetDragData) {
00449         PR_LOG(sDragLm, PR_LOG_DEBUG, ("dataFound = PR_TRUE\n"));
00450         dataFound = PR_TRUE;
00451       }
00452       else {
00453         PR_LOG(sDragLm, PR_LOG_DEBUG, ("dataFound = PR_FALSE\n"));
00454         // if we are looking for text/unicode and we fail to find it
00455         // on the clipboard first, try again with text/plain. If that
00456         // is present, convert it to unicode.
00457         if ( strcmp(flavorStr, kUnicodeMime) == 0 ) {
00458           PR_LOG(sDragLm, PR_LOG_DEBUG, ("we were looking for text/unicode...trying again with text/plain\n"));
00459           gdkFlavor = gdk_atom_intern(kTextMime, FALSE);
00460           GetTargetDragData(gdkFlavor);
00461           if (mTargetDragData) {
00462             PR_LOG(sDragLm, PR_LOG_DEBUG, ("Got text/plain data\n"));
00463             const char* castedText = NS_REINTERPRET_CAST(char*, mTargetDragData);
00464             PRUnichar* convertedText = nsnull;
00465             PRInt32 convertedTextLen = 0;
00466             nsPrimitiveHelpers::ConvertPlatformPlainTextToUnicode(castedText,
00467                                                                   mTargetDragDataLen,
00468                                                                   &convertedText,
00469                                                                   &convertedTextLen);
00470             if ( convertedText ) {
00471               PR_LOG(sDragLm, PR_LOG_DEBUG, ("successfully converted plain text to unicode.\n"));
00472               // out with the old, in with the new 
00473               g_free(mTargetDragData);
00474               mTargetDragData = convertedText;
00475               mTargetDragDataLen = convertedTextLen * 2;
00476               dataFound = PR_TRUE;
00477             } // if plain text data on clipboard
00478           } // if plain text flavor present
00479         } // if looking for text/unicode   
00480 
00481         // if we are looking for text/x-moz-url and we failed to find
00482         // it on the clipboard, try again with text/uri-list, and then
00483         // _NETSCAPE_URL
00484         if (strcmp(flavorStr, kURLMime) == 0) {
00485           PR_LOG(sDragLm, PR_LOG_DEBUG,
00486                  ("we were looking for text/x-moz-url...trying again with text/uri-list\n"));
00487           gdkFlavor = gdk_atom_intern(gTextUriListType, FALSE);
00488           GetTargetDragData(gdkFlavor);
00489           if (mTargetDragData) {
00490             PR_LOG(sDragLm, PR_LOG_DEBUG, ("Got text/uri-list data\n"));
00491             const char *data = NS_REINTERPRET_CAST(char*, mTargetDragData);
00492             PRUnichar* convertedText = nsnull;
00493             PRInt32 convertedTextLen = 0;
00494 
00495             GetTextUriListItem(data, mTargetDragDataLen, aItemIndex,
00496                                &convertedText, &convertedTextLen);
00497 
00498             if ( convertedText ) {
00499               PR_LOG(sDragLm, PR_LOG_DEBUG,
00500                      ("successfully converted _NETSCAPE_URL to unicode.\n"));
00501               // out with the old, in with the new 
00502               g_free(mTargetDragData);
00503               mTargetDragData = convertedText;
00504               mTargetDragDataLen = convertedTextLen * 2;
00505               dataFound = PR_TRUE;
00506             }
00507           }
00508           else {
00509             PR_LOG(sDragLm, PR_LOG_DEBUG, ("failed to get text/uri-list data\n"));
00510           }
00511           if (!dataFound) {
00512             PR_LOG(sDragLm, PR_LOG_DEBUG,
00513                    ("we were looking for text/x-moz-url...trying again with _NETSCAP_URL\n"));
00514             gdkFlavor = gdk_atom_intern(gMozUrlType, FALSE);
00515             GetTargetDragData(gdkFlavor);
00516             if (mTargetDragData) {
00517               PR_LOG(sDragLm, PR_LOG_DEBUG, ("Got _NETSCAPE_URL data\n"));
00518               const char* castedText = NS_REINTERPRET_CAST(char*, mTargetDragData);
00519               PRUnichar* convertedText = nsnull;
00520               PRInt32 convertedTextLen = 0;
00521               nsPrimitiveHelpers::ConvertPlatformPlainTextToUnicode(castedText,
00522                                                                     mTargetDragDataLen, 
00523                                                                     &convertedText,
00524                                                                     &convertedTextLen);
00525               if ( convertedText ) {
00526                 PR_LOG(sDragLm, PR_LOG_DEBUG,
00527                        ("successfully converted _NETSCAPE_URL to unicode.\n"));
00528                 // out with the old, in with the new 
00529                 g_free(mTargetDragData);
00530                 mTargetDragData = convertedText;
00531                 mTargetDragDataLen = convertedTextLen * 2;
00532                 dataFound = PR_TRUE;
00533               }
00534             }
00535             else {
00536               PR_LOG(sDragLm, PR_LOG_DEBUG, ("failed to get _NETSCAPE_URL data\n"));
00537             }
00538           }
00539         }
00540 
00541       } // else we try one last ditch effort to find our data
00542 
00543       if (dataFound) {
00544         // the DOM only wants LF, so convert from MacOS line endings
00545         // to DOM line endings.
00546         nsLinebreakHelpers::ConvertPlatformToDOMLinebreaks(flavorStr,
00547                                                            &mTargetDragData,
00548                                                            NS_REINTERPRET_CAST(int*,
00549                                                                                &mTargetDragDataLen));
00550         
00551         // put it into the transferable.
00552         nsCOMPtr<nsISupports> genericDataWrapper;
00553         nsPrimitiveHelpers::CreatePrimitiveForData(flavorStr, mTargetDragData,
00554                                                    mTargetDragDataLen, 
00555                                                    getter_AddRefs(genericDataWrapper));
00556         aTransferable->SetTransferData(flavorStr, genericDataWrapper, mTargetDragDataLen);
00557         // we found one, get out of this loop!
00558         PR_LOG(sDragLm, PR_LOG_DEBUG, ("dataFound and converted!\n"));
00559         break;
00560       } 
00561     }
00562   } // foreach flavor
00563 
00564   return NS_OK;
00565   
00566 }
00567 
00568 NS_IMETHODIMP
00569 nsDragService::IsDataFlavorSupported (const char *aDataFlavor,
00570                                       PRBool *_retval)
00571 {
00572   PR_LOG(sDragLm, PR_LOG_DEBUG, ("nsDragService::IsDataFlavorSupported %s", 
00573                                  aDataFlavor));
00574   if (!_retval)
00575     return NS_ERROR_INVALID_ARG;
00576 
00577   // set this to no by default
00578   *_retval = PR_FALSE;
00579 
00580   // check to make sure that we have a drag object set, here
00581   if (!mTargetDragContext) {
00582     PR_LOG(sDragLm, PR_LOG_DEBUG, ("*** warning: IsDataFlavorSupported called without a valid drag context!\n"));
00583     return NS_OK;
00584   }
00585 
00586   // check to see if the target context is a list.
00587   PRBool isList = IsTargetContextList();
00588   // if it is, just look in the internal data since we are the source
00589   // for it.
00590   if (isList) {
00591     PR_LOG(sDragLm, PR_LOG_DEBUG, ("It's a list.."));
00592     PRUint32 numDragItems = 0;
00593     // if we don't have mDataItems we didn't start this drag so it's
00594     // an external client trying to fool us.
00595     if (!mSourceDataItems)
00596       return NS_OK;
00597     mSourceDataItems->Count(&numDragItems);
00598     for (PRUint32 itemIndex = 0; itemIndex < numDragItems; ++itemIndex) {
00599       nsCOMPtr<nsISupports> genericItem;
00600       mSourceDataItems->GetElementAt(itemIndex, getter_AddRefs(genericItem));
00601       nsCOMPtr<nsITransferable> currItem (do_QueryInterface(genericItem));
00602       if (currItem) {
00603         nsCOMPtr <nsISupportsArray> flavorList;
00604         currItem->FlavorsTransferableCanExport(getter_AddRefs(flavorList));
00605         if (flavorList) {
00606           PRUint32 numFlavors;
00607           flavorList->Count( &numFlavors );
00608           for ( PRUint32 flavorIndex = 0; flavorIndex < numFlavors ; ++flavorIndex ) {
00609             nsCOMPtr<nsISupports> genericWrapper;
00610             flavorList->GetElementAt (flavorIndex, getter_AddRefs(genericWrapper));
00611             nsCOMPtr<nsISupportsCString> currentFlavor;
00612             currentFlavor = do_QueryInterface(genericWrapper);
00613             if (currentFlavor) {
00614               nsXPIDLCString flavorStr;
00615               currentFlavor->ToString ( getter_Copies(flavorStr) );
00616               PR_LOG(sDragLm, PR_LOG_DEBUG, ("checking %s against %s\n", 
00617                                              (const char *)flavorStr, aDataFlavor));
00618               if (strcmp(flavorStr, aDataFlavor) == 0) {
00619                 PR_LOG(sDragLm, PR_LOG_DEBUG, ("boioioioiooioioioing!\n"));
00620                 *_retval = PR_TRUE;
00621               }
00622             }
00623           }
00624         }
00625       }
00626     }
00627     return NS_OK;
00628   }
00629 
00630   // check the target context vs. this flavor, one at a time
00631   GList *tmp;
00632   for (tmp = mTargetDragContext->targets; tmp; tmp = tmp->next) {
00633     GdkAtom atom = GPOINTER_TO_INT(tmp->data);
00634     gchar *name = NULL;
00635     name = gdk_atom_name(atom);
00636     PR_LOG(sDragLm, PR_LOG_DEBUG, ("checking %s against %s\n", name, aDataFlavor));
00637     if (name && (strcmp(name, aDataFlavor) == 0)) {
00638       PR_LOG(sDragLm, PR_LOG_DEBUG, ("good!\n"));
00639       *_retval = PR_TRUE;
00640     }
00641     // check for automatic text/uri-list -> text/x-moz-url mapping
00642     if (*_retval == PR_FALSE && name && (strcmp(name, gTextUriListType) == 0) &&
00643         (strcmp(aDataFlavor, kURLMime) == 0)) {
00644       PR_LOG(sDragLm, PR_LOG_DEBUG, ("good! ( it's text/uri-list and we're checking against text/x-moz-url )\n"));
00645       *_retval = PR_TRUE;
00646     }
00647     // check for automatic _NETSCAPE_URL -> text/x-moz-url mapping
00648     if (*_retval == PR_FALSE && name && (strcmp(name, gMozUrlType) == 0) &&
00649         (strcmp(aDataFlavor, kURLMime) == 0)) {
00650       PR_LOG(sDragLm, PR_LOG_DEBUG, ("good! ( it's _NETSCAPE_URL and we're checking against text/x-moz-url )\n"));
00651       *_retval = PR_TRUE;
00652     }
00653     // check for auto text/plain -> text/unicode mapping
00654     if (*_retval == PR_FALSE && name && (strcmp(name, kTextMime) == 0) &&
00655         (strcmp(aDataFlavor, kUnicodeMime) == 0)) {
00656       PR_LOG(sDragLm, PR_LOG_DEBUG, ("good! ( it's text plain and we're checking against text/unicode )\n"));
00657       *_retval = PR_TRUE;
00658     }
00659     g_free(name);
00660   }
00661   return NS_OK;
00662 }
00663 
00664 // nsIDragSessionGTK
00665 
00666 NS_IMETHODIMP
00667 nsDragService::TargetSetLastContext  (GtkWidget      *aWidget,
00668                                       GdkDragContext *aContext,
00669                                       guint           aTime)
00670 {
00671   PR_LOG(sDragLm, PR_LOG_DEBUG, ("nsDragService::TargetSetLastContext"));
00672   mTargetWidget = aWidget;
00673   mTargetDragContext = aContext;
00674   mTargetTime = aTime;
00675   return NS_OK;
00676 }
00677 
00678 NS_IMETHODIMP
00679 nsDragService::TargetStartDragMotion (void)
00680 {
00681   PR_LOG(sDragLm, PR_LOG_DEBUG, ("nsDragService::TargetStartDragMotion"));
00682   mCanDrop = PR_FALSE;
00683   return NS_OK;
00684 }
00685 
00686 NS_IMETHODIMP
00687 nsDragService::TargetEndDragMotion   (GtkWidget      *aWidget,
00688                                       GdkDragContext *aContext,
00689                                       guint           aTime)
00690 {
00691   PR_LOG(sDragLm, PR_LOG_DEBUG, ("nsDragService::TargetEndDragMotion %d", mCanDrop));
00692 
00693   if (mCanDrop) {
00694     GdkDragAction action;
00695     // notify the dragger if we can drop
00696     switch (mDragAction) {
00697     case DRAGDROP_ACTION_COPY:
00698       action = GDK_ACTION_COPY;
00699       break;
00700     case DRAGDROP_ACTION_LINK:
00701       action = GDK_ACTION_LINK;
00702       break;
00703     default:
00704       action = GDK_ACTION_MOVE;
00705       break;
00706     }
00707     gdk_drag_status(aContext, action, aTime);
00708   }
00709   else {
00710     gdk_drag_status(aContext, (GdkDragAction)0, aTime);
00711   }
00712 
00713   return NS_OK;
00714 }
00715 
00716 NS_IMETHODIMP
00717 nsDragService::TargetDataReceived    (GtkWidget         *aWidget,
00718                                       GdkDragContext    *aContext,
00719                                       gint               aX,
00720                                       gint               aY,
00721                                       GtkSelectionData  *aSelectionData,
00722                                       guint              aInfo,
00723                                       guint32            aTime)
00724 {
00725   PR_LOG(sDragLm, PR_LOG_DEBUG, ("nsDragService::TargetDataReceived"));
00726   TargetResetData();
00727   mTargetDragDataReceived = PR_TRUE;
00728   if (aSelectionData->length > 0) {
00729     mTargetDragDataLen = aSelectionData->length;
00730     mTargetDragData = g_malloc(mTargetDragDataLen);
00731     memcpy(mTargetDragData, aSelectionData->data, mTargetDragDataLen);
00732   }
00733   else {
00734     PR_LOG(sDragLm, PR_LOG_DEBUG,
00735            ("Failed to get data.  selection data len was %d\n",
00736             aSelectionData->length));
00737   }
00738   return NS_OK;
00739 }
00740 
00741 NS_IMETHODIMP
00742 nsDragService::TargetSetTimeCallback (nsIDragSessionGTKTimeCB aCallback)
00743 {
00744   PR_LOG(sDragLm, PR_LOG_DEBUG, ("nsDragService::TargetSetTimeCallback"));
00745   mTimeCB = aCallback;
00746   return NS_OK;
00747 }
00748 
00749 PRBool
00750 nsDragService::IsTargetContextList(void)
00751 {
00752   PRBool retval = PR_FALSE;
00753 
00754   if (!mTargetDragContext)
00755     return retval;
00756 
00757   // gMimeListType drags only work for drags within a single process.
00758   // The gtk_drag_get_source_widget() function will return NULL if the
00759   // source of the drag is another app, so we use it to check if a
00760   // gMimeListType drop will work or not.
00761   if (gtk_drag_get_source_widget(mTargetDragContext) == NULL)
00762     return retval;
00763 
00764   GList *tmp;
00765 
00766   // walk the list of context targets and see if one of them is a list
00767   // of items.
00768   for (tmp = mTargetDragContext->targets; tmp; tmp = tmp->next) {
00769     GdkAtom atom = GPOINTER_TO_INT(tmp->data);
00770     gchar *name = NULL;
00771     name = gdk_atom_name(atom);
00772     if (strcmp(name, gMimeListType) == 0)
00773       retval = PR_TRUE;
00774     g_free(name);
00775     if (retval)
00776       break;
00777   }
00778   return retval;
00779 }
00780 
00781 void
00782 nsDragService::GetTargetDragData(GdkAtom aFlavor)
00783 {
00784   gtk_grab_add(mHiddenWidget);
00785   PR_LOG(sDragLm, PR_LOG_DEBUG, ("getting data flavor %d\n", aFlavor));
00786   PR_LOG(sDragLm, PR_LOG_DEBUG, ("mLastWidget is %p and mLastContext is %p\n",
00787                                  mTargetWidget, mTargetDragContext));
00788   // reset our target data areas
00789   TargetResetData();
00790   gtk_drag_get_data(mTargetWidget, mTargetDragContext, aFlavor, mTargetTime);
00791   // Make sure to set the mDataReceived to PR_FALSE since we're about
00792   // to try to get the data.  It might have been left set to PR_TRUE
00793   // if this is another request in the same drag session where the
00794   // previous one failed.  However, there are cases where we can get
00795   // the data received signal before we get to this point so only set
00796   // it if there isn't any drag data.
00797   PR_LOG(sDragLm, PR_LOG_DEBUG, ("about to start inner iteration."));
00798   while (!mTargetDragDataReceived && mDoingDrag) {
00799     // XXX check the number of iterations...we could grab forever and
00800     // that would make me sad.
00801     PR_LOG(sDragLm, PR_LOG_DEBUG, ("doing iteration...\n"));
00802     gtk_main_iteration();
00803   }
00804   PR_LOG(sDragLm, PR_LOG_DEBUG, ("finished inner iteration\n"));
00805   gtk_grab_remove(mHiddenWidget);
00806 }
00807 
00808 void
00809 nsDragService::TargetResetData(void)
00810 {
00811   mTargetDragDataReceived = PR_FALSE;
00812   // make sure to free old data if we have to
00813   if (mTargetDragData)
00814     g_free(mTargetDragData);
00815   mTargetDragData = 0;
00816   mTargetDragDataLen = 0;
00817 }
00818 
00819 GtkTargetList *
00820 nsDragService::GetSourceList(void)
00821 {
00822   if (!mSourceDataItems)
00823     return NULL;
00824   nsVoidArray targetArray;
00825   GtkTargetEntry *targets;
00826   GtkTargetList  *targetList = 0;
00827   PRUint32 targetCount = 0;
00828   unsigned int numDragItems = 0;
00829 
00830   mSourceDataItems->Count(&numDragItems);
00831 
00832   // Check to see if we're dragging > 1 item.
00833   if (numDragItems > 1) {
00834     // as the Xdnd protocol only supports a single item (or is it just
00835     // gtk's implementation?), we don't advertise all flavours listed
00836     // in the nsITransferable.
00837 
00838     // the application/x-moz-internal-item-list format, which preserves
00839     // all information for drags within the same mozilla instance.
00840     GdkAtom listAtom = gdk_atom_intern(gMimeListType, FALSE);
00841     GtkTargetEntry *listTarget = (GtkTargetEntry *)g_malloc(sizeof(GtkTargetEntry));
00842     listTarget->target = g_strdup(gMimeListType);
00843     listTarget->flags = 0;
00844     listTarget->info = listAtom;
00845     PR_LOG(sDragLm, PR_LOG_DEBUG, ("automatically adding target %s with id %ld\n", 
00846                                    listTarget->target, listAtom));
00847     targetArray.AppendElement(listTarget);
00848 
00849     // check what flavours are supported so we can decide what other
00850     // targets to advertise.
00851     nsCOMPtr<nsISupports> genericItem;
00852     mSourceDataItems->GetElementAt(0, getter_AddRefs(genericItem));
00853     nsCOMPtr<nsITransferable> currItem (do_QueryInterface(genericItem));
00854 
00855     if (currItem) {
00856       nsCOMPtr <nsISupportsArray> flavorList;
00857       currItem->FlavorsTransferableCanExport(getter_AddRefs(flavorList));
00858       if (flavorList) {
00859         PRUint32 numFlavors;
00860         flavorList->Count( &numFlavors );
00861         for (PRUint32 flavorIndex = 0; flavorIndex < numFlavors ;
00862              ++flavorIndex ) {
00863           nsCOMPtr<nsISupports> genericWrapper;
00864           flavorList->GetElementAt(flavorIndex, getter_AddRefs(genericWrapper));
00865           nsCOMPtr<nsISupportsCString> currentFlavor;
00866           currentFlavor = do_QueryInterface(genericWrapper);
00867           if (currentFlavor) {
00868             nsXPIDLCString flavorStr;
00869             currentFlavor->ToString ( getter_Copies(flavorStr) );
00870 
00871             // check if text/x-moz-url is supported.  If so, advertise
00872             // text/uri-list.
00873             if (strcmp(flavorStr, kURLMime) == 0) {
00874               listAtom = gdk_atom_intern(gTextUriListType, FALSE);
00875               listTarget = (GtkTargetEntry *)g_malloc(sizeof(GtkTargetEntry));
00876               listTarget->target = g_strdup(gTextUriListType);
00877               listTarget->flags = 0;
00878               listTarget->info = listAtom;
00879               PR_LOG(sDragLm, PR_LOG_DEBUG, ("automatically adding target %s with id %ld\n", 
00880                                              listTarget->target, listAtom));
00881               targetArray.AppendElement(listTarget);
00882             }
00883 
00884           }
00885         } // foreach flavor in item
00886       } // if valid flavor list
00887     } // if item is a transferable
00888   } else if (numDragItems == 1) {
00889     nsCOMPtr<nsISupports> genericItem;
00890     mSourceDataItems->GetElementAt(0, getter_AddRefs(genericItem));
00891     nsCOMPtr<nsITransferable> currItem (do_QueryInterface(genericItem));
00892     if (currItem) {
00893       nsCOMPtr <nsISupportsArray> flavorList;
00894       currItem->FlavorsTransferableCanExport(getter_AddRefs(flavorList));
00895       if (flavorList) {
00896         PRUint32 numFlavors;
00897         flavorList->Count( &numFlavors );
00898         for (PRUint32 flavorIndex = 0; flavorIndex < numFlavors ;
00899              ++flavorIndex ) {
00900           nsCOMPtr<nsISupports> genericWrapper;
00901           flavorList->GetElementAt(flavorIndex, getter_AddRefs(genericWrapper));
00902           nsCOMPtr<nsISupportsCString> currentFlavor;
00903           currentFlavor = do_QueryInterface(genericWrapper);
00904           if (currentFlavor) {
00905             nsXPIDLCString flavorStr;
00906             currentFlavor->ToString ( getter_Copies(flavorStr) );
00907             // get the atom
00908             GdkAtom atom = gdk_atom_intern(flavorStr, FALSE);
00909             GtkTargetEntry *target = (GtkTargetEntry *)g_malloc(sizeof(GtkTargetEntry));
00910             target->target = g_strdup(flavorStr);
00911             target->flags = 0;
00912             target->info = atom;
00913             PR_LOG(sDragLm, PR_LOG_DEBUG,
00914                    ("adding target %s with id %ld\n", target->target, atom));
00915             targetArray.AppendElement(target);
00916             // Check to see if this is text/unicode.  If it is, add
00917             // text/plain since we automatically support text/plain if
00918             // we support text/unicode.
00919             if (strcmp(flavorStr, kUnicodeMime) == 0) {
00920               // get the atom for the unicode string
00921               GdkAtom plainAtom = gdk_atom_intern(kTextMime, FALSE);
00922               GtkTargetEntry *plainTarget = (GtkTargetEntry *)g_malloc(sizeof(GtkTargetEntry));
00923               plainTarget->target = g_strdup(kTextMime);
00924               plainTarget->flags = 0;
00925               plainTarget->info = plainAtom;
00926               PR_LOG(sDragLm, PR_LOG_DEBUG, ("automatically adding target %s with id %ld\n", 
00927                                              plainTarget->target, plainAtom));
00928               targetArray.AppendElement(plainTarget);
00929             }
00930             // Check to see if this is the x-moz-url type.  If it is,
00931             // add _NETSCAPE_URL this is a type used by everybody.
00932             if (strcmp(flavorStr, kURLMime) == 0) {
00933               // get the atom name for it
00934               GdkAtom urlAtom = gdk_atom_intern(gMozUrlType, FALSE);
00935               GtkTargetEntry *urlTarget = (GtkTargetEntry *)g_malloc(sizeof(GtkTargetEntry));
00936               urlTarget->target = g_strdup(gMozUrlType);
00937               urlTarget->flags = 0;
00938               urlTarget->info = urlAtom;
00939               PR_LOG(sDragLm, PR_LOG_DEBUG, ("automatically adding target %s with id %ld\n",
00940                                              urlTarget->target, urlAtom));
00941               targetArray.AppendElement(urlTarget);
00942             }
00943           }
00944         } // foreach flavor in item
00945       } // if valid flavor list
00946     } // if item is a transferable
00947   } // if it is a single item drag
00948 
00949   // get all the elements that we created.
00950   targetCount = targetArray.Count();
00951   if (targetCount) {
00952     // allocate space to create the list of valid targets
00953     targets = (GtkTargetEntry *)g_malloc(sizeof(GtkTargetEntry) * targetCount);
00954     for (PRUint32 targetIndex = 0; targetIndex < targetCount; ++targetIndex) {
00955       GtkTargetEntry *disEntry = (GtkTargetEntry *)targetArray.ElementAt(targetIndex);
00956       // this is a string reference but it will be freed later.
00957       targets[targetIndex].target = disEntry->target;
00958       targets[targetIndex].flags = disEntry->flags;
00959       targets[targetIndex].info = disEntry->info;
00960     }
00961     targetList = gtk_target_list_new(targets, targetCount);
00962     // clean up the target list
00963     for (PRUint32 cleanIndex = 0; cleanIndex < targetCount; ++cleanIndex) {
00964       GtkTargetEntry *thisTarget = (GtkTargetEntry *)targetArray.ElementAt(cleanIndex);
00965       g_free(thisTarget->target);
00966       g_free(thisTarget);
00967     }
00968     g_free(targets);
00969   }
00970 
00971   return targetList;
00972 }
00973 
00974 void
00975 nsDragService::SourceEndDrag(void)
00976 {
00977   // this just releases the list of data items that we provide
00978   mSourceDataItems = 0;
00979 
00980   // Inform the drag session that we're ending the drag.
00981   EndDragSession();
00982 }
00983 
00984 static void
00985 CreateUriList(nsISupportsArray *items, gchar **text, gint *length)
00986 {
00987   PRUint32 i, count;
00988   GString *uriList = g_string_new(NULL);
00989 
00990   items->Count(&count);
00991   for (i = 0; i < count; i++) {
00992     nsCOMPtr<nsISupports> genericItem;
00993     items->GetElementAt(i, getter_AddRefs(genericItem));
00994     nsCOMPtr<nsITransferable> item;
00995     item = do_QueryInterface(genericItem);
00996 
00997     if (item) {
00998       PRUint32 tmpDataLen = 0;
00999       void    *tmpData = NULL;
01000       nsresult rv = 0;
01001       nsCOMPtr<nsISupports> data;
01002       rv = item->GetTransferData(kURLMime, getter_AddRefs(data), &tmpDataLen);
01003 
01004       if (NS_SUCCEEDED(rv)) {
01005         nsPrimitiveHelpers::CreateDataFromPrimitive (kURLMime, data,
01006                                                      &tmpData, tmpDataLen);
01007         char* plainTextData = nsnull;
01008         PRUnichar* castedUnicode = NS_REINTERPRET_CAST(PRUnichar*, tmpData);
01009         PRInt32 plainTextLen = 0;
01010         nsPrimitiveHelpers::ConvertUnicodeToPlatformPlainText(castedUnicode, 
01011                                                               tmpDataLen / 2, 
01012                                                               &plainTextData,
01013                                                               &plainTextLen);
01014         if (plainTextData) {
01015           PRInt32 j;
01016 
01017           // text/x-moz-url is of form url + "\n" + title.  We just
01018           // want the url.
01019           for (j = 0; j < plainTextLen; j++)
01020             if (plainTextData[j] == '\n' || plainTextData[j] == '\r') {
01021               plainTextData[j] = '\0';
01022               break;
01023             }
01024           g_string_append(uriList, plainTextData);
01025           g_string_append(uriList, "\r\n");
01026           // this wasn't allocated with glib
01027           free(plainTextData);
01028         }
01029         if (tmpData) {
01030           // this wasn't allocated with glib
01031           free(tmpData);
01032         }
01033       }
01034     }
01035   }
01036 
01037   *text = uriList->str;
01038   *length = uriList->len + 1;
01039   g_string_free(uriList, FALSE); // don't free the data
01040 }
01041 
01042 
01043 void
01044 nsDragService::SourceDataGet(GtkWidget        *aWidget,
01045                              GdkDragContext   *aContext,
01046                              GtkSelectionData *aSelectionData,
01047                              guint             aInfo,
01048                              guint32           aTime)
01049 {
01050   PR_LOG(sDragLm, PR_LOG_DEBUG, ("nsDragService::SourceDataGet"));
01051   GdkAtom atom = aInfo;
01052   nsXPIDLCString mimeFlavor;
01053   gchar *typeName = 0;
01054   typeName = gdk_atom_name(atom);
01055   if (!typeName) {
01056     PR_LOG(sDragLm, PR_LOG_DEBUG, ("failed to get atom name.\n"));
01057     return;
01058   }
01059 
01060   PR_LOG(sDragLm, PR_LOG_DEBUG, ("Type is %s\n", typeName));
01061   // make a copy since |nsXPIDLCString| won't use |g_free|...
01062   mimeFlavor.Adopt(nsCRT::strdup(typeName));
01063   g_free(typeName);
01064   // check to make sure that we have data items to return.
01065   if (!mSourceDataItems) {
01066     PR_LOG(sDragLm, PR_LOG_DEBUG, ("Failed to get our data items\n"));
01067     return;
01068   }
01069 
01070   if (strcmp(mimeFlavor, gTextUriListType) == 0) {
01071     // fall back for text/uri-list
01072     gchar *uriList;
01073     gint length;
01074 
01075     CreateUriList(mSourceDataItems, &uriList, &length);
01076 
01077     gtk_selection_data_set(aSelectionData, aSelectionData->target,
01078                            8, (guchar *)uriList, length);
01079     g_free(uriList);
01080     return;
01081   }
01082 
01083   nsCOMPtr<nsISupports> genericItem;
01084   mSourceDataItems->GetElementAt(0, getter_AddRefs(genericItem));
01085   nsCOMPtr<nsITransferable> item;
01086   item = do_QueryInterface(genericItem);
01087   if (item) {
01088     // if someone was asking for text/plain, lookup unicode instead so
01089     // we can convert it.
01090     PRBool needToDoConversionToPlainText = PR_FALSE;
01091     const char* actualFlavor = mimeFlavor;
01092     if (strcmp(mimeFlavor,kTextMime) == 0) {
01093       actualFlavor = kUnicodeMime;
01094       needToDoConversionToPlainText = PR_TRUE;
01095     }
01096     // if someone was asking for _NETSCAPE_URL we need to convert to
01097     // plain text but we also need to look for x-moz-url
01098     else if (strcmp(mimeFlavor, gMozUrlType) == 0) {
01099       actualFlavor = kURLMime;
01100       needToDoConversionToPlainText = PR_TRUE;
01101     }
01102     else
01103       actualFlavor = mimeFlavor;
01104 
01105     PRUint32 tmpDataLen = 0;
01106     void    *tmpData = NULL;
01107     nsresult rv;
01108     nsCOMPtr<nsISupports> data;
01109     rv = item->GetTransferData(actualFlavor, getter_AddRefs(data), &tmpDataLen);
01110     if (NS_SUCCEEDED(rv)) {
01111       nsPrimitiveHelpers::CreateDataFromPrimitive (actualFlavor, data,
01112                                                    &tmpData, tmpDataLen);
01113       // if required, do the extra work to convert unicode to plain
01114       // text and replace the output values with the plain text.
01115       if (needToDoConversionToPlainText) {
01116         char* plainTextData = nsnull;
01117         PRUnichar* castedUnicode = NS_REINTERPRET_CAST(PRUnichar*, tmpData);
01118         PRInt32 plainTextLen = 0;
01119         nsPrimitiveHelpers::ConvertUnicodeToPlatformPlainText(castedUnicode, 
01120                                                               tmpDataLen / 2, 
01121                                                               &plainTextData,
01122                                                               &plainTextLen);
01123         if (tmpData) {
01124           // this was not allocated using glib
01125           free(tmpData);
01126           tmpData = plainTextData;
01127           tmpDataLen = plainTextLen;
01128         }
01129       }
01130       if (tmpData) {
01131         // this copies the data
01132         gtk_selection_data_set(aSelectionData, aSelectionData->target,
01133                                8, (guchar *)tmpData, tmpDataLen);
01134         // this wasn't allocated with glib
01135         free(tmpData);
01136       }
01137     }
01138   }
01139 }
01140 
01141 /* static */
01142 void
01143 invisibleSourceDragDataGet (GtkWidget        *aWidget,
01144                             GdkDragContext   *aContext,
01145                             GtkSelectionData *aSelectionData,
01146                             guint             aInfo,
01147                             guint32           aTime,
01148                             gpointer          aData)
01149 {
01150   PR_LOG(sDragLm, PR_LOG_DEBUG, ("invisibleDragDataGet"));
01151   nsDragService *dragService = (nsDragService *)aData;
01152   dragService->SourceDataGet(aWidget, aContext, aSelectionData,
01153                              aInfo, aTime);
01154 }
01155 
01156 /* static */
01157 void
01158 invisibleSourceDragEnd     (GtkWidget        *aWidget,
01159                             GdkDragContext   *aContext,
01160                             gpointer          aData)
01161 {
01162   PR_LOG(sDragLm, PR_LOG_DEBUG, ("invisibleDragEnd"));
01163   nsDragService *dragService = (nsDragService *)aData;
01164   // The drag has ended.  Release the hostages!
01165   dragService->SourceEndDrag();
01166 }