Back to index

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