mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-16 14:55:47 +00:00
Make Linux paste work
This commit is contained in:
parent
a51634749e
commit
54f3a11eb0
@ -23,6 +23,7 @@
|
||||
#include "nsISupportsArray.h"
|
||||
#include "nsIClipboardOwner.h"
|
||||
#include "nsDataFlavor.h"
|
||||
#include "nsIGenericTransferable.h"
|
||||
|
||||
#include "nsIWidget.h"
|
||||
#include "nsIComponentManager.h"
|
||||
@ -44,6 +45,10 @@ NS_IMPL_RELEASE_INHERITED(nsClipboard, nsBaseClipboard)
|
||||
|
||||
static NS_DEFINE_IID(kIClipboardIID, NS_ICLIPBOARD_IID);
|
||||
static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID);
|
||||
|
||||
#if defined(DEBUG_akkana) || defined(DEBUG_mcafee)
|
||||
#define DEBUG_CLIPBOARD
|
||||
#endif
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
@ -53,18 +58,16 @@ static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID);
|
||||
//-------------------------------------------------------------------------
|
||||
nsClipboard::nsClipboard() : nsBaseClipboard()
|
||||
{
|
||||
#ifdef DEBUG_CLIPBOARD
|
||||
printf(" nsClipboard::nsClipboard()\n");
|
||||
#endif /* DEBUG_CLIPBOARD */
|
||||
|
||||
//NS_INIT_REFCNT();
|
||||
mIgnoreEmptyNotification = PR_FALSE;
|
||||
mWindow = nsnull;
|
||||
mClipboardOwner = nsnull;
|
||||
mTransferable = nsnull;
|
||||
|
||||
// Create a Native window for the shell container...
|
||||
//nsresult rv = nsComponentManager::CreateInstance(kWindowCID, nsnull, kIWidgetIID, (void**)&mWindow);
|
||||
//mWindow->Show(PR_FALSE);
|
||||
//mWindow->Resize(1,1,PR_FALSE);
|
||||
mSelectionData.data = nsnull;
|
||||
mSelectionData.length = 0;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
@ -74,9 +77,18 @@ nsClipboard::nsClipboard() : nsBaseClipboard()
|
||||
//-------------------------------------------------------------------------
|
||||
nsClipboard::~nsClipboard()
|
||||
{
|
||||
#ifdef DEBUG_CLIPBOARD
|
||||
printf(" nsClipboard::~nsClipboard()\n");
|
||||
#endif /* DEBUG_CLIPBOARD */
|
||||
|
||||
NS_IF_RELEASE(mWindow);
|
||||
// Remove all our event handlers:
|
||||
if (sWidget &&
|
||||
gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == sWidget->window)
|
||||
gtk_selection_remove_all(sWidget);
|
||||
|
||||
// free the selection data, if any
|
||||
if (mSelectionData.data != nsnull)
|
||||
g_free(mSelectionData.data);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -87,8 +99,6 @@ nsClipboard::~nsClipboard()
|
||||
*/
|
||||
nsresult nsClipboard::QueryInterface(const nsIID& aIID, void** aInstancePtr)
|
||||
{
|
||||
printf(" nsClipboard::QueryInterface()\n");
|
||||
|
||||
if (NULL == aInstancePtr) {
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
@ -106,83 +116,6 @@ nsresult nsClipboard::QueryInterface(const nsIID& aIID, void** aInstancePtr)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
NS_IMETHODIMP nsClipboard::SetNativeClipboardData()
|
||||
{
|
||||
mIgnoreEmptyNotification = PR_TRUE;
|
||||
|
||||
printf(" nsClipboard::SetNativeClipboardData()\n");
|
||||
|
||||
// make sure we have a good transferable
|
||||
if (nsnull == mTransferable) {
|
||||
printf(" SetNativeClipboardData: no transferable!\n");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// If we're already the selection owner, don't need to do anything,
|
||||
// we'll already get the events:
|
||||
if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == sWidget->window)
|
||||
return NS_OK;
|
||||
|
||||
// Clear the native clipboard
|
||||
if (sWidget &&
|
||||
gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == sWidget->window)
|
||||
gtk_selection_remove_all(sWidget);
|
||||
|
||||
|
||||
// register as the selection owner:
|
||||
gint have_selection =
|
||||
gtk_selection_owner_set(sWidget,
|
||||
GDK_SELECTION_PRIMARY,
|
||||
GDK_CURRENT_TIME);
|
||||
if (have_selection == 0)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
mIgnoreEmptyNotification = PR_FALSE;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
NS_IMETHODIMP nsClipboard::GetNativeClipboardData(nsITransferable * aTransferable)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
printf(" nsClipboard::GetNativeClipboardData()\n");
|
||||
|
||||
// make sure we have a good transferable
|
||||
if (nsnull == aTransferable) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* No-op.
|
||||
*
|
||||
*/
|
||||
NS_IMETHODIMP nsClipboard::ForceDataToClipboard()
|
||||
{
|
||||
printf(" nsClipboard::ForceDataToClipboard()\n");
|
||||
|
||||
// make sure we have a good transferable
|
||||
if (nsnull == mTransferable) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// GTK Weirdness!
|
||||
// This is here in the hope of being able to call
|
||||
@ -208,13 +141,21 @@ NS_IMETHODIMP nsClipboard::ForceDataToClipboard()
|
||||
|
||||
void nsClipboard::SetTopLevelWidget(GtkWidget* w)
|
||||
{
|
||||
#ifdef DEBUG_CLIPBOARD
|
||||
printf(" nsClipboard::SetTopLevelWidget\n");
|
||||
#endif /* DEBUG_CLIPBOARD */
|
||||
|
||||
// Don't set up any more event handlers if we're being called twice
|
||||
// for the same toplevel widget
|
||||
if (sWidget == w)
|
||||
return;
|
||||
|
||||
// If we're changing from one widget to another
|
||||
// (shouldn't generally happen), clear the old event handlers:
|
||||
if (sWidget &&
|
||||
gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == sWidget->window)
|
||||
gtk_selection_remove_all(sWidget);
|
||||
|
||||
sWidget = w;
|
||||
|
||||
// Get the clipboard from the service manager.
|
||||
@ -267,6 +208,250 @@ void nsClipboard::SetTopLevelWidget(GtkWidget* w)
|
||||
NS_IF_RELEASE(clipboard);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
NS_IMETHODIMP nsClipboard::SetNativeClipboardData()
|
||||
{
|
||||
mIgnoreEmptyNotification = PR_TRUE;
|
||||
|
||||
#ifdef DEBUG_CLIPBOARD
|
||||
printf(" nsClipboard::SetNativeClipboardData()\n");
|
||||
#endif /* DEBUG_CLIPBOARD */
|
||||
|
||||
// make sure we have a good transferable
|
||||
if (nsnull == mTransferable) {
|
||||
printf(" SetNativeClipboardData: no transferable!\n");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// If we're already the selection owner, don't need to do anything,
|
||||
// we'll already get the events:
|
||||
if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == sWidget->window)
|
||||
return NS_OK;
|
||||
|
||||
// Clear the native clipboard
|
||||
if (sWidget &&
|
||||
gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == sWidget->window)
|
||||
gtk_selection_remove_all(sWidget);
|
||||
|
||||
|
||||
// register as the selection owner:
|
||||
gint have_selection =
|
||||
gtk_selection_owner_set(sWidget,
|
||||
GDK_SELECTION_PRIMARY,
|
||||
GDK_CURRENT_TIME);
|
||||
if (have_selection == 0)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
mIgnoreEmptyNotification = PR_FALSE;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// The blocking Paste routine
|
||||
//
|
||||
NS_IMETHODIMP
|
||||
nsClipboard::GetNativeClipboardData(nsITransferable * aTransferable)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
#ifdef DEBUG_CLIPBOARD
|
||||
printf(" nsClipboard::GetNativeClipboardData()\n");
|
||||
#endif /* DEBUG_CLIPBOARD */
|
||||
|
||||
// make sure we have a good transferable
|
||||
if (nsnull == aTransferable) {
|
||||
printf(" GetNativeClipboardData: Transferable is null!\n");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIGenericTransferable> genericTrans = do_QueryInterface(aTransferable);
|
||||
if (!genericTrans)
|
||||
return rv;
|
||||
|
||||
#define ONLY_SUPPORT_PLAIN_TEXT 1
|
||||
#ifdef ONLY_SUPPORT_PLAIN_TEXT
|
||||
gtk_selection_convert(sWidget, GDK_SELECTION_PRIMARY,
|
||||
GDK_SELECTION_TYPE_STRING, GDK_CURRENT_TIME);
|
||||
// Tried to use straight Xlib call but this would need more work:
|
||||
//XConvertSelection(GDK_WINDOW_XDISPLAY(sWidget->window),
|
||||
// XA_PRIMARY, XA_STRING, gdk_selection_property,
|
||||
// GDK_WINDOW_XWINDOW(sWidget->window), GDK_CURRENT_TIME);
|
||||
|
||||
#else /* ONLY_SUPPORT_PLAIN_TEXT */
|
||||
//
|
||||
// XXX This code isn't implemented for Unix yet!
|
||||
// Instead of SetTransferData it will have to call gtk_selection_convert.
|
||||
//
|
||||
|
||||
// Get the transferable list of data flavors
|
||||
nsISupportsArray * dfList;
|
||||
aTransferable->GetTransferDataFlavors(&dfList);
|
||||
|
||||
// Walk through flavors and see which flavor matches the one being pasted:
|
||||
PRUint32 i;
|
||||
for (i=0;i<dfList->Count();i++) {
|
||||
nsIDataFlavor * df;
|
||||
nsISupports * supports = dfList->ElementAt(i);
|
||||
if (NS_OK == supports->QueryInterface(kIDataFlavorIID, (void **)&df)) {
|
||||
nsString mime;
|
||||
df->GetMimeType(mime);
|
||||
UINT format = GetFormat(mime);
|
||||
|
||||
void * data;
|
||||
PRUint32 dataLen;
|
||||
|
||||
if (nsnull != aDataObject) {
|
||||
res = GetNativeDataOffClipboard(aDataObject, format, &data, &dataLen);
|
||||
if (NS_OK == res) {
|
||||
genericTrans->SetTransferData(df, data, dataLen);
|
||||
}
|
||||
} else if (nsnull != aWindow) {
|
||||
res = GetNativeDataOffClipboard(aWindow, format, &data, &dataLen);
|
||||
if (NS_OK == res) {
|
||||
genericTrans->SetTransferData(df, data, dataLen);
|
||||
}
|
||||
}
|
||||
NS_IF_RELEASE(df);
|
||||
}
|
||||
NS_RELEASE(supports);
|
||||
}
|
||||
#endif /* ONLY_SUPPORT_PLAIN_TEXT */
|
||||
|
||||
//
|
||||
// We've told X what type to send, and we just have to wait
|
||||
// for the callback saying that the data have been transferred.
|
||||
//
|
||||
|
||||
#ifdef DEBUG_CLIPBOARD
|
||||
printf("Waiting for the callback\n");
|
||||
#endif /* DEBUG_CLIPBOARD */
|
||||
|
||||
if (mSelectionData.data != nsnull)
|
||||
g_free(mSelectionData.data);
|
||||
mSelectionData.data = nsnull;
|
||||
mSelectionData.length = 0;
|
||||
mBlocking = PR_TRUE;
|
||||
|
||||
// Now we need to wait until the callback comes in ...
|
||||
// i is in case we get a runaway (yuck).
|
||||
for (int i=0; mBlocking == PR_TRUE && i < 10000; ++i)
|
||||
{
|
||||
gtk_main_iteration_do(TRUE);
|
||||
}
|
||||
|
||||
mBlocking = PR_FALSE;
|
||||
|
||||
if (!mSelectionData.data)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
#ifdef DEBUG_CLIPBOARD
|
||||
printf("Got the callback: '%s', %d\n",
|
||||
mSelectionData.data, mSelectionData.length);
|
||||
#endif /* DEBUG_CLIPBOARD */
|
||||
|
||||
//
|
||||
// Now we have data in mSelectionData.data.
|
||||
// We just have to copy it to the transferable.
|
||||
//
|
||||
nsDataFlavor *dataFlavor = new nsDataFlavor();
|
||||
dataFlavor->Init(kTextMime, kTextMime);
|
||||
genericTrans->SetTransferData(dataFlavor,
|
||||
mSelectionData.data, mSelectionData.length);
|
||||
|
||||
// Can't free the selection data -- the transferable doesn't make a copy.
|
||||
//g_free(mSelectionData.data);
|
||||
//mSelectionData.data = nsnull;
|
||||
//mSelectionData.length = 0;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//
|
||||
// Called when the data from a paste comes in:
|
||||
//
|
||||
void
|
||||
nsClipboard::SelectionReceivedCB (GtkWidget *aWidget,
|
||||
GtkSelectionData *aSelectionData,
|
||||
gpointer aData)
|
||||
{
|
||||
#ifdef DEBUG_CLIPBOARD
|
||||
printf(" nsClipboard::SelectionReceivedCB\n");
|
||||
#endif /* DEBUG_CLIPBOARD */
|
||||
|
||||
// ARGHH! GTK doesn't pass the arg to the callback, so we can't
|
||||
// get "this" back! Until we solve this, get it from the service mgr:
|
||||
nsIClipboard* iclipboard;
|
||||
nsresult rv = nsServiceManager::GetService(kCClipboardCID,
|
||||
kIClipboardIID,
|
||||
(nsISupports **)&iclipboard);
|
||||
if (!NS_SUCCEEDED(rv)) {
|
||||
printf("Couldn't get clipboard service!\n");
|
||||
return;
|
||||
}
|
||||
nsClipboard* clipboard = (nsClipboard*)iclipboard;
|
||||
if (!clipboard) {
|
||||
printf("couldn't convert nsIClipboard to nsClipboard\n");
|
||||
return;
|
||||
}
|
||||
|
||||
clipboard->SelectionReceiver(aWidget, aSelectionData);
|
||||
}
|
||||
|
||||
void
|
||||
nsClipboard::SelectionReceiver (GtkWidget *aWidget,
|
||||
GtkSelectionData *aSelectionData)
|
||||
{
|
||||
mBlocking = PR_FALSE;
|
||||
|
||||
if (aSelectionData->length < 0)
|
||||
{
|
||||
printf("Error retrieving selection: length was %d\n",
|
||||
aSelectionData->length);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (aSelectionData->type)
|
||||
{
|
||||
case GDK_SELECTION_TYPE_STRING:
|
||||
mSelectionData = *aSelectionData;
|
||||
mSelectionData.data = g_new(guchar, aSelectionData->length + 1);
|
||||
memcpy(mSelectionData.data,
|
||||
aSelectionData->data, aSelectionData->length);
|
||||
mSelectionData.data[aSelectionData->length] = '\0';
|
||||
mSelectionData.length = aSelectionData->length;
|
||||
return;
|
||||
|
||||
default:
|
||||
printf("Can't convert type %s (%ld) to string\n",
|
||||
gdk_atom_name (aSelectionData->type), aSelectionData->type);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* No-op.
|
||||
*
|
||||
*/
|
||||
NS_IMETHODIMP nsClipboard::ForceDataToClipboard()
|
||||
{
|
||||
#ifdef DEBUG_CLIPBOARD
|
||||
printf(" nsClipboard::ForceDataToClipboard()\n");
|
||||
#endif /* DEBUG_CLIPBOARD */
|
||||
|
||||
// make sure we have a good transferable
|
||||
if (nsnull == mTransferable) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//
|
||||
// This is the callback which is called when another app
|
||||
// requests the selection.
|
||||
@ -277,7 +462,9 @@ void nsClipboard::SelectionGetCB(GtkWidget *widget,
|
||||
guint /*time*/,
|
||||
gpointer aData)
|
||||
{
|
||||
#ifdef DEBUG_CLIPBOARD
|
||||
printf(" nsClipboard::SelectionGetCB\n");
|
||||
#endif /* DEBUG_CLIPBOARD */
|
||||
|
||||
nsClipboard *clipboard = (nsClipboard *)aData;
|
||||
|
||||
@ -294,7 +481,6 @@ void nsClipboard::SelectionGetCB(GtkWidget *widget,
|
||||
// XXX hack, string-only for now.
|
||||
// Create string data-flavor.
|
||||
nsDataFlavor *dataFlavor = new nsDataFlavor();
|
||||
// For some reason the XIF data flavor uses text/txt instead of text/plain:
|
||||
dataFlavor->Init(kTextMime, kTextMime);
|
||||
|
||||
// Get data out of transferable.
|
||||
@ -325,29 +511,21 @@ void nsClipboard::SelectionClearCB(GtkWidget *widget,
|
||||
GdkEventSelection *event,
|
||||
gpointer data)
|
||||
{
|
||||
#ifdef DEBUG_CLIPBOARD
|
||||
printf(" nsClipboard::SelectionClearCB\n");
|
||||
#endif /* DEBUG_CLIPBOARD */
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
nsClipboard::SelectionReceivedCB (GtkWidget *aWidget,
|
||||
GtkSelectionData *aSelectionData,
|
||||
gpointer aData)
|
||||
{
|
||||
// ARGHH! GTK doesn't pass the arg to the callback, so we can't
|
||||
// get "this" back! Until we solve this, use the global:
|
||||
|
||||
printf(" nsClipboard::SelectionReceivedCB\n");
|
||||
}
|
||||
|
||||
|
||||
// The routine called when another app asks for the content of the selection
|
||||
void
|
||||
nsClipboard::SelectionRequestCB (GtkWidget *aWidget,
|
||||
GtkSelectionData *aSelectionData,
|
||||
gpointer aData)
|
||||
{
|
||||
#ifdef DEBUG_CLIPBOARD
|
||||
printf(" nsClipboard::SelectionRequestCB\n");
|
||||
#endif /* DEBUG_CLIPBOARD */
|
||||
}
|
||||
|
||||
void
|
||||
@ -355,5 +533,7 @@ nsClipboard::SelectionNotifyCB (GtkWidget *aWidget,
|
||||
GtkSelectionData *aSelectionData,
|
||||
gpointer aData)
|
||||
{
|
||||
#ifdef DEBUG_CLIPBOARD
|
||||
printf(" nsClipboard::SelectionNotifyCB\n");
|
||||
#endif /* DEBUG_CLIPBOARD */
|
||||
}
|
||||
|
@ -52,9 +52,16 @@ protected:
|
||||
|
||||
PRBool mIgnoreEmptyNotification;
|
||||
|
||||
nsIWidget *mWindow;
|
||||
static GtkWidget *sWidget;
|
||||
|
||||
// Used for communicating pasted data
|
||||
// from the asynchronous X routines back to a blocking paste:
|
||||
GtkSelectionData mSelectionData;
|
||||
PRBool mBlocking;
|
||||
|
||||
void SelectionReceiver(GtkWidget *aWidget,
|
||||
GtkSelectionData *aSelectionData);
|
||||
|
||||
static void SelectionGetCB(GtkWidget *widget,
|
||||
GtkSelectionData *selection_data,
|
||||
guint /*info*/,
|
||||
|
Loading…
Reference in New Issue
Block a user