Merge branch 'master' of git+ssh://dev.laptop.org/git/sugar
This commit is contained in:
commit
cf5ef53070
190
browser/GeckoBrowserPersist.cpp
Normal file
190
browser/GeckoBrowserPersist.cpp
Normal file
@ -0,0 +1,190 @@
|
||||
#include <config.h>
|
||||
|
||||
#ifdef HAVE_GECKO_1_9
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <gtkmozembed.h>
|
||||
#include <gtkmozembed_internal.h>
|
||||
#include <nsIRequest.h>
|
||||
#include <nsNetUtil.h>
|
||||
#include <nsISeekableStream.h>
|
||||
#include <nsIHttpChannel.h>
|
||||
#include <nsIUploadChannel.h>
|
||||
#include <nsIWebBrowser.h>
|
||||
#include <nsISHistory.h>
|
||||
#include <nsIHistoryEntry.h>
|
||||
#include <nsISHEntry.h>
|
||||
#include <nsIInputStream.h>
|
||||
#include <nsIWebNavigation.h>
|
||||
|
||||
#include "GeckoBrowserPersist.h"
|
||||
|
||||
GeckoBrowserPersist::GeckoBrowserPersist(SugarBrowser *browser)
|
||||
: mBrowser(browser)
|
||||
{
|
||||
}
|
||||
|
||||
GeckoBrowserPersist::~GeckoBrowserPersist()
|
||||
{
|
||||
}
|
||||
|
||||
static nsresult
|
||||
NewURI(const char *uri, nsIURI **result)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsIServiceManager> mgr;
|
||||
NS_GetServiceManager (getter_AddRefs (mgr));
|
||||
NS_ENSURE_TRUE(mgr, FALSE);
|
||||
|
||||
nsCOMPtr<nsIIOService> 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<nsIWebBrowser> webBrowser;
|
||||
gtk_moz_embed_get_nsIWebBrowser(GTK_MOZ_EMBED(browser),
|
||||
getter_AddRefs(webBrowser));
|
||||
NS_ENSURE_TRUE(webBrowser, NS_ERROR_FAILURE);
|
||||
|
||||
nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(webBrowser));
|
||||
NS_ENSURE_TRUE(webNav, NS_ERROR_FAILURE);
|
||||
|
||||
PRInt32 sindex;
|
||||
|
||||
nsCOMPtr<nsISHistory> sessionHistory;
|
||||
webNav->GetSessionHistory(getter_AddRefs(sessionHistory));
|
||||
NS_ENSURE_TRUE(sessionHistory, NS_ERROR_FAILURE);
|
||||
|
||||
nsCOMPtr<nsIHistoryEntry> entry;
|
||||
sessionHistory->GetIndex(&sindex);
|
||||
sessionHistory->GetEntryAtIndex(sindex, PR_FALSE, getter_AddRefs(entry));
|
||||
|
||||
nsCOMPtr<nsISHEntry> 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<nsIURI> sourceURI;
|
||||
rv = NewURI(uri, getter_AddRefs(sourceURI));
|
||||
NS_ENSURE_SUCCESS(rv, FALSE);
|
||||
|
||||
nsCOMPtr<nsILocalFile> destFile = do_CreateInstance("@mozilla.org/file/local;1");
|
||||
NS_ENSURE_TRUE(destFile, FALSE);
|
||||
|
||||
destFile->InitWithNativePath(nsCString(filename));
|
||||
|
||||
nsCOMPtr<nsIInputStream> postData;
|
||||
GetPostData(mBrowser, getter_AddRefs(postData));
|
||||
|
||||
nsCOMPtr<nsIChannel> inputChannel;
|
||||
rv = NS_NewChannel(getter_AddRefs(inputChannel), sourceURI,
|
||||
nsnull, nsnull, nsnull, nsIRequest::LOAD_NORMAL);
|
||||
NS_ENSURE_SUCCESS(rv, FALSE);
|
||||
|
||||
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(inputChannel));
|
||||
if (httpChannel) {
|
||||
nsCOMPtr<nsISeekableStream> stream(do_QueryInterface(postData));
|
||||
if (stream)
|
||||
{
|
||||
// Rewind the postdata stream
|
||||
stream->Seek(nsISeekableStream::NS_SEEK_SET, 0);
|
||||
nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(httpChannel));
|
||||
NS_ASSERTION(uploadChannel, "http must support nsIUploadChannel");
|
||||
// Attach the postdata to the http channel
|
||||
uploadChannel->SetUploadStream(postData, EmptyCString(), -1);
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIInputStream> stream;
|
||||
rv = inputChannel->Open(getter_AddRefs(stream));
|
||||
NS_ENSURE_SUCCESS(rv, FALSE);
|
||||
|
||||
nsCOMPtr<nsIFileOutputStream> 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;
|
||||
}
|
||||
|
||||
#endif
|
19
browser/GeckoBrowserPersist.h
Normal file
19
browser/GeckoBrowserPersist.h
Normal file
@ -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__
|
241
browser/GeckoDocumentObject.cpp
Normal file
241
browser/GeckoDocumentObject.cpp
Normal file
@ -0,0 +1,241 @@
|
||||
#include <config.h>
|
||||
|
||||
#ifdef HAVE_GECKO_1_9
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include <glib.h>
|
||||
#include <imgICache.h>
|
||||
#include <nsComponentManagerUtils.h>
|
||||
#include <nsCOMPtr.h>
|
||||
#include <nsIDOMHTMLElement.h>
|
||||
#include <nsIInterfaceRequestorUtils.h>
|
||||
#include <nsIIOService.h>
|
||||
#include <nsILocalFile.h>
|
||||
#include <nsIMIMEHeaderParam.h>
|
||||
#include <nsIProperties.h>
|
||||
#include <nsISupportsPrimitives.h>
|
||||
#include <nsIURI.h>
|
||||
#include <nsIURL.h>
|
||||
#include <nsServiceManagerUtils.h>
|
||||
#include <nsStringAPI.h>
|
||||
|
||||
#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<nsIDOMHTMLElement> 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 <nsIDOMHTMLImageElement> 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<nsIServiceManager> mgr;
|
||||
NS_GetServiceManager (getter_AddRefs (mgr));
|
||||
NS_ENSURE_TRUE(mgr, FALSE);
|
||||
|
||||
nsCOMPtr<nsIIOService> 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<nsIMIMEHeaderParam> 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;
|
||||
}
|
||||
|
||||
static nsresult
|
||||
GetImageProperties(char *imgURIStr, nsIProperties **properties)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsIURI> imageURI;
|
||||
rv = NewURI(imgURIStr, getter_AddRefs(imageURI));
|
||||
if(NS_FAILED(rv)) return rv;
|
||||
|
||||
nsCOMPtr<nsIServiceManager> mgr;
|
||||
NS_GetServiceManager(getter_AddRefs(mgr));
|
||||
NS_ENSURE_TRUE(mgr, NS_ERROR_FAILURE);
|
||||
|
||||
nsCOMPtr<imgICache> imgCache;
|
||||
rv = mgr->GetServiceByContractID("@mozilla.org/image/cache;1",
|
||||
NS_GET_IID(imgICache),
|
||||
getter_AddRefs(imgCache));
|
||||
if(NS_FAILED(rv)) return rv;
|
||||
|
||||
imgCache->FindEntryProperties(imageURI, properties);
|
||||
NS_ENSURE_TRUE(mgr, NS_ERROR_FAILURE);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
char *
|
||||
GeckoDocumentObject::GetImageName()
|
||||
{
|
||||
if(!IsImage()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(mImageName.Length()) {
|
||||
return g_strdup(mImageName.get());
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
char *imgURIStr = GetImageURI();
|
||||
|
||||
nsCOMPtr<nsIProperties> imgProperties;
|
||||
rv = GetImageProperties(imgURIStr, getter_AddRefs(imgProperties));
|
||||
NS_ENSURE_SUCCESS(rv, NULL);
|
||||
if (imgProperties) {
|
||||
nsCOMPtr<nsISupportsCString> 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<nsIURI> imageURI;
|
||||
rv = NewURI(imgURIStr, getter_AddRefs(imageURI));
|
||||
NS_ENSURE_SUCCESS(rv, NULL);
|
||||
|
||||
nsCOMPtr<nsIURL> url(do_QueryInterface(imageURI));
|
||||
if (url) {
|
||||
url->GetFileName(mImageName);
|
||||
}
|
||||
}
|
||||
|
||||
return mImageName.Length() ? g_strdup(mImageName.get()) : NULL;
|
||||
}
|
||||
|
||||
char *
|
||||
GeckoDocumentObject::GetImageMimeType()
|
||||
{
|
||||
if(!IsImage()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(mImageMimeType.Length()) {
|
||||
return g_strdup(mImageMimeType.get());
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
char *imgURIStr = GetImageURI();
|
||||
|
||||
nsCOMPtr<nsIProperties> imgProperties;
|
||||
rv = GetImageProperties(imgURIStr, getter_AddRefs(imgProperties));
|
||||
NS_ENSURE_SUCCESS(rv, NULL);
|
||||
if (imgProperties) {
|
||||
nsCOMPtr<nsISupportsCString> typeCString;
|
||||
imgProperties->Get("type",
|
||||
NS_GET_IID(nsISupportsCString),
|
||||
getter_AddRefs(typeCString));
|
||||
if (typeCString) {
|
||||
typeCString->GetData(mImageMimeType);
|
||||
}
|
||||
}
|
||||
|
||||
return mImageMimeType.Length() ? g_strdup(mImageMimeType.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);
|
||||
}
|
||||
|
||||
#endif
|
31
browser/GeckoDocumentObject.h
Normal file
31
browser/GeckoDocumentObject.h
Normal file
@ -0,0 +1,31 @@
|
||||
#ifndef __GECKO_DOCUMENT_OBJECT_H__
|
||||
#define __GECKO_DOCUMENT_OBJECT_H__
|
||||
|
||||
#include <nsIDOMNode.h>
|
||||
#include <nsIDOMHTMLImageElement.h>
|
||||
|
||||
#include "sugar-browser.h"
|
||||
|
||||
class GeckoDocumentObject
|
||||
{
|
||||
public:
|
||||
GeckoDocumentObject(SugarBrowser *browser, nsIDOMNode *node);
|
||||
~GeckoDocumentObject();
|
||||
|
||||
bool IsImage();
|
||||
char *GetImageURI();
|
||||
char *GetImageName();
|
||||
char *GetImageMimeType();
|
||||
bool SaveImage(const char *filename);
|
||||
private:
|
||||
SugarBrowser *mBrowser;
|
||||
nsCOMPtr<nsIDOMNode> mNode;
|
||||
nsCOMPtr<nsIDOMHTMLImageElement> mImage;
|
||||
nsCString mImageURI;
|
||||
nsCString mImageName;
|
||||
nsCString mImageMimeType;
|
||||
protected:
|
||||
/* additional members */
|
||||
};
|
||||
|
||||
#endif // __GECKO_DOCUMENT_OBJECT_H__
|
218
browser/GeckoDragDropHooks.cpp
Normal file
218
browser/GeckoDragDropHooks.cpp
Normal file
@ -0,0 +1,218 @@
|
||||
#include <config.h>
|
||||
|
||||
#ifdef HAVE_GECKO_1_9
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <glib.h>
|
||||
#include <nsStringAPI.h>
|
||||
#include <nsCOMPtr.h>
|
||||
#include <nsITransferable.h>
|
||||
#include <nsISupportsPrimitives.h>
|
||||
#include <nsIDOMEventTarget.h>
|
||||
#include <nsComponentManagerUtils.h>
|
||||
#include <nsServiceManagerUtils.h>
|
||||
#include <nsIInterfaceRequestorUtils.h>
|
||||
#include <nsIDOMMouseEvent.h>
|
||||
#include <nsIMIMEService.h>
|
||||
|
||||
#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;
|
||||
char *mime_type;
|
||||
char *file_ext;
|
||||
nsCString mime_ext;
|
||||
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();
|
||||
file_ext = strrchr(image_name, '.');
|
||||
mime_type = mDocumentObject->GetImageMimeType();
|
||||
|
||||
nsCOMPtr<nsIMIMEService> mimeService(do_GetService("@mozilla.org/mime;1",
|
||||
&rv));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = mimeService->GetPrimaryExtension(nsCString(mime_type),
|
||||
EmptyCString(),
|
||||
mime_ext);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if(!file_ext) {
|
||||
mFilePath.Append(image_name);
|
||||
mFilePath.Append(".");
|
||||
mFilePath.Append(mime_ext);
|
||||
} else if(strcmp(file_ext, mime_ext.get())) {
|
||||
image_name[strlen(file_ext)] = 0;
|
||||
mFilePath.Append(image_name);
|
||||
mFilePath.Append(".");
|
||||
mFilePath.Append(mime_ext);
|
||||
} else {
|
||||
mFilePath.Append(image_name);
|
||||
}
|
||||
|
||||
g_free(mime_type);
|
||||
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<nsISupportsString> 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<nsIDOMMouseEvent> mouseEvent;
|
||||
mouseEvent = do_QueryInterface(aEvent, &rv);
|
||||
if(NS_FAILED(rv)) return rv;
|
||||
|
||||
nsCOMPtr<nsIDOMEventTarget> eventTarget;
|
||||
rv = mouseEvent->GetTarget(getter_AddRefs(eventTarget));
|
||||
if(NS_FAILED(rv)) return rv;
|
||||
|
||||
nsCOMPtr<nsIDOMNode> 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<nsISupports> 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;
|
||||
}
|
||||
|
||||
#endif
|
25
browser/GeckoDragDropHooks.h
Normal file
25
browser/GeckoDragDropHooks.h
Normal file
@ -0,0 +1,25 @@
|
||||
#ifndef __GECKO_DRAG_DROP_HOOKS_H__
|
||||
#define __GECKO_DRAG_DROP_HOOKS_H__
|
||||
|
||||
#include <nsIClipboardDragDropHooks.h>
|
||||
|
||||
#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__
|
@ -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 \
|
||||
|
@ -24,6 +24,12 @@
|
||||
#include "GeckoContentHandler.h"
|
||||
#include "GeckoDownload.h"
|
||||
|
||||
#ifdef HAVE_GECKO_1_9
|
||||
#include "GeckoDragDropHooks.h"
|
||||
#include "GeckoDocumentObject.h"
|
||||
#include "GeckoBrowserPersist.h"
|
||||
#endif
|
||||
|
||||
#include <gdk/gdkx.h>
|
||||
#include <gtkmozembed_internal.h>
|
||||
#include <nsCOMPtr.h>
|
||||
@ -56,6 +62,8 @@
|
||||
#include <nsIHistoryEntry.h>
|
||||
#include <nsISHEntry.h>
|
||||
#include <nsIInputStream.h>
|
||||
#include <nsICommandManager.h>
|
||||
#include <nsIClipboardDragDropHooks.h>
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
@ -75,6 +83,8 @@ enum {
|
||||
|
||||
static guint signals[N_SIGNALS];
|
||||
|
||||
static GObjectClass *parent_class = NULL;
|
||||
|
||||
static const nsModuleComponentInfo sSugarComponents[] = {
|
||||
{
|
||||
"Gecko Content Handler",
|
||||
@ -210,25 +220,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<nsIServiceManager> mgr;
|
||||
NS_GetServiceManager (getter_AddRefs (mgr));
|
||||
NS_ENSURE_TRUE(mgr, FALSE);
|
||||
|
||||
nsCOMPtr<nsIIOService> 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 +249,6 @@ FilenameFromContentDisposition(nsCString contentDisposition, nsCString &fileName
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static nsresult
|
||||
ImageNameFromCache(nsIURI *imgURI, nsCString &imgName)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsIServiceManager> mgr;
|
||||
NS_GetServiceManager (getter_AddRefs (mgr));
|
||||
NS_ENSURE_TRUE(mgr, NS_ERROR_FAILURE);
|
||||
|
||||
nsCOMPtr<imgICache> imgCache;
|
||||
rv = mgr->GetServiceByContractID("@mozilla.org/image/cache;1",
|
||||
NS_GET_IID (imgICache),
|
||||
getter_AddRefs(imgCache));
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
|
||||
|
||||
nsCOMPtr<nsIProperties> imgProperties;
|
||||
imgCache->FindEntryProperties(imgURI, getter_AddRefs(imgProperties));
|
||||
if (imgProperties) {
|
||||
nsCOMPtr<nsISupportsCString> 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 +341,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<nsIWebBrowser> webBrowser;
|
||||
gtk_moz_embed_get_nsIWebBrowser(embed, getter_AddRefs(webBrowser));
|
||||
NS_ENSURE_TRUE(webBrowser, );
|
||||
|
||||
nsCOMPtr<nsICommandManager> commandManager = do_GetInterface(webBrowser);
|
||||
if (commandManager) {
|
||||
nsresult rv;
|
||||
nsIClipboardDragDropHooks *rawPtr = new GeckoDragDropHooks(
|
||||
SUGAR_BROWSER(widget));
|
||||
nsCOMPtr<nsIClipboardDragDropHooks> geckoDragDropHooks(
|
||||
do_QueryInterface(rawPtr, &rv));
|
||||
NS_ENSURE_SUCCESS(rv, );
|
||||
|
||||
nsCOMPtr<nsIDOMWindow> DOMWindow = do_GetInterface(webBrowser);
|
||||
nsCOMPtr<nsICommandParams> 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,33 +563,11 @@ location_cb(GtkMozEmbed *embed)
|
||||
update_navigation_properties(browser);
|
||||
}
|
||||
|
||||
static char *
|
||||
get_image_name(const char *uri)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsCString imgName;
|
||||
|
||||
nsCOMPtr<nsIURI> imgURI;
|
||||
rv = NewURI(uri, getter_AddRefs(imgURI));
|
||||
NS_ENSURE_SUCCESS(rv, NULL);
|
||||
|
||||
ImageNameFromCache(imgURI, imgName);
|
||||
|
||||
if (!imgName.Length()) {
|
||||
nsCOMPtr<nsIURL> 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)
|
||||
{
|
||||
SugarBrowser *browser = SUGAR_BROWSER(embed);
|
||||
#ifdef HAVE_GECKO_1_9
|
||||
SugarBrowser *browser = SUGAR_BROWSER(embed);
|
||||
SugarBrowserEvent *event;
|
||||
gint return_value = FALSE;
|
||||
|
||||
@ -610,36 +581,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<nsIDOMHTMLElement> 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 <nsIDOMHTMLImageElement> 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;
|
||||
@ -651,6 +596,9 @@ dom_mouse_click_cb(GtkMozEmbed *embed, nsIDOMMouseEvent *mouseEvent)
|
||||
sugar_browser_event_free(event);
|
||||
|
||||
return return_value;
|
||||
#else
|
||||
return FALSE;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
@ -712,71 +660,14 @@ sugar_browser_grab_focus(SugarBrowser *browser)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static nsresult
|
||||
GetPostData(SugarBrowser *browser, nsIInputStream **postData)
|
||||
{
|
||||
#ifdef HAVE_NS_WEB_BROWSER
|
||||
nsCOMPtr<nsIWebBrowser> webBrowser;
|
||||
gtk_moz_embed_get_nsIWebBrowser(GTK_MOZ_EMBED(browser),
|
||||
getter_AddRefs(webBrowser));
|
||||
NS_ENSURE_TRUE(webBrowser, NS_ERROR_FAILURE);
|
||||
|
||||
nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(webBrowser));
|
||||
NS_ENSURE_TRUE(webNav, NS_ERROR_FAILURE);
|
||||
|
||||
PRInt32 sindex;
|
||||
|
||||
nsCOMPtr<nsISHistory> sessionHistory;
|
||||
webNav->GetSessionHistory(getter_AddRefs(sessionHistory));
|
||||
NS_ENSURE_TRUE(sessionHistory, NS_ERROR_FAILURE);
|
||||
|
||||
nsCOMPtr<nsIHistoryEntry> entry;
|
||||
sessionHistory->GetIndex(&sindex);
|
||||
sessionHistory->GetEntryAtIndex(sindex, PR_FALSE, getter_AddRefs(entry));
|
||||
|
||||
nsCOMPtr<nsISHEntry> 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<nsIURI> sourceURI;
|
||||
rv = NewURI(uri, getter_AddRefs(sourceURI));
|
||||
NS_ENSURE_SUCCESS(rv, FALSE);
|
||||
|
||||
nsCOMPtr<nsILocalFile> destFile = do_CreateInstance("@mozilla.org/file/local;1");
|
||||
NS_ENSURE_TRUE(destFile, FALSE);
|
||||
|
||||
destFile->InitWithNativePath(nsCString(filename));
|
||||
|
||||
nsCOMPtr<nsIWebBrowser> webBrowser;
|
||||
gtk_moz_embed_get_nsIWebBrowser(GTK_MOZ_EMBED(browser),
|
||||
getter_AddRefs(webBrowser));
|
||||
NS_ENSURE_TRUE(webBrowser, FALSE);
|
||||
|
||||
nsCOMPtr<nsIWebBrowserPersist> webPersist = do_QueryInterface (webBrowser);
|
||||
NS_ENSURE_TRUE(webPersist, FALSE);
|
||||
|
||||
nsCOMPtr<nsIInputStream> postData;
|
||||
GetPostData(browser, getter_AddRefs(postData));
|
||||
|
||||
rv = webPersist->SaveURI(sourceURI, nsnull, nsnull, postData, nsnull, destFile);
|
||||
NS_ENSURE_SUCCESS(rv, FALSE);
|
||||
|
||||
return TRUE;
|
||||
#ifdef HAVE_GECKO_1_9
|
||||
GeckoBrowserPersist browserPersist(browser);
|
||||
return browserPersist.SaveURI(uri, filename);
|
||||
#else
|
||||
return FALSE;
|
||||
#endif
|
||||
|
@ -1,4 +1,4 @@
|
||||
gtk-theme-name = "olpc"
|
||||
gtk-theme-name = "sugar"
|
||||
gtk-icon-theme-name = "olpc"
|
||||
gtk-font-name = "Bitstream Vera Sans 7"
|
||||
gtk-icon-sizes = "gtk-menu=32,32:gtk-button=32,32"
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -369,6 +369,11 @@ class CanvasIcon(hippo.CanvasBox, hippo.CanvasItem):
|
||||
if not self._popup:
|
||||
return
|
||||
|
||||
if not self.get_context():
|
||||
# If we have been detached from our parent, don't show up the popup
|
||||
# in this case.
|
||||
return
|
||||
|
||||
popup_context = self.get_popup_context()
|
||||
|
||||
[x, y] = [None, None]
|
||||
|
@ -1,66 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# Copyright (C) 2007, One Laptop Per Child
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
import sys
|
||||
sys.path.insert(0, '/home/tomeu/sugar-jhbuild/source/sugar')
|
||||
|
||||
import gtk
|
||||
import hippo
|
||||
|
||||
from sugar.graphics.toolbar import Toolbar
|
||||
from sugar.graphics.iconbutton import IconButton
|
||||
from sugar.graphics.toggleiconbutton import ToggleIconButton
|
||||
from sugar.graphics.button import Button
|
||||
from sugar.graphics.entry import Entry
|
||||
|
||||
def _button_activated_cb(button):
|
||||
print "_button_activated_cb"
|
||||
|
||||
def _toggled_changed_cb(button, pspec):
|
||||
print "Toggle state: %d" % button.props.toggled
|
||||
|
||||
window = gtk.Window()
|
||||
window.connect("destroy", lambda w: gtk.main_quit())
|
||||
window.show()
|
||||
|
||||
canvas = hippo.Canvas()
|
||||
window.add(canvas)
|
||||
canvas.show()
|
||||
|
||||
vbox = hippo.CanvasBox()
|
||||
canvas.set_root(vbox)
|
||||
|
||||
for i in [1, 2]:
|
||||
toolbar = Toolbar()
|
||||
toolbar.props.box_width = 400
|
||||
vbox.append(toolbar)
|
||||
|
||||
icon_button = IconButton(icon_name='theme:stock-close')
|
||||
toolbar.append(icon_button)
|
||||
|
||||
toggle = ToggleIconButton(icon_name='theme:stock-back')
|
||||
toggle.connect('notify::toggled', _toggled_changed_cb)
|
||||
toolbar.append(toggle)
|
||||
|
||||
button = Button(text='Click me!', icon_name='theme:stock-close')
|
||||
button.connect('activated', _button_activated_cb)
|
||||
toolbar.append(button)
|
||||
|
||||
entry = Entry(text='mec')
|
||||
toolbar.append(entry)
|
||||
|
||||
gtk.main()
|
@ -1,71 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# Copyright (C) 2007, One Laptop Per Child
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
import gtk
|
||||
import hippo
|
||||
|
||||
from sugar.graphics.toolbar import Toolbar
|
||||
from sugar.graphics.frame import Frame
|
||||
from sugar.graphics.iconbutton import IconButton
|
||||
from sugar.graphics.entry import Entry
|
||||
|
||||
def _entry_activated_cb(entry):
|
||||
print "_entry_activated_cb"
|
||||
|
||||
def _entry_button_activated_cb(entry, action_id):
|
||||
print "_entry_button_activated_cb: " + str(action_id)
|
||||
entry.props.text = ''
|
||||
|
||||
window = gtk.Window()
|
||||
window.connect("destroy", lambda w: gtk.main_quit())
|
||||
window.show()
|
||||
|
||||
canvas = hippo.Canvas()
|
||||
window.add(canvas)
|
||||
canvas.show()
|
||||
|
||||
vbox = hippo.CanvasBox()
|
||||
canvas.set_root(vbox)
|
||||
|
||||
for i in [1, 2]:
|
||||
toolbar = Toolbar()
|
||||
vbox.append(toolbar)
|
||||
|
||||
button = IconButton('theme:stock-close')
|
||||
toolbar.append(button)
|
||||
|
||||
BUTTON_DELETE = 1
|
||||
entry = Entry()
|
||||
entry.props.text = 'mec mac'
|
||||
entry.add_button('theme:stock-close', BUTTON_DELETE)
|
||||
entry.connect('activated', _entry_activated_cb)
|
||||
entry.connect('button-activated', _entry_button_activated_cb)
|
||||
toolbar.append(entry, hippo.PACK_EXPAND)
|
||||
|
||||
entry = Entry()
|
||||
entry.props.text = 'moc muc'
|
||||
toolbar.append(entry, hippo.PACK_EXPAND)
|
||||
|
||||
gtk_entry = gtk.Entry()
|
||||
gtk_entry.props.has_frame = False
|
||||
#gtk_entry.connect("activate", self._entry_activate_cb)
|
||||
|
||||
gtk_entry_widget = hippo.CanvasWidget()
|
||||
gtk_entry_widget.props.widget = gtk_entry
|
||||
toolbar.append(gtk_entry_widget, hippo.PACK_EXPAND)
|
||||
|
||||
gtk.main()
|
@ -1,51 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# Copyright (C) 2007, One Laptop Per Child
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
import gtk
|
||||
import hippo
|
||||
|
||||
from sugar.graphics.toolbar import Toolbar
|
||||
from sugar.graphics.label import Label
|
||||
from sugar.graphics.iconbutton import IconButton
|
||||
|
||||
BUTTON_DELETE = 1
|
||||
|
||||
window = gtk.Window()
|
||||
window.connect("destroy", lambda w: gtk.main_quit())
|
||||
window.show()
|
||||
|
||||
canvas = hippo.Canvas()
|
||||
window.add(canvas)
|
||||
canvas.show()
|
||||
|
||||
vbox = hippo.CanvasBox()
|
||||
canvas.set_root(vbox)
|
||||
|
||||
toolbar = Toolbar()
|
||||
vbox.append(toolbar)
|
||||
|
||||
button = IconButton('theme:stock-close')
|
||||
toolbar.append(button)
|
||||
|
||||
label = Label('mec moc')
|
||||
toolbar.append(label)
|
||||
|
||||
label = Label()
|
||||
label.props.text = 'mac mic'
|
||||
toolbar.append(label)
|
||||
|
||||
gtk.main()
|
@ -1,64 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# Copyright (C) 2007, One Laptop Per Child
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
import sys
|
||||
sys.path.insert(0, '/home/tomeu/sugar-jhbuild/source/sugar')
|
||||
from gettext import gettext as _
|
||||
|
||||
import gtk
|
||||
import hippo
|
||||
|
||||
from sugar.graphics.toolbar import Toolbar
|
||||
from sugar.graphics.optionmenu import OptionMenu
|
||||
from sugar.graphics.menu import MenuItem
|
||||
from sugar.graphics.iconbutton import IconButton
|
||||
|
||||
def _option_menu_changed_cb(option_menu):
|
||||
print '_option_menu_activated_cb: %i' % option_menu.props.value
|
||||
|
||||
window = gtk.Window()
|
||||
window.connect("destroy", lambda w: gtk.main_quit())
|
||||
window.show()
|
||||
|
||||
canvas = hippo.Canvas()
|
||||
window.add(canvas)
|
||||
canvas.show()
|
||||
|
||||
vbox = hippo.CanvasBox()
|
||||
canvas.set_root(vbox)
|
||||
|
||||
toolbar = Toolbar()
|
||||
vbox.append(toolbar)
|
||||
|
||||
button = IconButton(icon_name='theme:stock-close')
|
||||
toolbar.append(button)
|
||||
|
||||
OPTION_ANYTHING = 1
|
||||
OPTION_DRAW = 2
|
||||
OPTION_WRITE = 3
|
||||
OPTION_CHAT = 4
|
||||
|
||||
option_menu = OptionMenu()
|
||||
option_menu.add_item(MenuItem(OPTION_ANYTHING, 'Anything'))
|
||||
option_menu.add_separator()
|
||||
option_menu.add_item(MenuItem(OPTION_DRAW, 'Draw', 'theme:stock-close'))
|
||||
option_menu.add_item(MenuItem(OPTION_WRITE, 'Write'))
|
||||
option_menu.add_item(MenuItem(OPTION_CHAT, 'Chat'))
|
||||
option_menu.connect('changed', _option_menu_changed_cb)
|
||||
toolbar.append(option_menu)
|
||||
|
||||
gtk.main()
|
@ -1,121 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# Copyright (C) 2006, Red Hat, Inc.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
import pygtk
|
||||
pygtk.require('2.0')
|
||||
|
||||
import gtk
|
||||
|
||||
# Main window
|
||||
window = gtk.Window()
|
||||
window.connect("destroy", lambda w: gtk.main_quit())
|
||||
#window.set_border_width(10)
|
||||
|
||||
# Main VBox
|
||||
|
||||
main_vbox = gtk.VBox(homogeneous=False, spacing=0)
|
||||
window.add(main_vbox)
|
||||
|
||||
############################### ##############################
|
||||
############################### Menus ##############################
|
||||
############################### ##############################
|
||||
|
||||
menu = gtk.Menu()
|
||||
file_menu = gtk.Menu() # Don't need to show menus
|
||||
edit_menu = gtk.Menu()
|
||||
|
||||
# Create the menu items
|
||||
dummy_item_1 = gtk.MenuItem("Dummy Item 1")
|
||||
dummy_item_2 = gtk.MenuItem("Dummy Item 2")
|
||||
quit_item = gtk.MenuItem("Quit")
|
||||
dummy_item_3 = gtk.MenuItem("Dummy Item 3")
|
||||
dummy_item_4 = gtk.MenuItem("Dummy Item 4")
|
||||
dummy_item_5 = gtk.MenuItem("Dummy Item 5")
|
||||
|
||||
# Add them to the menu
|
||||
file_menu.append(dummy_item_1)
|
||||
file_menu.append(dummy_item_2)
|
||||
file_menu.append(quit_item)
|
||||
|
||||
edit_menu.append(dummy_item_3)
|
||||
edit_menu.append(dummy_item_4)
|
||||
edit_menu.append(dummy_item_5)
|
||||
|
||||
# We can attach the Quit menu item to our exit function
|
||||
quit_item.connect_object ("activate", lambda w: gtk.main_quit (), "file.quit")
|
||||
|
||||
# We do need to show menu items
|
||||
dummy_item_1.show()
|
||||
dummy_item_2.show()
|
||||
quit_item.show()
|
||||
dummy_item_3.show()
|
||||
dummy_item_4.show()
|
||||
dummy_item_5.show()
|
||||
|
||||
# Pack the menu into the menubar
|
||||
menu_bar = gtk.MenuBar()
|
||||
main_vbox.pack_start(menu_bar, False, False, 0)
|
||||
menu_bar.show()
|
||||
|
||||
file_item = gtk.MenuItem("File")
|
||||
file_item.show()
|
||||
menu_bar.append(file_item)
|
||||
file_item.set_submenu(file_menu)
|
||||
|
||||
edit_item = gtk.MenuItem("Edit")
|
||||
edit_item.show()
|
||||
menu_bar.append(edit_item)
|
||||
edit_item.set_submenu(edit_menu)
|
||||
|
||||
|
||||
# Scrolled window
|
||||
scrolled_window = gtk.ScrolledWindow(hadjustment=None, vadjustment=None)
|
||||
#scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
|
||||
scrolled_window.set_border_width(10)
|
||||
main_vbox.pack_start(scrolled_window, True, True, 0)
|
||||
|
||||
# Vbox inside the scrolled window
|
||||
vbox = gtk.VBox(homogeneous=False, spacing=10)
|
||||
scrolled_window.add_with_viewport(vbox)
|
||||
vbox.set_border_width (10)
|
||||
|
||||
# Label
|
||||
label = gtk.Label("This is a label")
|
||||
vbox.pack_start(label, False, False, 0)
|
||||
|
||||
# Entry
|
||||
entry = gtk.Entry ()
|
||||
entry.set_text("Type some text here")
|
||||
vbox.pack_start(entry, False, False, 0)
|
||||
|
||||
# Buttons
|
||||
buttons_hbox = gtk.HBox(homogeneous=False, spacing=5)
|
||||
vbox.pack_start(buttons_hbox, False, False, 0)
|
||||
|
||||
button_1 = gtk.Button ("Button 1")
|
||||
buttons_hbox.pack_start(button_1, False, False, 0)
|
||||
|
||||
button_2 = gtk.Button ("Button 2")
|
||||
buttons_hbox.pack_start(button_2, False, False, 0)
|
||||
|
||||
button_3 = gtk.Button ("Button 3")
|
||||
buttons_hbox.pack_start(button_3, False, False, 0)
|
||||
|
||||
window.show_all()
|
||||
|
||||
gtk.main()
|
@ -17,20 +17,14 @@
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
import gtk
|
||||
import hippo
|
||||
|
||||
from sugar.graphics.frame import Frame
|
||||
|
||||
window = gtk.Window()
|
||||
class Window(gtk.Window):
|
||||
def __init__(self):
|
||||
gtk.Window.__init__(self)
|
||||
self.set_default_size(800, 600)
|
||||
|
||||
window = Window()
|
||||
window.connect("destroy", lambda w: gtk.main_quit())
|
||||
window.show()
|
||||
|
||||
canvas = hippo.Canvas()
|
||||
|
||||
frame = Frame()
|
||||
canvas.set_root(frame)
|
||||
|
||||
window.add(canvas)
|
||||
canvas.show()
|
||||
|
||||
gtk.main()
|
@ -1,45 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# Copyright (C) 2006, Red Hat, Inc.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
import pygtk
|
||||
pygtk.require('2.0')
|
||||
|
||||
from sugar.session.UITestSession import UITestSession
|
||||
|
||||
session = UITestSession()
|
||||
session.start()
|
||||
|
||||
import gtk
|
||||
|
||||
def _show_dialog(window):
|
||||
dialog = gtk.Dialog(title='No Unviewed Media',
|
||||
parent=window, flags=gtk.DIALOG_MODAL,
|
||||
buttons=(gtk.STOCK_OK, gtk.RESPONSE_ACCEPT))
|
||||
label = gtk.Label('There is no unviewed media to download.')
|
||||
dialog.vbox.pack_start(label, True, True, 0)
|
||||
label.show()
|
||||
response = dialog.run()
|
||||
dialog.hide()
|
||||
del dialog
|
||||
|
||||
window = gtk.Window()
|
||||
window.show()
|
||||
|
||||
_show_dialog(window)
|
||||
|
||||
gtk.main()
|
Loading…
Reference in New Issue
Block a user