From b7030a74dd5208afc75be42c81201cfa72ebbcc9 Mon Sep 17 00:00:00 2001 From: Tomeu Vizoso Date: Tue, 17 Apr 2007 16:53:34 -0300 Subject: [PATCH] Drag images out of mozilla. --- browser/GeckoBrowserPersist.cpp | 185 +++++++++++++++++++++ browser/GeckoBrowserPersist.h | 19 +++ browser/GeckoDocumentObject.cpp | 187 +++++++++++++++++++++ browser/GeckoDocumentObject.h | 29 ++++ browser/GeckoDragDropHooks.cpp | 185 +++++++++++++++++++++ browser/GeckoDragDropHooks.h | 25 +++ browser/Makefile.am | 9 + browser/sugar-browser.cpp | 218 ++++++------------------- services/clipboard/clipboardobject.py | 11 ++ services/clipboard/clipboardservice.py | 3 +- services/clipboard/typeregistry.py | 21 +++ shell/view/frame/clipboardbox.py | 46 ++++-- 12 files changed, 753 insertions(+), 185 deletions(-) create mode 100644 browser/GeckoBrowserPersist.cpp create mode 100644 browser/GeckoBrowserPersist.h create mode 100644 browser/GeckoDocumentObject.cpp create mode 100644 browser/GeckoDocumentObject.h create mode 100644 browser/GeckoDragDropHooks.cpp create mode 100644 browser/GeckoDragDropHooks.h diff --git a/browser/GeckoBrowserPersist.cpp b/browser/GeckoBrowserPersist.cpp new file mode 100644 index 00000000..48de4d11 --- /dev/null +++ b/browser/GeckoBrowserPersist.cpp @@ -0,0 +1,185 @@ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "GeckoBrowserPersist.h" + +GeckoBrowserPersist::GeckoBrowserPersist(SugarBrowser *browser) + : mBrowser(browser) +{ +} + +GeckoBrowserPersist::~GeckoBrowserPersist() +{ +} + +static nsresult +NewURI(const char *uri, nsIURI **result) +{ + nsresult rv; + + nsCOMPtr mgr; + NS_GetServiceManager (getter_AddRefs (mgr)); + NS_ENSURE_TRUE(mgr, FALSE); + + nsCOMPtr ioService; + rv = mgr->GetServiceByContractID ("@mozilla.org/network/io-service;1", + NS_GET_IID (nsIIOService), + getter_AddRefs(ioService)); + NS_ENSURE_SUCCESS(rv, FALSE); + + nsCString cSpec(uri); + return ioService->NewURI (cSpec, nsnull, nsnull, result); +} + +static nsresult +GetPostData(SugarBrowser *browser, nsIInputStream **postData) +{ +#ifdef HAVE_NS_WEB_BROWSER + nsCOMPtr webBrowser; + gtk_moz_embed_get_nsIWebBrowser(GTK_MOZ_EMBED(browser), + getter_AddRefs(webBrowser)); + NS_ENSURE_TRUE(webBrowser, NS_ERROR_FAILURE); + + nsCOMPtr webNav(do_QueryInterface(webBrowser)); + NS_ENSURE_TRUE(webNav, NS_ERROR_FAILURE); + + PRInt32 sindex; + + nsCOMPtr sessionHistory; + webNav->GetSessionHistory(getter_AddRefs(sessionHistory)); + NS_ENSURE_TRUE(sessionHistory, NS_ERROR_FAILURE); + + nsCOMPtr entry; + sessionHistory->GetIndex(&sindex); + sessionHistory->GetEntryAtIndex(sindex, PR_FALSE, getter_AddRefs(entry)); + + nsCOMPtr shEntry(do_QueryInterface(entry)); + if (shEntry) { + shEntry->GetPostData(postData); + } + + return NS_OK; +#endif + return NS_ERROR_NOT_IMPLEMENTED; +} + +bool +GeckoBrowserPersist::SaveURI(const char *uri, const char *filename) +{ + nsresult rv; + + nsCOMPtr sourceURI; + rv = NewURI(uri, getter_AddRefs(sourceURI)); + NS_ENSURE_SUCCESS(rv, FALSE); + + nsCOMPtr destFile = do_CreateInstance("@mozilla.org/file/local;1"); + NS_ENSURE_TRUE(destFile, FALSE); + + destFile->InitWithNativePath(nsCString(filename)); + + nsCOMPtr postData; + GetPostData(mBrowser, getter_AddRefs(postData)); + + nsCOMPtr inputChannel; + rv = NS_NewChannel(getter_AddRefs(inputChannel), sourceURI, + nsnull, nsnull, nsnull, nsIRequest::LOAD_NORMAL); + NS_ENSURE_SUCCESS(rv, FALSE); + + nsCOMPtr httpChannel(do_QueryInterface(inputChannel)); + if (httpChannel) { + nsCOMPtr stream(do_QueryInterface(postData)); + if (stream) + { + // Rewind the postdata stream + stream->Seek(nsISeekableStream::NS_SEEK_SET, 0); + nsCOMPtr uploadChannel(do_QueryInterface(httpChannel)); + NS_ASSERTION(uploadChannel, "http must support nsIUploadChannel"); + // Attach the postdata to the http channel + uploadChannel->SetUploadStream(postData, EmptyCString(), -1); + } + } + + nsCOMPtr stream; + rv = inputChannel->Open(getter_AddRefs(stream)); + NS_ENSURE_SUCCESS(rv, FALSE); + + nsCOMPtr fileOutputStream = + do_CreateInstance(NS_LOCALFILEOUTPUTSTREAM_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, FALSE); + + rv = fileOutputStream->Init(destFile, -1, -1, 0); + NS_ENSURE_SUCCESS(rv, FALSE); + + // Read data from the input and write to the output + char buffer[8192]; + PRUint32 bytesRead; + PRUint32 bytesRemaining; + PRBool cancel = PR_FALSE; + PRBool readError; + + rv = stream->Available(&bytesRemaining); + NS_ENSURE_SUCCESS(rv, FALSE); + + while (!cancel && bytesRemaining) + { + readError = PR_TRUE; + rv = stream->Read(buffer, PR_MIN(sizeof(buffer), bytesRemaining), &bytesRead); + if (NS_SUCCEEDED(rv)) + { + readError = PR_FALSE; + // Write out the data until something goes wrong, or, it is + // all written. We loop because for some errors (e.g., disk + // full), we get NS_OK with some bytes written, then an error. + // So, we want to write again in that case to get the actual + // error code. + const char *bufPtr = buffer; // Where to write from. + while (NS_SUCCEEDED(rv) && bytesRead) + { + PRUint32 bytesWritten = 0; + rv = fileOutputStream->Write(bufPtr, bytesRead, &bytesWritten); + if (NS_SUCCEEDED(rv)) + { + bytesRead -= bytesWritten; + bufPtr += bytesWritten; + bytesRemaining -= bytesWritten; + // Force an error if (for some reason) we get NS_OK but + // no bytes written. + if (!bytesWritten) + { + rv = NS_ERROR_FAILURE; + cancel = PR_TRUE; + } + } + else + { + // Disaster - can't write out the bytes - disk full / permission? + cancel = PR_TRUE; + } + } + } + else + { + // Disaster - can't read the bytes - broken link / file error? + cancel = PR_TRUE; + } + } + NS_ENSURE_SUCCESS(rv, FALSE); + + stream->Close(); + + return TRUE; +} diff --git a/browser/GeckoBrowserPersist.h b/browser/GeckoBrowserPersist.h new file mode 100644 index 00000000..e9767893 --- /dev/null +++ b/browser/GeckoBrowserPersist.h @@ -0,0 +1,19 @@ +#ifndef __GECKO_BROWSER_PERSIST_H__ +#define __GECKO_BROWSER_PERSIST_H__ + +#include "sugar-browser.h" + +class GeckoBrowserPersist +{ +public: + GeckoBrowserPersist(SugarBrowser *browser); + ~GeckoBrowserPersist(); + + bool SaveURI(const char *uri, const char *filename); +private: + SugarBrowser *mBrowser; +protected: + /* additional members */ +}; + +#endif // __GECKO_BROWSER_PERSIST_H__ diff --git a/browser/GeckoDocumentObject.cpp b/browser/GeckoDocumentObject.cpp new file mode 100644 index 00000000..6f034e18 --- /dev/null +++ b/browser/GeckoDocumentObject.cpp @@ -0,0 +1,187 @@ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "GeckoDocumentObject.h" +#include "GeckoBrowserPersist.h" + +GeckoDocumentObject::GeckoDocumentObject(SugarBrowser *browser, nsIDOMNode *node) + : mBrowser(browser), + mNode(node), + mImage(NULL) +{ +} + +GeckoDocumentObject::~GeckoDocumentObject() +{ +} + +bool GeckoDocumentObject::IsImage() +{ + if(mImage) { + return true; + } + + nsresult rv; + + PRUint16 type; + rv = mNode->GetNodeType(&type); + if(NS_FAILED(rv)) return rv; + + nsCOMPtr element = do_QueryInterface(mNode); + if ((nsIDOMNode::ELEMENT_NODE == type) && element) { + nsString uTag; + rv = element->GetLocalName(uTag); + if(NS_FAILED(rv)) return rv; + + nsCString tag; + NS_UTF16ToCString (uTag, NS_CSTRING_ENCODING_UTF8, tag); + + if (g_ascii_strcasecmp (tag.get(), "img") == 0) { + nsCOMPtr imagePtr; + imagePtr = do_QueryInterface(mNode, &rv); + if(NS_FAILED(rv)) return rv; + + mImage = imagePtr; + + return true; + } + } + + return false; +} + +static nsresult +NewURI(const char *uri, nsIURI **result) +{ + nsresult rv; + + nsCOMPtr mgr; + NS_GetServiceManager (getter_AddRefs (mgr)); + NS_ENSURE_TRUE(mgr, FALSE); + + nsCOMPtr ioService; + rv = mgr->GetServiceByContractID ("@mozilla.org/network/io-service;1", + NS_GET_IID (nsIIOService), + getter_AddRefs(ioService)); + NS_ENSURE_SUCCESS(rv, FALSE); + + nsCString cSpec(uri); + return ioService->NewURI (cSpec, nsnull, nsnull, result); +} + +static nsresult +FilenameFromContentDisposition(nsCString contentDisposition, nsCString &fileName) +{ + nsresult rv; + nsCString fallbackCharset; + + nsCOMPtr mimehdrpar = + do_GetService("@mozilla.org/network/mime-hdrparam;1"); + NS_ENSURE_TRUE(mimehdrpar, NS_ERROR_FAILURE); + + nsString aFileName; + rv = mimehdrpar->GetParameter (contentDisposition, "filename", + fallbackCharset, PR_TRUE, nsnull, + aFileName); + + if (NS_FAILED(rv) || !fileName.Length()) { + rv = mimehdrpar->GetParameter (contentDisposition, "name", + fallbackCharset, PR_TRUE, nsnull, + aFileName); + } + + if (NS_SUCCEEDED(rv) && fileName.Length()) { + NS_UTF16ToCString (aFileName, NS_CSTRING_ENCODING_UTF8, fileName); + } + + return NS_OK; +} + +char * +GeckoDocumentObject::GetImageName() +{ + if(!IsImage()) { + return NULL; + } + + nsresult rv; + char *imgURIStr = GetImageURI(); + + nsCOMPtr imageURI; + rv = NewURI(imgURIStr, getter_AddRefs(imageURI)); + NS_ENSURE_SUCCESS(rv, NULL); + + nsCOMPtr mgr; + NS_GetServiceManager (getter_AddRefs (mgr)); + NS_ENSURE_TRUE(mgr, NULL); + + nsCOMPtr imgCache; + rv = mgr->GetServiceByContractID("@mozilla.org/image/cache;1", + NS_GET_IID (imgICache), + getter_AddRefs(imgCache)); + NS_ENSURE_SUCCESS(rv, NULL); + + nsCOMPtr imgProperties; + imgCache->FindEntryProperties(imageURI, getter_AddRefs(imgProperties)); + if (imgProperties) { + nsCOMPtr dispositionCString; + imgProperties->Get("content-disposition", + NS_GET_IID(nsISupportsCString), + getter_AddRefs(dispositionCString)); + if (dispositionCString) { + nsCString contentDisposition; + dispositionCString->GetData(contentDisposition); + FilenameFromContentDisposition(contentDisposition, mImageName); + } + } + + if (!mImageName.Length()) { + nsCOMPtr url(do_QueryInterface(imageURI)); + if (url) { + url->GetFileName(mImageName); + } + } + + return mImageName.Length() ? g_strdup(mImageName.get()) : NULL; +} + +char * +GeckoDocumentObject::GetImageURI() +{ + if(!IsImage()) { + return NULL; + } + + if(!mImageURI.Length()) { + nsresult rv; + nsString img; + rv = mImage->GetSrc(img); + if (NS_FAILED(rv)) return NULL; + + NS_UTF16ToCString (img, NS_CSTRING_ENCODING_UTF8, mImageURI); + } + return g_strdup(mImageURI.get()); +} + +bool +GeckoDocumentObject::SaveImage(const char *filename) +{ + GeckoBrowserPersist browserPersist(mBrowser); + return browserPersist.SaveURI(mImageURI.get(), filename); +} diff --git a/browser/GeckoDocumentObject.h b/browser/GeckoDocumentObject.h new file mode 100644 index 00000000..05328e55 --- /dev/null +++ b/browser/GeckoDocumentObject.h @@ -0,0 +1,29 @@ +#ifndef __GECKO_DOCUMENT_OBJECT_H__ +#define __GECKO_DOCUMENT_OBJECT_H__ + +#include +#include + +#include "sugar-browser.h" + +class GeckoDocumentObject +{ +public: + GeckoDocumentObject(SugarBrowser *browser, nsIDOMNode *node); + ~GeckoDocumentObject(); + + bool IsImage(); + char *GetImageURI(); + char *GetImageName(); + bool SaveImage(const char *filename); +private: + SugarBrowser *mBrowser; + nsCOMPtr mNode; + nsCOMPtr mImage; + nsCString mImageURI; + nsCString mImageName; +protected: + /* additional members */ +}; + +#endif // __GECKO_DOCUMENT_OBJECT_H__ diff --git a/browser/GeckoDragDropHooks.cpp b/browser/GeckoDragDropHooks.cpp new file mode 100644 index 00000000..425ee455 --- /dev/null +++ b/browser/GeckoDragDropHooks.cpp @@ -0,0 +1,185 @@ +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "GeckoDragDropHooks.h" +#include "GeckoDocumentObject.h" + +#define TEXT_URI_LIST "text/uri-list" +#define TEXT_X_MOZ_URL "text/x-moz-url" +#define FILE_LOCALHOST "file://" + +//***************************************************************************** +// UriListDataProvider +//***************************************************************************** + +class UriListDataProvider : public nsIFlavorDataProvider +{ +public: + UriListDataProvider(GeckoDocumentObject *mDocumentObject); + virtual ~UriListDataProvider(); + NS_DECL_ISUPPORTS + NS_DECL_NSIFLAVORDATAPROVIDER +private: + GeckoDocumentObject *mDocumentObject; + nsCString mFilePath; +}; + +//***************************************************************************** + +NS_IMPL_ISUPPORTS1(UriListDataProvider, nsIFlavorDataProvider) + +UriListDataProvider::UriListDataProvider(GeckoDocumentObject *documentObject) + : mDocumentObject(documentObject) +{ +} + +UriListDataProvider::~UriListDataProvider() +{ + if(mFilePath.Length()) { + remove(mFilePath.get()); + } + + delete mDocumentObject; +} + +NS_IMETHODIMP +UriListDataProvider::GetFlavorData(nsITransferable *aTransferable, + const char *aFlavor, nsISupports **aData, + PRUint32 *aDataLen) +{ + NS_ENSURE_ARG_POINTER(aData && aDataLen); + + nsresult rv = NS_ERROR_NOT_IMPLEMENTED; + char *image_name; + timeval timestamp; + + *aData = nsnull; + *aDataLen = 0; + + if(g_ascii_strcasecmp(aFlavor, TEXT_URI_LIST) != 0) { + return rv; + } + + gettimeofday(×tamp, NULL); + + mFilePath.Append(g_get_tmp_dir()); + mFilePath.Append("/"); + mFilePath.AppendInt(timestamp.tv_sec); + mFilePath.AppendInt(timestamp.tv_usec); + + image_name = mDocumentObject->GetImageName(); + mFilePath.Append(image_name); + g_free(image_name); + + if(!mDocumentObject->SaveImage(mFilePath.get())) { + return NS_ERROR_FAILURE; + } + + nsCString localURI(FILE_LOCALHOST); + localURI.Append(mFilePath); + + nsString localURI16; + NS_CStringToUTF16(localURI, NS_CSTRING_ENCODING_UTF8, localURI16); + + nsCOMPtr localURIData(do_CreateInstance( + "@mozilla.org/supports-string;1", &rv)); + if(NS_FAILED(rv)) return rv; + + rv = localURIData->SetData(localURI16); + if(NS_FAILED(rv)) return rv; + + CallQueryInterface(localURIData, aData); + *aDataLen = sizeof(nsISupportsString*); + + // FIXME: Why do we need this? Is there a leak in mozilla? + this->Release(); + + return rv; +} + +//***************************************************************************** +// GeckoDragDropHooks +//***************************************************************************** + +NS_IMPL_ISUPPORTS1(GeckoDragDropHooks, nsIClipboardDragDropHooks) + +GeckoDragDropHooks::GeckoDragDropHooks(SugarBrowser *browser) + : mBrowser(browser) +{ +} + +GeckoDragDropHooks::~GeckoDragDropHooks() +{ +} + +NS_IMETHODIMP +GeckoDragDropHooks::AllowStartDrag(nsIDOMEvent *event, PRBool *_retval) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +GeckoDragDropHooks::AllowDrop(nsIDOMEvent *event, nsIDragSession *session, + PRBool *_retval) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +GeckoDragDropHooks::OnCopyOrDrag(nsIDOMEvent *aEvent, nsITransferable *trans, + PRBool *_retval) +{ + nsresult rv; + + *_retval = true; + + nsCOMPtr mouseEvent; + mouseEvent = do_QueryInterface(aEvent, &rv); + if(NS_FAILED(rv)) return rv; + + nsCOMPtr eventTarget; + rv = mouseEvent->GetTarget(getter_AddRefs(eventTarget)); + if(NS_FAILED(rv)) return rv; + + nsCOMPtr targetNode; + targetNode = do_QueryInterface(eventTarget, &rv); + if(NS_FAILED(rv)) return rv; + + GeckoDocumentObject *documentObject = new GeckoDocumentObject(mBrowser, + targetNode); + if(documentObject->IsImage()) { + rv = trans->RemoveDataFlavor(TEXT_X_MOZ_URL); + if(NS_FAILED(rv)) return rv; + + rv = trans->AddDataFlavor(TEXT_URI_LIST); + if(NS_FAILED(rv)) return rv; + + UriListDataProvider *rawPtr = new UriListDataProvider(documentObject); + nsCOMPtr dataProvider(do_QueryInterface(rawPtr, &rv)); + if(NS_FAILED(rv)) return rv; + + rv = trans->SetTransferData(TEXT_URI_LIST, dataProvider, 0); + if(NS_FAILED(rv)) return rv; + } + + return rv; +} + +NS_IMETHODIMP +GeckoDragDropHooks::OnPasteOrDrop(nsIDOMEvent *event, nsITransferable *trans, + PRBool *_retval) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} diff --git a/browser/GeckoDragDropHooks.h b/browser/GeckoDragDropHooks.h new file mode 100644 index 00000000..c551c0e5 --- /dev/null +++ b/browser/GeckoDragDropHooks.h @@ -0,0 +1,25 @@ +#ifndef __GECKO_DRAG_DROP_HOOKS_H__ +#define __GECKO_DRAG_DROP_HOOKS_H__ + +#include + +#include "sugar-browser.h" + +class GeckoDragDropHooks : public nsIClipboardDragDropHooks +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSICLIPBOARDDRAGDROPHOOKS + + GeckoDragDropHooks(SugarBrowser *browser); + +private: + ~GeckoDragDropHooks(); + + SugarBrowser *mBrowser; + +protected: + /* additional members */ +}; + +#endif // __GECKO_DRAG_DROP_HOOKS_H__ diff --git a/browser/Makefile.am b/browser/Makefile.am index ae013e01..b4185837 100644 --- a/browser/Makefile.am +++ b/browser/Makefile.am @@ -3,6 +3,7 @@ libsugarbrowser_la_CPPFLAGS = \ $(LIB_CFLAGS) \ $(GECKO_CFLAGS) \ $(NSPR_CFLAGS) \ + -I$(MOZILLA_INCLUDE_DIR)/commandhandler \ -I$(MOZILLA_INCLUDE_DIR)/dom \ -I$(MOZILLA_INCLUDE_DIR)/docshell \ -I$(MOZILLA_INCLUDE_DIR)/exthandler \ @@ -15,6 +16,8 @@ libsugarbrowser_la_CPPFLAGS = \ -I$(MOZILLA_INCLUDE_DIR)/uriloader \ -I$(MOZILLA_INCLUDE_DIR)/webbrwsr \ -I$(MOZILLA_INCLUDE_DIR)/webbrowserpersist \ + -I$(MOZILLA_INCLUDE_DIR)/widget \ + -I$(MOZILLA_INCLUDE_DIR)/xpcom \ -DPLUGIN_DIR=\"$(libdir)/mozilla/plugins\" \ -DSHARE_DIR=\"$(pkgdatadir)\" @@ -26,8 +29,14 @@ libsugarbrowser_la_LIBADD = \ libsugarbrowser_la_SOURCES = \ $(BUILT_SOURCES) \ + GeckoBrowserPersist.h \ + GeckoBrowserPersist.cpp \ GeckoContentHandler.h \ GeckoContentHandler.cpp \ + GeckoDocumentObject.h \ + GeckoDocumentObject.cpp \ + GeckoDragDropHooks.h \ + GeckoDragDropHooks.cpp \ GeckoDownload.h \ GeckoDownload.cpp \ sugar-address-entry.c \ diff --git a/browser/sugar-browser.cpp b/browser/sugar-browser.cpp index cd455b6f..270631b1 100644 --- a/browser/sugar-browser.cpp +++ b/browser/sugar-browser.cpp @@ -23,6 +23,9 @@ #include "sugar-marshal.h" #include "GeckoContentHandler.h" #include "GeckoDownload.h" +#include "GeckoDragDropHooks.h" +#include "GeckoDocumentObject.h" +#include "GeckoBrowserPersist.h" #include #include @@ -56,6 +59,8 @@ #include #include #include +#include +#include enum { PROP_0, @@ -75,6 +80,8 @@ enum { static guint signals[N_SIGNALS]; +static GObjectClass *parent_class = NULL; + static const nsModuleComponentInfo sSugarComponents[] = { { "Gecko Content Handler", @@ -210,25 +217,6 @@ sugar_browser_shutdown(void) G_DEFINE_TYPE(SugarBrowser, sugar_browser, GTK_TYPE_MOZ_EMBED) -static nsresult -NewURI(const char *uri, nsIURI **result) -{ - nsresult rv; - - nsCOMPtr mgr; - NS_GetServiceManager (getter_AddRefs (mgr)); - NS_ENSURE_TRUE(mgr, FALSE); - - nsCOMPtr ioService; - rv = mgr->GetServiceByContractID ("@mozilla.org/network/io-service;1", - NS_GET_IID (nsIIOService), - getter_AddRefs(ioService)); - NS_ENSURE_SUCCESS(rv, FALSE); - - nsCString cSpec(uri); - return ioService->NewURI (cSpec, nsnull, nsnull, result); -} - static nsresult FilenameFromContentDisposition(nsCString contentDisposition, nsCString &fileName) { @@ -258,38 +246,6 @@ FilenameFromContentDisposition(nsCString contentDisposition, nsCString &fileName return NS_OK; } -static nsresult -ImageNameFromCache(nsIURI *imgURI, nsCString &imgName) -{ - nsresult rv; - - nsCOMPtr mgr; - NS_GetServiceManager (getter_AddRefs (mgr)); - NS_ENSURE_TRUE(mgr, NS_ERROR_FAILURE); - - nsCOMPtr imgCache; - rv = mgr->GetServiceByContractID("@mozilla.org/image/cache;1", - NS_GET_IID (imgICache), - getter_AddRefs(imgCache)); - NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); - - nsCOMPtr imgProperties; - imgCache->FindEntryProperties(imgURI, getter_AddRefs(imgProperties)); - if (imgProperties) { - nsCOMPtr dispositionCString; - imgProperties->Get("content-disposition", - NS_GET_IID(nsISupportsCString), - getter_AddRefs(dispositionCString)); - if (dispositionCString) { - nsCString contentDisposition; - dispositionCString->GetData(contentDisposition); - FilenameFromContentDisposition(contentDisposition, imgName); - } - } - - return NS_OK; -} - static SugarBrowserMetadata * sugar_browser_get_document_metadata(SugarBrowser *browser) { @@ -382,13 +338,47 @@ sugar_browser_get_property(GObject *object, } } +static void +sugar_browser_realize(GtkWidget *widget) +{ + GTK_WIDGET_CLASS(parent_class)->realize(widget); + +#ifdef HAVE_NS_WEB_BROWSER + GtkMozEmbed *embed = GTK_MOZ_EMBED(widget); + nsCOMPtr webBrowser; + gtk_moz_embed_get_nsIWebBrowser(embed, getter_AddRefs(webBrowser)); + NS_ENSURE_TRUE(webBrowser, ); + + nsCOMPtr commandManager = do_GetInterface(webBrowser); + if (commandManager) { + nsresult rv; + nsIClipboardDragDropHooks *rawPtr = new GeckoDragDropHooks( + SUGAR_BROWSER(widget)); + nsCOMPtr geckoDragDropHooks( + do_QueryInterface(rawPtr, &rv)); + NS_ENSURE_SUCCESS(rv, ); + + nsCOMPtr DOMWindow = do_GetInterface(webBrowser); + nsCOMPtr cmdParamsObj = do_CreateInstance( + NS_COMMAND_PARAMS_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, ); + cmdParamsObj->SetISupportsValue("addhook", geckoDragDropHooks); + commandManager->DoCommand("cmd_clipboardDragDropHook", cmdParamsObj, + DOMWindow); + } +#endif +} static void sugar_browser_class_init(SugarBrowserClass *browser_class) { - GObjectClass *gobject_class = G_OBJECT_CLASS(browser_class); + GObjectClass *gobject_class = G_OBJECT_CLASS(browser_class); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(browser_class); - gobject_class->get_property = sugar_browser_get_property; + parent_class = (GObjectClass *) g_type_class_peek_parent(browser_class); + + gobject_class->get_property = sugar_browser_get_property; + widget_class->realize = sugar_browser_realize; signals[MOUSE_CLICK] = g_signal_new ("mouse_click", SUGAR_TYPE_BROWSER, @@ -570,29 +560,6 @@ location_cb(GtkMozEmbed *embed) update_navigation_properties(browser); } -static char * -get_image_name(const char *uri) -{ - nsresult rv; - - nsCString imgName; - - nsCOMPtr imgURI; - rv = NewURI(uri, getter_AddRefs(imgURI)); - NS_ENSURE_SUCCESS(rv, NULL); - - ImageNameFromCache(imgURI, imgName); - - if (!imgName.Length()) { - nsCOMPtr url(do_QueryInterface(imgURI)); - if (url) { - url->GetFileName(imgName); - } - } - - return imgName.Length() ? g_strdup(imgName.get()) : NULL; -} - static gboolean dom_mouse_click_cb(GtkMozEmbed *embed, nsIDOMMouseEvent *mouseEvent) { @@ -610,36 +577,10 @@ dom_mouse_click_cb(GtkMozEmbed *embed, nsIDOMMouseEvent *mouseEvent) event = sugar_browser_event_new(); - nsresult rv; - - PRUint16 type; - rv = targetNode->GetNodeType(&type); - if (NS_FAILED(rv)) return NS_ERROR_FAILURE; - - nsCOMPtr element = do_QueryInterface(targetNode); - if ((nsIDOMNode::ELEMENT_NODE == type) && element) { - nsString uTag; - rv = element->GetLocalName(uTag); - if (NS_FAILED(rv)) return NS_ERROR_FAILURE; - - nsCString tag; - NS_UTF16ToCString (uTag, NS_CSTRING_ENCODING_UTF8, tag); - - if (g_ascii_strcasecmp (tag.get(), "img") == 0) { - nsString img; - - nsCOMPtr image; - image = do_QueryInterface(targetNode, &rv); - if (NS_FAILED(rv) || !image) return NS_ERROR_FAILURE; - - rv = image->GetSrc(img); - if (NS_FAILED(rv)) return NS_ERROR_FAILURE; - - nsCString cImg; - NS_UTF16ToCString (img, NS_CSTRING_ENCODING_UTF8, cImg); - event->image_uri = g_strdup(cImg.get()); - event->image_name = get_image_name(event->image_uri); - } + GeckoDocumentObject documentObject(browser, targetNode); + if(documentObject.IsImage()) { + event->image_uri = documentObject.GetImageURI(); + event->image_name = documentObject.GetImageName(); } PRUint16 btn = 0; @@ -712,74 +653,13 @@ sugar_browser_grab_focus(SugarBrowser *browser) } } - -static nsresult -GetPostData(SugarBrowser *browser, nsIInputStream **postData) -{ -#ifdef HAVE_NS_WEB_BROWSER - nsCOMPtr webBrowser; - gtk_moz_embed_get_nsIWebBrowser(GTK_MOZ_EMBED(browser), - getter_AddRefs(webBrowser)); - NS_ENSURE_TRUE(webBrowser, NS_ERROR_FAILURE); - - nsCOMPtr webNav(do_QueryInterface(webBrowser)); - NS_ENSURE_TRUE(webNav, NS_ERROR_FAILURE); - - PRInt32 sindex; - - nsCOMPtr sessionHistory; - webNav->GetSessionHistory(getter_AddRefs(sessionHistory)); - NS_ENSURE_TRUE(sessionHistory, NS_ERROR_FAILURE); - - nsCOMPtr entry; - sessionHistory->GetIndex(&sindex); - sessionHistory->GetEntryAtIndex(sindex, PR_FALSE, getter_AddRefs(entry)); - - nsCOMPtr shEntry(do_QueryInterface(entry)); - if (shEntry) { - shEntry->GetPostData(postData); - } - - return NS_OK; -#endif - return NS_ERROR_NOT_IMPLEMENTED; -} - gboolean sugar_browser_save_uri(SugarBrowser *browser, const char *uri, const char *filename) { -#ifdef HAVE_NS_WEB_BROWSER - nsresult rv; - - nsCOMPtr sourceURI; - rv = NewURI(uri, getter_AddRefs(sourceURI)); - NS_ENSURE_SUCCESS(rv, FALSE); - - nsCOMPtr destFile = do_CreateInstance("@mozilla.org/file/local;1"); - NS_ENSURE_TRUE(destFile, FALSE); - - destFile->InitWithNativePath(nsCString(filename)); - - nsCOMPtr webBrowser; - gtk_moz_embed_get_nsIWebBrowser(GTK_MOZ_EMBED(browser), - getter_AddRefs(webBrowser)); - NS_ENSURE_TRUE(webBrowser, FALSE); - - nsCOMPtr webPersist = do_QueryInterface (webBrowser); - NS_ENSURE_TRUE(webPersist, FALSE); - - nsCOMPtr postData; - GetPostData(browser, getter_AddRefs(postData)); - - rv = webPersist->SaveURI(sourceURI, nsnull, nsnull, postData, nsnull, destFile); - NS_ENSURE_SUCCESS(rv, FALSE); - - return TRUE; -#else - return FALSE; -#endif + GeckoBrowserPersist browserPersist(browser); + return browserPersist.SaveURI(uri, filename); } gboolean diff --git a/services/clipboard/clipboardobject.py b/services/clipboard/clipboardobject.py index 919acd00..ab00b14d 100644 --- a/services/clipboard/clipboardobject.py +++ b/services/clipboard/clipboardobject.py @@ -1,3 +1,6 @@ +import os +import logging + import typeregistry class ClipboardObject: @@ -8,6 +11,10 @@ class ClipboardObject: self._percent = 0 self._formats = {} + def destroy(self): + for type, format in self._formats.iteritems(): + format.destroy() + def get_id(self): return self._id @@ -49,6 +56,10 @@ class Format: self._data = data self._on_disk = on_disk + def destroy(self): + if self._on_disk: + os.remove(self._data.replace('file://', '')) + def get_type(self): return self._type diff --git a/services/clipboard/clipboardservice.py b/services/clipboard/clipboardservice.py index 0ed423b5..16e37b19 100644 --- a/services/clipboard/clipboardservice.py +++ b/services/clipboard/clipboardservice.py @@ -109,7 +109,8 @@ class ClipboardDBusServiceHelper(dbus.service.Object): @dbus.service.method(_CLIPBOARD_DBUS_INTERFACE, in_signature="o", out_signature="") def delete_object(self, object_path): - del self._objects[str(object_path)] + cb_object = self._objects.pop(str(object_path)) + cb_object.destroy() self.object_deleted(object_path) logging.debug('Deleted object with object_id ' + object_path) diff --git a/services/clipboard/typeregistry.py b/services/clipboard/typeregistry.py index b794cee9..b6f4ae1f 100644 --- a/services/clipboard/typeregistry.py +++ b/services/clipboard/typeregistry.py @@ -197,6 +197,26 @@ class OOTextFileType(FileType): return mime_type in cls._types matches_mime_type = classmethod(matches_mime_type) +class UriListFileType(FileType): + + _types = set(['text/uri-list']) + + def get_name(self): + return _('text/uri-list') + + def get_icon(self): + return 'theme:stock-missing' + + def get_preview(self): + return 'preview' + + def get_activity(self): + return '' + + def matches_mime_type(cls, mime_type): + return mime_type in cls._types + matches_mime_type = classmethod(matches_mime_type) + class UnknownFileType(FileType): def get_name(self): return _('Object') @@ -221,6 +241,7 @@ class TypeRegistry: self._types.append(MsWordFileType) self._types.append(RtfFileType) self._types.append(OOTextFileType) + self._types.append(UriListFileType) self._types.append(UriFileType) self._types.append(ImageFileType) self._types.append(AbiwordFileType) diff --git a/shell/view/frame/clipboardbox.py b/shell/view/frame/clipboardbox.py index 2dcad10e..c057a42e 100644 --- a/shell/view/frame/clipboardbox.py +++ b/shell/view/frame/clipboardbox.py @@ -1,4 +1,7 @@ +import shutil +import os import logging + import hippo import gtk @@ -72,13 +75,25 @@ class ClipboardBox(hippo.CanvasBox): if not selection.data: return - logging.debug('ClipboardBox: adding type ' + selection.type + '.') - + logging.debug('ClipboardBox: adding type ' + selection.type + ' ' + selection.data) + cb_service = clipboardservice.get_instance() - cb_service.add_object_format(object_id, - selection.type, - selection.data, - on_disk = False) + if selection.type == 'text/uri-list': + # Copy the file, as it will be deleted when the dnd operation finishes. + file_path = selection.data.replace('file://', '') + new_file_path = os.path.join(os.path.split(file_path)[0], + "cb" + os.path.split(file_path)[1]) + shutil.copyfile(file_path, new_file_path) + + cb_service.add_object_format(object_id, + selection.type, + 'file://' + new_file_path, + on_disk=True) + else: + cb_service.add_object_format(object_id, + selection.type, + selection.data, + on_disk=False) def _object_added_cb(self, cb_service, object_id, name): icon = ClipboardIcon(self._popup_context, object_id, name) @@ -165,15 +180,16 @@ class ClipboardBox(hippo.CanvasBox): def drag_data_received_cb(self, widget, context, x, y, selection, targetType, time): logging.debug('ClipboardBox: got data for target ' + selection.target) - if selection: - object_id = self._context_map.get_object_id(context) - self._add_selection(object_id, selection) - else: - logging.warn('ClipboardBox: empty selection for target ' + selection.target) - - # If it's the last target to be processed, finish the dnd transaction - if not self._context_map.has_context(context): - context.finish(True, False, time) + try: + if selection: + object_id = self._context_map.get_object_id(context) + self._add_selection(object_id, selection) + else: + logging.warn('ClipboardBox: empty selection for target ' + selection.target) + finally: + # If it's the last target to be processed, finish the dnd transaction + if not self._context_map.has_context(context): + context.drop_finish(True, gtk.get_current_event_time()) def drag_data_get_cb(self, widget, context, selection, targetType, eventTime): logging.debug("drag_data_get_cb: requested target " + selection.target)