1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 #include "nsDragService.h"
10 #include "nsISupportsPrimitives.h"
12 #include "nsXPIDLString.h"
13 #include "nsReadableUtils.h"
14 #include "nsIWebBrowserPersist.h"
18 #include "nsNetUtil.h"
20 #include "wdgtos2rc.h"
21 #include "nsILocalFileOS2.h"
22 #include "nsIDocument.h"
23 #include "nsISelection.h"
26 // --------------------------------------------------------------------------
30 #ifndef DC_PREPAREITEM
31 #define DC_PREPAREITEM 0x0040
34 // limit URL object titles to a reasonable length
35 #define MAXTITLELTH 31
36 #define TITLESEPARATOR (L' ')
38 #define DTSHARE_NAME "\\SHAREMEM\\MOZ_DND"
39 #define DTSHARE_RMF "<DRM_DTSHARE, DRF_TEXT>"
41 #define OS2FILE_NAME "MOZ_TGT.TMP"
42 #define OS2FILE_TXTRMF "<DRM_OS2FILE, DRF_TEXT>"
43 #define OS2FILE_UNKRMF "<DRM_OS2FILE, DRF_UNKNOWN>"
45 // not defined in the OS/2 toolkit headers
47 APIRET APIENTRY
DosQueryModFromEIP(HMODULE
*phMod
, ULONG
*pObjNum
,
48 ULONG BuffLen
, PCHAR pBuff
,
49 ULONG
*pOffset
, ULONG Address
);
52 // --------------------------------------------------------------------------
55 nsresult
RenderToOS2File( PDRAGITEM pditem
, HWND hwnd
);
56 nsresult
RenderToOS2FileComplete(PDRAGTRANSFER pdxfer
, USHORT usResult
,
57 bool content
, char** outText
);
58 nsresult
RenderToDTShare( PDRAGITEM pditem
, HWND hwnd
);
59 nsresult
RenderToDTShareComplete(PDRAGTRANSFER pdxfer
, USHORT usResult
,
61 nsresult
RequestRendering( PDRAGITEM pditem
, HWND hwnd
, PCSZ pRMF
, PCSZ pName
);
62 nsresult
GetAtom( ATOM aAtom
, char** outText
);
63 nsresult
GetFileName(PDRAGITEM pditem
, char** outText
);
64 nsresult
GetFileContents(PCSZ pszPath
, char** outText
);
65 nsresult
GetTempFileName(char** outText
);
66 void SaveTypeAndSource(nsIFile
*file
, nsIDOMDocument
*domDoc
,
68 int UnicodeToCodepage( const nsAString
& inString
, char **outText
);
69 int CodepageToUnicode( const nsACString
& inString
, char16_t
**outText
);
70 void RemoveCarriageReturns(char * pszText
);
71 MRESULT EXPENTRY
nsDragWindowProc(HWND hWnd
, ULONG msg
, MPARAM mp1
, MPARAM mp2
);
73 // --------------------------------------------------------------------------
76 static HPOINTER gPtrArray
[IDC_DNDCOUNT
];
77 static char * gTempFile
= 0;
79 // --------------------------------------------------------------------------
80 // --------------------------------------------------------------------------
82 nsDragService::nsDragService()
84 // member initializers and constructor code
85 mDragWnd
= WinCreateWindow( HWND_DESKTOP
, WC_STATIC
, 0, 0, 0, 0, 0, 0,
86 HWND_DESKTOP
, HWND_BOTTOM
, 0, 0, 0);
87 WinSubclassWindow( mDragWnd
, nsDragWindowProc
);
89 HMODULE hModResources
= NULLHANDLE
;
90 DosQueryModFromEIP(&hModResources
, nullptr, 0, nullptr, nullptr,
92 for (int i
= 0; i
< IDC_DNDCOUNT
; i
++)
93 gPtrArray
[i
] = ::WinLoadPointer(HWND_DESKTOP
, hModResources
, i
+IDC_DNDBASE
);
96 // --------------------------------------------------------------------------
98 nsDragService::~nsDragService()
101 WinDestroyWindow(mDragWnd
);
103 for (int i
= 0; i
< IDC_DNDCOUNT
; i
++) {
104 WinDestroyPointer(gPtrArray
[i
]);
109 NS_IMPL_ISUPPORTS_INHERITED1(nsDragService
, nsBaseDragService
, nsIDragSessionOS2
)
111 // --------------------------------------------------------------------------
113 NS_IMETHODIMP
nsDragService::InvokeDragSession(nsIDOMNode
*aDOMNode
,
114 nsISupportsArray
*aTransferables
,
115 nsIScriptableRegion
*aRegion
,
116 uint32_t aActionType
)
119 return NS_ERROR_UNEXPECTED
;
121 nsresult rv
= nsBaseDragService::InvokeDragSession(aDOMNode
, aTransferables
,
122 aRegion
, aActionType
);
123 NS_ENSURE_SUCCESS(rv
, rv
);
125 mSourceDataItems
= aTransferables
;
126 WinSetCapture(HWND_DESKTOP
, NULLHANDLE
);
128 // Assume we are only dragging one thing for now
129 PDRAGINFO pDragInfo
= DrgAllocDraginfo(1);
131 return NS_ERROR_UNEXPECTED
;
133 pDragInfo
->usOperation
= DO_DEFAULT
;
136 dragitem
.hwndItem
= mDragWnd
;
137 dragitem
.ulItemID
= (ULONG
)this;
138 dragitem
.fsControl
= DC_OPEN
;
139 dragitem
.cxOffset
= 2;
140 dragitem
.cyOffset
= 2;
141 dragitem
.fsSupportedOps
= DO_COPYABLE
|DO_MOVEABLE
|DO_LINKABLE
;
143 // since there is no source file, leave these "blank"
144 dragitem
.hstrContainerName
= NULLHANDLE
;
145 dragitem
.hstrSourceName
= NULLHANDLE
;
147 rv
= NS_ERROR_FAILURE
;
150 // bracket this to reduce our footprint before the drag begins
152 nsCOMPtr
<nsISupports
> genericItem
;
153 mSourceDataItems
->GetElementAt(0, getter_AddRefs(genericItem
));
154 nsCOMPtr
<nsITransferable
> transItem (do_QueryInterface(genericItem
));
156 nsCOMPtr
<nsISupports
> genericData
;
159 // see if we have a URL or text; if so, the title method
160 // will save the data and mimetype for use with a native drop
162 if (NS_SUCCEEDED(transItem
->GetTransferData(kURLMime
,
163 getter_AddRefs(genericData
), &len
))) {
164 nsXPIDLCString targetName
;
165 rv
= GetUrlAndTitle( genericData
, getter_Copies(targetName
));
166 if (NS_SUCCEEDED(rv
)) {
167 // advise PM that we need a DM_RENDERPREPARE msg
168 // *before* it composes a render-to filename
169 dragitem
.fsControl
|= DC_PREPAREITEM
;
170 dragitem
.hstrType
= DrgAddStrHandle("UniformResourceLocator");
171 dragitem
.hstrRMF
= DrgAddStrHandle("<DRM_OS2FILE,DRF_TEXT>");
172 dragitem
.hstrTargetName
= DrgAddStrHandle(targetName
.get());
177 if (NS_SUCCEEDED(transItem
->GetTransferData(kUnicodeMime
,
178 getter_AddRefs(genericData
), &len
))) {
179 nsXPIDLCString targetName
;
180 rv
= GetUniTextTitle( genericData
, getter_Copies(targetName
));
181 if (NS_SUCCEEDED(rv
)) {
182 dragitem
.hstrType
= DrgAddStrHandle("Plain Text");
183 dragitem
.hstrRMF
= DrgAddStrHandle("<DRM_OS2FILE,DRF_TEXT>");
184 dragitem
.hstrTargetName
= DrgAddStrHandle(targetName
.get());
185 idIcon
= IDC_DNDTEXT
;
190 // if neither URL nor text are available, make this a Moz-only drag
191 // by making it unidentifiable to native apps
194 dragitem
.hstrType
= DrgAddStrHandle("Unknown");
195 dragitem
.hstrRMF
= DrgAddStrHandle("<DRM_UNKNOWN,DRF_UNKNOWN>");
196 dragitem
.hstrTargetName
= NULLHANDLE
;
198 DrgSetDragitem(pDragInfo
, &dragitem
, sizeof(DRAGITEM
), 0);
201 memset(&dragimage
, 0, sizeof(DRAGIMAGE
));
202 dragimage
.cb
= sizeof(DRAGIMAGE
);
203 dragimage
.fl
= DRG_ICON
;
205 dragimage
.hImage
= gPtrArray
[idIcon
-IDC_DNDBASE
];
206 if (dragimage
.hImage
) {
207 dragimage
.cyOffset
= 8;
208 dragimage
.cxOffset
= 2;
211 dragimage
.hImage
= WinQuerySysPointer(HWND_DESKTOP
, SPTR_FILE
, FALSE
);
214 LONG escState
= WinGetKeyState(HWND_DESKTOP
, VK_ESC
) & 0x01;
215 HWND hwndDest
= DrgDrag(mDragWnd
, pDragInfo
, &dragimage
, 1, VK_BUTTON2
,
216 (void*)0x80000000L
); // Don't lock the desktop PS
218 // determine whether the drag ended because Escape was pressed
219 if (hwndDest
== 0 && (WinGetKeyState(HWND_DESKTOP
, VK_ESC
) & 0x01) != escState
)
220 mUserCancelled
= true;
221 FireDragEventAtSource(NS_DRAGDROP_END
);
224 // do clean up; if the drop completed,
225 // the target will delete the string handles
227 DrgDeleteDraginfoStrHandles(pDragInfo
);
228 DrgFreeDraginfo(pDragInfo
);
230 // reset nsDragService's members
231 mSourceDataItems
= 0;
235 // reset nsBaseDragService's members
236 mSourceDocument
= nullptr;
237 mSourceNode
= nullptr;
238 mSelection
= nullptr;
239 mDataTransfer
= nullptr;
240 mUserCancelled
= false;
251 // --------------------------------------------------------------------------
253 MRESULT EXPENTRY
nsDragWindowProc(HWND hWnd
, ULONG msg
, MPARAM mp1
, MPARAM mp2
)
257 // if the user requests the contents of a URL be rendered (vs the URL
258 // itself), change the suggested target name from the URL's title to
259 // the name of the file that will be retrieved
260 case DM_RENDERPREPARE
: {
261 PDRAGTRANSFER pdxfer
= (PDRAGTRANSFER
)mp1
;
262 nsDragService
* dragservice
= (nsDragService
*)pdxfer
->pditem
->ulItemID
;
264 if (pdxfer
->usOperation
== DO_COPY
&&
265 (WinGetKeyState(HWND_DESKTOP
, VK_CTRL
) & 0x8000) &&
266 !strcmp(dragservice
->mMimeType
, kURLMime
)) {
267 // QI'ing nsIURL will fail for mailto: and the like
268 nsCOMPtr
<nsIURL
> urlObject(do_QueryInterface(dragservice
->mSourceData
));
270 nsAutoCString filename
;
271 urlObject
->GetFileName(filename
);
272 if (filename
.IsEmpty()) {
273 urlObject
->GetHost(filename
);
274 filename
.Append("/file");
276 DrgDeleteStrHandle(pdxfer
->pditem
->hstrTargetName
);
277 pdxfer
->pditem
->hstrTargetName
= DrgAddStrHandle(filename
.get());
280 return (MRESULT
)TRUE
;
284 nsresult rv
= NS_ERROR_FAILURE
;
285 PDRAGTRANSFER pdxfer
= (PDRAGTRANSFER
)mp1
;
286 nsDragService
* dragservice
= (nsDragService
*)pdxfer
->pditem
->ulItemID
;
287 char chPath
[CCHMAXPATH
];
289 DrgQueryStrName(pdxfer
->hstrRenderToName
, CCHMAXPATH
, chPath
);
291 // if the user Ctrl-dropped a URL, use the nsIURL interface
292 // to determine if it points to content (i.e. a file); if so,
293 // fetch its contents; if not (e.g. a 'mailto:' url), drop into
294 // the code that uses nsIURI to render a URL object
296 if (!strcmp(dragservice
->mMimeType
, kURLMime
)) {
297 if (pdxfer
->usOperation
== DO_COPY
&&
298 (WinGetKeyState(HWND_DESKTOP
, VK_CTRL
) & 0x8000)) {
299 nsCOMPtr
<nsIURL
> urlObject(do_QueryInterface(dragservice
->mSourceData
));
301 rv
= dragservice
->SaveAsContents(chPath
, urlObject
);
303 if (!NS_SUCCEEDED(rv
)) {
304 nsCOMPtr
<nsIURI
> uriObject(do_QueryInterface(dragservice
->mSourceData
));
306 rv
= dragservice
->SaveAsURL(chPath
, uriObject
);
310 // if we're dragging text, do NLS conversion then write it to file
311 if (!strcmp(dragservice
->mMimeType
, kUnicodeMime
)) {
312 nsCOMPtr
<nsISupportsString
> strObject(
313 do_QueryInterface(dragservice
->mSourceData
));
315 rv
= dragservice
->SaveAsText(chPath
, strObject
);
318 DrgPostTransferMsg(pdxfer
->hwndClient
, DM_RENDERCOMPLETE
, pdxfer
,
319 (NS_SUCCEEDED(rv
) ? DMFL_RENDEROK
: DMFL_RENDERFAIL
),
321 DrgFreeDragtransfer(pdxfer
);
322 return (MRESULT
)TRUE
;
325 // we don't use these msgs but neither does WinDefWindowProc()
326 case DM_DRAGOVERNOTIFY
:
327 case DM_ENDCONVERSATION
:
334 return ::WinDefWindowProc(hWnd
, msg
, mp1
, mp2
);
337 //-------------------------------------------------------------------------
339 // if the versions of Start & EndDragSession in nsBaseDragService
340 // were called (and they shouldn't be), they'd break nsIDragSessionOS2;
341 // they're overridden here and turned into no-ops to prevent this
343 NS_IMETHODIMP
nsDragService::StartDragSession()
345 NS_ERROR("OS/2 version of StartDragSession() should never be called!");
349 NS_IMETHODIMP
nsDragService::EndDragSession(bool aDragDone
)
351 NS_ERROR("OS/2 version of EndDragSession() should never be called!");
355 // --------------------------------------------------------------------------
357 NS_IMETHODIMP
nsDragService::GetNumDropItems(uint32_t *aNumDropItems
)
359 if (mSourceDataItems
)
360 mSourceDataItems
->Count(aNumDropItems
);
367 // --------------------------------------------------------------------------
369 NS_IMETHODIMP
nsDragService::GetData(nsITransferable
*aTransferable
,
372 // make sure that we have a transferable
374 return NS_ERROR_INVALID_ARG
;
376 // get flavor list that includes all acceptable flavors (including
377 // ones obtained through conversion). Flavors are nsISupportsCStrings
378 // so that they can be seen from JS.
379 nsresult rv
= NS_ERROR_FAILURE
;
380 nsCOMPtr
<nsISupportsArray
> flavorList
;
381 rv
= aTransferable
->FlavorsTransferableCanImport(getter_AddRefs(flavorList
));
385 // count the number of flavors
387 flavorList
->Count (&cnt
);
389 for (unsigned int i
= 0; i
< cnt
; ++i
) {
390 nsCOMPtr
<nsISupports
> genericWrapper
;
391 flavorList
->GetElementAt(i
, getter_AddRefs(genericWrapper
));
392 nsCOMPtr
<nsISupportsCString
> currentFlavor
;
393 currentFlavor
= do_QueryInterface(genericWrapper
);
395 nsXPIDLCString flavorStr
;
396 currentFlavor
->ToString(getter_Copies(flavorStr
));
398 nsCOMPtr
<nsISupports
> genericItem
;
400 mSourceDataItems
->GetElementAt(aItemIndex
, getter_AddRefs(genericItem
));
401 nsCOMPtr
<nsITransferable
> item (do_QueryInterface(genericItem
));
403 nsCOMPtr
<nsISupports
> data
;
404 uint32_t tmpDataLen
= 0;
405 rv
= item
->GetTransferData(flavorStr
, getter_AddRefs(data
),
407 if (NS_SUCCEEDED(rv
)) {
408 rv
= aTransferable
->SetTransferData(flavorStr
, data
, tmpDataLen
);
418 // --------------------------------------------------------------------------
420 // This returns true if any of the dragged items support a specified data
421 // flavor. This doesn't make a lot of sense when dragging multiple items:
422 // all of them ought to match. OTOH, Moz doesn't support multiple drag
423 // items so no problems arise. If they do, use the commented-out code to
424 // switch from "any" to "all".
426 NS_IMETHODIMP
nsDragService::IsDataFlavorSupported(const char *aDataFlavor
,
430 return NS_ERROR_INVALID_ARG
;
434 uint32_t numDragItems
= 0;
435 if (mSourceDataItems
)
436 mSourceDataItems
->Count(&numDragItems
);
440 // return true if all items support this flavor
441 // for (uint32_t itemIndex = 0, *_retval = true;
442 // itemIndex < numDragItems && *_retval; ++itemIndex) {
445 // return true if any item supports this flavor
446 for (uint32_t itemIndex
= 0;
447 itemIndex
< numDragItems
&& !(*_retval
); ++itemIndex
) {
449 nsCOMPtr
<nsISupports
> genericItem
;
450 mSourceDataItems
->GetElementAt(itemIndex
, getter_AddRefs(genericItem
));
451 nsCOMPtr
<nsITransferable
> currItem (do_QueryInterface(genericItem
));
454 nsCOMPtr
<nsISupportsArray
> flavorList
;
455 currItem
->FlavorsTransferableCanExport(getter_AddRefs(flavorList
));
459 flavorList
->Count( &numFlavors
);
461 for (uint32_t flavorIndex
=0; flavorIndex
< numFlavors
; ++flavorIndex
) {
462 nsCOMPtr
<nsISupports
> genericWrapper
;
463 flavorList
->GetElementAt(flavorIndex
, getter_AddRefs(genericWrapper
));
464 nsCOMPtr
<nsISupportsCString
> currentFlavor
;
465 currentFlavor
= do_QueryInterface(genericWrapper
);
468 nsXPIDLCString flavorStr
;
469 currentFlavor
->ToString ( getter_Copies(flavorStr
) );
470 if (strcmp(flavorStr
, aDataFlavor
) == 0) {
483 // --------------------------------------------------------------------------
485 // use nsIWebBrowserPersist to fetch the contents of a URL
487 nsresult
nsDragService::SaveAsContents(PCSZ pszDest
, nsIURL
* aURL
)
489 nsCOMPtr
<nsIURI
> linkURI(do_QueryInterface(aURL
));
491 return NS_ERROR_FAILURE
;
493 nsCOMPtr
<nsIWebBrowserPersist
> webPersist(
494 do_CreateInstance("@mozilla.org/embedding/browser/nsWebBrowserPersist;1"));
496 return NS_ERROR_FAILURE
;
498 nsCOMPtr
<nsIFile
> file
;
499 NS_NewNativeLocalFile(nsDependentCString(pszDest
), true,
500 getter_AddRefs(file
));
502 return NS_ERROR_FAILURE
;
505 if (NS_FAILED(file
->OpenANSIFileDesc("wb+", &fp
)))
506 return NS_ERROR_FAILURE
;
508 nsCOMPtr
<nsIDOMDocument
> domDoc
;
509 GetSourceDocument(getter_AddRefs(domDoc
));
510 nsCOMPtr
<nsIDocument
> document
= do_QueryInterface(domDoc
);
512 fwrite("", 0, 1, fp
);
514 webPersist
->SaveURI(linkURI
, nullptr, nullptr, nullptr, nullptr, file
,
515 document
->GetLoadContext());
520 // --------------------------------------------------------------------------
522 // save this URL in a file that the WPS will identify as a WPUrl object
524 nsresult
nsDragService::SaveAsURL(PCSZ pszDest
, nsIURI
* aURI
)
526 nsAutoCString strUri
;
527 aURI
->GetSpec(strUri
);
529 if (strUri
.IsEmpty())
530 return NS_ERROR_FAILURE
;
532 nsCOMPtr
<nsIFile
> file
;
533 NS_NewNativeLocalFile(nsDependentCString(pszDest
), true,
534 getter_AddRefs(file
));
536 return NS_ERROR_FAILURE
;
539 if (NS_FAILED(file
->OpenANSIFileDesc("wb+", &fp
)))
540 return NS_ERROR_FAILURE
;
542 fwrite(strUri
.get(), strUri
.Length(), 1, fp
);
545 nsCOMPtr
<nsIDOMDocument
> domDoc
;
546 GetSourceDocument(getter_AddRefs(domDoc
));
547 SaveTypeAndSource(file
, domDoc
, "UniformResourceLocator");
552 // --------------------------------------------------------------------------
554 // save this text to file after conversion to the current codepage
556 nsresult
nsDragService::SaveAsText(PCSZ pszDest
, nsISupportsString
* aString
)
558 nsAutoString strData
;
559 aString
->GetData(strData
);
561 if (strData
.IsEmpty())
562 return NS_ERROR_FAILURE
;
564 nsCOMPtr
<nsIFile
> file
;
565 NS_NewNativeLocalFile(nsDependentCString(pszDest
), true,
566 getter_AddRefs(file
));
568 return NS_ERROR_FAILURE
;
570 nsXPIDLCString textStr
;
571 int cnt
= UnicodeToCodepage(strData
, getter_Copies(textStr
));
573 return NS_ERROR_FAILURE
;
576 if (NS_FAILED(file
->OpenANSIFileDesc("wb+", &fp
)))
577 return NS_ERROR_FAILURE
;
579 fwrite(textStr
.get(), cnt
, 1, fp
);
582 nsCOMPtr
<nsIDOMDocument
> domDoc
;
583 GetSourceDocument(getter_AddRefs(domDoc
));
584 SaveTypeAndSource(file
, domDoc
, "Plain Text");
589 // --------------------------------------------------------------------------
591 // Split a Moz Url/Title into its components, save the Url for use by
592 // a native drop, then compose a title.
594 nsresult
nsDragService::GetUrlAndTitle(nsISupports
*aGenericData
,
597 // get the URL/title string
598 nsCOMPtr
<nsISupportsString
> strObject ( do_QueryInterface(aGenericData
));
600 return NS_ERROR_FAILURE
;
601 nsAutoString strData
;
602 strObject
->GetData(strData
);
604 // split string into URL and Title -
605 // if there's a title but no URL, there's no reason to continue
606 int32_t lineIndex
= strData
.FindChar ('\n');
608 return NS_ERROR_FAILURE
;
610 // get the URL portion of the text
615 strData
.Left(strUrl
, lineIndex
);
617 // save the URL for later use
618 nsCOMPtr
<nsIURI
> saveURI
;
619 NS_NewURI(getter_AddRefs(saveURI
), strUrl
);
621 return NS_ERROR_FAILURE
;
623 // if there's a bona-fide title & it isn't just a copy of the URL,
624 // limit it to a reasonable length, perform NLS conversion, then return
626 if (++lineIndex
&& lineIndex
!= (int)strData
.Length() &&
627 !strUrl
.Equals(Substring(strData
, lineIndex
, strData
.Length()))) {
628 uint32_t strLth
= std::min((int)strData
.Length()-lineIndex
, MAXTITLELTH
);
629 nsAutoString strTitle
;
630 strData
.Mid(strTitle
, lineIndex
, strLth
);
631 if (!UnicodeToCodepage(strTitle
, aTargetName
))
632 return NS_ERROR_FAILURE
;
634 mSourceData
= do_QueryInterface(saveURI
);
635 mMimeType
= kURLMime
;
639 // if the URI can be handled as a URL, construct a title from
640 // the hostname & filename; if not, use the first MAXTITLELTH
641 // characters that appear after the scheme name
643 nsAutoCString strTitle
;
645 nsCOMPtr
<nsIURL
> urlObj( do_QueryInterface(saveURI
));
647 nsAutoCString strFile
;
649 urlObj
->GetHost(strTitle
);
650 urlObj
->GetFileName(strFile
);
651 if (!strFile
.IsEmpty()) {
652 strTitle
.AppendLiteral("/");
653 strTitle
.Append(strFile
);
656 urlObj
->GetDirectory(strFile
);
657 if (strFile
.Length() > 1) {
658 nsAutoCString::const_iterator start
, end
, curr
;
659 strFile
.BeginReading(start
);
660 strFile
.EndReading(end
);
661 strFile
.EndReading(curr
);
662 for (curr
.advance(-2); curr
!= start
; --curr
)
665 strTitle
.Append(Substring(curr
, end
));
670 saveURI
->GetSpec(strTitle
);
671 int32_t index
= strTitle
.FindChar (':');
673 if ((strTitle
.get())[++index
] == '/')
674 if ((strTitle
.get())[++index
] == '/')
676 strTitle
.Cut(0, index
);
678 if (strTitle
.Length() > MAXTITLELTH
)
679 strTitle
.Truncate(MAXTITLELTH
);
682 *aTargetName
= ToNewCString(strTitle
);
684 mSourceData
= do_QueryInterface(saveURI
);
685 mMimeType
= kURLMime
;
689 // --------------------------------------------------------------------------
691 // Construct a title for text drops from the leading words of the text.
692 // Alphanumeric characters are copied to the title; sequences of
693 // non-alphanums are replaced by a single space
695 nsresult
nsDragService::GetUniTextTitle(nsISupports
*aGenericData
,
699 nsCOMPtr
<nsISupportsString
> strObject ( do_QueryInterface(aGenericData
));
701 return NS_ERROR_FAILURE
;
703 // alloc a buffer to hold the unicode title text
704 int bufsize
= (MAXTITLELTH
+1)*2;
705 char16_t
* buffer
= (char16_t
*)nsMemory::Alloc(bufsize
);
707 return NS_ERROR_FAILURE
;
709 nsAutoString strData
;
710 strObject
->GetData(strData
);
711 nsAutoString::const_iterator start
, end
;
712 strData
.BeginReading(start
);
713 strData
.EndReading(end
);
715 // skip over leading non-alphanumerics
716 for( ; start
!= end
; ++start
)
717 if (UniQueryChar( *start
, CT_ALNUM
))
720 // move alphanumerics into the buffer & replace contiguous
721 // non-alnums with a single separator character
723 for (ctr
=0, sep
=0; start
!= end
&& ctr
< MAXTITLELTH
; ++start
) {
724 if (UniQueryChar( *start
, CT_ALNUM
)) {
725 buffer
[ctr
] = *start
;
731 buffer
[ctr
] = TITLESEPARATOR
;
736 // eliminate trailing separators & lone characters
737 // orphaned when the title is truncated
740 if (ctr
>= MAXTITLELTH
- sep
&& buffer
[ctr
-2] == TITLESEPARATOR
)
744 // if we ended up with no alnums, call the result "text";
745 // otherwise, do NLS conversion
747 *aTargetName
= ToNewCString(NS_LITERAL_CSTRING("text"));
751 ctr
= UnicodeToCodepage( nsDependentString(buffer
), aTargetName
);
753 // free our buffer, then exit
754 nsMemory::Free(buffer
);
757 return NS_ERROR_FAILURE
;
759 mSourceData
= aGenericData
;
760 mMimeType
= kUnicodeMime
;
764 // --------------------------------------------------------------------------
766 // --------------------------------------------------------------------------
768 // DragOverMsg() provides minimal handling if a drag session is already
769 // in progress. If not, it assumes this is a native drag that has just
770 // entered the window and calls NativeDragEnter() to start a session.
772 NS_IMETHODIMP
nsDragService::DragOverMsg(PDRAGINFO pdinfo
, MRESULT
&mr
,
775 nsresult rv
= NS_ERROR_FAILURE
;
777 if (!&mr
|| !dragFlags
|| !pdinfo
|| !DrgAccessDraginfo(pdinfo
))
781 mr
= MRFROM2SHORT(DOR_NEVERDROP
, 0);
783 // examine the dragged item & "start" a drag session if OK;
784 // also, signal the need for a dragenter event
786 if (NS_SUCCEEDED(NativeDragEnter(pdinfo
)))
787 *dragFlags
|= DND_DISPATCHENTEREVENT
;
789 // if we're in a drag, set it up to be dispatched
792 switch (pdinfo
->usOperation
) {
794 SetDragAction(DRAGDROP_ACTION_COPY
);
797 SetDragAction(DRAGDROP_ACTION_LINK
);
800 SetDragAction(DRAGDROP_ACTION_MOVE
);
804 *dragFlags
|= DND_DISPATCHEVENT
| DND_GETDRAGOVERRESULT
| DND_MOZDRAG
;
806 *dragFlags
|= DND_DISPATCHEVENT
| DND_GETDRAGOVERRESULT
| DND_NATIVEDRAG
;
810 DrgFreeDraginfo(pdinfo
);
814 // --------------------------------------------------------------------------
816 // Evaluates native drag data, and if acceptable, creates & stores
817 // a transferable with the available flavors (but not the data);
818 // if successful, it "starts" the session.
820 NS_IMETHODIMP
nsDragService::NativeDragEnter(PDRAGINFO pdinfo
)
822 nsresult rv
= NS_ERROR_FAILURE
;
823 bool isFQFile
= FALSE
;
825 PDRAGITEM pditem
= 0;
827 if (pdinfo
->cditem
!= 1)
830 pditem
= DrgQueryDragitemPtr(pdinfo
, 0);
833 if (DrgVerifyRMF(pditem
, "DRM_ATOM", 0)) {
838 if (DrgVerifyRMF(pditem
, "DRM_DTSHARE", 0))
841 if (DrgVerifyRMF(pditem
, "DRM_OS2FILE", 0)) {
843 if (pditem
->hstrContainerName
&& pditem
->hstrSourceName
)
848 if (NS_SUCCEEDED(rv
)) {
849 rv
= NS_ERROR_FAILURE
;
850 nsCOMPtr
<nsITransferable
> trans(
851 do_CreateInstance("@mozilla.org/widget/transferable;1", &rv
));
853 trans
->Init(nullptr);
855 bool isUrl
= DrgVerifyType(pditem
, "UniformResourceLocator");
856 bool isAlt
= (WinGetKeyState(HWND_DESKTOP
, VK_ALT
) & 0x8000);
858 // if this is a fully-qualified file or the item claims to be
859 // a Url, identify it as a Url & also offer it as html
860 if ((isFQFile
&& !isAlt
) || isUrl
) {
861 trans
->AddDataFlavor(kURLMime
);
862 trans
->AddDataFlavor(kHTMLMime
);
865 // everything is always "text"
866 trans
->AddDataFlavor(kUnicodeMime
);
868 // if we can create the array, initialize the session
869 nsCOMPtr
<nsISupportsArray
> transArray(
870 do_CreateInstance("@mozilla.org/supports-array;1", &rv
));
872 transArray
->InsertElementAt(trans
, 0);
873 mSourceDataItems
= transArray
;
875 // add the dragged data to the transferable if we have easy access
876 // to it (i.e. no need to read a file or request rendering); for
877 // URLs, we'll skip creating a title until the drop occurs
878 nsXPIDLCString someText
;
880 if (NS_SUCCEEDED(GetAtom(pditem
->ulItemID
, getter_Copies(someText
))))
881 NativeDataToTransferable( someText
.get(), 0, isUrl
);
884 if (isFQFile
&& !isAlt
&&
885 NS_SUCCEEDED(GetFileName(pditem
, getter_Copies(someText
)))) {
886 nsCOMPtr
<nsIFile
> file
;
887 if (NS_SUCCEEDED(NS_NewNativeLocalFile(someText
, true,
888 getter_AddRefs(file
)))) {
889 nsAutoCString textStr
;
890 NS_GetURLSpecFromFile(file
, textStr
);
891 if (!textStr
.IsEmpty()) {
892 someText
.Assign(ToNewCString(textStr
));
893 NativeDataToTransferable( someText
.get(), 0, TRUE
);
909 // --------------------------------------------------------------------------
911 // Invoked after a dragover event has been dispatched, this constructs
912 // a reply to DM_DRAGOVER based on the canDrop & dragAction attributes.
914 NS_IMETHODIMP
nsDragService::GetDragoverResult(MRESULT
& mr
)
916 nsresult rv
= NS_ERROR_FAILURE
;
922 bool canDrop
= false;
924 GetCanDrop(&canDrop
);
932 GetDragAction(&action
);
933 if (action
& DRAGDROP_ACTION_COPY
)
936 if (action
& DRAGDROP_ACTION_LINK
)
943 if (action
== DRAGDROP_ACTION_NONE
)
947 mr
= MRFROM2SHORT(usDrop
, usOp
);
951 mr
= MRFROM2SHORT(DOR_NEVERDROP
, 0);
956 // --------------------------------------------------------------------------
958 // have the client dispatch the event, then call ExitSession()
960 NS_IMETHODIMP
nsDragService::DragLeaveMsg(PDRAGINFO pdinfo
, uint32_t* dragFlags
)
962 if (!mDoingDrag
|| !dragFlags
)
963 return NS_ERROR_FAILURE
;
966 *dragFlags
= DND_DISPATCHEVENT
| DND_EXITSESSION
| DND_MOZDRAG
;
968 *dragFlags
= DND_DISPATCHEVENT
| DND_EXITSESSION
| DND_NATIVEDRAG
;
973 // --------------------------------------------------------------------------
975 // DropHelp occurs when you press F1 during a drag; apparently,
976 // it's like a regular drop in that the target has to do clean up
978 NS_IMETHODIMP
nsDragService::DropHelpMsg(PDRAGINFO pdinfo
, uint32_t* dragFlags
)
981 return NS_ERROR_FAILURE
;
983 if (pdinfo
&& DrgAccessDraginfo(pdinfo
)) {
984 DrgDeleteDraginfoStrHandles(pdinfo
);
985 DrgFreeDraginfo(pdinfo
);
989 return NS_ERROR_FAILURE
;
992 *dragFlags
= DND_DISPATCHEVENT
| DND_EXITSESSION
| DND_MOZDRAG
;
994 *dragFlags
= DND_DISPATCHEVENT
| DND_EXITSESSION
| DND_NATIVEDRAG
;
999 // --------------------------------------------------------------------------
1001 // for native drags, clean up;
1002 // for all drags, signal that Moz is no longer in d&d mode
1004 NS_IMETHODIMP
nsDragService::ExitSession(uint32_t* dragFlags
)
1007 return NS_ERROR_FAILURE
;
1010 mSourceDataItems
= 0;
1014 // if we created a temp file, delete it
1016 DosDelete(gTempFile
);
1017 nsMemory::Free(gTempFile
);
1023 return NS_ERROR_FAILURE
;
1029 // --------------------------------------------------------------------------
1031 // If DropMsg() is presented with native data that has to be rendered,
1032 // the drop event & cleanup will be defered until the client's window
1033 // has received a render-complete msg.
1035 NS_IMETHODIMP
nsDragService::DropMsg(PDRAGINFO pdinfo
, HWND hwnd
,
1036 uint32_t* dragFlags
)
1038 if (!mDoingDrag
|| !dragFlags
|| !pdinfo
|| !DrgAccessDraginfo(pdinfo
))
1039 return NS_ERROR_FAILURE
;
1041 switch (pdinfo
->usOperation
) {
1043 SetDragAction(DRAGDROP_ACTION_MOVE
);
1046 SetDragAction(DRAGDROP_ACTION_COPY
);
1049 SetDragAction(DRAGDROP_ACTION_LINK
);
1051 default: // avoid "moving" (i.e. deleting) native text/objects
1053 SetDragAction(DRAGDROP_ACTION_MOVE
);
1055 SetDragAction(DRAGDROP_ACTION_COPY
);
1059 // if this is a native drag, move the source data to a transferable;
1060 // request rendering if needed
1061 nsresult rv
= NS_OK
;
1062 bool rendering
= false;
1064 rv
= NativeDrop( pdinfo
, hwnd
, &rendering
);
1066 // note: NativeDrop() sends an end-conversation msg to native
1067 // sources but nothing sends them to Mozilla - however, Mozilla
1068 // (i.e. nsDragService) doesn't need them, so...
1070 // if rendering, the action flags are off because we don't want
1071 // the client to do anything yet; the status flags are off because
1072 // we'll be exiting d&d mode before the next screen update occurs
1076 // otherwise, set the flags & free the native drag structures
1078 *dragFlags
= DND_EXITSESSION
;
1079 if (NS_SUCCEEDED(rv
)) {
1081 *dragFlags
|= DND_DISPATCHEVENT
| DND_INDROP
| DND_MOZDRAG
;
1083 *dragFlags
|= DND_DISPATCHEVENT
| DND_INDROP
| DND_NATIVEDRAG
;
1086 DrgDeleteDraginfoStrHandles(pdinfo
);
1087 DrgFreeDraginfo(pdinfo
);
1094 // --------------------------------------------------------------------------
1096 // Invoked by DropMsg to fill a transferable with native data;
1097 // if necessary, requests the source to render it.
1099 NS_IMETHODIMP
nsDragService::NativeDrop(PDRAGINFO pdinfo
, HWND hwnd
,
1104 nsresult rv
= NS_ERROR_FAILURE
;
1105 PDRAGITEM pditem
= DrgQueryDragitemPtr(pdinfo
, 0);
1109 nsXPIDLCString dropText
;
1110 bool isUrl
= DrgVerifyType(pditem
, "UniformResourceLocator");
1112 // identify format; the order of evaluation here is important
1114 // DRM_ATOM - DragText stores up to 255 chars in a Drg API atom
1115 // DRM_DTSHARE - DragText renders up to 1mb to named shared mem
1116 if (DrgVerifyRMF(pditem
, "DRM_ATOM", 0))
1117 rv
= GetAtom(pditem
->ulItemID
, getter_Copies(dropText
));
1119 if (DrgVerifyRMF(pditem
, "DRM_DTSHARE", 0)) {
1120 rv
= RenderToDTShare( pditem
, hwnd
);
1121 if (NS_SUCCEEDED(rv
))
1125 // DRM_OS2FILE - get the file's path or contents if it exists;
1126 // request rendering if it doesn't
1128 if (DrgVerifyRMF(pditem
, "DRM_OS2FILE", 0)) {
1129 bool isAlt
= (WinGetKeyState(HWND_DESKTOP
, VK_ALT
) & 0x8000);
1131 // the file has to be rendered - currently, we only present
1132 // its content, not its name, to Moz to avoid conflicts
1133 if (!pditem
->hstrContainerName
|| !pditem
->hstrSourceName
) {
1134 rv
= RenderToOS2File( pditem
, hwnd
);
1135 if (NS_SUCCEEDED(rv
))
1138 // for Url objects and 'Alt+Drop', get the file's contents;
1139 // otherwise, convert it's path to a Url
1141 nsXPIDLCString fileName
;
1142 if (NS_SUCCEEDED(GetFileName(pditem
, getter_Copies(fileName
)))) {
1144 rv
= GetFileContents(fileName
.get(), getter_Copies(dropText
));
1147 nsCOMPtr
<nsIFile
> file
;
1148 if (NS_SUCCEEDED(NS_NewNativeLocalFile(fileName
,
1149 true, getter_AddRefs(file
)))) {
1150 nsAutoCString textStr
;
1151 NS_GetURLSpecFromFile(file
, textStr
);
1152 if (!textStr
.IsEmpty()) {
1153 dropText
.Assign(ToNewCString(textStr
));
1157 } // filename as Url
1162 // if OK, put what data there is in the transferable; this could be
1163 // everything needed or just the title of a Url that needs rendering
1164 if (NS_SUCCEEDED(rv
)) {
1166 // for Urls, get the title & remove any linefeeds
1167 nsXPIDLCString titleText
;
1169 pditem
->hstrTargetName
&&
1170 NS_SUCCEEDED(GetAtom(pditem
->hstrTargetName
, getter_Copies(titleText
))))
1171 for (char* ptr
=strchr(titleText
.BeginWriting(),'\n'); ptr
; ptr
=strchr(ptr
, '\n'))
1174 rv
= NativeDataToTransferable( dropText
.get(), titleText
.get(), isUrl
);
1177 // except for renderings, tell the source we're done with the data
1179 DrgSendTransferMsg( pditem
->hwndItem
, DM_ENDCONVERSATION
,
1180 (MPARAM
)pditem
->ulItemID
,
1181 (MPARAM
)DMFL_TARGETSUCCESSFUL
);
1186 // --------------------------------------------------------------------------
1188 // Because RenderCompleteMsg() is called after the native (PM) drag
1189 // session has ended, all of the drag status flags should be off.
1191 // FYI... PM's asynchronous rendering mechanism is not compatible with
1192 // nsIDataFlavorProvider which expects data to be rendered synchronously
1194 NS_IMETHODIMP
nsDragService::RenderCompleteMsg(PDRAGTRANSFER pdxfer
,
1195 USHORT usResult
, uint32_t* dragFlags
)
1197 nsresult rv
= NS_ERROR_FAILURE
;
1198 if (!mDoingDrag
|| !pdxfer
)
1201 // this msg should never come from Moz - if it does, fail
1203 rv
= NativeRenderComplete(pdxfer
, usResult
);
1205 // DrgQueryDraginfoPtrFromDragitem() doesn't work - this does
1206 PDRAGINFO pdinfo
= (PDRAGINFO
)MAKEULONG(0x2c, HIUSHORT(pdxfer
->pditem
));
1208 DrgDeleteStrHandle(pdxfer
->hstrSelectedRMF
);
1209 DrgDeleteStrHandle(pdxfer
->hstrRenderToName
);
1210 DrgFreeDragtransfer(pdxfer
);
1212 // if the source is Moz, don't touch pdinfo - it's been freed already
1213 if (pdinfo
&& !mSourceNode
) {
1214 DrgDeleteDraginfoStrHandles(pdinfo
);
1215 DrgFreeDraginfo(pdinfo
);
1218 // this shouldn't happen
1220 return (ExitSession(dragFlags
));
1222 // d&d is over, so the DND_DragStatus flags should all be off
1223 *dragFlags
= DND_EXITSESSION
;
1224 if (NS_SUCCEEDED(rv
))
1225 *dragFlags
|= DND_DISPATCHEVENT
;
1227 // lie so the client will honor the exit-session flag
1231 // --------------------------------------------------------------------------
1233 // this is here to provide a false sense of symmetry with the other
1234 // method-pairs - rendered data always comes from a native source
1236 NS_IMETHODIMP
nsDragService::NativeRenderComplete(PDRAGTRANSFER pdxfer
,
1239 nsresult rv
= NS_ERROR_FAILURE
;
1242 // identify the rendering mechanism, then get the data
1243 if (NS_SUCCEEDED(GetAtom(pdxfer
->hstrSelectedRMF
, getter_Copies(rmf
)))) {
1244 nsXPIDLCString dropText
;
1245 if (!strcmp(rmf
.get(), DTSHARE_RMF
))
1246 rv
= RenderToDTShareComplete(pdxfer
, usResult
, getter_Copies(dropText
));
1248 if (!strcmp(rmf
.get(), OS2FILE_TXTRMF
) ||
1249 !strcmp(rmf
.get(), OS2FILE_UNKRMF
))
1250 rv
= RenderToOS2FileComplete(pdxfer
, usResult
, true,
1251 getter_Copies(dropText
));
1253 if (NS_SUCCEEDED(rv
)) {
1255 IsDataFlavorSupported(kURLMime
, &isUrl
);
1256 rv
= NativeDataToTransferable( dropText
.get(), 0, isUrl
);
1260 DrgSendTransferMsg(pdxfer
->hwndClient
, DM_ENDCONVERSATION
,
1261 (MPARAM
)pdxfer
->ulTargetInfo
,
1262 (MPARAM
)DMFL_TARGETSUCCESSFUL
);
1267 // --------------------------------------------------------------------------
1269 // fills the transferable created by NativeDragEnter with
1270 // the set of flavors and data the target will see onDrop
1272 NS_IMETHODIMP
nsDragService::NativeDataToTransferable( PCSZ pszText
,
1273 PCSZ pszTitle
, bool isUrl
)
1275 nsresult rv
= NS_ERROR_FAILURE
;
1276 // the transferable should have been created on DragEnter
1277 if (!mSourceDataItems
)
1280 nsCOMPtr
<nsISupports
> genericItem
;
1281 mSourceDataItems
->GetElementAt(0, getter_AddRefs(genericItem
));
1282 nsCOMPtr
<nsITransferable
> trans (do_QueryInterface(genericItem
));
1286 // remove invalid flavors
1288 trans
->RemoveDataFlavor(kURLMime
);
1289 trans
->RemoveDataFlavor(kHTMLMime
);
1292 // if there's no text, exit - but first see if we have the title of
1293 // a Url that needs to be rendered; if so, stash it for later use
1294 if (!pszText
|| !*pszText
) {
1295 if (isUrl
&& pszTitle
&& *pszTitle
) {
1296 nsXPIDLString outTitle
;
1297 if (CodepageToUnicode(nsDependentCString(pszTitle
),
1298 getter_Copies(outTitle
))) {
1299 nsCOMPtr
<nsISupportsString
> urlPrimitive(
1300 do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID
));
1301 if (urlPrimitive
) {
1302 urlPrimitive
->SetData(outTitle
);
1303 trans
->SetTransferData(kURLDescriptionMime
, urlPrimitive
,
1304 2*outTitle
.Length());
1311 nsXPIDLString outText
;
1312 if (!CodepageToUnicode(nsDependentCString(pszText
), getter_Copies(outText
)))
1317 // if no title was supplied, see if it was stored in the transferable
1318 nsXPIDLString outTitle
;
1319 if (pszTitle
&& *pszTitle
) {
1320 if (!CodepageToUnicode(nsDependentCString(pszTitle
),
1321 getter_Copies(outTitle
)))
1326 nsCOMPtr
<nsISupports
> genericData
;
1327 if (NS_SUCCEEDED(trans
->GetTransferData(kURLDescriptionMime
,
1328 getter_AddRefs(genericData
), &len
))) {
1329 nsCOMPtr
<nsISupportsString
> strObject(do_QueryInterface(genericData
));
1331 strObject
->GetData(outTitle
);
1335 // construct the Url flavor
1336 nsCOMPtr
<nsISupportsString
> urlPrimitive(
1337 do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID
));
1338 if (urlPrimitive
) {
1339 if (outTitle
.IsEmpty()) {
1340 urlPrimitive
->SetData(outText
);
1341 trans
->SetTransferData(kURLMime
, urlPrimitive
, 2*outText
.Length());
1344 nsString
urlStr( outText
+ NS_LITERAL_STRING("\n") + outTitle
);
1345 urlPrimitive
->SetData(urlStr
);
1346 trans
->SetTransferData(kURLMime
, urlPrimitive
, 2*urlStr
.Length());
1351 // construct the HTML flavor - for supported graphics,
1352 // use an IMG tag, for all others create a link
1353 nsCOMPtr
<nsISupportsString
> htmlPrimitive(
1354 do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID
));
1355 if (htmlPrimitive
) {
1357 nsCOMPtr
<nsIURI
> uri
;
1359 rv
= NS_ERROR_FAILURE
;
1360 if (NS_SUCCEEDED(NS_NewURI(getter_AddRefs(uri
), pszText
))) {
1361 nsCOMPtr
<nsIURL
> url (do_QueryInterface(uri
));
1363 nsAutoCString extension
;
1364 url
->GetFileExtension(extension
);
1365 if (!extension
.IsEmpty()) {
1366 if (extension
.LowerCaseEqualsLiteral("gif") ||
1367 extension
.LowerCaseEqualsLiteral("jpg") ||
1368 extension
.LowerCaseEqualsLiteral("png") ||
1369 extension
.LowerCaseEqualsLiteral("jpeg"))
1375 if (NS_SUCCEEDED(rv
))
1376 htmlStr
.Assign(NS_LITERAL_STRING("<img src=\"") +
1378 NS_LITERAL_STRING("\" alt=\"") +
1380 NS_LITERAL_STRING("\"/>") );
1382 htmlStr
.Assign(NS_LITERAL_STRING("<a href=\"") +
1384 NS_LITERAL_STRING("\">") +
1385 (outTitle
.IsEmpty() ? outText
: outTitle
) +
1386 NS_LITERAL_STRING("</a>") );
1388 htmlPrimitive
->SetData(htmlStr
);
1389 trans
->SetTransferData(kHTMLMime
, htmlPrimitive
, 2*htmlStr
.Length());
1394 // add the Text flavor
1395 nsCOMPtr
<nsISupportsString
> textPrimitive(
1396 do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID
));
1397 if (textPrimitive
) {
1398 textPrimitive
->SetData(nsDependentString(outText
));
1399 trans
->SetTransferData(kUnicodeMime
, textPrimitive
, 2*outText
.Length());
1403 // return OK if we put anything in the transferable
1407 // --------------------------------------------------------------------------
1409 // --------------------------------------------------------------------------
1411 // currently, the same filename is used for every render request;
1412 // it is deleted when the drag session ends
1414 nsresult
RenderToOS2File( PDRAGITEM pditem
, HWND hwnd
)
1416 nsresult rv
= NS_ERROR_FAILURE
;
1417 nsXPIDLCString fileName
;
1419 if (NS_SUCCEEDED(GetTempFileName(getter_Copies(fileName
)))) {
1420 const char * pszRMF
;
1421 if (DrgVerifyRMF(pditem
, "DRM_OS2FILE", "DRF_TEXT"))
1422 pszRMF
= OS2FILE_TXTRMF
;
1424 pszRMF
= OS2FILE_UNKRMF
;
1426 rv
= RequestRendering( pditem
, hwnd
, pszRMF
, fileName
.get());
1432 // --------------------------------------------------------------------------
1434 // return a buffer with the rendered file's Url or contents
1436 nsresult
RenderToOS2FileComplete(PDRAGTRANSFER pdxfer
, USHORT usResult
,
1437 bool content
, char** outText
)
1439 nsresult rv
= NS_ERROR_FAILURE
;
1441 // for now, override content flag & always return content
1444 if (usResult
& DMFL_RENDEROK
) {
1445 if (NS_SUCCEEDED(GetAtom( pdxfer
->hstrRenderToName
, &gTempFile
))) {
1447 rv
= GetFileContents(gTempFile
, outText
);
1449 nsCOMPtr
<nsIFile
> file
;
1450 if (NS_SUCCEEDED(NS_NewNativeLocalFile(nsDependentCString(gTempFile
),
1451 true, getter_AddRefs(file
)))) {
1452 nsAutoCString textStr
;
1453 NS_GetURLSpecFromFile(file
, textStr
);
1454 if (!textStr
.IsEmpty()) {
1455 *outText
= ToNewCString(textStr
);
1462 // gTempFile will be deleted when ExitSession() is called
1467 // --------------------------------------------------------------------------
1469 // DTShare uses 1mb of uncommitted named-shared memory
1470 // (next time I'll do it differently - rw)
1472 nsresult
RenderToDTShare( PDRAGITEM pditem
, HWND hwnd
)
1477 #ifdef MOZ_OS2_HIGH_MEMORY
1478 APIRET rc
= DosAllocSharedMem( &pMem
, DTSHARE_NAME
, 0x100000,
1479 PAG_WRITE
| PAG_READ
| OBJ_ANY
);
1480 if (rc
!= NO_ERROR
&&
1481 rc
!= ERROR_ALREADY_EXISTS
) { // Did the kernel handle OBJ_ANY?
1482 // Try again without OBJ_ANY and if the first failure was not caused
1483 // by OBJ_ANY then we will get the same failure, else we have taken
1484 // care of pre-FP13 systems where the kernel couldn't handle it.
1485 rc
= DosAllocSharedMem( &pMem
, DTSHARE_NAME
, 0x100000,
1486 PAG_WRITE
| PAG_READ
);
1489 APIRET rc
= DosAllocSharedMem( &pMem
, DTSHARE_NAME
, 0x100000,
1490 PAG_WRITE
| PAG_READ
);
1493 if (rc
== ERROR_ALREADY_EXISTS
)
1494 rc
= DosGetNamedSharedMem( &pMem
, DTSHARE_NAME
,
1495 PAG_WRITE
| PAG_READ
);
1497 rv
= NS_ERROR_FAILURE
;
1499 rv
= RequestRendering( pditem
, hwnd
, DTSHARE_RMF
, DTSHARE_NAME
);
1504 // --------------------------------------------------------------------------
1506 // return a buffer with the rendered text
1508 nsresult
RenderToDTShareComplete(PDRAGTRANSFER pdxfer
, USHORT usResult
,
1511 nsresult rv
= NS_ERROR_FAILURE
;
1515 APIRET rc
= DosGetNamedSharedMem( &pMem
, DTSHARE_NAME
, PAG_WRITE
| PAG_READ
);
1518 if (usResult
& DMFL_RENDEROK
) {
1519 pszText
= (char*)nsMemory::Alloc( ((ULONG
*)pMem
)[0] + 1);
1521 strcpy(pszText
, &((char*)pMem
)[sizeof(ULONG
)] );
1522 RemoveCarriageReturns(pszText
);
1527 // using DosGetNamedSharedMem() on memory we allocated appears
1528 // to increment its usage ctr, so we have to free it 2x
1536 // --------------------------------------------------------------------------
1538 // a generic request dispatcher
1540 nsresult
RequestRendering( PDRAGITEM pditem
, HWND hwnd
, PCSZ pRMF
, PCSZ pName
)
1542 PDRAGTRANSFER pdxfer
= DrgAllocDragtransfer( 1);
1544 return NS_ERROR_FAILURE
;
1546 pdxfer
->cb
= sizeof(DRAGTRANSFER
);
1547 pdxfer
->hwndClient
= hwnd
;
1548 pdxfer
->pditem
= pditem
;
1549 pdxfer
->hstrSelectedRMF
= DrgAddStrHandle( pRMF
);
1550 pdxfer
->hstrRenderToName
= 0;
1551 pdxfer
->ulTargetInfo
= pditem
->ulItemID
;
1552 pdxfer
->usOperation
= (USHORT
)DO_COPY
;
1553 pdxfer
->fsReply
= 0;
1555 // send the msg before setting a render-to name
1556 if (pditem
->fsControl
& DC_PREPAREITEM
)
1557 DrgSendTransferMsg( pditem
->hwndItem
, DM_RENDERPREPARE
, (MPARAM
)pdxfer
, 0);
1559 pdxfer
->hstrRenderToName
= DrgAddStrHandle( pName
);
1561 // send the msg after setting a render-to name
1562 if ((pditem
->fsControl
& (DC_PREPARE
| DC_PREPAREITEM
)) == DC_PREPARE
)
1563 DrgSendTransferMsg( pditem
->hwndItem
, DM_RENDERPREPARE
, (MPARAM
)pdxfer
, 0);
1565 // ask the source to render the selected item
1566 if (!DrgSendTransferMsg( pditem
->hwndItem
, DM_RENDER
, (MPARAM
)pdxfer
, 0))
1567 return NS_ERROR_FAILURE
;
1572 // --------------------------------------------------------------------------
1574 // return a ptr to a buffer containing the text associated
1575 // with a drag atom; the caller frees the buffer
1577 nsresult
GetAtom( ATOM aAtom
, char** outText
)
1579 nsresult rv
= NS_ERROR_FAILURE
;
1581 ULONG ulInLength
= DrgQueryStrNameLen(aAtom
);
1583 char* pszText
= (char*)nsMemory::Alloc(++ulInLength
);
1585 DrgQueryStrName(aAtom
, ulInLength
, pszText
);
1586 RemoveCarriageReturns(pszText
);
1594 // --------------------------------------------------------------------------
1596 // return a ptr to a buffer containing the file path specified
1597 // in the dragitem; the caller frees the buffer
1599 nsresult
GetFileName(PDRAGITEM pditem
, char** outText
)
1601 nsresult rv
= NS_ERROR_FAILURE
;
1602 ULONG cntCnr
= DrgQueryStrNameLen(pditem
->hstrContainerName
);
1603 ULONG cntSrc
= DrgQueryStrNameLen(pditem
->hstrSourceName
);
1605 char* pszText
= (char*)nsMemory::Alloc(cntCnr
+cntSrc
+1);
1607 DrgQueryStrName(pditem
->hstrContainerName
, cntCnr
+1, pszText
);
1608 DrgQueryStrName(pditem
->hstrSourceName
, cntSrc
+1, &pszText
[cntCnr
]);
1609 pszText
[cntCnr
+cntSrc
] = 0;
1616 // --------------------------------------------------------------------------
1618 // read the file; if successful, return a ptr to its contents;
1619 // the caller frees the buffer
1621 nsresult
GetFileContents(PCSZ pszPath
, char** outText
)
1623 nsresult rv
= NS_ERROR_FAILURE
;
1627 FILE *fp
= fopen(pszPath
, "r");
1629 fseek(fp
, 0, SEEK_END
);
1630 ULONG filesize
= ftell(fp
);
1631 fseek(fp
, 0, SEEK_SET
);
1633 size_t readsize
= (size_t)filesize
;
1634 pszText
= (char*)nsMemory::Alloc(readsize
+1);
1636 readsize
= fread((void *)pszText
, 1, readsize
, fp
);
1638 pszText
[readsize
] = '\0';
1639 RemoveCarriageReturns(pszText
);
1644 nsMemory::Free(pszText
);
1656 // --------------------------------------------------------------------------
1658 // currently, this returns the same path & filename every time
1660 nsresult
GetTempFileName(char** outText
)
1662 char * pszText
= (char*)nsMemory::Alloc(CCHMAXPATH
);
1664 return NS_ERROR_FAILURE
;
1666 const char * pszPath
;
1667 if (!DosScanEnv("TEMP", &pszPath
) || !DosScanEnv("TMP", &pszPath
))
1668 strcpy(pszText
, pszPath
);
1670 if (DosQueryPathInfo(".\\.", FIL_QUERYFULLNAME
, pszText
, CCHMAXPATH
))
1673 strcat(pszText
, "\\");
1674 strcat(pszText
, OS2FILE_NAME
);
1680 // --------------------------------------------------------------------------
1681 // --------------------------------------------------------------------------
1683 // set the file's .TYPE and .SUBJECT EAs; since this is non-critical
1684 // (though highly desirable), errors aren't reported
1686 void SaveTypeAndSource(nsIFile
*file
, nsIDOMDocument
*domDoc
,
1692 nsCOMPtr
<nsILocalFileOS2
> os2file(do_QueryInterface(file
));
1694 NS_FAILED(os2file
->SetFileTypes(nsDependentCString(pszType
))))
1697 // since the filetype has to be saved, this function
1698 // may be called even if there isn't any document
1702 nsCOMPtr
<nsIDocument
> doc(do_QueryInterface(domDoc
));
1706 // this gets the top-level content URL when frames are used;
1707 // when nextDoc is zero, currDoc is the browser window, and
1708 // prevDoc points to the content;
1709 // note: neither GetParentDocument() nor GetDocumentURI()
1710 // refcount the pointers they return, so nsCOMPtr isn't needed
1711 nsIDocument
*prevDoc
;
1712 nsIDocument
*currDoc
= doc
;
1713 nsIDocument
*nextDoc
= doc
;
1717 nextDoc
= currDoc
->GetParentDocument();
1720 nsIURI
* srcUri
= prevDoc
->GetDocumentURI();
1724 // identifying content as coming from chrome is none too useful...
1725 bool ignore
= false;
1726 srcUri
->SchemeIs("chrome", &ignore
);
1731 srcUri
->GetSpec(url
);
1732 os2file
->SetFileSource(url
);
1737 // --------------------------------------------------------------------------
1739 // to do: this needs to take into account the current page's encoding
1740 // if it is different than the PM codepage
1742 int UnicodeToCodepage(const nsAString
& aString
, char **aResult
)
1744 nsAutoCharBuffer buffer
;
1746 WideCharToMultiByte(0, PromiseFlatString(aString
).get(), aString
.Length(),
1748 *aResult
= ToNewCString(nsDependentCString(buffer
.Elements()));
1752 // --------------------------------------------------------------------------
1754 int CodepageToUnicode(const nsACString
& aString
, char16_t
**aResult
)
1756 nsAutoChar16Buffer buffer
;
1758 MultiByteToWideChar(0, PromiseFlatCString(aString
).get(),
1759 aString
.Length(), buffer
, bufLength
);
1760 *aResult
= ToNewUnicode(nsDependentString(buffer
.Elements()));
1764 // --------------------------------------------------------------------------
1766 // removes carriage returns in-place; it should only be used on
1767 // raw text buffers that haven't been assigned to a string object
1769 void RemoveCarriageReturns(char * pszText
)
1776 target
= strchr(pszText
, 0x0d);
1780 source
= target
+ 1;
1782 while ((next
= strchr(source
, 0x0d)) != 0) {
1784 cnt
= next
- source
;
1785 memcpy(target
, source
, cnt
);
1791 strcpy(target
, source
);
1795 // --------------------------------------------------------------------------