Make Linux paste work

This commit is contained in:
akkana%netscape.com 1999-04-20 22:40:53 +00:00
parent a51634749e
commit 54f3a11eb0
2 changed files with 287 additions and 100 deletions

View File

@ -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 */
}

View File

@ -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*/,